3 # Module for handling SCons documentation processing.
7 This module parses home-brew XML files that document various things
8 in SCons. Right now, it handles Builders, construction variables,
9 and Tools, but we expect it to get extended in the future.
11 In general, you can use any DocBook tag in the input, and this module
12 just adds processing various home-brew tags to try to make life a
17 <builder name="VARIABLE">
19 This is the summary description of an SCons Tool.
20 It will get placed in the man page,
21 and in the appropriate User's Guide appendix.
22 The name of any builder may be interpolated
23 anywhere in the document by specifying the
25 element. It need not be on a line by itself.
27 Unlike normal XML, blank lines are significant in these
28 descriptions and serve to separate paragraphs.
29 They'll get replaced in DocBook output with appropriate tags
30 to indicate a new paragraph.
33 print "this is example code, it will be offset and indented"
38 Construction variable example:
40 <cvar name="VARIABLE">
42 This is the summary description of a construction variable.
43 It will get placed in the man page,
44 and in the appropriate User's Guide appendix.
45 The name of any construction variable may be interpolated
46 anywhere in the document by specifying the
48 element. It need not be on a line by itself.
50 Unlike normal XML, blank lines are significant in these
51 descriptions and serve to separate paragraphs.
52 They'll get replaced in DocBook output with appropriate tags
53 to indicate a new paragraph.
56 print "this is example code, it will be offset and indented"
63 <tool name="VARIABLE">
65 This is the summary description of an SCons Tool.
66 It will get placed in the man page,
67 and in the appropriate User's Guide appendix.
68 The name of any tool may be interpolated
69 anywhere in the document by specifying the
71 element. It need not be on a line by itself.
73 Unlike normal XML, blank lines are significant in these
74 descriptions and serve to separate paragraphs.
75 They'll get replaced in DocBook output with appropriate tags
76 to indicate a new paragraph.
79 print "this is example code, it will be offset and indented"
88 import xml.sax.handler
91 def __init__(self, name):
93 self.sort_name = name.lower()
94 if self.sort_name[0] == '_':
95 self.sort_name = self.sort_name[1:]
99 def cmp_name(self, name):
103 def __cmp__(self, other):
104 return cmp(self.sort_name, other.sort_name)
110 def __init__(self, name):
111 Item.__init__(self, name)
112 self.entity = self.name.replace('+', 'X')
114 class ConstructionVariable(Item):
118 def __init__(self, tag, body=None):
124 body = ''.join(self.body)
125 return "<%s>%s</%s>\n" % (self.tag, body, self.tag)
126 def append(self, data):
127 self.body.append(data)
133 def append(self, data):
134 self.collect.append(data)
136 text = ''.join(self.collect)
137 paras = text.split('\n\n')
141 self.body.append('\n')
143 paras[0] = '\n' + paras[0]
146 paras[-1] = paras[-1] + '\n'
154 self.body.append(sep)
158 self.body.append(last)
159 def begin_chunk(self, chunk):
163 self.body.append(self.collect)
166 class SConsDocHandler(xml.sax.handler.ContentHandler,
167 xml.sax.handler.ErrorHandler):
169 self._start_dispatch = {}
170 self._end_dispatch = {}
171 keys = self.__class__.__dict__.keys()
172 start_tag_method_names = filter(lambda k: k[:6] == 'start_', keys)
173 end_tag_method_names = filter(lambda k: k[:4] == 'end_', keys)
174 for method_name in start_tag_method_names:
175 tag = method_name[6:]
176 self._start_dispatch[tag] = getattr(self, method_name)
177 for method_name in end_tag_method_names:
178 tag = method_name[4:]
179 self._end_dispatch[tag] = getattr(self, method_name)
182 self.current_object = []
187 def startElement(self, name, attrs):
189 start_element_method = self._start_dispatch[name]
191 self.characters('<%s>' % name)
193 start_element_method(attrs)
195 def endElement(self, name):
197 end_element_method = self._end_dispatch[name]
199 self.characters('</%s>' % name)
205 def characters(self, chars):
206 self.collect.append(chars)
208 def begin_collecting(self, chunk):
210 def end_collecting(self):
213 def begin_chunk(self):
222 def begin_xxx(self, obj):
223 self.stack.append(self.current_object)
224 self.current_object = obj
226 self.current_object = self.stack.pop()
231 def start_scons_doc(self, attrs):
233 def end_scons_doc(self):
236 def start_builder(self, attrs):
237 name = attrs.get('name')
239 builder = self.builders[name]
241 builder = Builder(name)
242 self.builders[name] = builder
243 self.begin_xxx(builder)
244 def end_builder(self):
247 def start_tool(self, attrs):
248 name = attrs.get('name')
250 tool = self.tools[name]
253 self.tools[name] = tool
258 def start_cvar(self, attrs):
259 name = attrs.get('name')
261 cvar = self.cvars[name]
263 cvar = ConstructionVariable(name)
264 self.cvars[name] = cvar
269 def start_summary(self, attrs):
271 self.current_object.summary = summary
272 self.begin_xxx(summary)
273 self.begin_collecting(summary)
274 def end_summary(self):
275 self.current_object.end_para()
278 def start_example(self, attrs):
279 example = Chunk("programlisting")
280 self.current_object.begin_chunk(example)
281 def end_example(self):
282 self.current_object.end_chunk()
284 def start_uses(self, attrs):
285 self.begin_collecting([])
287 self.current_object.uses = ''.join(self.collect).split()
288 self.current_object.uses.sort()
289 self.end_collecting()
291 def start_sets(self, attrs):
292 self.begin_collecting([])
294 self.current_object.sets = ''.join(self.collect).split()
295 self.current_object.sets.sort()
296 self.end_collecting()
298 # Stuff for the ErrorHandler portion.
299 def error(self, exception):
300 linenum = exception._linenum - self.preamble_lines
301 sys.stderr.write('%s:%d:%d: %s (error)\n' % (self.filename, linenum, exception._colnum, ''.join(exception.args)))
303 def fatalError(self, exception):
304 linenum = exception._linenum - self.preamble_lines
305 sys.stderr.write('%s:%d:%d: %s (fatalError)\n' % (self.filename, linenum, exception._colnum, ''.join(exception.args)))
307 def set_file_info(self, filename, preamble_lines):
308 self.filename = filename
309 self.preamble_lines = preamble_lines
311 # lifted from Ka-Ping Yee's way cool pydoc module.
312 def importfile(path):
313 """Import a Python source file or compiled file given its path."""
314 magic = imp.get_magic()
315 file = open(path, 'r')
316 if file.read(len(magic)) == magic:
317 kind = imp.PY_COMPILED
321 filename = os.path.basename(path)
322 name, ext = os.path.splitext(filename)
323 file = open(path, 'r')
325 module = imp.load_module(name, file, path, (ext, 'r', kind))
326 except ImportError, e:
327 sys.stderr.write("Could not import %s: %s\n" % (path, e))
334 # indent-tabs-mode:nil
336 # vim: set expandtab tabstop=4 shiftwidth=4: