1#!/usr/bin/perl -w
2
3use strict;
4
5#
6# Even with git, we don't always have name translations.
7# So have an email->real name table to translate the
8# (hopefully few) missing names
9#
10my %mailmap = (
11 'aherrman@de.ibm.com' => 'Andreas Herrmann',
12 'akpm@osdl.org' => 'Andrew Morton',
13 'andrew.vasquez@qlogic.com' => 'Andrew Vasquez',
14 'aquynh@gmail.com' => 'Nguyen Anh Quynh',
15 'axboe@suse.de' => 'Jens Axboe',
16 'blaisorblade@yahoo.it' => 'Paolo \'Blaisorblade\' Giarrusso',
17 'bunk@stusta.de' => 'Adrian Bunk',
18 'domen@coderock.org' => 'Domen Puncer',
19 'dougg@torque.net' => 'Douglas Gilbert',
20 'dwmw2@shinybook.infradead.org' => 'David Woodhouse',
21 'ecashin@coraid.com' => 'Ed L Cashin',
22 'felix@derklecks.de' => 'Felix Moeller',
23 'gregkh@suse.de' => 'Greg Kroah-Hartman',
24 'hch@lst.de' => 'Christoph Hellwig',
25 'htejun@gmail.com' => 'Tejun Heo',
26 'jejb@mulgrave.(none)' => 'James Bottomley',
27 'jejb@titanic.il.steeleye.com' => 'James Bottomley',
28 'jgarzik@pretzel.yyz.us' => 'Jeff Garzik',
29 'johnpol@2ka.mipt.ru' => 'Evgeniy Polyakov',
30 'kay.sievers@vrfy.org' => 'Kay Sievers',
31 'minyard@acm.org' => 'Corey Minyard',
32 'R.Marek@sh.cvut.cz' => 'Rudolf Marek',
33 'simon@thekelleys.org.uk' => 'Simon Kelley',
34 'ssant@in.ibm.com' => 'Sachin P Sant',
35 'tony.luck@intel.com' => 'Tony Luck',
36);
37
38my (%map);
39my $pstate = 1;
40my $n_records = 0;
41my $n_output = 0;
42
43
44sub shortlog_entry($$) {
45 my ($name, $desc) = @_;
46 my $key = $name;
47
48 $desc =~ s#/pub/scm/linux/kernel/git/#/.../#g;
49 $desc =~ s#\[PATCH\] ##g;
50
51 # store description in array, in email->{desc list} map
52 if (exists $map{$key}) {
53 # grab ref
54 my $obj = $map{$key};
55
56 # add desc to array
57 push(@$obj, $desc);
58 } else {
59 # create new array, containing 1 item
60 my @arr = ($desc);
61
62 # store ref to array
63 $map{$key} = \@arr;
64 }
65}
66
67# sort comparison function
68sub by_name($$) {
69 my ($a, $b) = @_;
70
71 uc($a) cmp uc($b);
72}
73
74sub shortlog_output {
75 my ($obj, $key, $desc);
76
77 foreach $key (sort by_name keys %map) {
78 # output author
79 printf "%s:\n", $key;
80
81 # output author's 1-line summaries
82 $obj = $map{$key};
83 foreach $desc (@$obj) {
84 print " $desc\n";
85 $n_output++;
86 }
87
88 # blank line separating author from next author
89 print "\n";
90 }
91}
92
93sub changelog_input {
94 my ($author, $desc);
95
96 while (<>) {
97 # get author and email
98 if ($pstate == 1) {
99 my ($email);
100
101 next unless /^Author: (.*)<(.*)>.*$/;
102
103 $n_records++;
104
105 $author = $1;
106 $email = $2;
107 $desc = undef;
108
109 # trim trailing whitespace.
110 # why doesn't chomp work?
111 while ($author && ($author =~ /\s$/)) {
112 chop $author;
113 }
114
115 # cset author fixups
116 if (exists $mailmap{$email}) {
117 $author = $mailmap{$email};
118 } elsif (exists $mailmap{$author}) {
119 $author = $mailmap{$author};
120 } elsif ((!$author) || ($author eq "")) {
121 $author = $email;
122 }
123
124 $pstate++;
125 }
126
127 # skip to blank line
128 elsif ($pstate == 2) {
129 next unless /^\s*$/;
130 $pstate++;
131 }
132
133 # skip to non-blank line
134 elsif ($pstate == 3) {
135 next unless /^\s*(\S.*)$/;
136
137 # skip lines that are obviously not
138 # a 1-line cset description
139 next if /^\s*From: /;
140
141 chomp;
142 $desc = $1;
143
144 &shortlog_entry($author, $desc);
145
146 $pstate = 1;
147 }
148
149 else {
150 die "invalid parse state $pstate";
151 }
152 }
153}
154
155sub finalize {
156 #print "\n$n_records records parsed.\n";
157
158 if ($n_records != $n_output) {
159 die "parse error: input records != output records\n";
160 }
161}
162
163&changelog_input;
164&shortlog_output;
165&finalize;
166exit(0);
167