|
|
#!/usr/bin/perl -w |
|
|
|
|
|
use strict; |
|
|
use Getopt::Std; |
|
|
use File::Basename qw(basename dirname); |
|
|
|
|
|
our ($opt_h, $opt_n, $opt_s); |
|
|
getopts('hns'); |
|
|
|
|
|
$opt_h && usage(); |
|
|
|
|
|
sub usage { |
|
|
print STDERR "Usage: ${\basename $0} [-h] [-n] [-s] < <log_data>\n"; |
|
|
exit(1); |
|
|
} |
|
|
|
|
|
my (%mailmap); |
|
|
my (%email); |
|
|
my (%map); |
|
|
my $pstate = 1; |
|
|
my $n_records = 0; |
|
|
my $n_output = 0; |
|
|
|
|
|
sub shortlog_entry($$) { |
|
|
my ($name, $desc) = @_; |
|
|
my $key = $name; |
|
|
|
|
|
$desc =~ s#/pub/scm/linux/kernel/git/#/.../#g; |
|
|
$desc =~ s#\[PATCH\] ##g; |
|
|
|
|
|
# store description in array, in email->{desc list} map |
|
|
if (exists $map{$key}) { |
|
|
# grab ref |
|
|
my $obj = $map{$key}; |
|
|
|
|
|
# add desc to array |
|
|
push(@$obj, $desc); |
|
|
} else { |
|
|
# create new array, containing 1 item |
|
|
my @arr = ($desc); |
|
|
|
|
|
# store ref to array |
|
|
$map{$key} = \@arr; |
|
|
} |
|
|
} |
|
|
|
|
|
# sort comparison function |
|
|
sub by_name($$) { |
|
|
my ($a, $b) = @_; |
|
|
|
|
|
uc($a) cmp uc($b); |
|
|
} |
|
|
sub by_nbentries($$) { |
|
|
my ($a, $b) = @_; |
|
|
my $a_entries = $map{$a}; |
|
|
my $b_entries = $map{$b}; |
|
|
|
|
|
@$b_entries - @$a_entries || by_name $a, $b; |
|
|
} |
|
|
|
|
|
my $sort_method = $opt_n ? \&by_nbentries : \&by_name; |
|
|
|
|
|
sub summary_output { |
|
|
my ($obj, $num, $key); |
|
|
|
|
|
foreach $key (sort $sort_method keys %map) { |
|
|
$obj = $map{$key}; |
|
|
$num = @$obj; |
|
|
printf "%s: %u\n", $key, $num; |
|
|
$n_output += $num; |
|
|
} |
|
|
} |
|
|
|
|
|
sub shortlog_output { |
|
|
my ($obj, $num, $key, $desc); |
|
|
|
|
|
foreach $key (sort $sort_method keys %map) { |
|
|
$obj = $map{$key}; |
|
|
$num = @$obj; |
|
|
|
|
|
# output author |
|
|
printf "%s (%u):\n", $key, $num; |
|
|
|
|
|
# output author's 1-line summaries |
|
|
foreach $desc (reverse @$obj) { |
|
|
print " $desc\n"; |
|
|
$n_output++; |
|
|
} |
|
|
|
|
|
# blank line separating author from next author |
|
|
print "\n"; |
|
|
} |
|
|
} |
|
|
|
|
|
sub changelog_input { |
|
|
my ($author, $desc); |
|
|
|
|
|
while (<>) { |
|
|
# get author and email |
|
|
if ($pstate == 1) { |
|
|
my ($email); |
|
|
|
|
|
next unless /^[Aa]uthor:?\s*(.*?)\s*<(.*)>/; |
|
|
|
|
|
$n_records++; |
|
|
|
|
|
$author = $1; |
|
|
$email = $2; |
|
|
$desc = undef; |
|
|
|
|
|
# cset author fixups |
|
|
if (exists $mailmap{$email}) { |
|
|
$author = $mailmap{$email}; |
|
|
} elsif (exists $mailmap{$author}) { |
|
|
$author = $mailmap{$author}; |
|
|
} elsif (!$author) { |
|
|
$author = $email; |
|
|
} |
|
|
$email{$author}{$email}++; |
|
|
$pstate++; |
|
|
} |
|
|
|
|
|
# skip to blank line |
|
|
elsif ($pstate == 2) { |
|
|
next unless /^\s*$/; |
|
|
$pstate++; |
|
|
} |
|
|
|
|
|
# skip to non-blank line |
|
|
elsif ($pstate == 3) { |
|
|
next unless /^\s*?(.*)/; |
|
|
|
|
|
# skip lines that are obviously not |
|
|
# a 1-line cset description |
|
|
next if /^\s*From: /; |
|
|
|
|
|
chomp; |
|
|
$desc = $1; |
|
|
|
|
|
&shortlog_entry($author, $desc); |
|
|
|
|
|
$pstate = 1; |
|
|
} |
|
|
|
|
|
else { |
|
|
die "invalid parse state $pstate"; |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
sub read_mailmap { |
|
|
my ($fh, $mailmap) = @_; |
|
|
while (<$fh>) { |
|
|
chomp; |
|
|
if (/^([^#].*?)\s*<(.*)>/) { |
|
|
$mailmap->{$2} = $1; |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
sub setup_mailmap { |
|
|
read_mailmap(\*DATA, \%mailmap); |
|
|
if (-f '.mailmap') { |
|
|
my $fh = undef; |
|
|
open $fh, '<', '.mailmap'; |
|
|
read_mailmap($fh, \%mailmap); |
|
|
close $fh; |
|
|
} |
|
|
} |
|
|
|
|
|
sub finalize { |
|
|
#print "\n$n_records records parsed.\n"; |
|
|
|
|
|
if ($n_records != $n_output) { |
|
|
die "parse error: input records != output records\n"; |
|
|
} |
|
|
if (0) { |
|
|
for my $author (sort keys %email) { |
|
|
my $e = $email{$author}; |
|
|
for my $email (sort keys %$e) { |
|
|
print STDERR "$author <$email>\n"; |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
&setup_mailmap; |
|
|
&changelog_input; |
|
|
$opt_s ? &summary_output : &shortlog_output; |
|
|
&finalize; |
|
|
exit(0); |
|
|
|
|
|
|
|
|
__DATA__ |
|
|
# |
|
|
# Even with git, we don't always have name translations. |
|
|
# So have an email->real name table to translate the |
|
|
# (hopefully few) missing names |
|
|
# |
|
|
Adrian Bunk <bunk@stusta.de> |
|
|
Andreas Herrmann <aherrman@de.ibm.com> |
|
|
Andrew Morton <akpm@osdl.org> |
|
|
Andrew Vasquez <andrew.vasquez@qlogic.com> |
|
|
Christoph Hellwig <hch@lst.de> |
|
|
Corey Minyard <minyard@acm.org> |
|
|
David Woodhouse <dwmw2@shinybook.infradead.org> |
|
|
Domen Puncer <domen@coderock.org> |
|
|
Douglas Gilbert <dougg@torque.net> |
|
|
Ed L Cashin <ecashin@coraid.com> |
|
|
Evgeniy Polyakov <johnpol@2ka.mipt.ru> |
|
|
Felix Moeller <felix@derklecks.de> |
|
|
Frank Zago <fzago@systemfabricworks.com> |
|
|
Greg Kroah-Hartman <gregkh@suse.de> |
|
|
James Bottomley <jejb@mulgrave.(none)> |
|
|
James Bottomley <jejb@titanic.il.steeleye.com> |
|
|
Jeff Garzik <jgarzik@pretzel.yyz.us> |
|
|
Jens Axboe <axboe@suse.de> |
|
|
Kay Sievers <kay.sievers@vrfy.org> |
|
|
Mitesh shah <mshah@teja.com> |
|
|
Morten Welinder <terra@gnome.org> |
|
|
Morten Welinder <welinder@anemone.rentec.com> |
|
|
Morten Welinder <welinder@darter.rentec.com> |
|
|
Morten Welinder <welinder@troll.com> |
|
|
Nguyen Anh Quynh <aquynh@gmail.com> |
|
|
Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it> |
|
|
Peter A Jonsson <pj@ludd.ltu.se> |
|
|
Ralf Wildenhues <Ralf.Wildenhues@gmx.de> |
|
|
Rudolf Marek <R.Marek@sh.cvut.cz> |
|
|
Rui Saraiva <rmps@joel.ist.utl.pt> |
|
|
Sachin P Sant <ssant@in.ibm.com> |
|
|
Santtu Hyrkk,Av(B <santtu.hyrkko@gmail.com> |
|
|
Simon Kelley <simon@thekelleys.org.uk> |
|
|
Tejun Heo <htejun@gmail.com> |
|
|
Tony Luck <tony.luck@intel.com>
|
|
|
|