diff options
| author | Joe Perches <joe@perches.com> | 2010-10-26 17:22:56 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-10-26 19:52:17 -0400 |
| commit | 6ef1c52e122b675acc88a8b016d6477f67988b91 (patch) | |
| tree | ae38fb0fa0811356aa95c5bf8246eb0f9826e37c /scripts | |
| parent | 683c6f8fcbcb6de8d07545ba70aff49e50d8bcf2 (diff) | |
scripts/get_maintainer.pl: use case insensitive name de-duplication
Case insensitive name and email address matching can help reduce
duplication when authors don't always use the exact same signature.
o Add a --interactive per-file exact_match hash so git history
can be checked on per-file only when there is no direct maintainer
o Make @interactive_to list global so save_commits_by_<foo> can check
email names & addresses against this list for duplication
o Don't allow --interactive and --sections
o rename subroutine get_maintainer to get_maintainers
o Added help text option to --interactive menu prompt
Update version to 0.26-beta4
Signed-off-by: Joe Perches <joe@perches.com>
Cc: Florian Mickler <florian@mickler.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'scripts')
| -rwxr-xr-x | scripts/get_maintainer.pl | 135 |
1 files changed, 101 insertions, 34 deletions
diff --git a/scripts/get_maintainer.pl b/scripts/get_maintainer.pl index f51176039ff5..61d3bb51bddf 100755 --- a/scripts/get_maintainer.pl +++ b/scripts/get_maintainer.pl | |||
| @@ -13,7 +13,7 @@ | |||
| 13 | use strict; | 13 | use strict; |
| 14 | 14 | ||
| 15 | my $P = $0; | 15 | my $P = $0; |
| 16 | my $V = '0.26-beta3'; | 16 | my $V = '0.26-beta4'; |
| 17 | 17 | ||
| 18 | use Getopt::Long qw(:config no_auto_abbrev); | 18 | use Getopt::Long qw(:config no_auto_abbrev); |
| 19 | 19 | ||
| @@ -242,6 +242,7 @@ if ($sections) { | |||
| 242 | $subsystem = 0; | 242 | $subsystem = 0; |
| 243 | $web = 0; | 243 | $web = 0; |
| 244 | $keywords = 0; | 244 | $keywords = 0; |
| 245 | $interactive = 0; | ||
| 245 | } else { | 246 | } else { |
| 246 | my $selections = $email + $scm + $status + $subsystem + $web; | 247 | my $selections = $email + $scm + $status + $subsystem + $web; |
| 247 | if ($selections == 0) { | 248 | if ($selections == 0) { |
| @@ -407,13 +408,15 @@ my @scm = (); | |||
| 407 | my @web = (); | 408 | my @web = (); |
| 408 | my @subsystem = (); | 409 | my @subsystem = (); |
| 409 | my @status = (); | 410 | my @status = (); |
| 411 | my @interactive_to = (); | ||
| 410 | my $signature_pattern; | 412 | my $signature_pattern; |
| 411 | 413 | ||
| 412 | my @to = get_maintainer(); | 414 | my @maintainers = get_maintainers(); |
| 413 | 415 | ||
| 414 | @to = merge_email(@to); | 416 | if (@maintainers) { |
| 415 | 417 | @maintainers = merge_email(@maintainers); | |
| 416 | output(@to) if (@to); | 418 | output(@maintainers); |
| 419 | } | ||
| 417 | 420 | ||
| 418 | if ($scm) { | 421 | if ($scm) { |
| 419 | @scm = uniq(@scm); | 422 | @scm = uniq(@scm); |
| @@ -437,7 +440,7 @@ if ($web) { | |||
| 437 | 440 | ||
| 438 | exit($exit); | 441 | exit($exit); |
| 439 | 442 | ||
| 440 | sub get_maintainer { | 443 | sub get_maintainers { |
| 441 | %email_hash_name = (); | 444 | %email_hash_name = (); |
| 442 | %email_hash_address = (); | 445 | %email_hash_address = (); |
| 443 | %commit_author_hash = (); | 446 | %commit_author_hash = (); |
| @@ -449,7 +452,7 @@ sub get_maintainer { | |||
| 449 | @web = (); | 452 | @web = (); |
| 450 | @subsystem = (); | 453 | @subsystem = (); |
| 451 | @status = (); | 454 | @status = (); |
| 452 | 455 | @interactive_to = (); | |
| 453 | if ($email_git_all_signature_types) { | 456 | if ($email_git_all_signature_types) { |
| 454 | $signature_pattern = "(.+?)[Bb][Yy]:"; | 457 | $signature_pattern = "(.+?)[Bb][Yy]:"; |
| 455 | } else { | 458 | } else { |
| @@ -458,10 +461,11 @@ sub get_maintainer { | |||
| 458 | 461 | ||
| 459 | # Find responsible parties | 462 | # Find responsible parties |
| 460 | 463 | ||
| 464 | my %exact_pattern_match_hash; | ||
| 465 | |||
| 461 | foreach my $file (@files) { | 466 | foreach my $file (@files) { |
| 462 | 467 | ||
| 463 | my %hash; | 468 | my %hash; |
| 464 | my $exact_pattern_match = 0; | ||
| 465 | my $tvi = find_first_section(); | 469 | my $tvi = find_first_section(); |
| 466 | while ($tvi < @typevalue) { | 470 | while ($tvi < @typevalue) { |
| 467 | my $start = find_starting_index($tvi); | 471 | my $start = find_starting_index($tvi); |
| @@ -497,7 +501,9 @@ sub get_maintainer { | |||
| 497 | my $file_pd = ($file =~ tr@/@@); | 501 | my $file_pd = ($file =~ tr@/@@); |
| 498 | $value_pd++ if (substr($value,-1,1) ne "/"); | 502 | $value_pd++ if (substr($value,-1,1) ne "/"); |
| 499 | $value_pd = -1 if ($value =~ /^\.\*/); | 503 | $value_pd = -1 if ($value =~ /^\.\*/); |
| 500 | $exact_pattern_match = 1 if ($value_pd >= $file_pd); | 504 | if ($value_pd >= $file_pd) { |
| 505 | $exact_pattern_match_hash{$file} = 1; | ||
| 506 | } | ||
| 501 | if ($pattern_depth == 0 || | 507 | if ($pattern_depth == 0 || |
| 502 | (($file_pd - $value_pd) < $pattern_depth)) { | 508 | (($file_pd - $value_pd) < $pattern_depth)) { |
| 503 | $hash{$tvi} = $value_pd; | 509 | $hash{$tvi} = $value_pd; |
| @@ -530,14 +536,6 @@ sub get_maintainer { | |||
| 530 | print("\n"); | 536 | print("\n"); |
| 531 | } | 537 | } |
| 532 | } | 538 | } |
| 533 | |||
| 534 | if ($email && ($email_git || | ||
| 535 | ($email_git_fallback && !$exact_pattern_match))) { | ||
| 536 | vcs_file_signoffs($file); | ||
| 537 | } | ||
| 538 | if ($email && $email_git_blame) { | ||
| 539 | vcs_file_blame($file); | ||
| 540 | } | ||
| 541 | } | 539 | } |
| 542 | 540 | ||
| 543 | if ($keywords) { | 541 | if ($keywords) { |
| @@ -547,6 +545,19 @@ sub get_maintainer { | |||
| 547 | } | 545 | } |
| 548 | } | 546 | } |
| 549 | 547 | ||
| 548 | @interactive_to = (@email_to, @list_to); | ||
| 549 | |||
| 550 | foreach my $file (@files) { | ||
| 551 | if ($email && | ||
| 552 | ($email_git || ($email_git_fallback && | ||
| 553 | !$exact_pattern_match_hash{$file}))) { | ||
| 554 | vcs_file_signoffs($file); | ||
| 555 | } | ||
| 556 | if ($email && $email_git_blame) { | ||
| 557 | vcs_file_blame($file); | ||
| 558 | } | ||
| 559 | } | ||
| 560 | |||
| 550 | if ($email) { | 561 | if ($email) { |
| 551 | foreach my $chief (@penguin_chief) { | 562 | foreach my $chief (@penguin_chief) { |
| 552 | if ($chief =~ m/^(.*):(.*)/) { | 563 | if ($chief =~ m/^(.*):(.*)/) { |
| @@ -580,7 +591,10 @@ sub get_maintainer { | |||
| 580 | } | 591 | } |
| 581 | } | 592 | } |
| 582 | 593 | ||
| 583 | @to = interactive_get_maintainer(\@to) if ($interactive); | 594 | if ($interactive) { |
| 595 | @interactive_to = @to; | ||
| 596 | @to = interactive_get_maintainers(\@interactive_to); | ||
| 597 | } | ||
| 584 | 598 | ||
| 585 | return @to; | 599 | return @to; |
| 586 | } | 600 | } |
| @@ -899,16 +913,16 @@ sub add_categories { | |||
| 899 | } | 913 | } |
| 900 | if ($list_additional =~ m/subscribers-only/) { | 914 | if ($list_additional =~ m/subscribers-only/) { |
| 901 | if ($email_subscriber_list) { | 915 | if ($email_subscriber_list) { |
| 902 | if (!$hash_list_to{$list_address}) { | 916 | if (!$hash_list_to{lc($list_address)}) { |
| 903 | $hash_list_to{$list_address} = 1; | 917 | $hash_list_to{lc($list_address)} = 1; |
| 904 | push(@list_to, [$list_address, | 918 | push(@list_to, [$list_address, |
| 905 | "subscriber list${list_role}"]); | 919 | "subscriber list${list_role}"]); |
| 906 | } | 920 | } |
| 907 | } | 921 | } |
| 908 | } else { | 922 | } else { |
| 909 | if ($email_list) { | 923 | if ($email_list) { |
| 910 | if (!$hash_list_to{$list_address}) { | 924 | if (!$hash_list_to{lc($list_address)}) { |
| 911 | $hash_list_to{$list_address} = 1; | 925 | $hash_list_to{lc($list_address)} = 1; |
| 912 | push(@list_to, [$list_address, | 926 | push(@list_to, [$list_address, |
| 913 | "open list${list_role}"]); | 927 | "open list${list_role}"]); |
| 914 | } | 928 | } |
| @@ -946,8 +960,8 @@ sub email_inuse { | |||
| 946 | my ($name, $address) = @_; | 960 | my ($name, $address) = @_; |
| 947 | 961 | ||
| 948 | return 1 if (($name eq "") && ($address eq "")); | 962 | return 1 if (($name eq "") && ($address eq "")); |
| 949 | return 1 if (($name ne "") && exists($email_hash_name{$name})); | 963 | return 1 if (($name ne "") && exists($email_hash_name{lc($name)})); |
| 950 | return 1 if (($address ne "") && exists($email_hash_address{$address})); | 964 | return 1 if (($address ne "") && exists($email_hash_address{lc($address)})); |
| 951 | 965 | ||
| 952 | return 0; | 966 | return 0; |
| 953 | } | 967 | } |
| @@ -965,8 +979,8 @@ sub push_email_address { | |||
| 965 | push(@email_to, [format_email($name, $address, $email_usename), $role]); | 979 | push(@email_to, [format_email($name, $address, $email_usename), $role]); |
| 966 | } elsif (!email_inuse($name, $address)) { | 980 | } elsif (!email_inuse($name, $address)) { |
| 967 | push(@email_to, [format_email($name, $address, $email_usename), $role]); | 981 | push(@email_to, [format_email($name, $address, $email_usename), $role]); |
| 968 | $email_hash_name{$name}++; | 982 | $email_hash_name{lc($name)}++; |
| 969 | $email_hash_address{$address}++; | 983 | $email_hash_address{lc($address)}++; |
| 970 | } | 984 | } |
| 971 | 985 | ||
| 972 | return 1; | 986 | return 1; |
| @@ -1259,7 +1273,7 @@ sub vcs_is_hg { | |||
| 1259 | return $vcs_used == 2; | 1273 | return $vcs_used == 2; |
| 1260 | } | 1274 | } |
| 1261 | 1275 | ||
| 1262 | sub interactive_get_maintainer { | 1276 | sub interactive_get_maintainers { |
| 1263 | my ($list_ref) = @_; | 1277 | my ($list_ref) = @_; |
| 1264 | my @list = @$list_ref; | 1278 | my @list = @$list_ref; |
| 1265 | 1279 | ||
| @@ -1269,11 +1283,12 @@ sub interactive_get_maintainer { | |||
| 1269 | my %authored; | 1283 | my %authored; |
| 1270 | my %signed; | 1284 | my %signed; |
| 1271 | my $count = 0; | 1285 | my $count = 0; |
| 1272 | 1286 | my $maintained = 0; | |
| 1273 | #select maintainers by default | 1287 | #select maintainers by default |
| 1274 | foreach my $entry (@list){ | 1288 | foreach my $entry (@list) { |
| 1275 | my $role = $entry->[1]; | 1289 | my $role = $entry->[1]; |
| 1276 | $selected{$count} = ($role =~ /^(maintainer|supporter|open list)/); | 1290 | $selected{$count} = ($role =~ /^(maintainer|supporter|open list)/i); |
| 1291 | $maintained = 1 if ($role =~ /^(maintainer|supporter)/i); | ||
| 1277 | $authored{$count} = 0; | 1292 | $authored{$count} = 0; |
| 1278 | $signed{$count} = 0; | 1293 | $signed{$count} = 0; |
| 1279 | $count++; | 1294 | $count++; |
| @@ -1286,8 +1301,14 @@ sub interactive_get_maintainer { | |||
| 1286 | while (!$done) { | 1301 | while (!$done) { |
| 1287 | $count = 0; | 1302 | $count = 0; |
| 1288 | if ($redraw) { | 1303 | if ($redraw) { |
| 1289 | printf STDERR "\n%1s %2s %-65sauth sign\n", | 1304 | printf STDERR "\n%1s %2s %-65s", |
| 1290 | "*", "#", "email/list and role:stats"; | 1305 | "*", "#", "email/list and role:stats"; |
| 1306 | if ($email_git || | ||
| 1307 | ($email_git_fallback && !$maintained) || | ||
| 1308 | $email_git_blame) { | ||
| 1309 | print STDERR "auth sign"; | ||
| 1310 | } | ||
| 1311 | print STDERR "\n"; | ||
| 1291 | foreach my $entry (@list) { | 1312 | foreach my $entry (@list) { |
| 1292 | my $email = $entry->[0]; | 1313 | my $email = $entry->[0]; |
| 1293 | my $role = $entry->[1]; | 1314 | my $role = $entry->[1]; |
| @@ -1453,6 +1474,27 @@ sub interactive_get_maintainer { | |||
| 1453 | $pattern_depth = $val; | 1474 | $pattern_depth = $val; |
| 1454 | $rerun = 1; | 1475 | $rerun = 1; |
| 1455 | } | 1476 | } |
| 1477 | } elsif ($sel eq "h" || $sel eq "?") { | ||
| 1478 | print STDERR <<EOT | ||
| 1479 | |||
| 1480 | Interactive mode allows you to select the various maintainers, submitters, | ||
| 1481 | commit signers and mailing lists that could be CC'd on a patch. | ||
| 1482 | |||
| 1483 | Any *'d entry is selected. | ||
| 1484 | |||
| 1485 | If you have git or hg installed, You can choose to summarize the commit | ||
| 1486 | history of files in the patch. Also, each line of the current file can | ||
| 1487 | be matched to its commit author and that commits signers with blame. | ||
| 1488 | |||
| 1489 | Various knobs exist to control the length of time for active commit | ||
| 1490 | tracking, the maximum number of commit authors and signers to add, | ||
| 1491 | and such. | ||
| 1492 | |||
| 1493 | Enter selections at the prompt until you are satisfied that the selected | ||
| 1494 | maintainers are appropriate. You may enter multiple selections separated | ||
| 1495 | by either commas or spaces. | ||
| 1496 | |||
| 1497 | EOT | ||
| 1456 | } else { | 1498 | } else { |
| 1457 | print STDERR "invalid option: '$nr'\n"; | 1499 | print STDERR "invalid option: '$nr'\n"; |
| 1458 | $redraw = 0; | 1500 | $redraw = 0; |
| @@ -1461,7 +1503,7 @@ sub interactive_get_maintainer { | |||
| 1461 | if ($rerun) { | 1503 | if ($rerun) { |
| 1462 | print STDERR "git-blame can be very slow, please have patience..." | 1504 | print STDERR "git-blame can be very slow, please have patience..." |
| 1463 | if ($email_git_blame); | 1505 | if ($email_git_blame); |
| 1464 | goto &get_maintainer; | 1506 | goto &get_maintainers; |
| 1465 | } | 1507 | } |
| 1466 | } | 1508 | } |
| 1467 | 1509 | ||
| @@ -1496,9 +1538,20 @@ sub save_commits_by_author { | |||
| 1496 | 1538 | ||
| 1497 | foreach my $line (@lines) { | 1539 | foreach my $line (@lines) { |
| 1498 | if ($line =~ m/$VCS_cmds{"author_pattern"}/) { | 1540 | if ($line =~ m/$VCS_cmds{"author_pattern"}/) { |
| 1541 | my $matched = 0; | ||
| 1499 | my $author = $1; | 1542 | my $author = $1; |
| 1500 | my ($name, $address) = parse_email($author); | 1543 | my ($name, $address) = parse_email($author); |
| 1501 | $author = format_email($name, $address, 1); | 1544 | foreach my $to (@interactive_to) { |
| 1545 | my ($to_name, $to_address) = parse_email($to->[0]); | ||
| 1546 | if ($email_remove_duplicates && | ||
| 1547 | ((lc($name) eq lc($to_name)) || | ||
| 1548 | (lc($address) eq lc($to_address)))) { | ||
| 1549 | $author = $to->[0]; | ||
| 1550 | $matched = 1; | ||
| 1551 | last; | ||
| 1552 | } | ||
| 1553 | } | ||
| 1554 | $author = format_email($name, $address, 1) if (!$matched); | ||
| 1502 | push(@authors, $author); | 1555 | push(@authors, $author); |
| 1503 | } | 1556 | } |
| 1504 | push(@commits, $1) if ($line =~ m/$VCS_cmds{"commit_pattern"}/); | 1557 | push(@commits, $1) if ($line =~ m/$VCS_cmds{"commit_pattern"}/); |
| @@ -1539,6 +1592,20 @@ sub save_commits_by_signer { | |||
| 1539 | my $type = $types[0]; | 1592 | my $type = $types[0]; |
| 1540 | my $signer = $signers[0]; | 1593 | my $signer = $signers[0]; |
| 1541 | 1594 | ||
| 1595 | my $matched = 0; | ||
| 1596 | my ($name, $address) = parse_email($signer); | ||
| 1597 | foreach my $to (@interactive_to) { | ||
| 1598 | my ($to_name, $to_address) = parse_email($to->[0]); | ||
| 1599 | if ($email_remove_duplicates && | ||
| 1600 | ((lc($name) eq lc($to_name)) || | ||
| 1601 | (lc($address) eq lc($to_address)))) { | ||
| 1602 | $signer = $to->[0]; | ||
| 1603 | $matched = 1; | ||
| 1604 | last; | ||
| 1605 | } | ||
| 1606 | $signer = format_email($name, $address, 1) if (!$matched); | ||
| 1607 | } | ||
| 1608 | |||
| 1542 | my $exists = 0; | 1609 | my $exists = 0; |
| 1543 | foreach my $ref(@{$commit_signer_hash{$signer}}) { | 1610 | foreach my $ref(@{$commit_signer_hash{$signer}}) { |
| 1544 | if (@{$ref}[0] eq $commit && | 1611 | if (@{$ref}[0] eq $commit && |
