3 # Module for handling SCons documentation processing.
5 from __future__ import generators ### KEEP FOR COMPATIBILITY FIXERS
8 This module parses home-brew XML files that document various things
9 in SCons. Right now, it handles Builders, functions, construction
10 variables, and Tools, but we expect it to get extended in the future.
12 In general, you can use any DocBook tag in the input, and this module
13 just adds processing various home-brew tags to try to make life a
18 <builder name="BUILDER">
20 This is the summary description of an SCons Builder.
21 It will get placed in the man page,
22 and in the appropriate User's Guide appendix.
23 The name of any builder may be interpolated
24 anywhere in the document by specifying the
26 element. It need not be on a line by itself.
28 Unlike normal XML, blank lines are significant in these
29 descriptions and serve to separate paragraphs.
30 They'll get replaced in DocBook output with appropriate tags
31 to indicate a new paragraph.
34 print "this is example code, it will be offset and indented"
41 <scons_function name="FUNCTION">
43 (arg1, arg2, key=value)
46 This is the summary description of an SCons function.
47 It will get placed in the man page,
48 and in the appropriate User's Guide appendix.
49 The name of any builder may be interpolated
50 anywhere in the document by specifying the
52 element. It need not be on a line by itself.
54 Unlike normal XML, blank lines are significant in these
55 descriptions and serve to separate paragraphs.
56 They'll get replaced in DocBook output with appropriate tags
57 to indicate a new paragraph.
60 print "this is example code, it will be offset and indented"
65 Construction variable example:
67 <cvar name="VARIABLE">
69 This is the summary description of a construction variable.
70 It will get placed in the man page,
71 and in the appropriate User's Guide appendix.
72 The name of any construction variable may be interpolated
73 anywhere in the document by specifying the
75 element. It need not be on a line by itself.
77 Unlike normal XML, blank lines are significant in these
78 descriptions and serve to separate paragraphs.
79 They'll get replaced in DocBook output with appropriate tags
80 to indicate a new paragraph.
83 print "this is example code, it will be offset and indented"
92 This is the summary description of an SCons Tool.
93 It will get placed in the man page,
94 and in the appropriate User's Guide appendix.
95 The name of any tool may be interpolated
96 anywhere in the document by specifying the
98 element. It need not be on a line by itself.
100 Unlike normal XML, blank lines are significant in these
101 descriptions and serve to separate paragraphs.
102 They'll get replaced in DocBook output with appropriate tags
103 to indicate a new paragraph.
106 print "this is example code, it will be offset and indented"
116 import xml.sax.handler
119 def __init__(self, name):
121 self.sort_name = name.lower()
122 if self.sort_name[0] == '_':
123 self.sort_name = self.sort_name[1:]
127 def cmp_name(self, name):
131 def __cmp__(self, other):
132 return cmp(self.sort_name, other.sort_name)
137 class Function(Item):
138 def __init__(self, name):
139 super(Function, self).__init__(name)
143 def __init__(self, name):
144 Item.__init__(self, name)
145 self.entity = self.name.replace('+', 'X')
147 class ConstructionVariable(Item):
151 def __init__(self, tag, body=None):
157 body = ''.join(self.body)
158 return "<%s>%s</%s>\n" % (self.tag, body, self.tag)
159 def append(self, data):
160 self.body.append(data)
163 def __init__(self, signature, body=None):
167 self.signature = signature
169 s = ''.join(self.body).strip()
171 for m in re.findall('([a-zA-Z/_]+|[^a-zA-Z/_]+)', s):
175 return ' '.join(result)
176 def append(self, data):
177 self.body.append(data)
183 def append(self, data):
184 self.collect.append(data)
186 text = ''.join(self.collect)
187 paras = text.split('\n\n')
191 self.body.append('\n')
193 paras[0] = '\n' + paras[0]
196 paras[-1] = paras[-1] + '\n'
204 self.body.append(sep)
208 self.body.append(last)
209 def begin_chunk(self, chunk):
213 self.body.append(self.collect)
216 class SConsDocHandler(xml.sax.handler.ContentHandler,
217 xml.sax.handler.ErrorHandler):
219 self._start_dispatch = {}
220 self._end_dispatch = {}
221 keys = self.__class__.__dict__.keys()
222 start_tag_method_names = [k for k in keys if k[:6] == 'start_']
223 end_tag_method_names = [k for k in keys if k[:4] == 'end_']
224 for method_name in start_tag_method_names:
225 tag = method_name[6:]
226 self._start_dispatch[tag] = getattr(self, method_name)
227 for method_name in end_tag_method_names:
228 tag = method_name[4:]
229 self._end_dispatch[tag] = getattr(self, method_name)
232 self.current_object = []
238 def startElement(self, name, attrs):
240 start_element_method = self._start_dispatch[name]
242 self.characters('<%s>' % name)
244 start_element_method(attrs)
246 def endElement(self, name):
248 end_element_method = self._end_dispatch[name]
250 self.characters('</%s>' % name)
256 def characters(self, chars):
257 self.collect.append(chars)
259 def begin_collecting(self, chunk):
261 def end_collecting(self):
264 def begin_chunk(self):
273 def begin_xxx(self, obj):
274 self.stack.append(self.current_object)
275 self.current_object = obj
277 self.current_object = self.stack.pop()
282 def start_scons_doc(self, attrs):
284 def end_scons_doc(self):
287 def start_builder(self, attrs):
288 name = attrs.get('name')
290 builder = self.builders[name]
292 builder = Builder(name)
293 self.builders[name] = builder
294 self.begin_xxx(builder)
295 def end_builder(self):
298 def start_scons_function(self, attrs):
299 name = attrs.get('name')
301 function = self.functions[name]
303 function = Function(name)
304 self.functions[name] = function
305 self.begin_xxx(function)
306 def end_scons_function(self):
309 def start_tool(self, attrs):
310 name = attrs.get('name')
312 tool = self.tools[name]
315 self.tools[name] = tool
320 def start_cvar(self, attrs):
321 name = attrs.get('name')
323 cvar = self.cvars[name]
325 cvar = ConstructionVariable(name)
326 self.cvars[name] = cvar
331 def start_arguments(self, attrs):
332 arguments = Arguments(attrs.get('signature', "both"))
333 self.current_object.arguments.append(arguments)
334 self.begin_xxx(arguments)
335 self.begin_collecting(arguments)
336 def end_arguments(self):
339 def start_summary(self, attrs):
341 self.current_object.summary = summary
342 self.begin_xxx(summary)
343 self.begin_collecting(summary)
344 def end_summary(self):
345 self.current_object.end_para()
348 def start_example(self, attrs):
349 example = Chunk("programlisting")
350 self.current_object.begin_chunk(example)
351 def end_example(self):
352 self.current_object.end_chunk()
354 def start_uses(self, attrs):
355 self.begin_collecting([])
357 self.current_object.uses = sorted(''.join(self.collect).split())
358 self.end_collecting()
360 def start_sets(self, attrs):
361 self.begin_collecting([])
363 self.current_object.sets = sorted(''.join(self.collect).split())
364 self.end_collecting()
366 # Stuff for the ErrorHandler portion.
367 def error(self, exception):
368 linenum = exception._linenum - self.preamble_lines
369 sys.stderr.write('%s:%d:%d: %s (error)\n' % (self.filename, linenum, exception._colnum, ''.join(exception.args)))
371 def fatalError(self, exception):
372 linenum = exception._linenum - self.preamble_lines
373 sys.stderr.write('%s:%d:%d: %s (fatalError)\n' % (self.filename, linenum, exception._colnum, ''.join(exception.args)))
375 def set_file_info(self, filename, preamble_lines):
376 self.filename = filename
377 self.preamble_lines = preamble_lines
379 # lifted from Ka-Ping Yee's way cool pydoc module.
380 def importfile(path):
381 """Import a Python source file or compiled file given its path."""
382 magic = imp.get_magic()
383 file = open(path, 'r')
384 if file.read(len(magic)) == magic:
385 kind = imp.PY_COMPILED
389 filename = os.path.basename(path)
390 name, ext = os.path.splitext(filename)
391 file = open(path, 'r')
393 module = imp.load_module(name, file, path, (ext, 'r', kind))
394 except ImportError, e:
395 sys.stderr.write("Could not import %s: %s\n" % (path, e))
402 # indent-tabs-mode:nil
404 # vim: set expandtab tabstop=4 shiftwidth=4: