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:]
98 def cmp_name(self, name):
102 def __cmp__(self, other):
103 return cmp(self.sort_name, other.sort_name)
109 def __init__(self, name):
110 Item.__init__(self, name)
111 self.entity = self.name.replace('+', 'X')
113 class ConstructionVariable(Item):
117 def __init__(self, tag, body=None):
123 body = ''.join(self.body)
124 return "<%s>%s</%s>\n" % (self.tag, body, self.tag)
125 def append(self, data):
126 self.body.append(data)
132 def append(self, data):
133 self.collect.append(data)
135 text = ''.join(self.collect)
136 paras = text.split('\n\n')
140 self.body.append('\n')
142 paras[0] = '\n' + paras[0]
145 paras[-1] = paras[-1] + '\n'
153 self.body.append(sep)
157 self.body.append(last)
158 def begin_chunk(self, chunk):
162 self.body.append(self.collect)
165 class SConsDocHandler(xml.sax.handler.ContentHandler,
166 xml.sax.handler.ErrorHandler):
168 self._start_dispatch = {}
169 self._end_dispatch = {}
170 keys = self.__class__.__dict__.keys()
171 start_tag_method_names = filter(lambda k: k[:6] == 'start_', keys)
172 end_tag_method_names = filter(lambda k: k[:4] == 'end_', keys)
173 for method_name in start_tag_method_names:
174 tag = method_name[6:]
175 self._start_dispatch[tag] = getattr(self, method_name)
176 for method_name in end_tag_method_names:
177 tag = method_name[4:]
178 self._end_dispatch[tag] = getattr(self, method_name)
181 self.current_object = []
186 def startElement(self, name, attrs):
188 start_element_method = self._start_dispatch[name]
190 self.characters('<%s>' % name)
192 start_element_method(attrs)
194 def endElement(self, name):
196 end_element_method = self._end_dispatch[name]
198 self.characters('</%s>' % name)
204 def characters(self, chars):
205 self.collect.append(chars)
207 def begin_collecting(self, chunk):
209 def end_collecting(self):
212 def begin_chunk(self):
221 def begin_xxx(self, obj):
222 self.stack.append(self.current_object)
223 self.current_object = obj
225 self.current_object = self.stack.pop()
230 def start_scons_doc(self, attrs):
232 def end_scons_doc(self):
235 def start_builder(self, attrs):
236 name = attrs.get('name')
238 builder = self.builders[name]
240 builder = Builder(name)
241 self.builders[name] = builder
242 self.begin_xxx(builder)
243 def end_builder(self):
246 def start_tool(self, attrs):
247 name = attrs.get('name')
249 tool = self.tools[name]
252 self.tools[name] = tool
257 def start_cvar(self, attrs):
258 name = attrs.get('name')
260 cvar = self.cvars[name]
262 cvar = ConstructionVariable(name)
263 self.cvars[name] = cvar
268 def start_summary(self, attrs):
270 self.current_object.summary = summary
271 self.begin_xxx(summary)
272 self.begin_collecting(summary)
273 def end_summary(self):
274 self.current_object.end_para()
277 def start_example(self, attrs):
278 example = Chunk("programlisting")
279 self.current_object.begin_chunk(example)
280 def end_example(self):
281 self.current_object.end_chunk()
283 def start_uses(self, attrs):
284 self.begin_collecting([])
286 self.current_object.uses = ''.join(self.collect).split()
287 self.end_collecting()
289 # Stuff for the ErrorHandler portion.
290 def error(self, exception):
291 linenum = exception._linenum - self.preamble_lines
292 sys.stderr.write('%s:%d:%d: %s (error)\n' % (self.filename, linenum, exception._colnum, ''.join(exception.args)))
294 def fatalError(self, exception):
295 linenum = exception._linenum - self.preamble_lines
296 sys.stderr.write('%s:%d:%d: %s (fatalError)\n' % (self.filename, linenum, exception._colnum, ''.join(exception.args)))
298 def set_file_info(self, filename, preamble_lines):
299 self.filename = filename
300 self.preamble_lines = preamble_lines
302 # lifted from Ka-Ping Yee's way cool pydoc module.
303 def importfile(path):
304 """Import a Python source file or compiled file given its path."""
305 magic = imp.get_magic()
306 file = open(path, 'r')
307 if file.read(len(magic)) == magic:
308 kind = imp.PY_COMPILED
312 filename = os.path.basename(path)
313 name, ext = os.path.splitext(filename)
314 file = open(path, 'r')
316 module = imp.load_module(name, file, path, (ext, 'r', kind))
317 except ImportError, e:
318 sys.stderr.write("Could not import %s: %s\n" % (path, e))