Code

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