[debian-edu-commits] r82993 - in trunk/alioth: . kgb-client-status scripts

pere at alioth.debian.org pere at alioth.debian.org
Fri Jan 24 10:02:39 UTC 2014


Author: pere
Date: 2014-01-24 10:02:39 +0000 (Fri, 24 Jan 2014)
New Revision: 82993

Added:
   trunk/alioth/htdocs/
   trunk/alioth/kgb-client-status/
   trunk/alioth/kgb-client-status/kgb-client.0cd23e71564cbd0cec9dc16e34c8a69d
   trunk/alioth/kgb-client-status/kgb-client.d083a9328147d4d43c971d2a9dd0674f
   trunk/alioth/kgb-client.conf
   trunk/alioth/scripts/
   trunk/alioth/scripts/HTMLTemplate.py
   trunk/alioth/scripts/check-static
   trunk/alioth/scripts/ciabot_svn.py
   trunk/alioth/scripts/cronfile
   trunk/alioth/scripts/update-bugs
   trunk/alioth/scripts/update-website
Removed:
   trunk/alioth/html/
Log:
Replicate current setup on alioth.

Added: trunk/alioth/kgb-client-status/kgb-client.0cd23e71564cbd0cec9dc16e34c8a69d
===================================================================
Added: trunk/alioth/kgb-client-status/kgb-client.d083a9328147d4d43c971d2a9dd0674f
===================================================================
Added: trunk/alioth/kgb-client.conf
===================================================================
--- trunk/alioth/kgb-client.conf	                        (rev 0)
+++ trunk/alioth/kgb-client.conf	2014-01-24 10:02:39 UTC (rev 82993)
@@ -0,0 +1,16 @@
+---
+repo-id: 'jenkins-debian-edu'
+# first capture is branch name, second capture is module name
+branch-and-module-re:
+ - "/()()"
+ignore-branch: trunk
+timeout: 7
+password: diuCai6v
+servers:
+# dam, KGB-0
+ - uri: http://kgb.ktnx.org:9418/
+# gregoa, KGB-2
+ - uri: http://colleen.colgarra.priv.at:8080/
+# Tincho, KGB-1
+ - uri: http://kgb.tincho.org:9418/
+status-dir: /home/groups/debian-edu/kgb-client-status

