Commit b67d94a0 authored by Joe Perches's avatar Joe Perches Committed by james toy

Fix email matching without name --n and --git-blame

   Using --non and --git-blame caused maintainer signature
   matching to fail.  Fixed that by adding 3rd argument to
   sub format_email to control show/hide name portion of address
Slurp -f file instead of reading line-by-line for K: pattern matching.
   Suggested by Wolfram Sang as more efficient
Refactor git command execution
   Break into 2 functions, execute/analyze
   Share code between --git and --git-blame
   Don't warn multiple times when git isn't installed
Improve stats reporting
   --git-min-percent and -- rolestats now count the total number of commits
   for either the period of --git-since or if using --git-blame the commits
   used by the current file and calculate commit % as
      # of commits signed / total commits * 100
Code style cleaning
   Use consistent sub foo { my (args...) = @_;
Signed-off-by: default avatarJoe Perches <joe@perches.com>
Cc: Ben Hutchings <ben@decadent.org.uk>
Cc: Greg KH <greg@kroah.com>
Cc: Pavel Machek <pavel@ucw.cz>
Cc: Wolfram Sang <w.sang@pengutronix.de>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
parent e13e757d
...@@ -182,7 +182,7 @@ if ($email_remove_duplicates) { ...@@ -182,7 +182,7 @@ if ($email_remove_duplicates) {
next if ($line =~ m/^\s*$/); next if ($line =~ m/^\s*$/);
my ($name, $address) = parse_email($line); my ($name, $address) = parse_email($line);
$line = format_email($name, $address); $line = format_email($name, $address, $email_usename);
next if ($line =~ m/^\s*$/); next if ($line =~ m/^\s*$/);
...@@ -214,14 +214,12 @@ foreach my $file (@ARGV) { ...@@ -214,14 +214,12 @@ foreach my $file (@ARGV) {
push(@files, $file); push(@files, $file);
if (-f $file && $keywords) { if (-f $file && $keywords) {
open(FILE, "<$file") or die "$P: Can't open ${file}\n"; open(FILE, "<$file") or die "$P: Can't open ${file}\n";
while (<FILE>) { my $text = do { local($/) ; <FILE> };
my $patch_line = $_;
foreach my $line (keys %keyword_hash) { foreach my $line (keys %keyword_hash) {
if ($patch_line =~ m/^.*$keyword_hash{$line}/x) { if ($text =~ m/$keyword_hash{$line}/x) {
push(@keyword_tvi, $line); push(@keyword_tvi, $line);
} }
} }
}
close(FILE); close(FILE);
} }
} else { } else {
...@@ -311,7 +309,7 @@ foreach my $file (@files) { ...@@ -311,7 +309,7 @@ foreach my $file (@files) {
} }
if ($email && $email_git) { if ($email && $email_git) {
recent_git_signoffs($file); git_file_signoffs($file);
} }
if ($email && $email_git_blame) { if ($email && $email_git_blame) {
...@@ -331,7 +329,7 @@ if ($email) { ...@@ -331,7 +329,7 @@ if ($email) {
if ($chief =~ m/^(.*):(.*)/) { if ($chief =~ m/^(.*):(.*)/) {
my $email_address; my $email_address;
$email_address = format_email($1, $2); $email_address = format_email($1, $2, $email_usename);
if ($email_git_penguin_chiefs) { if ($email_git_penguin_chiefs) {
push(@email_to, [$email_address, 'chief penguin']); push(@email_to, [$email_address, 'chief penguin']);
} else { } else {
...@@ -509,7 +507,7 @@ sub parse_email { ...@@ -509,7 +507,7 @@ sub parse_email {
} }
sub format_email { sub format_email {
my ($name, $address) = @_; my ($name, $address, $usename) = @_;
my $formatted_email; my $formatted_email;
...@@ -522,11 +520,11 @@ sub format_email { ...@@ -522,11 +520,11 @@ sub format_email {
$name = "\"$name\""; $name = "\"$name\"";
} }
if ($email_usename) { if ($usename) {
if ("$name" eq "") { if ("$name" eq "") {
$formatted_email = "$address"; $formatted_email = "$address";
} else { } else {
$formatted_email = "$name <${address}>"; $formatted_email = "$name <$address>";
} }
} else { } else {
$formatted_email = $address; $formatted_email = $address;
...@@ -671,7 +669,7 @@ sub add_categories { ...@@ -671,7 +669,7 @@ sub add_categories {
if ($tv =~ m/^(\C):\s*(.*)/) { if ($tv =~ m/^(\C):\s*(.*)/) {
if ($1 eq "P") { if ($1 eq "P") {
$name = $2; $name = $2;
$pvalue = format_email($name, $address); $pvalue = format_email($name, $address, $email_usename);
} }
} }
} }
...@@ -714,9 +712,9 @@ sub push_email_address { ...@@ -714,9 +712,9 @@ sub push_email_address {
} }
if (!$email_remove_duplicates) { if (!$email_remove_duplicates) {
push(@email_to, [format_email($name, $address), $role]); push(@email_to, [format_email($name, $address, $email_usename), $role]);
} elsif (!email_inuse($name, $address)) { } elsif (!email_inuse($name, $address)) {
push(@email_to, [format_email($name, $address), $role]); push(@email_to, [format_email($name, $address, $email_usename), $role]);
$email_hash_name{$name}++; $email_hash_name{$name}++;
$email_hash_address{$address}++; $email_hash_address{$address}++;
} }
...@@ -747,7 +745,7 @@ sub add_role { ...@@ -747,7 +745,7 @@ sub add_role {
my ($line, $role) = @_; my ($line, $role) = @_;
my ($name, $address) = parse_email($line); my ($name, $address) = parse_email($line);
my $email = format_email($name, $address); my $email = format_email($name, $address, $email_usename);
foreach my $entry (@email_to) { foreach my $entry (@email_to) {
if ($email_remove_duplicates) { if ($email_remove_duplicates) {
...@@ -784,7 +782,7 @@ sub which { ...@@ -784,7 +782,7 @@ sub which {
} }
sub mailmap { sub mailmap {
my @lines = @_; my (@lines) = @_;
my %hash; my %hash;
foreach my $line (@lines) { foreach my $line (@lines) {
...@@ -793,14 +791,14 @@ sub mailmap { ...@@ -793,14 +791,14 @@ sub mailmap {
$hash{$name} = $address; $hash{$name} = $address;
} elsif ($address ne $hash{$name}) { } elsif ($address ne $hash{$name}) {
$address = $hash{$name}; $address = $hash{$name};
$line = format_email($name, $address); $line = format_email($name, $address, $email_usename);
} }
if (exists($mailmap{$name})) { if (exists($mailmap{$name})) {
my $obj = $mailmap{$name}; my $obj = $mailmap{$name};
foreach my $map_address (@$obj) { foreach my $map_address (@$obj) {
if (($map_address eq $address) && if (($map_address eq $address) &&
($map_address ne $hash{$name})) { ($map_address ne $hash{$name})) {
$line = format_email($name, $hash{$name}); $line = format_email($name, $hash{$name}, $email_usename);
} }
} }
} }
...@@ -809,33 +807,44 @@ sub mailmap { ...@@ -809,33 +807,44 @@ sub mailmap {
return @lines; return @lines;
} }
sub recent_git_signoffs { my $printed_nogit = 0;
my ($file) = @_; my $printed_nogitdir = 0;
sub has_git {
my $sign_offs = "";
my $cmd = "";
my $output = "";
my $count = 0;
my @lines = ();
my %hash;
my $total_sign_offs;
if (which("git") eq "") { if (which("git") eq "") {
if (!$printed_nogit) {
warn("$P: git not found. Add --nogit to options?\n"); warn("$P: git not found. Add --nogit to options?\n");
return; $printed_nogit = 1;
}
return 0;
} }
if (!(-d ".git")) { if (!(-d ".git")) {
warn("$P: .git directory not found. Use a git repository for better results.\n"); if (!$printed_nogitdir) {
warn("$P: perhaps 'git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git'\n"); warn(".git directory not found. "
return; . "Using a git repository produces better results.\n");
warn("Try Linus Torvalds' latest git repository using:\n");
warn("git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git\n");
$printed_nogitdir = 1;
}
return 0;
} }
$cmd = "git log --since=${email_git_since} -- ${file}"; return 1;
}
sub git_find_signers {
my ($cmd) = @_;
my $output;
my @lines = ();
my $commits;
return (0, @lines) if (!has_git());
$output = `${cmd}`; $output = `${cmd}`;
$output =~ s/^\s*//gm; $output =~ s/^\s*//gm;
@lines = split("\n", $output); @lines = split("\n", $output);
$commits = grep(/^commit [0-9a-f]{40,40}/, @lines); # of commits
@lines = grep(/^[-_ a-z]+by:.*\@.*$/i, @lines); @lines = grep(/^[-_ a-z]+by:.*\@.*$/i, @lines);
if (!$email_git_penguin_chiefs) { if (!$email_git_penguin_chiefs) {
...@@ -844,10 +853,28 @@ sub recent_git_signoffs { ...@@ -844,10 +853,28 @@ sub recent_git_signoffs {
# cut -f2- -d":" # cut -f2- -d":"
s/.*:\s*(.+)\s*/$1/ for (@lines); s/.*:\s*(.+)\s*/$1/ for (@lines);
$total_sign_offs = @lines; ## Reformat email addresses (with names) to avoid badly written signatures
foreach my $line (@lines) { foreach my $line (@lines) {
my ($name, $address) = parse_email($line); my ($name, $address) = parse_email($line);
$line = format_email($name, $address); $line = format_email($name, $address, 1);
}
return ($commits, @lines);
}
sub git_assign_signers {
my ($role, $divisor, @lines) = @_;
my %hash;
my $count = 0;
return if (!has_git());
return if (@lines <= 0);
if ($divisor <= 0) {
warn("Bad divisor in git_assign_signers: $divisor\n");
$divisor = 1;
} }
if ($email_remove_duplicates) { if ($email_remove_duplicates) {
...@@ -862,20 +889,34 @@ sub recent_git_signoffs { ...@@ -862,20 +889,34 @@ sub recent_git_signoffs {
# sort -rn # sort -rn
foreach my $line (sort {$hash{$b} <=> $hash{$a}} keys %hash) { foreach my $line (sort {$hash{$b} <=> $hash{$a}} keys %hash) {
my $sign_offs = $hash{$line}; my $sign_offs = $hash{$line};
my $role; my $percent = $sign_offs * 100 / $divisor;
$percent = 100 if ($percent > 100);
$count++; $count++;
last if ($sign_offs < $email_git_min_signatures || last if ($sign_offs < $email_git_min_signatures ||
$count > $email_git_max_maintainers || $count > $email_git_max_maintainers ||
$sign_offs * 100 / $total_sign_offs < $email_git_min_percent); $percent < $email_git_min_percent);
push_email_address($line, ''); push_email_address($line, '');
$role = "git-signer";
if ($output_rolestats) { if ($output_rolestats) {
my $percent = sprintf("%.0f", $sign_offs * 100 / $total_sign_offs); my $fmt_percent = sprintf("%.0f", $percent);
$role = "$role:$sign_offs/$total_sign_offs=$percent%"; add_role($line, "$role:$sign_offs/$divisor=$fmt_percent%");
} } else {
add_role($line, $role); add_role($line, $role);
} }
}
}
sub git_file_signoffs {
my ($file) = @_;
my @signers = ();
my $total_signers;
return if (!has_git());
($total_signers, @signers) =
git_find_signers("git log --since=$email_git_since -- $file");
git_assign_signers("git_signer", $total_signers, @signers);
} }
sub save_commits { sub save_commits {
...@@ -883,6 +924,8 @@ sub save_commits { ...@@ -883,6 +924,8 @@ sub save_commits {
my $output; my $output;
my @lines = (); my @lines = ();
return (@lines) if (!has_git());
$output = `${cmd}`; $output = `${cmd}`;
@lines = split("\n", $output); @lines = split("\n", $output);
...@@ -897,13 +940,10 @@ sub save_commits { ...@@ -897,13 +940,10 @@ sub save_commits {
sub git_assign_blame { sub git_assign_blame {
my ($file) = @_; my ($file) = @_;
my @lines = ();
my @commits = ();
my $cmd; my $cmd;
my $output; my @commits = ();
my %hash; my @signers = ();
my $total_sign_offs; my $total_commits;
my $count;
if (@range) { if (@range) {
foreach my $file_range_diff (@range) { foreach my $file_range_diff (@range) {
...@@ -922,57 +962,27 @@ sub git_assign_blame { ...@@ -922,57 +962,27 @@ sub git_assign_blame {
} }
} }
$total_sign_offs = 0;
@commits = uniq(@commits); @commits = uniq(@commits);
foreach my $commit (@commits) { $total_commits = @commits;
$cmd = "git log -1 ${commit}";
$output = `${cmd}`;
$output =~ s/^\s*//gm;
@lines = split("\n", $output);
@lines = grep(/^[-_ a-z]+by:.*\@.*$/i, @lines);
if (!$email_git_penguin_chiefs) {
@lines = grep(!/${penguin_chiefs}/i, @lines);
}
# cut -f2- -d":"
s/.*:\s*(.+)\s*/$1/ for (@lines);
$total_sign_offs += @lines;
if ($email_remove_duplicates) { foreach my $commit (@commits) {
@lines = mailmap(@lines); my $commit_count;
} my @commit_signers = ();
$hash{$_}++ for @lines; ($commit_count, @commit_signers) =
git_find_signers("git log -1 $commit");
@signers = (@signers, @commit_signers);
} }
$count = 0;
foreach my $line (sort {$hash{$b} <=> $hash{$a}} keys %hash) {
my $sign_offs = $hash{$line};
my $role;
$count++;
last if ($sign_offs < $email_git_min_signatures ||
$count > $email_git_max_maintainers ||
$sign_offs * 100 / $total_sign_offs < $email_git_min_percent);
push_email_address($line, '');
if ($from_filename) { if ($from_filename) {
$role = "commits"; git_assign_signers("commits", $total_commits, @signers);
} else { } else {
$role = "modified commits"; git_assign_signers("modified commits", $total_commits, @signers);
}
if ($output_rolestats) {
my $percent = sprintf("%.0f", $sign_offs * 100 / $total_sign_offs);
$role = "$role:$sign_offs/$total_sign_offs=$percent%";
}
add_role($line, $role);
} }
} }
sub uniq { sub uniq {
my @parms = @_; my (@parms) = @_;
my %saw; my %saw;
@parms = grep(!$saw{$_}++, @parms); @parms = grep(!$saw{$_}++, @parms);
...@@ -980,7 +990,7 @@ sub uniq { ...@@ -980,7 +990,7 @@ sub uniq {
} }
sub sort_and_uniq { sub sort_and_uniq {
my @parms = @_; my (@parms) = @_;
my %saw; my %saw;
@parms = sort @parms; @parms = sort @parms;
...@@ -1008,7 +1018,7 @@ sub merge_email { ...@@ -1008,7 +1018,7 @@ sub merge_email {
} }
sub output { sub output {
my @parms = @_; my (@parms) = @_;
if ($output_multiline) { if ($output_multiline) {
foreach my $line (@parms) { foreach my $line (@parms) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment