git-shortlogon commit Add git-shortlog perl script (fa375c7)
   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