Example #1
0
def copy_asset_file(source, destination, context=None, renderer=None):
    # type: (unicode, unicode, Dict, BaseRenderer) -> None
    """Copy an asset file to destination.

    On copying, it expands the template variables if context argument is given and
    the asset is a template file.

    :param source: The path to source file
    :param destination: The path to destination file or directory
    :param context: The template variables.  If not given, template files are simply copied
    :param renderer: The template engine.  If not given, SphinxRenderer is used by default
    """
    if not os.path.exists(source):
        return

    if os.path.exists(destination) and os.path.isdir(destination):
        # Use source filename if destination points a directory
        destination = os.path.join(destination, os.path.basename(source))

    if source.lower().endswith('_t') and context:
        if renderer is None:
            from sphinx.util.template import SphinxRenderer
            renderer = SphinxRenderer()

        with codecs.open(source, 'r',
                         encoding='utf-8') as fsrc:  # type: ignore
            if destination.lower().endswith('_t'):
                destination = destination[:-2]
            with codecs.open(destination, 'w',
                             encoding='utf-8') as fdst:  # type: ignore
                fdst.write(renderer.render_string(fsrc.read(), context))
    else:
        copyfile(source, destination)
Example #2
0
    def _copy_searchtools(self, renderer=None):
        """Copy and patch searchtools

        This uses the included Sphinx version's searchtools, but patches it to
        remove automatic initialization. This is a fork of
        ``sphinx.util.fileutil.copy_asset``
        """
        self.app.info(bold('copying searchtools... '), nonl=True)

        path_src = os.path.join(package_dir, 'themes', 'basic', 'static',
                                'searchtools.js_t')
        if os.path.exists(path_src):
            path_dest = os.path.join(self.outdir, '_static', 'searchtools.js')
            if renderer is None:
                # Sphinx 1.4 used the renderer from the existing builder, but
                # the pattern for Sphinx 1.5 is to pass in a renderer separate
                # from the builder. This supports both patterns for future
                # compatibility
                if sphinx.version_info < (1, 5):
                    renderer = self.templates
                else:
                    from sphinx.util.template import SphinxRenderer
                    renderer = SphinxRenderer()
            with codecs.open(path_src, 'r', encoding='utf-8') as h_src:
                with codecs.open(path_dest, 'w', encoding='utf-8') as h_dest:
                    data = h_src.read()
                    data = self.REPLACEMENT_PATTERN.sub(self.REPLACEMENT_TEXT, data)
                    h_dest.write(renderer.render_string(
                        data,
                        self.get_static_readthedocs_context()
                    ))
        else:
            self.app.warn('Missing searchtools.js_t')
        self.app.info('done')
Example #3
0
def add_versions_menu_js_file(app):
    """Add doctr-versions-menu.js file as a static js file to Sphinx."""
    tmpdir = tempfile.mkdtemp()
    app.config._doctr_versions_menu_temp_dir = tmpdir
    js_file_name = 'doctr-versions-menu.js'
    renderer = SphinxRenderer(app.config.templates_path +
                              [str(Path(__file__).parent / '_template')])
    context = dict(
        json_file=_JS(
            '"/" + window.location.pathname.split("/")[1] + "/versions.json"'),
        github_project_url=_JS('getGithubProjectUrl()'),
        current_folder=_JS('getGhPagesCurrentFolder()'),
        badge_only=(app.config.html_theme != 'sphinx_rtd_theme'),
    )
    context.update(app.config.doctr_versions_menu_conf)
    with (Path(tmpdir) / js_file_name).open('w') as js_file:
        js_file.write(
            renderer.render(template_name='doctr-versions-menu.js_t',
                            context=context))
    app.config.html_static_path.append(tmpdir)
    app.add_js_file(js_file_name)
    if context['badge_only']:
        app.config.html_static_path.extend([
            str(Path(__file__).parent / '_css'),
            str(Path(__file__).parent / '_fonts'),
        ])
        app.add_css_file('badge_only.css')
