Add a easier method to find maintainers to CC for a patch

Signed-off-by: Joe Perches <[EMAIL PROTECTED]>

Changes since last submittal:

Added options to include|ignore penguin-chiefs
Changed defaults to appropriate for git-send-email
Added optional git signed-off-by: checking
Changed syntax to be more perl like  

diff --git a/scripts/get_maintainer.pl b/scripts/get_maintainer.pl
new file mode 100755
index 0000000..9c1d4cb
--- /dev/null
+++ b/scripts/get_maintainer.pl
@@ -0,0 +1,375 @@
+#!/usr/bin/perl -w
+# (c) 2007, Joe Perches <[EMAIL PROTECTED]>
+#           created from checkpatch.pl
+#
+# Print the contact information for the maintainers
+# of the files modified in a patch
+#
+# usage: perl scripts/get_maintainers.pl <patch>
+#
+# Licensed under the terms of the GNU GPL License version 2
+
+use strict;
+
+my $P = $0;
+$P =~ [EMAIL PROTECTED]/@@g;
+
+my $V = '0.08';
+
+use Getopt::Long qw(:config no_auto_abbrev);
+
+my $tree = "./";
+my $email_usename = 1;
+my $email_maintainer = 1;
+my $email_list = 1;
+my $email_subscriber_list = 0;
+my $email_git = 1;
+my $email_git_penguin_chiefs = 0;
+my $email_multiline = 1;
+my $email_separator = ", ";
+
+my %saw;
+
+my @penguin_chief = ();
+push(@penguin_chief,"Linus Torvalds:[EMAIL PROTECTED]");
+push(@penguin_chief,"Andrew Morton:[EMAIL PROTECTED]");
+
+my @penguin_chief_names = ();
+foreach my $chief (@penguin_chief) {
+    if ($chief =~ m/^(.*):(.*)/) {
+       my $chief_name = $1;
+       my $chief_addr = $2;
+       push(@penguin_chief_names, $chief_name);
+    }
+}
+my $penguin_chiefs = join("|",@penguin_chief_names);
+
+GetOptions(
+          'tree=s' => \$tree,
+          'git!' => \$email_git,
+          'git-chief-penguins!' => \$email_git_penguin_chiefs,
+          'm!' => \$email_maintainer,
+          'n!' => \$email_usename,
+          'l!' => \$email_list,
+          's!' => \$email_subscriber_list,
+          'multiline!' => \$email_multiline,
+          'separator=s' => \$email_separator,
+          ) or exit;
+
+my $exit = 0;
+
+if ($#ARGV < 0 ||
+    (!$email_maintainer
+     && !$email_list
+     && !$email_subscriber_list
+     && !$email_git
+     && !$email_git_penguin_chiefs)) {
+    print "usage: $P [options] patchfile\n";
+    print "version: $V\n";
+    print "  --tree [path] => linux kernel source path\n";
+    print "  --git => include recent git \*-by: signers\n";
+    print "  --git-penguin-chiefs => include ${penguin_chiefs}\n";
+    print "  --m => include maintainer(s) if any\n";
+    print "  --n => include name 'Full Name <[EMAIL PROTECTED]>'\n";
+    print "  --l => include list(s) if any\n";
+    print "  --s => include subscriber only list(s) if any\n";
+    print "  --separator [, ] => separator for multiple addresses on 1 line\n";
+    print "  --multiline => print 1 address per line\n";
+    print "Default: [--g --m --l --multiline]\n";
+    print "Be sure to select something...\n";
+    exit(1);
+}
+
+if ($tree && !top_of_kernel_tree($tree)) {
+    if (${tree} ne "" and ${tree} ne "./") {
+       print "'${tree}' ";
+    } else {
+       print "The current directory ";
+    }
+    print "doesn't appear to be a linux kernel source tree\n";
+    exit(2);
+}
+
+## Read MAINTAINERS for type/value pairs
+
+my @typevalue = ();
+open(MAINT, "<${tree}MAINTAINERS") || die "$P: Can't open 
${tree}MAINTAINERS\n";
+while (<MAINT>) {
+    if (m/^(\C):\s*(.*)/) {
+       my $type = $1;
+       my $value = $2;
+
+       ##Filename pattern matching
+       if ($type eq "F" || $type eq "X") {
+           $value =~ [EMAIL PROTECTED]@[EMAIL PROTECTED];       ##Convert . to 
\.
+           $value =~ s/\*/\.\*/g;       ##Convert * to .*
+       }
+       push(@typevalue, "$type:$value");
+    } elsif (!/^(\s)*$/) {
+       push(@typevalue, $_);
+    }
+}
+close(MAINT);
+
+## Find the patched filenames
+
+my @patchedfiles = ();
+open(PATCH, "<$ARGV[0]") or die "Can't open $ARGV[0]\n";
+while (<PATCH>) {
+    if (m/^\+\+\+\s+(\S+)/) {
+       my $file = $1;
+       $file =~ [EMAIL PROTECTED]/]*/@@;
+       $file =~ [EMAIL PROTECTED]@@;
+       push(@patchedfiles, $file);
+    }
+}
+close(PATCH);
+
+# Sort and uniq patchedfiles
+
+undef %saw;
[EMAIL PROTECTED] = sort @patchedfiles;
[EMAIL PROTECTED] = grep(!$saw{$_}++, @patchedfiles);
+
+# Find responsible parties
+
+my @email_to = ();
+foreach my $patchedfile (@patchedfiles) {
+    my $exclude = 0;
+
+#Git
+
+    if ($email_git_penguin_chiefs) {
+       foreach my $chief (@penguin_chief) {
+           if ($chief =~ m/^(.*):(.*)/) {
+               my $chief_name = $1;
+               my $chief_addr = $2;
+               if ($email_usename) {
+                   push(@email_to, format_email($chief_name, $chief_addr));
+               } else {
+                   push(@email_to, $chief_addr);
+               }
+           }
+       }
+    }
+
+    if ($email_git) {
+       recent_git_signoffs($patchedfile);
+    }
+
+#Do not match excluded file patterns
+
+    foreach my $line (@typevalue) {
+       if ($line =~ m/^(\C):(.*)/) {
+           my $type = $1;
+           my $value = $2;
+           if ($type eq 'X') {
+               if (file_match_pattern($patchedfile, $value)) {
+                   $exclude = 1;
+               }
+           }
+       }
+    }
+
+    if (!$exclude) {
+       my $tvi = 0;
+       foreach my $line (@typevalue) {
+           if ($line =~ m/^(\C):(.*)/) {
+               my $type = $1;
+               my $value = $2;
+               if ($type eq 'F') {
+                   if (file_match_pattern($patchedfile, $value)) {
+                       add_emails($tvi);
+                   }
+               }
+           }
+           $tvi++;
+       }
+    }
+}
+
+## add lk if no one else is interested...
+
+my $address_cnt = @email_to;
+if ($address_cnt == 0 && $email_list) {
+    push(@email_to, "[EMAIL PROTECTED]");
+}
+
+## sort and uniq email_to
+
[EMAIL PROTECTED] = sort @email_to;
+undef %saw;
[EMAIL PROTECTED] = grep(!$saw{$_}++, @email_to);
+
+if ($email_multiline) {
+    foreach my $addr (@email_to) {
+       print("${addr}\n");
+    }
+} else {
+    print(join($email_separator, @email_to));
+    print("\n");
+}
+
+exit($exit);
+
+sub file_match_pattern {
+    my ($file, $pattern) = @_;
+    if (substr($pattern, -1) eq "/") {
+       if ($file =~ [EMAIL PROTECTED]@) {
+           return 1;
+       }
+    } else {
+       if ($file =~ [EMAIL PROTECTED]@) {
+           my $s1 = ($file =~ tr@/@@);
+           my $s2 = ($pattern =~ tr@/@@);
+           if ($s1 == $s2) {
+               return 1;
+           }
+       }
+    }
+    return 0;
+}
+
+sub top_of_kernel_tree {
+       my ($tree) = @_;
+
+       if ($tree ne "" && substr($tree,length($tree)-1,1) ne "/") {
+           $tree .= "/";
+       }
+       if (   (-f "${tree}COPYING")
+           && (-f "${tree}CREDITS")
+           && (-f "${tree}Kbuild")
+           && (-f "${tree}MAINTAINERS")
+           && (-f "${tree}Makefile")
+           && (-f "${tree}README")
+           && (-d "${tree}Documentation")
+           && (-d "${tree}arch")
+           && (-d "${tree}include")
+           && (-d "${tree}drivers")
+           && (-d "${tree}fs")
+           && (-d "${tree}init")
+           && (-d "${tree}ipc")
+           && (-d "${tree}kernel")
+           && (-d "${tree}lib")
+           && (-d "${tree}scripts")) {
+               return 1;
+       }
+       return 0;
+}
+
+sub format_email {
+    my ($name, $email) = @_;
+
+    my $formatted_email = "";
+
+    if ($name =~ /[^a-z0-9 \.\-]/i) {    ##has "must quote" chars
+       $name =~ s/(?<!\\)"/\\"/g;       ##escape quotes
+       $formatted_email = "\"${name}\"\ \<${email}\>";
+    } else {
+       $formatted_email = "${name} \<${email}\>";
+    }
+    return $formatted_email;
+}
+
+sub add_emails {
+    my ($index) = @_;
+
+    $index = $index - 1;
+    while ($index >= 0) {
+       my $tv = $typevalue[$index];
+       if ($tv =~ m/^(\C):(.*)/) {
+           my $ptype = $1;
+           my $pvalue = $2;
+           if ($ptype eq "L") {
+               my $subscr = $pvalue;
+               if ($subscr =~ m/\s*\(subscribers-only\)/) {
+                   if ($email_subscriber_list) {
+                       $subscr =~ s/\s*\(subscribers-only\)//g;
+                       push(@email_to, $subscr);
+                   }
+               } else {
+                   if ($email_list) {
+                       push(@email_to, $pvalue);
+                   }
+               }
+           } elsif ($ptype eq "M") {
+               if ($email_maintainer) {
+                   if ($index >= 0) {
+                       my $tv = $typevalue[$index - 1];
+                       if ($tv =~ m/^(\C):(.*)/) {
+                           if ($1 eq "P" && $email_usename) {
+                               push(@email_to, format_email($2, $pvalue));
+                           } else {
+                               push(@email_to, $pvalue);
+                           }
+                       }
+                   } else {
+                       push(@email_to, $pvalue);
+                   }
+               }
+           }
+           $index--;
+       } else {
+           $index = -1;
+       }
+    }
+}
+
+sub which {
+    my ($bin) = @_;
+
+    foreach my $path (split /:/, $ENV{PATH}) {
+       if (-e "$path/$bin") {
+           return "$path/$bin";
+       }
+    }
+    
+    return "";
+}
+
+sub recent_git_signoffs {
+    my ($file) = @_;
+
+    my $sign_offs = "";
+    my $cmd = "";
+    my $output = "";
+
+    my @lines = ();
+
+    if (which("git") eq "") {
+       die("git not found\n");
+    }
+
+    $cmd = "git log --since=6.months.ago -- ${file}";
+    $cmd .= " | grep -i '^    [-a-z]*by:.*\\\@'";
+    if (!$email_git_penguin_chiefs) {
+       $cmd .= " | grep -E -v '${penguin_chiefs}'";
+    }
+    $cmd .= " | sort | uniq -c | sort -r -n | head -n 5";
+    $cmd .= " | cut -f 2 -d ':' -s";
+
+    $output = `${cmd}`;
+
+    $output =~ s/^\s*//gm;
+
+    @lines = split("\n", $output);
+    foreach my $line (@lines) {
+       if ($line =~ m/(.*) <(.*)>/) {
+           my $git_name = $1;
+           my $git_addr = $2;
+           $git_name =~ tr/^\"//;
+           $git_name =~ tr/\"$//;
+           if ($email_usename) {
+               push(@email_to, format_email($git_name, $git_addr));
+           } else {
+               push(@email_to, $git_addr);
+           }
+       } elsif ($line =~ m/<(.*)>/) {
+           my $git_addr = $1;
+           push(@email_to, $git_addr);
+       } else {
+           push(@email_to, $line);
+       }
+    }
+    return $output;
+}


-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to