]> git.ipfire.org Git - thirdparty/u-boot.git/blobdiff - scripts/get_maintainer.pl
Merge patch series "cmd: bdinfo: Optionally use getopt and implement bdinfo -a"
[thirdparty/u-boot.git] / scripts / get_maintainer.pl
index e3b41616c97efb9a076da5179332b0948593f45a..6c58578e9885d66d582b731c50ba031b33f5ab4a 100755 (executable)
@@ -1,4 +1,6 @@
 #!/usr/bin/env perl
+# SPDX-License-Identifier: GPL-2.0
+#
 # (c) 2007, Joe Perches <joe@perches.com>
 #           created from checkpatch.pl
 #
@@ -7,8 +9,6 @@
 #
 # usage: perl scripts/get_maintainer.pl [OPTIONS] <patch>
 #        perl scripts/get_maintainer.pl [OPTIONS] -f <file>
-#
-# Licensed under the terms of the GNU GPL License version 2
 
 use warnings;
 use strict;
@@ -19,6 +19,7 @@ my $V = '0.26';
 use Getopt::Long qw(:config no_auto_abbrev);
 use Cwd;
 use File::Find;
+use File::Spec::Functions;
 
 my $cur_path = fastgetcwd() . '/';
 my $lk_path = "./";
@@ -26,7 +27,9 @@ my $email = 1;
 my $email_usename = 1;
 my $email_maintainer = 1;
 my $email_reviewer = 1;
+my $email_fixes = 1;
 my $email_list = 1;
+my $email_moderated_list = 1;
 my $email_subscriber_list = 0;
 my $email_git_penguin_chiefs = 0;
 my $email_git = 0;
@@ -48,24 +51,31 @@ my $output_roles = 0;
 my $output_rolestats = 1;
 my $output_section_maxlen = 50;
 my $scm = 0;
+my $tree = 1;
 my $web = 0;
 my $subsystem = 0;
 my $status = 0;
 my $letters = "";
 my $keywords = 1;
 my $sections = 0;
-my $file_emails = 0;
+my $email_file_emails = 0;
 my $from_filename = 0;
 my $pattern_depth = 0;
 my $self_test = undef;
 my $version = 0;
 my $help = 0;
-my $find_maintainer_files = 1;
-
+my $find_maintainer_files = 0;
+my $maintainer_path;
 my $vcs_used = 0;
 
 my $exit = 0;
 
+my @files = ();
+my @fixes = ();                        # If a patch description includes Fixes: lines
+my @range = ();
+my @keyword_tvi = ();
+my @file_emails = ();
+
 my %commit_author_hash;
 my %commit_signer_hash;
 
