diff options
Diffstat (limited to 'bin/scons-proc.py')
-rw-r--r-- | bin/scons-proc.py | 283 |
1 files changed, 283 insertions, 0 deletions
diff --git a/bin/scons-proc.py b/bin/scons-proc.py new file mode 100644 index 0000000..cc3b085 --- /dev/null +++ b/bin/scons-proc.py @@ -0,0 +1,283 @@ +#!/usr/bin/env python +# +# Process a list of Python and/or XML files containing SCons documentation. +# +# This script creates formatted lists of the Builders, Tools or +# construction variables documented in the specified XML files. +# +# Dependening on the options, the lists are output in either +# DocBook-formatted generated XML files containing the summary text +# and/or .mod files contining the ENTITY definitions for each item, +# or in man-page-formatted output. +# +import getopt +import os.path +import re +import string +import StringIO +import sys +import xml.sax + +import SConsDoc + +base_sys_path = [os.getcwd() + '/build/test-tar-gz/lib/scons'] + sys.path + +helpstr = """\ +Usage: scons-proc.py [--man|--xml] + [-b file(s)] [-t file(s)] [-v file(s)] [infile ...] +Options: + -b file(s) dump builder information to the specified file(s) + -t file(s) dump tool information to the specified file(s) + -v file(s) dump variable information to the specified file(s) + --man print info in man page format, each -[btv] argument + is a single file name + --xml (default) print info in SML format, each -[btv] argument + is a pair of comma-separated .gen,.mod file names +""" + +opts, args = getopt.getopt(sys.argv[1:], + "b:ht:v:", + ['builders=', 'help', + 'man', 'xml', 'tools=', 'variables=']) + +buildersfiles = None +output_type = '--xml' +toolsfiles = None +variablesfiles = None + +for o, a in opts: + if o in ['-b', '--builders']: + buildersfiles = a + elif o in ['-h', '--help']: + sys.stdout.write(helpstr) + sys.exit(0) + elif o in ['--man', '--xml']: + output_type = o + elif o in ['-t', '--tools']: + toolsfiles = a + elif o in ['-v', '--variables']: + variablesfiles = a + +h = SConsDoc.SConsDocHandler() +saxparser = xml.sax.make_parser() +saxparser.setContentHandler(h) +saxparser.setErrorHandler(h) + +xml_preamble = """\ +<?xml version="1.0"?> +<scons_doc> +""" + +xml_postamble = """\ +</scons_doc> +""" + +for f in args: + _, ext = os.path.splitext(f) + if ext == '.py': + dir, _ = os.path.split(f) + if dir: + sys.path = [dir] + base_sys_path + module = SConsDoc.importfile(f) + h.set_file_info(f, len(xml_preamble.split('\n'))) + try: + content = module.__scons_doc__ + except AttributeError: + content = None + else: + del module.__scons_doc__ + else: + h.set_file_info(f, len(xml_preamble.split('\n'))) + content = open(f).read() + if content: + content = content.replace('&', '&') + input = xml_preamble + content + xml_postamble + try: + saxparser.parse(StringIO.StringIO(input)) + except: + sys.stderr.write("error in %s\n" % f) + raise + +Warning = """\ +<!-- +THIS IS AN AUTOMATICALLY-GENERATED FILE. DO NOT EDIT. +--> +""" + +Regular_Entities_Header = """\ +<!-- + + Regular %s entities. + +--> +""" + +Link_Entities_Header = """\ +<!-- + + Entities that are links to the %s entries in the appendix. + +--> +""" + +class SCons_XML: + def __init__(self, entries, **kw): + values = entries.values() + values.sort() + self.values = values + for k, v in kw.items(): + setattr(self, k, v) + def fopen(self, name): + if name == '-': + return sys.stdout + return open(name, 'w') + +class SCons_XML_to_XML(SCons_XML): + def write(self, files): + gen, mod = string.split(files, ',') + g.write_gen(gen) + g.write_mod(mod) + def write_gen(self, filename): + if not filename: + return + f = self.fopen(filename) + for v in self.values: + f.write('\n<varlistentry id="%s%s">\n' % + (self.prefix, self.idfunc(v.name))) + for term in self.termfunc(v.name): + f.write('<term><%s>%s</%s></term>\n' % + (self.tag, term, self.tag)) + f.write('<listitem>\n') + for chunk in v.summary.body: + f.write(str(chunk)) + if v.sets: + s = map(lambda x: '&cv-link-%s;' % x, v.sets) + f.write('<para>\n') + f.write('Sets: ' + ', '.join(s) + '.\n') + f.write('</para>\n') + if v.uses: + u = map(lambda x: '&cv-link-%s;' % x, v.uses) + f.write('<para>\n') + f.write('Uses: ' + ', '.join(u) + '.\n') + f.write('</para>\n') + f.write('</listitem>\n') + f.write('</varlistentry>\n') + def write_mod(self, filename): + if not filename: + return + f = self.fopen(filename) + f.write(Warning) + f.write('\n') + f.write(Regular_Entities_Header % self.description) + f.write('\n') + for v in self.values: + f.write('<!ENTITY %s%s "<%s>%s</%s>">\n' % + (self.prefix, self.idfunc(v.name), + self.tag, self.entityfunc(v.name), self.tag)) + f.write('\n') + f.write(Warning) + f.write('\n') + f.write(Link_Entities_Header % self.description) + f.write('\n') + for v in self.values: + f.write('<!ENTITY %slink-%s \'<link linkend="%s%s"><%s>%s</%s></link>\'>\n' % + (self.prefix, self.idfunc(v.name), + self.prefix, self.idfunc(v.name), + self.tag, self.entityfunc(v.name), self.tag)) + f.write('\n') + f.write(Warning) + +class SCons_XML_to_man(SCons_XML): + def mansep(self): + return ['\n'] + def initial_chunks(self, name): + return [name] + def write(self, filename): + if not filename: + return + f = self.fopen(filename) + chunks = [] + for v in self.values: + chunks.extend(self.mansep()) + for n in self.initial_chunks(v.name): + chunks.append('.IP %s\n' % n) + chunks.extend(map(str, v.summary.body)) + + body = ''.join(chunks) + body = string.replace(body, '<programlisting>', '.ES') + body = string.replace(body, '</programlisting>', '.EE') + body = string.replace(body, '\n</para>\n<para>\n', '\n\n') + body = string.replace(body, '<para>\n', '') + body = string.replace(body, '<para>', '\n') + body = string.replace(body, '</para>\n', '') + body = re.sub('\.EE\n\n+(?!\.IP)', '.EE\n.IP\n', body) + body = re.sub('&(scons|SConstruct|SConscript|jar);', r'\\fB\1\\fP', body) + body = string.replace(body, '&Dir;', r'\fBDir\fP') + body = string.replace(body, '⌖', r'\fItarget\fP') + body = string.replace(body, '&source;', r'\fIsource\fP') + body = re.sub('&b(-link)?-([^;]*);', r'\\fB\2\\fP()', body) + body = re.sub('&cv(-link)?-([^;]*);', r'$\2', body) + body = re.sub(r'<(command|envar|filename|literal|option)>([^<]*)</\1>', + r'\\fB\2\\fP', body) + body = re.sub(r'<(classname|emphasis|varname)>([^<]*)</\1>', + r'\\fI\2\\fP', body) + body = re.compile(r'^\\f([BI])(.*)\\fP\s*$', re.M).sub(r'.\1 \2', body) + body = re.compile(r'^\\f([BI])(.*)\\fP(\S+)', re.M).sub(r'.\1R \2 \3', body) + body = string.replace(body, '<', '<') + body = string.replace(body, '>', '>') + body = re.sub(r'\\([^f])', r'\\\\\1', body) + body = re.compile("^'\\\\\\\\", re.M).sub("'\\\\", body) + body = re.compile(r'^\.([BI]R?) -', re.M).sub(r'.\1 \-', body) + body = re.compile(r'^\.([BI]R?) (\S+)\\\\(\S+)', re.M).sub(r'.\1 "\2\\\\\\\\\2"', body) + body = re.compile(r'\\f([BI])-', re.M).sub(r'\\f\1\-', body) + f.write(body) + +if output_type == '--man': + processor_class = SCons_XML_to_man +elif output_type == '--xml': + processor_class = SCons_XML_to_XML +else: + sys.stderr.write("Unknown output type '%s'\n" % output_type) + sys.exit(1) + +if buildersfiles: + g = processor_class(h.builders, + description = 'builder', + prefix = 'b-', + tag = 'function', + idfunc = lambda x: x, + termfunc = lambda x: [x+'()', 'env.'+x+'()'], + entityfunc = lambda x: x) + + g.mansep = lambda: ['\n', "'\\" + '"'*69 + '\n'] + g.initial_chunks = lambda n: [n+'()', 'env.'+n+'()'] + + g.write(buildersfiles) + +if toolsfiles: + g = processor_class(h.tools, + description = 'tool', + prefix = 't-', + tag = 'literal', + idfunc = lambda x: string.replace(x, '+', 'X'), + termfunc = lambda x: [x], + entityfunc = lambda x: x) + + g.write(toolsfiles) + +if variablesfiles: + g = processor_class(h.cvars, + description = 'construction variable', + prefix = 'cv-', + tag = 'envar', + idfunc = lambda x: x, + termfunc = lambda x: [x], + entityfunc = lambda x: '$'+x) + + g.write(variablesfiles) + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: |