Added: trunk/alioth/scripts/HTMLTemplate.py
===================================================================
--- trunk/alioth/scripts/HTMLTemplate.py	                        (rev 0)
+++ trunk/alioth/scripts/HTMLTemplate.py	2014-01-24 10:02:39 UTC (rev 82993)
@@ -0,0 +1,744 @@
+"""HTMLTemplate - A fast, powerful, easy-to-use HTML templating system.
+
+See Manual.txt for documentation.
+"""
+
+# HTMLTemplate - A fast, powerful, easy-to-use HTML templating system.
+#
+# Copyright (C) 2004 HAS <hamish.sanderson at virgin.net>
+#
+# This library is free software; you can redistribute it and/or modify it under
+# the terms of the GNU Lesser General Public License as published by the Free 
+# Software Foundation; either version 2.1 of the License, or (at your option) 
+# any later version.
+#
+# This library is distributed in the hope that it will be useful, but WITHOUT 
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+# details.
+#
+# You should have received a copy of the GNU Lesser General Public License 
+# along with this library; if not, write to the Free Software Foundation, Inc.,
+# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+__all__ = ['ParseError', 'Node', 'Template']
+
+from HTMLParser import HTMLParser
+from keyword import kwlist
+import re
+
+
+#################################################
+# SUPPORT
+#################################################
+
+def renderAtts(atts):
+    # Renders an HTML tag's attributes from a list of name-value tuples.
+    result = ''
+    for name, value in atts:
+        if value is None:
+            result += ' ' + name
+        elif '"' in value:
+            result += " %s='%s'" % (name, value)
+        else:
+            result += ' %s="%s"' % (name, value)
+    return result
+
+
+def defaultEncoder(txt):
+    # Used to HTML-encode value in 'node.content = value'.
+    return txt.replace('&', '&').replace(
+            '<', '<').replace('>', '>').replace('"', '"')
+
+def defaultDecoder(txt):
+    # Used to HTML-decode content in 'value = node.content'.
+    return txt.replace('"', '"').replace(
+            '<', '<').replace('>', '>').replace('&', '&')
+
+
+#################################################
+# TEMPLATE PARSER
+#################################################
+
+class ParseError(Exception):
+    """A template parsing error."""
+    pass
+
+
+class ElementCollector:
+    # Collects a node's type, name and content as it's parsed. 
+    # When end of node is reached, the collected data is used
+    # to construct a Template/Repeater/Container instance.
+
+    def __init__(self, *args):
+        self.nodeType, self.nodeName, self.tagName, self.atts, \
+                self.isEmpty, self.omitTags, self.shouldDelete = args
+        self.content = ['']
+        self.elementNames = {}
+        self.__depth = 1
+    
+    # Methods used to track nested tags of same tag name; used to locate
+    # close tag that marks the end of this node.
+    
+    def incDepth(self):
+        self.__depth += 1
+        
+    def decDepth(self):
+        self.__depth -= 1
+        
+    def isComplete(self):
+        return self.__depth < 1
+    
+    # Methods used to collect plain HTML and any sub-nodes.
+    
+    def addText(self, txt):
+        self.content[-1] += txt
+        
+    def addElement(self, node, nodeType, nodeName):
+        self.content.extend([node, ''])
+        self.elementNames[nodeName] = nodeType
+
+
+class Parser(HTMLParser):
+
+    def unescape(self, s):
+        # kludge: avoid HTMLParser's stupid mangling of attribute values
+        return s
+        
+    # Handles parsing events sent by parseTemplate() as it processes
+    # a template string. Collects data in ElementCollector instances, 
+    # then converts these into Template/Repeater/Container objects
+    # which it assembles into a finished object model. Stack-based.
+
+    # Regular expressions used to match special tag attributes, 
+    # a.k.a. template compiler directives, that indicate an HTML
+    # element should be converted into a template node.
+    __specialAttValuePattern = re.compile('(-)?(con|rep|sep|del):(.*)')
+    __validNodeNamePattern = re.compile('[a-zA-Z][_a-zA-Z0-9]*')
+
+    # List of words already used as property and method names,
+    # so cannot be used as template node names as well:
+    __invalidNodeNames = kwlist + [
+            'content', 'raw', 'atts', 'omittags', 'omit', 'repeat', 'render']
+    
+    def __init__(self, attribute, encoder, decoder, warn):
+        HTMLParser.__init__(self)
+        self.__specialAttributeName = attribute
+        self.__encoder = encoder
+        self.__decoder = decoder
+        self.__warn = warn
+        # Each node's content is collected in an ElementCollector instance
+        # that's stored in the __outputStack stack while it's being parsed. 
+        # Once the end of the node is found, the ElementCollector's content
+        # is used to create an instance of the appropriate node class, which
+        # is then added to previous ElementCollector in the stack (i.e. the
+        # collector for its parent node).
+        self.__outputStack = [
+                ElementCollector('tem', '', None, None, False, False, False)]
+    
+    def __isSpecialTag(self, atts, specialAttName):
+        # Determines if any of an HTML tag's attributes are
+        # compiler directives.
+        for name, value in atts:
+            if name == specialAttName:
+                matchedValue = self.__specialAttValuePattern.match(value)
+                if matchedValue:
+                    atts = dict(atts)
+                    del atts[specialAttName]
+                    omitTags, nodeType, nodeName = matchedValue.groups()
+                    return True, nodeType, nodeName, omitTags, atts
+                elif self.__warn:
+                   from warnings import warn
+                   warn("Non-directive tag attribute found: %s=%r" 
+                           % (name, value))
+        return False, '', '', False, renderAtts(atts)
+    
+    def __startTag(self, tagName, atts, isEmpty):
+        # Process an HTML tag that marks the start of an HTML element, 
+        # i.e. <foo> or <foo/>. If the tag contains a compiler directive,
+        # start collecting the element's content to be turned into a 
+        # template node, otherwise reassemble it as regular HTML markup.
+        node = self.__outputStack[-1]
+        if node.shouldDelete:
+            isSpecial = 0
+        else:
+            isSpecial, nodeType, nodeName, omitTags, atts = \
+                    self.__isSpecialTag(atts, self. __specialAttributeName)
+        if isSpecial:
+            # Verify node name is legal, then process according to 
+            # directive's type (con, rep, sep, del).
+            if nodeType != 'del' and (
+                    not self.__validNodeNamePattern.match(nodeName) 
+                    or nodeName in self.__invalidNodeNames):
+                raise ParseError, "Invalid node name: %r" % nodeName
+            shouldDelete = nodeType == 'del'
+            if node.elementNames.has_key(nodeName):
+                if node.elementNames[nodeName] == nodeType:
+                    shouldDelete = True
+                elif nodeType != 'sep':
+                    raise ParseError, ("Invalid node name: %s:%s " 
+                            "(node %s:%s already found).") % (nodeType,  
+                            nodeName, node.elementNames[nodeName], nodeName)
+            self.__outputStack.append(ElementCollector(nodeType, nodeName, 
+                    tagName, atts, isEmpty, omitTags, shouldDelete))
+        else:
+            if node.tagName == tagName:
+                # Keep track of nested open tags of same name.
+                node.incDepth()
+            if not node.shouldDelete:
+                if isEmpty:
+                    endOfOpenTag = ' />'
+                else:
+                    endOfOpenTag = '>'
+                node.addText('<' + tagName + atts + endOfOpenTag)
+    
+    def __hasCompletedElement(self, element, parent):
+        # Called by __endTag when it finds the close tag that ends an HTML
+        # element denoting a template node.
+        if element.isEmpty:
+            content = []
+        else:
+            content = element.content
+        if element.nodeType in ['con', 'rep']:
+            node = makeNode(
+                    element.nodeType, element.nodeName, element.tagName, 
+                    element.atts, content, self.__encoder, self.__decoder)
+            if element.omitTags:
+                node.omittags()
+            parent.addElement(node, element.nodeType, element.nodeName)
+        else: # element.nodeType == 'sep'
+            # Add this separator to its repeater
+            for node in parent.content[1::2]:
+                if node._nodeName == element.nodeName:
+                    if node._nodeType != 'rep':
+                        raise ParseError, ("Can't process separator node "
+                                "'sep:%s': repeater node 'rep:%s' wasn't "
+                                "found. Found node '%s:%s' instead.") % (
+                                element.nodeName, element.nodeName, 
+                                element.nodeType, element.nodeName)
+                    if element.omitTags:
+                        if content:
+                            node._sep = content[0]
+                        else:
+                            node._sep = ''
+                    else:
+                        if content:
+                            node._sep = '<%s%s>%s</%s>' % (element.tagName, 
+                                    renderAtts(element.atts.items()), # FIXED
+                                    content[0], element.tagName)
+                        else:
+                            node._sep = '<%s%s />' % (element.tagName, 
+                                    renderAtts(element.atts.items())) # FIXED
+                    return
+            raise ParseError, ("Can't process separator node 'sep:%s' in node "
+                    "'%s:%s': repeater node 'rep:%s' wasn't found.") % (
+                    element.nodeName, parent.nodeType, parent.nodeName, 
+                    element.nodeName)
+    
+    def __endTag(self, tagName, isEmpty):
+        # Process an end tag that closes an HTML element, i.e. </foo> or 
+        # <foo/>. If the tag closes an HTML element representing a template
+        # node, call __hasCompletedElement() to finish that node's creation.
+        node = self.__outputStack[-1]
+        if node.tagName == tagName:
+            # Keep track of nested close tags of same name.
+            node.decDepth()
+        if node.isComplete():
+            self.__outputStack.pop()
+            if not node.shouldDelete:
+                parent = self.__outputStack[-1]
+                self.__hasCompletedElement(node, parent)
+        elif not isEmpty:
+            node.addText('</%s>' % tagName)
+
+    def __addText(self, txt):
+        self.__outputStack[-1].addText(txt)
+    
+    # event handlers; called by HTMLParser base class.
+
+    def handle_startendtag(self, tagName, atts):
+        self.__startTag(tagName, atts, True)
+        self.__endTag(tagName, True)
+
+    def handle_starttag(self, tagName, atts):
+        self.__startTag(tagName, atts, False)
+
+    def handle_endtag(self, tagName):
+        self.__endTag(tagName, False)
+
+    def handle_charref(self, txt):
+        self.__addText('&#%s;' % txt)
+
+    def handle_entityref(self, txt):
+        self.__addText('&%s;' % txt)
+
+    def handle_data(self, txt):
+        self.__addText(txt)
+
+    def handle_comment(self, txt):
+        self.__addText('<!--%s-->' % txt)
+
+    def handle_decl(self, txt):
+        self.__addText('<!%s>' % txt)
+
+    def handle_pi(self, txt):
+        self.__addText('<?%s>' % txt)
+    
+    def result(self):
+        # Get content of template's ElementCollector once parsing is done.
+        element = self.__outputStack.pop()
+        if element.nodeType != 'tem':
+            raise ParseError, ("Can't complete template: node '%s:%s' wasn't "
+                    "correctly closed.") % (element.nodeType, element.nodeName)
+        #if len(element.content) == 1:
+        #    raise ParseError, "No special %r attributes were found." % (
+        #            self. __specialAttributeName)
+        return element.content
+
+
+#################################################
+# OBJECT MODEL CLASSES
+#################################################
+
+# Note: HTMLTemplate implements its own performance-optimised object copying 
+# system which is much faster than standard lib's general-purpose deepcopy().
+# All cloning and rendering code is optimised for speed over grokability.
+
+# To summarise, cloning and rendering involves bouncing between a template
+# node's various base classes to perform the various steps of each operation
+# with child nodes being processed recursively. When cloning, all child nodes
+# are cloned as a single operation. When rendering, rather than wait until all
+# processing is complete, Repeaters perform a mini-render of their content
+# as soon as they finish rendering each clone of themselves. This reduces
+# the number of template object instances that build up during rendering,
+# reducing memory overheads, and is a bit faster than performing two separate
+# traversals, one to call the template's Controller functions to insert 
+# content, and another to traverse the (by now very large) template object
+# model to extract the finished HTML. 
+
+# Note that the one disadvantage of using incremental rendering is that it 
+# makes it awkward for an asynchronous system to acquire new template objects 
+# in advance and put them into storage for later processing. By the time the 
+# system digs these nodes back out of storage and fills them in, their content
+# has long since been rendered by some Repeater node, so any further changes
+# will not appear in the final page. Should anyone ever need to use 
+# HTMLTemplate in this fashion they can, of course, redesign the rendering
+# system so that all nodes created remain viable until a final, separate 
+# 'render everything' message is sent through the entire object model, but
+# it'll obviously cost extra in both performance and memory overheads - 
+# which is why it's not used as the standard operating model.
+
+class CloneNode(object):
+    """Makes cloned nodes."""
+    def __init__(self, node):
+        self.__dict__ = node.__dict__.copy()
+        self.__class__ = node.__class__
+
+# Node classes provide the basic functionality for a template node, with
+# additional functionality being added by the Content classes. The Python
+# implementation uses multiple inheritance to compose these behaviours;
+# languages with native support for mixins or delegates may find those
+# more appropriate (and easier for developers to follow).
+
+class Node:
+    """Abstract base class for template nodes; used for type checking when 
+       user replaces an existing template node with a new one.
+    """
+    pass
+
+class Container(Node):
+    """A Container node has a one-to-one relationship with the node 
+       that contains it.
+    """
+    
+    _nodeType = 'con'
+    
+    def __init__(self, nodeName, tagName, atts):
+        self._nodeName = nodeName
+        self._atts = dict(atts) # On cloning, shallow copy this dict.
+        if isinstance(self, NullContent):
+            self.__startTag = '<%s%%s />' % tagName
+            self.__endTag = ''
+        else:
+            self.__startTag = '<%s%%s>' % tagName
+            self.__endTag = '</%s>' % tagName
+        self.__omitTags = False
+        self._omit = False
+    
+    def _clone(self):
+        clone = CloneNode(self)
+        clone._atts = self._atts.copy()
+        return clone
+    
+    def _renderNode(self, collector):
+        # Adds node's content to supplied collector list. Tags are added
+        # here; PlainContent/RichContent's _renderContent() adds content.
+        if self.__omitTags:
+            self._renderContent(collector)
+        else:
+            collector.append(self.__startTag % renderAtts(self._atts.items()))
+            self._renderContent(collector)
+            collector.append(self.__endTag)
+
+    def _render(self, collector):
+        # Called by parent node to render this node and all its contents.
+        if not self._omit:
+            self._renderNode(collector)
+    
+    def __attsGet(self):
+        return Attributes(self._atts, self._encode, self._decode)
+    
+    def __attsSet(self, val):
+        self._atts = {}
+        atts = Attributes(self._atts, self._encode, self._decode)
+        for name, value in val.items():
+            atts[name] = value
+    
+    atts = property(__attsGet, __attsSet, 
+            doc="Get this element's tag attributes.")
+    
+    def omittags(self):
+        """Don't render this element's tag(s)."""
+        self.__omitTags = True
+    
+    def omit(self):
+        """Don't render this element."""
+        self._omit = True
+
+
+class Repeater(Container):
+    """A Repeater node has a one-to-many relationship with the node
+       that contains it.
+    """
+    
+    _nodeType = 'rep'
+    
+    def __init__(self, nodeName, tagName, atts):
+        self._sep = '\n'
+        self.__renderedContent = [] # On cloning, shallow-copy this list.
+        Container.__init__(self, nodeName, tagName, atts)
+        
+    _fastClone = Container._clone
+    
+    def _clone(self):
+        clone = Container._clone(self)
+        clone.__renderedContent = self.__renderedContent[:]
+        return clone
+    
+    def _render(self, collector):
+        # Called by parent node to render this node and all its contents.
+        if not self._omit:
+            collector.extend(self.__renderedContent[1:])
+    
+    def repeat(self, fn, list, *args):
+        """Render an instance of this node for each item in list."""
+        self.__renderedContent = collector = [] # replaces any previous content
+        # For each item in list, copy this node and pass it and the list item 
+        # to the supplied callback function. Once the function has finished
+        # inserting data into the cloned node, perform a mini-render of its
+        # content and add the result to self.__renderedContent - where it will
+        # remain until the original node is finally rendered by its parent.
+        for item in list:
+            clone = self._fastClone()
+            fn(clone, item, *args)
+            if not clone._omit:
+                collector.append(clone._sep)
+                clone._renderNode(collector)
+
+##
+
+class Attributes:
+    """Public facade for modifying a node's tag attributes. Behaves like
+       a much simplified dict object. Vended by Node's atts property.
+    """
+    
+    __attNamePattern = re.compile('^[a-zA-Z_][-.:a-zA-Z_0-9]*$')
+    
+    def __init__(self, atts, encoder, decoder):
+        self.__atts = atts # The Node's tag attributes dict.
+        self.__encode = encoder
+        self.__decode = decoder
+    
+    def __getitem__(self, name):
+        return self.__decode(self.__atts[name])
+        
+    def __setitem__(self, name, val):
+        try:
+            if not self.__attNamePattern.match(name): # Note: this 
+            # will throw a TypeError if 'name' is not string/unicode.
+                raise KeyError, "bad name."
+            if val != None:
+                if not isinstance(val, basestring):
+                    raise TypeError, "bad value: %r" % val
+                val = self.__encode(val)
+                if '"' in val and "'" in val:
+                    raise ValueError, "value %r contains " \
+                            "both single and double quotes." % val
+            self.__atts[name] = val
+        except Exception, e:
+            msg = str(e)
+            if not isinstance(name, basestring):
+                msg = "bad name."
+            raise e.__class__, "Can't set tag attribute %r: %s" % (name, msg)
+        
+    def __delitem__(self, name):
+        del self.__atts[name]
+    
+    def __repr__(self):
+        return '<Attributes [%s]>' % renderAtts(self.__atts.items())[1:]
+
+
+#######
+
+# Content classes provide nodes representing non-empty HTML elements with
+# support for containing plain HTML content/sub-nodes.
+
+class Content(object):
+    def __init__(self, encoder, decoder):
+        self._encode = encoder
+        self._decode = decoder
+    
+    def _printStructure(self, indent):
+        print indent + self._nodeType + ':' + self._nodeName
+
+##
+
+class NullContent(Content):
+    """Represents an empty HTML element's non-existent content."""
+    
+    def _renderContent(self, collector):
+        pass
+
+
+class PlainContent(Content):
+    """Represents a non-empty HTML element's content where it contains plain 
+       text/markup only.
+    """
+    
+    def __init__(self, content, encoder, decoder):
+        Content.__init__(self, encoder, decoder)
+        self.raw = content # Get/Set this element's content as raw markup;
+        # use with care.
+        
+    def _renderContent(self, collector):
+        # Called by Node classes to add HTML element's content.
+        collector.append(self.raw)
+    
+    def __contentGet(self):
+        return self._decode(self.raw)
+    
+    def __contentSet(self, txt):
+        self.raw = self._encode(txt)
+    
+    content = property(__contentGet, __contentSet, 
+            doc="Get/Set this element's content as escaped text.")
+
+
+class RichContent(Content):
+    """Represents a non-empty HTML element's content where it contains other 
+       Container/Repeater nodes.
+    """
+    
+    __validIdentifierPattern = re.compile('^[a-zA-Z_][a-zA-Z_0-9]*$')
+    
+    # KLUDGE: The following line keeps Python 2.3 sweet while it instantiates 
+    # instances of this class; without it, the process crashes hard as 
+    # __init__ conflicts with __setattr__.
+    __nodesDict = {}
+    
+    def __init__(self, content, encoder, decoder):
+        Content.__init__(self, encoder, decoder)
+        self.__nodesList = content # On cloning, deep copy this list.
+        self.__nodesDict = dict(
+                [(node._nodeName, node) for node in content[1::2]]) # (On clon-
+        # ing: replace with a new dict built from cloned self.__nodesList.)
+    
+    def __rawGet(self):
+        if self.__nodesDict:
+            raise RuntimeError, ("Can't get raw/content of a node that "
+                    "contains other nodes.")
+        else:
+            return self.__nodesList[0]
+    
+    # Note: property setting is done by __setattr__(), which takes precedence
+    # over property-based setters for some reason.
+    
+    raw = property(__rawGet, 
+            doc="Get/Set this element's raw content.")
+    
+    content = property(lambda self:self._decode(self.__rawGet()),
+            doc="Get/Set this element's content as escaped text.")
+    
+    def _initRichClone(self, clone):
+        # Once node is cloned, this is called to clone its sub-nodes.
+        clone.__nodesDict = {}
+        L = clone.__nodesList = self.__nodesList[:]
+        for i in range(1, len(L), 2):
+            clone.__nodesDict[L[i]._nodeName] = L[i] = L[i]._clone()
+        return clone
+    
+    def _renderContent(self, collector):
+        # Called by Node classes to add HTML element's content.
+        L = self.__nodesList
+        collector.append(L[0])
+        for i in range(1, len(L), 2):
+            L[i]._render(collector)
+            collector.append(L[i + 1])
+    
+    def _printStructure(self, indent):
+        Content._printStructure(self, indent)
+        for node in self.__nodesList[1::2]:
+            node._printStructure(indent + '\t')
+    
+    def __getattr__(self, name):
+        # Get a sub-node.
+        if self.__nodesDict.has_key(name):
+            return self.__nodesDict[name]
+        else:
+            raise AttributeError , "%s instance has no attribute %r." % (
+                    self.__class__.__name__, name)
+    
+    def __setattr__(self, name, value):
+        # Replace a sub-node, or replace node's content.
+        if self.__nodesDict.has_key(name):
+            if not isinstance(value, Node):
+                # Note: This type check is to catch careless user mistakes like
+                # 'node.foo = "text"' instead of  'node.foo.content = "text"'
+                raise TypeError, ("Can't replace node '%s:%s': value isn't a "
+                        "Node object.") % (self.__nodesDict[name]._nodeType,
+                         self.__nodesDict[name]._nodeName)
+            value = value._clone() 
+            value._nodeName = name
+            idx = self.__nodesList.index(self.__nodesDict[name])
+            self.__nodesDict[name] = self.__nodesList[idx] = value
+        elif name == 'content':
+            self.__nodesList = [self._encode(value)]
+            self.__nodesDict = {}
+        elif name == 'raw':
+            self.__nodesList = [value]
+            self.__nodesDict = {}
+        else:
+            self.__dict__[name] = value
+
+
+#######
+# Note: Container and Repeater objects are instantiated via the makeNode()
+# constructor function. This returns the appropriate class for the content 
+# supplied ('abstract factory'). Container and Repeater nodes are actually
+# represented by three different classes apiece, depending on whether they
+# represent empty or non-empty HTML elements and, in the case of the latter,
+# whether or not they contain any sub-nodes. The documentation glosses over
+# these details for simplicity, since the user doesn't need to know the
+# exact class of a node in order to use it.
+
+class EmptyContainer(NullContent, Container):
+    def __init__(self, nodeName, tagName, atts, content, encoder, decoder):
+        NullContent.__init__(self, encoder, decoder)
+        Container.__init__(self, nodeName, tagName, atts)
+
+
+class PlainContainer(PlainContent, Container):
+    def __init__(self, nodeName, tagName, atts, content, encoder, decoder):
+        PlainContent.__init__(self, content[0], encoder, decoder)
+        Container.__init__(self, nodeName, tagName, atts)
+
+
+class RichContainer(RichContent, Container):
+    def __init__(self, nodeName, tagName, atts, content, encoder, decoder):
+        RichContent.__init__(self, content, encoder, decoder)
+        Container.__init__(self, nodeName, tagName, atts)
+        
+    def _clone(self):
+        return self._initRichClone(Container._clone(self))
+
+##
+
+class EmptyRepeater(NullContent, Repeater):
+    def __init__(self, nodeName, tagName, atts, content, encoder, decoder):
+        NullContent.__init__(self, encoder, decoder)
+        Repeater.__init__(self, nodeName, tagName, atts)
+
+
+class PlainRepeater(PlainContent, Repeater):
+    def __init__(self, nodeName, tagName, atts, content, encoder, decoder):
+        PlainContent.__init__(self, content[0], encoder, decoder)
+        Repeater.__init__(self, nodeName, tagName, atts)
+
+
+class RichRepeater(RichContent, Repeater):
+    def __init__(self, nodeName, tagName, atts, content, encoder, decoder):
+        RichContent.__init__(self, content, encoder, decoder)
+        Repeater.__init__(self, nodeName, tagName, atts)
+        
+    def _clone(self):
+        return self._initRichClone(Repeater._clone(self))
+        
+    def _fastClone(self):
+        return self._initRichClone(Repeater._fastClone(self))
+
+##
+
+__nodeClasses = {
+        'con': {'empty': EmptyContainer, 
+                'plain': PlainContainer, 
+                'rich': RichContainer},
+        'rep': {'empty': EmptyRepeater, 
+                'plain': PlainRepeater, 
+                'rich': RichRepeater}}
+
+def makeNode(nodeType, nodeName, tagName, atts, content, encoder, decoder):
+    # Called by template parser.
+    return __nodeClasses[nodeType][{0: 'empty', 1: 'plain'}.get(len(content), 
+            'rich')](nodeName, tagName, atts, content, encoder, decoder)
+
+
+#################################################
+# MAIN
+#################################################
+
+class Template(RichContent):
+    """The top-level (i.e. root) node of the template object model."""
+    
+    _nodeType = 'tem'
+    _nodeName = ''
+    
+    def __init__(self, callback, html, attribute='node', 
+            codecs=(defaultEncoder, defaultDecoder), warnings=False):
+        """
+            callback : function -- the function that controls how this
+                    template is rendered
+            html : string or unicode -- the template HTML
+            [attribute : string or unicode] -- name of the tag attribute used
+                    to hold compiler directives
+            [codecs : tuple] -- a tuple containing two functions used by the 
+                    content property to encode/decode HTML entities
+            [warnings : boolean] -- warn when non-directive attribute
+                    is encountered
+        """
+        self.__callback = callback
+        parser = Parser(attribute, codecs[0], codecs[1], warnings)
+        parser.feed(html)
+        parser.close()
+        RichContent.__init__(self, parser.result(), *codecs)
+    
+    def render(self, *args):
+        """Render this template; *args will be passed directly to the template.
+        """
+        clone = self._initRichClone(CloneNode(self))
+        self.__callback(clone, *args)
+        collector = []
+        clone._renderContent(collector)
+        try: # quick-n-dirty error reporting; not a real substitute for type-
+            # checking for bad value assignments at point of origin, but cheap
+            return ''.join(collector)
+        except TypeError:
+            raise TypeError, ("Can't render template: some node's content was "
+                    "set to a non-text value.")
+
+    def structure(self):
+        """Print the object model's structure for diagnostic use."""
+        print '-' * 80
+        self._printStructure('')
+        print '-' * 80
+

