Subversion Repositories Scribus

Rev

Rev 12490 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
12490 malex 1
#!/usr/bin/python
2
# Copyright (c) 2007, Oleksandr Moskalenko, Craig Ringer
3
# All rights reserved.
4
#
5
#    This program is free software: you can redistribute it and/or modify
6
#    it under the terms of the GNU General Public License as published by
7
#    the Free Software Foundation, either version 3 of the License, or
8
#    (at your option) any later version.
9
#
10
#    This program is distributed in the hope that it will be useful,
11
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
12
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
#    GNU General Public License for more details.
14
#
15
#    You should have received a copy of the GNU General Public License
16
#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
17
###
18
"""Subversion XML parser
19
"""
20
__version__ = "0.1"
21
__license__ = "GPLv2"
22
__copyright__ = "Copyright 2007, Oleksandr Moskalenko"
23
__author__ = "Oleksandr Moskalenko <malex@tagancha.org>"
24
__contributors__ = ["Craig Ringer <craig@postnewspapers.com.au>"]
25
_debug = 1
26
 
27
# HTTP "User-Agent" header to send to servers when downloading Svn XML.
28
USER_AGENT = "SubversionXMLParser/%s +http://linux.tagancha.org/svnxmlparser" % __version__
29
# HTTP "Accept" header to send to servers when downloading Svn XML.  If you don't
30
# want to send an Accept header, set this to None.
31
ACCEPT_HEADER = "text/xml"
32
 
33
def fetchXml(uri, rev):
12512 malex 34
    """Fetches a document from the given uri (with gzip encoding). Returns the
12490 malex 35
        document as a string, or an empty string in case of a transmission problem."""
36
    import urllib2, gzip, StringIO
37
    try:
38
        revuri = "%s?%s" % (uri,rev)
39
        request = urllib2.Request(revuri)
40
        request.add_header('Accept-encoding', 'gzip')
41
        opener = urllib2.build_opener()
42
        handle = opener.open(request)
43
        compressedData = handle.read()
44
#        print 'Fetched ', len(compressedData), ' bytes.'
45
        compressedStream = StringIO.StringIO(compressedData)
46
        gzipper = gzip.GzipFile(fileobj=compressedStream,mode='r')
47
        xml = gzipper.read()
48
        if len(xml) <= 28:
49
            print "No commit for this revision\n"
50
            return  None
51
        return xml
52
    except:
53
        return None
54
 
55
def longest_common_prefix_for_paths(paths):
56
    '''
57
    Find the longest common prefix of `paths' and return it.
58
    `paths' must be a list of strings, using / as a path component
59
    separator.
60
    '''
61
    if len(paths) == 1:
62
        # use just this path
63
        return paths[0]
64
    else:
65
        # find common prefix
66
        p = [ x.split('/') for x in paths ]
67
        maxi = reduce( min, map( len, p ) )
68
        for i in range(0, maxi):
69
            if not reduce( lambda a,b: a and (b[i] == paths[0][i]),\
70
                           paths[1:], True):
71
                break
72
        return '/'.join(p[0][0:i])
73
 
74
def getText(nodelist):
75
    rc = ""
76
    for node in nodelist:
77
        if node.nodeType == node.TEXT_NODE:
78
            rc = rc + node.data
79
    return rc
80
 
81
def getCommit (xml):
82
    """Parses Svn XML and returns a dictionary containing commit data."""
83
    if xml == None:
84
        return xml
85
    from xml.dom import minidom, Node
86
    xmltree = minidom.parseString(xml)
87
    logentries = xmltree.getElementsByTagName('logentry')
88
    logdata = {}
89
    for logentry in logentries:
90
        if logentry.hasAttributes():
91
            revision = logentry.getAttribute('revision')
92
            logdata[revision]= {}
93
            logdata[revision]['author'] = logentry.getElementsByTagName('author')[0].childNodes[0].data
94
            logdata[revision]['date'] = logentry.getElementsByTagName('date')[0].childNodes[0].data
95
            try:
96
                logdata[revision]['msg'] = logentry.getElementsByTagName('msg')[0].childNodes[0].data
97
            except IndexError:
98
                logdata[revision]['msg'] = ""
99
            paths = []
100
            for path in logentry.getElementsByTagName("paths")[0].childNodes:
101
                if path.nodeType == Node.ELEMENT_NODE:
102
                    paths.append(path.childNodes[0].data)
103
            logdata[revision]['paths'] = paths
104
            common_path = longest_common_prefix_for_paths(paths)
105
            logdata[revision]['common_path'] = common_path
106
            short_paths = []
107
            for path in paths:
108
                try:
109
                    short_paths.append(path.split(common_path)[1][1:])
110
                except IndexError:
111
                    pass
112
            logdata[revision]['short_paths'] = short_paths
113
    return logdata
114
 
115
def printoutput(commitdata):
116
    datakeys = commitdata.keys()
117
    datakeys.sort()
118
    for i in datakeys:
119
        logentry = commitdata[i]
120
        logentry.keys().sort()
121
        print "Revision: " + str(i)
122
        for j in logentry.keys():
123
            if type(logentry[j]) != list:
124
                print "%s: \t %s" % (j,logentry[j].strip())
125
            else:
126
                print j+":"
127
                for k in logentry[j]:
128
                    print "\t "+k
129
 
130
def getbranch(logentry):
131
    import sys
132
    fullpath = logentry['common_path']
133
    pathelements = fullpath.split("/")
12512 malex 134
    print pathelements
12490 malex 135
    if pathelements[1] == 'trunk':
136
        return 'trunk'
137
    else:
12512 malex 138
        return "%s" % "/".join(pathelements)
12490 malex 139
 
140
def shortoutput(commitdata):
141
    outlist = []
142
    datakeys = commitdata.keys()
143
    datakeys.sort()
144
    for i in datakeys:
145
        logentry = commitdata[i]
146
        logentry.keys().sort()
147
        from datetime import datetime
148
        from time import strptime
149
        indatetime = logentry["date"].split('.')[0]
150
        rawdatetime = datetime(*strptime(indatetime, "%Y-%m-%dT%H:%M:%S")[0:6])
151
        outdate,outtime = rawdatetime.strftime("%Y-%m-%d %H:%M:%S").split(" ")
152
        branch = getbranch(logentry)
153
        outstr = "revision %s by %s in %s on %s at %s - %s" % (i, logentry["author"], branch, outdate, outtime, logentry["msg"])
154
        finalstr = outstr.replace("\n", " ")
155
        outlist.append(finalstr)
156
    return outlist
157
#        for j in logentry.keys():
158
#            #FIXME
159
#            if type(logentry[j]) != list:
160
#                print "%s: \t %s" % (j,logentry[j].strip())
161
#            else:
162
#                print j+":"
163
#                for k in logentry[j]:
164
#                    print "\t "+k
165
 
166
def processUri(xmluri,rev):
167
    print xmluri
168
    rawxml = fetchXml(xmluri,rev)
169
    commitdata = getCommit(rawxml)
170
    if commitdata == None:
171
        return None
172
    else:
173
        outdata = shortoutput(commitdata)
174
        return outdata
175
 
176
def getHead(xmluri):
177
    """Fetches the head revision number for internal processing. Returns 'HEAD'
178
    in case of error or misconfiguration."""
179
    rev = "HEAD"
180
    rawxml = fetchXml(xmluri,rev)
181
    commitdata = getCommit(rawxml)
182
    if commitdata == None:
183
        return None
184
    else:
185
        return commitdata.keys()[0]
186
 
187
def Main ():
188
    import sys
189
    """Called when the program is used interactively."""
190
    if len(sys.argv)>1:
191
        args = sys.argv[1:]
192
#        print args
193
    else:
194
        args = ['HEAD']
195
    for i in args:
196
        print "Fetching commit information for '%s':" % i
12512 malex 197
        uri = args[1]
198
        xml = fetchXml(uri,i)
12490 malex 199
        commitdata = getCommit(xml)
200
        if commitdata == None:
201
            sys.exit()
202
        out = shortoutput(commitdata)
203
        for i in out:
204
            print i
205
    sys.exit()
206
 
207
if __name__ == '__main__':
208
    Main()