3 # Copyright (c) 2007 Kimmo Varis
4 # Permission is hereby granted, free of charge, to any person obtaining
5 # a copy of this software and associated documentation files
6 # (the "Software"), to deal in the Software without restriction, including
7 # without limitation the rights to use, copy, modify, merge, publish,
8 # distribute, sublicense, and/or sell copies of the Software, and to
9 # permit persons to whom the Software is furnished to do so, subject to
10 # the following conditions:
11 # The above copyright notice and this permission notice shall be included
12 # in all copies or substantial portions of the Software.
13 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
14 # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
15 # OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
16 # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
17 # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
18 # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
19 # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 # This script gets log from Subversion as XML, parses it
25 svn_binary = 'C:\\Program Files\\Subversion\\bin\\svn.exe'
28 # Paramaters to output all info into XML, limit count is appended later
29 svn_params = [' --verbose', ' --xml', ' --limit']
31 from xml.dom.minidom import parseString
36 def run_svn(revisions):
37 """This function runs svn log command and returns output of it.
39 Returns SVN log as XML string.
41 svn_params.append(' %s' % revisions)
42 command = [svn_binary, svn_command, svn_params]
43 #os.chdir("G:\\WinMerge\\WinMerge_SVN")
44 print "Reading log from Subversion. This may take a while...\n"
45 output = subprocess.Popen(command, stdout = subprocess.PIPE).communicate()[0]
48 def parse_xml(xml_string):
49 """This function parses XML string to list of log entries.
51 Returns list log entries as strings.
53 dom1 = parseString(xml_string)
54 top_element = dom1.documentElement
56 for e in top_element.childNodes:
57 revision = get_revision(e)
58 item = parse_element(e)
60 log_line = revision, item[0], item[1], item[2]
61 log_list.append(log_line)
65 def get_revision(elem):
66 """ This function gets revision number from given element.
68 Returns revision number as string.
71 if elem.attributes != None:
72 attrib = elem.attributes["revision"]
74 revision = attrib.value
77 def parse_element(elem):
78 """ This function parses log data from one element it gets.
80 Returns tuple having date, author and message
87 for e in elem.childNodes:
88 if e.nodeType == e.ELEMENT_NODE:
89 if e.localName == "msg":
91 if e.localName == "author":
93 if e.localName == "date":
95 if msg_element != None and author_element != None and date_element != None:
97 # There might be empty log messages
98 if len(msg_element.childNodes) > 0:
99 msg = msg_element.childNodes[0].nodeValue
100 author = author_element.childNodes[0].nodeValue
101 date = date_element.childNodes[0].nodeValue
102 item = date, author, msg
106 def generate_output(log_lines):
108 output_log_lines(log_lines)
111 print 'This is WinMerge changelog generated by a script.'
112 print 'Log has been generated from WinMerge subversion repository.\n'
114 def output_log_lines(log_lines):
115 for line in log_lines:
118 author = line[2] + ':'
121 # If the log is about release, make it a header (with underline)
122 if msg.startswith('WinMerge') and (msg.find('Stable') > 0 or
123 msg.find('Beta') > 0 or
124 msg.find('Experimental')):
127 title = "\nWinMerge %s\n" % version
128 for i in range(len(title)):
132 msg = msg.replace('\n', '\n ')
133 print ' %-10s %s (r%s)' % (author, msg, rev)
136 print 'WinMerge changelog script.'
137 print 'Usage: changelog [-h] [-r:n] [--help] [--revisions:n]'
139 print ' -h, --help print this help'
140 print ' -r:n, -revisions:n tell script to output last n revisions'
141 print ' by default 100 last revisions are printed\n'
146 opts, args = getopt.getopt(argv, "hr:", ["help", "revisions:"])
148 for opt, arg in opts:
149 if opt in ("-h", "--help"):
152 if opt in ("-r", "--revisions"):
155 output = run_svn(revcount)
156 log_lines = parse_xml(output)
157 generate_output(log_lines)
160 if __name__ == "__main__":