Admin/website/build/pypager.py
changeset 16233 e634d33deb86
child 16240 95cc0e8f8a17
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Admin/website/build/pypager.py	Sat Jun 04 10:26:08 2005 +0200
@@ -0,0 +1,452 @@
+#!/usr/bin/env python
+# -*- coding: Latin-1 -*-
+
+__author__ = 'Florian Haftmann, florian.haftmann@informatik.tu-muenchen.de'
+__revision__ = '$Id$'
+
+# generic imports
+import sys
+import os
+from os import path
+import posixpath
+import codecs
+import shlex
+import optparse
+import time
+
+# xml imports
+from xml.sax.saxutils import escape
+from xml.sax.saxutils import quoteattr
+from xml.sax import make_parser as makeParser
+from xml.sax.handler import ContentHandler
+from xml.sax.handler import EntityResolver
+from xml.sax.xmlreader import AttributesImpl as Attributes
+from xml.sax import SAXException
+from xml.sax import SAXParseException
+
+nbsp = unichr(160)
+
+# global configuration
+outputEncoding = 'UTF-8'
+
+# implement your own functions for PIs here
+class Functions:
+
+    def __init__(self, pc, valdict, modtime, encodingMeta):
+
+        self._pc = pc
+        self._valdict = valdict
+        self._modtime = modtime
+        self._encodingMeta = encodingMeta
+
+    def getPc(self):
+
+        return self._pc
+
+    def value(self, handler, **args):
+
+        value = self._valdict[args[u"key"]]
+        handler.characters(value)
+
+    def title(self, handler, **args):
+
+        handler.characters(handler._title)
+
+    def contentType(self, handler, **args):
+
+        encoding = self._encodingMeta or handler._encoding
+        attr = {
+            u"http-equiv": u"Content-Type",
+            u"content": u"text/html; charset=%s" % encoding
+        }
+        handler.startElement(u"meta", attr)
+        handler.endElement(u"meta")
+
+    def currentDate(self, handler, **args):
+
+        handler.characters(unicode(time.strftime('%Y-%m-%d %H:%M:%S')))
+
+    def modificationDate(self, handler, **args):
+
+        handler.characters(unicode(time.strftime('%Y-%m-%d %H:%M:%S',
+            time.localtime(self._modtime))))
+
+    def relativeRoot(self, handler, **args):
+
+        href = args[u"href"].encode("latin-1")
+        handler.characters(self._pc.relDstPathOf('//'+href))
+
+    def include(self, handler, **args):
+
+        filename = args[u"file"].encode("latin-1")
+        filename = self._pc.absSrcPathOf(filename)
+        self._modtime = max(self._modtime, os.stat(filename).st_mtime)
+        istream = open(filename, "r")
+        parseWithER(istream, handler)
+        istream.close()
+
+    def navitem(self, handler, **args):
+
+        target = args[u"target"].encode("latin-1")
+        target = self._pc.relDstPathOf(target)
+        if self._pc.isSrc(target):
+            wrapTagname = u"strong"
+        else:
+            wrapTagname = u"span"
+        title = args[u"title"]
+        attr = {}
+        handler.startElement(u"li", attr)
+        handler.startElement(wrapTagname, {})
+        handler.startElement(u"a", {
+            u"href": unicode(target, 'latin-1')
+        })
+        handler.characters(title)
+        handler.endElement(u"a")
+        handler.endElement(wrapTagname)
+        handler.endElement(u"li")
+
+    def downloadCells(self, handler, **args):
+
+        target = args[u"target"].encode("latin-1")
+        targetReal = self._pc.absDstPathOf(target)
+        title = args.get(u"title", unicode(posixpath.split(target)[0], 'latin-1'))
+        size = os.stat(targetReal).st_size
+        handler.startElement(u"td", {})
+        handler.startElement(u"a", {
+            u"href": target
+        })
+        handler.characters(title)
+        handler.endElement(u"a")
+        handler.endElement(u"td")
+        handler.startElement(u"td", {})
+        handler.characters(u"%i%sKB" % (size / 1024, unichr(160)))
+        handler.endElement(u"td")
+
+    def cvs(self, handler, **args):
+
+        pass
+
+# a notion of paths
+class PathCalculator:
+
+    def __init__(self, srcLoc, srcRoot, dstRoot):
+
+        self._src = path.normpath(path.abspath(srcLoc))
+        srcPath, srcName = path.split(self._src)
+        self._srcRoot = path.normpath(path.abspath(srcRoot))
+        self._dstRoot = path.normpath(path.abspath(dstRoot))
+        self._relRoot = ""
+        relLocChain = []
+        diffRoot = srcPath
+        while diffRoot != self._srcRoot:
+            self._relRoot = path.join(self._relRoot, os.pardir)
+            diffRoot, chainPiece = path.split(diffRoot)
+            relLocChain.insert(0, chainPiece)
+        self._relRoot = self._relRoot and self._relRoot + '/'
+        self._relLoc = relLocChain and path.join(*relLocChain) or ""
+
+    def isSrc(self, loc):
+
+        return self.absSrcPathOf(loc) == self._src
+
+    def relRootPath(self):
+
+        return self._relRoot
+
+    def absSrcPathOf(self, loc):
+
+        if loc.startswith("//"):
+            return path.normpath(path.abspath(loc[2:]))
+        else:
+            return path.normpath(path.abspath(path.join(self._relLoc, loc)))
+
+    def absDstPathOf(self, loc):
+
+        if loc.startswith("//"):
+            return path.join(self._dstRoot, loc[2:])
+        else:
+            return path.join(self._dstRoot, self._relLoc, loc)
+
+    def relSrcPathOf(self, loc):
+
+        loc = self.absSrcPathOf(loc)
+        loc = self.stripCommonPrefix(loc, self._srcRoot)
+        loc = self.stripCommonPrefix(loc, self._relLoc)
+        return loc
+
+    def relDstPathOf(self, loc):
+
+        loc = self.absDstPathOf(loc)
+        loc = self.stripCommonPrefix(loc, self._dstRoot)
+        loc = self.stripCommonPrefix(loc, self._relLoc)
+        return loc
+
+    def stripCommonPrefix(self, loc, prefix):
+
+        common = self.commonPrefix((loc, prefix))
+        if common:
+            loc = loc[len(common):]
+            if loc and loc[0] == '/':
+                loc = loc[1:]
+        return loc
+
+    def commonPrefix(self, locs):
+
+        common = path.commonprefix(locs)
+        # commonprefix bugs
+        if [ loc for loc in locs if len(loc) != common ] and \
+            [ loc for loc in locs if len(common) < len(loc) and loc[len(common)] != path.sep ]:
+                common = path.split(common)[0]
+        if common and common[-1] == path.sep:
+            common = common[:-1]
+
+        return common or ""
+
+# the XML transformer
+class TransformerHandler(ContentHandler, EntityResolver):
+
+    def __init__(self, out, encoding, dtd, func):
+
+        ContentHandler.__init__(self)
+        #~ EntityResolver.__init__(self)
+        self._out = codecs.getwriter(encoding)(out)
+        self._ns_contexts = [{}] # contains uri -> prefix dicts
+        self._current_context = self._ns_contexts[-1]
+        self._undeclared_ns_maps = []
+        self._encoding = encoding
+        self._lastStart = False
+        self._func = func
+        self._characterBuffer = {}
+        self._currentXPath = []
+        self._title = None
+        self._init = False
+        self._dtd = dtd
+
+    def closeLastStart(self):
+
+        if self._lastStart:
+            self._out.write(u'>')
+            self._lastStart = False
+
+    def flushCharacterBuffer(self):
+
+        self._out.write(escape(u"".join(self._characterBuffer)))
+        self._characterBuffer = []
+
+    def transformAbsPath(self, attrs, attrname):
+
+        pathval = attrs.get(attrname, None)
+        if pathval and pathval.startswith(u"//"):
+            attrs = dict(attrs)
+            pathRel = self._func.getPc().relDstPathOf(pathval)
+            pathDst = self._func.getPc().absDstPathOf(pathval)
+            if not path.exists(pathDst):
+                raise Exception("Path does not exist: %s" % pathDst)
+            attrs[attrname] = pathRel
+            return attrs
+        else:
+            return attrs
+
+    def startDocument(self):
+
+        if not self._init:
+            if self._encoding.upper() != 'UTF-8':
+                self._out.write(u'<?xml version="1.0" encoding="%s"?>\n' %
+                                self._encoding)
+            else:
+                self._out.write(u'<?xml version="1.0"?>\n')
+            self._init = True
+
+    def startPrefixMapping(self, prefix, uri):
+
+        self._ns_contexts.append(self._current_context.copy())
+        self._current_context[uri] = prefix
+        self._undeclared_ns_maps.append((prefix, uri))
+
+    def endPrefixMapping(self, prefix):
+
+        self._current_context = self._ns_contexts[-1]
+        del self._ns_contexts[-1]
+
+    def startElement(self, name, attrs):
+
+        if name == u"dummy:wrapper":
+            return
+        self.closeLastStart()
+        self.flushCharacterBuffer()
+        self._out.write(u'<' + name)
+        # this list is not exhaustive
+        for tagname, attrname in ((u"a", u"href"), (u"img", u"src"), (u"link", u"href")):
+            if name == tagname:
+                attrs = self.transformAbsPath(attrs, attrname)
+        for (name, value) in attrs.items():
+            self._out.write(u' %s=%s' % (name, quoteattr(value)))
+        self._currentXPath.append(name)
+        self._lastStart = True
+
+    def endElement(self, name):
+
+        if name == u"dummy:wrapper":
+            return
+        elif name == u'title':
+            self._title = u"".join(self._characterBuffer)
+        self.flushCharacterBuffer()
+        if self._lastStart:
+            self._out.write(u'/>')
+            self._lastStart = False
+        else:
+            self._out.write('</%s>' % name)
+        self._currentXPath.pop()
+
+    def startElementNS(self, name, qname, attrs):
+
+        self.closeLastStart()
+        self.flushCharacterBuffer()
+        if name[0] is None:
+            # if the name was not namespace-scoped, use the unqualified part
+            name = name[1]
+        else:
+            # else try to restore the original prefix from the namespace
+            name = self._current_context[name[0]] + u":" + name[1]
+        self._out.write(u'<' + name)
+
+        for pair in self._undeclared_ns_maps:
+            self._out.write(u' xmlns:%s="%s"' % pair)
+        self._undeclared_ns_maps = []
+
+        for (name, value) in attrs.items():
+            name = self._current_context[name[0]] + ":" + name[1]
+            self._out.write(' %s=%s' % (name, quoteattr(value)))
+        self._out.write('>')
+        self._currentXPath.append(name)
+
+    def endElementNS(self, name, qname):
+
+        self.flushCharacterBuffer()
+        if name[0] is None:
+            name = name[1]
+        else:
+            name = self._current_context[name[0]] + u":" + name[1]
+        if self._lastStart:
+            self._out.write(u'/>')
+            self._lastStart = False
+        else:
+            self._out.write(u'</%s>' % name)
+        self._currentXPath.pop()
+
+    def characters(self, content):
+
+        self.closeLastStart()
+        self._characterBuffer.append(content)
+
+    def ignorableWhitespace(self, content):
+
+        self.closeLastStart()
+        self.flushCharacterBuffer()
+        self._out.write(content)
+
+    def resolveEntity(self, publicId, systemId):
+
+        loc, name = posixpath.split(systemId)
+        if loc == u"http://www.w3.org/TR/xhtml1/DTD" or loc == u"":
+            systemId = path.join(self._dtd, name)
+        return EntityResolver.resolveEntity(self, publicId, systemId)
+
+    def processingInstruction(self, target, data):
+
+        self.closeLastStart()
+        self.flushCharacterBuffer()
+        func = getattr(self._func, target)
+        args = {}
+        for keyval in shlex.split(data.encode("utf-8")):
+            key, val = keyval.split("=", 1)
+            args[key] = val
+        func(self, **args)
+
+def parseWithER(istream, handler):
+
+    parser = makeParser()
+    parser.setContentHandler(handler)
+    parser.setEntityResolver(handler)
+    parser.parse(istream)
+
+def main():
+
+    # parse command line
+    cmdlineparser = optparse.OptionParser(
+        usage = '%prog [options] [key=value]* src [dst]',
+        conflict_handler = "error",
+        description = '''Leightweight HTML page generation tool''',
+        add_help_option = True,
+    )
+    cmdlineparser.add_option("-s", "--srcroot",
+        action="store", dest="srcroot",
+        type="string", default=".",
+        help="source tree root", metavar='location')
+    cmdlineparser.add_option("-d", "--dstroot",
+        action="store", dest="dstroot",
+        type="string", default=".",
+        help="destination tree root", metavar='location')
+    cmdlineparser.add_option("-t", "--dtd",
+        action="store", dest="dtd",
+        type="string", default=".",
+        help="local mirror of XHTML DTDs", metavar='location')
+    cmdlineparser.add_option("-m", "--encodinghtml",
+        action="store", dest="encodinghtml",
+        type="string", default="",
+        help="force value of html content encoding meta ", metavar='encoding')
+
+
+    options, args = cmdlineparser.parse_args(sys.argv[1:])
+
+    # check source
+    if len(args) < 1:
+        cmdlineparser.error("Exactly one soure file must be given")
+
+    # read arguments
+    valdict = {}
+    if len(args) == 1:
+        src = args[0]
+        dst = None
+    else:
+        if "=" in args[-2]:
+            src = args[-1]
+            dst = None
+            vallist = args[:-1]
+        else:
+            src = args[-2]
+            dst = args[-1]
+            if dst == "-":
+                dst = None
+            vallist = args[:-2]
+        for keyval in vallist:
+            key, val = keyval.split("=", 1)
+            valdict[unicode(key, 'latin-1')] = unicode(val, 'latin-1')
+
+    # path calculator
+    pc = PathCalculator(src, options.srcroot, options.dstroot)
+
+    # function space
+    modtime = os.stat(src).st_mtime
+    func = Functions(pc, valdict, modtime, options.encodinghtml)
+
+    # allocate file handles
+    istream = open(src, 'r')
+    if dst is not None:
+        ostream = open(dst, 'wb')
+    else:
+        ostream = sys.stdout
+
+    # process file
+    transformer = TransformerHandler(ostream, outputEncoding, options.dtd, func)
+    parseWithER(istream, transformer)
+
+    # close handles
+    ostream.close()
+    istream.close()
+
+if __name__ == '__main__':
+    main()
+
+__todo__ = '''
+'''