Added: trunk/alioth/scripts/check-static
===================================================================
--- trunk/alioth/scripts/check-static	                        (rev 0)
+++ trunk/alioth/scripts/check-static	2014-01-24 10:02:39 UTC (rev 82993)
@@ -0,0 +1,5 @@
+#!/bin/sh
+
+BASE=/var/lib/gforge/chroot/home/groups/debian-med
+
+cp -rf $BASE/static/* $BASE/htdocs/


Property changes on: trunk/alioth/scripts/check-static
___________________________________________________________________
Added: svn:executable
   + *

Added: trunk/alioth/scripts/ciabot_svn.py
===================================================================
--- trunk/alioth/scripts/ciabot_svn.py	                        (rev 0)
+++ trunk/alioth/scripts/ciabot_svn.py	2014-01-24 10:02:39 UTC (rev 82993)
@@ -0,0 +1,398 @@
+#!/usr/bin/env python
+#
+# This is a CIA client script for Subversion repositories, written in python.
+# It generates commit messages using CIA's XML format, and can deliver them
+# using either XML-RPC or email. See below for usage and cuztomization
+# information.
+#
+# --------------------------------------------------------------------------
+#
+# Copyright (c) 2004-2007, Micah Dowty
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+#   * Redistributions of source code must retain the above copyright notice,
+#     this list of conditions and the following disclaimer.
+#   * Redistributions in binary form must reproduce the above copyright
+#     notice, this list of conditions and the following disclaimer in the
+#     documentation and/or other materials provided with the distribution.
+#   * The name of the author may not be used to endorse or promote products
+#     derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+#
+# --------------------------------------------------------------------------
+#
+# This script is cleaner and much more featureful than the shell
+# script version, but won't work on systems without Python.
+#
+# To use the CIA bot in your Subversion repository...
+#
+# 1. Customize the parameters below
+#
+# 2. This script should be called from your repository's post-commit
+#    hook with the repository and revision as arguments. For example,
+#    you could copy this script into your repository's "hooks" directory
+#    and add something like the following to the "post-commit" script,
+#    also in the repository's "hooks" directory:
+#
+#      REPOS="$1"
+#      REV="$2"
+#      $REPOS/hooks/ciabot_svn.py "$REPOS" "$REV" &
+#
+#    Or, if you have multiple project hosted, you can add each
+#    project's name to the commandline in that project's post-commit
+#    hook:
+#
+#      $REPOS/hooks/ciabot_svn.py "$REPOS" "$REV" "ProjectName" &
+#
+############# There are some parameters for this script that you can customize:
+
+class config:
+    # Replace this with your project's name, or always provide a project
+    # name on the commandline.
+    #
+    # NOTE: This shouldn't be a long description of your project. Ideally
+    #       it is a short identifier with no spaces, punctuation, or
+    #       unnecessary capitalization. This will be used in URLs related
+    #       to your project, as an internal identifier, and in IRC messages.
+    #       If you want a longer name shown for your project on the web
+    #       interface, please use the "title" metadata key rather than
+    #       putting that here.
+    #
+    project = "debian-med"
+
+    # Subversion's normal directory hierarchy is powerful enough that
+    # it doesn't have special methods of specifying modules, tags, or
+    # branches like CVS does.  Most projects do use a naming
+    # convention though that works similarly to CVS's modules, tags,
+    # and branches.
+    #
+    # This is a list of regular expressions that are tested against
+    # paths in the order specified. If a regex matches, the 'branch'
+    # and 'module' groups are stored and the matching section of the
+    # path is removed.
+    #
+    # Several common directory structure styles are below as defaults.
+    # Uncomment the ones you're using, or add your own regexes.
+    # Whitespace in the each regex are ignored.
+
+    pathRegexes = [
+        r"^ trunk/community|packages/(?P<module>[^/]+)/ "
+    #   r"^ (branches|tags)/ (?P<branch>[^/]+)/ ",
+    #   r"^ (branches|tags)/ (?P<module>[^/]+)/ (?P<branch>[^/]+)/ ",
+        ]
+
+    # If your repository is accessible over the web, put its base URL here
+    # and 'uri' attributes will be given to all <file> elements. This means
+    # that in CIA's online message viewer, each file in the tree will link
+    # directly to the file in your repository.
+    repositoryURI = None
+
+    # If your repository is accessible over the web via a tool like ViewVC 
+    # that allows viewing information about a full revision, put a format string
+    # for its URL here. You can specify various substitution keys in the Python
+    # syntax: "%(project)s" is replaced by the project name, and likewise
+    # "%(revision)s" and "%(author)s" are replaced by the revision / author.
+    # The resulting URI is added to the data sent to CIA. After this, in CIA's
+    # online message viewer, the commit will link directly to the corresponding
+    # revision page.
+    revisionURI = None
+    # Example (works for ViewVC as used by SourceForge.net):
+    #revisionURI = "https://svn.sourceforge.net/viewcvs.cgi/%(project)s?view=rev&rev=%(revision)s"
+
+    # This can be the http:// URI of the CIA server to deliver commits over
+    # XML-RPC, or it can be an email address to deliver using SMTP. The
+    # default here should work for most people. If you need to use e-mail
+    # instead, you can replace this with "cia at cia.navi.cx"
+    server = "http://cia.navi.cx"
+
+    # The SMTP server to use, only used if the CIA server above is an
+    # email address.
+    smtpServer = "localhost"
+
+    # The 'from' address to use. If you're delivering commits via email, set
+    # this to the address you would normally send email from on this host.
+    fromAddress = "debian-med-commit at lists.alioth.debian.org"
+
+    # When nonzero, print the message to stdout instead of delivering it to CIA.
+    debug = 0
+
+
+############# Normally the rest of this won't need modification
+
+import sys, os, re, urllib, getopt
+
+class File:
+    """A file in a Subversion repository. According to our current
+    configuration, this may have a module, branch, and URI in addition
+    to a path."""
+
+    # Map svn's status letters to our action names
+    actionMap = {
+        'U': 'modify',
+        'A': 'add',
+        'D': 'remove',
+        }
+
+    def __init__(self, fullPath, status=None):
+        self.fullPath = fullPath
+        self.path = fullPath
+        self.action = self.actionMap.get(status)
+
+    def getURI(self, repo):
+        """Get the URI of this file, given the repository's URI. This
+        encodes the full path and joins it to the given URI."""
+        quotedPath = urllib.quote(self.fullPath)
+        if quotedPath[0] == '/':
+            quotedPath = quotedPath[1:]
+        if repo[-1] != '/':
+            repo = repo + '/'
+        return repo + quotedPath
+
+    def makeTag(self, config):
+        """Return an XML tag for this file, using the given config"""
+        attrs = {}
+
+        if config.repositoryURI is not None:
+            attrs['uri'] = self.getURI(config.repositoryURI)
+
+        if self.action:
+            attrs['action'] = self.action
+
+        attrString = ''.join([' %s="%s"' % (key, escapeToXml(value,1))
+                              for key, value in attrs.items()])
+        return "<file%s>%s</file>" % (attrString, escapeToXml(self.path))
+
+
+class SvnClient:
+    """A CIA client for Subversion repositories. Uses svnlook to
+    gather information"""
+    name = 'Python Subversion client for CIA'
+    version = '1.20'
+
+    def __init__(self, repository, revision, config):
+        self.repository = repository
+        self.revision = revision
+        self.config = config
+
+    def deliver(self, message):
+        if config.debug:
+            print message
+        else:
+            server = self.config.server
+            if server.startswith('http:') or server.startswith('https:'):
+                # Deliver over XML-RPC
+                import xmlrpclib
+                xmlrpclib.ServerProxy(server).hub.deliver(message)
+            else:
+                # Deliver over email
+                import smtplib
+                smtp = smtplib.SMTP(self.config.smtpServer)
+                smtp.sendmail(self.config.fromAddress, server,
+                              "From: %s\r\nTo: %s\r\n"
+                              "Subject: DeliverXML\r\n\r\n%s" %
+                              (self.config.fromAddress, server, message))
+
+    def main(self):
+        self.collectData()
+        self.deliver("<message>" +
+                     self.makeGeneratorTag() +
+                     self.makeSourceTag() +
+                     self.makeBodyTag() +
+                     "</message>")
+
+    def makeAttrTags(self, *names):
+        """Given zero or more attribute names, generate XML elements for
+           those attributes only if they exist and are non-None.
+           """
+        s = ''
+        for name in names:
+            if hasattr(self, name):
+                v = getattr(self, name)
+                if v is not None:
+                    # Recent Pythons don't need this, but Python 2.1
+                    # at least can't convert other types directly
+                    # to Unicode. We have to take an intermediate step.
+                    if type(v) not in (type(''), type(u'')):
+                        v = str(v)
+                    
+                    s += "<%s>%s</%s>" % (name, escapeToXml(v), name)
+        return s
+
+    def makeGeneratorTag(self):
+        return "<generator>%s</generator>" % self.makeAttrTags(
+            'name',
+            'version',
+            )
+
+    def makeSourceTag(self):
+        return "<source>%s</source>" % self.makeAttrTags(
+            'project',
+            'module',
+            'branch',
+            )
+
+    def makeBodyTag(self):
+        return "<body><commit>%s%s</commit></body>" % (
+            self.makeAttrTags(
+            'revision',
+            'author',
+            'log',
+            'diffLines',
+            'url',
+            ),
+            self.makeFileTags(),
+            )
+
+    def makeFileTags(self):
+        """Return XML tags for our file list"""
+        return "<files>%s</files>" % ''.join([file.makeTag(self.config)
+                                              for file in self.files])
+
+    def svnlook(self, command):
+        """Run the given svnlook command on our current repository and
+        revision, returning all output"""
+        # We have to set LC_ALL to force svnlook to give us UTF-8 output,
+        # then we explicitly slurp that into a unicode object.
+        return unicode(os.popen(
+            'LC_ALL="en_US.UTF-8" svnlook %s -r "%s" "%s"' %
+            (command, self.revision, self.repository)).read(),
+            'utf-8', 'replace')
+
+    def collectData(self):
+        self.author = self.svnlook('author').strip()
+        self.project = self.config.project
+        self.log = self.svnlook('log')
+        self.diffLines = len(self.svnlook('diff').split('\n'))
+        self.files = self.collectFiles()
+        if self.config.revisionURI is not None:
+            self.url = self.config.revisionURI % self.__dict__
+        else:
+            self.url = None
+
+    def collectFiles(self):
+        # Extract all the files from the output of 'svnlook changed'
+        files = []
+        for line in self.svnlook('changed').split('\n'):
+            path = line[2:].strip()
+            if path:
+                status = line[0]
+                files.append(File(path, status))
+
+        # Try each of our several regexes. To be applied, the same
+        # regex must mach every file under consideration and they must
+        # all return the same results. If we find one matching regex,
+        # or we try all regexes without a match, we're done.
+        matchDict = None
+        for regex in self.config.pathRegexes:
+            matchDict = matchAgainstFiles(regex, files)
+            if matchDict is not None:
+                self.__dict__.update(matchDict)
+                break
+
+        return files
+
+
+def matchAgainstFiles(regex, files):
+    """Try matching a regex against all File objects in the provided list.
+       If the regex returns the same matches for every file, the matches
+       are returned in a dict and the matched portions are filtered out.
+       If not, returns None.
+       """
+    prevMatchDict = None
+    compiled = re.compile(regex, re.VERBOSE)
+    for f in files:
+
+        match = compiled.match(f.fullPath)
+        if not match:
+            # Give up, it must match every file
+            return None
+
+        matchDict = match.groupdict()
+        if prevMatchDict is not None and prevMatchDict != matchDict:
+            # Give up, we got conflicting matches
+            return None
+
+        prevMatchDict = matchDict
+
+    # If we got this far, the regex matched every file with
+    # the same results.  Now filter the matched portion out of
+    # each file and store the matches we found.
+    for f in files:
+        f.path = compiled.sub('', f.fullPath)
+    return prevMatchDict
+
+
+def escapeToXml(text, isAttrib=0):
+    text = unicode(text)
+    text = text.replace("&", "&")
+    text = text.replace("<", "<")
+    text = text.replace(">", ">")
+    if isAttrib == 1:
+        text = text.replace("'", "'")
+        text = text.replace("\"", """)
+    return text
+
+
+def usage():
+    """Print a short usage description of this script and exit"""
+    sys.stderr.write("Usage: %s [OPTIONS] REPOS-PATH REVISION [PROJECTNAME]\n" %
+                      sys.argv[0])
+
+
+def version():
+    """Print out the version of this script"""
+    sys.stderr.write("%s %s\n" % (sys.argv[0], SvnClient.version))
+
+
+def main():
+    try:
+        options = [ "version" ]
+        for key in config.__dict__:
+            if not key.startswith("_"):
+                options.append(key + "=");
+        opts, args = getopt.getopt(sys.argv[1:], "", options)
+    except getopt.GetoptError:
+        usage()
+        sys.exit(2)
+    
+    for o, a in opts:
+        if o == "--version":
+            version()
+            sys.exit()
+        else:
+            # Everything else maps straight to a config key. Just have
+            # to remove the "--" prefix from the option name.
+            config.__dict__[o[2:]] = a
+
+    # Print a usage message when not enough parameters are provided.
+    if not len(args) in (2,3):
+        sys.stderr.write("%s: incorrect number of arguments\n" % sys.argv[0])
+        usage();
+        sys.exit(2);
+
+    # If a project name was provided, override the default project name.
+    if len(args) == 3:
+        config.project = args[2]
+
+    # Go do the real work.
+    SvnClient(args[0], args[1], config).main()
+
+
+if __name__ == "__main__":
+    main()
+
+### The End ###


Property changes on: trunk/alioth/scripts/ciabot_svn.py
___________________________________________________________________
Added: svn:executable
   + *

Added: trunk/alioth/scripts/cronfile
===================================================================
--- trunk/alioth/scripts/cronfile	                        (rev 0)
+++ trunk/alioth/scripts/cronfile	2014-01-24 10:02:39 UTC (rev 82993)
@@ -0,0 +1,4 @@
+#m	h	dom	mon	dow	command
+00	00	*	*	*	/var/lib/gforge/chroot/home/groups/debian-med/scripts/update-bugs
+00	12	*	*	*	/var/lib/gforge/chroot/home/groups/debian-med/scripts/update-bugs
+*	*	*	*	*	/var/lib/gforge/chroot/home/groups/debian-med/scripts/check-static

Added: trunk/alioth/scripts/update-bugs
===================================================================
--- trunk/alioth/scripts/update-bugs	                        (rev 0)
+++ trunk/alioth/scripts/update-bugs	2014-01-24 10:02:39 UTC (rev 82993)
@@ -0,0 +1,338 @@
+#!/usr/bin/python
+
+#
+# This Python script is:
+#  (C) 2007, David Paleino <d.paleino at gmail.com>
+#
+# It is licensed under the terms of GNU General Public License (GPL) v2 or later.
+#
+
+import SOAPpy
+import HTMLTemplate
+import os
+import re
+from datetime import datetime
+from email.Utils import formatdate
+import time
+
+url = "http://bugs.debian.org/cgi-bin/soap.cgi"
+#base = "/var/lib/gforge/chroot/home/groups/debian-med"
+#namespace = "Debbugs/SOAP"
+#maint = "debian-med-packaging at lists.alioth.debian.org"
+#tasks_repos = "svn://svn.debian.org/svn/cdd/projects/med/trunk/debian-med/tasks/"
+base = "/var/lib/gforge/chroot/home/groups/debian-edu/htdocs/"
+namespace = "Debbugs/SOAP"
+maint = "debian-edu at lists.debian.org"
+tasks_repos = "svn://svn.debian.org/svn/debian-edu/trunk/src/debian-edu/tasks/"
+
+
+soap = SOAPpy.SOAPProxy(url, namespace)
+
+def getStatus(*args):
+	return soap.get_status(*args)
+
+def getBugs(*args):
+	"""
+		Possible keys are:
+		package, submitter, maint, src, severity, status, tag, owner, bugs
+		
+		To be called like getBugs(key, value), i.e.:
+		
+		getBugs("maint", "my at address.com")
+	"""
+	return soap.get_bugs(*args)
+
+def getField(bug, field):
+	return getStatus(bug).__getitem__('item').__getitem__('value').__getitem__(field)
+
+#<SOAPpy.Types.structType s-gensym3 at -1216426292>: {'item': 
+#<SOAPpy.Types.structType item at -1217077972>: {'value': 
+#<SOAPpy.Types.structType value at -1217031444>: {
+#'fixed_versions': [], 
+#'blockedby': '',
+#'keywords': 'unreproducible moreinfo',
+#'done': '"Nelson A. de Oliveira" <naoliv at gmail.com>',
+#'unarchived': '', 
+#'owner': '',
+#'id': 444343,
+#'subject': 'mummer: needs build dependency on libc headers and C++ compiler',
+#'forwarded': '',
+#'msgid': '<2007092721230716338.7665.reportbug at toblerone.sgn.cornell.edu>', 
+#'location': 'db-h',
+#'pending': 'done',
+#'found_date': [],
+#'originator': 'Robert Buels <rmb32 at cornell.edu>',
+#'blocks': '',
+#'tags': 'unreproducible moreinfo',
+#'date': 1190928242,
+#'mergedwith': '',
+#'severity': 'important',
+#'package': 'mummer',
+#'log_modified': 1191328025,
+#'fixed_date': [],
+#'found_versions': ['mummer/3.19-1'], 
+#'found': <SOAPpy.Types.structType found at -1216488532>: {'item': 
+#<SOAPpy.Types.structType item at -1216488340>: {'value': None, 'key': 
+#'mummer/3.19-1'}}, 'fixed': ''}, 'key': 444343}}
+
+def getSubject(bug):
+	return getField(bug, "subject")
+
+def getOriginator(bug):
+	return getField(bug, "originator")
+
+def getCloser(bug):
+	return getField(bug, "done")
+
+def getTags(bug):
+	return getField(bug, "tags")
+
+def getDate(bug):
+	return getField(bug, "date")
+
+def getSeverity(bug):
+	return getField(bug, "severity")
+
+def getPackage(bug):
+	return getField(bug, "package")
+
+def getAffectedVersions(bug):
+	return getField(bug, "found_versions")["data"]
+
+def getFixedVersions(bug):
+	return getField(bug, "fixed_versions")["data"]
+
+def getPending(bug):
+	return getField(bug, "pending")
+
+#
+# We're going to handle the HTML template here
+#
+
+# this is used later, for single-package pages
+pairs = []
+
+def renderTemplate(node, package, bugs):
+	global pairs
+	node.package.content = package
+	node.count.content = str(len(bugs))
+	
+	t = datetime.now()
+	node.date.content = formatdate(time.mktime(t.timetuple()))
+	#node.date.content = datetime.datetime.now().strftime("%a, %d %b %Y %H:%M:%S %Z")
+	#Sat, 13 Oct 2007 10:39:27 +0200
+	
+	bugs.sort()
+	openbugs = {}
+	fixedbugs = {}
+	opencount = 0
+	fixedcount = 0
+	for tuple in bugs:
+		name, id = tuple
+		if getPending(id) != "done":
+			if name not in openbugs:
+				openbugs[name] = []
+			openbugs[name].append(id)
+			opencount += 1
+		else:
+			if name not in fixedbugs:
+				fixedbugs[name] = []
+			fixedbugs[name].append(id)
+			fixedcount += 1
+	
+	openlist = openbugs.items()
+	openlist.sort()
+	node.opencount.content = str(opencount)
+	
+	fixedlist = fixedbugs.items()
+	fixedlist.sort()
+	node.fixedcount.content = str(fixedcount)
+	
+	tmp = openlist + fixedlist
+	dict = {}
+	for tuple in tmp:
+		name, bugs = tuple
+		if name not in dict:
+			dict[name] = []
+		for bug in bugs:
+			dict[name].append(bug)
+	for item in dict:
+		pairs.append((item, dict[item]))
+	
+	node.openlist.repeat(renderPackage, openlist)
+	node.fixedlist.repeat(renderPackage, fixedlist, True)
+
+def renderPackage(node, buglist, showfixed = False):
+	name, bugs = buglist
+	node.name.content = name
+	node.count.content = str(len(bugs))
+	node.numbers.repeat(renderBugs, bugs, name, showfixed)
+	
+def renderBugs(node, number, package, showfixed):
+	#url = "bug_details.php?id=%s" % str(number)
+	url = "pkgs/%s.php#%s" % (package, str(number))
+	
+	severity = getSeverity(number)
+	subject = getSubject(number)
+	
+	node.id.atts["class"] = "bugid %s" % severity
+	node.id.raw = '<a href="%s">%s</a>' % (url, str(number))
+	node.summary.atts["class"] = "summary %s" % severity
+	node.summary.raw = '<a href="%s">%s</a>' % (url, subject)
+	node.severity.atts["class"] = "severity %s" % severity
+	node.severity.content = severity
+	
+	if showfixed:
+		node.fixed.atts["class"] = "fixed %s" % severity
+		value = "<br />".join(getFixedVersions(number)).replace("%s/" % package, "")
+		node.fixed.raw = value
+	
+#
+# These are the single-package pages method
+#
+
+def renderStatic(node, package, bugs):
+	node.package.content = package
+	node.count.content = str(len(bugs))
+	
+	t = datetime.now()
+	node.date.content = formatdate(time.mktime(t.timetuple()))
+	
+	node.allbugs.repeat(renderStaticBugs, bugs, package)
+
+def renderStaticBugs(node, bug, package):
+	node.id.content = str(bug)
+	node.id.atts["href"] = "http://bugs.debian.org/%s" % str(bug)
+	node.id.atts["name"] = str(bug)
+	fields = ["Subject",
+		"Sender",
+		"Tags",
+		"Date",
+		"Severity",
+		"Found in",
+		"Fixed in"]
+	node.singlebug.repeat(renderStaticBugDetails, fields, bug, package)
+
+def renderStaticBugDetails(node, field, bug, package):
+	node.field.raw = '<?=_("%s")?>' % field
+	if field == "Subject":
+		value = getSubject(bug)
+	elif field == "Sender":
+		value = getOriginator(bug)
+	elif field == "Tags":
+		value = getTags(bug)
+	elif field == "Date":
+		value = datetime.fromtimestamp(getDate(bug)).strftime("%c")
+	elif field == "Severity":
+		value = getSeverity(bug)
+	elif field == "Found in":
+		value = " ".join(getAffectedVersions(bug)).replace("%s/" % package, "")
+	elif field == "Fixed in":
+		value = " ".join(getFixedVersions(bug)).replace("%s/" % package, "")
+	
+	node.value.content = str(value).strip()
+
+#
+# This is used to parse Task files.
+#
+
+tasks_packages = []
+def parseTask(file):
+	global tasks_packages
+	tmpone = []
+	tmp = []
+	
+	pattern = re.compile(r"Depends:")
+	continued = False
+	for line in file.readlines():
+		match = pattern.match(line)
+		if match and not continued:
+			tmpone.append(line.replace("Depends:", "").strip().split(","))
+			if line.strip().endswith("\\") == True:
+				continued = True
+				continue
+		elif continued == True:
+			tmpone.append(line.strip().split(","))
+			if line.strip().endswith("\\") == True:
+				continued = True
+			else:
+				continued = False
+			
+			continue
+	
+	for item in tmpone:
+		if type(item) == str:
+			tmp.append(item.split("|"))
+		elif type(item) == list:
+			for inner in item:
+				tmp.append(inner.split("|"))
+	
+	for item in tmp:
+		if type(item) == str and item != "":
+			tasks_packages.append(item.strip())
+		elif type(item) == list:
+			for inner in item:
+				if inner != "":
+					tasks_packages.append(inner.strip())
+	
+	tmp = tasks_packages
+	try:
+		tasks_packages = list(set(tmp.remove('\\')))
+	except:
+		tasks_packages = list(set(tmp))
+	
+	tasks_packages.sort()
+
+#
+# Let's get our task files
+#
+
+tasks = "%s/%s" % (base, "tasks")
+os.system("svn co %s %s >> /dev/null" % (tasks_repos, tasks))
+
+for file in os.listdir(tasks):
+	if os.path.isfile("%s/%s" % (tasks, file)):
+		f = open("%s/%s" % (tasks, file))
+		parseTask(f)
+		f.close()
+
+#
+# Let's get our bugs
+#
+
+bugs = []
+for package in tasks_packages:
+	for bug in getBugs("package", package):
+		bugs.append((package, bug))
+
+#bugs = [("a",1),("b",2),("b",3),("c",0),("c",4),("a",67809),("c",1208)]
+
+#
+# Let's render bugs.php
+#
+
+f = open("%s/htdocs/bugs.tmpl" % base)
+tmpl = HTMLTemplate.Template(renderTemplate, f.read())
+f.close()
+
+package = "all"
+
+f = open("%s/static/bugs.php" % base, "w")
+f.write(tmpl.render(package, bugs))
+f.close()
+
+#
+# Let's do the <package>.php pages
+#
+
+for pair in pairs:
+	name, bugs = pair
+	outfile = "%s.php" % name
+	
+	f = open("%s/htdocs/bug_details.tmpl" % base)
+	tmpl = HTMLTemplate.Template(renderStatic, f.read())
+	f.close
+	
+	f = open("%s/static/pkgs/%s" % (base, outfile), "w")
+	f.write(tmpl.render(name, bugs))
+	f.close()


Property changes on: trunk/alioth/scripts/update-bugs
___________________________________________________________________
Added: svn:executable
   + *

Added: trunk/alioth/scripts/update-website
===================================================================
--- trunk/alioth/scripts/update-website	                        (rev 0)
+++ trunk/alioth/scripts/update-website	2014-01-24 10:02:39 UTC (rev 82993)
@@ -0,0 +1,20 @@
+#!/bin/sh
+
+umask 002
+
+REPOS=$1
+REV=$2
+URL_REPOS="svn://svn.debian.org/svn/debian-med/trunk/community/website/"
+BASE=/var/lib/gforge/chroot/home/groups/debian-med
+
+echo "Updating website... rev. $REV"
+mv $BASE/htdocs/* $BASE/htdocs-backup/ && rm -rf $BASE/htdocs/*
+svn --force export $URL_REPOS $BASE/htdocs/
+[ "x$?" == "x0" ] && rm -rf $BASE/htdocs-backup/*
+
+# let's substitute our variables...
+AUTH=$(svnlook author $REPOS -r $REV | sed 's/\&/\&/g;s/</\</g;s/>/\>/g')
+
+sed -e "s/#REV#/$REV/" \
+    -e "s/#DATE#/`date -uR`/" \
+    -e "s/#AUTHOR#/$AUTH/g" -i $BASE/htdocs/inc/footer.inc.php


Property changes on: trunk/alioth/scripts/update-website
___________________________________________________________________
Added: svn:executable
   + *




More information about the debian-edu-commits mailing list