summaryrefslogtreecommitdiff
path: root/bin/scons-proc.py
diff options
context:
space:
mode:
Diffstat (limited to 'bin/scons-proc.py')
-rw-r--r--bin/scons-proc.py371
1 files changed, 371 insertions, 0 deletions
diff --git a/bin/scons-proc.py b/bin/scons-proc.py
new file mode 100644
index 0000000..9567db8
--- /dev/null
+++ b/bin/scons-proc.py
@@ -0,0 +1,371 @@
+#!/usr/bin/env python
+#
+# Process a list of Python and/or XML files containing SCons documentation.
+#
+# This script creates formatted lists of the Builders, functions, Tools
+# or construction variables documented in the specified XML files.
+#
+# Depending on the options, the lists are output in either
+# DocBook-formatted generated XML files containing the summary text
+# and/or .mod files containing the ENTITY definitions for each item.
+#
+import getopt
+import os
+import re
+import string
+import sys
+try:
+ from io import StringIO # usable as of 2.6; takes unicode only
+except ImportError:
+ # No 'io' module or no StringIO in io
+ exec('from cStringIO import StringIO')
+
+import SConsDoc
+from SConsDoc import tf as stf
+
+base_sys_path = [os.getcwd() + '/build/test-tar-gz/lib/scons'] + sys.path
+
+helpstr = """\
+Usage: scons-proc.py [-b file(s)] [-f file(s)] [-t file(s)] [-v file(s)]
+ [infile ...]
+Options:
+ -b file(s) dump builder information to the specified file(s)
+ -f file(s) dump function 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)
+
+ Regard that each -[btv] argument is a pair of
+ comma-separated .gen,.mod file names.
+
+"""
+
+opts, args = getopt.getopt(sys.argv[1:],
+ "b:f:ht:v:",
+ ['builders=', 'help',
+ 'tools=', 'variables='])
+
+buildersfiles = None
+functionsfiles = None
+toolsfiles = None
+variablesfiles = None
+
+for o, a in opts:
+ if o in ['-b', '--builders']:
+ buildersfiles = a
+ elif o in ['-f', '--functions']:
+ functionsfiles = a
+ elif o in ['-h', '--help']:
+ sys.stdout.write(helpstr)
+ sys.exit(0)
+ elif o in ['-t', '--tools']:
+ toolsfiles = a
+ elif o in ['-v', '--variables']:
+ variablesfiles = a
+
+def parse_docs(args, include_entities=True):
+ h = SConsDoc.SConsDocHandler()
+ for f in args:
+ if include_entities:
+ try:
+ h.parseXmlFile(f)
+ except:
+ sys.stderr.write("error in %s\n" % f)
+ raise
+ else:
+ content = open(f).read()
+ if content:
+ try:
+ h.parseContent(content, include_entities)
+ except:
+ sys.stderr.write("error in %s\n" % f)
+ raise
+ return h
+
+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(object):
+ def __init__(self, entries, **kw):
+ self.values = entries
+ for k, v in kw.items():
+ setattr(self, k, v)
+
+ def fopen(self, name):
+ if name == '-':
+ return sys.stdout
+ return open(name, 'w')
+
+ def write(self, files):
+ gen, mod = files.split(',')
+ self.write_gen(gen)
+ self.write_mod(mod)
+
+ def write_gen(self, filename):
+ if not filename:
+ return
+ # Try to split off .gen filename
+ if filename.count(','):
+ fl = filename.split(',')
+ filename = fl[0]
+
+ # Start new XML file
+ root = stf.newXmlTree("variablelist")
+
+ for v in self.values:
+
+ ve = stf.newNode("varlistentry")
+ stf.setAttribute(ve, 'id', '%s%s' % (v.prefix, v.idfunc()))
+ for t in v.xml_terms():
+ stf.appendNode(ve, t)
+ vl = stf.newNode("listitem")
+ added = False
+ if v.summary is not None:
+ for s in v.summary:
+ added = True
+ stf.appendNode(vl, stf.copyNode(s))
+
+ if len(v.sets):
+ added = True
+ vp = stf.newNode("para")
+ s = ['&cv-link-%s;' % x for x in v.sets]
+ stf.setText(vp, 'Sets: ' + ', '.join(s) + '.')
+ stf.appendNode(vl, vp)
+ if len(v.uses):
+ added = True
+ vp = stf.newNode("para")
+ u = ['&cv-link-%s;' % x for x in v.uses]
+ stf.setText(vp, 'Uses: ' + ', '.join(u) + '.')
+ stf.appendNode(vl, vp)
+
+ # Still nothing added to this list item?
+ if not added:
+ # Append an empty para
+ vp = stf.newNode("para")
+ stf.appendNode(vl, vp)
+
+ stf.appendNode(ve, vl)
+ stf.appendNode(root, ve)
+
+ # Write file
+ f = self.fopen(filename)
+ stf.writeGenTree(root, f)
+
+ def write_mod(self, filename):
+ try:
+ description = self.values[0].description
+ except:
+ description = ""
+ if not filename:
+ return
+ # Try to split off .mod filename
+ if filename.count(','):
+ fl = filename.split(',')
+ filename = fl[1]
+ f = self.fopen(filename)
+ f.write(Warning)
+ f.write('\n')
+ f.write(Regular_Entities_Header % description)
+ f.write('\n')
+ for v in self.values:
+ f.write('<!ENTITY %s%s "<%s xmlns=\'%s\'>%s</%s>">\n' %
+ (v.prefix, v.idfunc(),
+ v.tag, SConsDoc.dbxsd, v.entityfunc(), v.tag))
+ if self.env_signatures:
+ f.write('\n')
+ for v in self.values:
+ f.write('<!ENTITY %senv-%s "<%s xmlns=\'%s\'>env.%s</%s>">\n' %
+ (v.prefix, v.idfunc(),
+ v.tag, SConsDoc.dbxsd, v.entityfunc(), v.tag))
+ f.write('\n')
+ f.write(Warning)
+ f.write('\n')
+ f.write(Link_Entities_Header % description)
+ f.write('\n')
+ for v in self.values:
+ f.write('<!ENTITY %slink-%s "<link linkend=\'%s%s\' xmlns=\'%s\'><%s>%s</%s></link>">\n' %
+ (v.prefix, v.idfunc(),
+ v.prefix, v.idfunc(), SConsDoc.dbxsd,
+ v.tag, v.entityfunc(), v.tag))
+ if self.env_signatures:
+ f.write('\n')
+ for v in self.values:
+ f.write('<!ENTITY %slink-env-%s "<link linkend=\'%s%s\' xmlns=\'%s\'><%s>env.%s</%s></link>">\n' %
+ (v.prefix, v.idfunc(),
+ v.prefix, v.idfunc(), SConsDoc.dbxsd,
+ v.tag, v.entityfunc(), v.tag))
+ f.write('\n')
+ f.write(Warning)
+
+class Proxy(object):
+ def __init__(self, subject):
+ """Wrap an object as a Proxy object"""
+ self.__subject = subject
+
+ def __getattr__(self, name):
+ """Retrieve an attribute from the wrapped object. If the named
+ attribute doesn't exist, AttributeError is raised"""
+ return getattr(self.__subject, name)
+
+ def get(self):
+ """Retrieve the entire wrapped object"""
+ return self.__subject
+
+ def __cmp__(self, other):
+ if issubclass(other.__class__, self.__subject.__class__):
+ return cmp(self.__subject, other)
+ return cmp(self.__dict__, other.__dict__)
+
+class SConsThing(Proxy):
+ def idfunc(self):
+ return self.name
+
+ def xml_terms(self):
+ e = stf.newNode("term")
+ stf.setText(e, self.name)
+ return [e]
+
+class Builder(SConsThing):
+ description = 'builder'
+ prefix = 'b-'
+ tag = 'function'
+
+ def xml_terms(self):
+ ta = stf.newNode("term")
+ b = stf.newNode(self.tag)
+ stf.setText(b, self.name+'()')
+ stf.appendNode(ta, b)
+ tb = stf.newNode("term")
+ b = stf.newNode(self.tag)
+ stf.setText(b, 'env.'+self.name+'()')
+ stf.appendNode(tb, b)
+ return [ta, tb]
+
+ def entityfunc(self):
+ return self.name
+
+class Function(SConsThing):
+ description = 'function'
+ prefix = 'f-'
+ tag = 'function'
+
+ def xml_terms(self):
+ if self.arguments is None:
+ a = stf.newNode("arguments")
+ stf.setText(a, '()')
+ arguments = [a]
+ else:
+ arguments = self.arguments
+ tlist = []
+ for arg in arguments:
+ signature = 'both'
+ if stf.hasAttribute(arg, 'signature'):
+ signature = stf.getAttribute(arg, 'signature')
+ s = stf.getText(arg).strip()
+ if signature in ('both', 'global'):
+ t = stf.newNode("term")
+ syn = stf.newNode("literal")
+ stf.setText(syn, '%s%s' % (self.name, s))
+ stf.appendNode(t, syn)
+ tlist.append(t)
+ if signature in ('both', 'env'):
+ t = stf.newNode("term")
+ syn = stf.newNode("literal")
+ stf.setText(syn, 'env.%s%s' % (self.name, s))
+ stf.appendNode(t, syn)
+ tlist.append(t)
+
+ if not tlist:
+ tlist.append(stf.newNode("term"))
+ return tlist
+
+ def entityfunc(self):
+ return self.name
+
+class Tool(SConsThing):
+ description = 'tool'
+ prefix = 't-'
+ tag = 'literal'
+
+ def idfunc(self):
+ return self.name.replace('+', 'X')
+
+ def entityfunc(self):
+ return self.name
+
+class Variable(SConsThing):
+ description = 'construction variable'
+ prefix = 'cv-'
+ tag = 'envar'
+
+ def entityfunc(self):
+ return '$' + self.name
+
+def write_output_files(h, buildersfiles, functionsfiles,
+ toolsfiles, variablesfiles, write_func):
+ if buildersfiles:
+ g = processor_class([ Builder(b) for b in sorted(h.builders.values()) ],
+ env_signatures=True)
+ write_func(g, buildersfiles)
+
+ if functionsfiles:
+ g = processor_class([ Function(b) for b in sorted(h.functions.values()) ],
+ env_signatures=True)
+ write_func(g, functionsfiles)
+
+ if toolsfiles:
+ g = processor_class([ Tool(t) for t in sorted(h.tools.values()) ],
+ env_signatures=False)
+ write_func(g, toolsfiles)
+
+ if variablesfiles:
+ g = processor_class([ Variable(v) for v in sorted(h.cvars.values()) ],
+ env_signatures=False)
+ write_func(g, variablesfiles)
+
+processor_class = SCons_XML
+
+# Step 1: Creating entity files for builders, functions,...
+print "Generating entity files..."
+h = parse_docs(args, False)
+write_output_files(h, buildersfiles, functionsfiles, toolsfiles,
+ variablesfiles, SCons_XML.write_mod)
+
+# Step 2: Validating all input files
+print "Validating files against SCons XSD..."
+if SConsDoc.validate_all_xml(['src']):
+ print "OK"
+else:
+ print "Validation failed! Please correct the errors above and try again."
+
+# Step 3: Creating actual documentation snippets, using the
+# fully resolved and updated entities from the *.mod files.
+print "Updating documentation for builders, tools and functions..."
+h = parse_docs(args, True)
+write_output_files(h, buildersfiles, functionsfiles, toolsfiles,
+ variablesfiles, SCons_XML.write)
+print "Done"
+
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4: