0,0 → 1,209 |
#!/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() |