[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