Example #4
0
    def copy_static_readthedocs_files(self):
        log.info(bold('copying readthedocs static files... '), nonl=True)
        for filename in self.static_readthedocs_files:
            path_dest = os.path.join(self.outdir, '_static')
            path_src = os.path.join(os.path.abspath(os.path.dirname(__file__)),
                                    '_static', filename)
            ctx = self.get_static_readthedocs_context()
            if sphinx.version_info < (1, 5):
                copy_static_entry(
                    path_src,
                    path_dest,
                    self,
                    context=ctx,
                )
            else:
                from sphinx.util.template import SphinxRenderer
                renderer = SphinxRenderer()

                copy_asset(
                    path_src,
                    path_dest,
                    context=ctx,
                    renderer=renderer,
                )
        log.info('done')
Example #5
0
def add_versions_menu_js_file(app):
    """Add docs-versions-menu.js file as a static js file to Sphinx."""
    tmpdir = tempfile.mkdtemp()
    app.config._docs_versions_menu_temp_dir = tmpdir
    js_file_name = 'docs-versions-menu.js'
    template_path = [
        os.path.join(app.confdir, folder)
        for folder in app.config.templates_path
    ]
    template_name = 'docs-versions-menu.js_t'
    legacy_template_name = 'doctr-versions-menu.js_t'
    for folder in template_path:
        t_legacy = os.path.join(folder, legacy_template_name)
        t_new = os.path.join(folder, template_name)
        if os.path.isfile(t_legacy) and not os.path.isfile(t_new):
            print(
                "WARNING: using legacy template %s. This file should be "
                "renamed to %s" % (t_legacy, t_new)
            )
            template_name = legacy_template_name

    template_path.append(str(Path(__file__).parent / '_template'))
    renderer = SphinxRenderer(template_path=template_path)
    context = dict(
        json_file=_JS(
            '"/" + window.location.pathname.split("/")[1] + "/versions.json"'
        ),
        github_project_url=_JS('getGithubProjectUrl()'),
        current_folder=_JS('getGhPagesCurrentFolder()'),
        badge_only=(app.config.html_theme != 'sphinx_rtd_theme'),
        menu_title="Docs",
    )
    if app.config.doctr_versions_menu_conf:
        print(
            "WARNING: using legacy options from "
            "`doctr_versions_menu_conf`. This option should be "
            "renamed to `docs_versions_menu_conf`"
        )
        context.update(app.config.doctr_versions_menu_conf)
    context.update(app.config.docs_versions_menu_conf)
    js_file_path = Path(tmpdir) / js_file_name
    template = renderer.env.get_template(template_name)
    print(
        "creating %s from template %s for docs-versions-menu"
        % (js_file_name, template.filename)
    )
    with js_file_path.open('w') as js_file:
        js_file.write(template.render(**context))
    app.config.html_static_path.append(tmpdir)
    app.add_js_file(js_file_name)
    if context['badge_only']:
        app.config.html_static_path.extend(
            [
                str(Path(__file__).parent / '_css'),
                str(Path(__file__).parent / '_fonts'),
            ]
        )
        app.add_css_file('badge_only.css')
Example #6
0
def copy_asset(source: str,
               destination: str,
               excluded: PathMatcher = lambda path: False,
               context: Dict = None,
               renderer: "BaseRenderer" = None,
               onerror: Callable[[str, Exception], None] = None) -> None:
    """Copy asset files to destination recursively.

    On copying, it expands the template variables if context argument is given and
    the asset is a template file.

    :param source: The path to source file or directory
    :param destination: The path to destination directory
    :param excluded: The matcher to determine the given path should be copied or not
    :param context: The template variables.  If not given, template files are simply copied
    :param renderer: The template engine.  If not given, SphinxRenderer is used by default
    :param onerror: The error handler.
    """
    if not os.path.exists(source):
        return

    if renderer is None:
        from sphinx.util.template import SphinxRenderer
        renderer = SphinxRenderer()

    ensuredir(destination)
    if os.path.isfile(source):
        copy_asset_file(source, destination, context, renderer)
        return

    for root, dirs, files in os.walk(source, followlinks=True):
        reldir = relative_path(source, root)
        for dir in dirs[:]:
            if excluded(posixpath.join(reldir, dir)):
                dirs.remove(dir)
            else:
                ensuredir(posixpath.join(destination, reldir, dir))

        for filename in files:
            if not excluded(posixpath.join(reldir, filename)):
                try:
                    copy_asset_file(posixpath.join(root, filename),
                                    posixpath.join(destination, reldir),
                                    context, renderer)
                except Exception as exc:
                    if onerror:
                        onerror(posixpath.join(root, filename), exc)
                    else:
                        raise
