#!/usr/bin/env python # # Module for handling SCons documentation processing. # import os.path import imp import sys import xml.sax.handler class Item: def __init__(self, name): self.name = name self.sort_name = name.lower() if self.sort_name[0] == '_': self.sort_name = self.sort_name[1:] self.summary = [] self.uses = None def cmp_name(self, name): if name[0] == '_': name = name[1:] return name.lower() def __cmp__(self, other): return cmp(self.sort_name, other.sort_name) class Builder(Item): pass class Tool(Item): def __init__(self, name): Item.__init__(self, name) self.entity = self.name.replace('+', 'X') class ConstructionVariable(Item): pass class Chunk: def __init__(self, tag, body=None): self.tag = tag if not body: body = [] self.body = body def __str__(self): body = ''.join(self.body) return "<%s>%s\n" % (self.tag, body, self.tag) def append(self, data): self.body.append(data) class Summary: def __init__(self): self.body = [] self.collect = [] def append(self, data): self.collect.append(data) def end_para(self): text = ''.join(self.collect) paras = text.split('\n\n') if paras == ['\n']: return if paras[0] == '': self.body.append('\n') paras = paras[1:] paras[0] = '\n' + paras[0] if paras[-1] == '': paras = paras[:-1] paras[-1] = paras[-1] + '\n' last = '\n' else: last = None sep = None for p in paras: c = Chunk("para", p) if sep: self.body.append(sep) self.body.append(c) sep = '\n' if last: self.body.append(last) def begin_chunk(self, chunk): self.end_para() self.collect = chunk def end_chunk(self): self.body.append(self.collect) self.collect = [] class SConsDocHandler(xml.sax.handler.ContentHandler, xml.sax.handler.ErrorHandler): def __init__(self): self._start_dispatch = {} self._end_dispatch = {} keys = self.__class__.__dict__.keys() start_tag_method_names = filter(lambda k: k[:6] == 'start_', keys) end_tag_method_names = filter(lambda k: k[:4] == 'end_', keys) for method_name in start_tag_method_names: tag = method_name[6:] self._start_dispatch[tag] = getattr(self, method_name) for method_name in end_tag_method_names: tag = method_name[4:] self._end_dispatch[tag] = getattr(self, method_name) self.stack = [] self.collect = [] self.current_object = [] self.builders = {} self.tools = {} self.cvars = {} def startElement(self, name, attrs): try: start_element_method = self._start_dispatch[name] except KeyError: self.characters('<%s>' % name) else: start_element_method(attrs) def endElement(self, name): try: end_element_method = self._end_dispatch[name] except KeyError: self.characters('' % name) else: end_element_method() # # def characters(self, chars): self.collect.append(chars) def begin_collecting(self, chunk): self.collect = chunk def end_collecting(self): self.collect = [] def begin_chunk(self): pass def end_chunk(self): pass # # # def begin_xxx(self, obj): self.stack.append(self.current_object) self.current_object = obj def end_xxx(self): self.current_object = self.stack.pop() # # # def start_scons_doc(self, attrs): pass def end_scons_doc(self): pass def start_builder(self, attrs): name = attrs.get('name') try: builder = self.builders[name] except KeyError: builder = Builder(name) self.builders[name] = builder self.begin_xxx(builder) def end_builder(self): self.end_xxx() def start_tool(self, attrs): name = attrs.get('name') try: tool = self.tools[name] except KeyError: tool = Tool(name) self.tools[name] = tool self.begin_xxx(tool) def end_tool(self): self.end_xxx() def start_cvar(self, attrs): name = attrs.get('name') try: cvar = self.cvars[name] except KeyError: cvar = ConstructionVariable(name) self.cvars[name] = cvar self.begin_xxx(cvar) def end_cvar(self): self.end_xxx() def start_summary(self, attrs): summary = Summary() self.current_object.summary = summary self.begin_xxx(summary) self.begin_collecting(summary) def end_summary(self): self.current_object.end_para() self.end_xxx() def start_example(self, attrs): example = Chunk("programlisting") self.current_object.begin_chunk(example) def end_example(self): self.current_object.end_chunk() def start_uses(self, attrs): self.begin_collecting([]) def end_uses(self): self.current_object.uses = ''.join(self.collect).split() self.end_collecting() # Stuff for the ErrorHandler portion. def error(self, exception): linenum = exception._linenum - self.preamble_lines sys.stderr.write('%s:%d:%d: %s (error)\n' % (self.filename, linenum, exception._colnum, ''.join(exception.args))) def fatalError(self, exception): linenum = exception._linenum - self.preamble_lines sys.stderr.write('%s:%d:%d: %s (fatalError)\n' % (self.filename, linenum, exception._colnum, ''.join(exception.args))) def set_file_info(self, filename, preamble_lines): self.filename = filename self.preamble_lines = preamble_lines # lifted from Ka-Ping Yee's way cool pydoc module. def importfile(path): """Import a Python source file or compiled file given its path.""" magic = imp.get_magic() file = open(path, 'r') if file.read(len(magic)) == magic: kind = imp.PY_COMPILED else: kind = imp.PY_SOURCE file.close() filename = os.path.basename(path) name, ext = os.path.splitext(filename) file = open(path, 'r') try: module = imp.load_module(name, file, path, (ext, 'r', kind)) except ImportError, e: sys.stderr.write("Could not import %s: %s\n" % (path, e)) return None file.close() return module