Subversion Repositories Scribus

Rev

Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

#!/usr/bin/python
# Copyright (c) 2007, Oleksandr Moskalenko, Craig Ringer
# All rights reserved.
#
#    This program is free software: you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation, either version 3 of the License, or
#    (at your option) any later version.
#
#    This program 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 General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
###
"""Subversion XML parser
"""

__version__ = "0.1"
__license__ = "GPLv2"
__copyright__ = "Copyright 2007, Oleksandr Moskalenko"
__author__ = "Oleksandr Moskalenko <malex@tagancha.org>"
__contributors__ = ["Craig Ringer <craig@postnewspapers.com.au>"]
_debug = 1

# HTTP "User-Agent" header to send to servers when downloading Svn XML.
USER_AGENT = "SubversionXMLParser/%s +http://linux.tagancha.org/svnxmlparser" % __version__
# HTTP "Accept" header to send to servers when downloading Svn XML.  If you don't
# want to send an Accept header, set this to None.
ACCEPT_HEADER = "text/xml"

# Default URI:
URI = "https://www.postnewspapers.com.au/cgi-bin/xmllog"

def fetchXml(uri, rev):
    """Fetches a document from the given URI (with gzip encoding). Returns the
        document as a string, or an empty string in case of a transmission problem."""

    import urllib2, gzip, StringIO
    try:
        revuri = "%s?%s" % (uri,rev)
        request = urllib2.Request(revuri)
        request.add_header('Accept-encoding', 'gzip')
        opener = urllib2.build_opener()
        handle = opener.open(request)
        compressedData = handle.read()
#        print 'Fetched ', len(compressedData), ' bytes.'
        compressedStream = StringIO.StringIO(compressedData)
        gzipper = gzip.GzipFile(fileobj=compressedStream,mode='r')
        xml = gzipper.read()
        if len(xml) <= 28:
            print "No commit for this revision\n"
            return  None
        return xml
    except:
        return None

def longest_common_prefix_for_paths(paths):
    '''
    Find the longest common prefix of `paths'
and return it.
    `paths' must be a list of strings, using / as a path component
    separator.
    '
''
    if len(paths) == 1:
        # use just this path
        return paths[0]
    else:
        # find common prefix
        p = [ x.split('/') for x in paths ]
        maxi = reduce( min, map( len, p ) )
        for i in range(0, maxi):
            if not reduce( lambda a,b: a and (b[i] == paths[0][i]),\
                           paths[1:], True):
                break
        return '/'.join(p[0][0:i])

def getText(nodelist):
    rc = ""
    for node in nodelist:
        if node.nodeType == node.TEXT_NODE:
            rc = rc + node.data
    return rc

def getCommit (xml):
    """Parses Svn XML and returns a dictionary containing commit data."""
    if xml == None:
        return xml
    from xml.dom import minidom, Node
    xmltree = minidom.parseString(xml)
    logentries = xmltree.getElementsByTagName('logentry')
    logdata = {}
    for logentry in logentries:
        if logentry.hasAttributes():
            revision = logentry.getAttribute('revision')
            logdata[revision]= {}
            logdata[revision]['author'] = logentry.getElementsByTagName('author')[0].childNodes[0].data
            logdata[revision]['date'] = logentry.getElementsByTagName('date')[0].childNodes[0].data
            try:
                logdata[revision]['msg'] = logentry.getElementsByTagName('msg')[0].childNodes[0].data
            except IndexError:
                logdata[revision]['msg'] = ""
            paths = []
            for path in logentry.getElementsByTagName("paths")[0].childNodes:
                if path.nodeType == Node.ELEMENT_NODE:
                    paths.append(path.childNodes[0].data)
            logdata[revision]['paths'] = paths
            common_path = longest_common_prefix_for_paths(paths)
            logdata[revision]['common_path'] = common_path
            short_paths = []
            for path in paths:
                try:
                    short_paths.append(path.split(common_path)[1][1:])
                except IndexError:
                    pass
            logdata[revision]['short_paths'] = short_paths
    return logdata

def printoutput(commitdata):
    datakeys = commitdata.keys()
    datakeys.sort()
    for i in datakeys:
        logentry = commitdata[i]
        logentry.keys().sort()
        print "Revision: " + str(i)
        for j in logentry.keys():
            if type(logentry[j]) != list:
                print "%s: \t %s" % (j,logentry[j].strip())
            else:
                print j+":"
                for k in logentry[j]:
                    print "\t "+k

def getbranch(logentry):
    import sys
    fullpath = logentry['common_path']
    pathelements = fullpath.split("/")
    if pathelements[1] == 'trunk':
        return 'trunk'
    else:
        return "%s" % pathelements[2]

def shortoutput(commitdata):
    outlist = []
    datakeys = commitdata.keys()
    datakeys.sort()
    for i in datakeys:
        logentry = commitdata[i]
        logentry.keys().sort()
        from datetime import datetime
        from time import strptime
        indatetime = logentry["date"].split('.')[0]
        rawdatetime = datetime(*strptime(indatetime, "%Y-%m-%dT%H:%M:%S")[0:6])
        outdate,outtime = rawdatetime.strftime("%Y-%m-%d %H:%M:%S").split(" ")
        branch = getbranch(logentry)
        outstr = "revision %s by %s in %s on %s at %s - %s" % (i, logentry["author"], branch, outdate, outtime, logentry["msg"])
        finalstr = outstr.replace("\n", " ")
        outlist.append(finalstr)
    return outlist
#        for j in logentry.keys():
#            #FIXME
#            if type(logentry[j]) != list:
#                print "%s: \t %s" % (j,logentry[j].strip())
#            else:
#                print j+":"
#                for k in logentry[j]:
#                    print "\t "+k

def processUri(xmluri,rev):
    print xmluri
    rawxml = fetchXml(xmluri,rev)
    commitdata = getCommit(rawxml)
    if commitdata == None:
        return None
    else:
        outdata = shortoutput(commitdata)
        return outdata

def getHead(xmluri):
    """Fetches the head revision number for internal processing. Returns 'HEAD'
    in case of error or misconfiguration."""

    rev = "HEAD"
    rawxml = fetchXml(xmluri,rev)
    commitdata = getCommit(rawxml)
    if commitdata == None:
        return None
    else:
        return commitdata.keys()[0]

def Main ():
    import sys
    """Called when the program is used interactively."""
    if len(sys.argv)>1:
        args = sys.argv[1:]
#        print args
    else:
        args = ['HEAD']
    for i in args:
        print "Fetching commit information for '%s':" % i
        xml = fetchXml(URI,i)
        commitdata = getCommit(xml)
        if commitdata == None:
            sys.exit()
        out = shortoutput(commitdata)
        for i in out:
            print i
    sys.exit()

if __name__ == '__main__':
    Main()