Example #7
0
def copy_asset(source,
               destination,
               excluded=lambda path: False,
               context=None,
               renderer=None):
    # type: (unicode, unicode, Union[Callable[[unicode], bool], Matcher], Dict, BaseRenderer) -> None  # NOQA
    """Copy asset files to destination recursively.

    On copying, it expands the template variables if context argument is given and
    the asset is a template file.

    :param source: The path to source file or directory
    :param destination: The path to destination directory
    :param excluded: The matcher to determine the given path should be copied or not
    :param context: The template variables.  If not given, template files are simply copied
    :param renderer: The template engine.  If not given, SphinxRenderer is used by default
    """
    if not os.path.exists(source):
        return

    if renderer is None:
        from sphinx.util.template import SphinxRenderer
        renderer = SphinxRenderer()

    ensuredir(destination)
    if os.path.isfile(source):
        copy_asset_file(source, destination, context, renderer)
        return

    for root, dirs, files in walk(source, followlinks=True):
        reldir = relative_path(source, root)
        for dir in dirs[:]:
            if excluded(posixpath.join(reldir, dir)):
                dirs.remove(dir)
            else:
                ensuredir(posixpath.join(destination, reldir, dir))

        for filename in files:
            if not excluded(posixpath.join(reldir, filename)):
                copy_asset_file(posixpath.join(root, filename),
                                posixpath.join(destination, reldir), context,
                                renderer)
Example #8
0
    def finish(self):
        if self.config.review_catalog_file:
            copy_asset_file(
                path.join(self.srcdir, self.config.review_catalog_file),
                self.outdir)
        else:
            catalogfile = path.join(self.outdir, "catalog.yml")
            with codecs.open(catalogfile, 'w', 'utf-8') as f:
                template = SphinxRenderer()
                f.write(
                    template.render_string(TEMPLATE,
                                           {'chaps': self.out_files}))

        # copy image files
        if self.images:
            logger.info(bold('copying images...'), nonl=True)
            for dest, src in iteritems(self.images):
                logger.info(' ' + src, nonl=True)
                outdir = path.join(self.outdir, "images")
                outfile = path.join(outdir, dest)
                ensuredir(path.dirname(outfile))
                copy_asset_file(path.join(self.srcdir, src), outfile)
Example #9
0
 def render(self, name: str, context: Dict) -> str:
     template = SphinxRenderer(template_dir)
     return template.render(name, context)
Example #10
0
 def render(self, name, context):
     # type: (str, Dict) -> str
     template = SphinxRenderer(template_dir)
     return template.render(name, context)
