Raw
1 #!/usr/bin/perl
2
3 use warnings;
4 use strict;
5 use Getopt::Long;
6
7 sub parsing () { 1; }
8 sub waiting () { 2; }
9 my $state = parsing;
10
11 my @more;
12 my $append;
13 my $debug;
14
15 sub find_author {
16 my $map = shift;
17 for my $name (@_) {
18 my $fh;
19 print STDERR "Checking <$name>..."
20 if ($debug);
21 if (!open($fh, "-|",
22 qw(git log -1 --no-merges),
23 '--format=%an <%ae>',
24 "--author=$name",
25 "--all")) {
26 print STDERR "opening pipe to read from git log failed\n"
27 if ($debug);
28 $map->{$name} = $name;
29 next;
30 }
31 my $line = <$fh>;
32 if ($line) {
33 chomp $line;
34 print STDERR "read <$line> from git log\n"
35 if ($debug);
36 $map->{$name} = $line;
37 } else {
38 print STDERR "read false ($line) from git log\n"
39 if ($debug);
40 $map->{$name} = $name;
41 }
42 }
43 }
44
45 sub accumulate {
46 push @more, [@_];
47 }
48
49 my $mine;
50
51 sub compute_bylines {
52 my %names = map { $_->[1] => 1 } @more;
53 my %map = ();
54 my @append;
55 find_author(\%map, keys (%names));
56 for (@more) {
57 my ($tag, $name) = @$_;
58 if ($tag eq 'mine') {
59 $mine = $map{$name};
60 next;
61 }
62 $tag = ucfirst($tag);
63 push @append, "$tag: $map{$name}";
64 }
65 if (@append) {
66 $append = join("\n", @append) . "\n";
67 } else {
68 $append = "";
69 }
70 }
71
72 sub add_more_bylines {
73 if (!defined $append) {
74 compute_bylines();
75 }
76 print $append;
77 }
78
79 my $check_only;
80
81 exit 1 unless (GetOptions("signed-off-by=s" => \&accumulate,
82 "acked-by=s" => \&accumulate,
83 "reviewed-by=s" => \&accumulate,
84 "tested-by=s" => \&accumulate,
85 "helped-by=s" => \&accumulate,
86 "check-only!" => \$check_only,
87 "mine=s" => \&accumulate,
88 "debug!" => \$debug,
89 ));
90
91 compute_bylines();
92
93 if ($check_only) {
94 add_more_bylines();
95 exit 0;
96 }
97
98 my $seen_mine = 0;
99 while (<>) {
100 if ($state == parsing) {
101 if (/^[-A-Za-z]+-by: /i || /^Cc: /i) {
102 $state = waiting;
103 }
104 } elsif ($state == waiting) {
105 if (defined $mine && /^Signed-off-by: \Q$mine\E/) {
106 $seen_mine = 1;
107 next;
108 } elsif (/^[-A-Za-z]+-by: /i || /^Cc: /i) {
109 $state = waiting;
110 } else {
111 add_more_bylines();
112 if ($seen_mine) {
113 print "Signed-off-by: $mine\n";
114 }
115 $state = parsing;
116 $seen_mine = 0;
117 }
118 }
119 print;
120 }