18c2ecf20Sopenharmony_ci#!/usr/bin/env perl 28c2ecf20Sopenharmony_ci# SPDX-License-Identifier: GPL-2.0 38c2ecf20Sopenharmony_ci# 48c2ecf20Sopenharmony_ci# (c) 2007, Joe Perches <joe@perches.com> 58c2ecf20Sopenharmony_ci# created from checkpatch.pl 68c2ecf20Sopenharmony_ci# 78c2ecf20Sopenharmony_ci# Print selected MAINTAINERS information for 88c2ecf20Sopenharmony_ci# the files modified in a patch or for a file 98c2ecf20Sopenharmony_ci# 108c2ecf20Sopenharmony_ci# usage: perl scripts/get_maintainer.pl [OPTIONS] <patch> 118c2ecf20Sopenharmony_ci# perl scripts/get_maintainer.pl [OPTIONS] -f <file> 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ciuse warnings; 148c2ecf20Sopenharmony_ciuse strict; 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_cimy $P = $0; 178c2ecf20Sopenharmony_cimy $V = '0.26'; 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ciuse Getopt::Long qw(:config no_auto_abbrev); 208c2ecf20Sopenharmony_ciuse Cwd; 218c2ecf20Sopenharmony_ciuse File::Find; 228c2ecf20Sopenharmony_ciuse File::Spec::Functions; 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_cimy $cur_path = fastgetcwd() . '/'; 258c2ecf20Sopenharmony_cimy $lk_path = "./"; 268c2ecf20Sopenharmony_cimy $email = 1; 278c2ecf20Sopenharmony_cimy $email_usename = 1; 288c2ecf20Sopenharmony_cimy $email_maintainer = 1; 298c2ecf20Sopenharmony_cimy $email_reviewer = 1; 308c2ecf20Sopenharmony_cimy $email_fixes = 1; 318c2ecf20Sopenharmony_cimy $email_list = 1; 328c2ecf20Sopenharmony_cimy $email_moderated_list = 1; 338c2ecf20Sopenharmony_cimy $email_subscriber_list = 0; 348c2ecf20Sopenharmony_cimy $email_git_penguin_chiefs = 0; 358c2ecf20Sopenharmony_cimy $email_git = 0; 368c2ecf20Sopenharmony_cimy $email_git_all_signature_types = 0; 378c2ecf20Sopenharmony_cimy $email_git_blame = 0; 388c2ecf20Sopenharmony_cimy $email_git_blame_signatures = 1; 398c2ecf20Sopenharmony_cimy $email_git_fallback = 1; 408c2ecf20Sopenharmony_cimy $email_git_min_signatures = 1; 418c2ecf20Sopenharmony_cimy $email_git_max_maintainers = 5; 428c2ecf20Sopenharmony_cimy $email_git_min_percent = 5; 438c2ecf20Sopenharmony_cimy $email_git_since = "1-year-ago"; 448c2ecf20Sopenharmony_cimy $email_hg_since = "-365"; 458c2ecf20Sopenharmony_cimy $interactive = 0; 468c2ecf20Sopenharmony_cimy $email_remove_duplicates = 1; 478c2ecf20Sopenharmony_cimy $email_use_mailmap = 1; 488c2ecf20Sopenharmony_cimy $output_multiline = 1; 498c2ecf20Sopenharmony_cimy $output_separator = ", "; 508c2ecf20Sopenharmony_cimy $output_roles = 0; 518c2ecf20Sopenharmony_cimy $output_rolestats = 1; 528c2ecf20Sopenharmony_cimy $output_section_maxlen = 50; 538c2ecf20Sopenharmony_cimy $scm = 0; 548c2ecf20Sopenharmony_cimy $tree = 1; 558c2ecf20Sopenharmony_cimy $web = 0; 568c2ecf20Sopenharmony_cimy $subsystem = 0; 578c2ecf20Sopenharmony_cimy $status = 0; 588c2ecf20Sopenharmony_cimy $letters = ""; 598c2ecf20Sopenharmony_cimy $keywords = 1; 608c2ecf20Sopenharmony_cimy $sections = 0; 618c2ecf20Sopenharmony_cimy $email_file_emails = 0; 628c2ecf20Sopenharmony_cimy $from_filename = 0; 638c2ecf20Sopenharmony_cimy $pattern_depth = 0; 648c2ecf20Sopenharmony_cimy $self_test = undef; 658c2ecf20Sopenharmony_cimy $version = 0; 668c2ecf20Sopenharmony_cimy $help = 0; 678c2ecf20Sopenharmony_cimy $find_maintainer_files = 0; 688c2ecf20Sopenharmony_cimy $maintainer_path; 698c2ecf20Sopenharmony_cimy $vcs_used = 0; 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_cimy $exit = 0; 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_cimy @files = (); 748c2ecf20Sopenharmony_cimy @fixes = (); # If a patch description includes Fixes: lines 758c2ecf20Sopenharmony_cimy @range = (); 768c2ecf20Sopenharmony_cimy @keyword_tvi = (); 778c2ecf20Sopenharmony_cimy @file_emails = (); 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_cimy %commit_author_hash; 808c2ecf20Sopenharmony_cimy %commit_signer_hash; 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_cimy @penguin_chief = (); 838c2ecf20Sopenharmony_cipush(@penguin_chief, "Linus Torvalds:torvalds\@linux-foundation.org"); 848c2ecf20Sopenharmony_ci#Andrew wants in on most everything - 2009/01/14 858c2ecf20Sopenharmony_ci#push(@penguin_chief, "Andrew Morton:akpm\@linux-foundation.org"); 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_cimy @penguin_chief_names = (); 888c2ecf20Sopenharmony_ciforeach my $chief (@penguin_chief) { 898c2ecf20Sopenharmony_ci if ($chief =~ m/^(.*):(.*)/) { 908c2ecf20Sopenharmony_ci my $chief_name = $1; 918c2ecf20Sopenharmony_ci my $chief_addr = $2; 928c2ecf20Sopenharmony_ci push(@penguin_chief_names, $chief_name); 938c2ecf20Sopenharmony_ci } 948c2ecf20Sopenharmony_ci} 958c2ecf20Sopenharmony_cimy $penguin_chiefs = "\(" . join("|", @penguin_chief_names) . "\)"; 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci# Signature types of people who are either 988c2ecf20Sopenharmony_ci# a) responsible for the code in question, or 998c2ecf20Sopenharmony_ci# b) familiar enough with it to give relevant feedback 1008c2ecf20Sopenharmony_cimy @signature_tags = (); 1018c2ecf20Sopenharmony_cipush(@signature_tags, "Signed-off-by:"); 1028c2ecf20Sopenharmony_cipush(@signature_tags, "Reviewed-by:"); 1038c2ecf20Sopenharmony_cipush(@signature_tags, "Acked-by:"); 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_cimy $signature_pattern = "\(" . join("|", @signature_tags) . "\)"; 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci# rfc822 email address - preloaded methods go here. 1088c2ecf20Sopenharmony_cimy $rfc822_lwsp = "(?:(?:\\r\\n)?[ \\t])"; 1098c2ecf20Sopenharmony_cimy $rfc822_char = '[\\000-\\377]'; 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci# VCS command support: class-like functions and strings 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_cimy %VCS_cmds; 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_cimy %VCS_cmds_git = ( 1168c2ecf20Sopenharmony_ci "execute_cmd" => \&git_execute_cmd, 1178c2ecf20Sopenharmony_ci "available" => '(which("git") ne "") && (-e ".git")', 1188c2ecf20Sopenharmony_ci "find_signers_cmd" => 1198c2ecf20Sopenharmony_ci "git log --no-color --follow --since=\$email_git_since " . 1208c2ecf20Sopenharmony_ci '--numstat --no-merges ' . 1218c2ecf20Sopenharmony_ci '--format="GitCommit: %H%n' . 1228c2ecf20Sopenharmony_ci 'GitAuthor: %an <%ae>%n' . 1238c2ecf20Sopenharmony_ci 'GitDate: %aD%n' . 1248c2ecf20Sopenharmony_ci 'GitSubject: %s%n' . 1258c2ecf20Sopenharmony_ci '%b%n"' . 1268c2ecf20Sopenharmony_ci " -- \$file", 1278c2ecf20Sopenharmony_ci "find_commit_signers_cmd" => 1288c2ecf20Sopenharmony_ci "git log --no-color " . 1298c2ecf20Sopenharmony_ci '--numstat ' . 1308c2ecf20Sopenharmony_ci '--format="GitCommit: %H%n' . 1318c2ecf20Sopenharmony_ci 'GitAuthor: %an <%ae>%n' . 1328c2ecf20Sopenharmony_ci 'GitDate: %aD%n' . 1338c2ecf20Sopenharmony_ci 'GitSubject: %s%n' . 1348c2ecf20Sopenharmony_ci '%b%n"' . 1358c2ecf20Sopenharmony_ci " -1 \$commit", 1368c2ecf20Sopenharmony_ci "find_commit_author_cmd" => 1378c2ecf20Sopenharmony_ci "git log --no-color " . 1388c2ecf20Sopenharmony_ci '--numstat ' . 1398c2ecf20Sopenharmony_ci '--format="GitCommit: %H%n' . 1408c2ecf20Sopenharmony_ci 'GitAuthor: %an <%ae>%n' . 1418c2ecf20Sopenharmony_ci 'GitDate: %aD%n' . 1428c2ecf20Sopenharmony_ci 'GitSubject: %s%n"' . 1438c2ecf20Sopenharmony_ci " -1 \$commit", 1448c2ecf20Sopenharmony_ci "blame_range_cmd" => "git blame -l -L \$diff_start,+\$diff_length \$file", 1458c2ecf20Sopenharmony_ci "blame_file_cmd" => "git blame -l \$file", 1468c2ecf20Sopenharmony_ci "commit_pattern" => "^GitCommit: ([0-9a-f]{40,40})", 1478c2ecf20Sopenharmony_ci "blame_commit_pattern" => "^([0-9a-f]+) ", 1488c2ecf20Sopenharmony_ci "author_pattern" => "^GitAuthor: (.*)", 1498c2ecf20Sopenharmony_ci "subject_pattern" => "^GitSubject: (.*)", 1508c2ecf20Sopenharmony_ci "stat_pattern" => "^(\\d+)\\t(\\d+)\\t\$file\$", 1518c2ecf20Sopenharmony_ci "file_exists_cmd" => "git ls-files \$file", 1528c2ecf20Sopenharmony_ci "list_files_cmd" => "git ls-files \$file", 1538c2ecf20Sopenharmony_ci); 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_cimy %VCS_cmds_hg = ( 1568c2ecf20Sopenharmony_ci "execute_cmd" => \&hg_execute_cmd, 1578c2ecf20Sopenharmony_ci "available" => '(which("hg") ne "") && (-d ".hg")', 1588c2ecf20Sopenharmony_ci "find_signers_cmd" => 1598c2ecf20Sopenharmony_ci "hg log --date=\$email_hg_since " . 1608c2ecf20Sopenharmony_ci "--template='HgCommit: {node}\\n" . 1618c2ecf20Sopenharmony_ci "HgAuthor: {author}\\n" . 1628c2ecf20Sopenharmony_ci "HgSubject: {desc}\\n'" . 1638c2ecf20Sopenharmony_ci " -- \$file", 1648c2ecf20Sopenharmony_ci "find_commit_signers_cmd" => 1658c2ecf20Sopenharmony_ci "hg log " . 1668c2ecf20Sopenharmony_ci "--template='HgSubject: {desc}\\n'" . 1678c2ecf20Sopenharmony_ci " -r \$commit", 1688c2ecf20Sopenharmony_ci "find_commit_author_cmd" => 1698c2ecf20Sopenharmony_ci "hg log " . 1708c2ecf20Sopenharmony_ci "--template='HgCommit: {node}\\n" . 1718c2ecf20Sopenharmony_ci "HgAuthor: {author}\\n" . 1728c2ecf20Sopenharmony_ci "HgSubject: {desc|firstline}\\n'" . 1738c2ecf20Sopenharmony_ci " -r \$commit", 1748c2ecf20Sopenharmony_ci "blame_range_cmd" => "", # not supported 1758c2ecf20Sopenharmony_ci "blame_file_cmd" => "hg blame -n \$file", 1768c2ecf20Sopenharmony_ci "commit_pattern" => "^HgCommit: ([0-9a-f]{40,40})", 1778c2ecf20Sopenharmony_ci "blame_commit_pattern" => "^([ 0-9a-f]+):", 1788c2ecf20Sopenharmony_ci "author_pattern" => "^HgAuthor: (.*)", 1798c2ecf20Sopenharmony_ci "subject_pattern" => "^HgSubject: (.*)", 1808c2ecf20Sopenharmony_ci "stat_pattern" => "^(\\d+)\t(\\d+)\t\$file\$", 1818c2ecf20Sopenharmony_ci "file_exists_cmd" => "hg files \$file", 1828c2ecf20Sopenharmony_ci "list_files_cmd" => "hg manifest -R \$file", 1838c2ecf20Sopenharmony_ci); 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_cimy $conf = which_conf(".get_maintainer.conf"); 1868c2ecf20Sopenharmony_ciif (-f $conf) { 1878c2ecf20Sopenharmony_ci my @conf_args; 1888c2ecf20Sopenharmony_ci open(my $conffile, '<', "$conf") 1898c2ecf20Sopenharmony_ci or warn "$P: Can't find a readable .get_maintainer.conf file $!\n"; 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci while (<$conffile>) { 1928c2ecf20Sopenharmony_ci my $line = $_; 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci $line =~ s/\s*\n?$//g; 1958c2ecf20Sopenharmony_ci $line =~ s/^\s*//g; 1968c2ecf20Sopenharmony_ci $line =~ s/\s+/ /g; 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci next if ($line =~ m/^\s*#/); 1998c2ecf20Sopenharmony_ci next if ($line =~ m/^\s*$/); 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci my @words = split(" ", $line); 2028c2ecf20Sopenharmony_ci foreach my $word (@words) { 2038c2ecf20Sopenharmony_ci last if ($word =~ m/^#/); 2048c2ecf20Sopenharmony_ci push (@conf_args, $word); 2058c2ecf20Sopenharmony_ci } 2068c2ecf20Sopenharmony_ci } 2078c2ecf20Sopenharmony_ci close($conffile); 2088c2ecf20Sopenharmony_ci unshift(@ARGV, @conf_args) if @conf_args; 2098c2ecf20Sopenharmony_ci} 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_cimy @ignore_emails = (); 2128c2ecf20Sopenharmony_cimy $ignore_file = which_conf(".get_maintainer.ignore"); 2138c2ecf20Sopenharmony_ciif (-f $ignore_file) { 2148c2ecf20Sopenharmony_ci open(my $ignore, '<', "$ignore_file") 2158c2ecf20Sopenharmony_ci or warn "$P: Can't find a readable .get_maintainer.ignore file $!\n"; 2168c2ecf20Sopenharmony_ci while (<$ignore>) { 2178c2ecf20Sopenharmony_ci my $line = $_; 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci $line =~ s/\s*\n?$//; 2208c2ecf20Sopenharmony_ci $line =~ s/^\s*//; 2218c2ecf20Sopenharmony_ci $line =~ s/\s+$//; 2228c2ecf20Sopenharmony_ci $line =~ s/#.*$//; 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci next if ($line =~ m/^\s*$/); 2258c2ecf20Sopenharmony_ci if (rfc822_valid($line)) { 2268c2ecf20Sopenharmony_ci push(@ignore_emails, $line); 2278c2ecf20Sopenharmony_ci } 2288c2ecf20Sopenharmony_ci } 2298c2ecf20Sopenharmony_ci close($ignore); 2308c2ecf20Sopenharmony_ci} 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ciif ($#ARGV > 0) { 2338c2ecf20Sopenharmony_ci foreach (@ARGV) { 2348c2ecf20Sopenharmony_ci if ($_ =~ /^-{1,2}self-test(?:=|$)/) { 2358c2ecf20Sopenharmony_ci die "$P: using --self-test does not allow any other option or argument\n"; 2368c2ecf20Sopenharmony_ci } 2378c2ecf20Sopenharmony_ci } 2388c2ecf20Sopenharmony_ci} 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ciif (!GetOptions( 2418c2ecf20Sopenharmony_ci 'email!' => \$email, 2428c2ecf20Sopenharmony_ci 'git!' => \$email_git, 2438c2ecf20Sopenharmony_ci 'git-all-signature-types!' => \$email_git_all_signature_types, 2448c2ecf20Sopenharmony_ci 'git-blame!' => \$email_git_blame, 2458c2ecf20Sopenharmony_ci 'git-blame-signatures!' => \$email_git_blame_signatures, 2468c2ecf20Sopenharmony_ci 'git-fallback!' => \$email_git_fallback, 2478c2ecf20Sopenharmony_ci 'git-chief-penguins!' => \$email_git_penguin_chiefs, 2488c2ecf20Sopenharmony_ci 'git-min-signatures=i' => \$email_git_min_signatures, 2498c2ecf20Sopenharmony_ci 'git-max-maintainers=i' => \$email_git_max_maintainers, 2508c2ecf20Sopenharmony_ci 'git-min-percent=i' => \$email_git_min_percent, 2518c2ecf20Sopenharmony_ci 'git-since=s' => \$email_git_since, 2528c2ecf20Sopenharmony_ci 'hg-since=s' => \$email_hg_since, 2538c2ecf20Sopenharmony_ci 'i|interactive!' => \$interactive, 2548c2ecf20Sopenharmony_ci 'remove-duplicates!' => \$email_remove_duplicates, 2558c2ecf20Sopenharmony_ci 'mailmap!' => \$email_use_mailmap, 2568c2ecf20Sopenharmony_ci 'm!' => \$email_maintainer, 2578c2ecf20Sopenharmony_ci 'r!' => \$email_reviewer, 2588c2ecf20Sopenharmony_ci 'n!' => \$email_usename, 2598c2ecf20Sopenharmony_ci 'l!' => \$email_list, 2608c2ecf20Sopenharmony_ci 'fixes!' => \$email_fixes, 2618c2ecf20Sopenharmony_ci 'moderated!' => \$email_moderated_list, 2628c2ecf20Sopenharmony_ci 's!' => \$email_subscriber_list, 2638c2ecf20Sopenharmony_ci 'multiline!' => \$output_multiline, 2648c2ecf20Sopenharmony_ci 'roles!' => \$output_roles, 2658c2ecf20Sopenharmony_ci 'rolestats!' => \$output_rolestats, 2668c2ecf20Sopenharmony_ci 'separator=s' => \$output_separator, 2678c2ecf20Sopenharmony_ci 'subsystem!' => \$subsystem, 2688c2ecf20Sopenharmony_ci 'status!' => \$status, 2698c2ecf20Sopenharmony_ci 'scm!' => \$scm, 2708c2ecf20Sopenharmony_ci 'tree!' => \$tree, 2718c2ecf20Sopenharmony_ci 'web!' => \$web, 2728c2ecf20Sopenharmony_ci 'letters=s' => \$letters, 2738c2ecf20Sopenharmony_ci 'pattern-depth=i' => \$pattern_depth, 2748c2ecf20Sopenharmony_ci 'k|keywords!' => \$keywords, 2758c2ecf20Sopenharmony_ci 'sections!' => \$sections, 2768c2ecf20Sopenharmony_ci 'fe|file-emails!' => \$email_file_emails, 2778c2ecf20Sopenharmony_ci 'f|file' => \$from_filename, 2788c2ecf20Sopenharmony_ci 'find-maintainer-files' => \$find_maintainer_files, 2798c2ecf20Sopenharmony_ci 'mpath|maintainer-path=s' => \$maintainer_path, 2808c2ecf20Sopenharmony_ci 'self-test:s' => \$self_test, 2818c2ecf20Sopenharmony_ci 'v|version' => \$version, 2828c2ecf20Sopenharmony_ci 'h|help|usage' => \$help, 2838c2ecf20Sopenharmony_ci )) { 2848c2ecf20Sopenharmony_ci die "$P: invalid argument - use --help if necessary\n"; 2858c2ecf20Sopenharmony_ci} 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ciif ($help != 0) { 2888c2ecf20Sopenharmony_ci usage(); 2898c2ecf20Sopenharmony_ci exit 0; 2908c2ecf20Sopenharmony_ci} 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ciif ($version != 0) { 2938c2ecf20Sopenharmony_ci print("${P} ${V}\n"); 2948c2ecf20Sopenharmony_ci exit 0; 2958c2ecf20Sopenharmony_ci} 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ciif (defined $self_test) { 2988c2ecf20Sopenharmony_ci read_all_maintainer_files(); 2998c2ecf20Sopenharmony_ci self_test(); 3008c2ecf20Sopenharmony_ci exit 0; 3018c2ecf20Sopenharmony_ci} 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ciif (-t STDIN && !@ARGV) { 3048c2ecf20Sopenharmony_ci # We're talking to a terminal, but have no command line arguments. 3058c2ecf20Sopenharmony_ci die "$P: missing patchfile or -f file - use --help if necessary\n"; 3068c2ecf20Sopenharmony_ci} 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci$output_multiline = 0 if ($output_separator ne ", "); 3098c2ecf20Sopenharmony_ci$output_rolestats = 1 if ($interactive); 3108c2ecf20Sopenharmony_ci$output_roles = 1 if ($output_rolestats); 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ciif ($sections || $letters ne "") { 3138c2ecf20Sopenharmony_ci $sections = 1; 3148c2ecf20Sopenharmony_ci $email = 0; 3158c2ecf20Sopenharmony_ci $email_list = 0; 3168c2ecf20Sopenharmony_ci $scm = 0; 3178c2ecf20Sopenharmony_ci $status = 0; 3188c2ecf20Sopenharmony_ci $subsystem = 0; 3198c2ecf20Sopenharmony_ci $web = 0; 3208c2ecf20Sopenharmony_ci $keywords = 0; 3218c2ecf20Sopenharmony_ci $interactive = 0; 3228c2ecf20Sopenharmony_ci} else { 3238c2ecf20Sopenharmony_ci my $selections = $email + $scm + $status + $subsystem + $web; 3248c2ecf20Sopenharmony_ci if ($selections == 0) { 3258c2ecf20Sopenharmony_ci die "$P: Missing required option: email, scm, status, subsystem or web\n"; 3268c2ecf20Sopenharmony_ci } 3278c2ecf20Sopenharmony_ci} 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ciif ($email && 3308c2ecf20Sopenharmony_ci ($email_maintainer + $email_reviewer + 3318c2ecf20Sopenharmony_ci $email_list + $email_subscriber_list + 3328c2ecf20Sopenharmony_ci $email_git + $email_git_penguin_chiefs + $email_git_blame) == 0) { 3338c2ecf20Sopenharmony_ci die "$P: Please select at least 1 email option\n"; 3348c2ecf20Sopenharmony_ci} 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ciif ($tree && !top_of_kernel_tree($lk_path)) { 3378c2ecf20Sopenharmony_ci die "$P: The current directory does not appear to be " 3388c2ecf20Sopenharmony_ci . "a linux kernel source tree.\n"; 3398c2ecf20Sopenharmony_ci} 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci## Read MAINTAINERS for type/value pairs 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_cimy @typevalue = (); 3448c2ecf20Sopenharmony_cimy %keyword_hash; 3458c2ecf20Sopenharmony_cimy @mfiles = (); 3468c2ecf20Sopenharmony_cimy @self_test_info = (); 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_cisub read_maintainer_file { 3498c2ecf20Sopenharmony_ci my ($file) = @_; 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci open (my $maint, '<', "$file") 3528c2ecf20Sopenharmony_ci or die "$P: Can't open MAINTAINERS file '$file': $!\n"; 3538c2ecf20Sopenharmony_ci my $i = 1; 3548c2ecf20Sopenharmony_ci while (<$maint>) { 3558c2ecf20Sopenharmony_ci my $line = $_; 3568c2ecf20Sopenharmony_ci chomp $line; 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci if ($line =~ m/^([A-Z]):\s*(.*)/) { 3598c2ecf20Sopenharmony_ci my $type = $1; 3608c2ecf20Sopenharmony_ci my $value = $2; 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci ##Filename pattern matching 3638c2ecf20Sopenharmony_ci if ($type eq "F" || $type eq "X") { 3648c2ecf20Sopenharmony_ci $value =~ s@\.@\\\.@g; ##Convert . to \. 3658c2ecf20Sopenharmony_ci $value =~ s/\*/\.\*/g; ##Convert * to .* 3668c2ecf20Sopenharmony_ci $value =~ s/\?/\./g; ##Convert ? to . 3678c2ecf20Sopenharmony_ci ##if pattern is a directory and it lacks a trailing slash, add one 3688c2ecf20Sopenharmony_ci if ((-d $value)) { 3698c2ecf20Sopenharmony_ci $value =~ s@([^/])$@$1/@; 3708c2ecf20Sopenharmony_ci } 3718c2ecf20Sopenharmony_ci } elsif ($type eq "K") { 3728c2ecf20Sopenharmony_ci $keyword_hash{@typevalue} = $value; 3738c2ecf20Sopenharmony_ci } 3748c2ecf20Sopenharmony_ci push(@typevalue, "$type:$value"); 3758c2ecf20Sopenharmony_ci } elsif (!(/^\s*$/ || /^\s*\#/)) { 3768c2ecf20Sopenharmony_ci push(@typevalue, $line); 3778c2ecf20Sopenharmony_ci } 3788c2ecf20Sopenharmony_ci if (defined $self_test) { 3798c2ecf20Sopenharmony_ci push(@self_test_info, {file=>$file, linenr=>$i, line=>$line}); 3808c2ecf20Sopenharmony_ci } 3818c2ecf20Sopenharmony_ci $i++; 3828c2ecf20Sopenharmony_ci } 3838c2ecf20Sopenharmony_ci close($maint); 3848c2ecf20Sopenharmony_ci} 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_cisub find_is_maintainer_file { 3878c2ecf20Sopenharmony_ci my ($file) = $_; 3888c2ecf20Sopenharmony_ci return if ($file !~ m@/MAINTAINERS$@); 3898c2ecf20Sopenharmony_ci $file = $File::Find::name; 3908c2ecf20Sopenharmony_ci return if (! -f $file); 3918c2ecf20Sopenharmony_ci push(@mfiles, $file); 3928c2ecf20Sopenharmony_ci} 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_cisub find_ignore_git { 3958c2ecf20Sopenharmony_ci return grep { $_ !~ /^\.git$/; } @_; 3968c2ecf20Sopenharmony_ci} 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ciread_all_maintainer_files(); 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_cisub read_all_maintainer_files { 4018c2ecf20Sopenharmony_ci my $path = "${lk_path}MAINTAINERS"; 4028c2ecf20Sopenharmony_ci if (defined $maintainer_path) { 4038c2ecf20Sopenharmony_ci $path = $maintainer_path; 4048c2ecf20Sopenharmony_ci # Perl Cookbook tilde expansion if necessary 4058c2ecf20Sopenharmony_ci $path =~ s@^~([^/]*)@ $1 ? (getpwnam($1))[7] : ( $ENV{HOME} || $ENV{LOGDIR} || (getpwuid($<))[7])@ex; 4068c2ecf20Sopenharmony_ci } 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ci if (-d $path) { 4098c2ecf20Sopenharmony_ci $path .= '/' if ($path !~ m@/$@); 4108c2ecf20Sopenharmony_ci if ($find_maintainer_files) { 4118c2ecf20Sopenharmony_ci find( { wanted => \&find_is_maintainer_file, 4128c2ecf20Sopenharmony_ci preprocess => \&find_ignore_git, 4138c2ecf20Sopenharmony_ci no_chdir => 1, 4148c2ecf20Sopenharmony_ci }, "$path"); 4158c2ecf20Sopenharmony_ci } else { 4168c2ecf20Sopenharmony_ci opendir(DIR, "$path") or die $!; 4178c2ecf20Sopenharmony_ci my @files = readdir(DIR); 4188c2ecf20Sopenharmony_ci closedir(DIR); 4198c2ecf20Sopenharmony_ci foreach my $file (@files) { 4208c2ecf20Sopenharmony_ci push(@mfiles, "$path$file") if ($file !~ /^\./); 4218c2ecf20Sopenharmony_ci } 4228c2ecf20Sopenharmony_ci } 4238c2ecf20Sopenharmony_ci } elsif (-f "$path") { 4248c2ecf20Sopenharmony_ci push(@mfiles, "$path"); 4258c2ecf20Sopenharmony_ci } else { 4268c2ecf20Sopenharmony_ci die "$P: MAINTAINER file not found '$path'\n"; 4278c2ecf20Sopenharmony_ci } 4288c2ecf20Sopenharmony_ci die "$P: No MAINTAINER files found in '$path'\n" if (scalar(@mfiles) == 0); 4298c2ecf20Sopenharmony_ci foreach my $file (@mfiles) { 4308c2ecf20Sopenharmony_ci read_maintainer_file("$file"); 4318c2ecf20Sopenharmony_ci } 4328c2ecf20Sopenharmony_ci} 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_cisub maintainers_in_file { 4358c2ecf20Sopenharmony_ci my ($file) = @_; 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_ci return if ($file =~ m@\bMAINTAINERS$@); 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_ci if (-f $file && ($email_file_emails || $file =~ /\.yaml$/)) { 4408c2ecf20Sopenharmony_ci open(my $f, '<', $file) 4418c2ecf20Sopenharmony_ci or die "$P: Can't open $file: $!\n"; 4428c2ecf20Sopenharmony_ci my $text = do { local($/) ; <$f> }; 4438c2ecf20Sopenharmony_ci close($f); 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_ci my @poss_addr = $text =~ m$[A-Za-zÀ-ÿ\"\' \,\.\+-]*\s*[\,]*\s*[\(\<\{]{0,1}[A-Za-z0-9_\.\+-]+\@[A-Za-z0-9\.-]+\.[A-Za-z0-9]+[\)\>\}]{0,1}$g; 4468c2ecf20Sopenharmony_ci push(@file_emails, clean_file_emails(@poss_addr)); 4478c2ecf20Sopenharmony_ci } 4488c2ecf20Sopenharmony_ci} 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_ci# 4518c2ecf20Sopenharmony_ci# Read mail address map 4528c2ecf20Sopenharmony_ci# 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_cimy $mailmap; 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ciread_mailmap(); 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_cisub read_mailmap { 4598c2ecf20Sopenharmony_ci $mailmap = { 4608c2ecf20Sopenharmony_ci names => {}, 4618c2ecf20Sopenharmony_ci addresses => {} 4628c2ecf20Sopenharmony_ci }; 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ci return if (!$email_use_mailmap || !(-f "${lk_path}.mailmap")); 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_ci open(my $mailmap_file, '<', "${lk_path}.mailmap") 4678c2ecf20Sopenharmony_ci or warn "$P: Can't open .mailmap: $!\n"; 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_ci while (<$mailmap_file>) { 4708c2ecf20Sopenharmony_ci s/#.*$//; #strip comments 4718c2ecf20Sopenharmony_ci s/^\s+|\s+$//g; #trim 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_ci next if (/^\s*$/); #skip empty lines 4748c2ecf20Sopenharmony_ci #entries have one of the following formats: 4758c2ecf20Sopenharmony_ci # name1 <mail1> 4768c2ecf20Sopenharmony_ci # <mail1> <mail2> 4778c2ecf20Sopenharmony_ci # name1 <mail1> <mail2> 4788c2ecf20Sopenharmony_ci # name1 <mail1> name2 <mail2> 4798c2ecf20Sopenharmony_ci # (see man git-shortlog) 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_ci if (/^([^<]+)<([^>]+)>$/) { 4828c2ecf20Sopenharmony_ci my $real_name = $1; 4838c2ecf20Sopenharmony_ci my $address = $2; 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ci $real_name =~ s/\s+$//; 4868c2ecf20Sopenharmony_ci ($real_name, $address) = parse_email("$real_name <$address>"); 4878c2ecf20Sopenharmony_ci $mailmap->{names}->{$address} = $real_name; 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_ci } elsif (/^<([^>]+)>\s*<([^>]+)>$/) { 4908c2ecf20Sopenharmony_ci my $real_address = $1; 4918c2ecf20Sopenharmony_ci my $wrong_address = $2; 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci $mailmap->{addresses}->{$wrong_address} = $real_address; 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_ci } elsif (/^(.+)<([^>]+)>\s*<([^>]+)>$/) { 4968c2ecf20Sopenharmony_ci my $real_name = $1; 4978c2ecf20Sopenharmony_ci my $real_address = $2; 4988c2ecf20Sopenharmony_ci my $wrong_address = $3; 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_ci $real_name =~ s/\s+$//; 5018c2ecf20Sopenharmony_ci ($real_name, $real_address) = 5028c2ecf20Sopenharmony_ci parse_email("$real_name <$real_address>"); 5038c2ecf20Sopenharmony_ci $mailmap->{names}->{$wrong_address} = $real_name; 5048c2ecf20Sopenharmony_ci $mailmap->{addresses}->{$wrong_address} = $real_address; 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_ci } elsif (/^(.+)<([^>]+)>\s*(.+)\s*<([^>]+)>$/) { 5078c2ecf20Sopenharmony_ci my $real_name = $1; 5088c2ecf20Sopenharmony_ci my $real_address = $2; 5098c2ecf20Sopenharmony_ci my $wrong_name = $3; 5108c2ecf20Sopenharmony_ci my $wrong_address = $4; 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_ci $real_name =~ s/\s+$//; 5138c2ecf20Sopenharmony_ci ($real_name, $real_address) = 5148c2ecf20Sopenharmony_ci parse_email("$real_name <$real_address>"); 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_ci $wrong_name =~ s/\s+$//; 5178c2ecf20Sopenharmony_ci ($wrong_name, $wrong_address) = 5188c2ecf20Sopenharmony_ci parse_email("$wrong_name <$wrong_address>"); 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_ci my $wrong_email = format_email($wrong_name, $wrong_address, 1); 5218c2ecf20Sopenharmony_ci $mailmap->{names}->{$wrong_email} = $real_name; 5228c2ecf20Sopenharmony_ci $mailmap->{addresses}->{$wrong_email} = $real_address; 5238c2ecf20Sopenharmony_ci } 5248c2ecf20Sopenharmony_ci } 5258c2ecf20Sopenharmony_ci close($mailmap_file); 5268c2ecf20Sopenharmony_ci} 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_ci## use the filenames on the command line or find the filenames in the patchfiles 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_ciif (!@ARGV) { 5318c2ecf20Sopenharmony_ci push(@ARGV, "&STDIN"); 5328c2ecf20Sopenharmony_ci} 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_ciforeach my $file (@ARGV) { 5358c2ecf20Sopenharmony_ci if ($file ne "&STDIN") { 5368c2ecf20Sopenharmony_ci $file = canonpath($file); 5378c2ecf20Sopenharmony_ci ##if $file is a directory and it lacks a trailing slash, add one 5388c2ecf20Sopenharmony_ci if ((-d $file)) { 5398c2ecf20Sopenharmony_ci $file =~ s@([^/])$@$1/@; 5408c2ecf20Sopenharmony_ci } elsif (!(-f $file)) { 5418c2ecf20Sopenharmony_ci die "$P: file '${file}' not found\n"; 5428c2ecf20Sopenharmony_ci } 5438c2ecf20Sopenharmony_ci } 5448c2ecf20Sopenharmony_ci if ($from_filename && (vcs_exists() && !vcs_file_exists($file))) { 5458c2ecf20Sopenharmony_ci warn "$P: file '$file' not found in version control $!\n"; 5468c2ecf20Sopenharmony_ci } 5478c2ecf20Sopenharmony_ci if ($from_filename || ($file ne "&STDIN" && vcs_file_exists($file))) { 5488c2ecf20Sopenharmony_ci $file =~ s/^\Q${cur_path}\E//; #strip any absolute path 5498c2ecf20Sopenharmony_ci $file =~ s/^\Q${lk_path}\E//; #or the path to the lk tree 5508c2ecf20Sopenharmony_ci push(@files, $file); 5518c2ecf20Sopenharmony_ci if ($file ne "MAINTAINERS" && -f $file && $keywords) { 5528c2ecf20Sopenharmony_ci open(my $f, '<', $file) 5538c2ecf20Sopenharmony_ci or die "$P: Can't open $file: $!\n"; 5548c2ecf20Sopenharmony_ci my $text = do { local($/) ; <$f> }; 5558c2ecf20Sopenharmony_ci close($f); 5568c2ecf20Sopenharmony_ci if ($keywords) { 5578c2ecf20Sopenharmony_ci foreach my $line (keys %keyword_hash) { 5588c2ecf20Sopenharmony_ci if ($text =~ m/$keyword_hash{$line}/x) { 5598c2ecf20Sopenharmony_ci push(@keyword_tvi, $line); 5608c2ecf20Sopenharmony_ci } 5618c2ecf20Sopenharmony_ci } 5628c2ecf20Sopenharmony_ci } 5638c2ecf20Sopenharmony_ci } 5648c2ecf20Sopenharmony_ci } else { 5658c2ecf20Sopenharmony_ci my $file_cnt = @files; 5668c2ecf20Sopenharmony_ci my $lastfile; 5678c2ecf20Sopenharmony_ci 5688c2ecf20Sopenharmony_ci open(my $patch, "< $file") 5698c2ecf20Sopenharmony_ci or die "$P: Can't open $file: $!\n"; 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_ci # We can check arbitrary information before the patch 5728c2ecf20Sopenharmony_ci # like the commit message, mail headers, etc... 5738c2ecf20Sopenharmony_ci # This allows us to match arbitrary keywords against any part 5748c2ecf20Sopenharmony_ci # of a git format-patch generated file (subject tags, etc...) 5758c2ecf20Sopenharmony_ci 5768c2ecf20Sopenharmony_ci my $patch_prefix = ""; #Parsing the intro 5778c2ecf20Sopenharmony_ci 5788c2ecf20Sopenharmony_ci while (<$patch>) { 5798c2ecf20Sopenharmony_ci my $patch_line = $_; 5808c2ecf20Sopenharmony_ci if (m/^ mode change [0-7]+ => [0-7]+ (\S+)\s*$/) { 5818c2ecf20Sopenharmony_ci my $filename = $1; 5828c2ecf20Sopenharmony_ci push(@files, $filename); 5838c2ecf20Sopenharmony_ci } elsif (m/^rename (?:from|to) (\S+)\s*$/) { 5848c2ecf20Sopenharmony_ci my $filename = $1; 5858c2ecf20Sopenharmony_ci push(@files, $filename); 5868c2ecf20Sopenharmony_ci } elsif (m/^diff --git a\/(\S+) b\/(\S+)\s*$/) { 5878c2ecf20Sopenharmony_ci my $filename1 = $1; 5888c2ecf20Sopenharmony_ci my $filename2 = $2; 5898c2ecf20Sopenharmony_ci push(@files, $filename1); 5908c2ecf20Sopenharmony_ci push(@files, $filename2); 5918c2ecf20Sopenharmony_ci } elsif (m/^Fixes:\s+([0-9a-fA-F]{6,40})/) { 5928c2ecf20Sopenharmony_ci push(@fixes, $1) if ($email_fixes); 5938c2ecf20Sopenharmony_ci } elsif (m/^\+\+\+\s+(\S+)/ or m/^---\s+(\S+)/) { 5948c2ecf20Sopenharmony_ci my $filename = $1; 5958c2ecf20Sopenharmony_ci $filename =~ s@^[^/]*/@@; 5968c2ecf20Sopenharmony_ci $filename =~ s@\n@@; 5978c2ecf20Sopenharmony_ci $lastfile = $filename; 5988c2ecf20Sopenharmony_ci push(@files, $filename); 5998c2ecf20Sopenharmony_ci $patch_prefix = "^[+-].*"; #Now parsing the actual patch 6008c2ecf20Sopenharmony_ci } elsif (m/^\@\@ -(\d+),(\d+)/) { 6018c2ecf20Sopenharmony_ci if ($email_git_blame) { 6028c2ecf20Sopenharmony_ci push(@range, "$lastfile:$1:$2"); 6038c2ecf20Sopenharmony_ci } 6048c2ecf20Sopenharmony_ci } elsif ($keywords) { 6058c2ecf20Sopenharmony_ci foreach my $line (keys %keyword_hash) { 6068c2ecf20Sopenharmony_ci if ($patch_line =~ m/${patch_prefix}$keyword_hash{$line}/x) { 6078c2ecf20Sopenharmony_ci push(@keyword_tvi, $line); 6088c2ecf20Sopenharmony_ci } 6098c2ecf20Sopenharmony_ci } 6108c2ecf20Sopenharmony_ci } 6118c2ecf20Sopenharmony_ci } 6128c2ecf20Sopenharmony_ci close($patch); 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_ci if ($file_cnt == @files) { 6158c2ecf20Sopenharmony_ci warn "$P: file '${file}' doesn't appear to be a patch. " 6168c2ecf20Sopenharmony_ci . "Add -f to options?\n"; 6178c2ecf20Sopenharmony_ci } 6188c2ecf20Sopenharmony_ci @files = sort_and_uniq(@files); 6198c2ecf20Sopenharmony_ci } 6208c2ecf20Sopenharmony_ci} 6218c2ecf20Sopenharmony_ci 6228c2ecf20Sopenharmony_ci@file_emails = uniq(@file_emails); 6238c2ecf20Sopenharmony_ci@fixes = uniq(@fixes); 6248c2ecf20Sopenharmony_ci 6258c2ecf20Sopenharmony_cimy %email_hash_name; 6268c2ecf20Sopenharmony_cimy %email_hash_address; 6278c2ecf20Sopenharmony_cimy @email_to = (); 6288c2ecf20Sopenharmony_cimy %hash_list_to; 6298c2ecf20Sopenharmony_cimy @list_to = (); 6308c2ecf20Sopenharmony_cimy @scm = (); 6318c2ecf20Sopenharmony_cimy @web = (); 6328c2ecf20Sopenharmony_cimy @subsystem = (); 6338c2ecf20Sopenharmony_cimy @status = (); 6348c2ecf20Sopenharmony_cimy %deduplicate_name_hash = (); 6358c2ecf20Sopenharmony_cimy %deduplicate_address_hash = (); 6368c2ecf20Sopenharmony_ci 6378c2ecf20Sopenharmony_cimy @maintainers = get_maintainers(); 6388c2ecf20Sopenharmony_ciif (@maintainers) { 6398c2ecf20Sopenharmony_ci @maintainers = merge_email(@maintainers); 6408c2ecf20Sopenharmony_ci output(@maintainers); 6418c2ecf20Sopenharmony_ci} 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_ciif ($scm) { 6448c2ecf20Sopenharmony_ci @scm = uniq(@scm); 6458c2ecf20Sopenharmony_ci output(@scm); 6468c2ecf20Sopenharmony_ci} 6478c2ecf20Sopenharmony_ci 6488c2ecf20Sopenharmony_ciif ($status) { 6498c2ecf20Sopenharmony_ci @status = uniq(@status); 6508c2ecf20Sopenharmony_ci output(@status); 6518c2ecf20Sopenharmony_ci} 6528c2ecf20Sopenharmony_ci 6538c2ecf20Sopenharmony_ciif ($subsystem) { 6548c2ecf20Sopenharmony_ci @subsystem = uniq(@subsystem); 6558c2ecf20Sopenharmony_ci output(@subsystem); 6568c2ecf20Sopenharmony_ci} 6578c2ecf20Sopenharmony_ci 6588c2ecf20Sopenharmony_ciif ($web) { 6598c2ecf20Sopenharmony_ci @web = uniq(@web); 6608c2ecf20Sopenharmony_ci output(@web); 6618c2ecf20Sopenharmony_ci} 6628c2ecf20Sopenharmony_ci 6638c2ecf20Sopenharmony_ciexit($exit); 6648c2ecf20Sopenharmony_ci 6658c2ecf20Sopenharmony_cisub self_test { 6668c2ecf20Sopenharmony_ci my @lsfiles = (); 6678c2ecf20Sopenharmony_ci my @good_links = (); 6688c2ecf20Sopenharmony_ci my @bad_links = (); 6698c2ecf20Sopenharmony_ci my @section_headers = (); 6708c2ecf20Sopenharmony_ci my $index = 0; 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_ci @lsfiles = vcs_list_files($lk_path); 6738c2ecf20Sopenharmony_ci 6748c2ecf20Sopenharmony_ci for my $x (@self_test_info) { 6758c2ecf20Sopenharmony_ci $index++; 6768c2ecf20Sopenharmony_ci 6778c2ecf20Sopenharmony_ci ## Section header duplication and missing section content 6788c2ecf20Sopenharmony_ci if (($self_test eq "" || $self_test =~ /\bsections\b/) && 6798c2ecf20Sopenharmony_ci $x->{line} =~ /^\S[^:]/ && 6808c2ecf20Sopenharmony_ci defined $self_test_info[$index] && 6818c2ecf20Sopenharmony_ci $self_test_info[$index]->{line} =~ /^([A-Z]):\s*\S/) { 6828c2ecf20Sopenharmony_ci my $has_S = 0; 6838c2ecf20Sopenharmony_ci my $has_F = 0; 6848c2ecf20Sopenharmony_ci my $has_ML = 0; 6858c2ecf20Sopenharmony_ci my $status = ""; 6868c2ecf20Sopenharmony_ci if (grep(m@^\Q$x->{line}\E@, @section_headers)) { 6878c2ecf20Sopenharmony_ci print("$x->{file}:$x->{linenr}: warning: duplicate section header\t$x->{line}\n"); 6888c2ecf20Sopenharmony_ci } else { 6898c2ecf20Sopenharmony_ci push(@section_headers, $x->{line}); 6908c2ecf20Sopenharmony_ci } 6918c2ecf20Sopenharmony_ci my $nextline = $index; 6928c2ecf20Sopenharmony_ci while (defined $self_test_info[$nextline] && 6938c2ecf20Sopenharmony_ci $self_test_info[$nextline]->{line} =~ /^([A-Z]):\s*(\S.*)/) { 6948c2ecf20Sopenharmony_ci my $type = $1; 6958c2ecf20Sopenharmony_ci my $value = $2; 6968c2ecf20Sopenharmony_ci if ($type eq "S") { 6978c2ecf20Sopenharmony_ci $has_S = 1; 6988c2ecf20Sopenharmony_ci $status = $value; 6998c2ecf20Sopenharmony_ci } elsif ($type eq "F" || $type eq "N") { 7008c2ecf20Sopenharmony_ci $has_F = 1; 7018c2ecf20Sopenharmony_ci } elsif ($type eq "M" || $type eq "R" || $type eq "L") { 7028c2ecf20Sopenharmony_ci $has_ML = 1; 7038c2ecf20Sopenharmony_ci } 7048c2ecf20Sopenharmony_ci $nextline++; 7058c2ecf20Sopenharmony_ci } 7068c2ecf20Sopenharmony_ci if (!$has_ML && $status !~ /orphan|obsolete/i) { 7078c2ecf20Sopenharmony_ci print("$x->{file}:$x->{linenr}: warning: section without email address\t$x->{line}\n"); 7088c2ecf20Sopenharmony_ci } 7098c2ecf20Sopenharmony_ci if (!$has_S) { 7108c2ecf20Sopenharmony_ci print("$x->{file}:$x->{linenr}: warning: section without status \t$x->{line}\n"); 7118c2ecf20Sopenharmony_ci } 7128c2ecf20Sopenharmony_ci if (!$has_F) { 7138c2ecf20Sopenharmony_ci print("$x->{file}:$x->{linenr}: warning: section without file pattern\t$x->{line}\n"); 7148c2ecf20Sopenharmony_ci } 7158c2ecf20Sopenharmony_ci } 7168c2ecf20Sopenharmony_ci 7178c2ecf20Sopenharmony_ci next if ($x->{line} !~ /^([A-Z]):\s*(.*)/); 7188c2ecf20Sopenharmony_ci 7198c2ecf20Sopenharmony_ci my $type = $1; 7208c2ecf20Sopenharmony_ci my $value = $2; 7218c2ecf20Sopenharmony_ci 7228c2ecf20Sopenharmony_ci ## Filename pattern matching 7238c2ecf20Sopenharmony_ci if (($type eq "F" || $type eq "X") && 7248c2ecf20Sopenharmony_ci ($self_test eq "" || $self_test =~ /\bpatterns\b/)) { 7258c2ecf20Sopenharmony_ci $value =~ s@\.@\\\.@g; ##Convert . to \. 7268c2ecf20Sopenharmony_ci $value =~ s/\*/\.\*/g; ##Convert * to .* 7278c2ecf20Sopenharmony_ci $value =~ s/\?/\./g; ##Convert ? to . 7288c2ecf20Sopenharmony_ci ##if pattern is a directory and it lacks a trailing slash, add one 7298c2ecf20Sopenharmony_ci if ((-d $value)) { 7308c2ecf20Sopenharmony_ci $value =~ s@([^/])$@$1/@; 7318c2ecf20Sopenharmony_ci } 7328c2ecf20Sopenharmony_ci if (!grep(m@^$value@, @lsfiles)) { 7338c2ecf20Sopenharmony_ci print("$x->{file}:$x->{linenr}: warning: no file matches\t$x->{line}\n"); 7348c2ecf20Sopenharmony_ci } 7358c2ecf20Sopenharmony_ci 7368c2ecf20Sopenharmony_ci ## Link reachability 7378c2ecf20Sopenharmony_ci } elsif (($type eq "W" || $type eq "Q" || $type eq "B") && 7388c2ecf20Sopenharmony_ci $value =~ /^https?:/ && 7398c2ecf20Sopenharmony_ci ($self_test eq "" || $self_test =~ /\blinks\b/)) { 7408c2ecf20Sopenharmony_ci next if (grep(m@^\Q$value\E$@, @good_links)); 7418c2ecf20Sopenharmony_ci my $isbad = 0; 7428c2ecf20Sopenharmony_ci if (grep(m@^\Q$value\E$@, @bad_links)) { 7438c2ecf20Sopenharmony_ci $isbad = 1; 7448c2ecf20Sopenharmony_ci } else { 7458c2ecf20Sopenharmony_ci my $output = `wget --spider -q --no-check-certificate --timeout 10 --tries 1 $value`; 7468c2ecf20Sopenharmony_ci if ($? == 0) { 7478c2ecf20Sopenharmony_ci push(@good_links, $value); 7488c2ecf20Sopenharmony_ci } else { 7498c2ecf20Sopenharmony_ci push(@bad_links, $value); 7508c2ecf20Sopenharmony_ci $isbad = 1; 7518c2ecf20Sopenharmony_ci } 7528c2ecf20Sopenharmony_ci } 7538c2ecf20Sopenharmony_ci if ($isbad) { 7548c2ecf20Sopenharmony_ci print("$x->{file}:$x->{linenr}: warning: possible bad link\t$x->{line}\n"); 7558c2ecf20Sopenharmony_ci } 7568c2ecf20Sopenharmony_ci 7578c2ecf20Sopenharmony_ci ## SCM reachability 7588c2ecf20Sopenharmony_ci } elsif ($type eq "T" && 7598c2ecf20Sopenharmony_ci ($self_test eq "" || $self_test =~ /\bscm\b/)) { 7608c2ecf20Sopenharmony_ci next if (grep(m@^\Q$value\E$@, @good_links)); 7618c2ecf20Sopenharmony_ci my $isbad = 0; 7628c2ecf20Sopenharmony_ci if (grep(m@^\Q$value\E$@, @bad_links)) { 7638c2ecf20Sopenharmony_ci $isbad = 1; 7648c2ecf20Sopenharmony_ci } elsif ($value !~ /^(?:git|quilt|hg)\s+\S/) { 7658c2ecf20Sopenharmony_ci print("$x->{file}:$x->{linenr}: warning: malformed entry\t$x->{line}\n"); 7668c2ecf20Sopenharmony_ci } elsif ($value =~ /^git\s+(\S+)(\s+([^\(]+\S+))?/) { 7678c2ecf20Sopenharmony_ci my $url = $1; 7688c2ecf20Sopenharmony_ci my $branch = ""; 7698c2ecf20Sopenharmony_ci $branch = $3 if $3; 7708c2ecf20Sopenharmony_ci my $output = `git ls-remote --exit-code -h "$url" $branch > /dev/null 2>&1`; 7718c2ecf20Sopenharmony_ci if ($? == 0) { 7728c2ecf20Sopenharmony_ci push(@good_links, $value); 7738c2ecf20Sopenharmony_ci } else { 7748c2ecf20Sopenharmony_ci push(@bad_links, $value); 7758c2ecf20Sopenharmony_ci $isbad = 1; 7768c2ecf20Sopenharmony_ci } 7778c2ecf20Sopenharmony_ci } elsif ($value =~ /^(?:quilt|hg)\s+(https?:\S+)/) { 7788c2ecf20Sopenharmony_ci my $url = $1; 7798c2ecf20Sopenharmony_ci my $output = `wget --spider -q --no-check-certificate --timeout 10 --tries 1 $url`; 7808c2ecf20Sopenharmony_ci if ($? == 0) { 7818c2ecf20Sopenharmony_ci push(@good_links, $value); 7828c2ecf20Sopenharmony_ci } else { 7838c2ecf20Sopenharmony_ci push(@bad_links, $value); 7848c2ecf20Sopenharmony_ci $isbad = 1; 7858c2ecf20Sopenharmony_ci } 7868c2ecf20Sopenharmony_ci } 7878c2ecf20Sopenharmony_ci if ($isbad) { 7888c2ecf20Sopenharmony_ci print("$x->{file}:$x->{linenr}: warning: possible bad link\t$x->{line}\n"); 7898c2ecf20Sopenharmony_ci } 7908c2ecf20Sopenharmony_ci } 7918c2ecf20Sopenharmony_ci } 7928c2ecf20Sopenharmony_ci} 7938c2ecf20Sopenharmony_ci 7948c2ecf20Sopenharmony_cisub ignore_email_address { 7958c2ecf20Sopenharmony_ci my ($address) = @_; 7968c2ecf20Sopenharmony_ci 7978c2ecf20Sopenharmony_ci foreach my $ignore (@ignore_emails) { 7988c2ecf20Sopenharmony_ci return 1 if ($ignore eq $address); 7998c2ecf20Sopenharmony_ci } 8008c2ecf20Sopenharmony_ci 8018c2ecf20Sopenharmony_ci return 0; 8028c2ecf20Sopenharmony_ci} 8038c2ecf20Sopenharmony_ci 8048c2ecf20Sopenharmony_cisub range_is_maintained { 8058c2ecf20Sopenharmony_ci my ($start, $end) = @_; 8068c2ecf20Sopenharmony_ci 8078c2ecf20Sopenharmony_ci for (my $i = $start; $i < $end; $i++) { 8088c2ecf20Sopenharmony_ci my $line = $typevalue[$i]; 8098c2ecf20Sopenharmony_ci if ($line =~ m/^([A-Z]):\s*(.*)/) { 8108c2ecf20Sopenharmony_ci my $type = $1; 8118c2ecf20Sopenharmony_ci my $value = $2; 8128c2ecf20Sopenharmony_ci if ($type eq 'S') { 8138c2ecf20Sopenharmony_ci if ($value =~ /(maintain|support)/i) { 8148c2ecf20Sopenharmony_ci return 1; 8158c2ecf20Sopenharmony_ci } 8168c2ecf20Sopenharmony_ci } 8178c2ecf20Sopenharmony_ci } 8188c2ecf20Sopenharmony_ci } 8198c2ecf20Sopenharmony_ci return 0; 8208c2ecf20Sopenharmony_ci} 8218c2ecf20Sopenharmony_ci 8228c2ecf20Sopenharmony_cisub range_has_maintainer { 8238c2ecf20Sopenharmony_ci my ($start, $end) = @_; 8248c2ecf20Sopenharmony_ci 8258c2ecf20Sopenharmony_ci for (my $i = $start; $i < $end; $i++) { 8268c2ecf20Sopenharmony_ci my $line = $typevalue[$i]; 8278c2ecf20Sopenharmony_ci if ($line =~ m/^([A-Z]):\s*(.*)/) { 8288c2ecf20Sopenharmony_ci my $type = $1; 8298c2ecf20Sopenharmony_ci my $value = $2; 8308c2ecf20Sopenharmony_ci if ($type eq 'M') { 8318c2ecf20Sopenharmony_ci return 1; 8328c2ecf20Sopenharmony_ci } 8338c2ecf20Sopenharmony_ci } 8348c2ecf20Sopenharmony_ci } 8358c2ecf20Sopenharmony_ci return 0; 8368c2ecf20Sopenharmony_ci} 8378c2ecf20Sopenharmony_ci 8388c2ecf20Sopenharmony_cisub get_maintainers { 8398c2ecf20Sopenharmony_ci %email_hash_name = (); 8408c2ecf20Sopenharmony_ci %email_hash_address = (); 8418c2ecf20Sopenharmony_ci %commit_author_hash = (); 8428c2ecf20Sopenharmony_ci %commit_signer_hash = (); 8438c2ecf20Sopenharmony_ci @email_to = (); 8448c2ecf20Sopenharmony_ci %hash_list_to = (); 8458c2ecf20Sopenharmony_ci @list_to = (); 8468c2ecf20Sopenharmony_ci @scm = (); 8478c2ecf20Sopenharmony_ci @web = (); 8488c2ecf20Sopenharmony_ci @subsystem = (); 8498c2ecf20Sopenharmony_ci @status = (); 8508c2ecf20Sopenharmony_ci %deduplicate_name_hash = (); 8518c2ecf20Sopenharmony_ci %deduplicate_address_hash = (); 8528c2ecf20Sopenharmony_ci if ($email_git_all_signature_types) { 8538c2ecf20Sopenharmony_ci $signature_pattern = "(.+?)[Bb][Yy]:"; 8548c2ecf20Sopenharmony_ci } else { 8558c2ecf20Sopenharmony_ci $signature_pattern = "\(" . join("|", @signature_tags) . "\)"; 8568c2ecf20Sopenharmony_ci } 8578c2ecf20Sopenharmony_ci 8588c2ecf20Sopenharmony_ci # Find responsible parties 8598c2ecf20Sopenharmony_ci 8608c2ecf20Sopenharmony_ci my %exact_pattern_match_hash = (); 8618c2ecf20Sopenharmony_ci 8628c2ecf20Sopenharmony_ci foreach my $file (@files) { 8638c2ecf20Sopenharmony_ci 8648c2ecf20Sopenharmony_ci my %hash; 8658c2ecf20Sopenharmony_ci my $tvi = find_first_section(); 8668c2ecf20Sopenharmony_ci while ($tvi < @typevalue) { 8678c2ecf20Sopenharmony_ci my $start = find_starting_index($tvi); 8688c2ecf20Sopenharmony_ci my $end = find_ending_index($tvi); 8698c2ecf20Sopenharmony_ci my $exclude = 0; 8708c2ecf20Sopenharmony_ci my $i; 8718c2ecf20Sopenharmony_ci 8728c2ecf20Sopenharmony_ci #Do not match excluded file patterns 8738c2ecf20Sopenharmony_ci 8748c2ecf20Sopenharmony_ci for ($i = $start; $i < $end; $i++) { 8758c2ecf20Sopenharmony_ci my $line = $typevalue[$i]; 8768c2ecf20Sopenharmony_ci if ($line =~ m/^([A-Z]):\s*(.*)/) { 8778c2ecf20Sopenharmony_ci my $type = $1; 8788c2ecf20Sopenharmony_ci my $value = $2; 8798c2ecf20Sopenharmony_ci if ($type eq 'X') { 8808c2ecf20Sopenharmony_ci if (file_match_pattern($file, $value)) { 8818c2ecf20Sopenharmony_ci $exclude = 1; 8828c2ecf20Sopenharmony_ci last; 8838c2ecf20Sopenharmony_ci } 8848c2ecf20Sopenharmony_ci } 8858c2ecf20Sopenharmony_ci } 8868c2ecf20Sopenharmony_ci } 8878c2ecf20Sopenharmony_ci 8888c2ecf20Sopenharmony_ci if (!$exclude) { 8898c2ecf20Sopenharmony_ci for ($i = $start; $i < $end; $i++) { 8908c2ecf20Sopenharmony_ci my $line = $typevalue[$i]; 8918c2ecf20Sopenharmony_ci if ($line =~ m/^([A-Z]):\s*(.*)/) { 8928c2ecf20Sopenharmony_ci my $type = $1; 8938c2ecf20Sopenharmony_ci my $value = $2; 8948c2ecf20Sopenharmony_ci if ($type eq 'F') { 8958c2ecf20Sopenharmony_ci if (file_match_pattern($file, $value)) { 8968c2ecf20Sopenharmony_ci my $value_pd = ($value =~ tr@/@@); 8978c2ecf20Sopenharmony_ci my $file_pd = ($file =~ tr@/@@); 8988c2ecf20Sopenharmony_ci $value_pd++ if (substr($value,-1,1) ne "/"); 8998c2ecf20Sopenharmony_ci $value_pd = -1 if ($value =~ /^\.\*/); 9008c2ecf20Sopenharmony_ci if ($value_pd >= $file_pd && 9018c2ecf20Sopenharmony_ci range_is_maintained($start, $end) && 9028c2ecf20Sopenharmony_ci range_has_maintainer($start, $end)) { 9038c2ecf20Sopenharmony_ci $exact_pattern_match_hash{$file} = 1; 9048c2ecf20Sopenharmony_ci } 9058c2ecf20Sopenharmony_ci if ($pattern_depth == 0 || 9068c2ecf20Sopenharmony_ci (($file_pd - $value_pd) < $pattern_depth)) { 9078c2ecf20Sopenharmony_ci $hash{$tvi} = $value_pd; 9088c2ecf20Sopenharmony_ci } 9098c2ecf20Sopenharmony_ci } 9108c2ecf20Sopenharmony_ci } elsif ($type eq 'N') { 9118c2ecf20Sopenharmony_ci if ($file =~ m/$value/x) { 9128c2ecf20Sopenharmony_ci $hash{$tvi} = 0; 9138c2ecf20Sopenharmony_ci } 9148c2ecf20Sopenharmony_ci } 9158c2ecf20Sopenharmony_ci } 9168c2ecf20Sopenharmony_ci } 9178c2ecf20Sopenharmony_ci } 9188c2ecf20Sopenharmony_ci $tvi = $end + 1; 9198c2ecf20Sopenharmony_ci } 9208c2ecf20Sopenharmony_ci 9218c2ecf20Sopenharmony_ci foreach my $line (sort {$hash{$b} <=> $hash{$a}} keys %hash) { 9228c2ecf20Sopenharmony_ci add_categories($line); 9238c2ecf20Sopenharmony_ci if ($sections) { 9248c2ecf20Sopenharmony_ci my $i; 9258c2ecf20Sopenharmony_ci my $start = find_starting_index($line); 9268c2ecf20Sopenharmony_ci my $end = find_ending_index($line); 9278c2ecf20Sopenharmony_ci for ($i = $start; $i < $end; $i++) { 9288c2ecf20Sopenharmony_ci my $line = $typevalue[$i]; 9298c2ecf20Sopenharmony_ci if ($line =~ /^[FX]:/) { ##Restore file patterns 9308c2ecf20Sopenharmony_ci $line =~ s/([^\\])\.([^\*])/$1\?$2/g; 9318c2ecf20Sopenharmony_ci $line =~ s/([^\\])\.$/$1\?/g; ##Convert . back to ? 9328c2ecf20Sopenharmony_ci $line =~ s/\\\./\./g; ##Convert \. to . 9338c2ecf20Sopenharmony_ci $line =~ s/\.\*/\*/g; ##Convert .* to * 9348c2ecf20Sopenharmony_ci } 9358c2ecf20Sopenharmony_ci my $count = $line =~ s/^([A-Z]):/$1:\t/g; 9368c2ecf20Sopenharmony_ci if ($letters eq "" || (!$count || $letters =~ /$1/i)) { 9378c2ecf20Sopenharmony_ci print("$line\n"); 9388c2ecf20Sopenharmony_ci } 9398c2ecf20Sopenharmony_ci } 9408c2ecf20Sopenharmony_ci print("\n"); 9418c2ecf20Sopenharmony_ci } 9428c2ecf20Sopenharmony_ci } 9438c2ecf20Sopenharmony_ci 9448c2ecf20Sopenharmony_ci maintainers_in_file($file); 9458c2ecf20Sopenharmony_ci } 9468c2ecf20Sopenharmony_ci 9478c2ecf20Sopenharmony_ci if ($keywords) { 9488c2ecf20Sopenharmony_ci @keyword_tvi = sort_and_uniq(@keyword_tvi); 9498c2ecf20Sopenharmony_ci foreach my $line (@keyword_tvi) { 9508c2ecf20Sopenharmony_ci add_categories($line); 9518c2ecf20Sopenharmony_ci } 9528c2ecf20Sopenharmony_ci } 9538c2ecf20Sopenharmony_ci 9548c2ecf20Sopenharmony_ci foreach my $email (@email_to, @list_to) { 9558c2ecf20Sopenharmony_ci $email->[0] = deduplicate_email($email->[0]); 9568c2ecf20Sopenharmony_ci } 9578c2ecf20Sopenharmony_ci 9588c2ecf20Sopenharmony_ci foreach my $file (@files) { 9598c2ecf20Sopenharmony_ci if ($email && 9608c2ecf20Sopenharmony_ci ($email_git || 9618c2ecf20Sopenharmony_ci ($email_git_fallback && 9628c2ecf20Sopenharmony_ci $file !~ /MAINTAINERS$/ && 9638c2ecf20Sopenharmony_ci !$exact_pattern_match_hash{$file}))) { 9648c2ecf20Sopenharmony_ci vcs_file_signoffs($file); 9658c2ecf20Sopenharmony_ci } 9668c2ecf20Sopenharmony_ci if ($email && $email_git_blame) { 9678c2ecf20Sopenharmony_ci vcs_file_blame($file); 9688c2ecf20Sopenharmony_ci } 9698c2ecf20Sopenharmony_ci } 9708c2ecf20Sopenharmony_ci 9718c2ecf20Sopenharmony_ci if ($email) { 9728c2ecf20Sopenharmony_ci foreach my $chief (@penguin_chief) { 9738c2ecf20Sopenharmony_ci if ($chief =~ m/^(.*):(.*)/) { 9748c2ecf20Sopenharmony_ci my $email_address; 9758c2ecf20Sopenharmony_ci 9768c2ecf20Sopenharmony_ci $email_address = format_email($1, $2, $email_usename); 9778c2ecf20Sopenharmony_ci if ($email_git_penguin_chiefs) { 9788c2ecf20Sopenharmony_ci push(@email_to, [$email_address, 'chief penguin']); 9798c2ecf20Sopenharmony_ci } else { 9808c2ecf20Sopenharmony_ci @email_to = grep($_->[0] !~ /${email_address}/, @email_to); 9818c2ecf20Sopenharmony_ci } 9828c2ecf20Sopenharmony_ci } 9838c2ecf20Sopenharmony_ci } 9848c2ecf20Sopenharmony_ci 9858c2ecf20Sopenharmony_ci foreach my $email (@file_emails) { 9868c2ecf20Sopenharmony_ci my ($name, $address) = parse_email($email); 9878c2ecf20Sopenharmony_ci 9888c2ecf20Sopenharmony_ci my $tmp_email = format_email($name, $address, $email_usename); 9898c2ecf20Sopenharmony_ci push_email_address($tmp_email, ''); 9908c2ecf20Sopenharmony_ci add_role($tmp_email, 'in file'); 9918c2ecf20Sopenharmony_ci } 9928c2ecf20Sopenharmony_ci } 9938c2ecf20Sopenharmony_ci 9948c2ecf20Sopenharmony_ci foreach my $fix (@fixes) { 9958c2ecf20Sopenharmony_ci vcs_add_commit_signers($fix, "blamed_fixes"); 9968c2ecf20Sopenharmony_ci } 9978c2ecf20Sopenharmony_ci 9988c2ecf20Sopenharmony_ci my @to = (); 9998c2ecf20Sopenharmony_ci if ($email || $email_list) { 10008c2ecf20Sopenharmony_ci if ($email) { 10018c2ecf20Sopenharmony_ci @to = (@to, @email_to); 10028c2ecf20Sopenharmony_ci } 10038c2ecf20Sopenharmony_ci if ($email_list) { 10048c2ecf20Sopenharmony_ci @to = (@to, @list_to); 10058c2ecf20Sopenharmony_ci } 10068c2ecf20Sopenharmony_ci } 10078c2ecf20Sopenharmony_ci 10088c2ecf20Sopenharmony_ci if ($interactive) { 10098c2ecf20Sopenharmony_ci @to = interactive_get_maintainers(\@to); 10108c2ecf20Sopenharmony_ci } 10118c2ecf20Sopenharmony_ci 10128c2ecf20Sopenharmony_ci return @to; 10138c2ecf20Sopenharmony_ci} 10148c2ecf20Sopenharmony_ci 10158c2ecf20Sopenharmony_cisub file_match_pattern { 10168c2ecf20Sopenharmony_ci my ($file, $pattern) = @_; 10178c2ecf20Sopenharmony_ci if (substr($pattern, -1) eq "/") { 10188c2ecf20Sopenharmony_ci if ($file =~ m@^$pattern@) { 10198c2ecf20Sopenharmony_ci return 1; 10208c2ecf20Sopenharmony_ci } 10218c2ecf20Sopenharmony_ci } else { 10228c2ecf20Sopenharmony_ci if ($file =~ m@^$pattern@) { 10238c2ecf20Sopenharmony_ci my $s1 = ($file =~ tr@/@@); 10248c2ecf20Sopenharmony_ci my $s2 = ($pattern =~ tr@/@@); 10258c2ecf20Sopenharmony_ci if ($s1 == $s2) { 10268c2ecf20Sopenharmony_ci return 1; 10278c2ecf20Sopenharmony_ci } 10288c2ecf20Sopenharmony_ci } 10298c2ecf20Sopenharmony_ci } 10308c2ecf20Sopenharmony_ci return 0; 10318c2ecf20Sopenharmony_ci} 10328c2ecf20Sopenharmony_ci 10338c2ecf20Sopenharmony_cisub usage { 10348c2ecf20Sopenharmony_ci print <<EOT; 10358c2ecf20Sopenharmony_ciusage: $P [options] patchfile 10368c2ecf20Sopenharmony_ci $P [options] -f file|directory 10378c2ecf20Sopenharmony_civersion: $V 10388c2ecf20Sopenharmony_ci 10398c2ecf20Sopenharmony_ciMAINTAINER field selection options: 10408c2ecf20Sopenharmony_ci --email => print email address(es) if any 10418c2ecf20Sopenharmony_ci --git => include recent git \*-by: signers 10428c2ecf20Sopenharmony_ci --git-all-signature-types => include signers regardless of signature type 10438c2ecf20Sopenharmony_ci or use only ${signature_pattern} signers (default: $email_git_all_signature_types) 10448c2ecf20Sopenharmony_ci --git-fallback => use git when no exact MAINTAINERS pattern (default: $email_git_fallback) 10458c2ecf20Sopenharmony_ci --git-chief-penguins => include ${penguin_chiefs} 10468c2ecf20Sopenharmony_ci --git-min-signatures => number of signatures required (default: $email_git_min_signatures) 10478c2ecf20Sopenharmony_ci --git-max-maintainers => maximum maintainers to add (default: $email_git_max_maintainers) 10488c2ecf20Sopenharmony_ci --git-min-percent => minimum percentage of commits required (default: $email_git_min_percent) 10498c2ecf20Sopenharmony_ci --git-blame => use git blame to find modified commits for patch or file 10508c2ecf20Sopenharmony_ci --git-blame-signatures => when used with --git-blame, also include all commit signers 10518c2ecf20Sopenharmony_ci --git-since => git history to use (default: $email_git_since) 10528c2ecf20Sopenharmony_ci --hg-since => hg history to use (default: $email_hg_since) 10538c2ecf20Sopenharmony_ci --interactive => display a menu (mostly useful if used with the --git option) 10548c2ecf20Sopenharmony_ci --m => include maintainer(s) if any 10558c2ecf20Sopenharmony_ci --r => include reviewer(s) if any 10568c2ecf20Sopenharmony_ci --n => include name 'Full Name <addr\@domain.tld>' 10578c2ecf20Sopenharmony_ci --l => include list(s) if any 10588c2ecf20Sopenharmony_ci --moderated => include moderated lists(s) if any (default: true) 10598c2ecf20Sopenharmony_ci --s => include subscriber only list(s) if any (default: false) 10608c2ecf20Sopenharmony_ci --remove-duplicates => minimize duplicate email names/addresses 10618c2ecf20Sopenharmony_ci --roles => show roles (status:subsystem, git-signer, list, etc...) 10628c2ecf20Sopenharmony_ci --rolestats => show roles and statistics (commits/total_commits, %) 10638c2ecf20Sopenharmony_ci --file-emails => add email addresses found in -f file (default: 0 (off)) 10648c2ecf20Sopenharmony_ci --fixes => for patches, add signatures of commits with 'Fixes: <commit>' (default: 1 (on)) 10658c2ecf20Sopenharmony_ci --scm => print SCM tree(s) if any 10668c2ecf20Sopenharmony_ci --status => print status if any 10678c2ecf20Sopenharmony_ci --subsystem => print subsystem name if any 10688c2ecf20Sopenharmony_ci --web => print website(s) if any 10698c2ecf20Sopenharmony_ci 10708c2ecf20Sopenharmony_ciOutput type options: 10718c2ecf20Sopenharmony_ci --separator [, ] => separator for multiple entries on 1 line 10728c2ecf20Sopenharmony_ci using --separator also sets --nomultiline if --separator is not [, ] 10738c2ecf20Sopenharmony_ci --multiline => print 1 entry per line 10748c2ecf20Sopenharmony_ci 10758c2ecf20Sopenharmony_ciOther options: 10768c2ecf20Sopenharmony_ci --pattern-depth => Number of pattern directory traversals (default: 0 (all)) 10778c2ecf20Sopenharmony_ci --keywords => scan patch for keywords (default: $keywords) 10788c2ecf20Sopenharmony_ci --sections => print all of the subsystem sections with pattern matches 10798c2ecf20Sopenharmony_ci --letters => print all matching 'letter' types from all matching sections 10808c2ecf20Sopenharmony_ci --mailmap => use .mailmap file (default: $email_use_mailmap) 10818c2ecf20Sopenharmony_ci --no-tree => run without a kernel tree 10828c2ecf20Sopenharmony_ci --self-test => show potential issues with MAINTAINERS file content 10838c2ecf20Sopenharmony_ci --version => show version 10848c2ecf20Sopenharmony_ci --help => show this help information 10858c2ecf20Sopenharmony_ci 10868c2ecf20Sopenharmony_ciDefault options: 10878c2ecf20Sopenharmony_ci [--email --tree --nogit --git-fallback --m --r --n --l --multiline 10888c2ecf20Sopenharmony_ci --pattern-depth=0 --remove-duplicates --rolestats] 10898c2ecf20Sopenharmony_ci 10908c2ecf20Sopenharmony_ciNotes: 10918c2ecf20Sopenharmony_ci Using "-f directory" may give unexpected results: 10928c2ecf20Sopenharmony_ci Used with "--git", git signators for _all_ files in and below 10938c2ecf20Sopenharmony_ci directory are examined as git recurses directories. 10948c2ecf20Sopenharmony_ci Any specified X: (exclude) pattern matches are _not_ ignored. 10958c2ecf20Sopenharmony_ci Used with "--nogit", directory is used as a pattern match, 10968c2ecf20Sopenharmony_ci no individual file within the directory or subdirectory 10978c2ecf20Sopenharmony_ci is matched. 10988c2ecf20Sopenharmony_ci Used with "--git-blame", does not iterate all files in directory 10998c2ecf20Sopenharmony_ci Using "--git-blame" is slow and may add old committers and authors 11008c2ecf20Sopenharmony_ci that are no longer active maintainers to the output. 11018c2ecf20Sopenharmony_ci Using "--roles" or "--rolestats" with git send-email --cc-cmd or any 11028c2ecf20Sopenharmony_ci other automated tools that expect only ["name"] <email address> 11038c2ecf20Sopenharmony_ci may not work because of additional output after <email address>. 11048c2ecf20Sopenharmony_ci Using "--rolestats" and "--git-blame" shows the #/total=% commits, 11058c2ecf20Sopenharmony_ci not the percentage of the entire file authored. # of commits is 11068c2ecf20Sopenharmony_ci not a good measure of amount of code authored. 1 major commit may 11078c2ecf20Sopenharmony_ci contain a thousand lines, 5 trivial commits may modify a single line. 11088c2ecf20Sopenharmony_ci If git is not installed, but mercurial (hg) is installed and an .hg 11098c2ecf20Sopenharmony_ci repository exists, the following options apply to mercurial: 11108c2ecf20Sopenharmony_ci --git, 11118c2ecf20Sopenharmony_ci --git-min-signatures, --git-max-maintainers, --git-min-percent, and 11128c2ecf20Sopenharmony_ci --git-blame 11138c2ecf20Sopenharmony_ci Use --hg-since not --git-since to control date selection 11148c2ecf20Sopenharmony_ci File ".get_maintainer.conf", if it exists in the linux kernel source root 11158c2ecf20Sopenharmony_ci directory, can change whatever get_maintainer defaults are desired. 11168c2ecf20Sopenharmony_ci Entries in this file can be any command line argument. 11178c2ecf20Sopenharmony_ci This file is prepended to any additional command line arguments. 11188c2ecf20Sopenharmony_ci Multiple lines and # comments are allowed. 11198c2ecf20Sopenharmony_ci Most options have both positive and negative forms. 11208c2ecf20Sopenharmony_ci The negative forms for --<foo> are --no<foo> and --no-<foo>. 11218c2ecf20Sopenharmony_ci 11228c2ecf20Sopenharmony_ciEOT 11238c2ecf20Sopenharmony_ci} 11248c2ecf20Sopenharmony_ci 11258c2ecf20Sopenharmony_cisub top_of_kernel_tree { 11268c2ecf20Sopenharmony_ci my ($lk_path) = @_; 11278c2ecf20Sopenharmony_ci 11288c2ecf20Sopenharmony_ci if ($lk_path ne "" && substr($lk_path,length($lk_path)-1,1) ne "/") { 11298c2ecf20Sopenharmony_ci $lk_path .= "/"; 11308c2ecf20Sopenharmony_ci } 11318c2ecf20Sopenharmony_ci if ( (-f "${lk_path}COPYING") 11328c2ecf20Sopenharmony_ci && (-f "${lk_path}CREDITS") 11338c2ecf20Sopenharmony_ci && (-f "${lk_path}Kbuild") 11348c2ecf20Sopenharmony_ci && (-e "${lk_path}MAINTAINERS") 11358c2ecf20Sopenharmony_ci && (-f "${lk_path}Makefile") 11368c2ecf20Sopenharmony_ci && (-f "${lk_path}README") 11378c2ecf20Sopenharmony_ci && (-d "${lk_path}Documentation") 11388c2ecf20Sopenharmony_ci && (-d "${lk_path}arch") 11398c2ecf20Sopenharmony_ci && (-d "${lk_path}include") 11408c2ecf20Sopenharmony_ci && (-d "${lk_path}drivers") 11418c2ecf20Sopenharmony_ci && (-d "${lk_path}fs") 11428c2ecf20Sopenharmony_ci && (-d "${lk_path}init") 11438c2ecf20Sopenharmony_ci && (-d "${lk_path}ipc") 11448c2ecf20Sopenharmony_ci && (-d "${lk_path}kernel") 11458c2ecf20Sopenharmony_ci && (-d "${lk_path}lib") 11468c2ecf20Sopenharmony_ci && (-d "${lk_path}scripts")) { 11478c2ecf20Sopenharmony_ci return 1; 11488c2ecf20Sopenharmony_ci } 11498c2ecf20Sopenharmony_ci return 0; 11508c2ecf20Sopenharmony_ci} 11518c2ecf20Sopenharmony_ci 11528c2ecf20Sopenharmony_cisub parse_email { 11538c2ecf20Sopenharmony_ci my ($formatted_email) = @_; 11548c2ecf20Sopenharmony_ci 11558c2ecf20Sopenharmony_ci my $name = ""; 11568c2ecf20Sopenharmony_ci my $address = ""; 11578c2ecf20Sopenharmony_ci 11588c2ecf20Sopenharmony_ci if ($formatted_email =~ /^([^<]+)<(.+\@.*)>.*$/) { 11598c2ecf20Sopenharmony_ci $name = $1; 11608c2ecf20Sopenharmony_ci $address = $2; 11618c2ecf20Sopenharmony_ci } elsif ($formatted_email =~ /^\s*<(.+\@\S*)>.*$/) { 11628c2ecf20Sopenharmony_ci $address = $1; 11638c2ecf20Sopenharmony_ci } elsif ($formatted_email =~ /^(.+\@\S*).*$/) { 11648c2ecf20Sopenharmony_ci $address = $1; 11658c2ecf20Sopenharmony_ci } 11668c2ecf20Sopenharmony_ci 11678c2ecf20Sopenharmony_ci $name =~ s/^\s+|\s+$//g; 11688c2ecf20Sopenharmony_ci $name =~ s/^\"|\"$//g; 11698c2ecf20Sopenharmony_ci $address =~ s/^\s+|\s+$//g; 11708c2ecf20Sopenharmony_ci 11718c2ecf20Sopenharmony_ci if ($name =~ /[^\w \-]/i) { ##has "must quote" chars 11728c2ecf20Sopenharmony_ci $name =~ s/(?<!\\)"/\\"/g; ##escape quotes 11738c2ecf20Sopenharmony_ci $name = "\"$name\""; 11748c2ecf20Sopenharmony_ci } 11758c2ecf20Sopenharmony_ci 11768c2ecf20Sopenharmony_ci return ($name, $address); 11778c2ecf20Sopenharmony_ci} 11788c2ecf20Sopenharmony_ci 11798c2ecf20Sopenharmony_cisub format_email { 11808c2ecf20Sopenharmony_ci my ($name, $address, $usename) = @_; 11818c2ecf20Sopenharmony_ci 11828c2ecf20Sopenharmony_ci my $formatted_email; 11838c2ecf20Sopenharmony_ci 11848c2ecf20Sopenharmony_ci $name =~ s/^\s+|\s+$//g; 11858c2ecf20Sopenharmony_ci $name =~ s/^\"|\"$//g; 11868c2ecf20Sopenharmony_ci $address =~ s/^\s+|\s+$//g; 11878c2ecf20Sopenharmony_ci 11888c2ecf20Sopenharmony_ci if ($name =~ /[^\w \-]/i) { ##has "must quote" chars 11898c2ecf20Sopenharmony_ci $name =~ s/(?<!\\)"/\\"/g; ##escape quotes 11908c2ecf20Sopenharmony_ci $name = "\"$name\""; 11918c2ecf20Sopenharmony_ci } 11928c2ecf20Sopenharmony_ci 11938c2ecf20Sopenharmony_ci if ($usename) { 11948c2ecf20Sopenharmony_ci if ("$name" eq "") { 11958c2ecf20Sopenharmony_ci $formatted_email = "$address"; 11968c2ecf20Sopenharmony_ci } else { 11978c2ecf20Sopenharmony_ci $formatted_email = "$name <$address>"; 11988c2ecf20Sopenharmony_ci } 11998c2ecf20Sopenharmony_ci } else { 12008c2ecf20Sopenharmony_ci $formatted_email = $address; 12018c2ecf20Sopenharmony_ci } 12028c2ecf20Sopenharmony_ci 12038c2ecf20Sopenharmony_ci return $formatted_email; 12048c2ecf20Sopenharmony_ci} 12058c2ecf20Sopenharmony_ci 12068c2ecf20Sopenharmony_cisub find_first_section { 12078c2ecf20Sopenharmony_ci my $index = 0; 12088c2ecf20Sopenharmony_ci 12098c2ecf20Sopenharmony_ci while ($index < @typevalue) { 12108c2ecf20Sopenharmony_ci my $tv = $typevalue[$index]; 12118c2ecf20Sopenharmony_ci if (($tv =~ m/^([A-Z]):\s*(.*)/)) { 12128c2ecf20Sopenharmony_ci last; 12138c2ecf20Sopenharmony_ci } 12148c2ecf20Sopenharmony_ci $index++; 12158c2ecf20Sopenharmony_ci } 12168c2ecf20Sopenharmony_ci 12178c2ecf20Sopenharmony_ci return $index; 12188c2ecf20Sopenharmony_ci} 12198c2ecf20Sopenharmony_ci 12208c2ecf20Sopenharmony_cisub find_starting_index { 12218c2ecf20Sopenharmony_ci my ($index) = @_; 12228c2ecf20Sopenharmony_ci 12238c2ecf20Sopenharmony_ci while ($index > 0) { 12248c2ecf20Sopenharmony_ci my $tv = $typevalue[$index]; 12258c2ecf20Sopenharmony_ci if (!($tv =~ m/^([A-Z]):\s*(.*)/)) { 12268c2ecf20Sopenharmony_ci last; 12278c2ecf20Sopenharmony_ci } 12288c2ecf20Sopenharmony_ci $index--; 12298c2ecf20Sopenharmony_ci } 12308c2ecf20Sopenharmony_ci 12318c2ecf20Sopenharmony_ci return $index; 12328c2ecf20Sopenharmony_ci} 12338c2ecf20Sopenharmony_ci 12348c2ecf20Sopenharmony_cisub find_ending_index { 12358c2ecf20Sopenharmony_ci my ($index) = @_; 12368c2ecf20Sopenharmony_ci 12378c2ecf20Sopenharmony_ci while ($index < @typevalue) { 12388c2ecf20Sopenharmony_ci my $tv = $typevalue[$index]; 12398c2ecf20Sopenharmony_ci if (!($tv =~ m/^([A-Z]):\s*(.*)/)) { 12408c2ecf20Sopenharmony_ci last; 12418c2ecf20Sopenharmony_ci } 12428c2ecf20Sopenharmony_ci $index++; 12438c2ecf20Sopenharmony_ci } 12448c2ecf20Sopenharmony_ci 12458c2ecf20Sopenharmony_ci return $index; 12468c2ecf20Sopenharmony_ci} 12478c2ecf20Sopenharmony_ci 12488c2ecf20Sopenharmony_cisub get_subsystem_name { 12498c2ecf20Sopenharmony_ci my ($index) = @_; 12508c2ecf20Sopenharmony_ci 12518c2ecf20Sopenharmony_ci my $start = find_starting_index($index); 12528c2ecf20Sopenharmony_ci 12538c2ecf20Sopenharmony_ci my $subsystem = $typevalue[$start]; 12548c2ecf20Sopenharmony_ci if ($output_section_maxlen && length($subsystem) > $output_section_maxlen) { 12558c2ecf20Sopenharmony_ci $subsystem = substr($subsystem, 0, $output_section_maxlen - 3); 12568c2ecf20Sopenharmony_ci $subsystem =~ s/\s*$//; 12578c2ecf20Sopenharmony_ci $subsystem = $subsystem . "..."; 12588c2ecf20Sopenharmony_ci } 12598c2ecf20Sopenharmony_ci return $subsystem; 12608c2ecf20Sopenharmony_ci} 12618c2ecf20Sopenharmony_ci 12628c2ecf20Sopenharmony_cisub get_maintainer_role { 12638c2ecf20Sopenharmony_ci my ($index) = @_; 12648c2ecf20Sopenharmony_ci 12658c2ecf20Sopenharmony_ci my $i; 12668c2ecf20Sopenharmony_ci my $start = find_starting_index($index); 12678c2ecf20Sopenharmony_ci my $end = find_ending_index($index); 12688c2ecf20Sopenharmony_ci 12698c2ecf20Sopenharmony_ci my $role = "unknown"; 12708c2ecf20Sopenharmony_ci my $subsystem = get_subsystem_name($index); 12718c2ecf20Sopenharmony_ci 12728c2ecf20Sopenharmony_ci for ($i = $start + 1; $i < $end; $i++) { 12738c2ecf20Sopenharmony_ci my $tv = $typevalue[$i]; 12748c2ecf20Sopenharmony_ci if ($tv =~ m/^([A-Z]):\s*(.*)/) { 12758c2ecf20Sopenharmony_ci my $ptype = $1; 12768c2ecf20Sopenharmony_ci my $pvalue = $2; 12778c2ecf20Sopenharmony_ci if ($ptype eq "S") { 12788c2ecf20Sopenharmony_ci $role = $pvalue; 12798c2ecf20Sopenharmony_ci } 12808c2ecf20Sopenharmony_ci } 12818c2ecf20Sopenharmony_ci } 12828c2ecf20Sopenharmony_ci 12838c2ecf20Sopenharmony_ci $role = lc($role); 12848c2ecf20Sopenharmony_ci if ($role eq "supported") { 12858c2ecf20Sopenharmony_ci $role = "supporter"; 12868c2ecf20Sopenharmony_ci } elsif ($role eq "maintained") { 12878c2ecf20Sopenharmony_ci $role = "maintainer"; 12888c2ecf20Sopenharmony_ci } elsif ($role eq "odd fixes") { 12898c2ecf20Sopenharmony_ci $role = "odd fixer"; 12908c2ecf20Sopenharmony_ci } elsif ($role eq "orphan") { 12918c2ecf20Sopenharmony_ci $role = "orphan minder"; 12928c2ecf20Sopenharmony_ci } elsif ($role eq "obsolete") { 12938c2ecf20Sopenharmony_ci $role = "obsolete minder"; 12948c2ecf20Sopenharmony_ci } elsif ($role eq "buried alive in reporters") { 12958c2ecf20Sopenharmony_ci $role = "chief penguin"; 12968c2ecf20Sopenharmony_ci } 12978c2ecf20Sopenharmony_ci 12988c2ecf20Sopenharmony_ci return $role . ":" . $subsystem; 12998c2ecf20Sopenharmony_ci} 13008c2ecf20Sopenharmony_ci 13018c2ecf20Sopenharmony_cisub get_list_role { 13028c2ecf20Sopenharmony_ci my ($index) = @_; 13038c2ecf20Sopenharmony_ci 13048c2ecf20Sopenharmony_ci my $subsystem = get_subsystem_name($index); 13058c2ecf20Sopenharmony_ci 13068c2ecf20Sopenharmony_ci if ($subsystem eq "THE REST") { 13078c2ecf20Sopenharmony_ci $subsystem = ""; 13088c2ecf20Sopenharmony_ci } 13098c2ecf20Sopenharmony_ci 13108c2ecf20Sopenharmony_ci return $subsystem; 13118c2ecf20Sopenharmony_ci} 13128c2ecf20Sopenharmony_ci 13138c2ecf20Sopenharmony_cisub add_categories { 13148c2ecf20Sopenharmony_ci my ($index) = @_; 13158c2ecf20Sopenharmony_ci 13168c2ecf20Sopenharmony_ci my $i; 13178c2ecf20Sopenharmony_ci my $start = find_starting_index($index); 13188c2ecf20Sopenharmony_ci my $end = find_ending_index($index); 13198c2ecf20Sopenharmony_ci 13208c2ecf20Sopenharmony_ci push(@subsystem, $typevalue[$start]); 13218c2ecf20Sopenharmony_ci 13228c2ecf20Sopenharmony_ci for ($i = $start + 1; $i < $end; $i++) { 13238c2ecf20Sopenharmony_ci my $tv = $typevalue[$i]; 13248c2ecf20Sopenharmony_ci if ($tv =~ m/^([A-Z]):\s*(.*)/) { 13258c2ecf20Sopenharmony_ci my $ptype = $1; 13268c2ecf20Sopenharmony_ci my $pvalue = $2; 13278c2ecf20Sopenharmony_ci if ($ptype eq "L") { 13288c2ecf20Sopenharmony_ci my $list_address = $pvalue; 13298c2ecf20Sopenharmony_ci my $list_additional = ""; 13308c2ecf20Sopenharmony_ci my $list_role = get_list_role($i); 13318c2ecf20Sopenharmony_ci 13328c2ecf20Sopenharmony_ci if ($list_role ne "") { 13338c2ecf20Sopenharmony_ci $list_role = ":" . $list_role; 13348c2ecf20Sopenharmony_ci } 13358c2ecf20Sopenharmony_ci if ($list_address =~ m/([^\s]+)\s+(.*)$/) { 13368c2ecf20Sopenharmony_ci $list_address = $1; 13378c2ecf20Sopenharmony_ci $list_additional = $2; 13388c2ecf20Sopenharmony_ci } 13398c2ecf20Sopenharmony_ci if ($list_additional =~ m/subscribers-only/) { 13408c2ecf20Sopenharmony_ci if ($email_subscriber_list) { 13418c2ecf20Sopenharmony_ci if (!$hash_list_to{lc($list_address)}) { 13428c2ecf20Sopenharmony_ci $hash_list_to{lc($list_address)} = 1; 13438c2ecf20Sopenharmony_ci push(@list_to, [$list_address, 13448c2ecf20Sopenharmony_ci "subscriber list${list_role}"]); 13458c2ecf20Sopenharmony_ci } 13468c2ecf20Sopenharmony_ci } 13478c2ecf20Sopenharmony_ci } else { 13488c2ecf20Sopenharmony_ci if ($email_list) { 13498c2ecf20Sopenharmony_ci if (!$hash_list_to{lc($list_address)}) { 13508c2ecf20Sopenharmony_ci if ($list_additional =~ m/moderated/) { 13518c2ecf20Sopenharmony_ci if ($email_moderated_list) { 13528c2ecf20Sopenharmony_ci $hash_list_to{lc($list_address)} = 1; 13538c2ecf20Sopenharmony_ci push(@list_to, [$list_address, 13548c2ecf20Sopenharmony_ci "moderated list${list_role}"]); 13558c2ecf20Sopenharmony_ci } 13568c2ecf20Sopenharmony_ci } else { 13578c2ecf20Sopenharmony_ci $hash_list_to{lc($list_address)} = 1; 13588c2ecf20Sopenharmony_ci push(@list_to, [$list_address, 13598c2ecf20Sopenharmony_ci "open list${list_role}"]); 13608c2ecf20Sopenharmony_ci } 13618c2ecf20Sopenharmony_ci } 13628c2ecf20Sopenharmony_ci } 13638c2ecf20Sopenharmony_ci } 13648c2ecf20Sopenharmony_ci } elsif ($ptype eq "M") { 13658c2ecf20Sopenharmony_ci if ($email_maintainer) { 13668c2ecf20Sopenharmony_ci my $role = get_maintainer_role($i); 13678c2ecf20Sopenharmony_ci push_email_addresses($pvalue, $role); 13688c2ecf20Sopenharmony_ci } 13698c2ecf20Sopenharmony_ci } elsif ($ptype eq "R") { 13708c2ecf20Sopenharmony_ci if ($email_reviewer) { 13718c2ecf20Sopenharmony_ci my $subsystem = get_subsystem_name($i); 13728c2ecf20Sopenharmony_ci push_email_addresses($pvalue, "reviewer:$subsystem"); 13738c2ecf20Sopenharmony_ci } 13748c2ecf20Sopenharmony_ci } elsif ($ptype eq "T") { 13758c2ecf20Sopenharmony_ci push(@scm, $pvalue); 13768c2ecf20Sopenharmony_ci } elsif ($ptype eq "W") { 13778c2ecf20Sopenharmony_ci push(@web, $pvalue); 13788c2ecf20Sopenharmony_ci } elsif ($ptype eq "S") { 13798c2ecf20Sopenharmony_ci push(@status, $pvalue); 13808c2ecf20Sopenharmony_ci } 13818c2ecf20Sopenharmony_ci } 13828c2ecf20Sopenharmony_ci } 13838c2ecf20Sopenharmony_ci} 13848c2ecf20Sopenharmony_ci 13858c2ecf20Sopenharmony_cisub email_inuse { 13868c2ecf20Sopenharmony_ci my ($name, $address) = @_; 13878c2ecf20Sopenharmony_ci 13888c2ecf20Sopenharmony_ci return 1 if (($name eq "") && ($address eq "")); 13898c2ecf20Sopenharmony_ci return 1 if (($name ne "") && exists($email_hash_name{lc($name)})); 13908c2ecf20Sopenharmony_ci return 1 if (($address ne "") && exists($email_hash_address{lc($address)})); 13918c2ecf20Sopenharmony_ci 13928c2ecf20Sopenharmony_ci return 0; 13938c2ecf20Sopenharmony_ci} 13948c2ecf20Sopenharmony_ci 13958c2ecf20Sopenharmony_cisub push_email_address { 13968c2ecf20Sopenharmony_ci my ($line, $role) = @_; 13978c2ecf20Sopenharmony_ci 13988c2ecf20Sopenharmony_ci my ($name, $address) = parse_email($line); 13998c2ecf20Sopenharmony_ci 14008c2ecf20Sopenharmony_ci if ($address eq "") { 14018c2ecf20Sopenharmony_ci return 0; 14028c2ecf20Sopenharmony_ci } 14038c2ecf20Sopenharmony_ci 14048c2ecf20Sopenharmony_ci if (!$email_remove_duplicates) { 14058c2ecf20Sopenharmony_ci push(@email_to, [format_email($name, $address, $email_usename), $role]); 14068c2ecf20Sopenharmony_ci } elsif (!email_inuse($name, $address)) { 14078c2ecf20Sopenharmony_ci push(@email_to, [format_email($name, $address, $email_usename), $role]); 14088c2ecf20Sopenharmony_ci $email_hash_name{lc($name)}++ if ($name ne ""); 14098c2ecf20Sopenharmony_ci $email_hash_address{lc($address)}++; 14108c2ecf20Sopenharmony_ci } 14118c2ecf20Sopenharmony_ci 14128c2ecf20Sopenharmony_ci return 1; 14138c2ecf20Sopenharmony_ci} 14148c2ecf20Sopenharmony_ci 14158c2ecf20Sopenharmony_cisub push_email_addresses { 14168c2ecf20Sopenharmony_ci my ($address, $role) = @_; 14178c2ecf20Sopenharmony_ci 14188c2ecf20Sopenharmony_ci my @address_list = (); 14198c2ecf20Sopenharmony_ci 14208c2ecf20Sopenharmony_ci if (rfc822_valid($address)) { 14218c2ecf20Sopenharmony_ci push_email_address($address, $role); 14228c2ecf20Sopenharmony_ci } elsif (@address_list = rfc822_validlist($address)) { 14238c2ecf20Sopenharmony_ci my $array_count = shift(@address_list); 14248c2ecf20Sopenharmony_ci while (my $entry = shift(@address_list)) { 14258c2ecf20Sopenharmony_ci push_email_address($entry, $role); 14268c2ecf20Sopenharmony_ci } 14278c2ecf20Sopenharmony_ci } else { 14288c2ecf20Sopenharmony_ci if (!push_email_address($address, $role)) { 14298c2ecf20Sopenharmony_ci warn("Invalid MAINTAINERS address: '" . $address . "'\n"); 14308c2ecf20Sopenharmony_ci } 14318c2ecf20Sopenharmony_ci } 14328c2ecf20Sopenharmony_ci} 14338c2ecf20Sopenharmony_ci 14348c2ecf20Sopenharmony_cisub add_role { 14358c2ecf20Sopenharmony_ci my ($line, $role) = @_; 14368c2ecf20Sopenharmony_ci 14378c2ecf20Sopenharmony_ci my ($name, $address) = parse_email($line); 14388c2ecf20Sopenharmony_ci my $email = format_email($name, $address, $email_usename); 14398c2ecf20Sopenharmony_ci 14408c2ecf20Sopenharmony_ci foreach my $entry (@email_to) { 14418c2ecf20Sopenharmony_ci if ($email_remove_duplicates) { 14428c2ecf20Sopenharmony_ci my ($entry_name, $entry_address) = parse_email($entry->[0]); 14438c2ecf20Sopenharmony_ci if (($name eq $entry_name || $address eq $entry_address) 14448c2ecf20Sopenharmony_ci && ($role eq "" || !($entry->[1] =~ m/$role/)) 14458c2ecf20Sopenharmony_ci ) { 14468c2ecf20Sopenharmony_ci if ($entry->[1] eq "") { 14478c2ecf20Sopenharmony_ci $entry->[1] = "$role"; 14488c2ecf20Sopenharmony_ci } else { 14498c2ecf20Sopenharmony_ci $entry->[1] = "$entry->[1],$role"; 14508c2ecf20Sopenharmony_ci } 14518c2ecf20Sopenharmony_ci } 14528c2ecf20Sopenharmony_ci } else { 14538c2ecf20Sopenharmony_ci if ($email eq $entry->[0] 14548c2ecf20Sopenharmony_ci && ($role eq "" || !($entry->[1] =~ m/$role/)) 14558c2ecf20Sopenharmony_ci ) { 14568c2ecf20Sopenharmony_ci if ($entry->[1] eq "") { 14578c2ecf20Sopenharmony_ci $entry->[1] = "$role"; 14588c2ecf20Sopenharmony_ci } else { 14598c2ecf20Sopenharmony_ci $entry->[1] = "$entry->[1],$role"; 14608c2ecf20Sopenharmony_ci } 14618c2ecf20Sopenharmony_ci } 14628c2ecf20Sopenharmony_ci } 14638c2ecf20Sopenharmony_ci } 14648c2ecf20Sopenharmony_ci} 14658c2ecf20Sopenharmony_ci 14668c2ecf20Sopenharmony_cisub which { 14678c2ecf20Sopenharmony_ci my ($bin) = @_; 14688c2ecf20Sopenharmony_ci 14698c2ecf20Sopenharmony_ci foreach my $path (split(/:/, $ENV{PATH})) { 14708c2ecf20Sopenharmony_ci if (-e "$path/$bin") { 14718c2ecf20Sopenharmony_ci return "$path/$bin"; 14728c2ecf20Sopenharmony_ci } 14738c2ecf20Sopenharmony_ci } 14748c2ecf20Sopenharmony_ci 14758c2ecf20Sopenharmony_ci return ""; 14768c2ecf20Sopenharmony_ci} 14778c2ecf20Sopenharmony_ci 14788c2ecf20Sopenharmony_cisub which_conf { 14798c2ecf20Sopenharmony_ci my ($conf) = @_; 14808c2ecf20Sopenharmony_ci 14818c2ecf20Sopenharmony_ci foreach my $path (split(/:/, ".:$ENV{HOME}:.scripts")) { 14828c2ecf20Sopenharmony_ci if (-e "$path/$conf") { 14838c2ecf20Sopenharmony_ci return "$path/$conf"; 14848c2ecf20Sopenharmony_ci } 14858c2ecf20Sopenharmony_ci } 14868c2ecf20Sopenharmony_ci 14878c2ecf20Sopenharmony_ci return ""; 14888c2ecf20Sopenharmony_ci} 14898c2ecf20Sopenharmony_ci 14908c2ecf20Sopenharmony_cisub mailmap_email { 14918c2ecf20Sopenharmony_ci my ($line) = @_; 14928c2ecf20Sopenharmony_ci 14938c2ecf20Sopenharmony_ci my ($name, $address) = parse_email($line); 14948c2ecf20Sopenharmony_ci my $email = format_email($name, $address, 1); 14958c2ecf20Sopenharmony_ci my $real_name = $name; 14968c2ecf20Sopenharmony_ci my $real_address = $address; 14978c2ecf20Sopenharmony_ci 14988c2ecf20Sopenharmony_ci if (exists $mailmap->{names}->{$email} || 14998c2ecf20Sopenharmony_ci exists $mailmap->{addresses}->{$email}) { 15008c2ecf20Sopenharmony_ci if (exists $mailmap->{names}->{$email}) { 15018c2ecf20Sopenharmony_ci $real_name = $mailmap->{names}->{$email}; 15028c2ecf20Sopenharmony_ci } 15038c2ecf20Sopenharmony_ci if (exists $mailmap->{addresses}->{$email}) { 15048c2ecf20Sopenharmony_ci $real_address = $mailmap->{addresses}->{$email}; 15058c2ecf20Sopenharmony_ci } 15068c2ecf20Sopenharmony_ci } else { 15078c2ecf20Sopenharmony_ci if (exists $mailmap->{names}->{$address}) { 15088c2ecf20Sopenharmony_ci $real_name = $mailmap->{names}->{$address}; 15098c2ecf20Sopenharmony_ci } 15108c2ecf20Sopenharmony_ci if (exists $mailmap->{addresses}->{$address}) { 15118c2ecf20Sopenharmony_ci $real_address = $mailmap->{addresses}->{$address}; 15128c2ecf20Sopenharmony_ci } 15138c2ecf20Sopenharmony_ci } 15148c2ecf20Sopenharmony_ci return format_email($real_name, $real_address, 1); 15158c2ecf20Sopenharmony_ci} 15168c2ecf20Sopenharmony_ci 15178c2ecf20Sopenharmony_cisub mailmap { 15188c2ecf20Sopenharmony_ci my (@addresses) = @_; 15198c2ecf20Sopenharmony_ci 15208c2ecf20Sopenharmony_ci my @mapped_emails = (); 15218c2ecf20Sopenharmony_ci foreach my $line (@addresses) { 15228c2ecf20Sopenharmony_ci push(@mapped_emails, mailmap_email($line)); 15238c2ecf20Sopenharmony_ci } 15248c2ecf20Sopenharmony_ci merge_by_realname(@mapped_emails) if ($email_use_mailmap); 15258c2ecf20Sopenharmony_ci return @mapped_emails; 15268c2ecf20Sopenharmony_ci} 15278c2ecf20Sopenharmony_ci 15288c2ecf20Sopenharmony_cisub merge_by_realname { 15298c2ecf20Sopenharmony_ci my %address_map; 15308c2ecf20Sopenharmony_ci my (@emails) = @_; 15318c2ecf20Sopenharmony_ci 15328c2ecf20Sopenharmony_ci foreach my $email (@emails) { 15338c2ecf20Sopenharmony_ci my ($name, $address) = parse_email($email); 15348c2ecf20Sopenharmony_ci if (exists $address_map{$name}) { 15358c2ecf20Sopenharmony_ci $address = $address_map{$name}; 15368c2ecf20Sopenharmony_ci $email = format_email($name, $address, 1); 15378c2ecf20Sopenharmony_ci } else { 15388c2ecf20Sopenharmony_ci $address_map{$name} = $address; 15398c2ecf20Sopenharmony_ci } 15408c2ecf20Sopenharmony_ci } 15418c2ecf20Sopenharmony_ci} 15428c2ecf20Sopenharmony_ci 15438c2ecf20Sopenharmony_cisub git_execute_cmd { 15448c2ecf20Sopenharmony_ci my ($cmd) = @_; 15458c2ecf20Sopenharmony_ci my @lines = (); 15468c2ecf20Sopenharmony_ci 15478c2ecf20Sopenharmony_ci my $output = `$cmd`; 15488c2ecf20Sopenharmony_ci $output =~ s/^\s*//gm; 15498c2ecf20Sopenharmony_ci @lines = split("\n", $output); 15508c2ecf20Sopenharmony_ci 15518c2ecf20Sopenharmony_ci return @lines; 15528c2ecf20Sopenharmony_ci} 15538c2ecf20Sopenharmony_ci 15548c2ecf20Sopenharmony_cisub hg_execute_cmd { 15558c2ecf20Sopenharmony_ci my ($cmd) = @_; 15568c2ecf20Sopenharmony_ci my @lines = (); 15578c2ecf20Sopenharmony_ci 15588c2ecf20Sopenharmony_ci my $output = `$cmd`; 15598c2ecf20Sopenharmony_ci @lines = split("\n", $output); 15608c2ecf20Sopenharmony_ci 15618c2ecf20Sopenharmony_ci return @lines; 15628c2ecf20Sopenharmony_ci} 15638c2ecf20Sopenharmony_ci 15648c2ecf20Sopenharmony_cisub extract_formatted_signatures { 15658c2ecf20Sopenharmony_ci my (@signature_lines) = @_; 15668c2ecf20Sopenharmony_ci 15678c2ecf20Sopenharmony_ci my @type = @signature_lines; 15688c2ecf20Sopenharmony_ci 15698c2ecf20Sopenharmony_ci s/\s*(.*):.*/$1/ for (@type); 15708c2ecf20Sopenharmony_ci 15718c2ecf20Sopenharmony_ci # cut -f2- -d":" 15728c2ecf20Sopenharmony_ci s/\s*.*:\s*(.+)\s*/$1/ for (@signature_lines); 15738c2ecf20Sopenharmony_ci 15748c2ecf20Sopenharmony_ci## Reformat email addresses (with names) to avoid badly written signatures 15758c2ecf20Sopenharmony_ci 15768c2ecf20Sopenharmony_ci foreach my $signer (@signature_lines) { 15778c2ecf20Sopenharmony_ci $signer = deduplicate_email($signer); 15788c2ecf20Sopenharmony_ci } 15798c2ecf20Sopenharmony_ci 15808c2ecf20Sopenharmony_ci return (\@type, \@signature_lines); 15818c2ecf20Sopenharmony_ci} 15828c2ecf20Sopenharmony_ci 15838c2ecf20Sopenharmony_cisub vcs_find_signers { 15848c2ecf20Sopenharmony_ci my ($cmd, $file) = @_; 15858c2ecf20Sopenharmony_ci my $commits; 15868c2ecf20Sopenharmony_ci my @lines = (); 15878c2ecf20Sopenharmony_ci my @signatures = (); 15888c2ecf20Sopenharmony_ci my @authors = (); 15898c2ecf20Sopenharmony_ci my @stats = (); 15908c2ecf20Sopenharmony_ci 15918c2ecf20Sopenharmony_ci @lines = &{$VCS_cmds{"execute_cmd"}}($cmd); 15928c2ecf20Sopenharmony_ci 15938c2ecf20Sopenharmony_ci my $pattern = $VCS_cmds{"commit_pattern"}; 15948c2ecf20Sopenharmony_ci my $author_pattern = $VCS_cmds{"author_pattern"}; 15958c2ecf20Sopenharmony_ci my $stat_pattern = $VCS_cmds{"stat_pattern"}; 15968c2ecf20Sopenharmony_ci 15978c2ecf20Sopenharmony_ci $stat_pattern =~ s/(\$\w+)/$1/eeg; #interpolate $stat_pattern 15988c2ecf20Sopenharmony_ci 15998c2ecf20Sopenharmony_ci $commits = grep(/$pattern/, @lines); # of commits 16008c2ecf20Sopenharmony_ci 16018c2ecf20Sopenharmony_ci @authors = grep(/$author_pattern/, @lines); 16028c2ecf20Sopenharmony_ci @signatures = grep(/^[ \t]*${signature_pattern}.*\@.*$/, @lines); 16038c2ecf20Sopenharmony_ci @stats = grep(/$stat_pattern/, @lines); 16048c2ecf20Sopenharmony_ci 16058c2ecf20Sopenharmony_ci# print("stats: <@stats>\n"); 16068c2ecf20Sopenharmony_ci 16078c2ecf20Sopenharmony_ci return (0, \@signatures, \@authors, \@stats) if !@signatures; 16088c2ecf20Sopenharmony_ci 16098c2ecf20Sopenharmony_ci save_commits_by_author(@lines) if ($interactive); 16108c2ecf20Sopenharmony_ci save_commits_by_signer(@lines) if ($interactive); 16118c2ecf20Sopenharmony_ci 16128c2ecf20Sopenharmony_ci if (!$email_git_penguin_chiefs) { 16138c2ecf20Sopenharmony_ci @signatures = grep(!/${penguin_chiefs}/i, @signatures); 16148c2ecf20Sopenharmony_ci } 16158c2ecf20Sopenharmony_ci 16168c2ecf20Sopenharmony_ci my ($author_ref, $authors_ref) = extract_formatted_signatures(@authors); 16178c2ecf20Sopenharmony_ci my ($types_ref, $signers_ref) = extract_formatted_signatures(@signatures); 16188c2ecf20Sopenharmony_ci 16198c2ecf20Sopenharmony_ci return ($commits, $signers_ref, $authors_ref, \@stats); 16208c2ecf20Sopenharmony_ci} 16218c2ecf20Sopenharmony_ci 16228c2ecf20Sopenharmony_cisub vcs_find_author { 16238c2ecf20Sopenharmony_ci my ($cmd) = @_; 16248c2ecf20Sopenharmony_ci my @lines = (); 16258c2ecf20Sopenharmony_ci 16268c2ecf20Sopenharmony_ci @lines = &{$VCS_cmds{"execute_cmd"}}($cmd); 16278c2ecf20Sopenharmony_ci 16288c2ecf20Sopenharmony_ci if (!$email_git_penguin_chiefs) { 16298c2ecf20Sopenharmony_ci @lines = grep(!/${penguin_chiefs}/i, @lines); 16308c2ecf20Sopenharmony_ci } 16318c2ecf20Sopenharmony_ci 16328c2ecf20Sopenharmony_ci return @lines if !@lines; 16338c2ecf20Sopenharmony_ci 16348c2ecf20Sopenharmony_ci my @authors = (); 16358c2ecf20Sopenharmony_ci foreach my $line (@lines) { 16368c2ecf20Sopenharmony_ci if ($line =~ m/$VCS_cmds{"author_pattern"}/) { 16378c2ecf20Sopenharmony_ci my $author = $1; 16388c2ecf20Sopenharmony_ci my ($name, $address) = parse_email($author); 16398c2ecf20Sopenharmony_ci $author = format_email($name, $address, 1); 16408c2ecf20Sopenharmony_ci push(@authors, $author); 16418c2ecf20Sopenharmony_ci } 16428c2ecf20Sopenharmony_ci } 16438c2ecf20Sopenharmony_ci 16448c2ecf20Sopenharmony_ci save_commits_by_author(@lines) if ($interactive); 16458c2ecf20Sopenharmony_ci save_commits_by_signer(@lines) if ($interactive); 16468c2ecf20Sopenharmony_ci 16478c2ecf20Sopenharmony_ci return @authors; 16488c2ecf20Sopenharmony_ci} 16498c2ecf20Sopenharmony_ci 16508c2ecf20Sopenharmony_cisub vcs_save_commits { 16518c2ecf20Sopenharmony_ci my ($cmd) = @_; 16528c2ecf20Sopenharmony_ci my @lines = (); 16538c2ecf20Sopenharmony_ci my @commits = (); 16548c2ecf20Sopenharmony_ci 16558c2ecf20Sopenharmony_ci @lines = &{$VCS_cmds{"execute_cmd"}}($cmd); 16568c2ecf20Sopenharmony_ci 16578c2ecf20Sopenharmony_ci foreach my $line (@lines) { 16588c2ecf20Sopenharmony_ci if ($line =~ m/$VCS_cmds{"blame_commit_pattern"}/) { 16598c2ecf20Sopenharmony_ci push(@commits, $1); 16608c2ecf20Sopenharmony_ci } 16618c2ecf20Sopenharmony_ci } 16628c2ecf20Sopenharmony_ci 16638c2ecf20Sopenharmony_ci return @commits; 16648c2ecf20Sopenharmony_ci} 16658c2ecf20Sopenharmony_ci 16668c2ecf20Sopenharmony_cisub vcs_blame { 16678c2ecf20Sopenharmony_ci my ($file) = @_; 16688c2ecf20Sopenharmony_ci my $cmd; 16698c2ecf20Sopenharmony_ci my @commits = (); 16708c2ecf20Sopenharmony_ci 16718c2ecf20Sopenharmony_ci return @commits if (!(-f $file)); 16728c2ecf20Sopenharmony_ci 16738c2ecf20Sopenharmony_ci if (@range && $VCS_cmds{"blame_range_cmd"} eq "") { 16748c2ecf20Sopenharmony_ci my @all_commits = (); 16758c2ecf20Sopenharmony_ci 16768c2ecf20Sopenharmony_ci $cmd = $VCS_cmds{"blame_file_cmd"}; 16778c2ecf20Sopenharmony_ci $cmd =~ s/(\$\w+)/$1/eeg; #interpolate $cmd 16788c2ecf20Sopenharmony_ci @all_commits = vcs_save_commits($cmd); 16798c2ecf20Sopenharmony_ci 16808c2ecf20Sopenharmony_ci foreach my $file_range_diff (@range) { 16818c2ecf20Sopenharmony_ci next if (!($file_range_diff =~ m/(.+):(.+):(.+)/)); 16828c2ecf20Sopenharmony_ci my $diff_file = $1; 16838c2ecf20Sopenharmony_ci my $diff_start = $2; 16848c2ecf20Sopenharmony_ci my $diff_length = $3; 16858c2ecf20Sopenharmony_ci next if ("$file" ne "$diff_file"); 16868c2ecf20Sopenharmony_ci for (my $i = $diff_start; $i < $diff_start + $diff_length; $i++) { 16878c2ecf20Sopenharmony_ci push(@commits, $all_commits[$i]); 16888c2ecf20Sopenharmony_ci } 16898c2ecf20Sopenharmony_ci } 16908c2ecf20Sopenharmony_ci } elsif (@range) { 16918c2ecf20Sopenharmony_ci foreach my $file_range_diff (@range) { 16928c2ecf20Sopenharmony_ci next if (!($file_range_diff =~ m/(.+):(.+):(.+)/)); 16938c2ecf20Sopenharmony_ci my $diff_file = $1; 16948c2ecf20Sopenharmony_ci my $diff_start = $2; 16958c2ecf20Sopenharmony_ci my $diff_length = $3; 16968c2ecf20Sopenharmony_ci next if ("$file" ne "$diff_file"); 16978c2ecf20Sopenharmony_ci $cmd = $VCS_cmds{"blame_range_cmd"}; 16988c2ecf20Sopenharmony_ci $cmd =~ s/(\$\w+)/$1/eeg; #interpolate $cmd 16998c2ecf20Sopenharmony_ci push(@commits, vcs_save_commits($cmd)); 17008c2ecf20Sopenharmony_ci } 17018c2ecf20Sopenharmony_ci } else { 17028c2ecf20Sopenharmony_ci $cmd = $VCS_cmds{"blame_file_cmd"}; 17038c2ecf20Sopenharmony_ci $cmd =~ s/(\$\w+)/$1/eeg; #interpolate $cmd 17048c2ecf20Sopenharmony_ci @commits = vcs_save_commits($cmd); 17058c2ecf20Sopenharmony_ci } 17068c2ecf20Sopenharmony_ci 17078c2ecf20Sopenharmony_ci foreach my $commit (@commits) { 17088c2ecf20Sopenharmony_ci $commit =~ s/^\^//g; 17098c2ecf20Sopenharmony_ci } 17108c2ecf20Sopenharmony_ci 17118c2ecf20Sopenharmony_ci return @commits; 17128c2ecf20Sopenharmony_ci} 17138c2ecf20Sopenharmony_ci 17148c2ecf20Sopenharmony_cimy $printed_novcs = 0; 17158c2ecf20Sopenharmony_cisub vcs_exists { 17168c2ecf20Sopenharmony_ci %VCS_cmds = %VCS_cmds_git; 17178c2ecf20Sopenharmony_ci return 1 if eval $VCS_cmds{"available"}; 17188c2ecf20Sopenharmony_ci %VCS_cmds = %VCS_cmds_hg; 17198c2ecf20Sopenharmony_ci return 2 if eval $VCS_cmds{"available"}; 17208c2ecf20Sopenharmony_ci %VCS_cmds = (); 17218c2ecf20Sopenharmony_ci if (!$printed_novcs) { 17228c2ecf20Sopenharmony_ci warn("$P: No supported VCS found. Add --nogit to options?\n"); 17238c2ecf20Sopenharmony_ci warn("Using a git repository produces better results.\n"); 17248c2ecf20Sopenharmony_ci warn("Try Linus Torvalds' latest git repository using:\n"); 17258c2ecf20Sopenharmony_ci warn("git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git\n"); 17268c2ecf20Sopenharmony_ci $printed_novcs = 1; 17278c2ecf20Sopenharmony_ci } 17288c2ecf20Sopenharmony_ci return 0; 17298c2ecf20Sopenharmony_ci} 17308c2ecf20Sopenharmony_ci 17318c2ecf20Sopenharmony_cisub vcs_is_git { 17328c2ecf20Sopenharmony_ci vcs_exists(); 17338c2ecf20Sopenharmony_ci return $vcs_used == 1; 17348c2ecf20Sopenharmony_ci} 17358c2ecf20Sopenharmony_ci 17368c2ecf20Sopenharmony_cisub vcs_is_hg { 17378c2ecf20Sopenharmony_ci return $vcs_used == 2; 17388c2ecf20Sopenharmony_ci} 17398c2ecf20Sopenharmony_ci 17408c2ecf20Sopenharmony_cisub vcs_add_commit_signers { 17418c2ecf20Sopenharmony_ci return if (!vcs_exists()); 17428c2ecf20Sopenharmony_ci 17438c2ecf20Sopenharmony_ci my ($commit, $desc) = @_; 17448c2ecf20Sopenharmony_ci my $commit_count = 0; 17458c2ecf20Sopenharmony_ci my $commit_authors_ref; 17468c2ecf20Sopenharmony_ci my $commit_signers_ref; 17478c2ecf20Sopenharmony_ci my $stats_ref; 17488c2ecf20Sopenharmony_ci my @commit_authors = (); 17498c2ecf20Sopenharmony_ci my @commit_signers = (); 17508c2ecf20Sopenharmony_ci my $cmd; 17518c2ecf20Sopenharmony_ci 17528c2ecf20Sopenharmony_ci $cmd = $VCS_cmds{"find_commit_signers_cmd"}; 17538c2ecf20Sopenharmony_ci $cmd =~ s/(\$\w+)/$1/eeg; #substitute variables in $cmd 17548c2ecf20Sopenharmony_ci 17558c2ecf20Sopenharmony_ci ($commit_count, $commit_signers_ref, $commit_authors_ref, $stats_ref) = vcs_find_signers($cmd, ""); 17568c2ecf20Sopenharmony_ci @commit_authors = @{$commit_authors_ref} if defined $commit_authors_ref; 17578c2ecf20Sopenharmony_ci @commit_signers = @{$commit_signers_ref} if defined $commit_signers_ref; 17588c2ecf20Sopenharmony_ci 17598c2ecf20Sopenharmony_ci foreach my $signer (@commit_signers) { 17608c2ecf20Sopenharmony_ci $signer = deduplicate_email($signer); 17618c2ecf20Sopenharmony_ci } 17628c2ecf20Sopenharmony_ci 17638c2ecf20Sopenharmony_ci vcs_assign($desc, 1, @commit_signers); 17648c2ecf20Sopenharmony_ci} 17658c2ecf20Sopenharmony_ci 17668c2ecf20Sopenharmony_cisub interactive_get_maintainers { 17678c2ecf20Sopenharmony_ci my ($list_ref) = @_; 17688c2ecf20Sopenharmony_ci my @list = @$list_ref; 17698c2ecf20Sopenharmony_ci 17708c2ecf20Sopenharmony_ci vcs_exists(); 17718c2ecf20Sopenharmony_ci 17728c2ecf20Sopenharmony_ci my %selected; 17738c2ecf20Sopenharmony_ci my %authored; 17748c2ecf20Sopenharmony_ci my %signed; 17758c2ecf20Sopenharmony_ci my $count = 0; 17768c2ecf20Sopenharmony_ci my $maintained = 0; 17778c2ecf20Sopenharmony_ci foreach my $entry (@list) { 17788c2ecf20Sopenharmony_ci $maintained = 1 if ($entry->[1] =~ /^(maintainer|supporter)/i); 17798c2ecf20Sopenharmony_ci $selected{$count} = 1; 17808c2ecf20Sopenharmony_ci $authored{$count} = 0; 17818c2ecf20Sopenharmony_ci $signed{$count} = 0; 17828c2ecf20Sopenharmony_ci $count++; 17838c2ecf20Sopenharmony_ci } 17848c2ecf20Sopenharmony_ci 17858c2ecf20Sopenharmony_ci #menu loop 17868c2ecf20Sopenharmony_ci my $done = 0; 17878c2ecf20Sopenharmony_ci my $print_options = 0; 17888c2ecf20Sopenharmony_ci my $redraw = 1; 17898c2ecf20Sopenharmony_ci while (!$done) { 17908c2ecf20Sopenharmony_ci $count = 0; 17918c2ecf20Sopenharmony_ci if ($redraw) { 17928c2ecf20Sopenharmony_ci printf STDERR "\n%1s %2s %-65s", 17938c2ecf20Sopenharmony_ci "*", "#", "email/list and role:stats"; 17948c2ecf20Sopenharmony_ci if ($email_git || 17958c2ecf20Sopenharmony_ci ($email_git_fallback && !$maintained) || 17968c2ecf20Sopenharmony_ci $email_git_blame) { 17978c2ecf20Sopenharmony_ci print STDERR "auth sign"; 17988c2ecf20Sopenharmony_ci } 17998c2ecf20Sopenharmony_ci print STDERR "\n"; 18008c2ecf20Sopenharmony_ci foreach my $entry (@list) { 18018c2ecf20Sopenharmony_ci my $email = $entry->[0]; 18028c2ecf20Sopenharmony_ci my $role = $entry->[1]; 18038c2ecf20Sopenharmony_ci my $sel = ""; 18048c2ecf20Sopenharmony_ci $sel = "*" if ($selected{$count}); 18058c2ecf20Sopenharmony_ci my $commit_author = $commit_author_hash{$email}; 18068c2ecf20Sopenharmony_ci my $commit_signer = $commit_signer_hash{$email}; 18078c2ecf20Sopenharmony_ci my $authored = 0; 18088c2ecf20Sopenharmony_ci my $signed = 0; 18098c2ecf20Sopenharmony_ci $authored++ for (@{$commit_author}); 18108c2ecf20Sopenharmony_ci $signed++ for (@{$commit_signer}); 18118c2ecf20Sopenharmony_ci printf STDERR "%1s %2d %-65s", $sel, $count + 1, $email; 18128c2ecf20Sopenharmony_ci printf STDERR "%4d %4d", $authored, $signed 18138c2ecf20Sopenharmony_ci if ($authored > 0 || $signed > 0); 18148c2ecf20Sopenharmony_ci printf STDERR "\n %s\n", $role; 18158c2ecf20Sopenharmony_ci if ($authored{$count}) { 18168c2ecf20Sopenharmony_ci my $commit_author = $commit_author_hash{$email}; 18178c2ecf20Sopenharmony_ci foreach my $ref (@{$commit_author}) { 18188c2ecf20Sopenharmony_ci print STDERR " Author: @{$ref}[1]\n"; 18198c2ecf20Sopenharmony_ci } 18208c2ecf20Sopenharmony_ci } 18218c2ecf20Sopenharmony_ci if ($signed{$count}) { 18228c2ecf20Sopenharmony_ci my $commit_signer = $commit_signer_hash{$email}; 18238c2ecf20Sopenharmony_ci foreach my $ref (@{$commit_signer}) { 18248c2ecf20Sopenharmony_ci print STDERR " @{$ref}[2]: @{$ref}[1]\n"; 18258c2ecf20Sopenharmony_ci } 18268c2ecf20Sopenharmony_ci } 18278c2ecf20Sopenharmony_ci 18288c2ecf20Sopenharmony_ci $count++; 18298c2ecf20Sopenharmony_ci } 18308c2ecf20Sopenharmony_ci } 18318c2ecf20Sopenharmony_ci my $date_ref = \$email_git_since; 18328c2ecf20Sopenharmony_ci $date_ref = \$email_hg_since if (vcs_is_hg()); 18338c2ecf20Sopenharmony_ci if ($print_options) { 18348c2ecf20Sopenharmony_ci $print_options = 0; 18358c2ecf20Sopenharmony_ci if (vcs_exists()) { 18368c2ecf20Sopenharmony_ci print STDERR <<EOT 18378c2ecf20Sopenharmony_ci 18388c2ecf20Sopenharmony_ciVersion Control options: 18398c2ecf20Sopenharmony_cig use git history [$email_git] 18408c2ecf20Sopenharmony_cigf use git-fallback [$email_git_fallback] 18418c2ecf20Sopenharmony_cib use git blame [$email_git_blame] 18428c2ecf20Sopenharmony_cibs use blame signatures [$email_git_blame_signatures] 18438c2ecf20Sopenharmony_cic# minimum commits [$email_git_min_signatures] 18448c2ecf20Sopenharmony_ci%# min percent [$email_git_min_percent] 18458c2ecf20Sopenharmony_cid# history to use [$$date_ref] 18468c2ecf20Sopenharmony_cix# max maintainers [$email_git_max_maintainers] 18478c2ecf20Sopenharmony_cit all signature types [$email_git_all_signature_types] 18488c2ecf20Sopenharmony_cim use .mailmap [$email_use_mailmap] 18498c2ecf20Sopenharmony_ciEOT 18508c2ecf20Sopenharmony_ci } 18518c2ecf20Sopenharmony_ci print STDERR <<EOT 18528c2ecf20Sopenharmony_ci 18538c2ecf20Sopenharmony_ciAdditional options: 18548c2ecf20Sopenharmony_ci0 toggle all 18558c2ecf20Sopenharmony_citm toggle maintainers 18568c2ecf20Sopenharmony_citg toggle git entries 18578c2ecf20Sopenharmony_citl toggle open list entries 18588c2ecf20Sopenharmony_cits toggle subscriber list entries 18598c2ecf20Sopenharmony_cif emails in file [$email_file_emails] 18608c2ecf20Sopenharmony_cik keywords in file [$keywords] 18618c2ecf20Sopenharmony_cir remove duplicates [$email_remove_duplicates] 18628c2ecf20Sopenharmony_cip# pattern match depth [$pattern_depth] 18638c2ecf20Sopenharmony_ciEOT 18648c2ecf20Sopenharmony_ci } 18658c2ecf20Sopenharmony_ci print STDERR 18668c2ecf20Sopenharmony_ci"\n#(toggle), A#(author), S#(signed) *(all), ^(none), O(options), Y(approve): "; 18678c2ecf20Sopenharmony_ci 18688c2ecf20Sopenharmony_ci my $input = <STDIN>; 18698c2ecf20Sopenharmony_ci chomp($input); 18708c2ecf20Sopenharmony_ci 18718c2ecf20Sopenharmony_ci $redraw = 1; 18728c2ecf20Sopenharmony_ci my $rerun = 0; 18738c2ecf20Sopenharmony_ci my @wish = split(/[, ]+/, $input); 18748c2ecf20Sopenharmony_ci foreach my $nr (@wish) { 18758c2ecf20Sopenharmony_ci $nr = lc($nr); 18768c2ecf20Sopenharmony_ci my $sel = substr($nr, 0, 1); 18778c2ecf20Sopenharmony_ci my $str = substr($nr, 1); 18788c2ecf20Sopenharmony_ci my $val = 0; 18798c2ecf20Sopenharmony_ci $val = $1 if $str =~ /^(\d+)$/; 18808c2ecf20Sopenharmony_ci 18818c2ecf20Sopenharmony_ci if ($sel eq "y") { 18828c2ecf20Sopenharmony_ci $interactive = 0; 18838c2ecf20Sopenharmony_ci $done = 1; 18848c2ecf20Sopenharmony_ci $output_rolestats = 0; 18858c2ecf20Sopenharmony_ci $output_roles = 0; 18868c2ecf20Sopenharmony_ci last; 18878c2ecf20Sopenharmony_ci } elsif ($nr =~ /^\d+$/ && $nr > 0 && $nr <= $count) { 18888c2ecf20Sopenharmony_ci $selected{$nr - 1} = !$selected{$nr - 1}; 18898c2ecf20Sopenharmony_ci } elsif ($sel eq "*" || $sel eq '^') { 18908c2ecf20Sopenharmony_ci my $toggle = 0; 18918c2ecf20Sopenharmony_ci $toggle = 1 if ($sel eq '*'); 18928c2ecf20Sopenharmony_ci for (my $i = 0; $i < $count; $i++) { 18938c2ecf20Sopenharmony_ci $selected{$i} = $toggle; 18948c2ecf20Sopenharmony_ci } 18958c2ecf20Sopenharmony_ci } elsif ($sel eq "0") { 18968c2ecf20Sopenharmony_ci for (my $i = 0; $i < $count; $i++) { 18978c2ecf20Sopenharmony_ci $selected{$i} = !$selected{$i}; 18988c2ecf20Sopenharmony_ci } 18998c2ecf20Sopenharmony_ci } elsif ($sel eq "t") { 19008c2ecf20Sopenharmony_ci if (lc($str) eq "m") { 19018c2ecf20Sopenharmony_ci for (my $i = 0; $i < $count; $i++) { 19028c2ecf20Sopenharmony_ci $selected{$i} = !$selected{$i} 19038c2ecf20Sopenharmony_ci if ($list[$i]->[1] =~ /^(maintainer|supporter)/i); 19048c2ecf20Sopenharmony_ci } 19058c2ecf20Sopenharmony_ci } elsif (lc($str) eq "g") { 19068c2ecf20Sopenharmony_ci for (my $i = 0; $i < $count; $i++) { 19078c2ecf20Sopenharmony_ci $selected{$i} = !$selected{$i} 19088c2ecf20Sopenharmony_ci if ($list[$i]->[1] =~ /^(author|commit|signer)/i); 19098c2ecf20Sopenharmony_ci } 19108c2ecf20Sopenharmony_ci } elsif (lc($str) eq "l") { 19118c2ecf20Sopenharmony_ci for (my $i = 0; $i < $count; $i++) { 19128c2ecf20Sopenharmony_ci $selected{$i} = !$selected{$i} 19138c2ecf20Sopenharmony_ci if ($list[$i]->[1] =~ /^(open list)/i); 19148c2ecf20Sopenharmony_ci } 19158c2ecf20Sopenharmony_ci } elsif (lc($str) eq "s") { 19168c2ecf20Sopenharmony_ci for (my $i = 0; $i < $count; $i++) { 19178c2ecf20Sopenharmony_ci $selected{$i} = !$selected{$i} 19188c2ecf20Sopenharmony_ci if ($list[$i]->[1] =~ /^(subscriber list)/i); 19198c2ecf20Sopenharmony_ci } 19208c2ecf20Sopenharmony_ci } 19218c2ecf20Sopenharmony_ci } elsif ($sel eq "a") { 19228c2ecf20Sopenharmony_ci if ($val > 0 && $val <= $count) { 19238c2ecf20Sopenharmony_ci $authored{$val - 1} = !$authored{$val - 1}; 19248c2ecf20Sopenharmony_ci } elsif ($str eq '*' || $str eq '^') { 19258c2ecf20Sopenharmony_ci my $toggle = 0; 19268c2ecf20Sopenharmony_ci $toggle = 1 if ($str eq '*'); 19278c2ecf20Sopenharmony_ci for (my $i = 0; $i < $count; $i++) { 19288c2ecf20Sopenharmony_ci $authored{$i} = $toggle; 19298c2ecf20Sopenharmony_ci } 19308c2ecf20Sopenharmony_ci } 19318c2ecf20Sopenharmony_ci } elsif ($sel eq "s") { 19328c2ecf20Sopenharmony_ci if ($val > 0 && $val <= $count) { 19338c2ecf20Sopenharmony_ci $signed{$val - 1} = !$signed{$val - 1}; 19348c2ecf20Sopenharmony_ci } elsif ($str eq '*' || $str eq '^') { 19358c2ecf20Sopenharmony_ci my $toggle = 0; 19368c2ecf20Sopenharmony_ci $toggle = 1 if ($str eq '*'); 19378c2ecf20Sopenharmony_ci for (my $i = 0; $i < $count; $i++) { 19388c2ecf20Sopenharmony_ci $signed{$i} = $toggle; 19398c2ecf20Sopenharmony_ci } 19408c2ecf20Sopenharmony_ci } 19418c2ecf20Sopenharmony_ci } elsif ($sel eq "o") { 19428c2ecf20Sopenharmony_ci $print_options = 1; 19438c2ecf20Sopenharmony_ci $redraw = 1; 19448c2ecf20Sopenharmony_ci } elsif ($sel eq "g") { 19458c2ecf20Sopenharmony_ci if ($str eq "f") { 19468c2ecf20Sopenharmony_ci bool_invert(\$email_git_fallback); 19478c2ecf20Sopenharmony_ci } else { 19488c2ecf20Sopenharmony_ci bool_invert(\$email_git); 19498c2ecf20Sopenharmony_ci } 19508c2ecf20Sopenharmony_ci $rerun = 1; 19518c2ecf20Sopenharmony_ci } elsif ($sel eq "b") { 19528c2ecf20Sopenharmony_ci if ($str eq "s") { 19538c2ecf20Sopenharmony_ci bool_invert(\$email_git_blame_signatures); 19548c2ecf20Sopenharmony_ci } else { 19558c2ecf20Sopenharmony_ci bool_invert(\$email_git_blame); 19568c2ecf20Sopenharmony_ci } 19578c2ecf20Sopenharmony_ci $rerun = 1; 19588c2ecf20Sopenharmony_ci } elsif ($sel eq "c") { 19598c2ecf20Sopenharmony_ci if ($val > 0) { 19608c2ecf20Sopenharmony_ci $email_git_min_signatures = $val; 19618c2ecf20Sopenharmony_ci $rerun = 1; 19628c2ecf20Sopenharmony_ci } 19638c2ecf20Sopenharmony_ci } elsif ($sel eq "x") { 19648c2ecf20Sopenharmony_ci if ($val > 0) { 19658c2ecf20Sopenharmony_ci $email_git_max_maintainers = $val; 19668c2ecf20Sopenharmony_ci $rerun = 1; 19678c2ecf20Sopenharmony_ci } 19688c2ecf20Sopenharmony_ci } elsif ($sel eq "%") { 19698c2ecf20Sopenharmony_ci if ($str ne "" && $val >= 0) { 19708c2ecf20Sopenharmony_ci $email_git_min_percent = $val; 19718c2ecf20Sopenharmony_ci $rerun = 1; 19728c2ecf20Sopenharmony_ci } 19738c2ecf20Sopenharmony_ci } elsif ($sel eq "d") { 19748c2ecf20Sopenharmony_ci if (vcs_is_git()) { 19758c2ecf20Sopenharmony_ci $email_git_since = $str; 19768c2ecf20Sopenharmony_ci } elsif (vcs_is_hg()) { 19778c2ecf20Sopenharmony_ci $email_hg_since = $str; 19788c2ecf20Sopenharmony_ci } 19798c2ecf20Sopenharmony_ci $rerun = 1; 19808c2ecf20Sopenharmony_ci } elsif ($sel eq "t") { 19818c2ecf20Sopenharmony_ci bool_invert(\$email_git_all_signature_types); 19828c2ecf20Sopenharmony_ci $rerun = 1; 19838c2ecf20Sopenharmony_ci } elsif ($sel eq "f") { 19848c2ecf20Sopenharmony_ci bool_invert(\$email_file_emails); 19858c2ecf20Sopenharmony_ci $rerun = 1; 19868c2ecf20Sopenharmony_ci } elsif ($sel eq "r") { 19878c2ecf20Sopenharmony_ci bool_invert(\$email_remove_duplicates); 19888c2ecf20Sopenharmony_ci $rerun = 1; 19898c2ecf20Sopenharmony_ci } elsif ($sel eq "m") { 19908c2ecf20Sopenharmony_ci bool_invert(\$email_use_mailmap); 19918c2ecf20Sopenharmony_ci read_mailmap(); 19928c2ecf20Sopenharmony_ci $rerun = 1; 19938c2ecf20Sopenharmony_ci } elsif ($sel eq "k") { 19948c2ecf20Sopenharmony_ci bool_invert(\$keywords); 19958c2ecf20Sopenharmony_ci $rerun = 1; 19968c2ecf20Sopenharmony_ci } elsif ($sel eq "p") { 19978c2ecf20Sopenharmony_ci if ($str ne "" && $val >= 0) { 19988c2ecf20Sopenharmony_ci $pattern_depth = $val; 19998c2ecf20Sopenharmony_ci $rerun = 1; 20008c2ecf20Sopenharmony_ci } 20018c2ecf20Sopenharmony_ci } elsif ($sel eq "h" || $sel eq "?") { 20028c2ecf20Sopenharmony_ci print STDERR <<EOT 20038c2ecf20Sopenharmony_ci 20048c2ecf20Sopenharmony_ciInteractive mode allows you to select the various maintainers, submitters, 20058c2ecf20Sopenharmony_cicommit signers and mailing lists that could be CC'd on a patch. 20068c2ecf20Sopenharmony_ci 20078c2ecf20Sopenharmony_ciAny *'d entry is selected. 20088c2ecf20Sopenharmony_ci 20098c2ecf20Sopenharmony_ciIf you have git or hg installed, you can choose to summarize the commit 20108c2ecf20Sopenharmony_cihistory of files in the patch. Also, each line of the current file can 20118c2ecf20Sopenharmony_cibe matched to its commit author and that commits signers with blame. 20128c2ecf20Sopenharmony_ci 20138c2ecf20Sopenharmony_ciVarious knobs exist to control the length of time for active commit 20148c2ecf20Sopenharmony_citracking, the maximum number of commit authors and signers to add, 20158c2ecf20Sopenharmony_ciand such. 20168c2ecf20Sopenharmony_ci 20178c2ecf20Sopenharmony_ciEnter selections at the prompt until you are satisfied that the selected 20188c2ecf20Sopenharmony_cimaintainers are appropriate. You may enter multiple selections separated 20198c2ecf20Sopenharmony_ciby either commas or spaces. 20208c2ecf20Sopenharmony_ci 20218c2ecf20Sopenharmony_ciEOT 20228c2ecf20Sopenharmony_ci } else { 20238c2ecf20Sopenharmony_ci print STDERR "invalid option: '$nr'\n"; 20248c2ecf20Sopenharmony_ci $redraw = 0; 20258c2ecf20Sopenharmony_ci } 20268c2ecf20Sopenharmony_ci } 20278c2ecf20Sopenharmony_ci if ($rerun) { 20288c2ecf20Sopenharmony_ci print STDERR "git-blame can be very slow, please have patience..." 20298c2ecf20Sopenharmony_ci if ($email_git_blame); 20308c2ecf20Sopenharmony_ci goto &get_maintainers; 20318c2ecf20Sopenharmony_ci } 20328c2ecf20Sopenharmony_ci } 20338c2ecf20Sopenharmony_ci 20348c2ecf20Sopenharmony_ci #drop not selected entries 20358c2ecf20Sopenharmony_ci $count = 0; 20368c2ecf20Sopenharmony_ci my @new_emailto = (); 20378c2ecf20Sopenharmony_ci foreach my $entry (@list) { 20388c2ecf20Sopenharmony_ci if ($selected{$count}) { 20398c2ecf20Sopenharmony_ci push(@new_emailto, $list[$count]); 20408c2ecf20Sopenharmony_ci } 20418c2ecf20Sopenharmony_ci $count++; 20428c2ecf20Sopenharmony_ci } 20438c2ecf20Sopenharmony_ci return @new_emailto; 20448c2ecf20Sopenharmony_ci} 20458c2ecf20Sopenharmony_ci 20468c2ecf20Sopenharmony_cisub bool_invert { 20478c2ecf20Sopenharmony_ci my ($bool_ref) = @_; 20488c2ecf20Sopenharmony_ci 20498c2ecf20Sopenharmony_ci if ($$bool_ref) { 20508c2ecf20Sopenharmony_ci $$bool_ref = 0; 20518c2ecf20Sopenharmony_ci } else { 20528c2ecf20Sopenharmony_ci $$bool_ref = 1; 20538c2ecf20Sopenharmony_ci } 20548c2ecf20Sopenharmony_ci} 20558c2ecf20Sopenharmony_ci 20568c2ecf20Sopenharmony_cisub deduplicate_email { 20578c2ecf20Sopenharmony_ci my ($email) = @_; 20588c2ecf20Sopenharmony_ci 20598c2ecf20Sopenharmony_ci my $matched = 0; 20608c2ecf20Sopenharmony_ci my ($name, $address) = parse_email($email); 20618c2ecf20Sopenharmony_ci $email = format_email($name, $address, 1); 20628c2ecf20Sopenharmony_ci $email = mailmap_email($email); 20638c2ecf20Sopenharmony_ci 20648c2ecf20Sopenharmony_ci return $email if (!$email_remove_duplicates); 20658c2ecf20Sopenharmony_ci 20668c2ecf20Sopenharmony_ci ($name, $address) = parse_email($email); 20678c2ecf20Sopenharmony_ci 20688c2ecf20Sopenharmony_ci if ($name ne "" && $deduplicate_name_hash{lc($name)}) { 20698c2ecf20Sopenharmony_ci $name = $deduplicate_name_hash{lc($name)}->[0]; 20708c2ecf20Sopenharmony_ci $address = $deduplicate_name_hash{lc($name)}->[1]; 20718c2ecf20Sopenharmony_ci $matched = 1; 20728c2ecf20Sopenharmony_ci } elsif ($deduplicate_address_hash{lc($address)}) { 20738c2ecf20Sopenharmony_ci $name = $deduplicate_address_hash{lc($address)}->[0]; 20748c2ecf20Sopenharmony_ci $address = $deduplicate_address_hash{lc($address)}->[1]; 20758c2ecf20Sopenharmony_ci $matched = 1; 20768c2ecf20Sopenharmony_ci } 20778c2ecf20Sopenharmony_ci if (!$matched) { 20788c2ecf20Sopenharmony_ci $deduplicate_name_hash{lc($name)} = [ $name, $address ]; 20798c2ecf20Sopenharmony_ci $deduplicate_address_hash{lc($address)} = [ $name, $address ]; 20808c2ecf20Sopenharmony_ci } 20818c2ecf20Sopenharmony_ci $email = format_email($name, $address, 1); 20828c2ecf20Sopenharmony_ci $email = mailmap_email($email); 20838c2ecf20Sopenharmony_ci return $email; 20848c2ecf20Sopenharmony_ci} 20858c2ecf20Sopenharmony_ci 20868c2ecf20Sopenharmony_cisub save_commits_by_author { 20878c2ecf20Sopenharmony_ci my (@lines) = @_; 20888c2ecf20Sopenharmony_ci 20898c2ecf20Sopenharmony_ci my @authors = (); 20908c2ecf20Sopenharmony_ci my @commits = (); 20918c2ecf20Sopenharmony_ci my @subjects = (); 20928c2ecf20Sopenharmony_ci 20938c2ecf20Sopenharmony_ci foreach my $line (@lines) { 20948c2ecf20Sopenharmony_ci if ($line =~ m/$VCS_cmds{"author_pattern"}/) { 20958c2ecf20Sopenharmony_ci my $author = $1; 20968c2ecf20Sopenharmony_ci $author = deduplicate_email($author); 20978c2ecf20Sopenharmony_ci push(@authors, $author); 20988c2ecf20Sopenharmony_ci } 20998c2ecf20Sopenharmony_ci push(@commits, $1) if ($line =~ m/$VCS_cmds{"commit_pattern"}/); 21008c2ecf20Sopenharmony_ci push(@subjects, $1) if ($line =~ m/$VCS_cmds{"subject_pattern"}/); 21018c2ecf20Sopenharmony_ci } 21028c2ecf20Sopenharmony_ci 21038c2ecf20Sopenharmony_ci for (my $i = 0; $i < @authors; $i++) { 21048c2ecf20Sopenharmony_ci my $exists = 0; 21058c2ecf20Sopenharmony_ci foreach my $ref(@{$commit_author_hash{$authors[$i]}}) { 21068c2ecf20Sopenharmony_ci if (@{$ref}[0] eq $commits[$i] && 21078c2ecf20Sopenharmony_ci @{$ref}[1] eq $subjects[$i]) { 21088c2ecf20Sopenharmony_ci $exists = 1; 21098c2ecf20Sopenharmony_ci last; 21108c2ecf20Sopenharmony_ci } 21118c2ecf20Sopenharmony_ci } 21128c2ecf20Sopenharmony_ci if (!$exists) { 21138c2ecf20Sopenharmony_ci push(@{$commit_author_hash{$authors[$i]}}, 21148c2ecf20Sopenharmony_ci [ ($commits[$i], $subjects[$i]) ]); 21158c2ecf20Sopenharmony_ci } 21168c2ecf20Sopenharmony_ci } 21178c2ecf20Sopenharmony_ci} 21188c2ecf20Sopenharmony_ci 21198c2ecf20Sopenharmony_cisub save_commits_by_signer { 21208c2ecf20Sopenharmony_ci my (@lines) = @_; 21218c2ecf20Sopenharmony_ci 21228c2ecf20Sopenharmony_ci my $commit = ""; 21238c2ecf20Sopenharmony_ci my $subject = ""; 21248c2ecf20Sopenharmony_ci 21258c2ecf20Sopenharmony_ci foreach my $line (@lines) { 21268c2ecf20Sopenharmony_ci $commit = $1 if ($line =~ m/$VCS_cmds{"commit_pattern"}/); 21278c2ecf20Sopenharmony_ci $subject = $1 if ($line =~ m/$VCS_cmds{"subject_pattern"}/); 21288c2ecf20Sopenharmony_ci if ($line =~ /^[ \t]*${signature_pattern}.*\@.*$/) { 21298c2ecf20Sopenharmony_ci my @signatures = ($line); 21308c2ecf20Sopenharmony_ci my ($types_ref, $signers_ref) = extract_formatted_signatures(@signatures); 21318c2ecf20Sopenharmony_ci my @types = @$types_ref; 21328c2ecf20Sopenharmony_ci my @signers = @$signers_ref; 21338c2ecf20Sopenharmony_ci 21348c2ecf20Sopenharmony_ci my $type = $types[0]; 21358c2ecf20Sopenharmony_ci my $signer = $signers[0]; 21368c2ecf20Sopenharmony_ci 21378c2ecf20Sopenharmony_ci $signer = deduplicate_email($signer); 21388c2ecf20Sopenharmony_ci 21398c2ecf20Sopenharmony_ci my $exists = 0; 21408c2ecf20Sopenharmony_ci foreach my $ref(@{$commit_signer_hash{$signer}}) { 21418c2ecf20Sopenharmony_ci if (@{$ref}[0] eq $commit && 21428c2ecf20Sopenharmony_ci @{$ref}[1] eq $subject && 21438c2ecf20Sopenharmony_ci @{$ref}[2] eq $type) { 21448c2ecf20Sopenharmony_ci $exists = 1; 21458c2ecf20Sopenharmony_ci last; 21468c2ecf20Sopenharmony_ci } 21478c2ecf20Sopenharmony_ci } 21488c2ecf20Sopenharmony_ci if (!$exists) { 21498c2ecf20Sopenharmony_ci push(@{$commit_signer_hash{$signer}}, 21508c2ecf20Sopenharmony_ci [ ($commit, $subject, $type) ]); 21518c2ecf20Sopenharmony_ci } 21528c2ecf20Sopenharmony_ci } 21538c2ecf20Sopenharmony_ci } 21548c2ecf20Sopenharmony_ci} 21558c2ecf20Sopenharmony_ci 21568c2ecf20Sopenharmony_cisub vcs_assign { 21578c2ecf20Sopenharmony_ci my ($role, $divisor, @lines) = @_; 21588c2ecf20Sopenharmony_ci 21598c2ecf20Sopenharmony_ci my %hash; 21608c2ecf20Sopenharmony_ci my $count = 0; 21618c2ecf20Sopenharmony_ci 21628c2ecf20Sopenharmony_ci return if (@lines <= 0); 21638c2ecf20Sopenharmony_ci 21648c2ecf20Sopenharmony_ci if ($divisor <= 0) { 21658c2ecf20Sopenharmony_ci warn("Bad divisor in " . (caller(0))[3] . ": $divisor\n"); 21668c2ecf20Sopenharmony_ci $divisor = 1; 21678c2ecf20Sopenharmony_ci } 21688c2ecf20Sopenharmony_ci 21698c2ecf20Sopenharmony_ci @lines = mailmap(@lines); 21708c2ecf20Sopenharmony_ci 21718c2ecf20Sopenharmony_ci return if (@lines <= 0); 21728c2ecf20Sopenharmony_ci 21738c2ecf20Sopenharmony_ci @lines = sort(@lines); 21748c2ecf20Sopenharmony_ci 21758c2ecf20Sopenharmony_ci # uniq -c 21768c2ecf20Sopenharmony_ci $hash{$_}++ for @lines; 21778c2ecf20Sopenharmony_ci 21788c2ecf20Sopenharmony_ci # sort -rn 21798c2ecf20Sopenharmony_ci foreach my $line (sort {$hash{$b} <=> $hash{$a}} keys %hash) { 21808c2ecf20Sopenharmony_ci my $sign_offs = $hash{$line}; 21818c2ecf20Sopenharmony_ci my $percent = $sign_offs * 100 / $divisor; 21828c2ecf20Sopenharmony_ci 21838c2ecf20Sopenharmony_ci $percent = 100 if ($percent > 100); 21848c2ecf20Sopenharmony_ci next if (ignore_email_address($line)); 21858c2ecf20Sopenharmony_ci $count++; 21868c2ecf20Sopenharmony_ci last if ($sign_offs < $email_git_min_signatures || 21878c2ecf20Sopenharmony_ci $count > $email_git_max_maintainers || 21888c2ecf20Sopenharmony_ci $percent < $email_git_min_percent); 21898c2ecf20Sopenharmony_ci push_email_address($line, ''); 21908c2ecf20Sopenharmony_ci if ($output_rolestats) { 21918c2ecf20Sopenharmony_ci my $fmt_percent = sprintf("%.0f", $percent); 21928c2ecf20Sopenharmony_ci add_role($line, "$role:$sign_offs/$divisor=$fmt_percent%"); 21938c2ecf20Sopenharmony_ci } else { 21948c2ecf20Sopenharmony_ci add_role($line, $role); 21958c2ecf20Sopenharmony_ci } 21968c2ecf20Sopenharmony_ci } 21978c2ecf20Sopenharmony_ci} 21988c2ecf20Sopenharmony_ci 21998c2ecf20Sopenharmony_cisub vcs_file_signoffs { 22008c2ecf20Sopenharmony_ci my ($file) = @_; 22018c2ecf20Sopenharmony_ci 22028c2ecf20Sopenharmony_ci my $authors_ref; 22038c2ecf20Sopenharmony_ci my $signers_ref; 22048c2ecf20Sopenharmony_ci my $stats_ref; 22058c2ecf20Sopenharmony_ci my @authors = (); 22068c2ecf20Sopenharmony_ci my @signers = (); 22078c2ecf20Sopenharmony_ci my @stats = (); 22088c2ecf20Sopenharmony_ci my $commits; 22098c2ecf20Sopenharmony_ci 22108c2ecf20Sopenharmony_ci $vcs_used = vcs_exists(); 22118c2ecf20Sopenharmony_ci return if (!$vcs_used); 22128c2ecf20Sopenharmony_ci 22138c2ecf20Sopenharmony_ci my $cmd = $VCS_cmds{"find_signers_cmd"}; 22148c2ecf20Sopenharmony_ci $cmd =~ s/(\$\w+)/$1/eeg; # interpolate $cmd 22158c2ecf20Sopenharmony_ci 22168c2ecf20Sopenharmony_ci ($commits, $signers_ref, $authors_ref, $stats_ref) = vcs_find_signers($cmd, $file); 22178c2ecf20Sopenharmony_ci 22188c2ecf20Sopenharmony_ci @signers = @{$signers_ref} if defined $signers_ref; 22198c2ecf20Sopenharmony_ci @authors = @{$authors_ref} if defined $authors_ref; 22208c2ecf20Sopenharmony_ci @stats = @{$stats_ref} if defined $stats_ref; 22218c2ecf20Sopenharmony_ci 22228c2ecf20Sopenharmony_ci# print("commits: <$commits>\nsigners:<@signers>\nauthors: <@authors>\nstats: <@stats>\n"); 22238c2ecf20Sopenharmony_ci 22248c2ecf20Sopenharmony_ci foreach my $signer (@signers) { 22258c2ecf20Sopenharmony_ci $signer = deduplicate_email($signer); 22268c2ecf20Sopenharmony_ci } 22278c2ecf20Sopenharmony_ci 22288c2ecf20Sopenharmony_ci vcs_assign("commit_signer", $commits, @signers); 22298c2ecf20Sopenharmony_ci vcs_assign("authored", $commits, @authors); 22308c2ecf20Sopenharmony_ci if ($#authors == $#stats) { 22318c2ecf20Sopenharmony_ci my $stat_pattern = $VCS_cmds{"stat_pattern"}; 22328c2ecf20Sopenharmony_ci $stat_pattern =~ s/(\$\w+)/$1/eeg; #interpolate $stat_pattern 22338c2ecf20Sopenharmony_ci 22348c2ecf20Sopenharmony_ci my $added = 0; 22358c2ecf20Sopenharmony_ci my $deleted = 0; 22368c2ecf20Sopenharmony_ci for (my $i = 0; $i <= $#stats; $i++) { 22378c2ecf20Sopenharmony_ci if ($stats[$i] =~ /$stat_pattern/) { 22388c2ecf20Sopenharmony_ci $added += $1; 22398c2ecf20Sopenharmony_ci $deleted += $2; 22408c2ecf20Sopenharmony_ci } 22418c2ecf20Sopenharmony_ci } 22428c2ecf20Sopenharmony_ci my @tmp_authors = uniq(@authors); 22438c2ecf20Sopenharmony_ci foreach my $author (@tmp_authors) { 22448c2ecf20Sopenharmony_ci $author = deduplicate_email($author); 22458c2ecf20Sopenharmony_ci } 22468c2ecf20Sopenharmony_ci @tmp_authors = uniq(@tmp_authors); 22478c2ecf20Sopenharmony_ci my @list_added = (); 22488c2ecf20Sopenharmony_ci my @list_deleted = (); 22498c2ecf20Sopenharmony_ci foreach my $author (@tmp_authors) { 22508c2ecf20Sopenharmony_ci my $auth_added = 0; 22518c2ecf20Sopenharmony_ci my $auth_deleted = 0; 22528c2ecf20Sopenharmony_ci for (my $i = 0; $i <= $#stats; $i++) { 22538c2ecf20Sopenharmony_ci if ($author eq deduplicate_email($authors[$i]) && 22548c2ecf20Sopenharmony_ci $stats[$i] =~ /$stat_pattern/) { 22558c2ecf20Sopenharmony_ci $auth_added += $1; 22568c2ecf20Sopenharmony_ci $auth_deleted += $2; 22578c2ecf20Sopenharmony_ci } 22588c2ecf20Sopenharmony_ci } 22598c2ecf20Sopenharmony_ci for (my $i = 0; $i < $auth_added; $i++) { 22608c2ecf20Sopenharmony_ci push(@list_added, $author); 22618c2ecf20Sopenharmony_ci } 22628c2ecf20Sopenharmony_ci for (my $i = 0; $i < $auth_deleted; $i++) { 22638c2ecf20Sopenharmony_ci push(@list_deleted, $author); 22648c2ecf20Sopenharmony_ci } 22658c2ecf20Sopenharmony_ci } 22668c2ecf20Sopenharmony_ci vcs_assign("added_lines", $added, @list_added); 22678c2ecf20Sopenharmony_ci vcs_assign("removed_lines", $deleted, @list_deleted); 22688c2ecf20Sopenharmony_ci } 22698c2ecf20Sopenharmony_ci} 22708c2ecf20Sopenharmony_ci 22718c2ecf20Sopenharmony_cisub vcs_file_blame { 22728c2ecf20Sopenharmony_ci my ($file) = @_; 22738c2ecf20Sopenharmony_ci 22748c2ecf20Sopenharmony_ci my @signers = (); 22758c2ecf20Sopenharmony_ci my @all_commits = (); 22768c2ecf20Sopenharmony_ci my @commits = (); 22778c2ecf20Sopenharmony_ci my $total_commits; 22788c2ecf20Sopenharmony_ci my $total_lines; 22798c2ecf20Sopenharmony_ci 22808c2ecf20Sopenharmony_ci $vcs_used = vcs_exists(); 22818c2ecf20Sopenharmony_ci return if (!$vcs_used); 22828c2ecf20Sopenharmony_ci 22838c2ecf20Sopenharmony_ci @all_commits = vcs_blame($file); 22848c2ecf20Sopenharmony_ci @commits = uniq(@all_commits); 22858c2ecf20Sopenharmony_ci $total_commits = @commits; 22868c2ecf20Sopenharmony_ci $total_lines = @all_commits; 22878c2ecf20Sopenharmony_ci 22888c2ecf20Sopenharmony_ci if ($email_git_blame_signatures) { 22898c2ecf20Sopenharmony_ci if (vcs_is_hg()) { 22908c2ecf20Sopenharmony_ci my $commit_count; 22918c2ecf20Sopenharmony_ci my $commit_authors_ref; 22928c2ecf20Sopenharmony_ci my $commit_signers_ref; 22938c2ecf20Sopenharmony_ci my $stats_ref; 22948c2ecf20Sopenharmony_ci my @commit_authors = (); 22958c2ecf20Sopenharmony_ci my @commit_signers = (); 22968c2ecf20Sopenharmony_ci my $commit = join(" -r ", @commits); 22978c2ecf20Sopenharmony_ci my $cmd; 22988c2ecf20Sopenharmony_ci 22998c2ecf20Sopenharmony_ci $cmd = $VCS_cmds{"find_commit_signers_cmd"}; 23008c2ecf20Sopenharmony_ci $cmd =~ s/(\$\w+)/$1/eeg; #substitute variables in $cmd 23018c2ecf20Sopenharmony_ci 23028c2ecf20Sopenharmony_ci ($commit_count, $commit_signers_ref, $commit_authors_ref, $stats_ref) = vcs_find_signers($cmd, $file); 23038c2ecf20Sopenharmony_ci @commit_authors = @{$commit_authors_ref} if defined $commit_authors_ref; 23048c2ecf20Sopenharmony_ci @commit_signers = @{$commit_signers_ref} if defined $commit_signers_ref; 23058c2ecf20Sopenharmony_ci 23068c2ecf20Sopenharmony_ci push(@signers, @commit_signers); 23078c2ecf20Sopenharmony_ci } else { 23088c2ecf20Sopenharmony_ci foreach my $commit (@commits) { 23098c2ecf20Sopenharmony_ci my $commit_count; 23108c2ecf20Sopenharmony_ci my $commit_authors_ref; 23118c2ecf20Sopenharmony_ci my $commit_signers_ref; 23128c2ecf20Sopenharmony_ci my $stats_ref; 23138c2ecf20Sopenharmony_ci my @commit_authors = (); 23148c2ecf20Sopenharmony_ci my @commit_signers = (); 23158c2ecf20Sopenharmony_ci my $cmd; 23168c2ecf20Sopenharmony_ci 23178c2ecf20Sopenharmony_ci $cmd = $VCS_cmds{"find_commit_signers_cmd"}; 23188c2ecf20Sopenharmony_ci $cmd =~ s/(\$\w+)/$1/eeg; #substitute variables in $cmd 23198c2ecf20Sopenharmony_ci 23208c2ecf20Sopenharmony_ci ($commit_count, $commit_signers_ref, $commit_authors_ref, $stats_ref) = vcs_find_signers($cmd, $file); 23218c2ecf20Sopenharmony_ci @commit_authors = @{$commit_authors_ref} if defined $commit_authors_ref; 23228c2ecf20Sopenharmony_ci @commit_signers = @{$commit_signers_ref} if defined $commit_signers_ref; 23238c2ecf20Sopenharmony_ci 23248c2ecf20Sopenharmony_ci push(@signers, @commit_signers); 23258c2ecf20Sopenharmony_ci } 23268c2ecf20Sopenharmony_ci } 23278c2ecf20Sopenharmony_ci } 23288c2ecf20Sopenharmony_ci 23298c2ecf20Sopenharmony_ci if ($from_filename) { 23308c2ecf20Sopenharmony_ci if ($output_rolestats) { 23318c2ecf20Sopenharmony_ci my @blame_signers; 23328c2ecf20Sopenharmony_ci if (vcs_is_hg()) {{ # Double brace for last exit 23338c2ecf20Sopenharmony_ci my $commit_count; 23348c2ecf20Sopenharmony_ci my @commit_signers = (); 23358c2ecf20Sopenharmony_ci @commits = uniq(@commits); 23368c2ecf20Sopenharmony_ci @commits = sort(@commits); 23378c2ecf20Sopenharmony_ci my $commit = join(" -r ", @commits); 23388c2ecf20Sopenharmony_ci my $cmd; 23398c2ecf20Sopenharmony_ci 23408c2ecf20Sopenharmony_ci $cmd = $VCS_cmds{"find_commit_author_cmd"}; 23418c2ecf20Sopenharmony_ci $cmd =~ s/(\$\w+)/$1/eeg; #substitute variables in $cmd 23428c2ecf20Sopenharmony_ci 23438c2ecf20Sopenharmony_ci my @lines = (); 23448c2ecf20Sopenharmony_ci 23458c2ecf20Sopenharmony_ci @lines = &{$VCS_cmds{"execute_cmd"}}($cmd); 23468c2ecf20Sopenharmony_ci 23478c2ecf20Sopenharmony_ci if (!$email_git_penguin_chiefs) { 23488c2ecf20Sopenharmony_ci @lines = grep(!/${penguin_chiefs}/i, @lines); 23498c2ecf20Sopenharmony_ci } 23508c2ecf20Sopenharmony_ci 23518c2ecf20Sopenharmony_ci last if !@lines; 23528c2ecf20Sopenharmony_ci 23538c2ecf20Sopenharmony_ci my @authors = (); 23548c2ecf20Sopenharmony_ci foreach my $line (@lines) { 23558c2ecf20Sopenharmony_ci if ($line =~ m/$VCS_cmds{"author_pattern"}/) { 23568c2ecf20Sopenharmony_ci my $author = $1; 23578c2ecf20Sopenharmony_ci $author = deduplicate_email($author); 23588c2ecf20Sopenharmony_ci push(@authors, $author); 23598c2ecf20Sopenharmony_ci } 23608c2ecf20Sopenharmony_ci } 23618c2ecf20Sopenharmony_ci 23628c2ecf20Sopenharmony_ci save_commits_by_author(@lines) if ($interactive); 23638c2ecf20Sopenharmony_ci save_commits_by_signer(@lines) if ($interactive); 23648c2ecf20Sopenharmony_ci 23658c2ecf20Sopenharmony_ci push(@signers, @authors); 23668c2ecf20Sopenharmony_ci }} 23678c2ecf20Sopenharmony_ci else { 23688c2ecf20Sopenharmony_ci foreach my $commit (@commits) { 23698c2ecf20Sopenharmony_ci my $i; 23708c2ecf20Sopenharmony_ci my $cmd = $VCS_cmds{"find_commit_author_cmd"}; 23718c2ecf20Sopenharmony_ci $cmd =~ s/(\$\w+)/$1/eeg; #interpolate $cmd 23728c2ecf20Sopenharmony_ci my @author = vcs_find_author($cmd); 23738c2ecf20Sopenharmony_ci next if !@author; 23748c2ecf20Sopenharmony_ci 23758c2ecf20Sopenharmony_ci my $formatted_author = deduplicate_email($author[0]); 23768c2ecf20Sopenharmony_ci 23778c2ecf20Sopenharmony_ci my $count = grep(/$commit/, @all_commits); 23788c2ecf20Sopenharmony_ci for ($i = 0; $i < $count ; $i++) { 23798c2ecf20Sopenharmony_ci push(@blame_signers, $formatted_author); 23808c2ecf20Sopenharmony_ci } 23818c2ecf20Sopenharmony_ci } 23828c2ecf20Sopenharmony_ci } 23838c2ecf20Sopenharmony_ci if (@blame_signers) { 23848c2ecf20Sopenharmony_ci vcs_assign("authored lines", $total_lines, @blame_signers); 23858c2ecf20Sopenharmony_ci } 23868c2ecf20Sopenharmony_ci } 23878c2ecf20Sopenharmony_ci foreach my $signer (@signers) { 23888c2ecf20Sopenharmony_ci $signer = deduplicate_email($signer); 23898c2ecf20Sopenharmony_ci } 23908c2ecf20Sopenharmony_ci vcs_assign("commits", $total_commits, @signers); 23918c2ecf20Sopenharmony_ci } else { 23928c2ecf20Sopenharmony_ci foreach my $signer (@signers) { 23938c2ecf20Sopenharmony_ci $signer = deduplicate_email($signer); 23948c2ecf20Sopenharmony_ci } 23958c2ecf20Sopenharmony_ci vcs_assign("modified commits", $total_commits, @signers); 23968c2ecf20Sopenharmony_ci } 23978c2ecf20Sopenharmony_ci} 23988c2ecf20Sopenharmony_ci 23998c2ecf20Sopenharmony_cisub vcs_file_exists { 24008c2ecf20Sopenharmony_ci my ($file) = @_; 24018c2ecf20Sopenharmony_ci 24028c2ecf20Sopenharmony_ci my $exists; 24038c2ecf20Sopenharmony_ci 24048c2ecf20Sopenharmony_ci my $vcs_used = vcs_exists(); 24058c2ecf20Sopenharmony_ci return 0 if (!$vcs_used); 24068c2ecf20Sopenharmony_ci 24078c2ecf20Sopenharmony_ci my $cmd = $VCS_cmds{"file_exists_cmd"}; 24088c2ecf20Sopenharmony_ci $cmd =~ s/(\$\w+)/$1/eeg; # interpolate $cmd 24098c2ecf20Sopenharmony_ci $cmd .= " 2>&1"; 24108c2ecf20Sopenharmony_ci $exists = &{$VCS_cmds{"execute_cmd"}}($cmd); 24118c2ecf20Sopenharmony_ci 24128c2ecf20Sopenharmony_ci return 0 if ($? != 0); 24138c2ecf20Sopenharmony_ci 24148c2ecf20Sopenharmony_ci return $exists; 24158c2ecf20Sopenharmony_ci} 24168c2ecf20Sopenharmony_ci 24178c2ecf20Sopenharmony_cisub vcs_list_files { 24188c2ecf20Sopenharmony_ci my ($file) = @_; 24198c2ecf20Sopenharmony_ci 24208c2ecf20Sopenharmony_ci my @lsfiles = (); 24218c2ecf20Sopenharmony_ci 24228c2ecf20Sopenharmony_ci my $vcs_used = vcs_exists(); 24238c2ecf20Sopenharmony_ci return 0 if (!$vcs_used); 24248c2ecf20Sopenharmony_ci 24258c2ecf20Sopenharmony_ci my $cmd = $VCS_cmds{"list_files_cmd"}; 24268c2ecf20Sopenharmony_ci $cmd =~ s/(\$\w+)/$1/eeg; # interpolate $cmd 24278c2ecf20Sopenharmony_ci @lsfiles = &{$VCS_cmds{"execute_cmd"}}($cmd); 24288c2ecf20Sopenharmony_ci 24298c2ecf20Sopenharmony_ci return () if ($? != 0); 24308c2ecf20Sopenharmony_ci 24318c2ecf20Sopenharmony_ci return @lsfiles; 24328c2ecf20Sopenharmony_ci} 24338c2ecf20Sopenharmony_ci 24348c2ecf20Sopenharmony_cisub uniq { 24358c2ecf20Sopenharmony_ci my (@parms) = @_; 24368c2ecf20Sopenharmony_ci 24378c2ecf20Sopenharmony_ci my %saw; 24388c2ecf20Sopenharmony_ci @parms = grep(!$saw{$_}++, @parms); 24398c2ecf20Sopenharmony_ci return @parms; 24408c2ecf20Sopenharmony_ci} 24418c2ecf20Sopenharmony_ci 24428c2ecf20Sopenharmony_cisub sort_and_uniq { 24438c2ecf20Sopenharmony_ci my (@parms) = @_; 24448c2ecf20Sopenharmony_ci 24458c2ecf20Sopenharmony_ci my %saw; 24468c2ecf20Sopenharmony_ci @parms = sort @parms; 24478c2ecf20Sopenharmony_ci @parms = grep(!$saw{$_}++, @parms); 24488c2ecf20Sopenharmony_ci return @parms; 24498c2ecf20Sopenharmony_ci} 24508c2ecf20Sopenharmony_ci 24518c2ecf20Sopenharmony_cisub clean_file_emails { 24528c2ecf20Sopenharmony_ci my (@file_emails) = @_; 24538c2ecf20Sopenharmony_ci my @fmt_emails = (); 24548c2ecf20Sopenharmony_ci 24558c2ecf20Sopenharmony_ci foreach my $email (@file_emails) { 24568c2ecf20Sopenharmony_ci $email =~ s/[\(\<\{]{0,1}([A-Za-z0-9_\.\+-]+\@[A-Za-z0-9\.-]+)[\)\>\}]{0,1}/\<$1\>/g; 24578c2ecf20Sopenharmony_ci my ($name, $address) = parse_email($email); 24588c2ecf20Sopenharmony_ci if ($name eq '"[,\.]"') { 24598c2ecf20Sopenharmony_ci $name = ""; 24608c2ecf20Sopenharmony_ci } 24618c2ecf20Sopenharmony_ci 24628c2ecf20Sopenharmony_ci my @nw = split(/[^A-Za-zÀ-ÿ\'\,\.\+-]/, $name); 24638c2ecf20Sopenharmony_ci if (@nw > 2) { 24648c2ecf20Sopenharmony_ci my $first = $nw[@nw - 3]; 24658c2ecf20Sopenharmony_ci my $middle = $nw[@nw - 2]; 24668c2ecf20Sopenharmony_ci my $last = $nw[@nw - 1]; 24678c2ecf20Sopenharmony_ci 24688c2ecf20Sopenharmony_ci if (((length($first) == 1 && $first =~ m/[A-Za-z]/) || 24698c2ecf20Sopenharmony_ci (length($first) == 2 && substr($first, -1) eq ".")) || 24708c2ecf20Sopenharmony_ci (length($middle) == 1 || 24718c2ecf20Sopenharmony_ci (length($middle) == 2 && substr($middle, -1) eq "."))) { 24728c2ecf20Sopenharmony_ci $name = "$first $middle $last"; 24738c2ecf20Sopenharmony_ci } else { 24748c2ecf20Sopenharmony_ci $name = "$middle $last"; 24758c2ecf20Sopenharmony_ci } 24768c2ecf20Sopenharmony_ci } 24778c2ecf20Sopenharmony_ci 24788c2ecf20Sopenharmony_ci if (substr($name, -1) =~ /[,\.]/) { 24798c2ecf20Sopenharmony_ci $name = substr($name, 0, length($name) - 1); 24808c2ecf20Sopenharmony_ci } elsif (substr($name, -2) =~ /[,\.]"/) { 24818c2ecf20Sopenharmony_ci $name = substr($name, 0, length($name) - 2) . '"'; 24828c2ecf20Sopenharmony_ci } 24838c2ecf20Sopenharmony_ci 24848c2ecf20Sopenharmony_ci if (substr($name, 0, 1) =~ /[,\.]/) { 24858c2ecf20Sopenharmony_ci $name = substr($name, 1, length($name) - 1); 24868c2ecf20Sopenharmony_ci } elsif (substr($name, 0, 2) =~ /"[,\.]/) { 24878c2ecf20Sopenharmony_ci $name = '"' . substr($name, 2, length($name) - 2); 24888c2ecf20Sopenharmony_ci } 24898c2ecf20Sopenharmony_ci 24908c2ecf20Sopenharmony_ci my $fmt_email = format_email($name, $address, $email_usename); 24918c2ecf20Sopenharmony_ci push(@fmt_emails, $fmt_email); 24928c2ecf20Sopenharmony_ci } 24938c2ecf20Sopenharmony_ci return @fmt_emails; 24948c2ecf20Sopenharmony_ci} 24958c2ecf20Sopenharmony_ci 24968c2ecf20Sopenharmony_cisub merge_email { 24978c2ecf20Sopenharmony_ci my @lines; 24988c2ecf20Sopenharmony_ci my %saw; 24998c2ecf20Sopenharmony_ci 25008c2ecf20Sopenharmony_ci for (@_) { 25018c2ecf20Sopenharmony_ci my ($address, $role) = @$_; 25028c2ecf20Sopenharmony_ci if (!$saw{$address}) { 25038c2ecf20Sopenharmony_ci if ($output_roles) { 25048c2ecf20Sopenharmony_ci push(@lines, "$address ($role)"); 25058c2ecf20Sopenharmony_ci } else { 25068c2ecf20Sopenharmony_ci push(@lines, $address); 25078c2ecf20Sopenharmony_ci } 25088c2ecf20Sopenharmony_ci $saw{$address} = 1; 25098c2ecf20Sopenharmony_ci } 25108c2ecf20Sopenharmony_ci } 25118c2ecf20Sopenharmony_ci 25128c2ecf20Sopenharmony_ci return @lines; 25138c2ecf20Sopenharmony_ci} 25148c2ecf20Sopenharmony_ci 25158c2ecf20Sopenharmony_cisub output { 25168c2ecf20Sopenharmony_ci my (@parms) = @_; 25178c2ecf20Sopenharmony_ci 25188c2ecf20Sopenharmony_ci if ($output_multiline) { 25198c2ecf20Sopenharmony_ci foreach my $line (@parms) { 25208c2ecf20Sopenharmony_ci print("${line}\n"); 25218c2ecf20Sopenharmony_ci } 25228c2ecf20Sopenharmony_ci } else { 25238c2ecf20Sopenharmony_ci print(join($output_separator, @parms)); 25248c2ecf20Sopenharmony_ci print("\n"); 25258c2ecf20Sopenharmony_ci } 25268c2ecf20Sopenharmony_ci} 25278c2ecf20Sopenharmony_ci 25288c2ecf20Sopenharmony_cimy $rfc822re; 25298c2ecf20Sopenharmony_ci 25308c2ecf20Sopenharmony_cisub make_rfc822re { 25318c2ecf20Sopenharmony_ci# Basic lexical tokens are specials, domain_literal, quoted_string, atom, and 25328c2ecf20Sopenharmony_ci# comment. We must allow for rfc822_lwsp (or comments) after each of these. 25338c2ecf20Sopenharmony_ci# This regexp will only work on addresses which have had comments stripped 25348c2ecf20Sopenharmony_ci# and replaced with rfc822_lwsp. 25358c2ecf20Sopenharmony_ci 25368c2ecf20Sopenharmony_ci my $specials = '()<>@,;:\\\\".\\[\\]'; 25378c2ecf20Sopenharmony_ci my $controls = '\\000-\\037\\177'; 25388c2ecf20Sopenharmony_ci 25398c2ecf20Sopenharmony_ci my $dtext = "[^\\[\\]\\r\\\\]"; 25408c2ecf20Sopenharmony_ci my $domain_literal = "\\[(?:$dtext|\\\\.)*\\]$rfc822_lwsp*"; 25418c2ecf20Sopenharmony_ci 25428c2ecf20Sopenharmony_ci my $quoted_string = "\"(?:[^\\\"\\r\\\\]|\\\\.|$rfc822_lwsp)*\"$rfc822_lwsp*"; 25438c2ecf20Sopenharmony_ci 25448c2ecf20Sopenharmony_ci# Use zero-width assertion to spot the limit of an atom. A simple 25458c2ecf20Sopenharmony_ci# $rfc822_lwsp* causes the regexp engine to hang occasionally. 25468c2ecf20Sopenharmony_ci my $atom = "[^$specials $controls]+(?:$rfc822_lwsp+|\\Z|(?=[\\[\"$specials]))"; 25478c2ecf20Sopenharmony_ci my $word = "(?:$atom|$quoted_string)"; 25488c2ecf20Sopenharmony_ci my $localpart = "$word(?:\\.$rfc822_lwsp*$word)*"; 25498c2ecf20Sopenharmony_ci 25508c2ecf20Sopenharmony_ci my $sub_domain = "(?:$atom|$domain_literal)"; 25518c2ecf20Sopenharmony_ci my $domain = "$sub_domain(?:\\.$rfc822_lwsp*$sub_domain)*"; 25528c2ecf20Sopenharmony_ci 25538c2ecf20Sopenharmony_ci my $addr_spec = "$localpart\@$rfc822_lwsp*$domain"; 25548c2ecf20Sopenharmony_ci 25558c2ecf20Sopenharmony_ci my $phrase = "$word*"; 25568c2ecf20Sopenharmony_ci my $route = "(?:\@$domain(?:,\@$rfc822_lwsp*$domain)*:$rfc822_lwsp*)"; 25578c2ecf20Sopenharmony_ci my $route_addr = "\\<$rfc822_lwsp*$route?$addr_spec\\>$rfc822_lwsp*"; 25588c2ecf20Sopenharmony_ci my $mailbox = "(?:$addr_spec|$phrase$route_addr)"; 25598c2ecf20Sopenharmony_ci 25608c2ecf20Sopenharmony_ci my $group = "$phrase:$rfc822_lwsp*(?:$mailbox(?:,\\s*$mailbox)*)?;\\s*"; 25618c2ecf20Sopenharmony_ci my $address = "(?:$mailbox|$group)"; 25628c2ecf20Sopenharmony_ci 25638c2ecf20Sopenharmony_ci return "$rfc822_lwsp*$address"; 25648c2ecf20Sopenharmony_ci} 25658c2ecf20Sopenharmony_ci 25668c2ecf20Sopenharmony_cisub rfc822_strip_comments { 25678c2ecf20Sopenharmony_ci my $s = shift; 25688c2ecf20Sopenharmony_ci# Recursively remove comments, and replace with a single space. The simpler 25698c2ecf20Sopenharmony_ci# regexps in the Email Addressing FAQ are imperfect - they will miss escaped 25708c2ecf20Sopenharmony_ci# chars in atoms, for example. 25718c2ecf20Sopenharmony_ci 25728c2ecf20Sopenharmony_ci while ($s =~ s/^((?:[^"\\]|\\.)* 25738c2ecf20Sopenharmony_ci (?:"(?:[^"\\]|\\.)*"(?:[^"\\]|\\.)*)*) 25748c2ecf20Sopenharmony_ci \((?:[^()\\]|\\.)*\)/$1 /osx) {} 25758c2ecf20Sopenharmony_ci return $s; 25768c2ecf20Sopenharmony_ci} 25778c2ecf20Sopenharmony_ci 25788c2ecf20Sopenharmony_ci# valid: returns true if the parameter is an RFC822 valid address 25798c2ecf20Sopenharmony_ci# 25808c2ecf20Sopenharmony_cisub rfc822_valid { 25818c2ecf20Sopenharmony_ci my $s = rfc822_strip_comments(shift); 25828c2ecf20Sopenharmony_ci 25838c2ecf20Sopenharmony_ci if (!$rfc822re) { 25848c2ecf20Sopenharmony_ci $rfc822re = make_rfc822re(); 25858c2ecf20Sopenharmony_ci } 25868c2ecf20Sopenharmony_ci 25878c2ecf20Sopenharmony_ci return $s =~ m/^$rfc822re$/so && $s =~ m/^$rfc822_char*$/; 25888c2ecf20Sopenharmony_ci} 25898c2ecf20Sopenharmony_ci 25908c2ecf20Sopenharmony_ci# validlist: In scalar context, returns true if the parameter is an RFC822 25918c2ecf20Sopenharmony_ci# valid list of addresses. 25928c2ecf20Sopenharmony_ci# 25938c2ecf20Sopenharmony_ci# In list context, returns an empty list on failure (an invalid 25948c2ecf20Sopenharmony_ci# address was found); otherwise a list whose first element is the 25958c2ecf20Sopenharmony_ci# number of addresses found and whose remaining elements are the 25968c2ecf20Sopenharmony_ci# addresses. This is needed to disambiguate failure (invalid) 25978c2ecf20Sopenharmony_ci# from success with no addresses found, because an empty string is 25988c2ecf20Sopenharmony_ci# a valid list. 25998c2ecf20Sopenharmony_ci 26008c2ecf20Sopenharmony_cisub rfc822_validlist { 26018c2ecf20Sopenharmony_ci my $s = rfc822_strip_comments(shift); 26028c2ecf20Sopenharmony_ci 26038c2ecf20Sopenharmony_ci if (!$rfc822re) { 26048c2ecf20Sopenharmony_ci $rfc822re = make_rfc822re(); 26058c2ecf20Sopenharmony_ci } 26068c2ecf20Sopenharmony_ci # * null list items are valid according to the RFC 26078c2ecf20Sopenharmony_ci # * the '1' business is to aid in distinguishing failure from no results 26088c2ecf20Sopenharmony_ci 26098c2ecf20Sopenharmony_ci my @r; 26108c2ecf20Sopenharmony_ci if ($s =~ m/^(?:$rfc822re)?(?:,(?:$rfc822re)?)*$/so && 26118c2ecf20Sopenharmony_ci $s =~ m/^$rfc822_char*$/) { 26128c2ecf20Sopenharmony_ci while ($s =~ m/(?:^|,$rfc822_lwsp*)($rfc822re)/gos) { 26138c2ecf20Sopenharmony_ci push(@r, $1); 26148c2ecf20Sopenharmony_ci } 26158c2ecf20Sopenharmony_ci return wantarray ? (scalar(@r), @r) : 1; 26168c2ecf20Sopenharmony_ci } 26178c2ecf20Sopenharmony_ci return wantarray ? () : 0; 26188c2ecf20Sopenharmony_ci} 2619