14fd65389SHeinrich Schuchardt#!/usr/bin/env perl 292bca398SDaniel Schwierzeck# (c) 2007, Joe Perches <joe@perches.com> 392bca398SDaniel Schwierzeck# created from checkpatch.pl 492bca398SDaniel Schwierzeck# 592bca398SDaniel Schwierzeck# Print selected MAINTAINERS information for 692bca398SDaniel Schwierzeck# the files modified in a patch or for a file 792bca398SDaniel Schwierzeck# 892bca398SDaniel Schwierzeck# usage: perl scripts/get_maintainer.pl [OPTIONS] <patch> 992bca398SDaniel Schwierzeck# perl scripts/get_maintainer.pl [OPTIONS] -f <file> 1092bca398SDaniel Schwierzeck# 1192bca398SDaniel Schwierzeck# Licensed under the terms of the GNU GPL License version 2 1292bca398SDaniel Schwierzeck 134fd65389SHeinrich Schuchardtuse warnings; 1492bca398SDaniel Schwierzeckuse strict; 1592bca398SDaniel Schwierzeck 1692bca398SDaniel Schwierzeckmy $P = $0; 1792bca398SDaniel Schwierzeckmy $V = '0.26'; 1892bca398SDaniel Schwierzeck 1992bca398SDaniel Schwierzeckuse Getopt::Long qw(:config no_auto_abbrev); 204fd65389SHeinrich Schuchardtuse Cwd; 2168dc8769SDaniel Schwierzeckuse File::Find; 2292bca398SDaniel Schwierzeck 234fd65389SHeinrich Schuchardtmy $cur_path = fastgetcwd() . '/'; 2492bca398SDaniel Schwierzeckmy $lk_path = "./"; 2592bca398SDaniel Schwierzeckmy $email = 1; 2692bca398SDaniel Schwierzeckmy $email_usename = 1; 2792bca398SDaniel Schwierzeckmy $email_maintainer = 1; 284fd65389SHeinrich Schuchardtmy $email_reviewer = 1; 2992bca398SDaniel Schwierzeckmy $email_list = 1; 3092bca398SDaniel Schwierzeckmy $email_subscriber_list = 0; 3192bca398SDaniel Schwierzeckmy $email_git_penguin_chiefs = 0; 3292bca398SDaniel Schwierzeckmy $email_git = 0; 3392bca398SDaniel Schwierzeckmy $email_git_all_signature_types = 0; 3492bca398SDaniel Schwierzeckmy $email_git_blame = 0; 3592bca398SDaniel Schwierzeckmy $email_git_blame_signatures = 1; 3692bca398SDaniel Schwierzeckmy $email_git_fallback = 1; 3792bca398SDaniel Schwierzeckmy $email_git_min_signatures = 1; 3892bca398SDaniel Schwierzeckmy $email_git_max_maintainers = 5; 3992bca398SDaniel Schwierzeckmy $email_git_min_percent = 5; 4092bca398SDaniel Schwierzeckmy $email_git_since = "1-year-ago"; 4192bca398SDaniel Schwierzeckmy $email_hg_since = "-365"; 4292bca398SDaniel Schwierzeckmy $interactive = 0; 4392bca398SDaniel Schwierzeckmy $email_remove_duplicates = 1; 4492bca398SDaniel Schwierzeckmy $email_use_mailmap = 1; 4592bca398SDaniel Schwierzeckmy $output_multiline = 1; 4692bca398SDaniel Schwierzeckmy $output_separator = ", "; 4792bca398SDaniel Schwierzeckmy $output_roles = 0; 4892bca398SDaniel Schwierzeckmy $output_rolestats = 1; 494fd65389SHeinrich Schuchardtmy $output_section_maxlen = 50; 5092bca398SDaniel Schwierzeckmy $scm = 0; 5192bca398SDaniel Schwierzeckmy $web = 0; 5292bca398SDaniel Schwierzeckmy $subsystem = 0; 5392bca398SDaniel Schwierzeckmy $status = 0; 544fd65389SHeinrich Schuchardtmy $letters = ""; 5592bca398SDaniel Schwierzeckmy $keywords = 1; 5692bca398SDaniel Schwierzeckmy $sections = 0; 5792bca398SDaniel Schwierzeckmy $file_emails = 0; 5892bca398SDaniel Schwierzeckmy $from_filename = 0; 5992bca398SDaniel Schwierzeckmy $pattern_depth = 0; 6092bca398SDaniel Schwierzeckmy $version = 0; 6192bca398SDaniel Schwierzeckmy $help = 0; 62*ae530ff2SHeinrich Schuchardtmy $find_maintainer_files = 1; 6392bca398SDaniel Schwierzeck 6492bca398SDaniel Schwierzeckmy $vcs_used = 0; 6592bca398SDaniel Schwierzeck 6692bca398SDaniel Schwierzeckmy $exit = 0; 6792bca398SDaniel Schwierzeck 6892bca398SDaniel Schwierzeckmy %commit_author_hash; 6992bca398SDaniel Schwierzeckmy %commit_signer_hash; 7092bca398SDaniel Schwierzeck 7192bca398SDaniel Schwierzeckmy @penguin_chief = (); 72ca746f04SAndy Flemingpush(@penguin_chief, "Tom Rini:trini\@konsulko.com"); 7392bca398SDaniel Schwierzeck 7492bca398SDaniel Schwierzeckmy @penguin_chief_names = (); 7592bca398SDaniel Schwierzeckforeach my $chief (@penguin_chief) { 7692bca398SDaniel Schwierzeck if ($chief =~ m/^(.*):(.*)/) { 7792bca398SDaniel Schwierzeck my $chief_name = $1; 7892bca398SDaniel Schwierzeck my $chief_addr = $2; 7992bca398SDaniel Schwierzeck push(@penguin_chief_names, $chief_name); 8092bca398SDaniel Schwierzeck } 8192bca398SDaniel Schwierzeck} 8292bca398SDaniel Schwierzeckmy $penguin_chiefs = "\(" . join("|", @penguin_chief_names) . "\)"; 8392bca398SDaniel Schwierzeck 8492bca398SDaniel Schwierzeck# Signature types of people who are either 8592bca398SDaniel Schwierzeck# a) responsible for the code in question, or 8692bca398SDaniel Schwierzeck# b) familiar enough with it to give relevant feedback 8792bca398SDaniel Schwierzeckmy @signature_tags = (); 8892bca398SDaniel Schwierzeckpush(@signature_tags, "Signed-off-by:"); 8992bca398SDaniel Schwierzeckpush(@signature_tags, "Reviewed-by:"); 9092bca398SDaniel Schwierzeckpush(@signature_tags, "Acked-by:"); 9192bca398SDaniel Schwierzeck 9292bca398SDaniel Schwierzeckmy $signature_pattern = "\(" . join("|", @signature_tags) . "\)"; 9392bca398SDaniel Schwierzeck 9492bca398SDaniel Schwierzeck# rfc822 email address - preloaded methods go here. 9592bca398SDaniel Schwierzeckmy $rfc822_lwsp = "(?:(?:\\r\\n)?[ \\t])"; 9692bca398SDaniel Schwierzeckmy $rfc822_char = '[\\000-\\377]'; 9792bca398SDaniel Schwierzeck 9892bca398SDaniel Schwierzeck# VCS command support: class-like functions and strings 9992bca398SDaniel Schwierzeck 10092bca398SDaniel Schwierzeckmy %VCS_cmds; 10192bca398SDaniel Schwierzeck 10292bca398SDaniel Schwierzeckmy %VCS_cmds_git = ( 10392bca398SDaniel Schwierzeck "execute_cmd" => \&git_execute_cmd, 10492bca398SDaniel Schwierzeck "available" => '(which("git") ne "") && (-e ".git")', 10592bca398SDaniel Schwierzeck "find_signers_cmd" => 10692bca398SDaniel Schwierzeck "git log --no-color --follow --since=\$email_git_since " . 10792bca398SDaniel Schwierzeck '--numstat --no-merges ' . 10892bca398SDaniel Schwierzeck '--format="GitCommit: %H%n' . 10992bca398SDaniel Schwierzeck 'GitAuthor: %an <%ae>%n' . 11092bca398SDaniel Schwierzeck 'GitDate: %aD%n' . 11192bca398SDaniel Schwierzeck 'GitSubject: %s%n' . 11292bca398SDaniel Schwierzeck '%b%n"' . 11392bca398SDaniel Schwierzeck " -- \$file", 11492bca398SDaniel Schwierzeck "find_commit_signers_cmd" => 11592bca398SDaniel Schwierzeck "git log --no-color " . 11692bca398SDaniel Schwierzeck '--numstat ' . 11792bca398SDaniel Schwierzeck '--format="GitCommit: %H%n' . 11892bca398SDaniel Schwierzeck 'GitAuthor: %an <%ae>%n' . 11992bca398SDaniel Schwierzeck 'GitDate: %aD%n' . 12092bca398SDaniel Schwierzeck 'GitSubject: %s%n' . 12192bca398SDaniel Schwierzeck '%b%n"' . 12292bca398SDaniel Schwierzeck " -1 \$commit", 12392bca398SDaniel Schwierzeck "find_commit_author_cmd" => 12492bca398SDaniel Schwierzeck "git log --no-color " . 12592bca398SDaniel Schwierzeck '--numstat ' . 12692bca398SDaniel Schwierzeck '--format="GitCommit: %H%n' . 12792bca398SDaniel Schwierzeck 'GitAuthor: %an <%ae>%n' . 12892bca398SDaniel Schwierzeck 'GitDate: %aD%n' . 12992bca398SDaniel Schwierzeck 'GitSubject: %s%n"' . 13092bca398SDaniel Schwierzeck " -1 \$commit", 13192bca398SDaniel Schwierzeck "blame_range_cmd" => "git blame -l -L \$diff_start,+\$diff_length \$file", 13292bca398SDaniel Schwierzeck "blame_file_cmd" => "git blame -l \$file", 13392bca398SDaniel Schwierzeck "commit_pattern" => "^GitCommit: ([0-9a-f]{40,40})", 13492bca398SDaniel Schwierzeck "blame_commit_pattern" => "^([0-9a-f]+) ", 13592bca398SDaniel Schwierzeck "author_pattern" => "^GitAuthor: (.*)", 13692bca398SDaniel Schwierzeck "subject_pattern" => "^GitSubject: (.*)", 13792bca398SDaniel Schwierzeck "stat_pattern" => "^(\\d+)\\t(\\d+)\\t\$file\$", 1384fd65389SHeinrich Schuchardt "file_exists_cmd" => "git ls-files \$file", 13992bca398SDaniel Schwierzeck); 14092bca398SDaniel Schwierzeck 14192bca398SDaniel Schwierzeckmy %VCS_cmds_hg = ( 14292bca398SDaniel Schwierzeck "execute_cmd" => \&hg_execute_cmd, 14392bca398SDaniel Schwierzeck "available" => '(which("hg") ne "") && (-d ".hg")', 14492bca398SDaniel Schwierzeck "find_signers_cmd" => 14592bca398SDaniel Schwierzeck "hg log --date=\$email_hg_since " . 14692bca398SDaniel Schwierzeck "--template='HgCommit: {node}\\n" . 14792bca398SDaniel Schwierzeck "HgAuthor: {author}\\n" . 14892bca398SDaniel Schwierzeck "HgSubject: {desc}\\n'" . 14992bca398SDaniel Schwierzeck " -- \$file", 15092bca398SDaniel Schwierzeck "find_commit_signers_cmd" => 15192bca398SDaniel Schwierzeck "hg log " . 15292bca398SDaniel Schwierzeck "--template='HgSubject: {desc}\\n'" . 15392bca398SDaniel Schwierzeck " -r \$commit", 15492bca398SDaniel Schwierzeck "find_commit_author_cmd" => 15592bca398SDaniel Schwierzeck "hg log " . 15692bca398SDaniel Schwierzeck "--template='HgCommit: {node}\\n" . 15792bca398SDaniel Schwierzeck "HgAuthor: {author}\\n" . 15892bca398SDaniel Schwierzeck "HgSubject: {desc|firstline}\\n'" . 15992bca398SDaniel Schwierzeck " -r \$commit", 16092bca398SDaniel Schwierzeck "blame_range_cmd" => "", # not supported 16192bca398SDaniel Schwierzeck "blame_file_cmd" => "hg blame -n \$file", 16292bca398SDaniel Schwierzeck "commit_pattern" => "^HgCommit: ([0-9a-f]{40,40})", 16392bca398SDaniel Schwierzeck "blame_commit_pattern" => "^([ 0-9a-f]+):", 16492bca398SDaniel Schwierzeck "author_pattern" => "^HgAuthor: (.*)", 16592bca398SDaniel Schwierzeck "subject_pattern" => "^HgSubject: (.*)", 16692bca398SDaniel Schwierzeck "stat_pattern" => "^(\\d+)\t(\\d+)\t\$file\$", 1674fd65389SHeinrich Schuchardt "file_exists_cmd" => "hg files \$file", 16892bca398SDaniel Schwierzeck); 16992bca398SDaniel Schwierzeck 17092bca398SDaniel Schwierzeckmy $conf = which_conf(".get_maintainer.conf"); 17192bca398SDaniel Schwierzeckif (-f $conf) { 17292bca398SDaniel Schwierzeck my @conf_args; 17392bca398SDaniel Schwierzeck open(my $conffile, '<', "$conf") 17492bca398SDaniel Schwierzeck or warn "$P: Can't find a readable .get_maintainer.conf file $!\n"; 17592bca398SDaniel Schwierzeck 17692bca398SDaniel Schwierzeck while (<$conffile>) { 17792bca398SDaniel Schwierzeck my $line = $_; 17892bca398SDaniel Schwierzeck 17992bca398SDaniel Schwierzeck $line =~ s/\s*\n?$//g; 18092bca398SDaniel Schwierzeck $line =~ s/^\s*//g; 18192bca398SDaniel Schwierzeck $line =~ s/\s+/ /g; 18292bca398SDaniel Schwierzeck 18392bca398SDaniel Schwierzeck next if ($line =~ m/^\s*#/); 18492bca398SDaniel Schwierzeck next if ($line =~ m/^\s*$/); 18592bca398SDaniel Schwierzeck 18692bca398SDaniel Schwierzeck my @words = split(" ", $line); 18792bca398SDaniel Schwierzeck foreach my $word (@words) { 18892bca398SDaniel Schwierzeck last if ($word =~ m/^#/); 18992bca398SDaniel Schwierzeck push (@conf_args, $word); 19092bca398SDaniel Schwierzeck } 19192bca398SDaniel Schwierzeck } 19292bca398SDaniel Schwierzeck close($conffile); 19392bca398SDaniel Schwierzeck unshift(@ARGV, @conf_args) if @conf_args; 19492bca398SDaniel Schwierzeck} 19592bca398SDaniel Schwierzeck 1964fd65389SHeinrich Schuchardtmy @ignore_emails = (); 1974fd65389SHeinrich Schuchardtmy $ignore_file = which_conf(".get_maintainer.ignore"); 1984fd65389SHeinrich Schuchardtif (-f $ignore_file) { 1994fd65389SHeinrich Schuchardt open(my $ignore, '<', "$ignore_file") 2004fd65389SHeinrich Schuchardt or warn "$P: Can't find a readable .get_maintainer.ignore file $!\n"; 2014fd65389SHeinrich Schuchardt while (<$ignore>) { 2024fd65389SHeinrich Schuchardt my $line = $_; 2034fd65389SHeinrich Schuchardt 2044fd65389SHeinrich Schuchardt $line =~ s/\s*\n?$//; 2054fd65389SHeinrich Schuchardt $line =~ s/^\s*//; 2064fd65389SHeinrich Schuchardt $line =~ s/\s+$//; 2074fd65389SHeinrich Schuchardt $line =~ s/#.*$//; 2084fd65389SHeinrich Schuchardt 2094fd65389SHeinrich Schuchardt next if ($line =~ m/^\s*$/); 2104fd65389SHeinrich Schuchardt if (rfc822_valid($line)) { 2114fd65389SHeinrich Schuchardt push(@ignore_emails, $line); 2124fd65389SHeinrich Schuchardt } 2134fd65389SHeinrich Schuchardt } 2144fd65389SHeinrich Schuchardt close($ignore); 2154fd65389SHeinrich Schuchardt} 2164fd65389SHeinrich Schuchardt 21792bca398SDaniel Schwierzeckif (!GetOptions( 21892bca398SDaniel Schwierzeck 'email!' => \$email, 21992bca398SDaniel Schwierzeck 'git!' => \$email_git, 22092bca398SDaniel Schwierzeck 'git-all-signature-types!' => \$email_git_all_signature_types, 22192bca398SDaniel Schwierzeck 'git-blame!' => \$email_git_blame, 22292bca398SDaniel Schwierzeck 'git-blame-signatures!' => \$email_git_blame_signatures, 22392bca398SDaniel Schwierzeck 'git-fallback!' => \$email_git_fallback, 22492bca398SDaniel Schwierzeck 'git-chief-penguins!' => \$email_git_penguin_chiefs, 22592bca398SDaniel Schwierzeck 'git-min-signatures=i' => \$email_git_min_signatures, 22692bca398SDaniel Schwierzeck 'git-max-maintainers=i' => \$email_git_max_maintainers, 22792bca398SDaniel Schwierzeck 'git-min-percent=i' => \$email_git_min_percent, 22892bca398SDaniel Schwierzeck 'git-since=s' => \$email_git_since, 22992bca398SDaniel Schwierzeck 'hg-since=s' => \$email_hg_since, 23092bca398SDaniel Schwierzeck 'i|interactive!' => \$interactive, 23192bca398SDaniel Schwierzeck 'remove-duplicates!' => \$email_remove_duplicates, 23292bca398SDaniel Schwierzeck 'mailmap!' => \$email_use_mailmap, 23392bca398SDaniel Schwierzeck 'm!' => \$email_maintainer, 2344fd65389SHeinrich Schuchardt 'r!' => \$email_reviewer, 23592bca398SDaniel Schwierzeck 'n!' => \$email_usename, 23692bca398SDaniel Schwierzeck 'l!' => \$email_list, 23792bca398SDaniel Schwierzeck 's!' => \$email_subscriber_list, 23892bca398SDaniel Schwierzeck 'multiline!' => \$output_multiline, 23992bca398SDaniel Schwierzeck 'roles!' => \$output_roles, 24092bca398SDaniel Schwierzeck 'rolestats!' => \$output_rolestats, 24192bca398SDaniel Schwierzeck 'separator=s' => \$output_separator, 24292bca398SDaniel Schwierzeck 'subsystem!' => \$subsystem, 24392bca398SDaniel Schwierzeck 'status!' => \$status, 24492bca398SDaniel Schwierzeck 'scm!' => \$scm, 24592bca398SDaniel Schwierzeck 'web!' => \$web, 2464fd65389SHeinrich Schuchardt 'letters=s' => \$letters, 24792bca398SDaniel Schwierzeck 'pattern-depth=i' => \$pattern_depth, 24892bca398SDaniel Schwierzeck 'k|keywords!' => \$keywords, 24992bca398SDaniel Schwierzeck 'sections!' => \$sections, 25092bca398SDaniel Schwierzeck 'fe|file-emails!' => \$file_emails, 25192bca398SDaniel Schwierzeck 'f|file' => \$from_filename, 2524fd65389SHeinrich Schuchardt 'find-maintainer-files' => \$find_maintainer_files, 25392bca398SDaniel Schwierzeck 'v|version' => \$version, 25492bca398SDaniel Schwierzeck 'h|help|usage' => \$help, 25592bca398SDaniel Schwierzeck )) { 25692bca398SDaniel Schwierzeck die "$P: invalid argument - use --help if necessary\n"; 25792bca398SDaniel Schwierzeck} 25892bca398SDaniel Schwierzeck 25992bca398SDaniel Schwierzeckif ($help != 0) { 26092bca398SDaniel Schwierzeck usage(); 26192bca398SDaniel Schwierzeck exit 0; 26292bca398SDaniel Schwierzeck} 26392bca398SDaniel Schwierzeck 26492bca398SDaniel Schwierzeckif ($version != 0) { 26592bca398SDaniel Schwierzeck print("${P} ${V}\n"); 26692bca398SDaniel Schwierzeck exit 0; 26792bca398SDaniel Schwierzeck} 26892bca398SDaniel Schwierzeck 26992bca398SDaniel Schwierzeckif (-t STDIN && !@ARGV) { 27092bca398SDaniel Schwierzeck # We're talking to a terminal, but have no command line arguments. 27192bca398SDaniel Schwierzeck die "$P: missing patchfile or -f file - use --help if necessary\n"; 27292bca398SDaniel Schwierzeck} 27392bca398SDaniel Schwierzeck 27492bca398SDaniel Schwierzeck$output_multiline = 0 if ($output_separator ne ", "); 27592bca398SDaniel Schwierzeck$output_rolestats = 1 if ($interactive); 27692bca398SDaniel Schwierzeck$output_roles = 1 if ($output_rolestats); 27792bca398SDaniel Schwierzeck 2784fd65389SHeinrich Schuchardtif ($sections || $letters ne "") { 2794fd65389SHeinrich Schuchardt $sections = 1; 28092bca398SDaniel Schwierzeck $email = 0; 28192bca398SDaniel Schwierzeck $email_list = 0; 28292bca398SDaniel Schwierzeck $scm = 0; 28392bca398SDaniel Schwierzeck $status = 0; 28492bca398SDaniel Schwierzeck $subsystem = 0; 28592bca398SDaniel Schwierzeck $web = 0; 28692bca398SDaniel Schwierzeck $keywords = 0; 28792bca398SDaniel Schwierzeck $interactive = 0; 28892bca398SDaniel Schwierzeck} else { 28992bca398SDaniel Schwierzeck my $selections = $email + $scm + $status + $subsystem + $web; 29092bca398SDaniel Schwierzeck if ($selections == 0) { 29192bca398SDaniel Schwierzeck die "$P: Missing required option: email, scm, status, subsystem or web\n"; 29292bca398SDaniel Schwierzeck } 29392bca398SDaniel Schwierzeck} 29492bca398SDaniel Schwierzeck 29592bca398SDaniel Schwierzeckif ($email && 2964fd65389SHeinrich Schuchardt ($email_maintainer + $email_reviewer + 2974fd65389SHeinrich Schuchardt $email_list + $email_subscriber_list + 29892bca398SDaniel Schwierzeck $email_git + $email_git_penguin_chiefs + $email_git_blame) == 0) { 29992bca398SDaniel Schwierzeck die "$P: Please select at least 1 email option\n"; 30092bca398SDaniel Schwierzeck} 30192bca398SDaniel Schwierzeck 30292bca398SDaniel Schwierzeckif (!top_of_kernel_tree($lk_path)) { 30392bca398SDaniel Schwierzeck die "$P: The current directory does not appear to be " 3044fd65389SHeinrich Schuchardt . "a U-Boot source tree.\n"; 30592bca398SDaniel Schwierzeck} 30692bca398SDaniel Schwierzeck 30792bca398SDaniel Schwierzeck## Read MAINTAINERS for type/value pairs 30892bca398SDaniel Schwierzeck 30992bca398SDaniel Schwierzeckmy @typevalue = (); 31092bca398SDaniel Schwierzeckmy %keyword_hash; 3114fd65389SHeinrich Schuchardtmy @mfiles = (); 31292bca398SDaniel Schwierzeck 3134fd65389SHeinrich Schuchardtsub read_maintainer_file { 3144fd65389SHeinrich Schuchardt my ($file) = @_; 31568dc8769SDaniel Schwierzeck 3164fd65389SHeinrich Schuchardt open (my $maint, '<', "$file") 3174fd65389SHeinrich Schuchardt or die "$P: Can't open MAINTAINERS file '$file': $!\n"; 31892bca398SDaniel Schwierzeck while (<$maint>) { 31992bca398SDaniel Schwierzeck my $line = $_; 32092bca398SDaniel Schwierzeck 32135729218SHeiko Schocher if ($line =~ m/^([A-Z]):\s*(.*)/) { 32292bca398SDaniel Schwierzeck my $type = $1; 32392bca398SDaniel Schwierzeck my $value = $2; 32492bca398SDaniel Schwierzeck 32592bca398SDaniel Schwierzeck ##Filename pattern matching 32692bca398SDaniel Schwierzeck if ($type eq "F" || $type eq "X") { 32792bca398SDaniel Schwierzeck $value =~ s@\.@\\\.@g; ##Convert . to \. 32892bca398SDaniel Schwierzeck $value =~ s/\*/\.\*/g; ##Convert * to .* 32992bca398SDaniel Schwierzeck $value =~ s/\?/\./g; ##Convert ? to . 33092bca398SDaniel Schwierzeck ##if pattern is a directory and it lacks a trailing slash, add one 33192bca398SDaniel Schwierzeck if ((-d $value)) { 33292bca398SDaniel Schwierzeck $value =~ s@([^/])$@$1/@; 33392bca398SDaniel Schwierzeck } 33492bca398SDaniel Schwierzeck } elsif ($type eq "K") { 33592bca398SDaniel Schwierzeck $keyword_hash{@typevalue} = $value; 33692bca398SDaniel Schwierzeck } 33792bca398SDaniel Schwierzeck push(@typevalue, "$type:$value"); 3384fd65389SHeinrich Schuchardt } elsif (!(/^\s*$/ || /^\s*\#/)) { 33992bca398SDaniel Schwierzeck $line =~ s/\n$//g; 34092bca398SDaniel Schwierzeck push(@typevalue, $line); 34192bca398SDaniel Schwierzeck } 34292bca398SDaniel Schwierzeck } 3434fd65389SHeinrich Schuchardt close($maint); 34468dc8769SDaniel Schwierzeck} 34592bca398SDaniel Schwierzeck 3464fd65389SHeinrich Schuchardtsub find_is_maintainer_file { 3474fd65389SHeinrich Schuchardt my ($file) = $_; 3484fd65389SHeinrich Schuchardt return if ($file !~ m@/MAINTAINERS$@); 3494fd65389SHeinrich Schuchardt $file = $File::Find::name; 3504fd65389SHeinrich Schuchardt return if (! -f $file); 3514fd65389SHeinrich Schuchardt push(@mfiles, $file); 3524fd65389SHeinrich Schuchardt} 3534fd65389SHeinrich Schuchardt 3544fd65389SHeinrich Schuchardtsub find_ignore_git { 3554fd65389SHeinrich Schuchardt return grep { $_ !~ /^\.git$/; } @_; 3564fd65389SHeinrich Schuchardt} 3574fd65389SHeinrich Schuchardt 3584fd65389SHeinrich Schuchardtif (-d "${lk_path}MAINTAINERS") { 3594fd65389SHeinrich Schuchardt opendir(DIR, "${lk_path}MAINTAINERS") or die $!; 3604fd65389SHeinrich Schuchardt my @files = readdir(DIR); 3614fd65389SHeinrich Schuchardt closedir(DIR); 3624fd65389SHeinrich Schuchardt foreach my $file (@files) { 3634fd65389SHeinrich Schuchardt push(@mfiles, "${lk_path}MAINTAINERS/$file") if ($file !~ /^\./); 3644fd65389SHeinrich Schuchardt } 3654fd65389SHeinrich Schuchardt} 3664fd65389SHeinrich Schuchardt 3674fd65389SHeinrich Schuchardtif ($find_maintainer_files) { 3684fd65389SHeinrich Schuchardt find( { wanted => \&find_is_maintainer_file, 3694fd65389SHeinrich Schuchardt preprocess => \&find_ignore_git, 3704fd65389SHeinrich Schuchardt no_chdir => 1, 3714fd65389SHeinrich Schuchardt }, "${lk_path}"); 3724fd65389SHeinrich Schuchardt} else { 3734fd65389SHeinrich Schuchardt push(@mfiles, "${lk_path}MAINTAINERS") if -f "${lk_path}MAINTAINERS"; 3744fd65389SHeinrich Schuchardt} 3754fd65389SHeinrich Schuchardt 3764fd65389SHeinrich Schuchardtforeach my $file (@mfiles) { 3774fd65389SHeinrich Schuchardt read_maintainer_file("$file"); 3784fd65389SHeinrich Schuchardt} 37992bca398SDaniel Schwierzeck 38092bca398SDaniel Schwierzeck# 38192bca398SDaniel Schwierzeck# Read mail address map 38292bca398SDaniel Schwierzeck# 38392bca398SDaniel Schwierzeck 38492bca398SDaniel Schwierzeckmy $mailmap; 38592bca398SDaniel Schwierzeck 38692bca398SDaniel Schwierzeckread_mailmap(); 38792bca398SDaniel Schwierzeck 38892bca398SDaniel Schwierzecksub read_mailmap { 38992bca398SDaniel Schwierzeck $mailmap = { 39092bca398SDaniel Schwierzeck names => {}, 39192bca398SDaniel Schwierzeck addresses => {} 39292bca398SDaniel Schwierzeck }; 39392bca398SDaniel Schwierzeck 39492bca398SDaniel Schwierzeck return if (!$email_use_mailmap || !(-f "${lk_path}.mailmap")); 39592bca398SDaniel Schwierzeck 39692bca398SDaniel Schwierzeck open(my $mailmap_file, '<', "${lk_path}.mailmap") 39792bca398SDaniel Schwierzeck or warn "$P: Can't open .mailmap: $!\n"; 39892bca398SDaniel Schwierzeck 39992bca398SDaniel Schwierzeck while (<$mailmap_file>) { 40092bca398SDaniel Schwierzeck s/#.*$//; #strip comments 40192bca398SDaniel Schwierzeck s/^\s+|\s+$//g; #trim 40292bca398SDaniel Schwierzeck 40392bca398SDaniel Schwierzeck next if (/^\s*$/); #skip empty lines 40492bca398SDaniel Schwierzeck #entries have one of the following formats: 40592bca398SDaniel Schwierzeck # name1 <mail1> 40692bca398SDaniel Schwierzeck # <mail1> <mail2> 40792bca398SDaniel Schwierzeck # name1 <mail1> <mail2> 40892bca398SDaniel Schwierzeck # name1 <mail1> name2 <mail2> 40992bca398SDaniel Schwierzeck # (see man git-shortlog) 41092bca398SDaniel Schwierzeck 41192bca398SDaniel Schwierzeck if (/^([^<]+)<([^>]+)>$/) { 41292bca398SDaniel Schwierzeck my $real_name = $1; 41392bca398SDaniel Schwierzeck my $address = $2; 41492bca398SDaniel Schwierzeck 41592bca398SDaniel Schwierzeck $real_name =~ s/\s+$//; 41692bca398SDaniel Schwierzeck ($real_name, $address) = parse_email("$real_name <$address>"); 41792bca398SDaniel Schwierzeck $mailmap->{names}->{$address} = $real_name; 41892bca398SDaniel Schwierzeck 41992bca398SDaniel Schwierzeck } elsif (/^<([^>]+)>\s*<([^>]+)>$/) { 42092bca398SDaniel Schwierzeck my $real_address = $1; 42192bca398SDaniel Schwierzeck my $wrong_address = $2; 42292bca398SDaniel Schwierzeck 42392bca398SDaniel Schwierzeck $mailmap->{addresses}->{$wrong_address} = $real_address; 42492bca398SDaniel Schwierzeck 42592bca398SDaniel Schwierzeck } elsif (/^(.+)<([^>]+)>\s*<([^>]+)>$/) { 42692bca398SDaniel Schwierzeck my $real_name = $1; 42792bca398SDaniel Schwierzeck my $real_address = $2; 42892bca398SDaniel Schwierzeck my $wrong_address = $3; 42992bca398SDaniel Schwierzeck 43092bca398SDaniel Schwierzeck $real_name =~ s/\s+$//; 43192bca398SDaniel Schwierzeck ($real_name, $real_address) = 43292bca398SDaniel Schwierzeck parse_email("$real_name <$real_address>"); 43392bca398SDaniel Schwierzeck $mailmap->{names}->{$wrong_address} = $real_name; 43492bca398SDaniel Schwierzeck $mailmap->{addresses}->{$wrong_address} = $real_address; 43592bca398SDaniel Schwierzeck 43692bca398SDaniel Schwierzeck } elsif (/^(.+)<([^>]+)>\s*(.+)\s*<([^>]+)>$/) { 43792bca398SDaniel Schwierzeck my $real_name = $1; 43892bca398SDaniel Schwierzeck my $real_address = $2; 43992bca398SDaniel Schwierzeck my $wrong_name = $3; 44092bca398SDaniel Schwierzeck my $wrong_address = $4; 44192bca398SDaniel Schwierzeck 44292bca398SDaniel Schwierzeck $real_name =~ s/\s+$//; 44392bca398SDaniel Schwierzeck ($real_name, $real_address) = 44492bca398SDaniel Schwierzeck parse_email("$real_name <$real_address>"); 44592bca398SDaniel Schwierzeck 44692bca398SDaniel Schwierzeck $wrong_name =~ s/\s+$//; 44792bca398SDaniel Schwierzeck ($wrong_name, $wrong_address) = 44892bca398SDaniel Schwierzeck parse_email("$wrong_name <$wrong_address>"); 44992bca398SDaniel Schwierzeck 45092bca398SDaniel Schwierzeck my $wrong_email = format_email($wrong_name, $wrong_address, 1); 45192bca398SDaniel Schwierzeck $mailmap->{names}->{$wrong_email} = $real_name; 45292bca398SDaniel Schwierzeck $mailmap->{addresses}->{$wrong_email} = $real_address; 45392bca398SDaniel Schwierzeck } 45492bca398SDaniel Schwierzeck } 45592bca398SDaniel Schwierzeck close($mailmap_file); 45692bca398SDaniel Schwierzeck} 45792bca398SDaniel Schwierzeck 45892bca398SDaniel Schwierzeck## use the filenames on the command line or find the filenames in the patchfiles 45992bca398SDaniel Schwierzeck 46092bca398SDaniel Schwierzeckmy @files = (); 46192bca398SDaniel Schwierzeckmy @range = (); 46292bca398SDaniel Schwierzeckmy @keyword_tvi = (); 46392bca398SDaniel Schwierzeckmy @file_emails = (); 46492bca398SDaniel Schwierzeck 46592bca398SDaniel Schwierzeckif (!@ARGV) { 46692bca398SDaniel Schwierzeck push(@ARGV, "&STDIN"); 46792bca398SDaniel Schwierzeck} 46892bca398SDaniel Schwierzeck 46992bca398SDaniel Schwierzeckforeach my $file (@ARGV) { 47092bca398SDaniel Schwierzeck if ($file ne "&STDIN") { 47192bca398SDaniel Schwierzeck ##if $file is a directory and it lacks a trailing slash, add one 47292bca398SDaniel Schwierzeck if ((-d $file)) { 47392bca398SDaniel Schwierzeck $file =~ s@([^/])$@$1/@; 47492bca398SDaniel Schwierzeck } elsif (!(-f $file)) { 47592bca398SDaniel Schwierzeck die "$P: file '${file}' not found\n"; 47692bca398SDaniel Schwierzeck } 47792bca398SDaniel Schwierzeck } 4784fd65389SHeinrich Schuchardt if ($from_filename || ($file ne "&STDIN" && vcs_file_exists($file))) { 4794fd65389SHeinrich Schuchardt $file =~ s/^\Q${cur_path}\E//; #strip any absolute path 4804fd65389SHeinrich Schuchardt $file =~ s/^\Q${lk_path}\E//; #or the path to the lk tree 48192bca398SDaniel Schwierzeck push(@files, $file); 48292bca398SDaniel Schwierzeck if ($file ne "MAINTAINERS" && -f $file && ($keywords || $file_emails)) { 48392bca398SDaniel Schwierzeck open(my $f, '<', $file) 48492bca398SDaniel Schwierzeck or die "$P: Can't open $file: $!\n"; 48592bca398SDaniel Schwierzeck my $text = do { local($/) ; <$f> }; 48692bca398SDaniel Schwierzeck close($f); 48792bca398SDaniel Schwierzeck if ($keywords) { 48892bca398SDaniel Schwierzeck foreach my $line (keys %keyword_hash) { 48992bca398SDaniel Schwierzeck if ($text =~ m/$keyword_hash{$line}/x) { 49092bca398SDaniel Schwierzeck push(@keyword_tvi, $line); 49192bca398SDaniel Schwierzeck } 49292bca398SDaniel Schwierzeck } 49392bca398SDaniel Schwierzeck } 49492bca398SDaniel Schwierzeck if ($file_emails) { 49592bca398SDaniel Schwierzeck 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; 49692bca398SDaniel Schwierzeck push(@file_emails, clean_file_emails(@poss_addr)); 49792bca398SDaniel Schwierzeck } 49892bca398SDaniel Schwierzeck } 49992bca398SDaniel Schwierzeck } else { 50092bca398SDaniel Schwierzeck my $file_cnt = @files; 50192bca398SDaniel Schwierzeck my $lastfile; 50292bca398SDaniel Schwierzeck 50392bca398SDaniel Schwierzeck open(my $patch, "< $file") 50492bca398SDaniel Schwierzeck or die "$P: Can't open $file: $!\n"; 50592bca398SDaniel Schwierzeck 50692bca398SDaniel Schwierzeck # We can check arbitrary information before the patch 50792bca398SDaniel Schwierzeck # like the commit message, mail headers, etc... 50892bca398SDaniel Schwierzeck # This allows us to match arbitrary keywords against any part 50992bca398SDaniel Schwierzeck # of a git format-patch generated file (subject tags, etc...) 51092bca398SDaniel Schwierzeck 51192bca398SDaniel Schwierzeck my $patch_prefix = ""; #Parsing the intro 51292bca398SDaniel Schwierzeck 51392bca398SDaniel Schwierzeck while (<$patch>) { 51492bca398SDaniel Schwierzeck my $patch_line = $_; 51592bca398SDaniel Schwierzeck if (m/^\+\+\+\s+(\S+)/ or m/^---\s+(\S+)/) { 51692bca398SDaniel Schwierzeck my $filename = $1; 51792bca398SDaniel Schwierzeck $filename =~ s@^[^/]*/@@; 51892bca398SDaniel Schwierzeck $filename =~ s@\n@@; 51992bca398SDaniel Schwierzeck $lastfile = $filename; 52092bca398SDaniel Schwierzeck push(@files, $filename); 52192bca398SDaniel Schwierzeck $patch_prefix = "^[+-].*"; #Now parsing the actual patch 52292bca398SDaniel Schwierzeck } elsif (m/^\@\@ -(\d+),(\d+)/) { 52392bca398SDaniel Schwierzeck if ($email_git_blame) { 52492bca398SDaniel Schwierzeck push(@range, "$lastfile:$1:$2"); 52592bca398SDaniel Schwierzeck } 52692bca398SDaniel Schwierzeck } elsif ($keywords) { 52792bca398SDaniel Schwierzeck foreach my $line (keys %keyword_hash) { 52892bca398SDaniel Schwierzeck if ($patch_line =~ m/${patch_prefix}$keyword_hash{$line}/x) { 52992bca398SDaniel Schwierzeck push(@keyword_tvi, $line); 53092bca398SDaniel Schwierzeck } 53192bca398SDaniel Schwierzeck } 53292bca398SDaniel Schwierzeck } 53392bca398SDaniel Schwierzeck } 53492bca398SDaniel Schwierzeck close($patch); 53592bca398SDaniel Schwierzeck 53692bca398SDaniel Schwierzeck if ($file_cnt == @files) { 53792bca398SDaniel Schwierzeck warn "$P: file '${file}' doesn't appear to be a patch. " 53892bca398SDaniel Schwierzeck . "Add -f to options?\n"; 53992bca398SDaniel Schwierzeck } 54092bca398SDaniel Schwierzeck @files = sort_and_uniq(@files); 54192bca398SDaniel Schwierzeck } 54292bca398SDaniel Schwierzeck} 54392bca398SDaniel Schwierzeck 54492bca398SDaniel Schwierzeck@file_emails = uniq(@file_emails); 54592bca398SDaniel Schwierzeck 54692bca398SDaniel Schwierzeckmy %email_hash_name; 54792bca398SDaniel Schwierzeckmy %email_hash_address; 54892bca398SDaniel Schwierzeckmy @email_to = (); 54992bca398SDaniel Schwierzeckmy %hash_list_to; 55092bca398SDaniel Schwierzeckmy @list_to = (); 55192bca398SDaniel Schwierzeckmy @scm = (); 55292bca398SDaniel Schwierzeckmy @web = (); 55392bca398SDaniel Schwierzeckmy @subsystem = (); 55492bca398SDaniel Schwierzeckmy @status = (); 55592bca398SDaniel Schwierzeckmy %deduplicate_name_hash = (); 55692bca398SDaniel Schwierzeckmy %deduplicate_address_hash = (); 55792bca398SDaniel Schwierzeck 55892bca398SDaniel Schwierzeckmy @maintainers = get_maintainers(); 55992bca398SDaniel Schwierzeck 56092bca398SDaniel Schwierzeckif (@maintainers) { 56192bca398SDaniel Schwierzeck @maintainers = merge_email(@maintainers); 56292bca398SDaniel Schwierzeck output(@maintainers); 56392bca398SDaniel Schwierzeck} 56492bca398SDaniel Schwierzeck 56592bca398SDaniel Schwierzeckif ($scm) { 56692bca398SDaniel Schwierzeck @scm = uniq(@scm); 56792bca398SDaniel Schwierzeck output(@scm); 56892bca398SDaniel Schwierzeck} 56992bca398SDaniel Schwierzeck 57092bca398SDaniel Schwierzeckif ($status) { 57192bca398SDaniel Schwierzeck @status = uniq(@status); 57292bca398SDaniel Schwierzeck output(@status); 57392bca398SDaniel Schwierzeck} 57492bca398SDaniel Schwierzeck 57592bca398SDaniel Schwierzeckif ($subsystem) { 57692bca398SDaniel Schwierzeck @subsystem = uniq(@subsystem); 57792bca398SDaniel Schwierzeck output(@subsystem); 57892bca398SDaniel Schwierzeck} 57992bca398SDaniel Schwierzeck 58092bca398SDaniel Schwierzeckif ($web) { 58192bca398SDaniel Schwierzeck @web = uniq(@web); 58292bca398SDaniel Schwierzeck output(@web); 58392bca398SDaniel Schwierzeck} 58492bca398SDaniel Schwierzeck 58592bca398SDaniel Schwierzeckexit($exit); 58692bca398SDaniel Schwierzeck 5874fd65389SHeinrich Schuchardtsub ignore_email_address { 5884fd65389SHeinrich Schuchardt my ($address) = @_; 5894fd65389SHeinrich Schuchardt 5904fd65389SHeinrich Schuchardt foreach my $ignore (@ignore_emails) { 5914fd65389SHeinrich Schuchardt return 1 if ($ignore eq $address); 5924fd65389SHeinrich Schuchardt } 5934fd65389SHeinrich Schuchardt 5944fd65389SHeinrich Schuchardt return 0; 5954fd65389SHeinrich Schuchardt} 5964fd65389SHeinrich Schuchardt 59792bca398SDaniel Schwierzecksub range_is_maintained { 59892bca398SDaniel Schwierzeck my ($start, $end) = @_; 59992bca398SDaniel Schwierzeck 60092bca398SDaniel Schwierzeck for (my $i = $start; $i < $end; $i++) { 60192bca398SDaniel Schwierzeck my $line = $typevalue[$i]; 60235729218SHeiko Schocher if ($line =~ m/^([A-Z]):\s*(.*)/) { 60392bca398SDaniel Schwierzeck my $type = $1; 60492bca398SDaniel Schwierzeck my $value = $2; 60592bca398SDaniel Schwierzeck if ($type eq 'S') { 60692bca398SDaniel Schwierzeck if ($value =~ /(maintain|support)/i) { 60792bca398SDaniel Schwierzeck return 1; 60892bca398SDaniel Schwierzeck } 60992bca398SDaniel Schwierzeck } 61092bca398SDaniel Schwierzeck } 61192bca398SDaniel Schwierzeck } 61292bca398SDaniel Schwierzeck return 0; 61392bca398SDaniel Schwierzeck} 61492bca398SDaniel Schwierzeck 61592bca398SDaniel Schwierzecksub range_has_maintainer { 61692bca398SDaniel Schwierzeck my ($start, $end) = @_; 61792bca398SDaniel Schwierzeck 61892bca398SDaniel Schwierzeck for (my $i = $start; $i < $end; $i++) { 61992bca398SDaniel Schwierzeck my $line = $typevalue[$i]; 62035729218SHeiko Schocher if ($line =~ m/^([A-Z]):\s*(.*)/) { 62192bca398SDaniel Schwierzeck my $type = $1; 62292bca398SDaniel Schwierzeck my $value = $2; 62392bca398SDaniel Schwierzeck if ($type eq 'M') { 62492bca398SDaniel Schwierzeck return 1; 62592bca398SDaniel Schwierzeck } 62692bca398SDaniel Schwierzeck } 62792bca398SDaniel Schwierzeck } 62892bca398SDaniel Schwierzeck return 0; 62992bca398SDaniel Schwierzeck} 63092bca398SDaniel Schwierzeck 63192bca398SDaniel Schwierzecksub get_maintainers { 63292bca398SDaniel Schwierzeck %email_hash_name = (); 63392bca398SDaniel Schwierzeck %email_hash_address = (); 63492bca398SDaniel Schwierzeck %commit_author_hash = (); 63592bca398SDaniel Schwierzeck %commit_signer_hash = (); 63692bca398SDaniel Schwierzeck @email_to = (); 63792bca398SDaniel Schwierzeck %hash_list_to = (); 63892bca398SDaniel Schwierzeck @list_to = (); 63992bca398SDaniel Schwierzeck @scm = (); 64092bca398SDaniel Schwierzeck @web = (); 64192bca398SDaniel Schwierzeck @subsystem = (); 64292bca398SDaniel Schwierzeck @status = (); 64392bca398SDaniel Schwierzeck %deduplicate_name_hash = (); 64492bca398SDaniel Schwierzeck %deduplicate_address_hash = (); 64592bca398SDaniel Schwierzeck if ($email_git_all_signature_types) { 64692bca398SDaniel Schwierzeck $signature_pattern = "(.+?)[Bb][Yy]:"; 64792bca398SDaniel Schwierzeck } else { 64892bca398SDaniel Schwierzeck $signature_pattern = "\(" . join("|", @signature_tags) . "\)"; 64992bca398SDaniel Schwierzeck } 65092bca398SDaniel Schwierzeck 65192bca398SDaniel Schwierzeck # Find responsible parties 65292bca398SDaniel Schwierzeck 65392bca398SDaniel Schwierzeck my %exact_pattern_match_hash = (); 65492bca398SDaniel Schwierzeck 65592bca398SDaniel Schwierzeck foreach my $file (@files) { 65692bca398SDaniel Schwierzeck 65792bca398SDaniel Schwierzeck my %hash; 65892bca398SDaniel Schwierzeck my $tvi = find_first_section(); 65992bca398SDaniel Schwierzeck while ($tvi < @typevalue) { 66092bca398SDaniel Schwierzeck my $start = find_starting_index($tvi); 66192bca398SDaniel Schwierzeck my $end = find_ending_index($tvi); 66292bca398SDaniel Schwierzeck my $exclude = 0; 66392bca398SDaniel Schwierzeck my $i; 66492bca398SDaniel Schwierzeck 66592bca398SDaniel Schwierzeck #Do not match excluded file patterns 66692bca398SDaniel Schwierzeck 66792bca398SDaniel Schwierzeck for ($i = $start; $i < $end; $i++) { 66892bca398SDaniel Schwierzeck my $line = $typevalue[$i]; 66935729218SHeiko Schocher if ($line =~ m/^([A-Z]):\s*(.*)/) { 67092bca398SDaniel Schwierzeck my $type = $1; 67192bca398SDaniel Schwierzeck my $value = $2; 67292bca398SDaniel Schwierzeck if ($type eq 'X') { 67392bca398SDaniel Schwierzeck if (file_match_pattern($file, $value)) { 67492bca398SDaniel Schwierzeck $exclude = 1; 67592bca398SDaniel Schwierzeck last; 67692bca398SDaniel Schwierzeck } 67792bca398SDaniel Schwierzeck } 67892bca398SDaniel Schwierzeck } 67992bca398SDaniel Schwierzeck } 68092bca398SDaniel Schwierzeck 68192bca398SDaniel Schwierzeck if (!$exclude) { 68292bca398SDaniel Schwierzeck for ($i = $start; $i < $end; $i++) { 68392bca398SDaniel Schwierzeck my $line = $typevalue[$i]; 68435729218SHeiko Schocher if ($line =~ m/^([A-Z]):\s*(.*)/) { 68592bca398SDaniel Schwierzeck my $type = $1; 68692bca398SDaniel Schwierzeck my $value = $2; 68792bca398SDaniel Schwierzeck if ($type eq 'F') { 68892bca398SDaniel Schwierzeck if (file_match_pattern($file, $value)) { 68992bca398SDaniel Schwierzeck my $value_pd = ($value =~ tr@/@@); 69092bca398SDaniel Schwierzeck my $file_pd = ($file =~ tr@/@@); 69192bca398SDaniel Schwierzeck $value_pd++ if (substr($value,-1,1) ne "/"); 69292bca398SDaniel Schwierzeck $value_pd = -1 if ($value =~ /^\.\*/); 69392bca398SDaniel Schwierzeck if ($value_pd >= $file_pd && 69492bca398SDaniel Schwierzeck range_is_maintained($start, $end) && 69592bca398SDaniel Schwierzeck range_has_maintainer($start, $end)) { 69692bca398SDaniel Schwierzeck $exact_pattern_match_hash{$file} = 1; 69792bca398SDaniel Schwierzeck } 69892bca398SDaniel Schwierzeck if ($pattern_depth == 0 || 69992bca398SDaniel Schwierzeck (($file_pd - $value_pd) < $pattern_depth)) { 70092bca398SDaniel Schwierzeck $hash{$tvi} = $value_pd; 70192bca398SDaniel Schwierzeck } 70292bca398SDaniel Schwierzeck } 70392bca398SDaniel Schwierzeck } elsif ($type eq 'N') { 70492bca398SDaniel Schwierzeck if ($file =~ m/$value/x) { 70592bca398SDaniel Schwierzeck $hash{$tvi} = 0; 70692bca398SDaniel Schwierzeck } 70792bca398SDaniel Schwierzeck } 70892bca398SDaniel Schwierzeck } 70992bca398SDaniel Schwierzeck } 71092bca398SDaniel Schwierzeck } 71192bca398SDaniel Schwierzeck $tvi = $end + 1; 71292bca398SDaniel Schwierzeck } 71392bca398SDaniel Schwierzeck 71492bca398SDaniel Schwierzeck foreach my $line (sort {$hash{$b} <=> $hash{$a}} keys %hash) { 71592bca398SDaniel Schwierzeck add_categories($line); 71692bca398SDaniel Schwierzeck if ($sections) { 71792bca398SDaniel Schwierzeck my $i; 71892bca398SDaniel Schwierzeck my $start = find_starting_index($line); 71992bca398SDaniel Schwierzeck my $end = find_ending_index($line); 72092bca398SDaniel Schwierzeck for ($i = $start; $i < $end; $i++) { 72192bca398SDaniel Schwierzeck my $line = $typevalue[$i]; 72292bca398SDaniel Schwierzeck if ($line =~ /^[FX]:/) { ##Restore file patterns 72392bca398SDaniel Schwierzeck $line =~ s/([^\\])\.([^\*])/$1\?$2/g; 72492bca398SDaniel Schwierzeck $line =~ s/([^\\])\.$/$1\?/g; ##Convert . back to ? 72592bca398SDaniel Schwierzeck $line =~ s/\\\./\./g; ##Convert \. to . 72692bca398SDaniel Schwierzeck $line =~ s/\.\*/\*/g; ##Convert .* to * 72792bca398SDaniel Schwierzeck } 7284fd65389SHeinrich Schuchardt my $count = $line =~ s/^([A-Z]):/$1:\t/g; 7294fd65389SHeinrich Schuchardt if ($letters eq "" || (!$count || $letters =~ /$1/i)) { 73092bca398SDaniel Schwierzeck print("$line\n"); 73192bca398SDaniel Schwierzeck } 7324fd65389SHeinrich Schuchardt } 73392bca398SDaniel Schwierzeck print("\n"); 73492bca398SDaniel Schwierzeck } 73592bca398SDaniel Schwierzeck } 73692bca398SDaniel Schwierzeck } 73792bca398SDaniel Schwierzeck 73892bca398SDaniel Schwierzeck if ($keywords) { 73992bca398SDaniel Schwierzeck @keyword_tvi = sort_and_uniq(@keyword_tvi); 74092bca398SDaniel Schwierzeck foreach my $line (@keyword_tvi) { 74192bca398SDaniel Schwierzeck add_categories($line); 74292bca398SDaniel Schwierzeck } 74392bca398SDaniel Schwierzeck } 74492bca398SDaniel Schwierzeck 74592bca398SDaniel Schwierzeck foreach my $email (@email_to, @list_to) { 74692bca398SDaniel Schwierzeck $email->[0] = deduplicate_email($email->[0]); 74792bca398SDaniel Schwierzeck } 74892bca398SDaniel Schwierzeck 74992bca398SDaniel Schwierzeck foreach my $file (@files) { 75092bca398SDaniel Schwierzeck if ($email && 75192bca398SDaniel Schwierzeck ($email_git || ($email_git_fallback && 75292bca398SDaniel Schwierzeck !$exact_pattern_match_hash{$file}))) { 75392bca398SDaniel Schwierzeck vcs_file_signoffs($file); 75492bca398SDaniel Schwierzeck } 75592bca398SDaniel Schwierzeck if ($email && $email_git_blame) { 75692bca398SDaniel Schwierzeck vcs_file_blame($file); 75792bca398SDaniel Schwierzeck } 75892bca398SDaniel Schwierzeck } 75992bca398SDaniel Schwierzeck 76092bca398SDaniel Schwierzeck if ($email) { 76192bca398SDaniel Schwierzeck foreach my $chief (@penguin_chief) { 76292bca398SDaniel Schwierzeck if ($chief =~ m/^(.*):(.*)/) { 76392bca398SDaniel Schwierzeck my $email_address; 76492bca398SDaniel Schwierzeck 76592bca398SDaniel Schwierzeck $email_address = format_email($1, $2, $email_usename); 76692bca398SDaniel Schwierzeck if ($email_git_penguin_chiefs) { 76792bca398SDaniel Schwierzeck push(@email_to, [$email_address, 'chief penguin']); 76892bca398SDaniel Schwierzeck } else { 76992bca398SDaniel Schwierzeck @email_to = grep($_->[0] !~ /${email_address}/, @email_to); 77092bca398SDaniel Schwierzeck } 77192bca398SDaniel Schwierzeck } 77292bca398SDaniel Schwierzeck } 77392bca398SDaniel Schwierzeck 77492bca398SDaniel Schwierzeck foreach my $email (@file_emails) { 77592bca398SDaniel Schwierzeck my ($name, $address) = parse_email($email); 77692bca398SDaniel Schwierzeck 77792bca398SDaniel Schwierzeck my $tmp_email = format_email($name, $address, $email_usename); 77892bca398SDaniel Schwierzeck push_email_address($tmp_email, ''); 77992bca398SDaniel Schwierzeck add_role($tmp_email, 'in file'); 78092bca398SDaniel Schwierzeck } 78192bca398SDaniel Schwierzeck } 78292bca398SDaniel Schwierzeck 78392bca398SDaniel Schwierzeck my @to = (); 78492bca398SDaniel Schwierzeck if ($email || $email_list) { 78592bca398SDaniel Schwierzeck if ($email) { 78692bca398SDaniel Schwierzeck @to = (@to, @email_to); 78792bca398SDaniel Schwierzeck } 78892bca398SDaniel Schwierzeck if ($email_list) { 78992bca398SDaniel Schwierzeck @to = (@to, @list_to); 79092bca398SDaniel Schwierzeck } 79192bca398SDaniel Schwierzeck } 79292bca398SDaniel Schwierzeck 79392bca398SDaniel Schwierzeck if ($interactive) { 79492bca398SDaniel Schwierzeck @to = interactive_get_maintainers(\@to); 79592bca398SDaniel Schwierzeck } 79692bca398SDaniel Schwierzeck 79792bca398SDaniel Schwierzeck return @to; 79892bca398SDaniel Schwierzeck} 79992bca398SDaniel Schwierzeck 80092bca398SDaniel Schwierzecksub file_match_pattern { 80192bca398SDaniel Schwierzeck my ($file, $pattern) = @_; 80292bca398SDaniel Schwierzeck if (substr($pattern, -1) eq "/") { 80392bca398SDaniel Schwierzeck if ($file =~ m@^$pattern@) { 80492bca398SDaniel Schwierzeck return 1; 80592bca398SDaniel Schwierzeck } 80692bca398SDaniel Schwierzeck } else { 80792bca398SDaniel Schwierzeck if ($file =~ m@^$pattern@) { 80892bca398SDaniel Schwierzeck my $s1 = ($file =~ tr@/@@); 80992bca398SDaniel Schwierzeck my $s2 = ($pattern =~ tr@/@@); 81092bca398SDaniel Schwierzeck if ($s1 == $s2) { 81192bca398SDaniel Schwierzeck return 1; 81292bca398SDaniel Schwierzeck } 81392bca398SDaniel Schwierzeck } 81492bca398SDaniel Schwierzeck } 81592bca398SDaniel Schwierzeck return 0; 81692bca398SDaniel Schwierzeck} 81792bca398SDaniel Schwierzeck 81892bca398SDaniel Schwierzecksub usage { 81992bca398SDaniel Schwierzeck print <<EOT; 82092bca398SDaniel Schwierzeckusage: $P [options] patchfile 82192bca398SDaniel Schwierzeck $P [options] -f file|directory 82292bca398SDaniel Schwierzeckversion: $V 82392bca398SDaniel Schwierzeck 82492bca398SDaniel SchwierzeckMAINTAINER field selection options: 82592bca398SDaniel Schwierzeck --email => print email address(es) if any 82692bca398SDaniel Schwierzeck --git => include recent git \*-by: signers 82792bca398SDaniel Schwierzeck --git-all-signature-types => include signers regardless of signature type 82892bca398SDaniel Schwierzeck or use only ${signature_pattern} signers (default: $email_git_all_signature_types) 82992bca398SDaniel Schwierzeck --git-fallback => use git when no exact MAINTAINERS pattern (default: $email_git_fallback) 83092bca398SDaniel Schwierzeck --git-chief-penguins => include ${penguin_chiefs} 83192bca398SDaniel Schwierzeck --git-min-signatures => number of signatures required (default: $email_git_min_signatures) 83292bca398SDaniel Schwierzeck --git-max-maintainers => maximum maintainers to add (default: $email_git_max_maintainers) 83392bca398SDaniel Schwierzeck --git-min-percent => minimum percentage of commits required (default: $email_git_min_percent) 83492bca398SDaniel Schwierzeck --git-blame => use git blame to find modified commits for patch or file 8354fd65389SHeinrich Schuchardt --git-blame-signatures => when used with --git-blame, also include all commit signers 83692bca398SDaniel Schwierzeck --git-since => git history to use (default: $email_git_since) 83792bca398SDaniel Schwierzeck --hg-since => hg history to use (default: $email_hg_since) 83892bca398SDaniel Schwierzeck --interactive => display a menu (mostly useful if used with the --git option) 83992bca398SDaniel Schwierzeck --m => include maintainer(s) if any 8404fd65389SHeinrich Schuchardt --r => include reviewer(s) if any 84192bca398SDaniel Schwierzeck --n => include name 'Full Name <addr\@domain.tld>' 84292bca398SDaniel Schwierzeck --l => include list(s) if any 84392bca398SDaniel Schwierzeck --s => include subscriber only list(s) if any 84492bca398SDaniel Schwierzeck --remove-duplicates => minimize duplicate email names/addresses 84592bca398SDaniel Schwierzeck --roles => show roles (status:subsystem, git-signer, list, etc...) 84692bca398SDaniel Schwierzeck --rolestats => show roles and statistics (commits/total_commits, %) 84792bca398SDaniel Schwierzeck --file-emails => add email addresses found in -f file (default: 0 (off)) 84892bca398SDaniel Schwierzeck --scm => print SCM tree(s) if any 84992bca398SDaniel Schwierzeck --status => print status if any 85092bca398SDaniel Schwierzeck --subsystem => print subsystem name if any 85192bca398SDaniel Schwierzeck --web => print website(s) if any 85292bca398SDaniel Schwierzeck 85392bca398SDaniel SchwierzeckOutput type options: 85492bca398SDaniel Schwierzeck --separator [, ] => separator for multiple entries on 1 line 85592bca398SDaniel Schwierzeck using --separator also sets --nomultiline if --separator is not [, ] 85692bca398SDaniel Schwierzeck --multiline => print 1 entry per line 85792bca398SDaniel Schwierzeck 85892bca398SDaniel SchwierzeckOther options: 85992bca398SDaniel Schwierzeck --pattern-depth => Number of pattern directory traversals (default: 0 (all)) 86092bca398SDaniel Schwierzeck --keywords => scan patch for keywords (default: $keywords) 86192bca398SDaniel Schwierzeck --sections => print all of the subsystem sections with pattern matches 8624fd65389SHeinrich Schuchardt --letters => print all matching 'letter' types from all matching sections 86392bca398SDaniel Schwierzeck --mailmap => use .mailmap file (default: $email_use_mailmap) 86492bca398SDaniel Schwierzeck --version => show version 86592bca398SDaniel Schwierzeck --help => show this help information 86692bca398SDaniel Schwierzeck 86792bca398SDaniel SchwierzeckDefault options: 8684fd65389SHeinrich Schuchardt [--email --nogit --git-fallback --m --r --n --l --multiline --pattern-depth=0 86992bca398SDaniel Schwierzeck --remove-duplicates --rolestats] 87092bca398SDaniel Schwierzeck 87192bca398SDaniel SchwierzeckNotes: 87292bca398SDaniel Schwierzeck Using "-f directory" may give unexpected results: 87392bca398SDaniel Schwierzeck Used with "--git", git signators for _all_ files in and below 87492bca398SDaniel Schwierzeck directory are examined as git recurses directories. 87592bca398SDaniel Schwierzeck Any specified X: (exclude) pattern matches are _not_ ignored. 87692bca398SDaniel Schwierzeck Used with "--nogit", directory is used as a pattern match, 87792bca398SDaniel Schwierzeck no individual file within the directory or subdirectory 87892bca398SDaniel Schwierzeck is matched. 87992bca398SDaniel Schwierzeck Used with "--git-blame", does not iterate all files in directory 88092bca398SDaniel Schwierzeck Using "--git-blame" is slow and may add old committers and authors 88192bca398SDaniel Schwierzeck that are no longer active maintainers to the output. 88292bca398SDaniel Schwierzeck Using "--roles" or "--rolestats" with git send-email --cc-cmd or any 88392bca398SDaniel Schwierzeck other automated tools that expect only ["name"] <email address> 88492bca398SDaniel Schwierzeck may not work because of additional output after <email address>. 88592bca398SDaniel Schwierzeck Using "--rolestats" and "--git-blame" shows the #/total=% commits, 88692bca398SDaniel Schwierzeck not the percentage of the entire file authored. # of commits is 88792bca398SDaniel Schwierzeck not a good measure of amount of code authored. 1 major commit may 88892bca398SDaniel Schwierzeck contain a thousand lines, 5 trivial commits may modify a single line. 88992bca398SDaniel Schwierzeck If git is not installed, but mercurial (hg) is installed and an .hg 89092bca398SDaniel Schwierzeck repository exists, the following options apply to mercurial: 89192bca398SDaniel Schwierzeck --git, 89292bca398SDaniel Schwierzeck --git-min-signatures, --git-max-maintainers, --git-min-percent, and 89392bca398SDaniel Schwierzeck --git-blame 89492bca398SDaniel Schwierzeck Use --hg-since not --git-since to control date selection 89592bca398SDaniel Schwierzeck File ".get_maintainer.conf", if it exists in the linux kernel source root 89692bca398SDaniel Schwierzeck directory, can change whatever get_maintainer defaults are desired. 89792bca398SDaniel Schwierzeck Entries in this file can be any command line argument. 89892bca398SDaniel Schwierzeck This file is prepended to any additional command line arguments. 89992bca398SDaniel Schwierzeck Multiple lines and # comments are allowed. 9004fd65389SHeinrich Schuchardt Most options have both positive and negative forms. 9014fd65389SHeinrich Schuchardt The negative forms for --<foo> are --no<foo> and --no-<foo>. 9024fd65389SHeinrich Schuchardt 90392bca398SDaniel SchwierzeckEOT 90492bca398SDaniel Schwierzeck} 90592bca398SDaniel Schwierzeck 90692bca398SDaniel Schwierzecksub top_of_kernel_tree { 90792bca398SDaniel Schwierzeck my ($lk_path) = @_; 90892bca398SDaniel Schwierzeck 90992bca398SDaniel Schwierzeck if ($lk_path ne "" && substr($lk_path,length($lk_path)-1,1) ne "/") { 91092bca398SDaniel Schwierzeck $lk_path .= "/"; 91192bca398SDaniel Schwierzeck } 91227e77183SDaniel Schwierzeck if ( (-f "${lk_path}Kbuild") 9134fd65389SHeinrich Schuchardt && (-e "${lk_path}MAINTAINERS") 91492bca398SDaniel Schwierzeck && (-f "${lk_path}Makefile") 91592bca398SDaniel Schwierzeck && (-f "${lk_path}README") 91692bca398SDaniel Schwierzeck && (-d "${lk_path}arch") 917ee360cd2SDaniel Schwierzeck && (-d "${lk_path}board") 918ee360cd2SDaniel Schwierzeck && (-d "${lk_path}common") 919ee360cd2SDaniel Schwierzeck && (-d "${lk_path}doc") 92092bca398SDaniel Schwierzeck && (-d "${lk_path}drivers") 921ee360cd2SDaniel Schwierzeck && (-d "${lk_path}dts") 92292bca398SDaniel Schwierzeck && (-d "${lk_path}fs") 92392bca398SDaniel Schwierzeck && (-d "${lk_path}lib") 924ee360cd2SDaniel Schwierzeck && (-d "${lk_path}include") 925ee360cd2SDaniel Schwierzeck && (-d "${lk_path}net") 926ee360cd2SDaniel Schwierzeck && (-d "${lk_path}post") 927ee360cd2SDaniel Schwierzeck && (-d "${lk_path}scripts") 928ee360cd2SDaniel Schwierzeck && (-d "${lk_path}test") 929ee360cd2SDaniel Schwierzeck && (-d "${lk_path}tools")) { 93092bca398SDaniel Schwierzeck return 1; 93192bca398SDaniel Schwierzeck } 93292bca398SDaniel Schwierzeck return 0; 93392bca398SDaniel Schwierzeck} 93492bca398SDaniel Schwierzeck 93592bca398SDaniel Schwierzecksub parse_email { 93692bca398SDaniel Schwierzeck my ($formatted_email) = @_; 93792bca398SDaniel Schwierzeck 93892bca398SDaniel Schwierzeck my $name = ""; 93992bca398SDaniel Schwierzeck my $address = ""; 94092bca398SDaniel Schwierzeck 94192bca398SDaniel Schwierzeck if ($formatted_email =~ /^([^<]+)<(.+\@.*)>.*$/) { 94292bca398SDaniel Schwierzeck $name = $1; 94392bca398SDaniel Schwierzeck $address = $2; 94492bca398SDaniel Schwierzeck } elsif ($formatted_email =~ /^\s*<(.+\@\S*)>.*$/) { 94592bca398SDaniel Schwierzeck $address = $1; 94692bca398SDaniel Schwierzeck } elsif ($formatted_email =~ /^(.+\@\S*).*$/) { 94792bca398SDaniel Schwierzeck $address = $1; 94892bca398SDaniel Schwierzeck } 94992bca398SDaniel Schwierzeck 95092bca398SDaniel Schwierzeck $name =~ s/^\s+|\s+$//g; 95192bca398SDaniel Schwierzeck $name =~ s/^\"|\"$//g; 95292bca398SDaniel Schwierzeck $address =~ s/^\s+|\s+$//g; 95392bca398SDaniel Schwierzeck 95492bca398SDaniel Schwierzeck if ($name =~ /[^\w \-]/i) { ##has "must quote" chars 95592bca398SDaniel Schwierzeck $name =~ s/(?<!\\)"/\\"/g; ##escape quotes 95692bca398SDaniel Schwierzeck $name = "\"$name\""; 95792bca398SDaniel Schwierzeck } 95892bca398SDaniel Schwierzeck 95992bca398SDaniel Schwierzeck return ($name, $address); 96092bca398SDaniel Schwierzeck} 96192bca398SDaniel Schwierzeck 96292bca398SDaniel Schwierzecksub format_email { 96392bca398SDaniel Schwierzeck my ($name, $address, $usename) = @_; 96492bca398SDaniel Schwierzeck 96592bca398SDaniel Schwierzeck my $formatted_email; 96692bca398SDaniel Schwierzeck 96792bca398SDaniel Schwierzeck $name =~ s/^\s+|\s+$//g; 96892bca398SDaniel Schwierzeck $name =~ s/^\"|\"$//g; 96992bca398SDaniel Schwierzeck $address =~ s/^\s+|\s+$//g; 97092bca398SDaniel Schwierzeck 97192bca398SDaniel Schwierzeck if ($name =~ /[^\w \-]/i) { ##has "must quote" chars 97292bca398SDaniel Schwierzeck $name =~ s/(?<!\\)"/\\"/g; ##escape quotes 97392bca398SDaniel Schwierzeck $name = "\"$name\""; 97492bca398SDaniel Schwierzeck } 97592bca398SDaniel Schwierzeck 97692bca398SDaniel Schwierzeck if ($usename) { 97792bca398SDaniel Schwierzeck if ("$name" eq "") { 97892bca398SDaniel Schwierzeck $formatted_email = "$address"; 97992bca398SDaniel Schwierzeck } else { 98092bca398SDaniel Schwierzeck $formatted_email = "$name <$address>"; 98192bca398SDaniel Schwierzeck } 98292bca398SDaniel Schwierzeck } else { 98392bca398SDaniel Schwierzeck $formatted_email = $address; 98492bca398SDaniel Schwierzeck } 98592bca398SDaniel Schwierzeck 98692bca398SDaniel Schwierzeck return $formatted_email; 98792bca398SDaniel Schwierzeck} 98892bca398SDaniel Schwierzeck 98992bca398SDaniel Schwierzecksub find_first_section { 99092bca398SDaniel Schwierzeck my $index = 0; 99192bca398SDaniel Schwierzeck 99292bca398SDaniel Schwierzeck while ($index < @typevalue) { 99392bca398SDaniel Schwierzeck my $tv = $typevalue[$index]; 99435729218SHeiko Schocher if (($tv =~ m/^([A-Z]):\s*(.*)/)) { 99592bca398SDaniel Schwierzeck last; 99692bca398SDaniel Schwierzeck } 99792bca398SDaniel Schwierzeck $index++; 99892bca398SDaniel Schwierzeck } 99992bca398SDaniel Schwierzeck 100092bca398SDaniel Schwierzeck return $index; 100192bca398SDaniel Schwierzeck} 100292bca398SDaniel Schwierzeck 100392bca398SDaniel Schwierzecksub find_starting_index { 100492bca398SDaniel Schwierzeck my ($index) = @_; 100592bca398SDaniel Schwierzeck 100692bca398SDaniel Schwierzeck while ($index > 0) { 100792bca398SDaniel Schwierzeck my $tv = $typevalue[$index]; 100835729218SHeiko Schocher if (!($tv =~ m/^([A-Z]):\s*(.*)/)) { 100992bca398SDaniel Schwierzeck last; 101092bca398SDaniel Schwierzeck } 101192bca398SDaniel Schwierzeck $index--; 101292bca398SDaniel Schwierzeck } 101392bca398SDaniel Schwierzeck 101492bca398SDaniel Schwierzeck return $index; 101592bca398SDaniel Schwierzeck} 101692bca398SDaniel Schwierzeck 101792bca398SDaniel Schwierzecksub find_ending_index { 101892bca398SDaniel Schwierzeck my ($index) = @_; 101992bca398SDaniel Schwierzeck 102092bca398SDaniel Schwierzeck while ($index < @typevalue) { 102192bca398SDaniel Schwierzeck my $tv = $typevalue[$index]; 102235729218SHeiko Schocher if (!($tv =~ m/^([A-Z]):\s*(.*)/)) { 102392bca398SDaniel Schwierzeck last; 102492bca398SDaniel Schwierzeck } 102592bca398SDaniel Schwierzeck $index++; 102692bca398SDaniel Schwierzeck } 102792bca398SDaniel Schwierzeck 102892bca398SDaniel Schwierzeck return $index; 102992bca398SDaniel Schwierzeck} 103092bca398SDaniel Schwierzeck 10314fd65389SHeinrich Schuchardtsub get_subsystem_name { 10324fd65389SHeinrich Schuchardt my ($index) = @_; 10334fd65389SHeinrich Schuchardt 10344fd65389SHeinrich Schuchardt my $start = find_starting_index($index); 10354fd65389SHeinrich Schuchardt 10364fd65389SHeinrich Schuchardt my $subsystem = $typevalue[$start]; 10374fd65389SHeinrich Schuchardt if ($output_section_maxlen && length($subsystem) > $output_section_maxlen) { 10384fd65389SHeinrich Schuchardt $subsystem = substr($subsystem, 0, $output_section_maxlen - 3); 10394fd65389SHeinrich Schuchardt $subsystem =~ s/\s*$//; 10404fd65389SHeinrich Schuchardt $subsystem = $subsystem . "..."; 10414fd65389SHeinrich Schuchardt } 10424fd65389SHeinrich Schuchardt return $subsystem; 10434fd65389SHeinrich Schuchardt} 10444fd65389SHeinrich Schuchardt 104592bca398SDaniel Schwierzecksub get_maintainer_role { 104692bca398SDaniel Schwierzeck my ($index) = @_; 104792bca398SDaniel Schwierzeck 104892bca398SDaniel Schwierzeck my $i; 104992bca398SDaniel Schwierzeck my $start = find_starting_index($index); 105092bca398SDaniel Schwierzeck my $end = find_ending_index($index); 105192bca398SDaniel Schwierzeck 105292bca398SDaniel Schwierzeck my $role = "unknown"; 10534fd65389SHeinrich Schuchardt my $subsystem = get_subsystem_name($index); 105492bca398SDaniel Schwierzeck 105592bca398SDaniel Schwierzeck for ($i = $start + 1; $i < $end; $i++) { 105692bca398SDaniel Schwierzeck my $tv = $typevalue[$i]; 105735729218SHeiko Schocher if ($tv =~ m/^([A-Z]):\s*(.*)/) { 105892bca398SDaniel Schwierzeck my $ptype = $1; 105992bca398SDaniel Schwierzeck my $pvalue = $2; 106092bca398SDaniel Schwierzeck if ($ptype eq "S") { 106192bca398SDaniel Schwierzeck $role = $pvalue; 106292bca398SDaniel Schwierzeck } 106392bca398SDaniel Schwierzeck } 106492bca398SDaniel Schwierzeck } 106592bca398SDaniel Schwierzeck 106692bca398SDaniel Schwierzeck $role = lc($role); 106792bca398SDaniel Schwierzeck if ($role eq "supported") { 106892bca398SDaniel Schwierzeck $role = "supporter"; 106992bca398SDaniel Schwierzeck } elsif ($role eq "maintained") { 107092bca398SDaniel Schwierzeck $role = "maintainer"; 107192bca398SDaniel Schwierzeck } elsif ($role eq "odd fixes") { 107292bca398SDaniel Schwierzeck $role = "odd fixer"; 107392bca398SDaniel Schwierzeck } elsif ($role eq "orphan") { 107492bca398SDaniel Schwierzeck $role = "orphan minder"; 107592bca398SDaniel Schwierzeck } elsif ($role eq "obsolete") { 107692bca398SDaniel Schwierzeck $role = "obsolete minder"; 107792bca398SDaniel Schwierzeck } elsif ($role eq "buried alive in reporters") { 107892bca398SDaniel Schwierzeck $role = "chief penguin"; 107992bca398SDaniel Schwierzeck } 108092bca398SDaniel Schwierzeck 108192bca398SDaniel Schwierzeck return $role . ":" . $subsystem; 108292bca398SDaniel Schwierzeck} 108392bca398SDaniel Schwierzeck 108492bca398SDaniel Schwierzecksub get_list_role { 108592bca398SDaniel Schwierzeck my ($index) = @_; 108692bca398SDaniel Schwierzeck 10874fd65389SHeinrich Schuchardt my $subsystem = get_subsystem_name($index); 108892bca398SDaniel Schwierzeck 108992bca398SDaniel Schwierzeck if ($subsystem eq "THE REST") { 109092bca398SDaniel Schwierzeck $subsystem = ""; 109192bca398SDaniel Schwierzeck } 109292bca398SDaniel Schwierzeck 109392bca398SDaniel Schwierzeck return $subsystem; 109492bca398SDaniel Schwierzeck} 109592bca398SDaniel Schwierzeck 109692bca398SDaniel Schwierzecksub add_categories { 109792bca398SDaniel Schwierzeck my ($index) = @_; 109892bca398SDaniel Schwierzeck 109992bca398SDaniel Schwierzeck my $i; 110092bca398SDaniel Schwierzeck my $start = find_starting_index($index); 110192bca398SDaniel Schwierzeck my $end = find_ending_index($index); 110292bca398SDaniel Schwierzeck 110392bca398SDaniel Schwierzeck push(@subsystem, $typevalue[$start]); 110492bca398SDaniel Schwierzeck 110592bca398SDaniel Schwierzeck for ($i = $start + 1; $i < $end; $i++) { 110692bca398SDaniel Schwierzeck my $tv = $typevalue[$i]; 110735729218SHeiko Schocher if ($tv =~ m/^([A-Z]):\s*(.*)/) { 110892bca398SDaniel Schwierzeck my $ptype = $1; 110992bca398SDaniel Schwierzeck my $pvalue = $2; 111092bca398SDaniel Schwierzeck if ($ptype eq "L") { 111192bca398SDaniel Schwierzeck my $list_address = $pvalue; 111292bca398SDaniel Schwierzeck my $list_additional = ""; 111392bca398SDaniel Schwierzeck my $list_role = get_list_role($i); 111492bca398SDaniel Schwierzeck 111592bca398SDaniel Schwierzeck if ($list_role ne "") { 111692bca398SDaniel Schwierzeck $list_role = ":" . $list_role; 111792bca398SDaniel Schwierzeck } 111892bca398SDaniel Schwierzeck if ($list_address =~ m/([^\s]+)\s+(.*)$/) { 111992bca398SDaniel Schwierzeck $list_address = $1; 112092bca398SDaniel Schwierzeck $list_additional = $2; 112192bca398SDaniel Schwierzeck } 112292bca398SDaniel Schwierzeck if ($list_additional =~ m/subscribers-only/) { 112392bca398SDaniel Schwierzeck if ($email_subscriber_list) { 112492bca398SDaniel Schwierzeck if (!$hash_list_to{lc($list_address)}) { 112592bca398SDaniel Schwierzeck $hash_list_to{lc($list_address)} = 1; 112692bca398SDaniel Schwierzeck push(@list_to, [$list_address, 112792bca398SDaniel Schwierzeck "subscriber list${list_role}"]); 112892bca398SDaniel Schwierzeck } 112992bca398SDaniel Schwierzeck } 113092bca398SDaniel Schwierzeck } else { 113192bca398SDaniel Schwierzeck if ($email_list) { 113292bca398SDaniel Schwierzeck if (!$hash_list_to{lc($list_address)}) { 113392bca398SDaniel Schwierzeck $hash_list_to{lc($list_address)} = 1; 113492bca398SDaniel Schwierzeck if ($list_additional =~ m/moderated/) { 113592bca398SDaniel Schwierzeck push(@list_to, [$list_address, 113692bca398SDaniel Schwierzeck "moderated list${list_role}"]); 113792bca398SDaniel Schwierzeck } else { 113892bca398SDaniel Schwierzeck push(@list_to, [$list_address, 113992bca398SDaniel Schwierzeck "open list${list_role}"]); 114092bca398SDaniel Schwierzeck } 114192bca398SDaniel Schwierzeck } 114292bca398SDaniel Schwierzeck } 114392bca398SDaniel Schwierzeck } 114492bca398SDaniel Schwierzeck } elsif ($ptype eq "M") { 114592bca398SDaniel Schwierzeck my ($name, $address) = parse_email($pvalue); 114692bca398SDaniel Schwierzeck if ($name eq "") { 114792bca398SDaniel Schwierzeck if ($i > 0) { 114892bca398SDaniel Schwierzeck my $tv = $typevalue[$i - 1]; 114935729218SHeiko Schocher if ($tv =~ m/^([A-Z]):\s*(.*)/) { 115092bca398SDaniel Schwierzeck if ($1 eq "P") { 115192bca398SDaniel Schwierzeck $name = $2; 115292bca398SDaniel Schwierzeck $pvalue = format_email($name, $address, $email_usename); 115392bca398SDaniel Schwierzeck } 115492bca398SDaniel Schwierzeck } 115592bca398SDaniel Schwierzeck } 115692bca398SDaniel Schwierzeck } 115792bca398SDaniel Schwierzeck if ($email_maintainer) { 115892bca398SDaniel Schwierzeck my $role = get_maintainer_role($i); 115992bca398SDaniel Schwierzeck push_email_addresses($pvalue, $role); 116092bca398SDaniel Schwierzeck } 11614fd65389SHeinrich Schuchardt } elsif ($ptype eq "R") { 11624fd65389SHeinrich Schuchardt my ($name, $address) = parse_email($pvalue); 11634fd65389SHeinrich Schuchardt if ($name eq "") { 11644fd65389SHeinrich Schuchardt if ($i > 0) { 11654fd65389SHeinrich Schuchardt my $tv = $typevalue[$i - 1]; 11664fd65389SHeinrich Schuchardt if ($tv =~ m/^([A-Z]):\s*(.*)/) { 11674fd65389SHeinrich Schuchardt if ($1 eq "P") { 11684fd65389SHeinrich Schuchardt $name = $2; 11694fd65389SHeinrich Schuchardt $pvalue = format_email($name, $address, $email_usename); 11704fd65389SHeinrich Schuchardt } 11714fd65389SHeinrich Schuchardt } 11724fd65389SHeinrich Schuchardt } 11734fd65389SHeinrich Schuchardt } 11744fd65389SHeinrich Schuchardt if ($email_reviewer) { 11754fd65389SHeinrich Schuchardt my $subsystem = get_subsystem_name($i); 11764fd65389SHeinrich Schuchardt push_email_addresses($pvalue, "reviewer:$subsystem"); 11774fd65389SHeinrich Schuchardt } 117892bca398SDaniel Schwierzeck } elsif ($ptype eq "T") { 117992bca398SDaniel Schwierzeck push(@scm, $pvalue); 118092bca398SDaniel Schwierzeck } elsif ($ptype eq "W") { 118192bca398SDaniel Schwierzeck push(@web, $pvalue); 118292bca398SDaniel Schwierzeck } elsif ($ptype eq "S") { 118392bca398SDaniel Schwierzeck push(@status, $pvalue); 118492bca398SDaniel Schwierzeck } 118592bca398SDaniel Schwierzeck } 118692bca398SDaniel Schwierzeck } 118792bca398SDaniel Schwierzeck} 118892bca398SDaniel Schwierzeck 118992bca398SDaniel Schwierzecksub email_inuse { 119092bca398SDaniel Schwierzeck my ($name, $address) = @_; 119192bca398SDaniel Schwierzeck 119292bca398SDaniel Schwierzeck return 1 if (($name eq "") && ($address eq "")); 119392bca398SDaniel Schwierzeck return 1 if (($name ne "") && exists($email_hash_name{lc($name)})); 119492bca398SDaniel Schwierzeck return 1 if (($address ne "") && exists($email_hash_address{lc($address)})); 119592bca398SDaniel Schwierzeck 119692bca398SDaniel Schwierzeck return 0; 119792bca398SDaniel Schwierzeck} 119892bca398SDaniel Schwierzeck 119992bca398SDaniel Schwierzecksub push_email_address { 120092bca398SDaniel Schwierzeck my ($line, $role) = @_; 120192bca398SDaniel Schwierzeck 120292bca398SDaniel Schwierzeck my ($name, $address) = parse_email($line); 120392bca398SDaniel Schwierzeck 120492bca398SDaniel Schwierzeck if ($address eq "") { 120592bca398SDaniel Schwierzeck return 0; 120692bca398SDaniel Schwierzeck } 120792bca398SDaniel Schwierzeck 120892bca398SDaniel Schwierzeck if (!$email_remove_duplicates) { 120992bca398SDaniel Schwierzeck push(@email_to, [format_email($name, $address, $email_usename), $role]); 121092bca398SDaniel Schwierzeck } elsif (!email_inuse($name, $address)) { 121192bca398SDaniel Schwierzeck push(@email_to, [format_email($name, $address, $email_usename), $role]); 121292bca398SDaniel Schwierzeck $email_hash_name{lc($name)}++ if ($name ne ""); 121392bca398SDaniel Schwierzeck $email_hash_address{lc($address)}++; 121492bca398SDaniel Schwierzeck } 121592bca398SDaniel Schwierzeck 121692bca398SDaniel Schwierzeck return 1; 121792bca398SDaniel Schwierzeck} 121892bca398SDaniel Schwierzeck 121992bca398SDaniel Schwierzecksub push_email_addresses { 122092bca398SDaniel Schwierzeck my ($address, $role) = @_; 122192bca398SDaniel Schwierzeck 122292bca398SDaniel Schwierzeck my @address_list = (); 122392bca398SDaniel Schwierzeck 122492bca398SDaniel Schwierzeck if (rfc822_valid($address)) { 122592bca398SDaniel Schwierzeck push_email_address($address, $role); 122692bca398SDaniel Schwierzeck } elsif (@address_list = rfc822_validlist($address)) { 122792bca398SDaniel Schwierzeck my $array_count = shift(@address_list); 122892bca398SDaniel Schwierzeck while (my $entry = shift(@address_list)) { 122992bca398SDaniel Schwierzeck push_email_address($entry, $role); 123092bca398SDaniel Schwierzeck } 123192bca398SDaniel Schwierzeck } else { 123292bca398SDaniel Schwierzeck if (!push_email_address($address, $role)) { 123392bca398SDaniel Schwierzeck warn("Invalid MAINTAINERS address: '" . $address . "'\n"); 123492bca398SDaniel Schwierzeck } 123592bca398SDaniel Schwierzeck } 123692bca398SDaniel Schwierzeck} 123792bca398SDaniel Schwierzeck 123892bca398SDaniel Schwierzecksub add_role { 123992bca398SDaniel Schwierzeck my ($line, $role) = @_; 124092bca398SDaniel Schwierzeck 124192bca398SDaniel Schwierzeck my ($name, $address) = parse_email($line); 124292bca398SDaniel Schwierzeck my $email = format_email($name, $address, $email_usename); 124392bca398SDaniel Schwierzeck 124492bca398SDaniel Schwierzeck foreach my $entry (@email_to) { 124592bca398SDaniel Schwierzeck if ($email_remove_duplicates) { 124692bca398SDaniel Schwierzeck my ($entry_name, $entry_address) = parse_email($entry->[0]); 124792bca398SDaniel Schwierzeck if (($name eq $entry_name || $address eq $entry_address) 124892bca398SDaniel Schwierzeck && ($role eq "" || !($entry->[1] =~ m/$role/)) 124992bca398SDaniel Schwierzeck ) { 125092bca398SDaniel Schwierzeck if ($entry->[1] eq "") { 125192bca398SDaniel Schwierzeck $entry->[1] = "$role"; 125292bca398SDaniel Schwierzeck } else { 125392bca398SDaniel Schwierzeck $entry->[1] = "$entry->[1],$role"; 125492bca398SDaniel Schwierzeck } 125592bca398SDaniel Schwierzeck } 125692bca398SDaniel Schwierzeck } else { 125792bca398SDaniel Schwierzeck if ($email eq $entry->[0] 125892bca398SDaniel Schwierzeck && ($role eq "" || !($entry->[1] =~ m/$role/)) 125992bca398SDaniel Schwierzeck ) { 126092bca398SDaniel Schwierzeck if ($entry->[1] eq "") { 126192bca398SDaniel Schwierzeck $entry->[1] = "$role"; 126292bca398SDaniel Schwierzeck } else { 126392bca398SDaniel Schwierzeck $entry->[1] = "$entry->[1],$role"; 126492bca398SDaniel Schwierzeck } 126592bca398SDaniel Schwierzeck } 126692bca398SDaniel Schwierzeck } 126792bca398SDaniel Schwierzeck } 126892bca398SDaniel Schwierzeck} 126992bca398SDaniel Schwierzeck 127092bca398SDaniel Schwierzecksub which { 127192bca398SDaniel Schwierzeck my ($bin) = @_; 127292bca398SDaniel Schwierzeck 127392bca398SDaniel Schwierzeck foreach my $path (split(/:/, $ENV{PATH})) { 127492bca398SDaniel Schwierzeck if (-e "$path/$bin") { 127592bca398SDaniel Schwierzeck return "$path/$bin"; 127692bca398SDaniel Schwierzeck } 127792bca398SDaniel Schwierzeck } 127892bca398SDaniel Schwierzeck 127992bca398SDaniel Schwierzeck return ""; 128092bca398SDaniel Schwierzeck} 128192bca398SDaniel Schwierzeck 128292bca398SDaniel Schwierzecksub which_conf { 128392bca398SDaniel Schwierzeck my ($conf) = @_; 128492bca398SDaniel Schwierzeck 128592bca398SDaniel Schwierzeck foreach my $path (split(/:/, ".:$ENV{HOME}:.scripts")) { 128692bca398SDaniel Schwierzeck if (-e "$path/$conf") { 128792bca398SDaniel Schwierzeck return "$path/$conf"; 128892bca398SDaniel Schwierzeck } 128992bca398SDaniel Schwierzeck } 129092bca398SDaniel Schwierzeck 129192bca398SDaniel Schwierzeck return ""; 129292bca398SDaniel Schwierzeck} 129392bca398SDaniel Schwierzeck 129492bca398SDaniel Schwierzecksub mailmap_email { 129592bca398SDaniel Schwierzeck my ($line) = @_; 129692bca398SDaniel Schwierzeck 129792bca398SDaniel Schwierzeck my ($name, $address) = parse_email($line); 129892bca398SDaniel Schwierzeck my $email = format_email($name, $address, 1); 129992bca398SDaniel Schwierzeck my $real_name = $name; 130092bca398SDaniel Schwierzeck my $real_address = $address; 130192bca398SDaniel Schwierzeck 130292bca398SDaniel Schwierzeck if (exists $mailmap->{names}->{$email} || 130392bca398SDaniel Schwierzeck exists $mailmap->{addresses}->{$email}) { 130492bca398SDaniel Schwierzeck if (exists $mailmap->{names}->{$email}) { 130592bca398SDaniel Schwierzeck $real_name = $mailmap->{names}->{$email}; 130692bca398SDaniel Schwierzeck } 130792bca398SDaniel Schwierzeck if (exists $mailmap->{addresses}->{$email}) { 130892bca398SDaniel Schwierzeck $real_address = $mailmap->{addresses}->{$email}; 130992bca398SDaniel Schwierzeck } 131092bca398SDaniel Schwierzeck } else { 131192bca398SDaniel Schwierzeck if (exists $mailmap->{names}->{$address}) { 131292bca398SDaniel Schwierzeck $real_name = $mailmap->{names}->{$address}; 131392bca398SDaniel Schwierzeck } 131492bca398SDaniel Schwierzeck if (exists $mailmap->{addresses}->{$address}) { 131592bca398SDaniel Schwierzeck $real_address = $mailmap->{addresses}->{$address}; 131692bca398SDaniel Schwierzeck } 131792bca398SDaniel Schwierzeck } 131892bca398SDaniel Schwierzeck return format_email($real_name, $real_address, 1); 131992bca398SDaniel Schwierzeck} 132092bca398SDaniel Schwierzeck 132192bca398SDaniel Schwierzecksub mailmap { 132292bca398SDaniel Schwierzeck my (@addresses) = @_; 132392bca398SDaniel Schwierzeck 132492bca398SDaniel Schwierzeck my @mapped_emails = (); 132592bca398SDaniel Schwierzeck foreach my $line (@addresses) { 132692bca398SDaniel Schwierzeck push(@mapped_emails, mailmap_email($line)); 132792bca398SDaniel Schwierzeck } 132892bca398SDaniel Schwierzeck merge_by_realname(@mapped_emails) if ($email_use_mailmap); 132992bca398SDaniel Schwierzeck return @mapped_emails; 133092bca398SDaniel Schwierzeck} 133192bca398SDaniel Schwierzeck 133292bca398SDaniel Schwierzecksub merge_by_realname { 133392bca398SDaniel Schwierzeck my %address_map; 133492bca398SDaniel Schwierzeck my (@emails) = @_; 133592bca398SDaniel Schwierzeck 133692bca398SDaniel Schwierzeck foreach my $email (@emails) { 133792bca398SDaniel Schwierzeck my ($name, $address) = parse_email($email); 133892bca398SDaniel Schwierzeck if (exists $address_map{$name}) { 133992bca398SDaniel Schwierzeck $address = $address_map{$name}; 134092bca398SDaniel Schwierzeck $email = format_email($name, $address, 1); 134192bca398SDaniel Schwierzeck } else { 134292bca398SDaniel Schwierzeck $address_map{$name} = $address; 134392bca398SDaniel Schwierzeck } 134492bca398SDaniel Schwierzeck } 134592bca398SDaniel Schwierzeck} 134692bca398SDaniel Schwierzeck 134792bca398SDaniel Schwierzecksub git_execute_cmd { 134892bca398SDaniel Schwierzeck my ($cmd) = @_; 134992bca398SDaniel Schwierzeck my @lines = (); 135092bca398SDaniel Schwierzeck 135192bca398SDaniel Schwierzeck my $output = `$cmd`; 135292bca398SDaniel Schwierzeck $output =~ s/^\s*//gm; 135392bca398SDaniel Schwierzeck @lines = split("\n", $output); 135492bca398SDaniel Schwierzeck 135592bca398SDaniel Schwierzeck return @lines; 135692bca398SDaniel Schwierzeck} 135792bca398SDaniel Schwierzeck 135892bca398SDaniel Schwierzecksub hg_execute_cmd { 135992bca398SDaniel Schwierzeck my ($cmd) = @_; 136092bca398SDaniel Schwierzeck my @lines = (); 136192bca398SDaniel Schwierzeck 136292bca398SDaniel Schwierzeck my $output = `$cmd`; 136392bca398SDaniel Schwierzeck @lines = split("\n", $output); 136492bca398SDaniel Schwierzeck 136592bca398SDaniel Schwierzeck return @lines; 136692bca398SDaniel Schwierzeck} 136792bca398SDaniel Schwierzeck 136892bca398SDaniel Schwierzecksub extract_formatted_signatures { 136992bca398SDaniel Schwierzeck my (@signature_lines) = @_; 137092bca398SDaniel Schwierzeck 137192bca398SDaniel Schwierzeck my @type = @signature_lines; 137292bca398SDaniel Schwierzeck 137392bca398SDaniel Schwierzeck s/\s*(.*):.*/$1/ for (@type); 137492bca398SDaniel Schwierzeck 137592bca398SDaniel Schwierzeck # cut -f2- -d":" 137692bca398SDaniel Schwierzeck s/\s*.*:\s*(.+)\s*/$1/ for (@signature_lines); 137792bca398SDaniel Schwierzeck 137892bca398SDaniel Schwierzeck## Reformat email addresses (with names) to avoid badly written signatures 137992bca398SDaniel Schwierzeck 138092bca398SDaniel Schwierzeck foreach my $signer (@signature_lines) { 138192bca398SDaniel Schwierzeck $signer = deduplicate_email($signer); 138292bca398SDaniel Schwierzeck } 138392bca398SDaniel Schwierzeck 138492bca398SDaniel Schwierzeck return (\@type, \@signature_lines); 138592bca398SDaniel Schwierzeck} 138692bca398SDaniel Schwierzeck 138792bca398SDaniel Schwierzecksub vcs_find_signers { 138892bca398SDaniel Schwierzeck my ($cmd, $file) = @_; 138992bca398SDaniel Schwierzeck my $commits; 139092bca398SDaniel Schwierzeck my @lines = (); 139192bca398SDaniel Schwierzeck my @signatures = (); 139292bca398SDaniel Schwierzeck my @authors = (); 139392bca398SDaniel Schwierzeck my @stats = (); 139492bca398SDaniel Schwierzeck 139592bca398SDaniel Schwierzeck @lines = &{$VCS_cmds{"execute_cmd"}}($cmd); 139692bca398SDaniel Schwierzeck 139792bca398SDaniel Schwierzeck my $pattern = $VCS_cmds{"commit_pattern"}; 139892bca398SDaniel Schwierzeck my $author_pattern = $VCS_cmds{"author_pattern"}; 139992bca398SDaniel Schwierzeck my $stat_pattern = $VCS_cmds{"stat_pattern"}; 140092bca398SDaniel Schwierzeck 140192bca398SDaniel Schwierzeck $stat_pattern =~ s/(\$\w+)/$1/eeg; #interpolate $stat_pattern 140292bca398SDaniel Schwierzeck 140392bca398SDaniel Schwierzeck $commits = grep(/$pattern/, @lines); # of commits 140492bca398SDaniel Schwierzeck 140592bca398SDaniel Schwierzeck @authors = grep(/$author_pattern/, @lines); 140692bca398SDaniel Schwierzeck @signatures = grep(/^[ \t]*${signature_pattern}.*\@.*$/, @lines); 140792bca398SDaniel Schwierzeck @stats = grep(/$stat_pattern/, @lines); 140892bca398SDaniel Schwierzeck 140992bca398SDaniel Schwierzeck# print("stats: <@stats>\n"); 141092bca398SDaniel Schwierzeck 141192bca398SDaniel Schwierzeck return (0, \@signatures, \@authors, \@stats) if !@signatures; 141292bca398SDaniel Schwierzeck 141392bca398SDaniel Schwierzeck save_commits_by_author(@lines) if ($interactive); 141492bca398SDaniel Schwierzeck save_commits_by_signer(@lines) if ($interactive); 141592bca398SDaniel Schwierzeck 141692bca398SDaniel Schwierzeck if (!$email_git_penguin_chiefs) { 141792bca398SDaniel Schwierzeck @signatures = grep(!/${penguin_chiefs}/i, @signatures); 141892bca398SDaniel Schwierzeck } 141992bca398SDaniel Schwierzeck 142092bca398SDaniel Schwierzeck my ($author_ref, $authors_ref) = extract_formatted_signatures(@authors); 142192bca398SDaniel Schwierzeck my ($types_ref, $signers_ref) = extract_formatted_signatures(@signatures); 142292bca398SDaniel Schwierzeck 142392bca398SDaniel Schwierzeck return ($commits, $signers_ref, $authors_ref, \@stats); 142492bca398SDaniel Schwierzeck} 142592bca398SDaniel Schwierzeck 142692bca398SDaniel Schwierzecksub vcs_find_author { 142792bca398SDaniel Schwierzeck my ($cmd) = @_; 142892bca398SDaniel Schwierzeck my @lines = (); 142992bca398SDaniel Schwierzeck 143092bca398SDaniel Schwierzeck @lines = &{$VCS_cmds{"execute_cmd"}}($cmd); 143192bca398SDaniel Schwierzeck 143292bca398SDaniel Schwierzeck if (!$email_git_penguin_chiefs) { 143392bca398SDaniel Schwierzeck @lines = grep(!/${penguin_chiefs}/i, @lines); 143492bca398SDaniel Schwierzeck } 143592bca398SDaniel Schwierzeck 143692bca398SDaniel Schwierzeck return @lines if !@lines; 143792bca398SDaniel Schwierzeck 143892bca398SDaniel Schwierzeck my @authors = (); 143992bca398SDaniel Schwierzeck foreach my $line (@lines) { 144092bca398SDaniel Schwierzeck if ($line =~ m/$VCS_cmds{"author_pattern"}/) { 144192bca398SDaniel Schwierzeck my $author = $1; 144292bca398SDaniel Schwierzeck my ($name, $address) = parse_email($author); 144392bca398SDaniel Schwierzeck $author = format_email($name, $address, 1); 144492bca398SDaniel Schwierzeck push(@authors, $author); 144592bca398SDaniel Schwierzeck } 144692bca398SDaniel Schwierzeck } 144792bca398SDaniel Schwierzeck 144892bca398SDaniel Schwierzeck save_commits_by_author(@lines) if ($interactive); 144992bca398SDaniel Schwierzeck save_commits_by_signer(@lines) if ($interactive); 145092bca398SDaniel Schwierzeck 145192bca398SDaniel Schwierzeck return @authors; 145292bca398SDaniel Schwierzeck} 145392bca398SDaniel Schwierzeck 145492bca398SDaniel Schwierzecksub vcs_save_commits { 145592bca398SDaniel Schwierzeck my ($cmd) = @_; 145692bca398SDaniel Schwierzeck my @lines = (); 145792bca398SDaniel Schwierzeck my @commits = (); 145892bca398SDaniel Schwierzeck 145992bca398SDaniel Schwierzeck @lines = &{$VCS_cmds{"execute_cmd"}}($cmd); 146092bca398SDaniel Schwierzeck 146192bca398SDaniel Schwierzeck foreach my $line (@lines) { 146292bca398SDaniel Schwierzeck if ($line =~ m/$VCS_cmds{"blame_commit_pattern"}/) { 146392bca398SDaniel Schwierzeck push(@commits, $1); 146492bca398SDaniel Schwierzeck } 146592bca398SDaniel Schwierzeck } 146692bca398SDaniel Schwierzeck 146792bca398SDaniel Schwierzeck return @commits; 146892bca398SDaniel Schwierzeck} 146992bca398SDaniel Schwierzeck 147092bca398SDaniel Schwierzecksub vcs_blame { 147192bca398SDaniel Schwierzeck my ($file) = @_; 147292bca398SDaniel Schwierzeck my $cmd; 147392bca398SDaniel Schwierzeck my @commits = (); 147492bca398SDaniel Schwierzeck 147592bca398SDaniel Schwierzeck return @commits if (!(-f $file)); 147692bca398SDaniel Schwierzeck 147792bca398SDaniel Schwierzeck if (@range && $VCS_cmds{"blame_range_cmd"} eq "") { 147892bca398SDaniel Schwierzeck my @all_commits = (); 147992bca398SDaniel Schwierzeck 148092bca398SDaniel Schwierzeck $cmd = $VCS_cmds{"blame_file_cmd"}; 148192bca398SDaniel Schwierzeck $cmd =~ s/(\$\w+)/$1/eeg; #interpolate $cmd 148292bca398SDaniel Schwierzeck @all_commits = vcs_save_commits($cmd); 148392bca398SDaniel Schwierzeck 148492bca398SDaniel Schwierzeck foreach my $file_range_diff (@range) { 148592bca398SDaniel Schwierzeck next if (!($file_range_diff =~ m/(.+):(.+):(.+)/)); 148692bca398SDaniel Schwierzeck my $diff_file = $1; 148792bca398SDaniel Schwierzeck my $diff_start = $2; 148892bca398SDaniel Schwierzeck my $diff_length = $3; 148992bca398SDaniel Schwierzeck next if ("$file" ne "$diff_file"); 149092bca398SDaniel Schwierzeck for (my $i = $diff_start; $i < $diff_start + $diff_length; $i++) { 149192bca398SDaniel Schwierzeck push(@commits, $all_commits[$i]); 149292bca398SDaniel Schwierzeck } 149392bca398SDaniel Schwierzeck } 149492bca398SDaniel Schwierzeck } elsif (@range) { 149592bca398SDaniel Schwierzeck foreach my $file_range_diff (@range) { 149692bca398SDaniel Schwierzeck next if (!($file_range_diff =~ m/(.+):(.+):(.+)/)); 149792bca398SDaniel Schwierzeck my $diff_file = $1; 149892bca398SDaniel Schwierzeck my $diff_start = $2; 149992bca398SDaniel Schwierzeck my $diff_length = $3; 150092bca398SDaniel Schwierzeck next if ("$file" ne "$diff_file"); 150192bca398SDaniel Schwierzeck $cmd = $VCS_cmds{"blame_range_cmd"}; 150292bca398SDaniel Schwierzeck $cmd =~ s/(\$\w+)/$1/eeg; #interpolate $cmd 150392bca398SDaniel Schwierzeck push(@commits, vcs_save_commits($cmd)); 150492bca398SDaniel Schwierzeck } 150592bca398SDaniel Schwierzeck } else { 150692bca398SDaniel Schwierzeck $cmd = $VCS_cmds{"blame_file_cmd"}; 150792bca398SDaniel Schwierzeck $cmd =~ s/(\$\w+)/$1/eeg; #interpolate $cmd 150892bca398SDaniel Schwierzeck @commits = vcs_save_commits($cmd); 150992bca398SDaniel Schwierzeck } 151092bca398SDaniel Schwierzeck 151192bca398SDaniel Schwierzeck foreach my $commit (@commits) { 151292bca398SDaniel Schwierzeck $commit =~ s/^\^//g; 151392bca398SDaniel Schwierzeck } 151492bca398SDaniel Schwierzeck 151592bca398SDaniel Schwierzeck return @commits; 151692bca398SDaniel Schwierzeck} 151792bca398SDaniel Schwierzeck 151892bca398SDaniel Schwierzeckmy $printed_novcs = 0; 151992bca398SDaniel Schwierzecksub vcs_exists { 152092bca398SDaniel Schwierzeck %VCS_cmds = %VCS_cmds_git; 152192bca398SDaniel Schwierzeck return 1 if eval $VCS_cmds{"available"}; 152292bca398SDaniel Schwierzeck %VCS_cmds = %VCS_cmds_hg; 152392bca398SDaniel Schwierzeck return 2 if eval $VCS_cmds{"available"}; 152492bca398SDaniel Schwierzeck %VCS_cmds = (); 152592bca398SDaniel Schwierzeck if (!$printed_novcs) { 152692bca398SDaniel Schwierzeck warn("$P: No supported VCS found. Add --nogit to options?\n"); 152792bca398SDaniel Schwierzeck warn("Using a git repository produces better results.\n"); 152892bca398SDaniel Schwierzeck warn("Try Linus Torvalds' latest git repository using:\n"); 152992bca398SDaniel Schwierzeck warn("git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git\n"); 153092bca398SDaniel Schwierzeck $printed_novcs = 1; 153192bca398SDaniel Schwierzeck } 153292bca398SDaniel Schwierzeck return 0; 153392bca398SDaniel Schwierzeck} 153492bca398SDaniel Schwierzeck 153592bca398SDaniel Schwierzecksub vcs_is_git { 153692bca398SDaniel Schwierzeck vcs_exists(); 153792bca398SDaniel Schwierzeck return $vcs_used == 1; 153892bca398SDaniel Schwierzeck} 153992bca398SDaniel Schwierzeck 154092bca398SDaniel Schwierzecksub vcs_is_hg { 154192bca398SDaniel Schwierzeck return $vcs_used == 2; 154292bca398SDaniel Schwierzeck} 154392bca398SDaniel Schwierzeck 154492bca398SDaniel Schwierzecksub interactive_get_maintainers { 154592bca398SDaniel Schwierzeck my ($list_ref) = @_; 154692bca398SDaniel Schwierzeck my @list = @$list_ref; 154792bca398SDaniel Schwierzeck 154892bca398SDaniel Schwierzeck vcs_exists(); 154992bca398SDaniel Schwierzeck 155092bca398SDaniel Schwierzeck my %selected; 155192bca398SDaniel Schwierzeck my %authored; 155292bca398SDaniel Schwierzeck my %signed; 155392bca398SDaniel Schwierzeck my $count = 0; 155492bca398SDaniel Schwierzeck my $maintained = 0; 155592bca398SDaniel Schwierzeck foreach my $entry (@list) { 155692bca398SDaniel Schwierzeck $maintained = 1 if ($entry->[1] =~ /^(maintainer|supporter)/i); 155792bca398SDaniel Schwierzeck $selected{$count} = 1; 155892bca398SDaniel Schwierzeck $authored{$count} = 0; 155992bca398SDaniel Schwierzeck $signed{$count} = 0; 156092bca398SDaniel Schwierzeck $count++; 156192bca398SDaniel Schwierzeck } 156292bca398SDaniel Schwierzeck 156392bca398SDaniel Schwierzeck #menu loop 156492bca398SDaniel Schwierzeck my $done = 0; 156592bca398SDaniel Schwierzeck my $print_options = 0; 156692bca398SDaniel Schwierzeck my $redraw = 1; 156792bca398SDaniel Schwierzeck while (!$done) { 156892bca398SDaniel Schwierzeck $count = 0; 156992bca398SDaniel Schwierzeck if ($redraw) { 157092bca398SDaniel Schwierzeck printf STDERR "\n%1s %2s %-65s", 157192bca398SDaniel Schwierzeck "*", "#", "email/list and role:stats"; 157292bca398SDaniel Schwierzeck if ($email_git || 157392bca398SDaniel Schwierzeck ($email_git_fallback && !$maintained) || 157492bca398SDaniel Schwierzeck $email_git_blame) { 157592bca398SDaniel Schwierzeck print STDERR "auth sign"; 157692bca398SDaniel Schwierzeck } 157792bca398SDaniel Schwierzeck print STDERR "\n"; 157892bca398SDaniel Schwierzeck foreach my $entry (@list) { 157992bca398SDaniel Schwierzeck my $email = $entry->[0]; 158092bca398SDaniel Schwierzeck my $role = $entry->[1]; 158192bca398SDaniel Schwierzeck my $sel = ""; 158292bca398SDaniel Schwierzeck $sel = "*" if ($selected{$count}); 158392bca398SDaniel Schwierzeck my $commit_author = $commit_author_hash{$email}; 158492bca398SDaniel Schwierzeck my $commit_signer = $commit_signer_hash{$email}; 158592bca398SDaniel Schwierzeck my $authored = 0; 158692bca398SDaniel Schwierzeck my $signed = 0; 158792bca398SDaniel Schwierzeck $authored++ for (@{$commit_author}); 158892bca398SDaniel Schwierzeck $signed++ for (@{$commit_signer}); 158992bca398SDaniel Schwierzeck printf STDERR "%1s %2d %-65s", $sel, $count + 1, $email; 159092bca398SDaniel Schwierzeck printf STDERR "%4d %4d", $authored, $signed 159192bca398SDaniel Schwierzeck if ($authored > 0 || $signed > 0); 159292bca398SDaniel Schwierzeck printf STDERR "\n %s\n", $role; 159392bca398SDaniel Schwierzeck if ($authored{$count}) { 159492bca398SDaniel Schwierzeck my $commit_author = $commit_author_hash{$email}; 159592bca398SDaniel Schwierzeck foreach my $ref (@{$commit_author}) { 159692bca398SDaniel Schwierzeck print STDERR " Author: @{$ref}[1]\n"; 159792bca398SDaniel Schwierzeck } 159892bca398SDaniel Schwierzeck } 159992bca398SDaniel Schwierzeck if ($signed{$count}) { 160092bca398SDaniel Schwierzeck my $commit_signer = $commit_signer_hash{$email}; 160192bca398SDaniel Schwierzeck foreach my $ref (@{$commit_signer}) { 160292bca398SDaniel Schwierzeck print STDERR " @{$ref}[2]: @{$ref}[1]\n"; 160392bca398SDaniel Schwierzeck } 160492bca398SDaniel Schwierzeck } 160592bca398SDaniel Schwierzeck 160692bca398SDaniel Schwierzeck $count++; 160792bca398SDaniel Schwierzeck } 160892bca398SDaniel Schwierzeck } 160992bca398SDaniel Schwierzeck my $date_ref = \$email_git_since; 161092bca398SDaniel Schwierzeck $date_ref = \$email_hg_since if (vcs_is_hg()); 161192bca398SDaniel Schwierzeck if ($print_options) { 161292bca398SDaniel Schwierzeck $print_options = 0; 161392bca398SDaniel Schwierzeck if (vcs_exists()) { 161492bca398SDaniel Schwierzeck print STDERR <<EOT 161592bca398SDaniel Schwierzeck 161692bca398SDaniel SchwierzeckVersion Control options: 161792bca398SDaniel Schwierzeckg use git history [$email_git] 161892bca398SDaniel Schwierzeckgf use git-fallback [$email_git_fallback] 161992bca398SDaniel Schwierzeckb use git blame [$email_git_blame] 162092bca398SDaniel Schwierzeckbs use blame signatures [$email_git_blame_signatures] 162192bca398SDaniel Schwierzeckc# minimum commits [$email_git_min_signatures] 162292bca398SDaniel Schwierzeck%# min percent [$email_git_min_percent] 162392bca398SDaniel Schwierzeckd# history to use [$$date_ref] 162492bca398SDaniel Schwierzeckx# max maintainers [$email_git_max_maintainers] 162592bca398SDaniel Schwierzeckt all signature types [$email_git_all_signature_types] 162692bca398SDaniel Schwierzeckm use .mailmap [$email_use_mailmap] 162792bca398SDaniel SchwierzeckEOT 162892bca398SDaniel Schwierzeck } 162992bca398SDaniel Schwierzeck print STDERR <<EOT 163092bca398SDaniel Schwierzeck 163192bca398SDaniel SchwierzeckAdditional options: 163292bca398SDaniel Schwierzeck0 toggle all 163392bca398SDaniel Schwierzecktm toggle maintainers 163492bca398SDaniel Schwierzecktg toggle git entries 163592bca398SDaniel Schwierzecktl toggle open list entries 163692bca398SDaniel Schwierzeckts toggle subscriber list entries 163792bca398SDaniel Schwierzeckf emails in file [$file_emails] 163892bca398SDaniel Schwierzeckk keywords in file [$keywords] 163992bca398SDaniel Schwierzeckr remove duplicates [$email_remove_duplicates] 164092bca398SDaniel Schwierzeckp# pattern match depth [$pattern_depth] 164192bca398SDaniel SchwierzeckEOT 164292bca398SDaniel Schwierzeck } 164392bca398SDaniel Schwierzeck print STDERR 164492bca398SDaniel Schwierzeck"\n#(toggle), A#(author), S#(signed) *(all), ^(none), O(options), Y(approve): "; 164592bca398SDaniel Schwierzeck 164692bca398SDaniel Schwierzeck my $input = <STDIN>; 164792bca398SDaniel Schwierzeck chomp($input); 164892bca398SDaniel Schwierzeck 164992bca398SDaniel Schwierzeck $redraw = 1; 165092bca398SDaniel Schwierzeck my $rerun = 0; 165192bca398SDaniel Schwierzeck my @wish = split(/[, ]+/, $input); 165292bca398SDaniel Schwierzeck foreach my $nr (@wish) { 165392bca398SDaniel Schwierzeck $nr = lc($nr); 165492bca398SDaniel Schwierzeck my $sel = substr($nr, 0, 1); 165592bca398SDaniel Schwierzeck my $str = substr($nr, 1); 165692bca398SDaniel Schwierzeck my $val = 0; 165792bca398SDaniel Schwierzeck $val = $1 if $str =~ /^(\d+)$/; 165892bca398SDaniel Schwierzeck 165992bca398SDaniel Schwierzeck if ($sel eq "y") { 166092bca398SDaniel Schwierzeck $interactive = 0; 166192bca398SDaniel Schwierzeck $done = 1; 166292bca398SDaniel Schwierzeck $output_rolestats = 0; 166392bca398SDaniel Schwierzeck $output_roles = 0; 166492bca398SDaniel Schwierzeck last; 166592bca398SDaniel Schwierzeck } elsif ($nr =~ /^\d+$/ && $nr > 0 && $nr <= $count) { 166692bca398SDaniel Schwierzeck $selected{$nr - 1} = !$selected{$nr - 1}; 166792bca398SDaniel Schwierzeck } elsif ($sel eq "*" || $sel eq '^') { 166892bca398SDaniel Schwierzeck my $toggle = 0; 166992bca398SDaniel Schwierzeck $toggle = 1 if ($sel eq '*'); 167092bca398SDaniel Schwierzeck for (my $i = 0; $i < $count; $i++) { 167192bca398SDaniel Schwierzeck $selected{$i} = $toggle; 167292bca398SDaniel Schwierzeck } 167392bca398SDaniel Schwierzeck } elsif ($sel eq "0") { 167492bca398SDaniel Schwierzeck for (my $i = 0; $i < $count; $i++) { 167592bca398SDaniel Schwierzeck $selected{$i} = !$selected{$i}; 167692bca398SDaniel Schwierzeck } 167792bca398SDaniel Schwierzeck } elsif ($sel eq "t") { 167892bca398SDaniel Schwierzeck if (lc($str) eq "m") { 167992bca398SDaniel Schwierzeck for (my $i = 0; $i < $count; $i++) { 168092bca398SDaniel Schwierzeck $selected{$i} = !$selected{$i} 168192bca398SDaniel Schwierzeck if ($list[$i]->[1] =~ /^(maintainer|supporter)/i); 168292bca398SDaniel Schwierzeck } 168392bca398SDaniel Schwierzeck } elsif (lc($str) eq "g") { 168492bca398SDaniel Schwierzeck for (my $i = 0; $i < $count; $i++) { 168592bca398SDaniel Schwierzeck $selected{$i} = !$selected{$i} 168692bca398SDaniel Schwierzeck if ($list[$i]->[1] =~ /^(author|commit|signer)/i); 168792bca398SDaniel Schwierzeck } 168892bca398SDaniel Schwierzeck } elsif (lc($str) eq "l") { 168992bca398SDaniel Schwierzeck for (my $i = 0; $i < $count; $i++) { 169092bca398SDaniel Schwierzeck $selected{$i} = !$selected{$i} 169192bca398SDaniel Schwierzeck if ($list[$i]->[1] =~ /^(open list)/i); 169292bca398SDaniel Schwierzeck } 169392bca398SDaniel Schwierzeck } elsif (lc($str) eq "s") { 169492bca398SDaniel Schwierzeck for (my $i = 0; $i < $count; $i++) { 169592bca398SDaniel Schwierzeck $selected{$i} = !$selected{$i} 169692bca398SDaniel Schwierzeck if ($list[$i]->[1] =~ /^(subscriber list)/i); 169792bca398SDaniel Schwierzeck } 169892bca398SDaniel Schwierzeck } 169992bca398SDaniel Schwierzeck } elsif ($sel eq "a") { 170092bca398SDaniel Schwierzeck if ($val > 0 && $val <= $count) { 170192bca398SDaniel Schwierzeck $authored{$val - 1} = !$authored{$val - 1}; 170292bca398SDaniel Schwierzeck } elsif ($str eq '*' || $str eq '^') { 170392bca398SDaniel Schwierzeck my $toggle = 0; 170492bca398SDaniel Schwierzeck $toggle = 1 if ($str eq '*'); 170592bca398SDaniel Schwierzeck for (my $i = 0; $i < $count; $i++) { 170692bca398SDaniel Schwierzeck $authored{$i} = $toggle; 170792bca398SDaniel Schwierzeck } 170892bca398SDaniel Schwierzeck } 170992bca398SDaniel Schwierzeck } elsif ($sel eq "s") { 171092bca398SDaniel Schwierzeck if ($val > 0 && $val <= $count) { 171192bca398SDaniel Schwierzeck $signed{$val - 1} = !$signed{$val - 1}; 171292bca398SDaniel Schwierzeck } elsif ($str eq '*' || $str eq '^') { 171392bca398SDaniel Schwierzeck my $toggle = 0; 171492bca398SDaniel Schwierzeck $toggle = 1 if ($str eq '*'); 171592bca398SDaniel Schwierzeck for (my $i = 0; $i < $count; $i++) { 171692bca398SDaniel Schwierzeck $signed{$i} = $toggle; 171792bca398SDaniel Schwierzeck } 171892bca398SDaniel Schwierzeck } 171992bca398SDaniel Schwierzeck } elsif ($sel eq "o") { 172092bca398SDaniel Schwierzeck $print_options = 1; 172192bca398SDaniel Schwierzeck $redraw = 1; 172292bca398SDaniel Schwierzeck } elsif ($sel eq "g") { 172392bca398SDaniel Schwierzeck if ($str eq "f") { 172492bca398SDaniel Schwierzeck bool_invert(\$email_git_fallback); 172592bca398SDaniel Schwierzeck } else { 172692bca398SDaniel Schwierzeck bool_invert(\$email_git); 172792bca398SDaniel Schwierzeck } 172892bca398SDaniel Schwierzeck $rerun = 1; 172992bca398SDaniel Schwierzeck } elsif ($sel eq "b") { 173092bca398SDaniel Schwierzeck if ($str eq "s") { 173192bca398SDaniel Schwierzeck bool_invert(\$email_git_blame_signatures); 173292bca398SDaniel Schwierzeck } else { 173392bca398SDaniel Schwierzeck bool_invert(\$email_git_blame); 173492bca398SDaniel Schwierzeck } 173592bca398SDaniel Schwierzeck $rerun = 1; 173692bca398SDaniel Schwierzeck } elsif ($sel eq "c") { 173792bca398SDaniel Schwierzeck if ($val > 0) { 173892bca398SDaniel Schwierzeck $email_git_min_signatures = $val; 173992bca398SDaniel Schwierzeck $rerun = 1; 174092bca398SDaniel Schwierzeck } 174192bca398SDaniel Schwierzeck } elsif ($sel eq "x") { 174292bca398SDaniel Schwierzeck if ($val > 0) { 174392bca398SDaniel Schwierzeck $email_git_max_maintainers = $val; 174492bca398SDaniel Schwierzeck $rerun = 1; 174592bca398SDaniel Schwierzeck } 174692bca398SDaniel Schwierzeck } elsif ($sel eq "%") { 174792bca398SDaniel Schwierzeck if ($str ne "" && $val >= 0) { 174892bca398SDaniel Schwierzeck $email_git_min_percent = $val; 174992bca398SDaniel Schwierzeck $rerun = 1; 175092bca398SDaniel Schwierzeck } 175192bca398SDaniel Schwierzeck } elsif ($sel eq "d") { 175292bca398SDaniel Schwierzeck if (vcs_is_git()) { 175392bca398SDaniel Schwierzeck $email_git_since = $str; 175492bca398SDaniel Schwierzeck } elsif (vcs_is_hg()) { 175592bca398SDaniel Schwierzeck $email_hg_since = $str; 175692bca398SDaniel Schwierzeck } 175792bca398SDaniel Schwierzeck $rerun = 1; 175892bca398SDaniel Schwierzeck } elsif ($sel eq "t") { 175992bca398SDaniel Schwierzeck bool_invert(\$email_git_all_signature_types); 176092bca398SDaniel Schwierzeck $rerun = 1; 176192bca398SDaniel Schwierzeck } elsif ($sel eq "f") { 176292bca398SDaniel Schwierzeck bool_invert(\$file_emails); 176392bca398SDaniel Schwierzeck $rerun = 1; 176492bca398SDaniel Schwierzeck } elsif ($sel eq "r") { 176592bca398SDaniel Schwierzeck bool_invert(\$email_remove_duplicates); 176692bca398SDaniel Schwierzeck $rerun = 1; 176792bca398SDaniel Schwierzeck } elsif ($sel eq "m") { 176892bca398SDaniel Schwierzeck bool_invert(\$email_use_mailmap); 176992bca398SDaniel Schwierzeck read_mailmap(); 177092bca398SDaniel Schwierzeck $rerun = 1; 177192bca398SDaniel Schwierzeck } elsif ($sel eq "k") { 177292bca398SDaniel Schwierzeck bool_invert(\$keywords); 177392bca398SDaniel Schwierzeck $rerun = 1; 177492bca398SDaniel Schwierzeck } elsif ($sel eq "p") { 177592bca398SDaniel Schwierzeck if ($str ne "" && $val >= 0) { 177692bca398SDaniel Schwierzeck $pattern_depth = $val; 177792bca398SDaniel Schwierzeck $rerun = 1; 177892bca398SDaniel Schwierzeck } 177992bca398SDaniel Schwierzeck } elsif ($sel eq "h" || $sel eq "?") { 178092bca398SDaniel Schwierzeck print STDERR <<EOT 178192bca398SDaniel Schwierzeck 178292bca398SDaniel SchwierzeckInteractive mode allows you to select the various maintainers, submitters, 178392bca398SDaniel Schwierzeckcommit signers and mailing lists that could be CC'd on a patch. 178492bca398SDaniel Schwierzeck 178592bca398SDaniel SchwierzeckAny *'d entry is selected. 178692bca398SDaniel Schwierzeck 178792bca398SDaniel SchwierzeckIf you have git or hg installed, you can choose to summarize the commit 178892bca398SDaniel Schwierzeckhistory of files in the patch. Also, each line of the current file can 178992bca398SDaniel Schwierzeckbe matched to its commit author and that commits signers with blame. 179092bca398SDaniel Schwierzeck 179192bca398SDaniel SchwierzeckVarious knobs exist to control the length of time for active commit 179292bca398SDaniel Schwierzecktracking, the maximum number of commit authors and signers to add, 179392bca398SDaniel Schwierzeckand such. 179492bca398SDaniel Schwierzeck 179592bca398SDaniel SchwierzeckEnter selections at the prompt until you are satisfied that the selected 179692bca398SDaniel Schwierzeckmaintainers are appropriate. You may enter multiple selections separated 179792bca398SDaniel Schwierzeckby either commas or spaces. 179892bca398SDaniel Schwierzeck 179992bca398SDaniel SchwierzeckEOT 180092bca398SDaniel Schwierzeck } else { 180192bca398SDaniel Schwierzeck print STDERR "invalid option: '$nr'\n"; 180292bca398SDaniel Schwierzeck $redraw = 0; 180392bca398SDaniel Schwierzeck } 180492bca398SDaniel Schwierzeck } 180592bca398SDaniel Schwierzeck if ($rerun) { 180692bca398SDaniel Schwierzeck print STDERR "git-blame can be very slow, please have patience..." 180792bca398SDaniel Schwierzeck if ($email_git_blame); 180892bca398SDaniel Schwierzeck goto &get_maintainers; 180992bca398SDaniel Schwierzeck } 181092bca398SDaniel Schwierzeck } 181192bca398SDaniel Schwierzeck 181292bca398SDaniel Schwierzeck #drop not selected entries 181392bca398SDaniel Schwierzeck $count = 0; 181492bca398SDaniel Schwierzeck my @new_emailto = (); 181592bca398SDaniel Schwierzeck foreach my $entry (@list) { 181692bca398SDaniel Schwierzeck if ($selected{$count}) { 181792bca398SDaniel Schwierzeck push(@new_emailto, $list[$count]); 181892bca398SDaniel Schwierzeck } 181992bca398SDaniel Schwierzeck $count++; 182092bca398SDaniel Schwierzeck } 182192bca398SDaniel Schwierzeck return @new_emailto; 182292bca398SDaniel Schwierzeck} 182392bca398SDaniel Schwierzeck 182492bca398SDaniel Schwierzecksub bool_invert { 182592bca398SDaniel Schwierzeck my ($bool_ref) = @_; 182692bca398SDaniel Schwierzeck 182792bca398SDaniel Schwierzeck if ($$bool_ref) { 182892bca398SDaniel Schwierzeck $$bool_ref = 0; 182992bca398SDaniel Schwierzeck } else { 183092bca398SDaniel Schwierzeck $$bool_ref = 1; 183192bca398SDaniel Schwierzeck } 183292bca398SDaniel Schwierzeck} 183392bca398SDaniel Schwierzeck 183492bca398SDaniel Schwierzecksub deduplicate_email { 183592bca398SDaniel Schwierzeck my ($email) = @_; 183692bca398SDaniel Schwierzeck 183792bca398SDaniel Schwierzeck my $matched = 0; 183892bca398SDaniel Schwierzeck my ($name, $address) = parse_email($email); 183992bca398SDaniel Schwierzeck $email = format_email($name, $address, 1); 184092bca398SDaniel Schwierzeck $email = mailmap_email($email); 184192bca398SDaniel Schwierzeck 184292bca398SDaniel Schwierzeck return $email if (!$email_remove_duplicates); 184392bca398SDaniel Schwierzeck 184492bca398SDaniel Schwierzeck ($name, $address) = parse_email($email); 184592bca398SDaniel Schwierzeck 184692bca398SDaniel Schwierzeck if ($name ne "" && $deduplicate_name_hash{lc($name)}) { 184792bca398SDaniel Schwierzeck $name = $deduplicate_name_hash{lc($name)}->[0]; 184892bca398SDaniel Schwierzeck $address = $deduplicate_name_hash{lc($name)}->[1]; 184992bca398SDaniel Schwierzeck $matched = 1; 185092bca398SDaniel Schwierzeck } elsif ($deduplicate_address_hash{lc($address)}) { 185192bca398SDaniel Schwierzeck $name = $deduplicate_address_hash{lc($address)}->[0]; 185292bca398SDaniel Schwierzeck $address = $deduplicate_address_hash{lc($address)}->[1]; 185392bca398SDaniel Schwierzeck $matched = 1; 185492bca398SDaniel Schwierzeck } 185592bca398SDaniel Schwierzeck if (!$matched) { 185692bca398SDaniel Schwierzeck $deduplicate_name_hash{lc($name)} = [ $name, $address ]; 185792bca398SDaniel Schwierzeck $deduplicate_address_hash{lc($address)} = [ $name, $address ]; 185892bca398SDaniel Schwierzeck } 185992bca398SDaniel Schwierzeck $email = format_email($name, $address, 1); 186092bca398SDaniel Schwierzeck $email = mailmap_email($email); 186192bca398SDaniel Schwierzeck return $email; 186292bca398SDaniel Schwierzeck} 186392bca398SDaniel Schwierzeck 186492bca398SDaniel Schwierzecksub save_commits_by_author { 186592bca398SDaniel Schwierzeck my (@lines) = @_; 186692bca398SDaniel Schwierzeck 186792bca398SDaniel Schwierzeck my @authors = (); 186892bca398SDaniel Schwierzeck my @commits = (); 186992bca398SDaniel Schwierzeck my @subjects = (); 187092bca398SDaniel Schwierzeck 187192bca398SDaniel Schwierzeck foreach my $line (@lines) { 187292bca398SDaniel Schwierzeck if ($line =~ m/$VCS_cmds{"author_pattern"}/) { 187392bca398SDaniel Schwierzeck my $author = $1; 187492bca398SDaniel Schwierzeck $author = deduplicate_email($author); 187592bca398SDaniel Schwierzeck push(@authors, $author); 187692bca398SDaniel Schwierzeck } 187792bca398SDaniel Schwierzeck push(@commits, $1) if ($line =~ m/$VCS_cmds{"commit_pattern"}/); 187892bca398SDaniel Schwierzeck push(@subjects, $1) if ($line =~ m/$VCS_cmds{"subject_pattern"}/); 187992bca398SDaniel Schwierzeck } 188092bca398SDaniel Schwierzeck 188192bca398SDaniel Schwierzeck for (my $i = 0; $i < @authors; $i++) { 188292bca398SDaniel Schwierzeck my $exists = 0; 188392bca398SDaniel Schwierzeck foreach my $ref(@{$commit_author_hash{$authors[$i]}}) { 188492bca398SDaniel Schwierzeck if (@{$ref}[0] eq $commits[$i] && 188592bca398SDaniel Schwierzeck @{$ref}[1] eq $subjects[$i]) { 188692bca398SDaniel Schwierzeck $exists = 1; 188792bca398SDaniel Schwierzeck last; 188892bca398SDaniel Schwierzeck } 188992bca398SDaniel Schwierzeck } 189092bca398SDaniel Schwierzeck if (!$exists) { 189192bca398SDaniel Schwierzeck push(@{$commit_author_hash{$authors[$i]}}, 189292bca398SDaniel Schwierzeck [ ($commits[$i], $subjects[$i]) ]); 189392bca398SDaniel Schwierzeck } 189492bca398SDaniel Schwierzeck } 189592bca398SDaniel Schwierzeck} 189692bca398SDaniel Schwierzeck 189792bca398SDaniel Schwierzecksub save_commits_by_signer { 189892bca398SDaniel Schwierzeck my (@lines) = @_; 189992bca398SDaniel Schwierzeck 190092bca398SDaniel Schwierzeck my $commit = ""; 190192bca398SDaniel Schwierzeck my $subject = ""; 190292bca398SDaniel Schwierzeck 190392bca398SDaniel Schwierzeck foreach my $line (@lines) { 190492bca398SDaniel Schwierzeck $commit = $1 if ($line =~ m/$VCS_cmds{"commit_pattern"}/); 190592bca398SDaniel Schwierzeck $subject = $1 if ($line =~ m/$VCS_cmds{"subject_pattern"}/); 190692bca398SDaniel Schwierzeck if ($line =~ /^[ \t]*${signature_pattern}.*\@.*$/) { 190792bca398SDaniel Schwierzeck my @signatures = ($line); 190892bca398SDaniel Schwierzeck my ($types_ref, $signers_ref) = extract_formatted_signatures(@signatures); 190992bca398SDaniel Schwierzeck my @types = @$types_ref; 191092bca398SDaniel Schwierzeck my @signers = @$signers_ref; 191192bca398SDaniel Schwierzeck 191292bca398SDaniel Schwierzeck my $type = $types[0]; 191392bca398SDaniel Schwierzeck my $signer = $signers[0]; 191492bca398SDaniel Schwierzeck 191592bca398SDaniel Schwierzeck $signer = deduplicate_email($signer); 191692bca398SDaniel Schwierzeck 191792bca398SDaniel Schwierzeck my $exists = 0; 191892bca398SDaniel Schwierzeck foreach my $ref(@{$commit_signer_hash{$signer}}) { 191992bca398SDaniel Schwierzeck if (@{$ref}[0] eq $commit && 192092bca398SDaniel Schwierzeck @{$ref}[1] eq $subject && 192192bca398SDaniel Schwierzeck @{$ref}[2] eq $type) { 192292bca398SDaniel Schwierzeck $exists = 1; 192392bca398SDaniel Schwierzeck last; 192492bca398SDaniel Schwierzeck } 192592bca398SDaniel Schwierzeck } 192692bca398SDaniel Schwierzeck if (!$exists) { 192792bca398SDaniel Schwierzeck push(@{$commit_signer_hash{$signer}}, 192892bca398SDaniel Schwierzeck [ ($commit, $subject, $type) ]); 192992bca398SDaniel Schwierzeck } 193092bca398SDaniel Schwierzeck } 193192bca398SDaniel Schwierzeck } 193292bca398SDaniel Schwierzeck} 193392bca398SDaniel Schwierzeck 193492bca398SDaniel Schwierzecksub vcs_assign { 193592bca398SDaniel Schwierzeck my ($role, $divisor, @lines) = @_; 193692bca398SDaniel Schwierzeck 193792bca398SDaniel Schwierzeck my %hash; 193892bca398SDaniel Schwierzeck my $count = 0; 193992bca398SDaniel Schwierzeck 194092bca398SDaniel Schwierzeck return if (@lines <= 0); 194192bca398SDaniel Schwierzeck 194292bca398SDaniel Schwierzeck if ($divisor <= 0) { 194392bca398SDaniel Schwierzeck warn("Bad divisor in " . (caller(0))[3] . ": $divisor\n"); 194492bca398SDaniel Schwierzeck $divisor = 1; 194592bca398SDaniel Schwierzeck } 194692bca398SDaniel Schwierzeck 194792bca398SDaniel Schwierzeck @lines = mailmap(@lines); 194892bca398SDaniel Schwierzeck 194992bca398SDaniel Schwierzeck return if (@lines <= 0); 195092bca398SDaniel Schwierzeck 195192bca398SDaniel Schwierzeck @lines = sort(@lines); 195292bca398SDaniel Schwierzeck 195392bca398SDaniel Schwierzeck # uniq -c 195492bca398SDaniel Schwierzeck $hash{$_}++ for @lines; 195592bca398SDaniel Schwierzeck 195692bca398SDaniel Schwierzeck # sort -rn 195792bca398SDaniel Schwierzeck foreach my $line (sort {$hash{$b} <=> $hash{$a}} keys %hash) { 195892bca398SDaniel Schwierzeck my $sign_offs = $hash{$line}; 195992bca398SDaniel Schwierzeck my $percent = $sign_offs * 100 / $divisor; 196092bca398SDaniel Schwierzeck 196192bca398SDaniel Schwierzeck $percent = 100 if ($percent > 100); 19624fd65389SHeinrich Schuchardt next if (ignore_email_address($line)); 196392bca398SDaniel Schwierzeck $count++; 196492bca398SDaniel Schwierzeck last if ($sign_offs < $email_git_min_signatures || 196592bca398SDaniel Schwierzeck $count > $email_git_max_maintainers || 196692bca398SDaniel Schwierzeck $percent < $email_git_min_percent); 196792bca398SDaniel Schwierzeck push_email_address($line, ''); 196892bca398SDaniel Schwierzeck if ($output_rolestats) { 196992bca398SDaniel Schwierzeck my $fmt_percent = sprintf("%.0f", $percent); 197092bca398SDaniel Schwierzeck add_role($line, "$role:$sign_offs/$divisor=$fmt_percent%"); 197192bca398SDaniel Schwierzeck } else { 197292bca398SDaniel Schwierzeck add_role($line, $role); 197392bca398SDaniel Schwierzeck } 197492bca398SDaniel Schwierzeck } 197592bca398SDaniel Schwierzeck} 197692bca398SDaniel Schwierzeck 197792bca398SDaniel Schwierzecksub vcs_file_signoffs { 197892bca398SDaniel Schwierzeck my ($file) = @_; 197992bca398SDaniel Schwierzeck 198092bca398SDaniel Schwierzeck my $authors_ref; 198192bca398SDaniel Schwierzeck my $signers_ref; 198292bca398SDaniel Schwierzeck my $stats_ref; 198392bca398SDaniel Schwierzeck my @authors = (); 198492bca398SDaniel Schwierzeck my @signers = (); 198592bca398SDaniel Schwierzeck my @stats = (); 198692bca398SDaniel Schwierzeck my $commits; 198792bca398SDaniel Schwierzeck 198892bca398SDaniel Schwierzeck $vcs_used = vcs_exists(); 198992bca398SDaniel Schwierzeck return if (!$vcs_used); 199092bca398SDaniel Schwierzeck 199192bca398SDaniel Schwierzeck my $cmd = $VCS_cmds{"find_signers_cmd"}; 199292bca398SDaniel Schwierzeck $cmd =~ s/(\$\w+)/$1/eeg; # interpolate $cmd 199392bca398SDaniel Schwierzeck 199492bca398SDaniel Schwierzeck ($commits, $signers_ref, $authors_ref, $stats_ref) = vcs_find_signers($cmd, $file); 199592bca398SDaniel Schwierzeck 199692bca398SDaniel Schwierzeck @signers = @{$signers_ref} if defined $signers_ref; 199792bca398SDaniel Schwierzeck @authors = @{$authors_ref} if defined $authors_ref; 199892bca398SDaniel Schwierzeck @stats = @{$stats_ref} if defined $stats_ref; 199992bca398SDaniel Schwierzeck 200092bca398SDaniel Schwierzeck# print("commits: <$commits>\nsigners:<@signers>\nauthors: <@authors>\nstats: <@stats>\n"); 200192bca398SDaniel Schwierzeck 200292bca398SDaniel Schwierzeck foreach my $signer (@signers) { 200392bca398SDaniel Schwierzeck $signer = deduplicate_email($signer); 200492bca398SDaniel Schwierzeck } 200592bca398SDaniel Schwierzeck 200692bca398SDaniel Schwierzeck vcs_assign("commit_signer", $commits, @signers); 200792bca398SDaniel Schwierzeck vcs_assign("authored", $commits, @authors); 200892bca398SDaniel Schwierzeck if ($#authors == $#stats) { 200992bca398SDaniel Schwierzeck my $stat_pattern = $VCS_cmds{"stat_pattern"}; 201092bca398SDaniel Schwierzeck $stat_pattern =~ s/(\$\w+)/$1/eeg; #interpolate $stat_pattern 201192bca398SDaniel Schwierzeck 201292bca398SDaniel Schwierzeck my $added = 0; 201392bca398SDaniel Schwierzeck my $deleted = 0; 201492bca398SDaniel Schwierzeck for (my $i = 0; $i <= $#stats; $i++) { 201592bca398SDaniel Schwierzeck if ($stats[$i] =~ /$stat_pattern/) { 201692bca398SDaniel Schwierzeck $added += $1; 201792bca398SDaniel Schwierzeck $deleted += $2; 201892bca398SDaniel Schwierzeck } 201992bca398SDaniel Schwierzeck } 202092bca398SDaniel Schwierzeck my @tmp_authors = uniq(@authors); 202192bca398SDaniel Schwierzeck foreach my $author (@tmp_authors) { 202292bca398SDaniel Schwierzeck $author = deduplicate_email($author); 202392bca398SDaniel Schwierzeck } 202492bca398SDaniel Schwierzeck @tmp_authors = uniq(@tmp_authors); 202592bca398SDaniel Schwierzeck my @list_added = (); 202692bca398SDaniel Schwierzeck my @list_deleted = (); 202792bca398SDaniel Schwierzeck foreach my $author (@tmp_authors) { 202892bca398SDaniel Schwierzeck my $auth_added = 0; 202992bca398SDaniel Schwierzeck my $auth_deleted = 0; 203092bca398SDaniel Schwierzeck for (my $i = 0; $i <= $#stats; $i++) { 203192bca398SDaniel Schwierzeck if ($author eq deduplicate_email($authors[$i]) && 203292bca398SDaniel Schwierzeck $stats[$i] =~ /$stat_pattern/) { 203392bca398SDaniel Schwierzeck $auth_added += $1; 203492bca398SDaniel Schwierzeck $auth_deleted += $2; 203592bca398SDaniel Schwierzeck } 203692bca398SDaniel Schwierzeck } 203792bca398SDaniel Schwierzeck for (my $i = 0; $i < $auth_added; $i++) { 203892bca398SDaniel Schwierzeck push(@list_added, $author); 203992bca398SDaniel Schwierzeck } 204092bca398SDaniel Schwierzeck for (my $i = 0; $i < $auth_deleted; $i++) { 204192bca398SDaniel Schwierzeck push(@list_deleted, $author); 204292bca398SDaniel Schwierzeck } 204392bca398SDaniel Schwierzeck } 204492bca398SDaniel Schwierzeck vcs_assign("added_lines", $added, @list_added); 204592bca398SDaniel Schwierzeck vcs_assign("removed_lines", $deleted, @list_deleted); 204692bca398SDaniel Schwierzeck } 204792bca398SDaniel Schwierzeck} 204892bca398SDaniel Schwierzeck 204992bca398SDaniel Schwierzecksub vcs_file_blame { 205092bca398SDaniel Schwierzeck my ($file) = @_; 205192bca398SDaniel Schwierzeck 205292bca398SDaniel Schwierzeck my @signers = (); 205392bca398SDaniel Schwierzeck my @all_commits = (); 205492bca398SDaniel Schwierzeck my @commits = (); 205592bca398SDaniel Schwierzeck my $total_commits; 205692bca398SDaniel Schwierzeck my $total_lines; 205792bca398SDaniel Schwierzeck 205892bca398SDaniel Schwierzeck $vcs_used = vcs_exists(); 205992bca398SDaniel Schwierzeck return if (!$vcs_used); 206092bca398SDaniel Schwierzeck 206192bca398SDaniel Schwierzeck @all_commits = vcs_blame($file); 206292bca398SDaniel Schwierzeck @commits = uniq(@all_commits); 206392bca398SDaniel Schwierzeck $total_commits = @commits; 206492bca398SDaniel Schwierzeck $total_lines = @all_commits; 206592bca398SDaniel Schwierzeck 206692bca398SDaniel Schwierzeck if ($email_git_blame_signatures) { 206792bca398SDaniel Schwierzeck if (vcs_is_hg()) { 206892bca398SDaniel Schwierzeck my $commit_count; 206992bca398SDaniel Schwierzeck my $commit_authors_ref; 207092bca398SDaniel Schwierzeck my $commit_signers_ref; 207192bca398SDaniel Schwierzeck my $stats_ref; 207292bca398SDaniel Schwierzeck my @commit_authors = (); 207392bca398SDaniel Schwierzeck my @commit_signers = (); 207492bca398SDaniel Schwierzeck my $commit = join(" -r ", @commits); 207592bca398SDaniel Schwierzeck my $cmd; 207692bca398SDaniel Schwierzeck 207792bca398SDaniel Schwierzeck $cmd = $VCS_cmds{"find_commit_signers_cmd"}; 207892bca398SDaniel Schwierzeck $cmd =~ s/(\$\w+)/$1/eeg; #substitute variables in $cmd 207992bca398SDaniel Schwierzeck 208092bca398SDaniel Schwierzeck ($commit_count, $commit_signers_ref, $commit_authors_ref, $stats_ref) = vcs_find_signers($cmd, $file); 208192bca398SDaniel Schwierzeck @commit_authors = @{$commit_authors_ref} if defined $commit_authors_ref; 208292bca398SDaniel Schwierzeck @commit_signers = @{$commit_signers_ref} if defined $commit_signers_ref; 208392bca398SDaniel Schwierzeck 208492bca398SDaniel Schwierzeck push(@signers, @commit_signers); 208592bca398SDaniel Schwierzeck } else { 208692bca398SDaniel Schwierzeck foreach my $commit (@commits) { 208792bca398SDaniel Schwierzeck my $commit_count; 208892bca398SDaniel Schwierzeck my $commit_authors_ref; 208992bca398SDaniel Schwierzeck my $commit_signers_ref; 209092bca398SDaniel Schwierzeck my $stats_ref; 209192bca398SDaniel Schwierzeck my @commit_authors = (); 209292bca398SDaniel Schwierzeck my @commit_signers = (); 209392bca398SDaniel Schwierzeck my $cmd; 209492bca398SDaniel Schwierzeck 209592bca398SDaniel Schwierzeck $cmd = $VCS_cmds{"find_commit_signers_cmd"}; 209692bca398SDaniel Schwierzeck $cmd =~ s/(\$\w+)/$1/eeg; #substitute variables in $cmd 209792bca398SDaniel Schwierzeck 209892bca398SDaniel Schwierzeck ($commit_count, $commit_signers_ref, $commit_authors_ref, $stats_ref) = vcs_find_signers($cmd, $file); 209992bca398SDaniel Schwierzeck @commit_authors = @{$commit_authors_ref} if defined $commit_authors_ref; 210092bca398SDaniel Schwierzeck @commit_signers = @{$commit_signers_ref} if defined $commit_signers_ref; 210192bca398SDaniel Schwierzeck 210292bca398SDaniel Schwierzeck push(@signers, @commit_signers); 210392bca398SDaniel Schwierzeck } 210492bca398SDaniel Schwierzeck } 210592bca398SDaniel Schwierzeck } 210692bca398SDaniel Schwierzeck 210792bca398SDaniel Schwierzeck if ($from_filename) { 210892bca398SDaniel Schwierzeck if ($output_rolestats) { 210992bca398SDaniel Schwierzeck my @blame_signers; 211092bca398SDaniel Schwierzeck if (vcs_is_hg()) {{ # Double brace for last exit 211192bca398SDaniel Schwierzeck my $commit_count; 211292bca398SDaniel Schwierzeck my @commit_signers = (); 211392bca398SDaniel Schwierzeck @commits = uniq(@commits); 211492bca398SDaniel Schwierzeck @commits = sort(@commits); 211592bca398SDaniel Schwierzeck my $commit = join(" -r ", @commits); 211692bca398SDaniel Schwierzeck my $cmd; 211792bca398SDaniel Schwierzeck 211892bca398SDaniel Schwierzeck $cmd = $VCS_cmds{"find_commit_author_cmd"}; 211992bca398SDaniel Schwierzeck $cmd =~ s/(\$\w+)/$1/eeg; #substitute variables in $cmd 212092bca398SDaniel Schwierzeck 212192bca398SDaniel Schwierzeck my @lines = (); 212292bca398SDaniel Schwierzeck 212392bca398SDaniel Schwierzeck @lines = &{$VCS_cmds{"execute_cmd"}}($cmd); 212492bca398SDaniel Schwierzeck 212592bca398SDaniel Schwierzeck if (!$email_git_penguin_chiefs) { 212692bca398SDaniel Schwierzeck @lines = grep(!/${penguin_chiefs}/i, @lines); 212792bca398SDaniel Schwierzeck } 212892bca398SDaniel Schwierzeck 212992bca398SDaniel Schwierzeck last if !@lines; 213092bca398SDaniel Schwierzeck 213192bca398SDaniel Schwierzeck my @authors = (); 213292bca398SDaniel Schwierzeck foreach my $line (@lines) { 213392bca398SDaniel Schwierzeck if ($line =~ m/$VCS_cmds{"author_pattern"}/) { 213492bca398SDaniel Schwierzeck my $author = $1; 213592bca398SDaniel Schwierzeck $author = deduplicate_email($author); 213692bca398SDaniel Schwierzeck push(@authors, $author); 213792bca398SDaniel Schwierzeck } 213892bca398SDaniel Schwierzeck } 213992bca398SDaniel Schwierzeck 214092bca398SDaniel Schwierzeck save_commits_by_author(@lines) if ($interactive); 214192bca398SDaniel Schwierzeck save_commits_by_signer(@lines) if ($interactive); 214292bca398SDaniel Schwierzeck 214392bca398SDaniel Schwierzeck push(@signers, @authors); 214492bca398SDaniel Schwierzeck }} 214592bca398SDaniel Schwierzeck else { 214692bca398SDaniel Schwierzeck foreach my $commit (@commits) { 214792bca398SDaniel Schwierzeck my $i; 214892bca398SDaniel Schwierzeck my $cmd = $VCS_cmds{"find_commit_author_cmd"}; 214992bca398SDaniel Schwierzeck $cmd =~ s/(\$\w+)/$1/eeg; #interpolate $cmd 215092bca398SDaniel Schwierzeck my @author = vcs_find_author($cmd); 215192bca398SDaniel Schwierzeck next if !@author; 215292bca398SDaniel Schwierzeck 215392bca398SDaniel Schwierzeck my $formatted_author = deduplicate_email($author[0]); 215492bca398SDaniel Schwierzeck 215592bca398SDaniel Schwierzeck my $count = grep(/$commit/, @all_commits); 215692bca398SDaniel Schwierzeck for ($i = 0; $i < $count ; $i++) { 215792bca398SDaniel Schwierzeck push(@blame_signers, $formatted_author); 215892bca398SDaniel Schwierzeck } 215992bca398SDaniel Schwierzeck } 216092bca398SDaniel Schwierzeck } 216192bca398SDaniel Schwierzeck if (@blame_signers) { 216292bca398SDaniel Schwierzeck vcs_assign("authored lines", $total_lines, @blame_signers); 216392bca398SDaniel Schwierzeck } 216492bca398SDaniel Schwierzeck } 216592bca398SDaniel Schwierzeck foreach my $signer (@signers) { 216692bca398SDaniel Schwierzeck $signer = deduplicate_email($signer); 216792bca398SDaniel Schwierzeck } 216892bca398SDaniel Schwierzeck vcs_assign("commits", $total_commits, @signers); 216992bca398SDaniel Schwierzeck } else { 217092bca398SDaniel Schwierzeck foreach my $signer (@signers) { 217192bca398SDaniel Schwierzeck $signer = deduplicate_email($signer); 217292bca398SDaniel Schwierzeck } 217392bca398SDaniel Schwierzeck vcs_assign("modified commits", $total_commits, @signers); 217492bca398SDaniel Schwierzeck } 217592bca398SDaniel Schwierzeck} 217692bca398SDaniel Schwierzeck 21774fd65389SHeinrich Schuchardtsub vcs_file_exists { 21784fd65389SHeinrich Schuchardt my ($file) = @_; 21794fd65389SHeinrich Schuchardt 21804fd65389SHeinrich Schuchardt my $exists; 21814fd65389SHeinrich Schuchardt 21824fd65389SHeinrich Schuchardt my $vcs_used = vcs_exists(); 21834fd65389SHeinrich Schuchardt return 0 if (!$vcs_used); 21844fd65389SHeinrich Schuchardt 21854fd65389SHeinrich Schuchardt my $cmd = $VCS_cmds{"file_exists_cmd"}; 21864fd65389SHeinrich Schuchardt $cmd =~ s/(\$\w+)/$1/eeg; # interpolate $cmd 21874fd65389SHeinrich Schuchardt $cmd .= " 2>&1"; 21884fd65389SHeinrich Schuchardt $exists = &{$VCS_cmds{"execute_cmd"}}($cmd); 21894fd65389SHeinrich Schuchardt 21904fd65389SHeinrich Schuchardt return 0 if ($? != 0); 21914fd65389SHeinrich Schuchardt 21924fd65389SHeinrich Schuchardt return $exists; 21934fd65389SHeinrich Schuchardt} 21944fd65389SHeinrich Schuchardt 219592bca398SDaniel Schwierzecksub uniq { 219692bca398SDaniel Schwierzeck my (@parms) = @_; 219792bca398SDaniel Schwierzeck 219892bca398SDaniel Schwierzeck my %saw; 219992bca398SDaniel Schwierzeck @parms = grep(!$saw{$_}++, @parms); 220092bca398SDaniel Schwierzeck return @parms; 220192bca398SDaniel Schwierzeck} 220292bca398SDaniel Schwierzeck 220392bca398SDaniel Schwierzecksub sort_and_uniq { 220492bca398SDaniel Schwierzeck my (@parms) = @_; 220592bca398SDaniel Schwierzeck 220692bca398SDaniel Schwierzeck my %saw; 220792bca398SDaniel Schwierzeck @parms = sort @parms; 220892bca398SDaniel Schwierzeck @parms = grep(!$saw{$_}++, @parms); 220992bca398SDaniel Schwierzeck return @parms; 221092bca398SDaniel Schwierzeck} 221192bca398SDaniel Schwierzeck 221292bca398SDaniel Schwierzecksub clean_file_emails { 221392bca398SDaniel Schwierzeck my (@file_emails) = @_; 221492bca398SDaniel Schwierzeck my @fmt_emails = (); 221592bca398SDaniel Schwierzeck 221692bca398SDaniel Schwierzeck foreach my $email (@file_emails) { 221792bca398SDaniel Schwierzeck $email =~ s/[\(\<\{]{0,1}([A-Za-z0-9_\.\+-]+\@[A-Za-z0-9\.-]+)[\)\>\}]{0,1}/\<$1\>/g; 221892bca398SDaniel Schwierzeck my ($name, $address) = parse_email($email); 221992bca398SDaniel Schwierzeck if ($name eq '"[,\.]"') { 222092bca398SDaniel Schwierzeck $name = ""; 222192bca398SDaniel Schwierzeck } 222292bca398SDaniel Schwierzeck 222392bca398SDaniel Schwierzeck my @nw = split(/[^A-Za-zÀ-ÿ\'\,\.\+-]/, $name); 222492bca398SDaniel Schwierzeck if (@nw > 2) { 222592bca398SDaniel Schwierzeck my $first = $nw[@nw - 3]; 222692bca398SDaniel Schwierzeck my $middle = $nw[@nw - 2]; 222792bca398SDaniel Schwierzeck my $last = $nw[@nw - 1]; 222892bca398SDaniel Schwierzeck 222992bca398SDaniel Schwierzeck if (((length($first) == 1 && $first =~ m/[A-Za-z]/) || 223092bca398SDaniel Schwierzeck (length($first) == 2 && substr($first, -1) eq ".")) || 223192bca398SDaniel Schwierzeck (length($middle) == 1 || 223292bca398SDaniel Schwierzeck (length($middle) == 2 && substr($middle, -1) eq "."))) { 223392bca398SDaniel Schwierzeck $name = "$first $middle $last"; 223492bca398SDaniel Schwierzeck } else { 223592bca398SDaniel Schwierzeck $name = "$middle $last"; 223692bca398SDaniel Schwierzeck } 223792bca398SDaniel Schwierzeck } 223892bca398SDaniel Schwierzeck 223992bca398SDaniel Schwierzeck if (substr($name, -1) =~ /[,\.]/) { 224092bca398SDaniel Schwierzeck $name = substr($name, 0, length($name) - 1); 224192bca398SDaniel Schwierzeck } elsif (substr($name, -2) =~ /[,\.]"/) { 224292bca398SDaniel Schwierzeck $name = substr($name, 0, length($name) - 2) . '"'; 224392bca398SDaniel Schwierzeck } 224492bca398SDaniel Schwierzeck 224592bca398SDaniel Schwierzeck if (substr($name, 0, 1) =~ /[,\.]/) { 224692bca398SDaniel Schwierzeck $name = substr($name, 1, length($name) - 1); 224792bca398SDaniel Schwierzeck } elsif (substr($name, 0, 2) =~ /"[,\.]/) { 224892bca398SDaniel Schwierzeck $name = '"' . substr($name, 2, length($name) - 2); 224992bca398SDaniel Schwierzeck } 225092bca398SDaniel Schwierzeck 225192bca398SDaniel Schwierzeck my $fmt_email = format_email($name, $address, $email_usename); 225292bca398SDaniel Schwierzeck push(@fmt_emails, $fmt_email); 225392bca398SDaniel Schwierzeck } 225492bca398SDaniel Schwierzeck return @fmt_emails; 225592bca398SDaniel Schwierzeck} 225692bca398SDaniel Schwierzeck 225792bca398SDaniel Schwierzecksub merge_email { 225892bca398SDaniel Schwierzeck my @lines; 225992bca398SDaniel Schwierzeck my %saw; 226092bca398SDaniel Schwierzeck 226192bca398SDaniel Schwierzeck for (@_) { 226292bca398SDaniel Schwierzeck my ($address, $role) = @$_; 226392bca398SDaniel Schwierzeck if (!$saw{$address}) { 226492bca398SDaniel Schwierzeck if ($output_roles) { 226592bca398SDaniel Schwierzeck push(@lines, "$address ($role)"); 226692bca398SDaniel Schwierzeck } else { 226792bca398SDaniel Schwierzeck push(@lines, $address); 226892bca398SDaniel Schwierzeck } 226992bca398SDaniel Schwierzeck $saw{$address} = 1; 227092bca398SDaniel Schwierzeck } 227192bca398SDaniel Schwierzeck } 227292bca398SDaniel Schwierzeck 227392bca398SDaniel Schwierzeck return @lines; 227492bca398SDaniel Schwierzeck} 227592bca398SDaniel Schwierzeck 227692bca398SDaniel Schwierzecksub output { 227792bca398SDaniel Schwierzeck my (@parms) = @_; 227892bca398SDaniel Schwierzeck 227992bca398SDaniel Schwierzeck if ($output_multiline) { 228092bca398SDaniel Schwierzeck foreach my $line (@parms) { 228192bca398SDaniel Schwierzeck print("${line}\n"); 228292bca398SDaniel Schwierzeck } 228392bca398SDaniel Schwierzeck } else { 228492bca398SDaniel Schwierzeck print(join($output_separator, @parms)); 228592bca398SDaniel Schwierzeck print("\n"); 228692bca398SDaniel Schwierzeck } 228792bca398SDaniel Schwierzeck} 228892bca398SDaniel Schwierzeck 228992bca398SDaniel Schwierzeckmy $rfc822re; 229092bca398SDaniel Schwierzeck 229192bca398SDaniel Schwierzecksub make_rfc822re { 229292bca398SDaniel Schwierzeck# Basic lexical tokens are specials, domain_literal, quoted_string, atom, and 229392bca398SDaniel Schwierzeck# comment. We must allow for rfc822_lwsp (or comments) after each of these. 229492bca398SDaniel Schwierzeck# This regexp will only work on addresses which have had comments stripped 229592bca398SDaniel Schwierzeck# and replaced with rfc822_lwsp. 229692bca398SDaniel Schwierzeck 229792bca398SDaniel Schwierzeck my $specials = '()<>@,;:\\\\".\\[\\]'; 229892bca398SDaniel Schwierzeck my $controls = '\\000-\\037\\177'; 229992bca398SDaniel Schwierzeck 230092bca398SDaniel Schwierzeck my $dtext = "[^\\[\\]\\r\\\\]"; 230192bca398SDaniel Schwierzeck my $domain_literal = "\\[(?:$dtext|\\\\.)*\\]$rfc822_lwsp*"; 230292bca398SDaniel Schwierzeck 230392bca398SDaniel Schwierzeck my $quoted_string = "\"(?:[^\\\"\\r\\\\]|\\\\.|$rfc822_lwsp)*\"$rfc822_lwsp*"; 230492bca398SDaniel Schwierzeck 230592bca398SDaniel Schwierzeck# Use zero-width assertion to spot the limit of an atom. A simple 230692bca398SDaniel Schwierzeck# $rfc822_lwsp* causes the regexp engine to hang occasionally. 230792bca398SDaniel Schwierzeck my $atom = "[^$specials $controls]+(?:$rfc822_lwsp+|\\Z|(?=[\\[\"$specials]))"; 230892bca398SDaniel Schwierzeck my $word = "(?:$atom|$quoted_string)"; 230992bca398SDaniel Schwierzeck my $localpart = "$word(?:\\.$rfc822_lwsp*$word)*"; 231092bca398SDaniel Schwierzeck 231192bca398SDaniel Schwierzeck my $sub_domain = "(?:$atom|$domain_literal)"; 231292bca398SDaniel Schwierzeck my $domain = "$sub_domain(?:\\.$rfc822_lwsp*$sub_domain)*"; 231392bca398SDaniel Schwierzeck 231492bca398SDaniel Schwierzeck my $addr_spec = "$localpart\@$rfc822_lwsp*$domain"; 231592bca398SDaniel Schwierzeck 231692bca398SDaniel Schwierzeck my $phrase = "$word*"; 231792bca398SDaniel Schwierzeck my $route = "(?:\@$domain(?:,\@$rfc822_lwsp*$domain)*:$rfc822_lwsp*)"; 231892bca398SDaniel Schwierzeck my $route_addr = "\\<$rfc822_lwsp*$route?$addr_spec\\>$rfc822_lwsp*"; 231992bca398SDaniel Schwierzeck my $mailbox = "(?:$addr_spec|$phrase$route_addr)"; 232092bca398SDaniel Schwierzeck 232192bca398SDaniel Schwierzeck my $group = "$phrase:$rfc822_lwsp*(?:$mailbox(?:,\\s*$mailbox)*)?;\\s*"; 232292bca398SDaniel Schwierzeck my $address = "(?:$mailbox|$group)"; 232392bca398SDaniel Schwierzeck 232492bca398SDaniel Schwierzeck return "$rfc822_lwsp*$address"; 232592bca398SDaniel Schwierzeck} 232692bca398SDaniel Schwierzeck 232792bca398SDaniel Schwierzecksub rfc822_strip_comments { 232892bca398SDaniel Schwierzeck my $s = shift; 232992bca398SDaniel Schwierzeck# Recursively remove comments, and replace with a single space. The simpler 233092bca398SDaniel Schwierzeck# regexps in the Email Addressing FAQ are imperfect - they will miss escaped 233192bca398SDaniel Schwierzeck# chars in atoms, for example. 233292bca398SDaniel Schwierzeck 233392bca398SDaniel Schwierzeck while ($s =~ s/^((?:[^"\\]|\\.)* 233492bca398SDaniel Schwierzeck (?:"(?:[^"\\]|\\.)*"(?:[^"\\]|\\.)*)*) 233592bca398SDaniel Schwierzeck \((?:[^()\\]|\\.)*\)/$1 /osx) {} 233692bca398SDaniel Schwierzeck return $s; 233792bca398SDaniel Schwierzeck} 233892bca398SDaniel Schwierzeck 233992bca398SDaniel Schwierzeck# valid: returns true if the parameter is an RFC822 valid address 234092bca398SDaniel Schwierzeck# 234192bca398SDaniel Schwierzecksub rfc822_valid { 234292bca398SDaniel Schwierzeck my $s = rfc822_strip_comments(shift); 234392bca398SDaniel Schwierzeck 234492bca398SDaniel Schwierzeck if (!$rfc822re) { 234592bca398SDaniel Schwierzeck $rfc822re = make_rfc822re(); 234692bca398SDaniel Schwierzeck } 234792bca398SDaniel Schwierzeck 234892bca398SDaniel Schwierzeck return $s =~ m/^$rfc822re$/so && $s =~ m/^$rfc822_char*$/; 234992bca398SDaniel Schwierzeck} 235092bca398SDaniel Schwierzeck 235192bca398SDaniel Schwierzeck# validlist: In scalar context, returns true if the parameter is an RFC822 235292bca398SDaniel Schwierzeck# valid list of addresses. 235392bca398SDaniel Schwierzeck# 235492bca398SDaniel Schwierzeck# In list context, returns an empty list on failure (an invalid 235592bca398SDaniel Schwierzeck# address was found); otherwise a list whose first element is the 235692bca398SDaniel Schwierzeck# number of addresses found and whose remaining elements are the 235792bca398SDaniel Schwierzeck# addresses. This is needed to disambiguate failure (invalid) 235892bca398SDaniel Schwierzeck# from success with no addresses found, because an empty string is 235992bca398SDaniel Schwierzeck# a valid list. 236092bca398SDaniel Schwierzeck 236192bca398SDaniel Schwierzecksub rfc822_validlist { 236292bca398SDaniel Schwierzeck my $s = rfc822_strip_comments(shift); 236392bca398SDaniel Schwierzeck 236492bca398SDaniel Schwierzeck if (!$rfc822re) { 236592bca398SDaniel Schwierzeck $rfc822re = make_rfc822re(); 236692bca398SDaniel Schwierzeck } 236792bca398SDaniel Schwierzeck # * null list items are valid according to the RFC 236892bca398SDaniel Schwierzeck # * the '1' business is to aid in distinguishing failure from no results 236992bca398SDaniel Schwierzeck 237092bca398SDaniel Schwierzeck my @r; 237192bca398SDaniel Schwierzeck if ($s =~ m/^(?:$rfc822re)?(?:,(?:$rfc822re)?)*$/so && 237292bca398SDaniel Schwierzeck $s =~ m/^$rfc822_char*$/) { 237392bca398SDaniel Schwierzeck while ($s =~ m/(?:^|,$rfc822_lwsp*)($rfc822re)/gos) { 237492bca398SDaniel Schwierzeck push(@r, $1); 237592bca398SDaniel Schwierzeck } 237692bca398SDaniel Schwierzeck return wantarray ? (scalar(@r), @r) : 1; 237792bca398SDaniel Schwierzeck } 237892bca398SDaniel Schwierzeck return wantarray ? () : 0; 237992bca398SDaniel Schwierzeck} 2380