4 # summarize and re-format subversion's log output to plain text
6 # Written by Rocco Rutte <pdmef@cs.tu-berlin.de>
7 # for internal use with mutt-ng <http://mutt-ng.berlios.de/>.
12 # -t print only today's messages
13 # -s YYYY-MM-DD print only messages since (and including) date
14 # -i string use string for indentation
15 # -m number break lines at the latest at number columns
16 # -p string prefix for filenames in 'svn log -v' output;
17 # for things like 'A /mutt-ng/trunk/foo' set this
18 # to 'mutt-ng/', i.e. exclude the leading / from
19 # it but include everything up to the last char
20 # before (trunk|tags|branches)
23 # Note: lines matching ``^([^:]+):?$'' will be ignored if the first
24 # submatch in brackets is a known author; i.e. the logs
34 # will be interpreted as only 'added l33t c0d3' if 'Foo Bar' is known as
35 # an author. This does not count when grouping messages for authors,
36 # those lines are just skipped. This is hard-coded, see below.
40 # as the first line of log messages when change is only committed by
41 # someone with access but the original author is someone else. If
42 # there's no such author line, the author's name will be grabbed from
43 # the %committers table below.
49 # hard-coded configuration: this maps user to full names
51 "ak1" => "Andreas Krennmair <ak\@synflood.at>",
52 "nion" => "Nico Golde <nion\@muttng.org>",
53 "pdmef" => "Rocco Rutte <pdmef\@cs.tu-berlin.de>",
54 "dkg1" => "Daniel K. Gebhart <dpkg1\@users.berlios.de>"
59 "filesM" => "Modified",
60 "filesD" => "Deleted",
61 "filesR" => "Replaced"
82 # nicely print log lines in itemized style with eye-candy indentation and
83 # somewhat smart line-breaking
86 my @lines = split (/\n/, $text);
88 print "$indent$indent-";
89 my @words = split (/\ /, $l);
90 my $c = length ($indent);
92 if (length ($w) + $c > $linemax) {
93 print "\n$indent$indent $w";
94 $c = length ($indent);
98 $c += length ($w) + 1;
106 This is: svnlog2changelog.pl
107 written by Rocco Rutte <pdmef\@cs.tu-berlin.de>
108 for use with mutt-ng <http://mutt-ng.berlios.de/>
111 svnlog2changelog.pl -h
112 svn log -v | svnlog2changelog.pl [-t] [-i YYYY-MM-DD] [-m number] [-p string]
115 -t print only today's messages
116 -s YYYY-MM-DD print only messages since (and including) date
117 -i string use string for indentation
118 -m number break lines at the latest at number columns
119 -p string prefix for filenames in 'svn log -v' output;
120 for things like 'A /mutt-ng/trunk/foo' set this
121 to 'mutt-ng/', i.e. exclude the leading / from
122 it but include everything up to the last char
123 before (trunk|tags|branches)
127 - print Subversion's log for today:
128 svn log -v -r "{`date "+%Y-%m-%d"`}:HEAD" | svnlog2changelog.pl -t [-i string]
130 - print Subversion's log since (and including) YYYY-MM-DD
131 svn log -v | svnlog2changelog.pl -s YYYY-MM-DD [-i string]
138 for my $k (keys %committers) {
139 if (substr ($committers{$k}, 0, length ($name)) eq $name) {
146 # get and process options
147 getopts ("tm:s:hi:p:", \%options);
148 if (defined $options{'t'}) {
149 $today = strftime ("%Y-%m-%d", localtime (time ()));
151 if (defined $options{'m'} and $options{'m'} =~ /^[0-9]{2,}$/) {
152 $linemax = $options{'m'};
154 if (defined $options{'s'} and $options{'s'} =~ /^[0-9]{4}-[0-9]{2}-[0-9]{2}$/) {
155 $since = $options{'s'};
157 if (defined $options{'h'}) {
161 if (defined $options{'i'}) {
162 $indent = $options{'i'};
164 if (defined $options{'p'}) {
165 $pfx = $options{'p'};
172 if ($_ =~ /^r([0-9]+)/) {
177 my @items = split (/\ \|\ /, $_);
178 my @dateinfo = split (/\ /, $items[2]);
179 $curentry = $dateinfo[0];
180 $curauthor = $items[1];
181 $curcomm = $items[1];
182 # _keep_ latest rev. number for day
183 if (not defined ${$changes{$curentry}}{'rev'} or
184 ${$changes{$curentry}}{'rev'} lt substr ($items[0], 1)) {
185 ${$changes{$curentry}}{'rev'} = substr ($items[0], 1);
187 # _keep_ latest commit time for day
188 if (not defined ${$changes{$curentry}}{'time'}) {
189 ${$changes{$curentry}}{'time'} = "$dateinfo[1] $dateinfo[2]";
195 # check log line: contains author?
196 if ($_ =~ /^From: (.*)$/) {
197 $curauthor = "$1 ($curcomm)";
200 elsif (defined $committers{$curauthor}) {
201 $curauthor = "$committers{$curcomm} ($curcomm)";
203 # check log line: contains noise?
204 if (length ($_) == 0 or $_ =~ /^[-]+$/ or
205 $_ =~ /^([^:]+):?$/ and &isknown ($1) or
206 $_ eq "Changed paths:") {
209 # check log line: contains list of changes/deleted/added files?
210 if ((length ($pfx) > 0 and $_ =~ /([AMD]) \/($pfx?.*)?$/) or
211 (length ($pfx) == 0 and $_ =~ /([AMD]) \/(.*)?$/)) {
217 $target =~ s#$pfx##g;
218 ${${$changes{$curentry}}{"files$what"}}{$target} = 1;
220 # here the line really contains the log message
221 # try to be smart and remove itemizations people make
223 $clean =~ s/^[- \t*]*//;
224 if (length ($clean) > 0) {
225 ${${$changes{$curentry}}{'log'}}{$curauthor} .= "$clean (r$currev)\n";
235 for my $k (sort { $b cmp $a } (keys (%changes))) {
237 if (not defined %{${$changes{$k}}{'log'}} or
238 (length ($since) > 0 && length ($today) == 0 && ($k lt $since)) or
239 (length ($today) > 0 && ($k ne $today))) {
242 # print first line with date, time and latest revision for current day
243 print "$first$k ${$changes{$k}}{'time'} ";
246 print "Latest Revision: ${$changes{$k}}{'rev'}\n\n";
247 # per author: print his name and an itemized list of his log msgs.
248 # with smart line-breaking and indentation
249 for my $a (keys %{${$changes{$k}}{'log'}}) {
250 print "$first2$indent";
251 if (defined $committers{$a}) {
252 print $committers{$a};
257 &niceline (${${$changes{$k}}{'log'}}{$a});
260 for my $a (keys %fmap) {
261 if (defined %{${$changes{$k}}{$a}}) {
262 print "$first$indent$fmap{$a} Files:\n";
263 my $fixme = join (", ", keys %{${$changes{$k}}{$a}});