1#!/usr/bin/perl -w
2
3use strict;
4use Getopt::Std;
5use File::Basename qw(basename dirname);
6
7our ($opt_h, $opt_n, $opt_s);
8getopts('hns');
9
10$opt_h && usage();
11
12sub usage {
13 print STDERR "Usage: ${\basename $0} [-h] [-n] [-s] < <log_data>\n";
14 exit(1);
15}
16
17my (%mailmap);
18my (%email);
19my (%map);
20my $pstate = 1;
21my $n_records = 0;
22my $n_output = 0;
23
24sub 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
48sub by_name($$) {
49 my ($a, $b) = @_;
50
51 uc($a) cmp uc($b);
52}
53sub 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
61my $sort_method = $opt_n ? \&by_nbentries : \&by_name;
62
63sub 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
74sub 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
95sub 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
151sub read_mailmap {
152 my ($fh, $mailmap) = @_;
153 while (<$fh>) {
154 chomp;
155 if (/^([^#].*?)\s*<(.*)>/) {
156 $mailmap->{$2} = $1;
157 }
158 }
159}
160
161sub 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
171sub 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;
191exit(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#
200Adrian Bunk <bunk@stusta.de>
201Andreas Herrmann <aherrman@de.ibm.com>
202Andrew Morton <akpm@osdl.org>
203Andrew Vasquez <andrew.vasquez@qlogic.com>
204Christoph Hellwig <hch@lst.de>
205Corey Minyard <minyard@acm.org>
206David Woodhouse <dwmw2@shinybook.infradead.org>
207Domen Puncer <domen@coderock.org>
208Douglas Gilbert <dougg@torque.net>
209Ed L Cashin <ecashin@coraid.com>
210Evgeniy Polyakov <johnpol@2ka.mipt.ru>
211Felix Moeller <felix@derklecks.de>
212Frank Zago <fzago@systemfabricworks.com>
213Greg Kroah-Hartman <gregkh@suse.de>
214James Bottomley <jejb@mulgrave.(none)>
215James Bottomley <jejb@titanic.il.steeleye.com>
216Jeff Garzik <jgarzik@pretzel.yyz.us>
217Jens Axboe <axboe@suse.de>
218Kay Sievers <kay.sievers@vrfy.org>
219Mitesh shah <mshah@teja.com>
220Morten Welinder <terra@gnome.org>
221Morten Welinder <welinder@anemone.rentec.com>
222Morten Welinder <welinder@darter.rentec.com>
223Morten Welinder <welinder@troll.com>
224Nguyen Anh Quynh <aquynh@gmail.com>
225Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it>
226Peter A Jonsson <pj@ludd.ltu.se>
227Ralf Wildenhues <Ralf.Wildenhues@gmx.de>
228Rudolf Marek <R.Marek@sh.cvut.cz>
229Rui Saraiva <rmps@joel.ist.utl.pt>
230Sachin P Sant <ssant@in.ibm.com>
231Santtu Hyrkk\e,Av\e(B <santtu.hyrkko@gmail.com>
232Simon Kelley <simon@thekelleys.org.uk>
233Tejun Heo <htejun@gmail.com>
234Tony Luck <tony.luck@intel.com>