scripts/get_maintainer.pl: optionally ignore non-maintainer signatures
[safe/jmp/linux-2.6] / scripts / get_maintainer.pl
index e54f72f..f66018d 100755 (executable)
@@ -25,6 +25,7 @@ my $email_list = 1;
 my $email_subscriber_list = 0;
 my $email_git_penguin_chiefs = 0;
 my $email_git = 1;
+my $email_git_all_signature_types = 1;
 my $email_git_blame = 0;
 my $email_git_min_signatures = 1;
 my $email_git_max_maintainers = 5;
@@ -51,9 +52,9 @@ my $help = 0;
 my $exit = 0;
 
 my @penguin_chief = ();
-push(@penguin_chief,"Linus Torvalds:torvalds\@linux-foundation.org");
+push(@penguin_chief, "Linus Torvalds:torvalds\@linux-foundation.org");
 #Andrew wants in on most everything - 2009/01/14
-#push(@penguin_chief,"Andrew Morton:akpm\@linux-foundation.org");
+#push(@penguin_chief, "Andrew Morton:akpm\@linux-foundation.org");
 
 my @penguin_chief_names = ();
 foreach my $chief (@penguin_chief) {
@@ -63,7 +64,16 @@ foreach my $chief (@penguin_chief) {
        push(@penguin_chief_names, $chief_name);
     }
 }
-my $penguin_chiefs = "\(" . join("|",@penguin_chief_names) . "\)";
+my $penguin_chiefs = "\(" . join("|", @penguin_chief_names) . "\)";
+
+# Signature types of people who are either
+#      a) responsible for the code in question, or
+#      b) familiar enough with it to give relevant feedback
+my @signature_tags = ();
+push(@signature_tags, "Signed-off-by:");
+push(@signature_tags, "Reviewed-by:");
+push(@signature_tags, "Acked-by:");
+my $signaturePattern = "\(" . join("|", @signature_tags) . "\)";
 
 # rfc822 email address - preloaded methods go here.
 my $rfc822_lwsp = "(?:(?:\\r\\n)?[ \\t])";