@@ -245,6 +255,8 @@ if (!GetOptions(
                'r!' => \$email_reviewer,
                'n!' => \$email_usename,
                'l!' => \$email_list,
+               'fixes!' => \$email_fixes,
+               'moderated!' => \$email_moderated_list,
                's!' => \$email_subscriber_list,
                'multiline!' => \$output_multiline,
                'roles!' => \$output_roles,
@@ -253,14 +265,16 @@ if (!GetOptions(
                'subsystem!' => \$subsystem,
                'status!' => \$status,
                'scm!' => \$scm,
+               'tree!' => \$tree,
                'web!' => \$web,
                'letters=s' => \$letters,
                'pattern-depth=i' => \$pattern_depth,
                'k|keywords!' => \$keywords,
                'sections!' => \$sections,
-               'fe|file-emails!' => \$file_emails,
+               'fe|file-emails!' => \$email_file_emails,
                'f|file' => \$from_filename,
                'find-maintainer-files' => \$find_maintainer_files,
+               'mpath|maintainer-path=s' => \$maintainer_path,
                'self-test:s' => \$self_test,
                'v|version' => \$version,
                'h|help|usage' => \$help,
@@ -317,7 +331,7 @@ if ($email &&
     die "$P: Please select at least 1 email option\n";
 }
 
-if (!top_of_kernel_tree($lk_path)) {
+if ($tree && !top_of_kernel_tree($lk_path)) {
     die "$P: The current directory does not appear to be "
        . "a U-Boot source tree.\n";
 }
@@ -382,26 +396,52 @@ sub find_ignore_git {
 read_all_maintainer_files();
 
 sub read_all_maintainer_files {
-    if (-d "${lk_path}MAINTAINERS") {
-        opendir(DIR, "${lk_path}MAINTAINERS") or die $!;
-        my @files = readdir(DIR);
-        closedir(DIR);
-        foreach my $file (@files) {
-            push(@mfiles, "${lk_path}MAINTAINERS/$file") if ($file !~ /^\./);
-        }
-    }
-
-    if ($find_maintainer_files) {
-        find( { wanted => \&find_is_maintainer_file,
-                preprocess => \&find_ignore_git,
-                no_chdir => 1,
-        }, "${lk_path}");
+    my $path = "${lk_path}MAINTAINERS";
+    if (defined $maintainer_path) {
+       $path = $maintainer_path;
+       # Perl Cookbook tilde expansion if necessary
+       $path =~ s@^~([^/]*)@ $1 ? (getpwnam($1))[7] : ( $ENV{HOME} || $ENV{LOGDIR} || (getpwuid($<))[7])@ex;
+    }
+
+    if (-d $path) {
+       $path .= '/' if ($path !~ m@/$@);
+       if ($find_maintainer_files) {
+           find( { wanted => \&find_is_maintainer_file,
+                   preprocess => \&find_ignore_git,
+                   no_chdir => 1,
+               }, "$path");
+       } else {
+           opendir(DIR, "$path") or die $!;
+           my @files = readdir(DIR);
+           closedir(DIR);
+           foreach my $file (@files) {
+               push(@mfiles, "$path$file") if ($file !~ /^\./);
+           }
+       }
+    } elsif (-f "$path") {
+       push(@mfiles, "$path");
     } else {
-        push(@mfiles, "${lk_path}MAINTAINERS") if -f "${lk_path}MAINTAINERS";
+       die "$P: MAINTAINER file not found '$path'\n";
     }
-
+    die "$P: No MAINTAINER files found in '$path'\n" if (scalar(@mfiles) == 0);
     foreach my $file (@mfiles) {
-        read_maintainer_file("$file");
+       read_maintainer_file("$file");
+    }
+}
+
+sub maintainers_in_file {
+    my ($file) = @_;
+
+    return if ($file =~ m@\bMAINTAINERS$@);
+
+    if (-f $file && ($email_file_emails || $file =~ /\.yaml$/)) {
+       open(my $f, '<', $file)
+           or die "$P: Can't open $file: $!\n";
+       my $text = do { local($/) ; <$f> };
+       close($f);
+
+       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;
+       push(@file_emails, clean_file_emails(@poss_addr));
     }
 }
 
@@ -485,17 +525,13 @@ sub read_mailmap {
 
 ## use the filenames on the command line or find the filenames in the patchfiles
 
-my @files = ();
-my @range = ();
-my @keyword_tvi = ();
-my @file_emails = ();
-
 if (!@ARGV) {
     push(@ARGV, "&STDIN");
 }
 
 foreach my $file (@ARGV) {
     if ($file ne "&STDIN") {
+       $file = canonpath($file);
        ##if $file is a directory and it lacks a trailing slash, add one
        if ((-d $file)) {
            $file =~ s@([^/])$@$1/@;
@@ -503,11 +539,14 @@ foreach my $file (@ARGV) {
            die "$P: file '${file}' not found\n";
        }
     }
+    if ($from_filename && (vcs_exists() && !vcs_file_exists($file))) {
+       warn "$P: file '$file' not found in version control $!\n";
+    }
     if ($from_filename || ($file ne "&STDIN" && vcs_file_exists($file))) {
        $file =~ s/^\Q${cur_path}\E//;  #strip any absolute path
        $file =~ s/^\Q${lk_path}\E//;   #or the path to the lk tree
        push(@files, $file);
-       if ($file ne "MAINTAINERS" && -f $file && ($keywords || $file_emails)) {
+       if ($file ne "MAINTAINERS" && -f $file && $keywords) {
            open(my $f, '<', $file)
                or die "$P: Can't open $file: $!\n";
            my $text = do { local($/) ; <$f> };
@@ -519,10 +558,6 @@ foreach my $file (@ARGV) {
                    }
                }
            }
-           if ($file_emails) {
-               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;
-               push(@file_emails, clean_file_emails(@poss_addr));
-           }
        }
     } else {
        my $file_cnt = @files;
@@ -540,7 +575,20 @@ foreach my $file (@ARGV) {
 
        while (<$patch>) {
            my $patch_line = $_;
-           if (m/^\+\+\+\s+(\S+)/ or m/^---\s+(\S+)/) {
+           if (m/^ mode change [0-7]+ => [0-7]+ (\S+)\s*$/) {
+               my $filename = $1;
+               push(@files, $filename);
+           } elsif (m/^rename (?:from|to) (\S+)\s*$/) {
+               my $filename = $1;
+               push(@files, $filename);
+           } elsif (m/^diff --git a\/(\S+) b\/(\S+)\s*$/) {
+               my $filename1 = $1;
+               my $filename2 = $2;
+               push(@files, $filename1);
+               push(@files, $filename2);
+           } elsif (m/^Fixes:\s+([0-9a-fA-F]{6,40})/) {
+               push(@fixes, $1) if ($email_fixes);
+           } elsif (m/^\+\+\+\s+(\S+)/ or m/^---\s+(\S+)/) {
                my $filename = $1;
                $filename =~ s@^[^/]*/@@;
                $filename =~ s@\n@@;
@@ -570,6 +618,7 @@ foreach my $file (@ARGV) {
 }
 
 @file_emails = uniq(@file_emails);
+@fixes = uniq(@fixes);
 
 my %email_hash_name;
 my %email_hash_address;
@@ -584,7 +633,6 @@ my %deduplicate_name_hash = ();
 my %deduplicate_address_hash = ();
 
 my @maintainers = get_maintainers();
-
 if (@maintainers) {
     @maintainers = merge_email(@maintainers);
     output(@maintainers);
@@ -890,6 +938,8 @@ sub get_maintainers {
                print("\n");
            }
        }
+
+       maintainers_in_file($file);
     }
 
     if ($keywords) {
@@ -905,8 +955,10 @@ sub get_maintainers {
 
     foreach my $file (@files) {
        if ($email &&
-           ($email_git || ($email_git_fallback &&
-                           !$exact_pattern_match_hash{$file}))) {
+           ($email_git ||
+            ($email_git_fallback &&
+             $file !~ /MAINTAINERS$/ &&
+             !$exact_pattern_match_hash{$file}))) {
            vcs_file_signoffs($file);
        }
        if ($email && $email_git_blame) {
@@ -929,6 +981,7 @@ sub get_maintainers {
        }
 
        foreach my $email (@file_emails) {
+           $email = mailmap_email($email);
            my ($name, $address) = parse_email($email);
 
            my $tmp_email = format_email($name, $address, $email_usename);
@@ -937,6 +990,10 @@ sub get_maintainers {
        }
     }
 
+    foreach my $fix (@fixes) {
+       vcs_add_commit_signers($fix, "blamed_fixes");
+    }
+
     my @to = ();
     if ($email || $email_list) {
        if ($email) {
@@ -997,11 +1054,13 @@ MAINTAINER field selection options:
     --r => include reviewer(s) if any
     --n => include name 'Full Name <addr\@domain.tld>'
     --l => include list(s) if any
-    --s => include subscriber only list(s) if any
+    --moderated => include moderated lists(s) if any (default: true)
+    --s => include subscriber only list(s) if any (default: false)
     --remove-duplicates => minimize duplicate email names/addresses
     --roles => show roles (status:subsystem, git-signer, list, etc...)
     --rolestats => show roles and statistics (commits/total_commits, %)
     --file-emails => add email addresses found in -f file (default: 0 (off))
+    --fixes => for patches, add signatures of commits with 'Fixes: <commit>' (default: 1 (on))
   --scm => print SCM tree(s) if any
   --status => print status if any
   --subsystem => print subsystem name if any
@@ -1018,13 +1077,14 @@ Other options:
   --sections => print all of the subsystem sections with pattern matches
   --letters => print all matching 'letter' types from all matching sections
   --mailmap => use .mailmap file (default: $email_use_mailmap)
+  --no-tree => run without a kernel tree
   --self-test => show potential issues with MAINTAINERS file content
   --version => show version
   --help => show this help information
 
 Default options:
-  [--email --nogit --git-fallback --m --r --n --l --multiline --pattern-depth=0
-   --remove-duplicates --rolestats]
+  [--email --tree --nogit --git-fallback --m --r --n --l --multiline
+   --pattern-depth=0 --remove-duplicates --rolestats]
 
 Notes:
   Using "-f directory" may give unexpected results:
@@ -1288,11 +1348,14 @@ sub add_categories {
                } else {
                    if ($email_list) {
                        if (!$hash_list_to{lc($list_address)}) {
-                           $hash_list_to{lc($list_address)} = 1;
                            if ($list_additional =~ m/moderated/) {
-                               push(@list_to, [$list_address,
-                                               "moderated list${list_role}"]);
+                               if ($email_moderated_list) {
+                                   $hash_list_to{lc($list_address)} = 1;
+                                   push(@list_to, [$list_address,
+                                                   "moderated list${list_role}"]);
+                               }
                            } else {
+                               $hash_list_to{lc($list_address)} = 1;
                                push(@list_to, [$list_address,
                                                "open list${list_role}"]);
                            }
@@ -1300,35 +1363,11 @@ sub add_categories {
                    }
                }
            } elsif ($ptype eq "M") {
-               my ($name, $address) = parse_email($pvalue);
-               if ($name eq "") {
-                   if ($i > 0) {
-                       my $tv = $typevalue[$i - 1];
-                       if ($tv =~ m/^([A-Z]):\s*(.*)/) {
-                           if ($1 eq "P") {
-                               $name = $2;
-                               $pvalue = format_email($name, $address, $email_usename);
-                           }
-                       }
-                   }
-               }
                if ($email_maintainer) {
                    my $role = get_maintainer_role($i);
                    push_email_addresses($pvalue, $role);
                }
            } elsif ($ptype eq "R") {
-               my ($name, $address) = parse_email($pvalue);
-               if ($name eq "") {
-                   if ($i > 0) {
-                       my $tv = $typevalue[$i - 1];
-                       if ($tv =~ m/^([A-Z]):\s*(.*)/) {
-                           if ($1 eq "P") {
-                               $name = $2;
-                               $pvalue = format_email($name, $address, $email_usename);
-                           }
-                       }
-                   }
-               }
                if ($email_reviewer) {
                    my $subsystem = get_subsystem_name($i);
                    push_email_addresses($pvalue, "reviewer:$subsystem");
@@ -1680,7 +1719,7 @@ sub vcs_exists {
     %VCS_cmds = %VCS_cmds_hg;
     return 2 if eval $VCS_cmds{"available"};
     %VCS_cmds = ();
-    if (!$printed_novcs) {
+    if (!$printed_novcs && $email_git) {
        warn("$P: No supported VCS found.  Add --nogit to options?\n");
        warn("Using a git repository produces better results.\n");
        warn("Try Linus Torvalds' latest git repository using:\n");
@@ -1699,6 +1738,32 @@ sub vcs_is_hg {
     return $vcs_used == 2;
 }
 
+sub vcs_add_commit_signers {
+    return if (!vcs_exists());
+
+    my ($commit, $desc) = @_;
+    my $commit_count = 0;
+    my $commit_authors_ref;
+    my $commit_signers_ref;
+    my $stats_ref;
+    my @commit_authors = ();
+    my @commit_signers = ();
+    my $cmd;
+
+    $cmd = $VCS_cmds{"find_commit_signers_cmd"};
+    $cmd =~ s/(\$\w+)/$1/eeg;  #substitute variables in $cmd
+
+    ($commit_count, $commit_signers_ref, $commit_authors_ref, $stats_ref) = vcs_find_signers($cmd, "");
+    @commit_authors = @{$commit_authors_ref} if defined $commit_authors_ref;
+    @commit_signers = @{$commit_signers_ref} if defined $commit_signers_ref;
+
+    foreach my $signer (@commit_signers) {
+       $signer = deduplicate_email($signer);
+    }
+
+    vcs_assign($desc, 1, @commit_signers);
+}
+
 sub interactive_get_maintainers {
     my ($list_ref) = @_;
     my @list = @$list_ref;
@@ -1792,7 +1857,7 @@ tm toggle maintainers
 tg toggle git entries
 tl toggle open list entries
 ts toggle subscriber list entries
-f  emails in file       [$file_emails]
+f  emails in file       [$email_file_emails]
 k  keywords in file     [$keywords]
 r  remove duplicates    [$email_remove_duplicates]
 p# pattern match depth  [$pattern_depth]
@@ -1917,7 +1982,7 @@ EOT
                bool_invert(\$email_git_all_signature_types);
                $rerun = 1;
            } elsif ($sel eq "f") {
-               bool_invert(\$file_emails);
+               bool_invert(\$email_file_emails);
                $rerun = 1;
            } elsif ($sel eq "r") {
                bool_invert(\$email_remove_duplicates);