| #!/usr/bin/perl | |
| use warnings; | |
| use strict; | |
| use Getopt::Long; | |
| sub parsing () { 1; } | |
| sub waiting () { 2; } | |
| my $state = parsing; | |
| my @more; | |
| my $append; | |
| my $debug; | |
| sub find_author { | |
| my $map = shift; | |
| for my $name (@_) { | |
| my $fh; | |
| print STDERR "Checking <$name>..." | |
| if ($debug); | |
| if (!open($fh, "-|", | |
| qw(git log -1 --no-merges), | |
| '--format=%an <%ae>', | |
| "--author=$name", | |
| "--all")) { | |
| print STDERR "opening pipe to read from git log failed\n" | |
| if ($debug); | |
| $map->{$name} = $name; | |
| next; | |
| } | |
| my $line = <$fh>; | |
| if ($line) { | |
| chomp $line; | |
| print STDERR "read <$line> from git log\n" | |
| if ($debug); | |
| $map->{$name} = $line; | |
| } else { | |
| print STDERR "read false ($line) from git log\n" | |
| if ($debug); | |
| $map->{$name} = $name; | |
| } | |
| } | |
| } | |
| sub accumulate { | |
| push @more, [@_]; | |
| } | |
| my $mine; | |
| sub compute_bylines { | |
| my %names = map { $_->[1] => 1 } @more; | |
| my %map = (); | |
| my @append; | |
| find_author(\%map, keys (%names)); | |
| for (@more) { | |
| my ($tag, $name) = @$_; | |
| if ($tag eq 'mine') { | |
| $mine = $map{$name}; | |
| next; | |
| } | |
| $tag = ucfirst($tag); | |
| push @append, "$tag: $map{$name}"; | |
| } | |
| if (@append) { | |
| $append = join("\n", @append) . "\n"; | |
| } else { | |
| $append = ""; | |
| } | |
| } | |
| sub add_more_bylines { | |
| if (!defined $append) { | |
| compute_bylines(); | |
| } | |
| print $append; | |
| } | |
| my $check_only; | |
| exit 1 unless (GetOptions("signed-off-by=s" => \&accumulate, | |
| "acked-by=s" => \&accumulate, | |
| "reviewed-by=s" => \&accumulate, | |
| "tested-by=s" => \&accumulate, | |
| "helped-by=s" => \&accumulate, | |
| "check-only!" => \$check_only, | |
| "mine=s" => \&accumulate, | |
| "debug!" => \$debug, | |
| )); | |
| compute_bylines(); | |
| if ($check_only) { | |
| add_more_bylines(); | |
| exit 0; | |
| } | |
| my $seen_mine = 0; | |
| while (<>) { | |
| if ($state == parsing) { | |
| if (/^[-A-Za-z]+-by: /i || /^Cc: /i) { | |
| $state = waiting; | |
| } | |
| } elsif ($state == waiting) { | |
| if (defined $mine && /^Signed-off-by: \Q$mine\E/) { | |
| $seen_mine = 1; | |
| next; | |
| } elsif (/^[-A-Za-z]+-by: /i || /^Cc: /i) { | |
| $state = waiting; | |
| } else { | |
| add_more_bylines(); | |
| if ($seen_mine) { | |
| print "Signed-off-by: $mine\n"; | |
| } | |
| $state = parsing; | |
| $seen_mine = 0; | |
| } | |
| } | |
| print; | |
| } |