diff mbox series

get_maintainer.pl: update from Linux kernel v5.13-rc6

Message ID 20210615073029.39312-1-twoerner@gmail.com
State Accepted
Commit e57c7c5c4282ce93ca6c57f299aec645bb65812d
Delegated to: Tom Rini
Headers show
Series get_maintainer.pl: update from Linux kernel v5.13-rc6 | expand

Commit Message

Trevor Woerner June 15, 2021, 7:30 a.m. UTC
Update U-Boot's version of scripts/get_maintainer.pl to sync it up with the
latest changes to the Linux kernel's version of the same script.

The last sync was with Linux kernel version v4.16. The commits to the kernel's
get_maintainer.pl since then (starting with the most recent) are:

	6343f6b71f83 get_maintainer: exclude MAINTAINERS file(s) from --git-fallback
	cdfe2d220476 get_maintainer: add test for file in VCS
	e33c9fe8b80c get_maintainer: fix unexpected behavior for path/to//file (double slashes)
	0c78c0137621 get_maintainer: add email addresses from .yaml files
	0ef82fcefb99 scripts/get_maintainer.pl: deprioritize old Fixes: addresses
	ef0c08192ac0 get_maintainer: remove uses of P: for maintainer name
	2f5bd343694e scripts/get_maintainer.pl: add signatures from Fixes: <badcommit> lines in commit message
	49662503e8e4 get_maintainer: add ability to skip moderated mailing lists
	0fbd75fd7fee get_maintainer: allow option --mpath <directory> to read all files in <directory>
	5f0baf95b1ed get_maintainer.pl: add -mpath=<path or file> for MAINTAINERS file location
	31bb82c9caa9 get_maintainer: allow usage outside of kernel tree
	0455c74788fd get_maintainer: improve patch recognition
	882ea1d64eb3 scripts: use SPDX tag in get_maintainer and checkpatch

Signed-off-by: Trevor Woerner <twoerner@gmail.com>
---
 scripts/get_maintainer.pl | 204 +++++++++++++++++++++++++-------------
 1 file changed, 134 insertions(+), 70 deletions(-)

Comments

Trevor Woerner July 8, 2021, 12:22 p.m. UTC | #1
ping?

Tom, have you had a chance to try out this update?

On Tue, Jun 15, 2021 at 3:30 AM Trevor Woerner <twoerner@gmail.com> wrote:

> Update U-Boot's version of scripts/get_maintainer.pl to sync it up with
> the
> latest changes to the Linux kernel's version of the same script.
>
> The last sync was with Linux kernel version v4.16. The commits to the
> kernel's
> get_maintainer.pl since then (starting with the most recent) are:
>
>         6343f6b71f83 get_maintainer: exclude MAINTAINERS file(s) from
> --git-fallback
>         cdfe2d220476 get_maintainer: add test for file in VCS
>         e33c9fe8b80c get_maintainer: fix unexpected behavior for
> path/to//file (double slashes)
>         0c78c0137621 get_maintainer: add email addresses from .yaml files
>         0ef82fcefb99 scripts/get_maintainer.pl: deprioritize old Fixes:
> addresses
>         ef0c08192ac0 get_maintainer: remove uses of P: for maintainer name
>         2f5bd343694e scripts/get_maintainer.pl: add signatures from
> Fixes: <badcommit> lines in commit message
>         49662503e8e4 get_maintainer: add ability to skip moderated mailing
> lists
>         0fbd75fd7fee get_maintainer: allow option --mpath <directory> to
> read all files in <directory>
>         5f0baf95b1ed get_maintainer.pl: add -mpath=<path or file> for
> MAINTAINERS file location
>         31bb82c9caa9 get_maintainer: allow usage outside of kernel tree
>         0455c74788fd get_maintainer: improve patch recognition
>         882ea1d64eb3 scripts: use SPDX tag in get_maintainer and checkpatch
>
> Signed-off-by: Trevor Woerner <twoerner@gmail.com>
> ---
>  scripts/get_maintainer.pl | 204 +++++++++++++++++++++++++-------------
>  1 file changed, 134 insertions(+), 70 deletions(-)
>
> diff --git a/scripts/get_maintainer.pl b/scripts/get_maintainer.pl
> index e3b41616c9..81116e215e 100755
> --- a/scripts/get_maintainer.pl
> +++ b/scripts/get_maintainer.pl
> @@ -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) {
> @@ -937,6 +989,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 +1053,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 +1076,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 +1347,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 +1362,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");
> @@ -1699,6 +1737,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 +1856,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 +1981,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);
> --
> 2.30.0.rc0
>
>
Tom Rini July 9, 2021, 4:30 p.m. UTC | #2
On Thu, Jul 08, 2021 at 08:22:35AM -0400, Trevor Woerner wrote:
> ping?
> 
> Tom, have you had a chance to try out this update?

