diff options
author | Dirk Baechle <dl9obn@darc.de> | 2013-05-03 22:30:28 (GMT) |
---|---|---|
committer | Dirk Baechle <dl9obn@darc.de> | 2013-05-03 22:30:28 (GMT) |
commit | 106a09dc814071594306eed8382fd30929e605ab (patch) | |
tree | 5cda0c7b94858ef25546d5ae059e90aaf23e9ce0 /bin/scons-doc.py | |
parent | 6af67d1431b5d534731ff0dc17ff306639a1a854 (diff) | |
download | SCons-106a09dc814071594306eed8382fd30929e605ab.zip SCons-106a09dc814071594306eed8382fd30929e605ab.tar.gz SCons-106a09dc814071594306eed8382fd30929e605ab.tar.bz2 |
- removed suffix= from 'scons_output_command ' and moved it
one up in the hierarchy to the 'scons_output' tag
Diffstat (limited to 'bin/scons-doc.py')
-rw-r--r-- | bin/scons-doc.py | 280 |
1 files changed, 53 insertions, 227 deletions
diff --git a/bin/scons-doc.py b/bin/scons-doc.py index ff06c04..95da5f3 100644 --- a/bin/scons-doc.py +++ b/bin/scons-doc.py @@ -22,31 +22,11 @@ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -# scons-doc.py - an SGML preprocessor for capturing SCons output -# and inserting it into examples in our DocBook -# documentation # -# Synopsis: -# -# scons-doc [OPTIONS] [.in files] -# -# When no input files are given, the folder doc/user/* is searched for .in files. -# -# Available options: -# -# -d, --diff create examples for the .in file and output a unified -# diff against the related .xml file -# -r, --run create examples for the .in file, but do not change -# any files -# -s, --simple_diff use a simpler output for the diff mode (no unified -# diff!) -# -u, --update create examples for the .in file and update the -# related .xml file -# -# This script looks for some SGML tags that describe SCons example +# This script looks for some XML tags that describe SCons example # configurations and commands to execute in those configurations, and # uses TestCmd.py to execute the commands and insert the output from -# those commands into the SGML that we output. This way, we can run a +# those commands into the XML that we output. This way, we can run a # script and update all of our example documentation output without # a lot of laborious by-hand checking. # @@ -89,8 +69,8 @@ # SCons output is generated from the following sort of tag: # # <scons_output example="ex1" os="posix"> -# <scons_output_command>scons -Q foo</scons_output_command> -# <scons_output_command>scons -Q foo</scons_output_command> +# <scons_output_command suffix="1">scons -Q foo</scons_output_command> +# <scons_output_command suffix="2">scons -Q foo</scons_output_command> # </scons_output> # # You tell it which example to use with the "example" attribute, and then @@ -98,7 +78,7 @@ # supply an "os" tag, which specifies the type of operating system this # example is intended to show; if you omit this, default value is "posix". # -# The generated SGML will show the command line (with the appropriate +# The generated XML will show the command line (with the appropriate # command-line prompt for the operating system), execute the command in # a temporary directory with the example files, capture the standard # output from SCons, and insert it into the text as appropriate. @@ -106,13 +86,10 @@ # can see if there are any problems executing the command. # -import optparse import os import re -import sgmllib import sys import time -import glob sys.path.append(os.path.join(os.getcwd(), 'QMTest')) sys.path.append(os.path.join(os.getcwd(), 'build', 'QMTest')) @@ -129,56 +106,6 @@ os.environ['SCONS_LIB_DIR'] = scons_lib_dir import TestCmd -# The regular expression that identifies entity references in the -# standard sgmllib omits the underscore from the legal characters. -# Override it with our own regular expression that adds underscore. -sgmllib.entityref = re.compile('&([a-zA-Z][-_.a-zA-Z0-9]*)[^-_a-zA-Z0-9]') - -# Classes for collecting different types of data we're interested in. -class DataCollector(object): - """Generic class for collecting data between a start tag and end - tag. We subclass for various types of tags we care about.""" - def __init__(self): - self.data = "" - def afunc(self, data): - self.data = self.data + data - -class Example(DataCollector): - """An SCons example. This is essentially a list of files that - will get written to a temporary directory to collect output - from one or more SCons runs.""" - def __init__(self): - DataCollector.__init__(self) - self.files = [] - self.dirs = [] - -class File(DataCollector): - """A file, that will get written out to a temporary directory - for one or more SCons runs.""" - def __init__(self, name): - DataCollector.__init__(self) - self.name = name - -class Directory(DataCollector): - """A directory, that will get created in a temporary directory - for one or more SCons runs.""" - def __init__(self, name): - DataCollector.__init__(self) - self.name = name - -class Output(DataCollector): - """Where the command output goes. This is essentially - a list of commands that will get executed.""" - def __init__(self): - DataCollector.__init__(self) - self.commandlist = [] - -class Command(DataCollector): - """A tag for where the command output goes. This is essentially - a list of commands that will get executed.""" - def __init__(self): - DataCollector.__init__(self) - self.output = None Prompt = { 'posix' : '% ', @@ -517,115 +444,51 @@ def ExecuteCommand(args, c, t, dict): func = lambda args, c, t, dict: [] return func(args[1:], c, t, dict) -class MySGML(sgmllib.SGMLParser): - """A subclass of the standard Python sgmllib SGML parser. - - This extends the standard sgmllib parser to recognize, and do cool - stuff with, the added tags that describe our SCons examples, - commands, and other stuff. - """ - def __init__(self, outfp): - sgmllib.SGMLParser.__init__(self) - self.examples = {} - self.afunclist = [] - self.outfp = outfp - - # The first set of methods here essentially implement pass-through - # handling of most of the stuff in an SGML file. We're really - # only concerned with the tags specific to SCons example processing, - # the methods for which get defined below. - - def handle_data(self, data): - try: - f = self.afunclist[-1] - except IndexError: - self.outfp.write(data) - else: - f(data) - def handle_comment(self, data): - self.outfp.write('<!--' + data + '-->') +def for_display(contents): + contents = contents.replace('__ROOT__', '') + contents = contents.replace('<', '<') + contents = contents.replace('>', '>') + return contents - def handle_decl(self, data): - self.outfp.write('<!' + data + '>') - def unknown_starttag(self, tag, attrs): - try: - f = self.example.afunc - except AttributeError: - f = self.outfp.write - if not attrs: - f('<' + tag + '>') - else: - f('<' + tag) - for name, value in attrs: - f(' ' + name + '=' + '"' + value + '"') - f('>') - - def unknown_endtag(self, tag): - self.outfp.write('</' + tag + '>') - - def unknown_entityref(self, ref): - self.outfp.write('&' + ref + ';') - - def unknown_charref(self, ref): - self.outfp.write('&#' + ref + ';') - - # Here is where the heavy lifting begins. The following methods - # handle the begin-end tags of our SCons examples. - - def for_display(self, contents): - contents = contents.replace('__ROOT__', '') - contents = contents.replace('<', '<') - contents = contents.replace('>', '>') - return contents - - - def start_scons_output(self, attrs): - t = [t for t in attrs if t[0] == 'example'] - if not t: - self.error("no <scons_output> example attribute found") - exname = t[0][1] - try: - e = self.examples[exname] - except KeyError: - self.error("unknown example name '%s'" % exname) - # Default values for an example. - o = Output() - o.preserve = None - o.os = 'posix' - o.tools = '' - o.e = e - # Locally-set. - for name, value in attrs: - setattr(o, name, value) - self.o = o - self.afunclist.append(o.afunc) - - def end_scons_output(self): - # The real raison d'etre for this script, this is where we - # actually execute SCons to fetch the output. - o = self.o - e = o.e +def create_scons_output(e): + # The real raison d'etre for this script, this is where we + # actually execute SCons to fetch the output. + + # Loop over all outputs for the example + for o in e.outputs: + # Create new test directory t = TestCmd.TestCmd(workdir='', combine=1) if o.preserve: t.preserve() t.subdir('ROOT', 'WORK') t.rootpath = t.workpath('ROOT').replace('\\', '\\\\') - + for d in e.dirs: dir = t.workpath('WORK', d.name) if not os.path.exists(dir): os.makedirs(dir) - + for f in e.files: + if f.isFileRef(): + continue + # + # Left-align file's contents, starting on the first + # non-empty line + # + data = f.content.split('\n') i = 0 - while f.data[i] == '\n': + # Skip empty lines + while data[i] == '': i = i + 1 - lines = f.data[i:].split('\n') + lines = data[i:] i = 0 + # Scan first line for the number of spaces + # that this block is indented while lines[0][i] == ' ': i = i + 1 + # Left-align block lines = [l[i:] for l in lines] path = f.name.replace('__ROOT__', t.rootpath) if not os.path.isabs(path): @@ -639,89 +502,52 @@ class MySGML(sgmllib.SGMLParser): t.write(path, content) if hasattr(f, 'chmod'): os.chmod(path, int(f.chmod, 0)) - - i = len(o.prefix) - while o.prefix[i-1] != '\n': - i = i - 1 - - self.outfp.write('<screen>' + o.prefix[:i]) - p = o.prefix[i:] - + # Regular expressions for making the doc output consistent, # regardless of reported addresses or Python version. - + # Massage addresses in object repr strings to a constant. address_re = re.compile(r' at 0x[0-9a-fA-F]*\>') - + # Massage file names in stack traces (sometimes reported as absolute # paths) to a consistent relative path. engine_re = re.compile(r' File ".*/src/engine/SCons/') - + # Python 2.5 changed the stack trace when the module is read # from standard input from read "... line 7, in ?" to # "... line 7, in <module>". file_re = re.compile(r'^( *File ".*", line \d+, in) \?$', re.M) - + # Python 2.6 made UserList a new-style class, which changes the # AttributeError message generated by our NodeList subclass. nodelist_re = re.compile(r'(AttributeError:) NodeList instance (has no attribute \S+)') - + for c in o.commandlist: - self.outfp.write(p + Prompt[o.os]) - d = c.data.replace('__ROOT__', '') - self.outfp.write('<userinput>' + d + '</userinput>\n') - - e = c.data.replace('__ROOT__', t.workpath('ROOT')) - args = e.split() + # Open new output file + fpath = os.path.join(SConsExamples.generated_examples, + e.name+'_'+c.suffix+'.out','w') + outfp = open(fpath) + outfp.write(Prompt[o.os]) + d = c.cmd.replace('__ROOT__', '') + outfp.write('<userinput>' + d + '</userinput>\n') + + cmd_work = c.cmd.replace('__ROOT__', t.workpath('ROOT')) + args = cmd_work.split() lines = ExecuteCommand(args, c, t, {'osname':o.os, 'tools':o.tools}) content = None if c.output: content = c.output elif lines: - content = ( '\n' + p).join(lines) + content = '\n'.join(lines) if content: content = address_re.sub(r' at 0x700000>', content) content = engine_re.sub(r' File "bootstrap/src/engine/SCons/', content) content = file_re.sub(r'\1 <module>', content) content = nodelist_re.sub(r"\1 'NodeList' object \2", content) - content = self.for_display(content) - self.outfp.write(p + content + '\n') - - if o.data[0] == '\n': - o.data = o.data[1:] - self.outfp.write(o.data + '</screen>') - delattr(self, 'o') - self.afunclist = self.afunclist[:-1] - - def start_scons_output_command(self, attrs): - try: - o = self.o - except AttributeError: - self.error("<scons_output_command> tag outside of <scons_output>") - try: - o.prefix - except AttributeError: - o.prefix = o.data - o.data = "" - c = Command() - for name, value in attrs: - setattr(c, name, value) - o.commandlist.append(c) - self.afunclist.append(c.afunc) - - def end_scons_output_command(self): - self.o.data = "" - self.afunclist = self.afunclist[:-1] - - - -def main(): - argv = sys.argv - - -if __name__ == "__main__": - sys.exit(main()) - + content = for_display(content) + outfp.write(content + '\n') + outfp.close() + # Local Variables: # tab-width:4 # indent-tabs-mode:nil |