Subversion Repositories Scribus

Rev

Go to most recent revision | Details | 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
# Default URI:
34
URI = "https://www.postnewspapers.com.au/cgi-bin/xmllog"
35
 
36
def fetchXml(uri, rev):
37
    """Fetches a document from the given URI (with gzip encoding). Returns the
38
        document as a string, or an empty string in case of a transmission problem."""
39
    import urllib2, gzip, StringIO
40
    try:
41
        revuri = "%s?%s" % (uri,rev)
42
        request = urllib2.Request(revuri)
43
        request.add_header('Accept-encoding', 'gzip')
44
        opener = urllib2.build_opener()
45
        handle = opener.open(request)
46
        compressedData = handle.read()
47
#        print 'Fetched ', len(compressedData), ' bytes.'
48
        compressedStream = StringIO.StringIO(compressedData)
49
        gzipper = gzip.GzipFile(fileobj=compressedStream,mode='r')
50
        xml = gzipper.read()
51
        if len(xml) <= 28:
52
            print "No commit for this revision\n"
53
            return  None
54
        return xml
55
    except:
56
        return None
57
 
58
def longest_common_prefix_for_paths(paths):
59
    '''
60
    Find the longest common prefix of `paths' and return it.
61
    `paths' must be a list of strings, using / as a path component
62
    separator.
63
    '''
64
    if len(paths) == 1:
65
        # use just this path
66
        return paths[0]
67
    else:
68
        # find common prefix
69
        p = [ x.split('/') for x in paths ]
70
        maxi = reduce( min, map( len, p ) )
71
        for i in range(0, maxi):
72
            if not reduce( lambda a,b: a and (b[i] == paths[0][i]),\
73
                           paths[1:], True):
74
                break
75
        return '/'.join(p[0][0:i])
76
 
77
def getText(nodelist):
78
    rc = ""
79
    for node in nodelist:
80
        if node.nodeType == node.TEXT_NODE:
81
            rc = rc + node.data
82
    return rc
83
 
84
def getCommit (xml):
85
    """Parses Svn XML and returns a dictionary containing commit data."""
86
    if xml == None:
87
        return xml
88
    from xml.dom import minidom, Node
89
    xmltree = minidom.parseString(xml)
90
    logentries = xmltree.getElementsByTagName('logentry')
91
    logdata = {}
92
    for logentry in logentries:
93
        if logentry.hasAttributes():
94
            revision = logentry.getAttribute('revision')
95
            logdata[revision]= {}
96
            logdata[revision]['author'] = logentry.getElementsByTagName('author')[0].childNodes[0].data
97
            logdata[revision]['date'] = logentry.getElementsByTagName('date')[0].childNodes[0].data
98
            try:
99
                logdata[revision]['msg'] = logentry.getElementsByTagName('msg')[0].childNodes[0].data
100
            except IndexError:
101
                logdata[revision]['msg'] = ""
102
            paths = []
103
            for path in logentry.getElementsByTagName("paths")[0].childNodes:
104
                if path.nodeType == Node.ELEMENT_NODE:
105
                    paths.append(path.childNodes[0].data)
106
            logdata[revision]['paths'] = paths
107
            common_path = longest_common_prefix_for_paths(paths)
108
            logdata[revision]['common_path'] = common_path
109
            short_paths = []
110
            for path in paths:
111
                try:
112
                    short_paths.append(path.split(common_path)[1][1:])
113
                except IndexError:
114
                    pass
115
            logdata[revision]['short_paths'] = short_paths
116
    return logdata
117
 
118
def printoutput(commitdata):
119
    datakeys = commitdata.keys()
120
    datakeys.sort()
121
    for i in datakeys:
122
        logentry = commitdata[i]
123
        logentry.keys().sort()
124
        print "Revision: " + str(i)
125
        for j in logentry.keys():
126
            if type(logentry[j]) != list:
127
                print "%s: \t %s" % (j,logentry[j].strip())
128
            else:
129
                print j+":"
130
                for k in logentry[j]:
131
                    print "\t "+k
132
 
133
def getbranch(logentry):
134
    import sys
135
    fullpath = logentry['common_path']
136
    pathelements = fullpath.split("/")
137
    if pathelements[1] == 'trunk':
138
        return 'trunk'
139
    else:
140
        return "%s" % pathelements[2]
141
 
142
def shortoutput(commitdata):
143
    outlist = []
144
    datakeys = commitdata.keys()
145
    datakeys.sort()
146
    for i in datakeys:
147
        logentry = commitdata[i]
148
        logentry.keys().sort()
149
        from datetime import datetime
150
        from time import strptime
151
        indatetime = logentry["date"].split('.')[0]
152
        rawdatetime = datetime(*strptime(indatetime, "%Y-%m-%dT%H:%M:%S")[0:6])
153
        outdate,outtime = rawdatetime.strftime("%Y-%m-%d %H:%M:%S").split(" ")
154
        branch = getbranch(logentry)
155
        outstr = "revision %s by %s in %s on %s at %s - %s" % (i, logentry["author"], branch, outdate, outtime, logentry["msg"])
156
        finalstr = outstr.replace("\n", " ")
157
        outlist.append(finalstr)
158
    return outlist
159
#        for j in logentry.keys():
160
#            #FIXME
161
#            if type(logentry[j]) != list:
162
#                print "%s: \t %s" % (j,logentry[j].strip())
163
#            else:
164
#                print j+":"
165
#                for k in logentry[j]:
166
#                    print "\t "+k
167
 
168
def processUri(xmluri,rev):
169
    print xmluri
170
    rawxml = fetchXml(xmluri,rev)
171
    commitdata = getCommit(rawxml)
172
    if commitdata == None:
173
        return None
174
    else:
175
        outdata = shortoutput(commitdata)
176
        return outdata
177
 
178
def getHead(xmluri):
179
    """Fetches the head revision number for internal processing. Returns 'HEAD'
180
    in case of error or misconfiguration."""
181
    rev = "HEAD"
182
    rawxml = fetchXml(xmluri,rev)
183
    commitdata = getCommit(rawxml)
184
    if commitdata == None:
185
        return None
186
    else:
187
        return commitdata.keys()[0]
188
 
189
def Main ():
190
    import sys
191
    """Called when the program is used interactively."""
192
    if len(sys.argv)>1:
193
        args = sys.argv[1:]
194
#        print args
195
    else:
196
        args = ['HEAD']
197
    for i in args:
198
        print "Fetching commit information for '%s':" % i
199
        xml = fetchXml(URI,i)
200
        commitdata = getCommit(xml)
201
        if commitdata == None:
202
            sys.exit()
203
        out = shortoutput(commitdata)
204
        for i in out:
205
            print i
206
    sys.exit()
207
 
208
if __name__ == '__main__':
209
    Main()