File svn-gource.py of Package gource

#!/usr/bin/python
## Copyright (c) 2009 Cameron Hart (cam@bitshifter.net.nz)
## All rights reserved.
##
## Redistribution and use in source and binary forms, with or without
## modification, are permitted provided that the following conditions
## are met:
## 1. Redistributions of source code must retain the above copyright
##    notice, this list of conditions and the following disclaimer.
## 2. 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.
## 3. 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 AUTHOR ``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 AUTHOR 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.
import sys
import time
import getopt
import re
from xml.etree import ElementTree

opt_filter_dirs = False

_USAGE = """
svn-gource.py [--help] [--filter-dirs] <file>

The input file must be the output of the command svn log --verbose --xml.
"""

# regular expression for matching any file with an extension
extn_prog = re.compile(".*/?[^/]+\.[^\.]+$")

def reverse(data):
    """Returns the log entries in reverse."""
    for index in range(len(data)-1, -1, -1):
        yield data[index]

def processXmltree(xmltree):
    global opt_filter_dirs
    for logentry in reverse(xmltree.getiterator("logentry")):
        datetext = logentry.find("date").text

        # svn xml logs always use UTC
        timestamp = (time.mktime(time.strptime(datetext[:-8], "%Y-%m-%dT%H:%M:%S")))
        # a bit of a hack to get it into local time again...
        #timestamp = timestamp - time.timezone

        #author might not exist
        try:
            author = logentry.find("author").text
        except:
            author = ""

        # output all affected files
        for pathentry in logentry.getiterator("path"):

            # apply directory filtering strategy
            if opt_filter_dirs and not re.match(extn_prog, pathentry.text):
                continue;

            # join output
            print( "|".join( ( "%d" % int(timestamp), "%s" % author.encode("utf-8"), "%s" % pathentry.get("action"), "%s" % pathentry.text.encode("utf-8"), "" ) ) )

def printUsage(message):
    sys.stderr.write(_USAGE)
    if message:
        sys.exit('\nFATAL ERROR: ' + message)
    else:
        sys.exit(1)

def processArguments():
    global opt_filter_dirs

    try:
        opts, filenames = getopt.getopt(sys.argv[1:], '', ['help', 'filter-dirs'])
    except getopt.GetoptError:
        printUsage('Invalid arguments.')

    for (opt, val) in opts:
        if opt == '--help':
            printUsage(None)
        elif opt == '--filter-dirs':
            opt_filter_dirs = True

    if not filenames:
        printUsage('No input file specified.')

    return filenames[0]


if __name__ == "__main__":
    filename = processArguments()

    xmltree = ElementTree.parse(filename)

    processXmltree(xmltree)