Edgewall Software

Changes between Initial Version and Version 1 of GenshiRecipes/RecursiveIncludeScanner


Ignore:
Timestamp:
Aug 20, 2006, 5:16:04 PM (18 years ago)
Author:
robinbryce@…
Comment:

Thanks for all the help on IRC :-)

Legend:

Unmodified
Added
Removed
Modified
  • GenshiRecipes/RecursiveIncludeScanner

    v1 v1  
     1== Motivation ==
     2
     3This recipe evolved after discussion of another recipe, [wiki:MarkupRecipes/SconsXIncludeScanner Implicit dependencies with scons], on [IrcChannel #markup]. The solution, and the source code used in this recipe, was kindly provided by Cristopher Lenz (aka:cmlenz).
     4
     5When working with a relatively large set of xml sources that make use of XIncludes there is a common question that comes in two forms:
     6
     7 * What files '''will''' be included by a particular source ?
     8 * What files '''were''' included by a particular source ?
     9
     10This recipe seeks to address the first sense as far as is possible. [wiki:MarkupRecipes/SconsXIncludeScanner Implicit dependencies with scons] could be used as a starting point for answering the second.
     11
     12== Code ==
     13
     14scan-includes.py:
     15{{{
     16#!python
     17"""Recursive xincludes scanner for Markup
     18
     19This solution was kindly provided by Christopher Lenz <cmlenz@gmx.de>
     20"""
     21
     22import os,sys
     23from markup.core import START
     24from markup.filters import IncludeFilter
     25from markup.input import XMLParser
     26 
     27def scan_xincludes(filename):
     28    basedir, filename = os.path.split(filename)
     29    namespace = IncludeFilter.NAMESPACE
     30    includes = set([filename])
     31    notfound = set()
     32    visited = set()
     33 
     34    def collect(filename):
     35        try:
     36            fileobj = open(os.path.join(basedir, filename), 'U')
     37            try:
     38                for kind, data, pos in XMLParser(fileobj, filename=filename):
     39                    if kind is START:
     40                        tag, attrib = data
     41                        if tag in namespace and tag.localname == 'include':
     42                            includes.add(attrib.get('href'))
     43            finally:
     44                fileobj.close()
     45            visited.add(filename)
     46        except IOError:
     47            includes.remove(filename)
     48            notfound.add(filename)
     49
     50 
     51    while len(includes) > len(visited):
     52        for filename in includes - visited:
     53            collect(filename)
     54 
     55    return includes,notfound
     56 
     57 
     58if __name__ == '__main__':
     59    includes,notfound = scan_xincludes(sys.argv[1])
     60    for include in includes:
     61        print include
     62    if notfound:
     63        print "WARNING: the follwing include hrefs were not found:"
     64        for ref in notfound:
     65            print ref
     66}}}
     67
     68== Limitations ==
     69
     70No consideration is given to conditional includes. All includes, that refer to existent files, are listed. If you make use of conditional includes, this scanner will yield false positives.
     71
     72No attempt is made to handle includes that make use of dynamically generated file names. Any such references will end up in the 'notfound' set.
     73
     74So this recipe can only reliably answer "What files '''may''' be included by a particular source?"
     75
     76== Discussion ==
     77
     78Markup syntax supports conditional includes and includes whose target file names are dynamic. The latter makes it impossible to know for certain "before the show", which files '''will''' be included. Conditional includes that depend on static state could be determined before the show. This is, however, far from trivial.
     79
     80Integrating Markup, or anything like it, into a build system is a typical scenario that prompts these questions. Typically you will want automatic dependencies, and reliable, but minimal, rebuilds in the event that any of your source files are changed.
     81
     82For build system dependencies the consequence of false positives is often acceptable. The consequence being more sources are rebuilt than strictly necessary. And, answering the latter form of the question, "what files '''were''' included" is usually sufficient for ensuring re-builds are both minimal and correct.
     83
     84