# -*- coding: utf-8 -*- """ sphinx.builders.websupport ~~~~~~~~~~~~~~~~~~~~~~~~~~ Builder for the web support package. :copyright: Copyright 2007-2015 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.jinja2glue import BuiltinTemplateLoader from sphinx.util.osutil import os_path, relative_uri, ensuredir, copyfile from sphinx.builders.html import PickleHTMLBuilder from sphinx.writers.websupport import WebSupportTranslator class WebSupportBuilder(PickleHTMLBuilder): """ Builds documents for the web support package. """ name = 'websupport' versioning_method = 'commentable' versioning_compare = True # for commentable node's uuid stability. def init(self): 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') def set_webinfo(self, staticdir, virtual_staticdir, search, storage): self.staticdir = staticdir self.virtual_staticdir = virtual_staticdir self.search = search self.storage = storage def init_translator_class(self): if self.translator_class is None: self.translator_class = WebSupportTranslator def prepare_writing(self, docnames): PickleHTMLBuilder.prepare_writing(self, docnames) self.globalcontext['no_search_suffix'] = True def write_doc(self, docname, doctree): 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): 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): self.indexer = self.search self.indexer.init_indexing(changed=docnames) def _render_page(self, pagename, addctx, templatename, event_arg=None): # 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)): 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): 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): # 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) def dump_search_index(self): self.indexer.finish_indexing()