Example #11
0
def generate(d, overwrite=True, silent=False):
    """Generate project based on values in *d*."""
    template = SphinxRenderer()

    texescape.init()
    indent = ' ' * 4

    if 'mastertoctree' not in d:
        d['mastertoctree'] = ''
    if 'mastertocmaxdepth' not in d:
        d['mastertocmaxdepth'] = 2

    d['PY3'] = PY3
    d['project_fn'] = make_filename(d['project'])
    d['project_url'] = urlquote(d['project'].encode('idna'))
    d['project_manpage'] = d['project_fn'].lower()
    d['now'] = time.asctime()
    d['project_underline'] = column_width(d['project']) * '='
    extensions = (',\n' + indent).join(
        repr('sphinx.ext.' + name) for name in EXTENSIONS
        if d.get('ext_' + name))
    if extensions:
        d['extensions'] = '\n' + indent + extensions + ',\n'
    else:
        d['extensions'] = extensions
    d['copyright'] = time.strftime('%Y') + ', ' + d['author']
    d['author_texescaped'] = text_type(d['author']).\
        translate(texescape.tex_escape_map)
    d['project_doc'] = d['project'] + ' Documentation'
    d['project_doc_texescaped'] = text_type(d['project'] + ' Documentation').\
        translate(texescape.tex_escape_map)

    # escape backslashes and single quotes in strings that are put into
    # a Python string literal
    for key in ('project', 'project_doc', 'project_doc_texescaped', 'author',
                'author_texescaped', 'copyright', 'version', 'release',
                'master'):
        d[key + '_str'] = d[key].replace('\\', '\\\\').replace("'", "\\'")

    if not path.isdir(d['path']):
        mkdir_p(d['path'])

    srcdir = d['sep'] and path.join(d['path'], 'source') or d['path']

    mkdir_p(srcdir)
    if d['sep']:
        builddir = path.join(d['path'], 'build')
        d['exclude_patterns'] = ''
    else:
        builddir = path.join(srcdir, d['dot'] + 'build')
        exclude_patterns = map(repr, [
            d['dot'] + 'build',
            'Thumbs.db',
            '.DS_Store',
        ])
        d['exclude_patterns'] = ', '.join(exclude_patterns)
    mkdir_p(builddir)
    mkdir_p(path.join(srcdir, d['dot'] + 'templates'))
    mkdir_p(path.join(srcdir, d['dot'] + 'static'))

    def write_file(fpath, content, newline=None):
        if overwrite or not path.isfile(fpath):
            print('Creating file %s.' % fpath)
            with open(fpath, 'wt', encoding='utf-8', newline=newline) as f:
                f.write(content)
        else:
            print('File %s already exists, skipping.' % fpath)

    with open(os.path.join(package_dir, 'templates', 'quickstart',
                           'conf.py_t')) as f:
        conf_text = convert_python_source(f.read())

    write_file(path.join(srcdir, 'conf.py'),
               template.render_string(conf_text, d))

    masterfile = path.join(srcdir, d['master'] + d['suffix'])
    write_file(masterfile, template.render('quickstart/master_doc.rst_t', d))

    if d.get('make_mode') is True:
        makefile_template = 'quickstart/Makefile.new_t'
        batchfile_template = 'quickstart/make.bat.new_t'
    else:
        makefile_template = 'quickstart/Makefile_t'
        batchfile_template = 'quickstart/make.bat_t'

    if d['makefile'] is True:
        d['rsrcdir'] = d['sep'] and 'source' or '.'
        d['rbuilddir'] = d['sep'] and 'build' or d['dot'] + 'build'
        # use binary mode, to avoid writing \r\n on Windows
        write_file(path.join(d['path'], 'Makefile'),
                   template.render(makefile_template, d), u'\n')

    if d['batchfile'] is True:
        d['rsrcdir'] = d['sep'] and 'source' or '.'
        d['rbuilddir'] = d['sep'] and 'build' or d['dot'] + 'build'
        write_file(path.join(d['path'], 'make.bat'),
                   template.render(batchfile_template, d), u'\r\n')

    if silent:
        return
    print()
    print(bold('Finished: An initial directory structure has been created.'))
    print('''
You should now populate your master file %s and create other documentation
source files. ''' % masterfile + ((d['makefile'] or d['batchfile']) and '''\
Use the Makefile to build the docs, like so:
   make builder
''' or '''\
Use the sphinx-build command to build the docs, like so:
   sphinx-build -b builder %s %s
''' % (srcdir, builddir)) + '''\
where "builder" is one of the supported builders, e.g. html, latex or linkcheck.
''')