git-svn: don't die on rebuild when --upgrade is specified
[git] / git-shortlog.perl
1 #!/usr/bin/perl -w
2
3 use strict;
4 use Getopt::Std;
5 use File::Basename qw(basename dirname);
6
7 our ($opt_h, $opt_n, $opt_s);
8 getopts('hns');
9
10 $opt_h && usage();
11
12 sub usage {
13         print STDERR "Usage: ${\basename $0} [-h] [-n] [-s] < <log_data>\n";
14         exit(1);
15 }
16
17 my (%mailmap);
18 my (%email);
19 my (%map);
20 my $pstate = 1;
21 my $n_records = 0;
22 my $n_output = 0;
23
24 sub shortlog_entry($$) {
25         my ($name, $desc) = @_;
26         my $key = $name;
27
28         $desc =~ s#/pub/scm/linux/kernel/git/#/.../#g;
29         $desc =~ s#\[PATCH\] ##g;
30
31         # store description in array, in email->{desc list} map
32         if (exists $map{$key}) {
33                 # grab ref
34                 my $obj = $map{$key};
35
36                 # add desc to array
37                 push(@$obj, $desc);
38         } else {
39                 # create new array, containing 1 item
40                 my @arr = ($desc);
41
42                 # store ref to array
43                 $map{$key} = \@arr;
44         }
45 }
46
47 # sort comparison function
48 sub by_name($$) {
49         my ($a, $b) = @_;
50
51         uc($a) cmp uc($b);
52 }
53 sub by_nbentries($$) {
54         my ($a, $b) = @_;
55         my $a_entries = $map{$a};
56         my $b_entries = $map{$b};
57
58         @$b_entries - @$a_entries || by_name $a, $b;
59 }
60
61 my $sort_method = $opt_n ? \&by_nbentries : \&by_name;
62
63 sub summary_output {
64         my ($obj, $num, $key);
65
66         foreach $key (sort $sort_method keys %map) {
67                 $obj = $map{$key};
68                 $num = @$obj;
69                 printf "%s: %u\n", $key, $num;
70                 $n_output += $num;
71         }
72 }
73
74 sub shortlog_output {
75         my ($obj, $num, $key, $desc);
76
77         foreach $key (sort $sort_method keys %map) {
78                 $obj = $map{$key};
79                 $num = @$obj;
80
81                 # output author
82                 printf "%s (%u):\n", $key, $num;
83
84                 # output author's 1-line summaries
85                 foreach $desc (reverse @$obj) {
86                         print "  $desc\n";
87                         $n_output++;
88                 }
89
90                 # blank line separating author from next author
91                 print "\n";
92         }
93 }
94
95 sub changelog_input {
96         my ($author, $desc);
97
98         while (<>) {
99                 # get author and email
100                 if ($pstate == 1) {
101                         my ($email);
102
103                         next unless /^[Aa]uthor:?\s*(.*?)\s*<(.*)>/;
104
105                         $n_records++;
106
107                         $author = $1;
108                         $email = $2;
109                         $desc = undef;
110
111                         # cset author fixups
112                         if (exists $mailmap{$email}) {
113                                 $author = $mailmap{$email};
114                         } elsif (exists $mailmap{$author}) {
115                                 $author = $mailmap{$author};
116                         } elsif (!$author) {
117                                 $author = $email;
118                         }
119                         $email{$author}{$email}++;
120                         $pstate++;
121                 }
122
123                 # skip to blank line
124                 elsif ($pstate == 2) {
125                         next unless /^\s*$/;
126                         $pstate++;
127                 }
128
129                 # skip to non-blank line
130                 elsif ($pstate == 3) {
131                         next unless /^\s*?(.*)/;
132
133                         # skip lines that are obviously not
134                         # a 1-line cset description
135                         next if /^\s*From: /;
136
137                         chomp;
138                         $desc = $1;
139
140                         &shortlog_entry($author, $desc);
141
142                         $pstate = 1;
143                 }
144         
145                 else {
146                         die "invalid parse state $pstate";
147                 }
148         }
149 }
150
151 sub read_mailmap {
152         my ($fh, $mailmap) = @_;
153         while (<$fh>) {
154                 chomp;
155                 if (/^([^#].*?)\s*<(.*)>/) {
156                         $mailmap->{$2} = $1;
157                 }
158         }
159 }
160
161 sub setup_mailmap {
162         read_mailmap(\*DATA, \%mailmap);
163         if (-f '.mailmap') {
164                 my $fh = undef;
165                 open $fh, '<', '.mailmap';
166                 read_mailmap($fh, \%mailmap);
167                 close $fh;
168         }
169 }
170
171 sub finalize {
172         #print "\n$n_records records parsed.\n";
173
174         if ($n_records != $n_output) {
175                 die "parse error: input records != output records\n";
176         }
177         if (0) {
178                 for my $author (sort keys %email) {
179                         my $e = $email{$author};
180                         for my $email (sort keys %$e) {
181                                 print STDERR "$author <$email>\n";
182                         }
183                 }
184         }
185 }
186
187 &setup_mailmap;
188 &changelog_input;
189 $opt_s ? &summary_output : &shortlog_output;
190 &finalize;
191 exit(0);
192
193
194 __DATA__
195 #
196 # Even with git, we don't always have name translations.
197 # So have an email->real name table to translate the
198 # (hopefully few) missing names
199 #
200 Adrian Bunk <bunk@stusta.de>
201 Andreas Herrmann <aherrman@de.ibm.com>
202 Andrew Morton <akpm@osdl.org>
203 Andrew Vasquez <andrew.vasquez@qlogic.com>
204 Christoph Hellwig <hch@lst.de>
205 Corey Minyard <minyard@acm.org>
206 David Woodhouse <dwmw2@shinybook.infradead.org>
207 Domen Puncer <domen@coderock.org>
208 Douglas Gilbert <dougg@torque.net>
209 Ed L Cashin <ecashin@coraid.com>
210 Evgeniy Polyakov <johnpol@2ka.mipt.ru>
211 Felix Moeller <felix@derklecks.de>
212 Frank Zago <fzago@systemfabricworks.com>
213 Greg Kroah-Hartman <gregkh@suse.de>
214 James Bottomley <jejb@mulgrave.(none)>
215 James Bottomley <jejb@titanic.il.steeleye.com>
216 Jeff Garzik <jgarzik@pretzel.yyz.us>
217 Jens Axboe <axboe@suse.de>
218 Kay Sievers <kay.sievers@vrfy.org>
219 Mitesh shah <mshah@teja.com>
220 Morten Welinder <terra@gnome.org>
221 Morten Welinder <welinder@anemone.rentec.com>
222 Morten Welinder <welinder@darter.rentec.com>
223 Morten Welinder <welinder@troll.com>
224 Nguyen Anh Quynh <aquynh@gmail.com>
225 Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it>
226 Peter A Jonsson <pj@ludd.ltu.se>
227 Ralf Wildenhues <Ralf.Wildenhues@gmx.de>
228 Rudolf Marek <R.Marek@sh.cvut.cz>
229 Rui Saraiva <rmps@joel.ist.utl.pt>
230 Sachin P Sant <ssant@in.ibm.com>
231 Santtu Hyrkk\e,Av\e(B <santtu.hyrkko@gmail.com>
232 Simon Kelley <simon@thekelleys.org.uk>
233 Tejun Heo <htejun@gmail.com>
234 Tony Luck <tony.luck@intel.com>