aboutsummaryrefslogtreecommitdiffstats
path: root/scripts
diff options
context:
space:
mode:
authorJoe Perches <joe@perches.com>2010-10-26 17:22:58 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2010-10-26 19:52:17 -0400
commitb9e2331dd1e0e04f7f2a6f8aa0c05bac2a7f0d7b (patch)
tree57696e66a6244c8795d0a3a2155fa9c61291a292 /scripts
parent47abc7225761faf28be52b3ac4dc26ffeac7b750 (diff)
scripts/get_maintainer.pl: use mailmap in name deduplication and other updates
Use Florian Mickler's mailmap routine to reduce name duplication. o Add subroutine deduplicate_email to centralize code o Add hashes for deduplicate_(name|address)_hash o Remove now unused @interactive_to o Whitespace neatening o Add command line --help text o Add --mailmap command line option control o Interactive changes: - Add toggles for maintainer, git and list selections - Default selection is all - Add mailmap control Update to 0.26-beta5 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-xscripts/get_maintainer.pl232
1 files changed, 148 insertions, 84 deletions
diff --git a/scripts/get_maintainer.pl b/scripts/get_maintainer.pl
index 0abfdbc5cdff..e822518bc610 100755
--- a/scripts/get_maintainer.pl
+++ b/scripts/get_maintainer.pl
@@ -13,7 +13,7 @@
13use strict; 13use strict;
14 14
15my $P = $0; 15my $P = $0;
16my $V = '0.26-beta4'; 16my $V = '0.26-beta5';
17 17
18use Getopt::Long qw(:config no_auto_abbrev); 18use Getopt::Long qw(:config no_auto_abbrev);
19 19
@@ -36,6 +36,7 @@ my $email_git_since = "1-year-ago";
36my $email_hg_since = "-365"; 36my $email_hg_since = "-365";
37my $interactive = 0; 37my $interactive = 0;
38my $email_remove_duplicates = 1; 38my $email_remove_duplicates = 1;
39my $email_use_mailmap = 1;
39my $output_multiline = 1; 40my $output_multiline = 1;
40my $output_separator = ", "; 41my $output_separator = ", ";
41my $output_roles = 0; 42my $output_roles = 0;
@@ -192,6 +193,7 @@ if (!GetOptions(
192 'hg-since=s' => \$email_hg_since, 193 'hg-since=s' => \$email_hg_since,
193 'i|interactive!' => \$interactive, 194 'i|interactive!' => \$interactive,
194 'remove-duplicates!' => \$email_remove_duplicates, 195 'remove-duplicates!' => \$email_remove_duplicates,
196 'mailmap!' => \$email_use_mailmap,
195 'm!' => \$email_maintainer, 197 'm!' => \$email_maintainer,
196 'n!' => \$email_usename, 198 'n!' => \$email_usename,
197 'l!' => \$email_list, 199 'l!' => \$email_list,
@@ -300,17 +302,17 @@ close($maint);
300# Read mail address map 302# Read mail address map
301# 303#
302 304
303my $mailmap = read_mailmap(); 305my $mailmap;
306
307read_mailmap();
304 308
305sub read_mailmap { 309sub read_mailmap {
306 my $mailmap = { 310 $mailmap = {
307 names => {}, 311 names => {},
308 addresses => {} 312 addresses => {}
309 }; 313 };
310 314
311 if (!$email_remove_duplicates) { 315 return if (!$email_use_mailmap || !(-f "${lk_path}.mailmap"));
312 return $mailmap;
313 }
314 316
315 open(my $mailmap_file, '<', "${lk_path}.mailmap") 317 open(my $mailmap_file, '<', "${lk_path}.mailmap")
316 or warn "$P: Can't open .mailmap: $!\n"; 318 or warn "$P: Can't open .mailmap: $!\n";
@@ -331,6 +333,7 @@ sub read_mailmap {
331 my $address = $2; 333 my $address = $2;
332 334
333 $real_name =~ s/\s+$//; 335 $real_name =~ s/\s+$//;
336 ($real_name, $address) = parse_email("$real_name <$address>");
334 $mailmap->{names}->{$address} = $real_name; 337 $mailmap->{names}->{$address} = $real_name;
335 338
336 } elsif (/^<([^\s]+)>\s*<([^\s]+)>$/) { 339 } elsif (/^<([^\s]+)>\s*<([^\s]+)>$/) {
@@ -340,12 +343,13 @@ sub read_mailmap {
340 $mailmap->{addresses}->{$wrong_address} = $real_address; 343 $mailmap->{addresses}->{$wrong_address} = $real_address;
341 344
342 } elsif (/^(.+)<([^\s]+)>\s*<([^\s]+)>$/) { 345 } elsif (/^(.+)<([^\s]+)>\s*<([^\s]+)>$/) {
343 my $real_name= $1; 346 my $real_name = $1;
344 my $real_address = $2; 347 my $real_address = $2;
345 my $wrong_address = $3; 348 my $wrong_address = $3;
346 349
347 $real_name =~ s/\s+$//; 350 $real_name =~ s/\s+$//;
348 351 ($real_name, $real_address) =
352 parse_email("$real_name <$real_address>");
349 $mailmap->{names}->{$wrong_address} = $real_name; 353 $mailmap->{names}->{$wrong_address} = $real_name;
350 $mailmap->{addresses}->{$wrong_address} = $real_address; 354 $mailmap->{addresses}->{$wrong_address} = $real_address;
351 355
@@ -356,15 +360,19 @@ sub read_mailmap {
356 my $wrong_address = $4; 360 my $wrong_address = $4;
357 361
358 $real_name =~ s/\s+$//; 362 $real_name =~ s/\s+$//;
363 ($real_name, $real_address) =
364 parse_email("$real_name <$real_address>");
365
359 $wrong_name =~ s/\s+$//; 366 $wrong_name =~ s/\s+$//;
367 ($wrong_name, $wrong_address) =
368 parse_email("$wrong_name <$wrong_address>");
360 369
361 $mailmap->{names}->{format_email($wrong_name,$wrong_address,1)} = $real_name; 370 my $wrong_email = format_email($wrong_name, $wrong_address, 1);
362 $mailmap->{addresses}->{format_email($wrong_name,$wrong_address,1)} = $real_address; 371 $mailmap->{names}->{$wrong_email} = $real_name;
372 $mailmap->{addresses}->{$wrong_email} = $real_address;
363 } 373 }
364 } 374 }
365 close($mailmap_file); 375 close($mailmap_file);
366
367 return $mailmap;
368} 376}
369 377
370## use the filenames on the command line or find the filenames in the patchfiles 378## use the filenames on the command line or find the filenames in the patchfiles
@@ -453,7 +461,8 @@ my @scm = ();
453my @web = (); 461my @web = ();
454my @subsystem = (); 462my @subsystem = ();
455my @status = (); 463my @status = ();
456my @interactive_to = (); 464my %deduplicate_name_hash = ();
465my %deduplicate_address_hash = ();
457my $signature_pattern; 466my $signature_pattern;
458 467
459my @maintainers = get_maintainers(); 468my @maintainers = get_maintainers();
@@ -497,7 +506,8 @@ sub get_maintainers {
497 @web = (); 506 @web = ();
498 @subsystem = (); 507 @subsystem = ();
499 @status = (); 508 @status = ();
500 @interactive_to = (); 509 %deduplicate_name_hash = ();
510 %deduplicate_address_hash = ();
501 if ($email_git_all_signature_types) { 511 if ($email_git_all_signature_types) {
502 $signature_pattern = "(.+?)[Bb][Yy]:"; 512 $signature_pattern = "(.+?)[Bb][Yy]:";
503 } else { 513 } else {
@@ -506,7 +516,7 @@ sub get_maintainers {
506 516
507 # Find responsible parties 517 # Find responsible parties
508 518
509 my %exact_pattern_match_hash; 519 my %exact_pattern_match_hash = ();
510 520
511 foreach my $file (@files) { 521 foreach my $file (@files) {
512 522
@@ -590,7 +600,9 @@ sub get_maintainers {
590 } 600 }
591 } 601 }
592 602
593 @interactive_to = (@email_to, @list_to); 603 foreach my $email (@email_to, @list_to) {
604 $email->[0] = deduplicate_email($email->[0]);
605 }
594 606
595 foreach my $file (@files) { 607 foreach my $file (@files) {
596 if ($email && 608 if ($email &&
@@ -637,8 +649,7 @@ sub get_maintainers {
637 } 649 }
638 650
639 if ($interactive) { 651 if ($interactive) {
640 @interactive_to = @to; 652 @to = interactive_get_maintainers(\@to);
641 @to = interactive_get_maintainers(\@interactive_to);
642 } 653 }
643 654
644 return @to; 655 return @to;
@@ -702,8 +713,9 @@ Output type options:
702 713
703Other options: 714Other options:
704 --pattern-depth => Number of pattern directory traversals (default: 0 (all)) 715 --pattern-depth => Number of pattern directory traversals (default: 0 (all))
705 --keywords => scan patch for keywords (default: 1 (on)) 716 --keywords => scan patch for keywords (default: $keywords)
706 --sections => print the entire subsystem sections with pattern matches 717 --sections => print all of the subsystem sections with pattern matches
718 --mailmap => use .mailmap file (default: $email_use_mailmap)
707 --version => show version 719 --version => show version
708 --help => show this help information 720 --help => show this help information
709 721
@@ -1107,7 +1119,7 @@ sub which_conf {
1107} 1119}
1108 1120
1109sub mailmap_email { 1121sub mailmap_email {
1110 my $line = shift; 1122 my ($line) = @_;
1111 1123
1112 my ($name, $address) = parse_email($line); 1124 my ($name, $address) = parse_email($line);
1113 my $email = format_email($name, $address, 1); 1125 my $email = format_email($name, $address, 1);
@@ -1136,26 +1148,25 @@ sub mailmap_email {
1136sub mailmap { 1148sub mailmap {
1137 my (@addresses) = @_; 1149 my (@addresses) = @_;
1138 1150
1139 my @ret = (); 1151 my @mapped_emails = ();
1140 foreach my $line (@addresses) { 1152 foreach my $line (@addresses) {
1141 push(@ret, mailmap_email($line), 1); 1153 push(@mapped_emails, mailmap_email($line));
1142 } 1154 }
1143 1155 merge_by_realname(@mapped_emails) if ($email_use_mailmap);
1144 merge_by_realname(@ret) if $email_remove_duplicates; 1156 return @mapped_emails;
1145
1146 return @ret;
1147} 1157}
1148 1158
1149sub merge_by_realname { 1159sub merge_by_realname {
1150 my %address_map; 1160 my %address_map;
1151 my (@emails) = @_; 1161 my (@emails) = @_;
1162
1152 foreach my $email (@emails) { 1163 foreach my $email (@emails) {
1153 my ($name, $address) = parse_email($email); 1164 my ($name, $address) = parse_email($email);
1154 if (!exists $address_map{$name}) { 1165 if (exists $address_map{$name}) {
1155 $address_map{$name} = $address;
1156 } else {
1157 $address = $address_map{$name}; 1166 $address = $address_map{$name};
1158 $email = format_email($name,$address,1); 1167 $email = format_email($name, $address, 1);
1168 } else {
1169 $address_map{$name} = $address;
1159 } 1170 }
1160 } 1171 }
1161} 1172}
@@ -1194,8 +1205,7 @@ sub extract_formatted_signatures {
1194## Reformat email addresses (with names) to avoid badly written signatures 1205## Reformat email addresses (with names) to avoid badly written signatures
1195 1206
1196 foreach my $signer (@signature_lines) { 1207 foreach my $signer (@signature_lines) {
1197 my ($name, $address) = parse_email($signer); 1208 $signer = deduplicate_email($signer);
1198 $signer = format_email($name, $address, 1);
1199 } 1209 }
1200 1210
1201 return (\@type, \@signature_lines); 1211 return (\@type, \@signature_lines);
@@ -1339,6 +1349,7 @@ sub vcs_exists {
1339} 1349}
1340 1350
1341sub vcs_is_git { 1351sub vcs_is_git {
1352 vcs_exists();
1342 return $vcs_used == 1; 1353 return $vcs_used == 1;
1343} 1354}
1344 1355
@@ -1357,11 +1368,9 @@ sub interactive_get_maintainers {
1357 my %signed; 1368 my %signed;
1358 my $count = 0; 1369 my $count = 0;
1359 my $maintained = 0; 1370 my $maintained = 0;
1360 #select maintainers by default
1361 foreach my $entry (@list) { 1371 foreach my $entry (@list) {
1362 my $role = $entry->[1]; 1372 $maintained = 1 if ($entry->[1] =~ /^(maintainer|supporter)/i);
1363 $selected{$count} = ($role =~ /^(maintainer|supporter|open list)/i); 1373 $selected{$count} = 1;
1364 $maintained = 1 if ($role =~ /^(maintainer|supporter)/i);
1365 $authored{$count} = 0; 1374 $authored{$count} = 0;
1366 $signed{$count} = 0; 1375 $signed{$count} = 0;
1367 $count++; 1376 $count++;
@@ -1418,24 +1427,34 @@ sub interactive_get_maintainers {
1418 if ($print_options) { 1427 if ($print_options) {
1419 $print_options = 0; 1428 $print_options = 0;
1420 if (vcs_exists()) { 1429 if (vcs_exists()) {
1421 print STDERR 1430 print STDERR <<EOT
1422"\nVersion Control options:\n" . 1431
1423"g use git history [$email_git]\n" . 1432Version Control options:
1424"gf use git-fallback [$email_git_fallback]\n" . 1433g use git history [$email_git]
1425"b use git blame [$email_git_blame]\n" . 1434gf use git-fallback [$email_git_fallback]
1426"bs use blame signatures [$email_git_blame_signatures]\n" . 1435b use git blame [$email_git_blame]
1427"c# minimum commits [$email_git_min_signatures]\n" . 1436bs use blame signatures [$email_git_blame_signatures]
1428"%# min percent [$email_git_min_percent]\n" . 1437c# minimum commits [$email_git_min_signatures]
1429"d# history to use [$$date_ref]\n" . 1438%# min percent [$email_git_min_percent]
1430"x# max maintainers [$email_git_max_maintainers]\n" . 1439d# history to use [$$date_ref]
1431"t all signature types [$email_git_all_signature_types]\n"; 1440x# max maintainers [$email_git_max_maintainers]
1441t all signature types [$email_git_all_signature_types]
1442m use .mailmap [$email_use_mailmap]
1443EOT
1432 } 1444 }
1433 print STDERR "\nAdditional options:\n" . 1445 print STDERR <<EOT
1434"0 toggle all\n" . 1446
1435"f emails in file [$file_emails]\n" . 1447Additional options:
1436"k keywords in file [$keywords]\n" . 14480 toggle all
1437"r remove duplicates [$email_remove_duplicates]\n" . 1449tm toggle maintainers
1438"p# pattern match depth [$pattern_depth]\n"; 1450tg toggle git entries
1451tl toggle open list entries
1452ts toggle subscriber list entries
1453f emails in file [$file_emails]
1454k keywords in file [$keywords]
1455r remove duplicates [$email_remove_duplicates]
1456p# pattern match depth [$pattern_depth]
1457EOT
1439 } 1458 }
1440 print STDERR 1459 print STDERR
1441"\n#(toggle), A#(author), S#(signed) *(all), ^(none), O(options), Y(approve): "; 1460"\n#(toggle), A#(author), S#(signed) *(all), ^(none), O(options), Y(approve): ";
@@ -1471,6 +1490,28 @@ sub interactive_get_maintainers {
1471 for (my $i = 0; $i < $count; $i++) { 1490 for (my $i = 0; $i < $count; $i++) {
1472 $selected{$i} = !$selected{$i}; 1491 $selected{$i} = !$selected{$i};
1473 } 1492 }
1493 } elsif ($sel eq "t") {
1494 if (lc($str) eq "m") {
1495 for (my $i = 0; $i < $count; $i++) {
1496 $selected{$i} = !$selected{$i}
1497 if ($list[$i]->[1] =~ /^(maintainer|supporter)/i);
1498 }
1499 } elsif (lc($str) eq "g") {
1500 for (my $i = 0; $i < $count; $i++) {
1501 $selected{$i} = !$selected{$i}
1502 if ($list[$i]->[1] =~ /^(author|commit|signer)/i);
1503 }
1504 } elsif (lc($str) eq "l") {
1505 for (my $i = 0; $i < $count; $i++) {
1506 $selected{$i} = !$selected{$i}
1507 if ($list[$i]->[1] =~ /^(open list)/i);
1508 }
1509 } elsif (lc($str) eq "s") {
1510 for (my $i = 0; $i < $count; $i++) {
1511 $selected{$i} = !$selected{$i}
1512 if ($list[$i]->[1] =~ /^(subscriber list)/i);
1513 }
1514 }
1474 } elsif ($sel eq "a") { 1515 } elsif ($sel eq "a") {
1475 if ($val > 0 && $val <= $count) { 1516 if ($val > 0 && $val <= $count) {
1476 $authored{$val - 1} = !$authored{$val - 1}; 1517 $authored{$val - 1} = !$authored{$val - 1};
@@ -1539,6 +1580,10 @@ sub interactive_get_maintainers {
1539 } elsif ($sel eq "r") { 1580 } elsif ($sel eq "r") {
1540 bool_invert(\$email_remove_duplicates); 1581 bool_invert(\$email_remove_duplicates);
1541 $rerun = 1; 1582 $rerun = 1;
1583 } elsif ($sel eq "m") {
1584 bool_invert(\$email_use_mailmap);
1585 read_mailmap();
1586 $rerun = 1;
1542 } elsif ($sel eq "k") { 1587 } elsif ($sel eq "k") {
1543 bool_invert(\$keywords); 1588 bool_invert(\$keywords);
1544 $rerun = 1; 1589 $rerun = 1;
@@ -1602,6 +1647,36 @@ sub bool_invert {
1602 } 1647 }
1603} 1648}
1604 1649
1650sub deduplicate_email {
1651 my ($email) = @_;
1652
1653 my $matched = 0;
1654 my ($name, $address) = parse_email($email);
1655 $email = format_email($name, $address, 1);
1656 $email = mailmap_email($email);
1657
1658 return $email if (!$email_remove_duplicates);
1659
1660 ($name, $address) = parse_email($email);
1661
1662 if ($deduplicate_name_hash{lc($name)}) {
1663 $name = $deduplicate_name_hash{lc($name)}->[0];
1664 $address = $deduplicate_name_hash{lc($name)}->[1];
1665 $matched = 1;
1666 } elsif ($deduplicate_address_hash{lc($address)}) {
1667 $name = $deduplicate_address_hash{lc($address)}->[0];
1668 $address = $deduplicate_address_hash{lc($address)}->[1];
1669 $matched = 1;
1670 }
1671 if (!$matched) {
1672 $deduplicate_name_hash{lc($name)} = [ $name, $address ];
1673 $deduplicate_address_hash{lc($address)} = [ $name, $address ];
1674 }
1675 $email = format_email($name, $address, 1);
1676 $email = mailmap_email($email);
1677 return $email;
1678}
1679
1605sub save_commits_by_author { 1680sub save_commits_by_author {
1606 my (@lines) = @_; 1681 my (@lines) = @_;
1607 1682
@@ -1611,20 +1686,8 @@ sub save_commits_by_author {
1611 1686
1612 foreach my $line (@lines) { 1687 foreach my $line (@lines) {
1613 if ($line =~ m/$VCS_cmds{"author_pattern"}/) { 1688 if ($line =~ m/$VCS_cmds{"author_pattern"}/) {
1614 my $matched = 0;
1615 my $author = $1; 1689 my $author = $1;
1616 my ($name, $address) = parse_email($author); 1690 $author = deduplicate_email($author);
1617 foreach my $to (@interactive_to) {
1618 my ($to_name, $to_address) = parse_email($to->[0]);
1619 if ($email_remove_duplicates &&
1620 ((lc($name) eq lc($to_name)) ||
1621 (lc($address) eq lc($to_address)))) {
1622 $author = $to->[0];
1623 $matched = 1;
1624 last;
1625 }
1626 }
1627 $author = format_email($name, $address, 1) if (!$matched);
1628 push(@authors, $author); 1691 push(@authors, $author);
1629 } 1692 }
1630 push(@commits, $1) if ($line =~ m/$VCS_cmds{"commit_pattern"}/); 1693 push(@commits, $1) if ($line =~ m/$VCS_cmds{"commit_pattern"}/);
@@ -1665,19 +1728,7 @@ sub save_commits_by_signer {
1665 my $type = $types[0]; 1728 my $type = $types[0];
1666 my $signer = $signers[0]; 1729 my $signer = $signers[0];
1667 1730
1668 my $matched = 0; 1731 $signer = deduplicate_email($signer);
1669 my ($name, $address) = parse_email($signer);
1670 foreach my $to (@interactive_to) {
1671 my ($to_name, $to_address) = parse_email($to->[0]);
1672 if ($email_remove_duplicates &&
1673 ((lc($name) eq lc($to_name)) ||
1674 (lc($address) eq lc($to_address)))) {
1675 $signer = $to->[0];
1676 $matched = 1;
1677 last;
1678 }
1679 $signer = format_email($name, $address, 1) if (!$matched);
1680 }
1681 1732
1682 my $exists = 0; 1733 my $exists = 0;
1683 foreach my $ref(@{$commit_signer_hash{$signer}}) { 1734 foreach my $ref(@{$commit_signer_hash{$signer}}) {
@@ -1751,6 +1802,11 @@ sub vcs_file_signoffs {
1751 $cmd =~ s/(\$\w+)/$1/eeg; # interpolate $cmd 1802 $cmd =~ s/(\$\w+)/$1/eeg; # interpolate $cmd
1752 1803
1753 ($commits, @signers) = vcs_find_signers($cmd); 1804 ($commits, @signers) = vcs_find_signers($cmd);
1805
1806 foreach my $signer (@signers) {
1807 $signer = deduplicate_email($signer);
1808 }
1809
1754 vcs_assign("commit_signer", $commits, @signers); 1810 vcs_assign("commit_signer", $commits, @signers);
1755} 1811}
1756 1812
@@ -1828,9 +1884,8 @@ sub vcs_file_blame {
1828 foreach my $line (@lines) { 1884 foreach my $line (@lines) {
1829 if ($line =~ m/$VCS_cmds{"author_pattern"}/) { 1885 if ($line =~ m/$VCS_cmds{"author_pattern"}/) {
1830 my $author = $1; 1886 my $author = $1;
1831 my ($name, $address) = parse_email($author); 1887 $author = deduplicate_email($author);
1832 $author = format_email($name, $address, 1); 1888 push(@authors, $author);
1833 push(@authors, $1);
1834 } 1889 }
1835 } 1890 }
1836 1891
@@ -1846,9 +1901,12 @@ sub vcs_file_blame {
1846 $cmd =~ s/(\$\w+)/$1/eeg; #interpolate $cmd 1901 $cmd =~ s/(\$\w+)/$1/eeg; #interpolate $cmd
1847 my @author = vcs_find_author($cmd); 1902 my @author = vcs_find_author($cmd);
1848 next if !@author; 1903 next if !@author;
1904
1905 my $formatted_author = deduplicate_email($author[0]);
1906
1849 my $count = grep(/$commit/, @all_commits); 1907 my $count = grep(/$commit/, @all_commits);
1850 for ($i = 0; $i < $count ; $i++) { 1908 for ($i = 0; $i < $count ; $i++) {
1851 push(@blame_signers, $author[0]); 1909 push(@blame_signers, $formatted_author);
1852 } 1910 }
1853 } 1911 }
1854 } 1912 }
@@ -1856,8 +1914,14 @@ sub vcs_file_blame {
1856 vcs_assign("authored lines", $total_lines, @blame_signers); 1914 vcs_assign("authored lines", $total_lines, @blame_signers);
1857 } 1915 }
1858 } 1916 }
1917 foreach my $signer (@signers) {
1918 $signer = deduplicate_email($signer);
1919 }
1859 vcs_assign("commits", $total_commits, @signers); 1920 vcs_assign("commits", $total_commits, @signers);
1860 } else { 1921 } else {
1922 foreach my $signer (@signers) {
1923 $signer = deduplicate_email($signer);
1924 }
1861 vcs_assign("modified commits", $total_commits, @signers); 1925 vcs_assign("modified commits", $total_commits, @signers);
1862 } 1926 }
1863} 1927}