EVOLUTION-MANAGER
Edit File: builder.py
# -*- coding: utf-8 -*- """ sphinx.builders.websupport ~~~~~~~~~~~~~~~~~~~~~~~~~~ Builder for the web support package. :copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. """ from os import path import posixpath import shutil from docutils.io import StringOutput from sphinx import version_info as sphinx_version from sphinx.jinja2glue import BuiltinTemplateLoader from sphinx.util.osutil import os_path, relative_uri, ensuredir, copyfile from sphinxcontrib.serializinghtml import PickleHTMLBuilder from . import package_dir from .writer import WebSupportTranslator from .utils import is_commentable if False: # For type annotation from typing import Any, Dict, Iterable, Tuple # NOQA from docutils import nodes # NOQA from sphinx.application import Sphinx # NOQA RESOURCES = [ 'ajax-loader.gif', 'comment-bright.png', 'comment-close.png', 'comment.png', 'down-pressed.png', 'down.png', 'up-pressed.png', 'up.png', 'websupport.js', ] class WebSupportBuilder(PickleHTMLBuilder): """ Builds documents for the web support package. """ name = 'websupport' default_translator_class = WebSupportTranslator versioning_compare = True # for commentable node's uuid stability. def init(self): # type: () -> None PickleHTMLBuilder.init(self) # templates are needed for this builder, but the serializing # builder does not initialize them self.init_templates() if not isinstance(self.templates, BuiltinTemplateLoader): raise RuntimeError('websupport builder must be used with ' 'the builtin templates') # add our custom JS self.script_files.append('_static/websupport.js') @property def versioning_method(self): if sphinx_version < (2, 0): return 'commentable' else: return is_commentable def set_webinfo(self, staticdir, virtual_staticdir, search, storage): # type: (str, str, Any, str) -> None self.staticdir = staticdir self.virtual_staticdir = virtual_staticdir self.search = search self.storage = storage def prepare_writing(self, docnames): # type: (Iterable[str]) -> None PickleHTMLBuilder.prepare_writing(self, docnames) self.globalcontext['no_search_suffix'] = True def write_doc(self, docname, doctree): # type: (str, nodes.Node) -> None destination = StringOutput(encoding='utf-8') doctree.settings = self.docsettings self.secnumbers = self.env.toc_secnumbers.get(docname, {}) self.fignumbers = self.env.toc_fignumbers.get(docname, {}) self.imgpath = '/' + posixpath.join(self.virtual_staticdir, self.imagedir) self.dlpath = '/' + posixpath.join(self.virtual_staticdir, '_downloads') self.current_docname = docname self.docwriter.write(doctree, destination) self.docwriter.assemble_parts() body = self.docwriter.parts['fragment'] metatags = self.docwriter.clean_meta ctx = self.get_doc_context(docname, body, metatags) self.handle_page(docname, ctx, event_arg=doctree) def write_doc_serialized(self, docname, doctree): # type: (str, nodes.Node) -> None self.imgpath = '/' + posixpath.join(self.virtual_staticdir, self.imagedir) self.post_process_images(doctree) title = self.env.longtitles.get(docname) title = title and self.render_partial(title)['title'] or '' self.index_page(docname, doctree, title) def load_indexer(self, docnames): # type: (Iterable[str]) -> None self.indexer = self.search # type: ignore self.indexer.init_indexing(changed=docnames) # type: ignore def _render_page(self, pagename, addctx, templatename, event_arg=None): # type: (str, Dict, str, str) -> Tuple[Dict, Dict] # This is mostly copied from StandaloneHTMLBuilder. However, instead # of rendering the template and saving the html, create a context # dict and pickle it. ctx = self.globalcontext.copy() ctx['pagename'] = pagename def pathto(otheruri, resource=False, baseuri=self.get_target_uri(pagename)): # type: (str, bool, str) -> str if resource and '://' in otheruri: return otheruri elif not resource: otheruri = self.get_target_uri(otheruri) return relative_uri(baseuri, otheruri) or '#' else: return '/' + posixpath.join(self.virtual_staticdir, otheruri) ctx['pathto'] = pathto ctx['hasdoc'] = lambda name: name in self.env.all_docs ctx['encoding'] = self.config.html_output_encoding ctx['toctree'] = lambda **kw: self._get_local_toctree(pagename, **kw) self.add_sidebars(pagename, ctx) ctx.update(addctx) newtmpl = self.app.emit_firstresult('html-page-context', pagename, templatename, ctx, event_arg) if newtmpl: templatename = newtmpl # create a dict that will be pickled and used by webapps doc_ctx = { 'body': ctx.get('body', ''), 'title': ctx.get('title', ''), 'css': ctx.get('css', ''), 'script': ctx.get('script', ''), } # partially render the html template to get at interesting macros template = self.templates.environment.get_template(templatename) template_module = template.make_module(ctx) for item in ['sidebar', 'relbar', 'script', 'css']: if hasattr(template_module, item): doc_ctx[item] = getattr(template_module, item)() return ctx, doc_ctx def handle_page(self, pagename, addctx, templatename='page.html', outfilename=None, event_arg=None): # type: (str, Dict, str, str, str) -> None ctx, doc_ctx = self._render_page(pagename, addctx, templatename, event_arg) if not outfilename: outfilename = path.join(self.outdir, 'pickles', os_path(pagename) + self.out_suffix) ensuredir(path.dirname(outfilename)) self.dump_context(doc_ctx, outfilename) # if there is a source file, copy the source file for the # "show source" link if ctx.get('sourcename'): source_name = path.join(self.staticdir, '_sources', os_path(ctx['sourcename'])) ensuredir(path.dirname(source_name)) copyfile(self.env.doc2path(pagename), source_name) def handle_finish(self): # type: () -> None # get global values for css and script files _, doc_ctx = self._render_page('tmp', {}, 'page.html') self.globalcontext['css'] = doc_ctx['css'] self.globalcontext['script'] = doc_ctx['script'] PickleHTMLBuilder.handle_finish(self) # move static stuff over to separate directory directories = [self.imagedir, '_static'] for directory in directories: src = path.join(self.outdir, directory) dst = path.join(self.staticdir, directory) if path.isdir(src): if path.isdir(dst): shutil.rmtree(dst) shutil.move(src, dst) self.copy_resources() def copy_resources(self): # type: () -> None # copy resource files to static dir dst = path.join(self.staticdir, '_static') if path.isdir(dst): for resource in RESOURCES: src = path.join(package_dir, 'files', resource) shutil.copy(src, dst) def dump_search_index(self): # type: () -> None self.indexer.finish_indexing() # type: ignore def setup(app): # type: (Sphinx) -> Dict[str, Any] if sphinx_version >= (2, 0): app.add_builder(WebSupportBuilder) return { 'version': 'builtin', 'parallel_read_safe': True, 'parallel_write_safe': True, }