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 = ''.join(self.collect).split()
358 self.current_object.uses.sort()
359 self.end_collecting()
361 def start_sets(self, attrs):
362 self.begin_collecting([])
364 self.current_object.sets = ''.join(self.collect).split()
365 self.current_object.sets.sort()
366 self.end_collecting()
368 # Stuff for the ErrorHandler portion.
369 def error(self, exception):
370 linenum = exception._linenum - self.preamble_lines
371 sys.stderr.write('%s:%d:%d: %s (error)\n' % (self.filename, linenum, exception._colnum, ''.join(exception.args)))
373 def fatalError(self, exception):
374 linenum = exception._linenum - self.preamble_lines
375 sys.stderr.write('%s:%d:%d: %s (fatalError)\n' % (self.filename, linenum, exception._colnum, ''.join(exception.args)))
377 def set_file_info(self, filename, preamble_lines):
378 self.filename = filename
379 self.preamble_lines = preamble_lines
381 # lifted from Ka-Ping Yee's way cool pydoc module.
382 def importfile(path):
383 """Import a Python source file or compiled file given its path."""
384 magic = imp.get_magic()
385 file = open(path, 'r')
386 if file.read(len(magic)) == magic:
387 kind = imp.PY_COMPILED
391 filename = os.path.basename(path)
392 name, ext = os.path.splitext(filename)
393 file = open(path, 'r')
395 module = imp.load_module(name, file, path, (ext, 'r', kind))
396 except ImportError, e:
397 sys.stderr.write("Could not import %s: %s\n" % (path, e))
404 # indent-tabs-mode:nil
406 # vim: set expandtab tabstop=4 shiftwidth=4: