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 # Depending on the options, the lists are output in either
9 # DocBook-formatted generated XML files containing the summary text
10 # and/or .mod files containing the ENTITY definitions for each item.
17 from SConsDoc
import tf
as stf
19 base_sys_path
= [os
.getcwd() + '/build/test-tar-gz/lib/scons'] + sys
.path
22 Usage: scons-proc.py [-b file(s)] [-f file(s)] [-t file(s)] [-v file(s)]
25 -b file(s) dump builder information to the specified file(s)
26 -f file(s) dump function information to the specified file(s)
27 -t file(s) dump tool information to the specified file(s)
28 -v file(s) dump variable information to the specified file(s)
30 The "files" argument following a -[bftv] argument is expected to
31 be a comma-separated pair of names like: foo.gen,foo.mod
35 opts
, args
= getopt
.getopt(sys
.argv
[1:],
38 'tools=', 'variables='])
46 if o
in ['-b', '--builders']:
48 elif o
in ['-f', '--functions']:
50 elif o
in ['-h', '--help']:
51 sys
.stdout
.write(helpstr
)
53 elif o
in ['-t', '--tools']:
55 elif o
in ['-v', '--variables']:
58 def parse_docs(args
, include_entities
=True):
59 h
= SConsDoc
.SConsDocHandler()
64 except Exception as e
:
65 print("error parsing %s\n" % f
, file=sys
.stderr
)
66 print(str(e
), file=sys
.stderr
)
69 # mode we read (text/bytes) has to match handling in SConsDoc
70 with
open(f
, 'r') as fp
:
74 h
.parseContent(content
, include_entities
)
75 except Exception as e
:
76 print("error parsing %s\n" % f
, file=sys
.stderr
)
77 print(str(e
), file=sys
.stderr
)
83 THIS IS AN AUTOMATICALLY-GENERATED FILE. DO NOT EDIT.
87 Regular_Entities_Header
= """\
95 Link_Entities_Header
= """\
98 Entities that are links to the %s entries
104 def __init__(self
, entries
, **kw
):
105 self
.values
= entries
106 for k
, v
in kw
.items():
109 def fopen(self
, name
, mode
='w'):
112 return open(name
, mode
)
114 def write(self
, files
):
115 gen
, mod
= files
.split(',')
119 def write_gen(self
, filename
):
122 # Try to split off .gen filename
123 if filename
.count(','):
124 fl
= filename
.split(',')
128 root
= stf
.newXmlTree("variablelist")
130 for v
in self
.values
:
132 ve
= stf
.newNode("varlistentry")
133 stf
.setAttribute(ve
, 'id', '%s%s' % (v
.prefix
, v
.idfunc()))
134 for t
in v
.xml_terms():
135 stf
.appendNode(ve
, t
)
136 vl
= stf
.newNode("listitem")
138 if v
.summary
is not None:
141 stf
.appendNode(vl
, stf
.copyNode(s
))
145 vp
= stf
.newNode("para")
146 stf
.setText(vp
, 'Sets: ')
147 for x
in v
.sets
[:-1]:
148 stf
.appendCvLink(vp
, x
, ', ')
149 stf
.appendCvLink(vp
, v
.sets
[-1], '.')
150 stf
.appendNode(vl
, vp
)
154 vp
= stf
.newNode("para")
155 stf
.setText(vp
, 'Uses: ')
156 for x
in v
.uses
[:-1]:
157 stf
.appendCvLink(vp
, x
, ', ')
158 stf
.appendCvLink(vp
, v
.uses
[-1], '.')
159 stf
.appendNode(vl
, vp
)
161 # Still nothing added to this list item?
163 # Append an empty para
164 vp
= stf
.newNode("para")
165 stf
.appendNode(vl
, vp
)
167 stf
.appendNode(ve
, vl
)
168 stf
.appendNode(root
, ve
)
171 f
= self
.fopen(filename
)
172 stf
.writeGenTree(root
, f
)
175 def write_mod(self
, filename
):
177 description
= self
.values
[0].description
182 # Try to split off .mod filename
183 if filename
.count(','):
184 fl
= filename
.split(',')
186 f
= self
.fopen(filename
)
189 f
.write(Regular_Entities_Header
% description
)
191 for v
in self
.values
:
192 f
.write('<!ENTITY %s%s "<%s xmlns=\'%s\'>%s</%s>">\n' %
193 (v
.prefix
, v
.idfunc(),
194 v
.tag
, SConsDoc
.dbxsd
, v
.entityfunc(), v
.tag
))
195 if self
.env_signatures
:
197 for v
in self
.values
:
198 f
.write('<!ENTITY %senv-%s "<%s xmlns=\'%s\'>env.%s</%s>">\n' %
199 (v
.prefix
, v
.idfunc(),
200 v
.tag
, SConsDoc
.dbxsd
, v
.entityfunc(), v
.tag
))
202 f
.write(Link_Entities_Header
% description
)
204 for v
in self
.values
:
205 f
.write('<!ENTITY %slink-%s "<link linkend=\'%s%s\' xmlns=\'%s\'><%s>%s</%s></link>">\n' %
206 (v
.prefix
, v
.idfunc(),
207 v
.prefix
, v
.idfunc(), SConsDoc
.dbxsd
,
208 v
.tag
, v
.entityfunc(), v
.tag
))
209 if self
.env_signatures
:
211 for v
in self
.values
:
212 f
.write('<!ENTITY %slink-env-%s "<link linkend=\'%s%s\' xmlns=\'%s\'><%s>env.%s</%s></link>">\n' %
213 (v
.prefix
, v
.idfunc(),
214 v
.prefix
, v
.idfunc(), SConsDoc
.dbxsd
,
215 v
.tag
, v
.entityfunc(), v
.tag
))
219 def __init__(self
, subject
):
220 """Wrap an object as a Proxy object"""
221 self
.__subject
= subject
223 def __getattr__(self
, name
):
224 """Retrieve an attribute from the wrapped object.
226 If the named attribute doesn't exist, AttributeError is raised
228 return getattr(self
.__subject
, name
)
231 """Retrieve the entire wrapped object"""
232 return self
.__subject
234 def __eq__(self
, other
):
235 if issubclass(other
.__class
__, self
.__subject
.__class
__):
236 return self
.__subject
== other
237 return self
.__dict
__ == other
.__dict
__
239 ## def __lt__(self, other):
240 ## if issubclass(other.__class__, self.__subject.__class__):
241 ## return self.__subject < other
242 ## return self.__dict__ < other.__dict__
244 class SConsThing(Proxy
):
245 """Base class for the SConsDoc special elements"""
250 e
= stf
.newNode("term")
251 stf
.setText(e
, self
.name
)
254 class Builder(SConsThing
):
255 """Generate the descriptions and entities for <builder> elements"""
256 description
= 'builder'
261 """emit xml for an scons builder
263 builders don't show a full signature, just func()
265 # build term for global function
266 gterm
= stf
.newNode("term")
267 func
= stf
.newSubNode(gterm
, Builder
.tag
)
268 stf
.setText(func
, self
.name
)
269 stf
.setTail(func
, '()')
271 # build term for env. method
272 mterm
= stf
.newNode("term")
273 inst
= stf
.newSubNode(mterm
, "replaceable")
274 stf
.setText(inst
, "env")
275 stf
.setTail(inst
, ".")
276 # we could use <function> here, but it's a "method"
277 meth
= stf
.newSubNode(mterm
, "methodname")
278 stf
.setText(meth
, self
.name
)
279 stf
.setTail(meth
, '()')
281 return [gterm
, mterm
]
283 def entityfunc(self
):
286 class Function(SConsThing
):
287 """Generate the descriptions and entities for <scons_function> elements"""
288 description
= 'function'
293 """emit xml for an scons function
295 The signature attribute controls whether to emit the
296 global function, the environment method, or both.
298 if self
.arguments
is None:
299 a
= stf
.newNode("arguments")
303 arguments
= self
.arguments
305 for arg
in arguments
:
307 if stf
.hasAttribute(arg
, 'signature'):
308 signature
= stf
.getAttribute(arg
, 'signature')
309 sig
= stf
.getText(arg
).strip()[1:-1] # strip (), temporarily
310 if signature
in ('both', 'global'):
311 # build term for global function
312 gterm
= stf
.newNode("term")
313 func
= stf
.newSubNode(gterm
, Function
.tag
)
314 stf
.setText(func
, self
.name
)
316 # if there are parameters, use that entity
317 stf
.setTail(func
, "(")
318 s
= stf
.newSubNode(gterm
, "parameter")
322 stf
.setTail(func
, "()")
324 if signature
in ('both', 'env'):
325 # build term for env. method
326 mterm
= stf
.newNode("term")
327 inst
= stf
.newSubNode(mterm
, "replaceable")
328 stf
.setText(inst
, "env")
329 stf
.setTail(inst
, ".")
330 # we could use <function> here, but it's a "method"
331 meth
= stf
.newSubNode(mterm
, "methodname")
332 stf
.setText(meth
, self
.name
)
334 # if there are parameters, use that entity
335 stf
.setTail(meth
, "(")
336 s
= stf
.newSubNode(mterm
, "parameter")
340 stf
.setTail(meth
, "()")
344 tlist
.append(stf
.newNode("term"))
347 def entityfunc(self
):
350 class Tool(SConsThing
):
351 """Generate the descriptions and entities for <tool> elements"""
357 return self
.name
.replace('+', 'X')
359 def entityfunc(self
):
362 class Variable(SConsThing
):
363 """Generate the descriptions and entities for <cvar> elements"""
364 description
= 'construction variable'
369 term
= stf
.newNode("term")
370 var
= stf
.newSubNode(term
, Variable
.tag
)
371 stf
.setText(var
, self
.name
)
374 def entityfunc(self
):
375 return '$' + self
.name
377 def write_output_files(h
, buildersfiles
, functionsfiles
,
378 toolsfiles
, variablesfiles
, write_func
):
380 g
= processor_class([Builder(b
) for b
in sorted(h
.builders
.values())],
382 write_func(g
, buildersfiles
)
385 g
= processor_class([Function(b
) for b
in sorted(h
.functions
.values())],
387 write_func(g
, functionsfiles
)
390 g
= processor_class([Tool(t
) for t
in sorted(h
.tools
.values())],
391 env_signatures
=False)
392 write_func(g
, toolsfiles
)
395 g
= processor_class([Variable(v
) for v
in sorted(h
.cvars
.values())],
396 env_signatures
=False)
397 write_func(g
, variablesfiles
)
399 processor_class
= SCons_XML
401 # Step 1: Creating entity files for builders, functions,...
402 print("Generating entity files...")
403 h
= parse_docs(args
, include_entities
=False)
404 write_output_files(h
, buildersfiles
, functionsfiles
, toolsfiles
,
405 variablesfiles
, SCons_XML
.write_mod
)
407 # Step 2: Validating all input files
408 print("Validating files against SCons XSD...")
409 if SConsDoc
.validate_all_xml(['SCons']):
412 print("Validation failed! Please correct the errors above and try again.")
415 # Step 3: Creating actual documentation snippets, using the
416 # fully resolved and updated entities from the *.mod files.
417 print("Updating documentation for builders, tools and functions...")
418 h
= parse_docs(args
, include_entities
=True)
419 write_output_files(h
, buildersfiles
, functionsfiles
, toolsfiles
,
420 variablesfiles
, SCons_XML
.write
)
425 # indent-tabs-mode:nil
427 # vim: set expandtab tabstop=4 shiftwidth=4: