#!/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; }