Edgewall Software


Genshi Recipes: XInclude scanner for SCons


You need to integrate Genshi sources into an  SCons based build system and you would like implicit dependencies for xi:include directives.


import sys
from genshi.filters import IncludeFilter
from genshi.template import Template,TemplateLoader

def genshi_xinclude_scan(node, env, path, arg):
    t = Template(node.get_contents())
    loader = TemplateLoader('.'.split())
    t.filters.insert(0, IncludeFilter(loader))
    return loader._cache.keys()

markup_scanner = Scanner(
    skeys = '.xhtml .html .xml'.split())
scanners = Environment().Dictionary('SCANNERS')
env = Environment(SCANNERS = scanners + [genshi_scanner])

env.Command('page-out', 'page.html', './render $SOURCES $TARGET')

So, assuming page.html references another file, say base.html, using the XInclude recipe, any edit to base.html will cause scons to consider page-out to be out of date. After an edit of either page.html or base.html scons -f SConscript will be sufficient to bring page-out up to date.

render is a trivial wrapper script that renders the final output using Genshi for a single source file. Mine looks like this::

import sys
    import wingdbstub
except ImportError:
from genshi.filters import IncludeFilter
from genshi.template import Template, TemplateLoader

t = Template(file(sys.argv[1]).read())
t.filters.insert(0, IncludeFilter(TemplateLoader('.'.split())))
outf = sys.stdout
if len(sys.argv) > 2:
    outf = file(sys.argv[2], 'w')
print >> outf, t.generate()

There may be slicker ways of doing this. If you know them then please update this recipe.

See also: GenshiRecipes, GenshiRecipes/RecursiveIncludeScanner