Thanks, I need to do a build/related PR shortly and I'll pick this up
then.

> 
> On Tue, Jun 15, 2021 at 3:30 AM Trevor Woerner <twoerner@gmail.com> wrote:
> 
> > Update U-Boot's version of scripts/get_maintainer.pl to sync it up with
> > the
> > latest changes to the Linux kernel's version of the same script.
> >
> > The last sync was with Linux kernel version v4.16. The commits to the
> > kernel's
> > get_maintainer.pl since then (starting with the most recent) are:
> >
> >         6343f6b71f83 get_maintainer: exclude MAINTAINERS file(s) from
> > --git-fallback
> >         cdfe2d220476 get_maintainer: add test for file in VCS
> >         e33c9fe8b80c get_maintainer: fix unexpected behavior for
> > path/to//file (double slashes)
> >         0c78c0137621 get_maintainer: add email addresses from .yaml files
> >         0ef82fcefb99 scripts/get_maintainer.pl: deprioritize old Fixes:
> > addresses
> >         ef0c08192ac0 get_maintainer: remove uses of P: for maintainer name
> >         2f5bd343694e scripts/get_maintainer.pl: add signatures from
> > Fixes: <badcommit> lines in commit message
> >         49662503e8e4 get_maintainer: add ability to skip moderated mailing
> > lists
> >         0fbd75fd7fee get_maintainer: allow option --mpath <directory> to
> > read all files in <directory>
> >         5f0baf95b1ed get_maintainer.pl: add -mpath=<path or file> for
> > MAINTAINERS file location
> >         31bb82c9caa9 get_maintainer: allow usage outside of kernel tree
> >         0455c74788fd get_maintainer: improve patch recognition
> >         882ea1d64eb3 scripts: use SPDX tag in get_maintainer and checkpatch
> >
> > Signed-off-by: Trevor Woerner <twoerner@gmail.com>
> > ---
> >  scripts/get_maintainer.pl | 204 +++++++++++++++++++++++++-------------
> >  1 file changed, 134 insertions(+), 70 deletions(-)
> >
> > diff --git a/scripts/get_maintainer.pl b/scripts/get_maintainer.pl
> > index e3b41616c9..81116e215e 100755
> > --- a/scripts/get_maintainer.pl
> > +++ b/scripts/get_maintainer.pl
> > @@ -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) {
> > @@ -937,6 +989,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 +1053,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 +1076,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 +1347,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 +1362,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");
> > @@ -1699,6 +1737,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 +1856,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 +1981,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);
> > --
> > 2.30.0.rc0
> >
> >
Tom Rini July 15, 2021, 1:27 a.m. UTC | #3
On Tue, Jun 15, 2021 at 03:30:29AM -0400, Trevor Woerner wrote:

> Update U-Boot's version of scripts/get_maintainer.pl to sync it up with the
> latest changes to the Linux kernel's version of the same script.
> 
> The last sync was with Linux kernel version v4.16. The commits to the kernel's
> get_maintainer.pl since then (starting with the most recent) are:
> 
> 	6343f6b71f83 get_maintainer: exclude MAINTAINERS file(s) from --git-fallback
> 	cdfe2d220476 get_maintainer: add test for file in VCS
> 	e33c9fe8b80c get_maintainer: fix unexpected behavior for path/to//file (double slashes)
> 	0c78c0137621 get_maintainer: add email addresses from .yaml files
> 	0ef82fcefb99 scripts/get_maintainer.pl: deprioritize old Fixes: addresses
> 	ef0c08192ac0 get_maintainer: remove uses of P: for maintainer name
> 	2f5bd343694e scripts/get_maintainer.pl: add signatures from Fixes: <badcommit> lines in commit message
> 	49662503e8e4 get_maintainer: add ability to skip moderated mailing lists
> 	0fbd75fd7fee get_maintainer: allow option --mpath <directory> to read all files in <directory>
> 	5f0baf95b1ed get_maintainer.pl: add -mpath=<path or file> for MAINTAINERS file location
> 	31bb82c9caa9 get_maintainer: allow usage outside of kernel tree
> 	0455c74788fd get_maintainer: improve patch recognition
> 	882ea1d64eb3 scripts: use SPDX tag in get_maintainer and checkpatch
> 
> Signed-off-by: Trevor Woerner <twoerner@gmail.com>

Applied to u-boot/master, thanks!
diff mbox series

Patch

diff --git a/scripts/get_maintainer.pl b/scripts/get_maintainer.pl
index e3b41616c9..81116e215e 100755
--- a/scripts/get_maintainer.pl
+++ b/scripts/get_maintainer.pl
@@ -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) {
@@ -937,6 +989,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 +1053,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 +1076,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 +1347,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 +1362,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");
@@ -1699,6 +1737,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 +1856,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 +1981,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);