# -*- coding: utf-8 -*- """ Jinja Documenation Builder """ import sys import os import re from docutils import nodes, utils from docutils.core import publish_parts from docutils.writers import html4css1 from xml.sax import saxutils from jinja import Template, Context, StringLoader TEMPLATE = """ {{ title }} | Jinja Documentation

{{ title }}

{{ body }}
"""[1:] class DocumentationBuilder(object): def __init__(self, root, dest, rules): self.root = root self.rules = rules self.dest = dest def build(self): for folder, subfolders, files in os.walk(self.root): searchpath = [] if '.svn' in subfolders: subfolders.remove('.svn') for f in files: f = os.path.join(folder, f)[len(self.root):] for rule, params in self.rules: m = rule.search(f) if m is None: continue fid = f.rsplit('/', 1)[-1].rsplit('.')[0] output = self.render(fid, f, params) self.save(fid, f, output, params) break def render(self, fid, f, params): writer = PageWriter() parts = publish_parts( file(os.path.join(self.root, f)).read(), source_path=f, writer=writer, settings_overrides={'initial_header_level': 2} ) template = Template(TEMPLATE, StringLoader()) return template.render(Context({ 'title': parts['title'], 'body': parts['body'], 'toc': parts['toc'], 'root': fid == 'index', 'fid': fid })).encode('utf-8') def save(self, fid, f, output, params): folder = os.path.join(self.dest, params.get('dest', '')) filename = '%s.html' % fid try: os.makedirs(folder) except OSError: pass fp = file(os.path.join(folder, filename), 'w') fp.write(output) fp.close() class PageWriter(html4css1.Writer): def __init__(self): html4css1.Writer.__init__(self) self.translator_class = PageTranslator def translate(self): html4css1.Writer.translate(self) contents = self.build_contents(self.document) contents_doc = self.document.copy() contents_doc.children = contents contents_visitor = self.translator_class(contents_doc) contents_doc.walkabout(contents_visitor) toc = [] tmp = {} for item in contents_visitor.fragment: if not item or item in ('
  • ', '
  • '): continue elif item.startswith('': toc.append(tmp) tmp = {} else: tmp['caption'] = item self.parts['toc'] = toc def build_contents(self, node, level=0): level += 1 sections = [] i = len(node) - 1 while i >= 0 and isinstance(node[i], nodes.section): sections.append(node[i]) i -= 1 sections.reverse() entries = [] autonum = 0 depth = 4 # XXX FIXME for section in sections: title = section[0] entrytext = title try: reference = nodes.reference('', '', refid=section['ids'][0], *entrytext) except IndexError: continue ref_id = self.document.set_id(reference) entry = nodes.paragraph('', '', reference) item = nodes.list_item('', entry) if level < depth: subsects = self.build_contents(section, level) item += subsects entries.append(item) if entries: contents = nodes.bullet_list('', *entries) return contents else: return [] class PageTranslator(html4css1.HTMLTranslator): def visit_table(self, node): self.body.append(self.starttag(node, 'table', CLASS='docutils')) def visit_reference(self, node): if node.has_key('refuri'): href = node['refuri'] if ( self.settings.cloak_email_addresses and href.startswith('mailto:')): href = self.cloak_mailto(href) self.in_mailto = 1 else: assert node.has_key('refid'), \ 'References must have "refuri" or "refid" attribute.' href = '#' + node['refid'] if not '/' in href and href.endswith('.txt'): href = './%s.html' % (href[:-4]) atts = {'href': href, 'class': 'reference'} if not isinstance(node.parent, nodes.TextElement): assert len(node) == 1 and isinstance(node[0], nodes.image) atts['class'] += ' image-reference' self.body.append(self.starttag(node, 'a', '', **atts)) if __name__ == '__main__': app = DocumentationBuilder( 'source/', 'build/', [ (re.compile(r'\.txt$'), { 'dest': './', 'root': './' }) ] ) app.build()