aboutsummaryrefslogtreecommitdiffstats
path: root/modules/subversion/templates/ciabot_svn.py
diff options
context:
space:
mode:
Diffstat (limited to 'modules/subversion/templates/ciabot_svn.py')
-rw-r--r--modules/subversion/templates/ciabot_svn.py398
1 files changed, 0 insertions, 398 deletions
diff --git a/modules/subversion/templates/ciabot_svn.py b/modules/subversion/templates/ciabot_svn.py
deleted file mode 100644
index ab7828b4..00000000
--- a/modules/subversion/templates/ciabot_svn.py
+++ /dev/null
@@ -1,398 +0,0 @@
-#!/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 = "Mageia"
-
- # 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/ (?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@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 = "cia-user@localhost"
-
- # 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("&", "&amp;")
- text = text.replace("<", "&lt;")
- text = text.replace(">", "&gt;")
- if isAttrib == 1:
- text = text.replace("'", "&apos;")
- text = text.replace("\"", "&quot;")
- 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 ###