3 # Process a list of Python and/or XML files containing SCons documentation.
5 # This script creates formatted lists of the Builders, functions, Tools
6 # or construction variables documented in the specified XML files.
8 # Dependening on the options, the lists are output in either
9 # DocBook-formatted generated XML files containing the summary text
10 # and/or .mod files contining the ENTITY definitions for each item,
11 # or in man-page-formatted output.
23 base_sys_path = [os.getcwd() + '/build/test-tar-gz/lib/scons'] + sys.path
26 Usage: scons-proc.py [--man|--xml]
27 [-b file(s)] [-f file(s)] [-t file(s)] [-v file(s)]
30 -b file(s) dump builder information to the specified file(s)
31 -f file(s) dump function information to the specified file(s)
32 -t file(s) dump tool information to the specified file(s)
33 -v file(s) dump variable information to the specified file(s)
34 --man print info in man page format, each -[btv] argument
36 --xml (default) print info in SML format, each -[btv] argument
37 is a pair of comma-separated .gen,.mod file names
40 opts, args = getopt.getopt(sys.argv[1:],
43 'man', 'xml', 'tools=', 'variables='])
52 if o in ['-b', '--builders']:
54 elif o in ['-f', '--functions']:
56 elif o in ['-h', '--help']:
57 sys.stdout.write(helpstr)
59 elif o in ['--man', '--xml']:
61 elif o in ['-t', '--tools']:
63 elif o in ['-v', '--variables']:
66 h = SConsDoc.SConsDocHandler()
67 saxparser = xml.sax.make_parser()
68 saxparser.setContentHandler(h)
69 saxparser.setErrorHandler(h)
81 _, ext = os.path.splitext(f)
83 dir, _ = os.path.split(f)
85 sys.path = [dir] + base_sys_path
86 module = SConsDoc.importfile(f)
87 h.set_file_info(f, len(xml_preamble.split('\n')))
89 content = module.__scons_doc__
90 except AttributeError:
93 del module.__scons_doc__
95 h.set_file_info(f, len(xml_preamble.split('\n')))
96 content = open(f).read()
98 content = content.replace('&', '&')
99 input = xml_preamble + content + xml_postamble
101 saxparser.parse(StringIO.StringIO(input))
103 sys.stderr.write("error in %s\n" % f)
108 THIS IS AN AUTOMATICALLY-GENERATED FILE. DO NOT EDIT.
112 Regular_Entities_Header = """\
120 Link_Entities_Header = """\
123 Entities that are links to the %s entries in the appendix.
129 def __init__(self, entries, **kw):
130 self.values = entries
131 for k, v in kw.items():
133 def fopen(self, name):
136 return open(name, 'w')
138 class SCons_XML_to_XML(SCons_XML):
139 def write(self, files):
140 gen, mod = string.split(files, ',')
143 def write_gen(self, filename):
146 f = self.fopen(filename)
147 for v in self.values:
148 f.write('\n<varlistentry id="%s%s">\n' %
149 (v.prefix, v.idfunc()))
150 for term in v.termfunc():
151 f.write('<term><%s>%s</%s></term>\n' %
152 (v.tag, term, v.tag))
153 f.write('<listitem>\n')
154 for chunk in v.summary.body:
157 s = map(lambda x: '&cv-link-%s;' % x, v.sets)
159 f.write('Sets: ' + ', '.join(s) + '.\n')
162 u = map(lambda x: '&cv-link-%s;' % x, v.uses)
164 f.write('Uses: ' + ', '.join(u) + '.\n')
166 f.write('</listitem>\n')
167 f.write('</varlistentry>\n')
168 def write_mod(self, filename):
169 description = self.values[0].description
172 f = self.fopen(filename)
175 f.write(Regular_Entities_Header % description)
177 for v in self.values:
178 f.write('<!ENTITY %s%s "<%s>%s</%s>">\n' %
179 (v.prefix, v.idfunc(),
180 v.tag, v.entityfunc(), v.tag))
181 if self.env_signatures:
183 for v in self.values:
184 f.write('<!ENTITY %senv-%s "<%s>env.%s</%s>">\n' %
185 (v.prefix, v.idfunc(),
186 v.tag, v.entityfunc(), v.tag))
190 f.write(Link_Entities_Header % description)
192 for v in self.values:
193 f.write('<!ENTITY %slink-%s \'<link linkend="%s%s"><%s>%s</%s></link>\'>\n' %
194 (v.prefix, v.idfunc(),
195 v.prefix, v.idfunc(),
196 v.tag, v.entityfunc(), v.tag))
197 if self.env_signatures:
199 for v in self.values:
200 f.write('<!ENTITY %slink-env-%s \'<link linkend="%s%s"><%s>env.%s</%s></link>\'>\n' %
201 (v.prefix, v.idfunc(),
202 v.prefix, v.idfunc(),
203 v.tag, v.entityfunc(), v.tag))
207 class SCons_XML_to_man(SCons_XML):
208 def write(self, filename):
211 f = self.fopen(filename)
213 for v in self.values:
214 chunks.extend(v.mansep())
215 chunks.extend(v.initial_chunks())
216 chunks.extend(map(str, v.summary.body))
218 body = ''.join(chunks)
219 body = string.replace(body, '<programlisting>', '.ES')
220 body = string.replace(body, '</programlisting>', '.EE')
221 body = string.replace(body, '\n</para>\n<para>\n', '\n\n')
222 body = string.replace(body, '<para>\n', '')
223 body = string.replace(body, '<para>', '\n')
224 body = string.replace(body, '</para>\n', '')
226 body = string.replace(body, '<variablelist>\n', '.RS 10\n')
227 # Handling <varlistentry> needs to be rationalized and made
228 # consistent. Right now, the <term> values map to arbitrary,
229 # ad-hoc idioms in the current man page.
230 body = re.compile(r'<varlistentry>\n<term><literal>([^<]*)</literal></term>\n<listitem>\n').sub(r'.TP 6\n.B \1\n', body)
231 body = re.compile(r'<varlistentry>\n<term><parameter>([^<]*)</parameter></term>\n<listitem>\n').sub(r'.IP \1\n', body)
232 body = re.compile(r'<varlistentry>\n<term>([^<]*)</term>\n<listitem>\n').sub(r'.HP 6\n.B \1\n', body)
233 body = string.replace(body, '</listitem>\n', '')
234 body = string.replace(body, '</varlistentry>\n', '')
235 body = string.replace(body, '</variablelist>\n', '.RE\n')
237 body = re.sub(r'\.EE\n\n+(?!\.IP)', '.EE\n.IP\n', body)
238 body = string.replace(body, '\n.IP\n\'\\"', '\n\n\'\\"')
239 body = re.sub('&(scons|SConstruct|SConscript|jar|Make);', r'\\fB\1\\fP', body)
240 body = string.replace(body, '&Dir;', r'\fBDir\fP')
241 body = string.replace(body, '⌖', r'\fItarget\fP')
242 body = string.replace(body, '&source;', r'\fIsource\fP')
243 body = re.sub('&b(-link)?-([^;]*);', r'\\fB\2\\fP()', body)
244 body = re.sub('&cv(-link)?-([^;]*);', r'$\2', body)
245 body = re.sub('&f(-link)?-env-([^;]*);', r'\\fBenv.\2\\fP()', body)
246 body = re.sub('&f(-link)?-([^;]*);', r'\\fB\2\\fP()', body)
247 body = re.sub(r'<(application|command|envar|filename|function|literal|option)>([^<]*)</\1>',
249 body = re.sub(r'<(classname|emphasis|varname)>([^<]*)</\1>',
251 body = re.compile(r'^\\f([BI])([^\\]* [^\\]*)\\fP\s*$', re.M).sub(r'.\1 "\2"', body)
252 body = re.compile(r'^\\f([BI])(.*)\\fP\s*$', re.M).sub(r'.\1 \2', body)
253 body = re.compile(r'^\\f([BI])(.*)\\fP(\S+)$', re.M).sub(r'.\1R \2 \3', body)
254 body = re.compile(r'^(\S+)\\f([BI])(.*)\\fP$', re.M).sub(r'.R\2 \1 \3', body)
255 body = string.replace(body, '<', '<')
256 body = string.replace(body, '>', '>')
257 body = re.sub(r'\\([^f])', r'\\\\\1', body)
258 body = re.compile("^'\\\\\\\\", re.M).sub("'\\\\", body)
259 body = re.compile(r'^\.([BI]R?) --', re.M).sub(r'.\1 \-\-', body)
260 body = re.compile(r'^\.([BI]R?) -', re.M).sub(r'.\1 \-', body)
261 body = re.compile(r'^\.([BI]R?) (\S+)\\\\(\S+)$', re.M).sub(r'.\1 "\2\\\\\\\\\2"', body)
262 body = re.compile(r'\\f([BI])-', re.M).sub(r'\\f\1\-', body)
266 def __init__(self, subject):
267 """Wrap an object as a Proxy object"""
268 self.__subject = subject
270 def __getattr__(self, name):
271 """Retrieve an attribute from the wrapped object. If the named
272 attribute doesn't exist, AttributeError is raised"""
273 return getattr(self.__subject, name)
276 """Retrieve the entire wrapped object"""
277 return self.__subject
279 def __cmp__(self, other):
280 if issubclass(other.__class__, self.__subject.__class__):
281 return cmp(self.__subject, other)
282 return cmp(self.__dict__, other.__dict__)
284 class Builder(Proxy):
285 description = 'builder'
291 return ['%s()' % self.name, 'env.%s()' % self.name]
292 def entityfunc(self):
295 return ['\n', "'\\" + '"'*69 + '\n']
296 def initial_chunks(self):
297 return [ '.IP %s\n' % t for t in self.termfunc() ]
299 class Function(Proxy):
300 description = 'function'
306 return ['%s()' % self.name, 'env.%s()' % self.name]
307 def entityfunc(self):
310 return ['\n', "'\\" + '"'*69 + '\n']
311 def initial_chunks(self):
313 arguments = self.arguments
314 except AttributeError:
317 for arg in arguments:
319 signature = arg.signature
320 except AttributeError:
322 if signature in ('both', 'global'):
323 result.append('.TP\n.RI %s%s\n' % (self.name, arg))
324 if signature in ('both', 'env'):
325 result.append('.TP\n.IR env .%s%s\n' % (self.name, arg))
333 return string.replace(self.name, '+', 'X')
336 def entityfunc(self):
340 def initial_chunks(self):
341 return ['.IP %s\n' % self.name]
343 class Variable(Proxy):
344 description = 'construction variable'
351 def entityfunc(self):
352 return '$' + self.name
355 def initial_chunks(self):
356 return ['.IP %s\n' % self.name]
358 if output_type == '--man':
359 processor_class = SCons_XML_to_man
360 elif output_type == '--xml':
361 processor_class = SCons_XML_to_XML
363 sys.stderr.write("Unknown output type '%s'\n" % output_type)
367 g = processor_class([ Builder(b) for b in sorted(h.builders.values()) ],
369 g.write(buildersfiles)
372 g = processor_class([ Function(b) for b in sorted(h.functions.values()) ],
374 g.write(functionsfiles)
377 g = processor_class([ Tool(t) for t in sorted(h.tools.values()) ],
378 env_signatures=False)
382 g = processor_class([ Variable(v) for v in sorted(h.cvars.values()) ],
383 env_signatures=False)
384 g.write(variablesfiles)
388 # indent-tabs-mode:nil
390 # vim: set expandtab tabstop=4 shiftwidth=4: