""" A class that deals with generating the website. TODO: add a way to syntax-color embedded source code, possibly based on: http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/252170 """ import os, shutil from genshi.template import MarkupTemplate, TemplateLoader from docutils.core import publish_parts gTemplateDir = os.path.join( os.path.dirname(os.path.dirname(os.path.abspath(__file__))), 'templates') gTemplateIncludes = os.path.join(gTemplateDir, 'global') gTopMenu=[ ('Home', '/index.html'), ('Documentation', '/documentation/index.html'), ('Development', '/development.html'), ('Download', '/downloads.html'), ('Examples', '/examples/index.html'), ('Mailing lists', 'http://sourceforge.net/mail/?group_id=14534'), ] gBottomMenu=[ ] class SiteGenerator (object): def __init__(self, templateRoot, siteRoot): self.templateRoot = templateRoot self.siteRoot = siteRoot def _makeGlobals(self, outputpath): """ Return the dictionary of global functions/constants for the template. The output of the template will be written als 'outputpath' (relative to the site root). Note that this function does *not* write to the filesystem """ def url(path): """ Return 'path' as a relative URL. 'Path' is supposed to be site-relative (that is '/some/path') and this function returns a path relative to the current page. """ if path.startswith('http://') or path.startswith('https://'): return path if not path.startswith('/'): return path while path.startswith('/'): path = path[1:] dirpath = os.path.dirname(outputpath) if dirpath == '.' or dirpath == '': return path else: rootpath = os.path.sep.join(['..'] * (1+dirpath.count(os.path.sep))) return os.path.join(rootpath, path) return dict( url=url, topmenu=gTopMenu, bottommenu=gBottomMenu, ) def _makeLoader(self, _templateFn): #return TemplateLoader([ os.path.dirname(_templateFn), gTemplateIncludes, ]) return TemplateLoader(gTemplateIncludes) def localPathForSitePath(self, sitePath): while sitePath.startswith(os.sep): sitePath = sitePath[1:] return os.path.join(self.siteRoot, sitePath) def emitHTML(self, _htmlpath, _templateFn, **kwds): """ read the specified template, perform template instantantiation and write the result to _htmlpath. Any keyword arguments are used to fill in the blanks in the template. """ while _htmlpath.startswith(os.sep): _htmlpath = _htmlpath[1:] outfn = os.path.join(self.siteRoot, _htmlpath) infn = os.path.join(gTemplateDir, _templateFn) outdn = os.path.dirname(outfn) if not os.path.exists(outdn): os.makedirs(outdn) tmpl = MarkupTemplate(open(infn, 'r').read(), loader=self._makeLoader(infn), lookup='strict') variables = self._makeGlobals(_htmlpath) variables.update(kwds) stream = tmpl.generate(**variables) fp = open(outfn, "w") fp.write(stream.render('html')) fp.close() def copyReST(self, _infn, _outfn, template='static-rest.html', **kwds): input = open(_infn, 'rU').read() output = publish_parts( source=input, source_path=_infn, writer_name='html', settings_overrides=dict( input_encoding='utf-8', initial_header_level=2, )) kwds.update(output) self.emitHTML(_outfn, template, **kwds) def copy(self, input, output): """ Copy 'input' to 'output' (where 'output' is a path relative to the site root). If 'input' is a directory it is copied recursively, version managment turds are ignored. """ output = self.localPathForSitePath(output) if not os.path.exists(os.path.dirname(output)): os.makedirs(os.path.dirname(output)) if os.path.isfile(input): data = open(input, 'rb') open(output, 'wb').write(data) data = None else: if os.path.exists(output): shutil.rmtree(output) os.mkdir(output) for dirpath, dirnames, filenames in os.walk(input): for dn in ('.svn', 'CVS'): if dn in dirnames: dirnames.remove(dn) if dirpath == input: relpath = '.' else: relpath = output[len(input):] for dn in dirnames: os.mkdir(os.path.join(output, relpath, dn)) for fn in filenames: data = open(os.path.join(dirpath, fn), 'rb').read() open(os.path.join(output, relpath, fn), 'wb').write(data) data = None