@@ -100,6 +110,7 @@ my %VCS_cmds_hg = (
 if (!GetOptions(
                'email!' => \$email,
                'git!' => \$email_git,
+               'git-all-signature-types!' => \$email_git_all_signature_types,
                'git-blame!' => \$email_git_blame,
                'git-chief-penguins!' => \$email_git_penguin_chiefs,
                'git-min-signatures=i' => \$email_git_min_signatures,
@@ -126,7 +137,7 @@ if (!GetOptions(
                'fe|file-emails!' => \$file_emails,
                'f|file' => \$from_filename,
                'v|version' => \$version,
-               'h|help' => \$help,
+               'h|help|usage' => \$help,
                )) {
     die "$P: invalid argument - use --help if necessary\n";
 }
@@ -141,9 +152,9 @@ if ($version != 0) {
     exit 0;
 }
 
-if ($#ARGV < 0) {
-    usage();
-    die "$P: argument missing: patchfile or -f file please\n";
+if (-t STDIN && !@ARGV) {
+    # We're talking to a terminal, but have no command line arguments.
+    die "$P: missing patchfile or -f file - use --help if necessary\n";
 }
 
 if ($output_separator ne ", ") {
@@ -165,7 +176,6 @@ if ($sections) {
 } else {
     my $selections = $email + $scm + $status + $subsystem + $web;
     if ($selections == 0) {
-       usage();
        die "$P:  Missing required option: email, scm, status, subsystem or web\n";
     }
 }
@@ -173,7 +183,6 @@ if ($sections) {
 if ($email &&
     ($email_maintainer + $email_list + $email_subscriber_list +
      $email_git + $email_git_penguin_chiefs + $email_git_blame) == 0) {
-    usage();
     die "$P: Please select at least 1 email option\n";
 }
 
@@ -182,13 +191,18 @@ if (!top_of_kernel_tree($lk_path)) {
        . "a linux kernel source tree.\n";
 }
 
+if ($email_git_all_signature_types) {
+    $signaturePattern = "(.+?)[Bb][Yy]:";
+}
+
 ## Read MAINTAINERS for type/value pairs
 
 my @typevalue = ();
 my %keyword_hash;
 
-open(MAINT, "<${lk_path}MAINTAINERS") || die "$P: Can't open MAINTAINERS\n";
-while (<MAINT>) {
+open (my $maint, '<', "${lk_path}MAINTAINERS")
+    or die "$P: Can't open MAINTAINERS: $!\n";
+while (<$maint>) {
     my $line = $_;
 
     if ($line =~ m/^(\C):\s*(.*)/) {
@@ -213,13 +227,14 @@ while (<MAINT>) {
        push(@typevalue, $line);
     }
 }
-close(MAINT);
+close($maint);
 
 my %mailmap;
 
 if ($email_remove_duplicates) {
-    open(MAILMAP, "<${lk_path}.mailmap") || warn "$P: Can't open .mailmap\n";
-    while (<MAILMAP>) {
+    open(my $mailmap, '<', "${lk_path}.mailmap")
+       or warn "$P: Can't open .mailmap: $!\n";
+    while (<$mailmap>) {
        my $line = $_;
 
        next if ($line =~ m/^\s*#/);
@@ -238,7 +253,7 @@ if ($email_remove_duplicates) {
            $mailmap{$name} = \@arr;
        }
     }
-    close(MAILMAP);
+    close($mailmap);
 }
 
 ## use the filenames on the command line or find the filenames in the patchfiles
@@ -248,19 +263,26 @@ my @range = ();
 my @keyword_tvi = ();
 my @file_emails = ();
 
+if (!@ARGV) {
+    push(@ARGV, "&STDIN");
+}
+
 foreach my $file (@ARGV) {
-    ##if $file is a directory and it lacks a trailing slash, add one
-    if ((-d $file)) {
-       $file =~ s@([^/])$@$1/@;
-    } elsif (!(-f $file)) {
-       die "$P: file '${file}' not found\n";
+    if ($file ne "&STDIN") {
+       ##if $file is a directory and it lacks a trailing slash, add one
+       if ((-d $file)) {
+           $file =~ s@([^/])$@$1/@;
+       } elsif (!(-f $file)) {
+           die "$P: file '${file}' not found\n";
+       }
     }
     if ($from_filename) {
        push(@files, $file);
        if (-f $file && ($keywords || $file_emails)) {
-           open(FILE, "<$file") or die "$P: Can't open ${file}\n";
-           my $text = do { local($/) ; <FILE> };
-           close(FILE);
+           open(my $f, '<', $file)
+               or die "$P: Can't open $file: $!\n";
+           my $text = do { local($/) ; <$f> };
+           close($f);
            if ($keywords) {
                foreach my $line (keys %keyword_hash) {
                    if ($text =~ m/$keyword_hash{$line}/x) {
@@ -276,8 +298,10 @@ foreach my $file (@ARGV) {
     } else {
        my $file_cnt = @files;
        my $lastfile;
-       open(PATCH, "<$file") or die "$P: Can't open ${file}\n";
-       while (<PATCH>) {
+
+       open(my $patch, "< $file")
+           or die "$P: Can't open $file: $!\n";
+       while (<$patch>) {
            my $patch_line = $_;
            if (m/^\+\+\+\s+(\S+)/) {
                my $filename = $1;
@@ -297,7 +321,8 @@ foreach my $file (@ARGV) {
                }
            }
        }
-       close(PATCH);
+       close($patch);
+
        if ($file_cnt == @files) {
            warn "$P: file '${file}' doesn't appear to be a patch.  "
                . "Add -f to options?\n";
@@ -337,6 +362,7 @@ foreach my $file (@files) {
                if ($type eq 'X') {
                    if (file_match_pattern($file, $value)) {
                        $exclude = 1;
+                       last;
                    }
                }
            }
@@ -363,8 +389,7 @@ foreach my $file (@files) {
            }
        }
 
-       $tvi += ($end - $start);
-
+       $tvi = $end + 1;
     }
 
     foreach my $line (sort {$hash{$b} <=> $hash{$a}} keys %hash) {
@@ -381,8 +406,10 @@ foreach my $file (@files) {
                        $line =~ s/\\\./\./g;           ##Convert \. to .
                        $line =~ s/\.\*/\*/g;           ##Convert .* to *
                    }
+                   $line =~ s/^([A-Z]):/$1:\t/g;
                    print("$line\n");
                }
+               print("\n");
            }
     }
 
@@ -485,13 +512,15 @@ version: $V
 MAINTAINER field selection options:
   --email => print email address(es) if any
     --git => include recent git \*-by: signers
+    --git-all-signature-types => include signers regardless of signature type
+        or use only ${signaturePattern} signers (default: $email_git_all_signature_types)
     --git-chief-penguins => include ${penguin_chiefs}
-    --git-min-signatures => number of signatures required (default: 1)
-    --git-max-maintainers => maximum maintainers to add (default: 5)
-    --git-min-percent => minimum percentage of commits required (default: 5)
+    --git-min-signatures => number of signatures required (default: $email_git_min_signatures)
+    --git-max-maintainers => maximum maintainers to add (default: $email_git_max_maintainers)
+    --git-min-percent => minimum percentage of commits required (default: $email_git_min_percent)
     --git-blame => use git blame to find modified commits for patch or file
-    --git-since => git history to use (default: 1-year-ago)
-    --hg-since => hg history to use (default: -365)
+    --git-since => git history to use (default: $email_git_since)
+    --hg-since => hg history to use (default: $email_hg_since)
     --m => include maintainer(s) if any
     --n => include name 'Full Name <addr\@domain.tld>'
     --l => include list(s) if any
@@ -593,7 +622,7 @@ sub parse_email {
     $name =~ s/^\"|\"$//g;
     $address =~ s/^\s+|\s+$//g;
 
-    if ($name =~ /[^a-z0-9 \.\-]/i) {    ##has "must quote" chars
+    if ($name =~ /[^\w \-]/i) {         ##has "must quote" chars
        $name =~ s/(?<!\\)"/\\"/g;       ##escape quotes
        $name = "\"$name\"";
     }
@@ -610,7 +639,7 @@ sub format_email {
     $name =~ s/^\"|\"$//g;
     $address =~ s/^\s+|\s+$//g;
 
-    if ($name =~ /[^a-z0-9 \.\-]/i) {    ##has "must quote" chars
+    if ($name =~ /[^\w \-]/i) {          ##has "must quote" chars
        $name =~ s/(?<!\\)"/\\"/g;       ##escape quotes
        $name = "\"$name\"";
     }
@@ -952,7 +981,7 @@ sub vcs_find_signers {
 
     $commits = grep(/$pattern/, @lines);       # of commits
 
-    @lines = grep(/^[-_        a-z]+by:.*\@.*$/i, @lines);
+    @lines = grep(/^[ \t]*${signaturePattern}.*\@.*$/, @lines);
     if (!$email_git_penguin_chiefs) {
        @lines = grep(!/${penguin_chiefs}/i, @lines);
     }
@@ -1280,7 +1309,7 @@ sub rfc822_strip_comments {
 
 #   valid: returns true if the parameter is an RFC822 valid address
 #
-sub rfc822_valid ($) {
+sub rfc822_valid {
     my $s = rfc822_strip_comments(shift);
 
     if (!$rfc822re) {
@@ -1300,7 +1329,7 @@ sub rfc822_valid ($) {
 #              from success with no addresses found, because an empty string is
 #              a valid list.
 
-sub rfc822_validlist ($) {
+sub rfc822_validlist {
     my $s = rfc822_strip_comments(shift);
 
     if (!$rfc822re) {