From 63ab52db5ba7f362266cfed03109387ca73e5eb5 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Tue, 26 Oct 2010 14:22:51 -0700 Subject: scripts/get_maintainer.pl: Add --git-blame --rolestats "Authored lines" information When options --git-blame and --rolestats are specified, add the maintainers with the qualifying --git-min-percent amount of lines authored of the complete file. Does not add more authors than specified by --git-max-maintainers. For anyone using hg, this option works but is _very_ slow. It's orders of magnitude slower than git slow. The get_maintainer.pl version was incremented to 0.25. This can be used with or without --git. For instance: $ ./scripts/get_maintainer.pl --git-blame --nogit --rolestats -f lib/bitmap.c Paul Jackson (authored lines:406/613=66%,commits:7/20=35%) Akinobu Mita (authored lines:87/613=14%,commits:3/20=15%) Reinette Chatre (authored lines:42/613=7%) Andrew Morton (commits:16/20=80%) Paul Mundt (commits:3/20=15%) Randy Dunlap (commits:2/20=10%) $ ./scripts/get_maintainer.pl --git-blame --git --rolestats -f lib/bitmap.c Andrew Morton (commit_signer:4/5=80%,commits:16/20=80%) Akinobu Mita (commit_signer:2/5=40%,authored lines:87/613=14%,commits:3/20=15%) Jack Steiner (commit_signer:1/5=20%) Ben Hutchings (commit_signer:1/5=20%) Lee Schermerhorn (commit_signer:1/5=20%) Paul Jackson (authored lines:406/613=66%,commits:7/20=35%) Reinette Chatre (authored lines:42/613=7%) Paul Mundt (commits:3/20=15%) Randy Dunlap (commits:2/20=10%) linux-kernel@vger.kernel.org (open list) Signed-off-by: Joe Perches Cc: Mark Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- scripts/get_maintainer.pl | 60 ++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 57 insertions(+), 3 deletions(-) (limited to 'scripts') diff --git a/scripts/get_maintainer.pl b/scripts/get_maintainer.pl index b2281982f52..a91ae631840 100755 --- a/scripts/get_maintainer.pl +++ b/scripts/get_maintainer.pl @@ -13,7 +13,7 @@ use strict; my $P = $0; -my $V = '0.24'; +my $V = '0.25'; use Getopt::Long qw(:config no_auto_abbrev); @@ -88,6 +88,7 @@ my %VCS_cmds_git = ( "available" => '(which("git") ne "") && (-d ".git")', "find_signers_cmd" => "git log --no-color --since=\$email_git_since -- \$file", "find_commit_signers_cmd" => "git log --no-color -1 \$commit", + "find_commit_author_cmd" => "git log -1 --format=\"%an <%ae>\" \$commit", "blame_range_cmd" => "git blame -l -L \$diff_start,+\$diff_length \$file", "blame_file_cmd" => "git blame -l \$file", "commit_pattern" => "^commit [0-9a-f]{40,40}", @@ -101,6 +102,7 @@ my %VCS_cmds_hg = ( "hg log --date=\$email_hg_since" . " --template='commit {node}\\n{desc}\\n' -- \$file", "find_commit_signers_cmd" => "hg log --template='{desc}\\n' -r \$commit", + "find_commit_author_cmd" => "hg log -l 1 --template='{author}\\n' -r \$commit", "blame_range_cmd" => "", # not supported "blame_file_cmd" => "hg blame -c \$file", "commit_pattern" => "^commit [0-9a-f]{40,40}", @@ -1014,6 +1016,9 @@ sub vcs_find_signers { if (!$email_git_penguin_chiefs) { @lines = grep(!/${penguin_chiefs}/i, @lines); } + + return (0, @lines) if !@lines; + # cut -f2- -d":" s/.*:\s*(.+)\s*/$1/ for (@lines); @@ -1027,6 +1032,28 @@ sub vcs_find_signers { return ($commits, @lines); } +sub vcs_find_author { + my ($cmd) = @_; + my @lines = (); + + @lines = &{$VCS_cmds{"execute_cmd"}}($cmd); + + if (!$email_git_penguin_chiefs) { + @lines = grep(!/${penguin_chiefs}/i, @lines); + } + + return @lines if !@lines; + +## Reformat email addresses (with names) to avoid badly written signatures + + foreach my $line (@lines) { + my ($name, $address) = parse_email($line); + $line = format_email($name, $address, 1); + } + + return @lines; +} + sub vcs_save_commits { my ($cmd) = @_; my @lines = (); @@ -1084,6 +1111,10 @@ sub vcs_blame { @commits = vcs_save_commits($cmd); } + foreach my $commit (@commits) { + $commit =~ s/^\^//g; + } + return @commits; } @@ -1121,6 +1152,8 @@ sub vcs_assign { @lines = mailmap(@lines); } + return if (@lines <= 0); + @lines = sort(@lines); # uniq -c @@ -1165,14 +1198,17 @@ sub vcs_file_blame { my ($file) = @_; my @signers = (); + my @all_commits = (); my @commits = (); my $total_commits; + my $total_lines; return if (!vcs_exists()); - @commits = vcs_blame($file); - @commits = uniq(@commits); + @all_commits = vcs_blame($file); + @commits = uniq(@all_commits); $total_commits = @commits; + $total_lines = @all_commits; foreach my $commit (@commits) { my $commit_count; @@ -1182,10 +1218,28 @@ sub vcs_file_blame { $cmd =~ s/(\$\w+)/$1/eeg; #interpolate $cmd ($commit_count, @commit_signers) = vcs_find_signers($cmd); + push(@signers, @commit_signers); } if ($from_filename) { + if ($output_rolestats) { + my @blame_signers; + foreach my $commit (@commits) { + my $i; + my $cmd = $VCS_cmds{"find_commit_author_cmd"}; + $cmd =~ s/(\$\w+)/$1/eeg; #interpolate $cmd + my @author = vcs_find_author($cmd); + next if !@author; + my $count = grep(/$commit/, @all_commits); + for ($i = 0; $i < $count ; $i++) { + push(@blame_signers, $author[0]); + } + } + if (@blame_signers) { + vcs_assign("authored lines", $total_lines, @blame_signers); + } + } vcs_assign("commits", $total_commits, @signers); } else { vcs_assign("modified commits", $total_commits, @signers); -- cgit v1.2.3-70-g09d2 From 6ffd9485f5c9c0b2d2aea9f904dff08e7088010a Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Tue, 26 Oct 2010 14:22:51 -0700 Subject: scripts/get_maintainer.pl: use correct indentation Fix an overly indented block. Signed-off-by: Joe Perches Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- scripts/get_maintainer.pl | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) (limited to 'scripts') diff --git a/scripts/get_maintainer.pl b/scripts/get_maintainer.pl index a91ae631840..65c6acf1bb3 100755 --- a/scripts/get_maintainer.pl +++ b/scripts/get_maintainer.pl @@ -420,23 +420,23 @@ foreach my $file (@files) { foreach my $line (sort {$hash{$b} <=> $hash{$a}} keys %hash) { add_categories($line); - if ($sections) { - my $i; - my $start = find_starting_index($line); - my $end = find_ending_index($line); - for ($i = $start; $i < $end; $i++) { - my $line = $typevalue[$i]; - if ($line =~ /^[FX]:/) { ##Restore file patterns - $line =~ s/([^\\])\.([^\*])/$1\?$2/g; - $line =~ s/([^\\])\.$/$1\?/g; ##Convert . back to ? - $line =~ s/\\\./\./g; ##Convert \. to . - $line =~ s/\.\*/\*/g; ##Convert .* to * - } - $line =~ s/^([A-Z]):/$1:\t/g; - print("$line\n"); + if ($sections) { + my $i; + my $start = find_starting_index($line); + my $end = find_ending_index($line); + for ($i = $start; $i < $end; $i++) { + my $line = $typevalue[$i]; + if ($line =~ /^[FX]:/) { ##Restore file patterns + $line =~ s/([^\\])\.([^\*])/$1\?$2/g; + $line =~ s/([^\\])\.$/$1\?/g; ##Convert . back to ? + $line =~ s/\\\./\./g; ##Convert \. to . + $line =~ s/\.\*/\*/g; ##Convert .* to * } - print("\n"); + $line =~ s/^([A-Z]):/$1:\t/g; + print("$line\n"); } + print("\n"); + } } if ($email && $email_git) { -- cgit v1.2.3-70-g09d2 From fab9ed12fcd0c182a72509382c3da55c527963e3 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Tue, 26 Oct 2010 14:22:52 -0700 Subject: scripts/get_maintainer.pl: don't search MAINTAINERS for keywords or emails Keyword matching uses K: patterns from MAINTAINERS, so if looking for the MAINTAINERS maintainer, don't search MAINTAINERS for pattern matches. MAINTAINERS also has rather a lot of email addresses and is easily searched using grep "^M:", so skip it. Signed-off-by: Joe Perches Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- scripts/get_maintainer.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'scripts') diff --git a/scripts/get_maintainer.pl b/scripts/get_maintainer.pl index 65c6acf1bb3..77f4f2e4cd8 100755 --- a/scripts/get_maintainer.pl +++ b/scripts/get_maintainer.pl @@ -304,7 +304,7 @@ foreach my $file (@ARGV) { } if ($from_filename) { push(@files, $file); - if (-f $file && ($keywords || $file_emails)) { + if ($file ne "MAINTAINERS" && -f $file && ($keywords || $file_emails)) { open(my $f, '<', $file) or die "$P: Can't open $file: $!\n"; my $text = do { local($/) ; <$f> }; -- cgit v1.2.3-70-g09d2 From e3e9d11479737692f797bad1762f71468d577a93 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Tue, 26 Oct 2010 14:22:53 -0700 Subject: scripts/get_maintainer.pl: add default --git-fallback, remove default --git Adding commit signers when there is a listed MAINTAINER for a file can make the output list longer than necessary. Change the --git default from on to off. Add a new --git-fallback option (default on) used to add commit signers only when there is no MAINTAINER for a file. git history is used when --git-fallback is enabled and the pattern directory depth is not the same as the file directory depth. For instance: X86 ARCHITECTURE (32-BIT AND 64-BIT) M: Thomas Gleixner M: Ingo Molnar M: "H. Peter Anvin" M: x86@kernel.org T: git git://git.kernel.org/pub/scm/linux/kernel/git/x86/linux-2.6-x86.git S: Maintained F: Documentation/x86/ F: arch/x86/ If using "./scripts/get_maintainer -f arch/x86/lib/atomic64_32.c", the pattern for "arch/x86/" does not match the directory depth of "arch/x86/lib" so the MAINTAINERS entries and git history is used to produce: $ ./scripts/get_maintainer.pl -f --rolestats arch/x86/lib/atomic64_32.c Thomas Gleixner (maintainer:X86 ARCHITECTURE...) Ingo Molnar (maintainer:X86 ARCHITECTURE...) "H. Peter Anvin" (maintainer:X86 ARCHITECTURE...,commit_signer:1/1=100%) x86@kernel.org (maintainer:X86 ARCHITECTURE...) Luca Barbieri (commit_signer:1/1=100%) linux-kernel@vger.kernel.org (open list) Luca Barbieri is added because he signed the only commit to arch/x86/lib/atomic64_32.c during the last year and he meets the other default qualifications. --git-min-percent (default:10) --git-min-signatures (default:1) If current users of ./scripts/get_maintainers.pl have scripts that use --nogit that expect git history to be excluded, those scripts should be updated to include --nogit-fallback or a .get_maintainer.conf file should be created with --nogit-fallback. Signed-off-by: Joe Perches Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- scripts/get_maintainer.pl | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'scripts') diff --git a/scripts/get_maintainer.pl b/scripts/get_maintainer.pl index 77f4f2e4cd8..f46576949cc 100755 --- a/scripts/get_maintainer.pl +++ b/scripts/get_maintainer.pl @@ -24,9 +24,10 @@ my $email_maintainer = 1; my $email_list = 1; my $email_subscriber_list = 0; my $email_git_penguin_chiefs = 0; -my $email_git = 1; +my $email_git = 0; my $email_git_all_signature_types = 0; my $email_git_blame = 0; +my $email_git_fallback = 1; my $email_git_min_signatures = 1; my $email_git_max_maintainers = 5; my $email_git_min_percent = 5; @@ -138,6 +139,7 @@ if (!GetOptions( 'git!' => \$email_git, 'git-all-signature-types!' => \$email_git_all_signature_types, 'git-blame!' => \$email_git_blame, + 'git-fallback!' => \$email_git_fallback, 'git-chief-penguins!' => \$email_git_penguin_chiefs, 'git-min-signatures=i' => \$email_git_min_signatures, 'git-max-maintainers=i' => \$email_git_max_maintainers, @@ -371,6 +373,7 @@ my @status = (); foreach my $file (@files) { my %hash; + my $exact_pattern_match = 0; my $tvi = find_first_section(); while ($tvi < @typevalue) { my $start = find_starting_index($tvi); @@ -405,6 +408,8 @@ foreach my $file (@files) { my $value_pd = ($value =~ tr@/@@); my $file_pd = ($file =~ tr@/@@); $value_pd++ if (substr($value,-1,1) ne "/"); + $value_pd = -1 if ($value =~ /^\.\*/); + $exact_pattern_match = 1 if ($value_pd >= $file_pd); if ($pattern_depth == 0 || (($file_pd - $value_pd) < $pattern_depth)) { $hash{$tvi} = $value_pd; @@ -439,7 +444,8 @@ foreach my $file (@files) { } } - if ($email && $email_git) { + if ($email && + ($email_git || ($email_git_fallback && !$exact_pattern_match))) { vcs_file_signoffs($file); } @@ -540,6 +546,7 @@ MAINTAINER field selection options: --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-fallback => use git when no exact MAINTAINERS pattern (default: $email_git_fallback) --git-chief-penguins => include ${penguin_chiefs} --git-min-signatures => number of signatures required (default: $email_git_min_signatures) --git-max-maintainers => maximum maintainers to add (default: $email_git_max_maintainers) -- cgit v1.2.3-70-g09d2 From bcde44ed7d2a58733efdf04b5392c027d1348bac Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Tue, 26 Oct 2010 14:22:53 -0700 Subject: scripts/get_maintainer.pl: use .get_maintainer.conf from . then $HOME then scripts On Mon, 2010-09-13 at 00:01 -0400, Valdis.Kletnieks@vt.edu wrote: > Any chance of getting that to be ~/.get_maintainer.conf rather than > ./.get_maintainer.conf? I've just gotten bit like the 3rd or 4th time by > "oh but you didn't create that file in *this* tree" > (I usually have a linus git tree, a linux-next tree, and 3-4 -mm trees) Sure. Add a search path for the .conf file. 3 paths are added: . customized per-tree configurations $HOME user global configuration when per-tree configs don't exist ./scripts lk defaults to override script Signed-off-by: Joe Perches Cc: Valdis Kletnieks Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- scripts/get_maintainer.pl | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) (limited to 'scripts') diff --git a/scripts/get_maintainer.pl b/scripts/get_maintainer.pl index f46576949cc..e5a400c53bf 100755 --- a/scripts/get_maintainer.pl +++ b/scripts/get_maintainer.pl @@ -110,10 +110,12 @@ my %VCS_cmds_hg = ( "blame_commit_pattern" => "^([0-9a-f]+):" ); -if (-f "${lk_path}.get_maintainer.conf") { +my $conf = which_conf(".get_maintainer.conf"); +if (-f $conf) { my @conf_args; - open(my $conffile, '<', "${lk_path}.get_maintainer.conf") - or warn "$P: Can't open .get_maintainer.conf: $!\n"; + open(my $conffile, '<', "$conf") + or warn "$P: Can't find a readable .get_maintainer.conf file $!\n"; + while (<$conffile>) { my $line = $_; @@ -961,6 +963,18 @@ sub which { return ""; } +sub which_conf { + my ($conf) = @_; + + foreach my $path (split(/:/, ".:$ENV{HOME}:.scripts")) { + if (-e "$path/$conf") { + return "$path/$conf"; + } + } + + return ""; +} + sub mailmap { my (@lines) = @_; my %hash; -- cgit v1.2.3-70-g09d2 From dace8e300d6820c2842de750d12b498a743bcfe5 Mon Sep 17 00:00:00 2001 From: Florian Mickler Date: Tue, 26 Oct 2010 14:22:54 -0700 Subject: scripts/get_maintainer.pl: add interactive mode This is a first version of an interactive mode for scripts/get_maintainer.pl. It allows the user to interact with the script. Each cc candidate can be selected and deselected and a shortlog of authored commits can be displayed for each candidate. The menu is displayed via STDERR, the end result is outputted to STDOUT. This unusual mechanism allows using get_maintainer.pl in interactive mode via git send-email --cc-cmd. Signed-off-by: Joe Perches Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- scripts/get_maintainer.pl | 146 ++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 141 insertions(+), 5 deletions(-) (limited to 'scripts') diff --git a/scripts/get_maintainer.pl b/scripts/get_maintainer.pl index e5a400c53bf..1ae8c50f190 100755 --- a/scripts/get_maintainer.pl +++ b/scripts/get_maintainer.pl @@ -33,6 +33,7 @@ my $email_git_max_maintainers = 5; my $email_git_min_percent = 5; my $email_git_since = "1-year-ago"; my $email_hg_since = "-365"; +my $interactive = 0; my $email_remove_duplicates = 1; my $output_multiline = 1; my $output_separator = ", "; @@ -52,6 +53,8 @@ my $help = 0; my $exit = 0; +my %shortlog_buffer; + my @penguin_chief = (); push(@penguin_chief, "Linus Torvalds:torvalds\@linux-foundation.org"); #Andrew wants in on most everything - 2009/01/14 @@ -93,7 +96,8 @@ my %VCS_cmds_git = ( "blame_range_cmd" => "git blame -l -L \$diff_start,+\$diff_length \$file", "blame_file_cmd" => "git blame -l \$file", "commit_pattern" => "^commit [0-9a-f]{40,40}", - "blame_commit_pattern" => "^([0-9a-f]+) " + "blame_commit_pattern" => "^([0-9a-f]+) ", + "shortlog_cmd" => "git log --no-color --oneline --since=\$email_git_since --author=\"\$email\" -- \$file" ); my %VCS_cmds_hg = ( @@ -107,7 +111,8 @@ my %VCS_cmds_hg = ( "blame_range_cmd" => "", # not supported "blame_file_cmd" => "hg blame -c \$file", "commit_pattern" => "^commit [0-9a-f]{40,40}", - "blame_commit_pattern" => "^([0-9a-f]+):" + "blame_commit_pattern" => "^([0-9a-f]+):", + "shortlog_cmd" => "ht log --date=\$email_hg_since" ); my $conf = which_conf(".get_maintainer.conf"); @@ -148,6 +153,7 @@ if (!GetOptions( 'git-min-percent=i' => \$email_git_min_percent, 'git-since=s' => \$email_git_since, 'hg-since=s' => \$email_hg_since, + 'i|interactive!' => \$interactive, 'remove-duplicates!' => \$email_remove_duplicates, 'm!' => \$email_maintainer, 'n!' => \$email_usename, @@ -225,6 +231,8 @@ if ($email_git_all_signature_types) { $signaturePattern = "(.+?)[Bb][Yy]:"; } + + ## Read MAINTAINERS for type/value pairs my @typevalue = (); @@ -450,10 +458,13 @@ foreach my $file (@files) { ($email_git || ($email_git_fallback && !$exact_pattern_match))) { vcs_file_signoffs($file); } - if ($email && $email_git_blame) { vcs_file_blame($file); } + if ($email && $interactive){ + vcs_file_shortlogs($file); + + } } if ($keywords) { @@ -486,9 +497,13 @@ if ($email) { } } + if ($email || $email_list) { my @to = (); if ($email) { + if ($interactive) { + @email_to = @{vcs_interactive_menu(\@email_to)}; + } @to = (@to, @email_to); } if ($email_list) { @@ -501,7 +516,6 @@ if ($scm) { @scm = uniq(@scm); output(@scm); } - if ($status) { @status = uniq(@status); output(@status); @@ -556,6 +570,7 @@ MAINTAINER field selection options: --git-blame => use git blame to find modified commits for patch or file --git-since => git history to use (default: $email_git_since) --hg-since => hg history to use (default: $email_hg_since) + --interactive => display a menu (mostly useful if used with the --git option) --m => include maintainer(s) if any --n => include name 'Full Name ' --l => include list(s) if any @@ -1156,6 +1171,127 @@ sub vcs_exists { return 0; } +sub vcs_interactive_menu { + my $list_ref = shift; + my @list = @$list_ref; + + return if (!vcs_exists()); + + my %selected; + my %shortlog; + my $input; + my $count = 0; + + #select maintainers by default + foreach my $entry (@list){ + my $role = $entry->[1]; + $selected{$count} = ($role =~ /maintainer:|supporter:/); + $count++; + } + + #menu loop + do { + my $count = 0; + foreach my $entry (@list){ + my $email = $entry->[0]; + my $role = $entry->[1]; + if ($selected{$count}){ + print STDERR "* "; + } else { + print STDERR " "; + } + print STDERR "$count: $email,\t\t $role"; + print STDERR "\n"; + if ($shortlog{$count}){ + my $entries_ref = vcs_get_shortlog($email); + foreach my $entry_ref (@{$entries_ref}){ + my $filename = @{$entry_ref}[0]; + my @shortlog = @{@{$entry_ref}[1]}; + print STDERR "\tshortlog for $filename (authored commits: " . @shortlog . ").\n"; + foreach my $commit (@shortlog){ + print STDERR "\t $commit\n"; + } + print STDERR "\n"; + } + } + $count++; + } + print STDERR "\n"; + print STDERR "Choose whom to cc by entering a commaseperated list of numbers and hitting enter.\n"; + print STDERR "To show a short list of commits, precede the number by a '?',\n"; + print STDERR "A blank line indicates that you are satisfied with your choice.\n"; + $input = ; + chomp($input); + + my @wish = split(/[, ]+/,$input); + foreach my $nr (@wish){ + my $logtoggle = 0; + if ($nr =~ /\?/){ + $nr =~ s/\?//; + $logtoggle = 1; + } + + #skip out of bounds numbers + next unless ($nr <= $count && $nr >= 0); + + if ($logtoggle){ + $shortlog{$nr} = !$shortlog{$nr}; + } else { + $selected{$nr} = !$selected{$nr}; + + #switch shortlog on if an entry get's selected + if ($selected{$nr}){ + $shortlog{$nr}=1; + } + } + }; + } while(length($input) > 0); + + #drop not selected entries + $count = 0; + my @new_emailto; + foreach my $entry (@list){ + if ($selected{$count}){ + push(@new_emailto,$list[$count]); + print STDERR "$count: "; + print STDERR $email_to[$count]->[0]; + print STDERR ",\t\t "; + print STDERR $email_to[$count]->[1]; + print STDERR "\n"; + } + $count++; + } + return \@new_emailto; +} + +sub vcs_get_shortlog { + my $arg = shift; + my ($name, $address) = parse_email($arg); + return $shortlog_buffer{$address}; +} + +sub vcs_file_shortlogs { + my ($file) = @_; + print STDERR "shortlog processing $file:"; + foreach my $entry (@email_to){ + my ($name, $address) = parse_email($entry->[0]); + print STDERR "."; + my $commits_ref = vcs_email_shortlog($address, $file); + push(@{$shortlog_buffer{$address}}, [ $file, $commits_ref ]); + } + print STDERR "\n"; +} + +sub vcs_email_shortlog { + my $email = shift; + my ($file) = @_; + + my $cmd = $VCS_cmds{"shortlog_cmd"}; + $cmd =~ s/(\$\w+)/$1/eeg; #substitute variables + my @lines = &{$VCS_cmds{"execute_cmd"}}($cmd); + return \@lines; +} + sub vcs_assign { my ($role, $divisor, @lines) = @_; @@ -1236,7 +1372,7 @@ sub vcs_file_blame { my @commit_signers = (); my $cmd = $VCS_cmds{"find_commit_signers_cmd"}; - $cmd =~ s/(\$\w+)/$1/eeg; #interpolate $cmd + $cmd =~ s/(\$\w+)/$1/eeg; #substitute variables in $cmd ($commit_count, @commit_signers) = vcs_find_signers($cmd); -- cgit v1.2.3-70-g09d2 From 683c6f8fcbcb6de8d07545ba70aff49e50d8bcf2 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Tue, 26 Oct 2010 14:22:55 -0700 Subject: scripts/get_maintainer.pl: improve --interactive UI o Added searching by git-blame as well as git-history o Added different selection toggles o Added ability to list commits by author or by sign-off-type o Use custom git and hg formats to make searching for subject/author a bit easier. o Move inlined section matching and searching git/hg history to new get_maintainer subroutine o Added subroutines save_commits_by_author and save_commits_by_signer o Removed subroutines vcs_get_shortlog and vcs_email_shortlog o Rename camelcase signaturePattern to signature_pattern Update to 0.26 beta3 Signed-off-by: Joe Perches Cc: Florian Mickler Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- scripts/get_maintainer.pl | 871 +++++++++++++++++++++++++++++++--------------- 1 file changed, 596 insertions(+), 275 deletions(-) (limited to 'scripts') diff --git a/scripts/get_maintainer.pl b/scripts/get_maintainer.pl index 1ae8c50f190..f51176039ff 100755 --- a/scripts/get_maintainer.pl +++ b/scripts/get_maintainer.pl @@ -13,7 +13,7 @@ use strict; my $P = $0; -my $V = '0.25'; +my $V = '0.26-beta3'; use Getopt::Long qw(:config no_auto_abbrev); @@ -27,6 +27,7 @@ my $email_git_penguin_chiefs = 0; my $email_git = 0; my $email_git_all_signature_types = 0; my $email_git_blame = 0; +my $email_git_blame_signatures = 1; my $email_git_fallback = 1; my $email_git_min_signatures = 1; my $email_git_max_maintainers = 5; @@ -51,9 +52,12 @@ my $pattern_depth = 0; my $version = 0; my $help = 0; +my $vcs_used = 0; + my $exit = 0; -my %shortlog_buffer; +my %commit_author_hash; +my %commit_signer_hash; my @penguin_chief = (); push(@penguin_chief, "Linus Torvalds:torvalds\@linux-foundation.org"); @@ -77,7 +81,6 @@ 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])"; @@ -90,29 +93,62 @@ my %VCS_cmds; my %VCS_cmds_git = ( "execute_cmd" => \&git_execute_cmd, "available" => '(which("git") ne "") && (-d ".git")', - "find_signers_cmd" => "git log --no-color --since=\$email_git_since -- \$file", - "find_commit_signers_cmd" => "git log --no-color -1 \$commit", - "find_commit_author_cmd" => "git log -1 --format=\"%an <%ae>\" \$commit", + "find_signers_cmd" => + "git log --no-color --since=\$email_git_since " . + '--format="GitCommit: %H%n' . + 'GitAuthor: %an <%ae>%n' . + 'GitDate: %aD%n' . + 'GitSubject: %s%n' . + '%b%n"' . + " -- \$file", + "find_commit_signers_cmd" => + "git log --no-color " . + '--format="GitCommit: %H%n' . + 'GitAuthor: %an <%ae>%n' . + 'GitDate: %aD%n' . + 'GitSubject: %s%n' . + '%b%n"' . + " -1 \$commit", + "find_commit_author_cmd" => + "git log --no-color " . + '--format="GitCommit: %H%n' . + 'GitAuthor: %an <%ae>%n' . + 'GitDate: %aD%n' . + 'GitSubject: %s%n"' . + " -1 \$commit", "blame_range_cmd" => "git blame -l -L \$diff_start,+\$diff_length \$file", "blame_file_cmd" => "git blame -l \$file", - "commit_pattern" => "^commit [0-9a-f]{40,40}", + "commit_pattern" => "^GitCommit: ([0-9a-f]{40,40})", "blame_commit_pattern" => "^([0-9a-f]+) ", - "shortlog_cmd" => "git log --no-color --oneline --since=\$email_git_since --author=\"\$email\" -- \$file" + "author_pattern" => "^GitAuthor: (.*)", + "subject_pattern" => "^GitSubject: (.*)", ); my %VCS_cmds_hg = ( "execute_cmd" => \&hg_execute_cmd, "available" => '(which("hg") ne "") && (-d ".hg")', "find_signers_cmd" => - "hg log --date=\$email_hg_since" . - " --template='commit {node}\\n{desc}\\n' -- \$file", - "find_commit_signers_cmd" => "hg log --template='{desc}\\n' -r \$commit", - "find_commit_author_cmd" => "hg log -l 1 --template='{author}\\n' -r \$commit", + "hg log --date=\$email_hg_since " . + "--template='HgCommit: {node}\\n" . + "HgAuthor: {author}\\n" . + "HgSubject: {desc}\\n'" . + " -- \$file", + "find_commit_signers_cmd" => + "hg log " . + "--template='HgSubject: {desc}\\n'" . + " -r \$commit", + "find_commit_author_cmd" => + "hg log " . + "--template='HgCommit: {node}\\n" . + "HgAuthor: {author}\\n" . + "HgSubject: {desc|firstline}\\n'" . + " -r \$commit", "blame_range_cmd" => "", # not supported - "blame_file_cmd" => "hg blame -c \$file", - "commit_pattern" => "^commit [0-9a-f]{40,40}", - "blame_commit_pattern" => "^([0-9a-f]+):", - "shortlog_cmd" => "ht log --date=\$email_hg_since" + "blame_file_cmd" => "hg blame -n \$file", + "commit_pattern" => "^HgCommit: ([0-9a-f]{40,40})", + "blame_commit_pattern" => "^([ 0-9a-f]+):", + "author_pattern" => "^HgAuthor: (.*)", + "subject_pattern" => "^HgSubject: (.*)", ); my $conf = which_conf(".get_maintainer.conf"); @@ -146,6 +182,7 @@ if (!GetOptions( 'git!' => \$email_git, 'git-all-signature-types!' => \$email_git_all_signature_types, 'git-blame!' => \$email_git_blame, + 'git-blame-signatures!' => \$email_git_blame_signatures, 'git-fallback!' => \$email_git_fallback, 'git-chief-penguins!' => \$email_git_penguin_chiefs, 'git-min-signatures=i' => \$email_git_min_signatures, @@ -193,13 +230,9 @@ if (-t STDIN && !@ARGV) { die "$P: missing patchfile or -f file - use --help if necessary\n"; } -if ($output_separator ne ", ") { - $output_multiline = 0; -} - -if ($output_rolestats) { - $output_roles = 1; -} +$output_multiline = 0 if ($output_separator ne ", "); +$output_rolestats = 1 if ($interactive); +$output_roles = 1 if ($output_rolestats); if ($sections) { $email = 0; @@ -227,12 +260,6 @@ 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 = (); @@ -371,168 +398,193 @@ foreach my $file (@ARGV) { @file_emails = uniq(@file_emails); +my %email_hash_name; +my %email_hash_address; my @email_to = (); +my %hash_list_to; my @list_to = (); my @scm = (); my @web = (); my @subsystem = (); my @status = (); +my $signature_pattern; -# Find responsible parties +my @to = get_maintainer(); -foreach my $file (@files) { +@to = merge_email(@to); - my %hash; - my $exact_pattern_match = 0; - my $tvi = find_first_section(); - while ($tvi < @typevalue) { - my $start = find_starting_index($tvi); - my $end = find_ending_index($tvi); - my $exclude = 0; - my $i; - - #Do not match excluded file patterns - - for ($i = $start; $i < $end; $i++) { - my $line = $typevalue[$i]; - if ($line =~ m/^(\C):\s*(.*)/) { - my $type = $1; - my $value = $2; - if ($type eq 'X') { - if (file_match_pattern($file, $value)) { - $exclude = 1; - last; - } - } - } - } +output(@to) if (@to); + +if ($scm) { + @scm = uniq(@scm); + output(@scm); +} + +if ($status) { + @status = uniq(@status); + output(@status); +} + +if ($subsystem) { + @subsystem = uniq(@subsystem); + output(@subsystem); +} + +if ($web) { + @web = uniq(@web); + output(@web); +} + +exit($exit); + +sub get_maintainer { + %email_hash_name = (); + %email_hash_address = (); + %commit_author_hash = (); + %commit_signer_hash = (); + @email_to = (); + %hash_list_to = (); + @list_to = (); + @scm = (); + @web = (); + @subsystem = (); + @status = (); + + if ($email_git_all_signature_types) { + $signature_pattern = "(.+?)[Bb][Yy]:"; + } else { + $signature_pattern = "\(" . join("|", @signature_tags) . "\)"; + } + + # Find responsible parties + + foreach my $file (@files) { + + my %hash; + my $exact_pattern_match = 0; + my $tvi = find_first_section(); + while ($tvi < @typevalue) { + my $start = find_starting_index($tvi); + my $end = find_ending_index($tvi); + my $exclude = 0; + my $i; + + #Do not match excluded file patterns - if (!$exclude) { for ($i = $start; $i < $end; $i++) { my $line = $typevalue[$i]; if ($line =~ m/^(\C):\s*(.*)/) { my $type = $1; my $value = $2; - if ($type eq 'F') { + if ($type eq 'X') { if (file_match_pattern($file, $value)) { - my $value_pd = ($value =~ tr@/@@); - my $file_pd = ($file =~ tr@/@@); - $value_pd++ if (substr($value,-1,1) ne "/"); - $value_pd = -1 if ($value =~ /^\.\*/); - $exact_pattern_match = 1 if ($value_pd >= $file_pd); - if ($pattern_depth == 0 || - (($file_pd - $value_pd) < $pattern_depth)) { - $hash{$tvi} = $value_pd; + $exclude = 1; + last; + } + } + } + } + + if (!$exclude) { + for ($i = $start; $i < $end; $i++) { + my $line = $typevalue[$i]; + if ($line =~ m/^(\C):\s*(.*)/) { + my $type = $1; + my $value = $2; + if ($type eq 'F') { + if (file_match_pattern($file, $value)) { + my $value_pd = ($value =~ tr@/@@); + my $file_pd = ($file =~ tr@/@@); + $value_pd++ if (substr($value,-1,1) ne "/"); + $value_pd = -1 if ($value =~ /^\.\*/); + $exact_pattern_match = 1 if ($value_pd >= $file_pd); + if ($pattern_depth == 0 || + (($file_pd - $value_pd) < $pattern_depth)) { + $hash{$tvi} = $value_pd; + } } } } } } + $tvi = $end + 1; } - $tvi = $end + 1; - } - - foreach my $line (sort {$hash{$b} <=> $hash{$a}} keys %hash) { - add_categories($line); - if ($sections) { - my $i; - my $start = find_starting_index($line); - my $end = find_ending_index($line); - for ($i = $start; $i < $end; $i++) { - my $line = $typevalue[$i]; - if ($line =~ /^[FX]:/) { ##Restore file patterns - $line =~ s/([^\\])\.([^\*])/$1\?$2/g; - $line =~ s/([^\\])\.$/$1\?/g; ##Convert . back to ? - $line =~ s/\\\./\./g; ##Convert \. to . - $line =~ s/\.\*/\*/g; ##Convert .* to * + foreach my $line (sort {$hash{$b} <=> $hash{$a}} keys %hash) { + add_categories($line); + if ($sections) { + my $i; + my $start = find_starting_index($line); + my $end = find_ending_index($line); + for ($i = $start; $i < $end; $i++) { + my $line = $typevalue[$i]; + if ($line =~ /^[FX]:/) { ##Restore file patterns + $line =~ s/([^\\])\.([^\*])/$1\?$2/g; + $line =~ s/([^\\])\.$/$1\?/g; ##Convert . back to ? + $line =~ s/\\\./\./g; ##Convert \. to . + $line =~ s/\.\*/\*/g; ##Convert .* to * + } + $line =~ s/^([A-Z]):/$1:\t/g; + print("$line\n"); } - $line =~ s/^([A-Z]):/$1:\t/g; - print("$line\n"); + print("\n"); } - print("\n"); } - } - - if ($email && - ($email_git || ($email_git_fallback && !$exact_pattern_match))) { - vcs_file_signoffs($file); - } - if ($email && $email_git_blame) { - vcs_file_blame($file); - } - if ($email && $interactive){ - vcs_file_shortlogs($file); + if ($email && ($email_git || + ($email_git_fallback && !$exact_pattern_match))) { + vcs_file_signoffs($file); + } + if ($email && $email_git_blame) { + vcs_file_blame($file); + } } -} -if ($keywords) { - @keyword_tvi = sort_and_uniq(@keyword_tvi); - foreach my $line (@keyword_tvi) { - add_categories($line); + if ($keywords) { + @keyword_tvi = sort_and_uniq(@keyword_tvi); + foreach my $line (@keyword_tvi) { + add_categories($line); + } } -} -if ($email) { - foreach my $chief (@penguin_chief) { - if ($chief =~ m/^(.*):(.*)/) { - my $email_address; + if ($email) { + foreach my $chief (@penguin_chief) { + if ($chief =~ m/^(.*):(.*)/) { + my $email_address; - $email_address = format_email($1, $2, $email_usename); - if ($email_git_penguin_chiefs) { - push(@email_to, [$email_address, 'chief penguin']); - } else { - @email_to = grep($_->[0] !~ /${email_address}/, @email_to); + $email_address = format_email($1, $2, $email_usename); + if ($email_git_penguin_chiefs) { + push(@email_to, [$email_address, 'chief penguin']); + } else { + @email_to = grep($_->[0] !~ /${email_address}/, @email_to); + } } } - } - foreach my $email (@file_emails) { - my ($name, $address) = parse_email($email); + foreach my $email (@file_emails) { + my ($name, $address) = parse_email($email); - my $tmp_email = format_email($name, $address, $email_usename); - push_email_address($tmp_email, ''); - add_role($tmp_email, 'in file'); + my $tmp_email = format_email($name, $address, $email_usename); + push_email_address($tmp_email, ''); + add_role($tmp_email, 'in file'); + } } -} - -if ($email || $email_list) { my @to = (); - if ($email) { - if ($interactive) { - @email_to = @{vcs_interactive_menu(\@email_to)}; + if ($email || $email_list) { + if ($email) { + @to = (@to, @email_to); + } + if ($email_list) { + @to = (@to, @list_to); } - @to = (@to, @email_to); - } - if ($email_list) { - @to = (@to, @list_to); } - output(merge_email(@to)); -} -if ($scm) { - @scm = uniq(@scm); - output(@scm); -} -if ($status) { - @status = uniq(@status); - output(@status); -} + @to = interactive_get_maintainer(\@to) if ($interactive); -if ($subsystem) { - @subsystem = uniq(@subsystem); - output(@subsystem); + return @to; } -if ($web) { - @web = uniq(@web); - output(@web); -} - -exit($exit); - sub file_match_pattern { my ($file, $pattern) = @_; if (substr($pattern, -1) eq "/") { @@ -561,7 +613,7 @@ 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) + or use only ${signature_pattern} signers (default: $email_git_all_signature_types) --git-fallback => use git when no exact MAINTAINERS pattern (default: $email_git_fallback) --git-chief-penguins => include ${penguin_chiefs} --git-min-signatures => number of signatures required (default: $email_git_min_signatures) @@ -847,11 +899,19 @@ sub add_categories { } if ($list_additional =~ m/subscribers-only/) { if ($email_subscriber_list) { - push(@list_to, [$list_address, "subscriber list${list_role}"]); + if (!$hash_list_to{$list_address}) { + $hash_list_to{$list_address} = 1; + push(@list_to, [$list_address, + "subscriber list${list_role}"]); + } } } else { if ($email_list) { - push(@list_to, [$list_address, "open list${list_role}"]); + if (!$hash_list_to{$list_address}) { + $hash_list_to{$list_address} = 1; + push(@list_to, [$list_address, + "open list${list_role}"]); + } } } } elsif ($ptype eq "M") { @@ -882,9 +942,6 @@ sub add_categories { } } -my %email_hash_name; -my %email_hash_address; - sub email_inuse { my ($name, $address) = @_; @@ -1037,10 +1094,31 @@ sub hg_execute_cmd { return @lines; } +sub extract_formatted_signatures { + my (@signature_lines) = @_; + + my @type = @signature_lines; + + s/\s*(.*):.*/$1/ for (@type); + + # cut -f2- -d":" + s/\s*.*:\s*(.+)\s*/$1/ for (@signature_lines); + +## Reformat email addresses (with names) to avoid badly written signatures + + foreach my $signer (@signature_lines) { + my ($name, $address) = parse_email($signer); + $signer = format_email($name, $address, 1); + } + + return (\@type, \@signature_lines); +} + sub vcs_find_signers { my ($cmd) = @_; - my @lines = (); my $commits; + my @lines = (); + my @signatures = (); @lines = &{$VCS_cmds{"execute_cmd"}}($cmd); @@ -1048,24 +1126,20 @@ sub vcs_find_signers { $commits = grep(/$pattern/, @lines); # of commits - @lines = grep(/^[ \t]*${signaturePattern}.*\@.*$/, @lines); - if (!$email_git_penguin_chiefs) { - @lines = grep(!/${penguin_chiefs}/i, @lines); - } + @signatures = grep(/^[ \t]*${signature_pattern}.*\@.*$/, @lines); - return (0, @lines) if !@lines; + return (0, @signatures) if !@signatures; - # cut -f2- -d":" - s/.*:\s*(.+)\s*/$1/ for (@lines); + save_commits_by_author(@lines) if ($interactive); + save_commits_by_signer(@lines) if ($interactive); -## Reformat email addresses (with names) to avoid badly written signatures - - foreach my $line (@lines) { - my ($name, $address) = parse_email($line); - $line = format_email($name, $address, 1); + if (!$email_git_penguin_chiefs) { + @signatures = grep(!/${penguin_chiefs}/i, @signatures); } - return ($commits, @lines); + my ($types_ref, $signers_ref) = extract_formatted_signatures(@signatures); + + return ($commits, @$signers_ref); } sub vcs_find_author { @@ -1080,14 +1154,20 @@ sub vcs_find_author { return @lines if !@lines; -## Reformat email addresses (with names) to avoid badly written signatures - + my @authors = (); foreach my $line (@lines) { - my ($name, $address) = parse_email($line); - $line = format_email($name, $address, 1); + if ($line =~ m/$VCS_cmds{"author_pattern"}/) { + my $author = $1; + my ($name, $address) = parse_email($author); + $author = format_email($name, $address, 1); + push(@authors, $author); + } } - return @lines; + save_commits_by_author(@lines) if ($interactive); + save_commits_by_signer(@lines) if ($interactive); + + return @authors; } sub vcs_save_commits { @@ -1159,7 +1239,7 @@ sub vcs_exists { %VCS_cmds = %VCS_cmds_git; return 1 if eval $VCS_cmds{"available"}; %VCS_cmds = %VCS_cmds_hg; - return 1 if eval $VCS_cmds{"available"}; + return 2 if eval $VCS_cmds{"available"}; %VCS_cmds = (); if (!$printed_novcs) { warn("$P: No supported VCS found. Add --nogit to options?\n"); @@ -1171,125 +1251,309 @@ sub vcs_exists { return 0; } -sub vcs_interactive_menu { - my $list_ref = shift; +sub vcs_is_git { + return $vcs_used == 1; +} + +sub vcs_is_hg { + return $vcs_used == 2; +} + +sub interactive_get_maintainer { + my ($list_ref) = @_; my @list = @$list_ref; - return if (!vcs_exists()); + vcs_exists(); my %selected; - my %shortlog; - my $input; + my %authored; + my %signed; my $count = 0; #select maintainers by default foreach my $entry (@list){ - my $role = $entry->[1]; - $selected{$count} = ($role =~ /maintainer:|supporter:/); - $count++; + my $role = $entry->[1]; + $selected{$count} = ($role =~ /^(maintainer|supporter|open list)/); + $authored{$count} = 0; + $signed{$count} = 0; + $count++; } #menu loop - do { - my $count = 0; - foreach my $entry (@list){ - my $email = $entry->[0]; - my $role = $entry->[1]; - if ($selected{$count}){ - print STDERR "* "; - } else { - print STDERR " "; - } - print STDERR "$count: $email,\t\t $role"; - print STDERR "\n"; - if ($shortlog{$count}){ - my $entries_ref = vcs_get_shortlog($email); - foreach my $entry_ref (@{$entries_ref}){ - my $filename = @{$entry_ref}[0]; - my @shortlog = @{@{$entry_ref}[1]}; - print STDERR "\tshortlog for $filename (authored commits: " . @shortlog . ").\n"; - foreach my $commit (@shortlog){ - print STDERR "\t $commit\n"; + my $done = 0; + my $print_options = 0; + my $redraw = 1; + while (!$done) { + $count = 0; + if ($redraw) { + printf STDERR "\n%1s %2s %-65sauth sign\n", + "*", "#", "email/list and role:stats"; + foreach my $entry (@list) { + my $email = $entry->[0]; + my $role = $entry->[1]; + my $sel = ""; + $sel = "*" if ($selected{$count}); + my $commit_author = $commit_author_hash{$email}; + my $commit_signer = $commit_signer_hash{$email}; + my $authored = 0; + my $signed = 0; + $authored++ for (@{$commit_author}); + $signed++ for (@{$commit_signer}); + printf STDERR "%1s %2d %-65s", $sel, $count + 1, $email; + printf STDERR "%4d %4d", $authored, $signed + if ($authored > 0 || $signed > 0); + printf STDERR "\n %s\n", $role; + if ($authored{$count}) { + my $commit_author = $commit_author_hash{$email}; + foreach my $ref (@{$commit_author}) { + print STDERR " Author: @{$ref}[1]\n"; } - print STDERR "\n"; } + if ($signed{$count}) { + my $commit_signer = $commit_signer_hash{$email}; + foreach my $ref (@{$commit_signer}) { + print STDERR " @{$ref}[2]: @{$ref}[1]\n"; + } + } + + $count++; } - $count++; } - print STDERR "\n"; - print STDERR "Choose whom to cc by entering a commaseperated list of numbers and hitting enter.\n"; - print STDERR "To show a short list of commits, precede the number by a '?',\n"; - print STDERR "A blank line indicates that you are satisfied with your choice.\n"; - $input = ; + my $date_ref = \$email_git_since; + $date_ref = \$email_hg_since if (vcs_is_hg()); + if ($print_options) { + $print_options = 0; + if (vcs_exists()) { + print STDERR +"\nVersion Control options:\n" . +"g use git history [$email_git]\n" . +"gf use git-fallback [$email_git_fallback]\n" . +"b use git blame [$email_git_blame]\n" . +"bs use blame signatures [$email_git_blame_signatures]\n" . +"c# minimum commits [$email_git_min_signatures]\n" . +"%# min percent [$email_git_min_percent]\n" . +"d# history to use [$$date_ref]\n" . +"x# max maintainers [$email_git_max_maintainers]\n" . +"t all signature types [$email_git_all_signature_types]\n"; + } + print STDERR "\nAdditional options:\n" . +"0 toggle all\n" . +"f emails in file [$file_emails]\n" . +"k keywords in file [$keywords]\n" . +"r remove duplicates [$email_remove_duplicates]\n" . +"p# pattern match depth [$pattern_depth]\n"; + } + print STDERR +"\n#(toggle), A#(author), S#(signed) *(all), ^(none), O(options), Y(approve): "; + + my $input = ; chomp($input); - my @wish = split(/[, ]+/,$input); - foreach my $nr (@wish){ - my $logtoggle = 0; - if ($nr =~ /\?/){ - $nr =~ s/\?//; - $logtoggle = 1; + $redraw = 1; + my $rerun = 0; + my @wish = split(/[, ]+/, $input); + foreach my $nr (@wish) { + $nr = lc($nr); + my $sel = substr($nr, 0, 1); + my $str = substr($nr, 1); + my $val = 0; + $val = $1 if $str =~ /^(\d+)$/; + + if ($sel eq "y") { + $interactive = 0; + $done = 1; + $output_rolestats = 0; + $output_roles = 0; + last; + } elsif ($nr =~ /^\d+$/ && $nr > 0 && $nr <= $count) { + $selected{$nr - 1} = !$selected{$nr - 1}; + } elsif ($sel eq "*" || $sel eq '^') { + my $toggle = 0; + $toggle = 1 if ($sel eq '*'); + for (my $i = 0; $i < $count; $i++) { + $selected{$i} = $toggle; } - - #skip out of bounds numbers - next unless ($nr <= $count && $nr >= 0); - - if ($logtoggle){ - $shortlog{$nr} = !$shortlog{$nr}; + } elsif ($sel eq "0") { + for (my $i = 0; $i < $count; $i++) { + $selected{$i} = !$selected{$i}; + } + } elsif ($sel eq "a") { + if ($val > 0 && $val <= $count) { + $authored{$val - 1} = !$authored{$val - 1}; + } elsif ($str eq '*' || $str eq '^') { + my $toggle = 0; + $toggle = 1 if ($str eq '*'); + for (my $i = 0; $i < $count; $i++) { + $authored{$i} = $toggle; + } + } + } elsif ($sel eq "s") { + if ($val > 0 && $val <= $count) { + $signed{$val - 1} = !$signed{$val - 1}; + } elsif ($str eq '*' || $str eq '^') { + my $toggle = 0; + $toggle = 1 if ($str eq '*'); + for (my $i = 0; $i < $count; $i++) { + $signed{$i} = $toggle; + } + } + } elsif ($sel eq "o") { + $print_options = 1; + $redraw = 1; + } elsif ($sel eq "g") { + if ($str eq "f") { + bool_invert(\$email_git_fallback); } else { - $selected{$nr} = !$selected{$nr}; - - #switch shortlog on if an entry get's selected - if ($selected{$nr}){ - $shortlog{$nr}=1; - } + bool_invert(\$email_git); + } + $rerun = 1; + } elsif ($sel eq "b") { + if ($str eq "s") { + bool_invert(\$email_git_blame_signatures); + } else { + bool_invert(\$email_git_blame); + } + $rerun = 1; + } elsif ($sel eq "c") { + if ($val > 0) { + $email_git_min_signatures = $val; + $rerun = 1; + } + } elsif ($sel eq "x") { + if ($val > 0) { + $email_git_max_maintainers = $val; + $rerun = 1; + } + } elsif ($sel eq "%") { + if ($str ne "" && $val >= 0) { + $email_git_min_percent = $val; + $rerun = 1; } - }; - } while(length($input) > 0); + } elsif ($sel eq "d") { + if (vcs_is_git()) { + $email_git_since = $str; + } elsif (vcs_is_hg()) { + $email_hg_since = $str; + } + $rerun = 1; + } elsif ($sel eq "t") { + bool_invert(\$email_git_all_signature_types); + $rerun = 1; + } elsif ($sel eq "f") { + bool_invert(\$file_emails); + $rerun = 1; + } elsif ($sel eq "r") { + bool_invert(\$email_remove_duplicates); + $rerun = 1; + } elsif ($sel eq "k") { + bool_invert(\$keywords); + $rerun = 1; + } elsif ($sel eq "p") { + if ($str ne "" && $val >= 0) { + $pattern_depth = $val; + $rerun = 1; + } + } else { + print STDERR "invalid option: '$nr'\n"; + $redraw = 0; + } + } + if ($rerun) { + print STDERR "git-blame can be very slow, please have patience..." + if ($email_git_blame); + goto &get_maintainer; + } + } #drop not selected entries $count = 0; - my @new_emailto; - foreach my $entry (@list){ - if ($selected{$count}){ - push(@new_emailto,$list[$count]); - print STDERR "$count: "; - print STDERR $email_to[$count]->[0]; - print STDERR ",\t\t "; - print STDERR $email_to[$count]->[1]; - print STDERR "\n"; + my @new_emailto = (); + foreach my $entry (@list) { + if ($selected{$count}) { + push(@new_emailto, $list[$count]); } $count++; } - return \@new_emailto; + return @new_emailto; } -sub vcs_get_shortlog { - my $arg = shift; - my ($name, $address) = parse_email($arg); - return $shortlog_buffer{$address}; +sub bool_invert { + my ($bool_ref) = @_; + + if ($$bool_ref) { + $$bool_ref = 0; + } else { + $$bool_ref = 1; + } } -sub vcs_file_shortlogs { - my ($file) = @_; - print STDERR "shortlog processing $file:"; - foreach my $entry (@email_to){ - my ($name, $address) = parse_email($entry->[0]); - print STDERR "."; - my $commits_ref = vcs_email_shortlog($address, $file); - push(@{$shortlog_buffer{$address}}, [ $file, $commits_ref ]); +sub save_commits_by_author { + my (@lines) = @_; + + my @authors = (); + my @commits = (); + my @subjects = (); + + foreach my $line (@lines) { + if ($line =~ m/$VCS_cmds{"author_pattern"}/) { + my $author = $1; + my ($name, $address) = parse_email($author); + $author = format_email($name, $address, 1); + push(@authors, $author); + } + push(@commits, $1) if ($line =~ m/$VCS_cmds{"commit_pattern"}/); + push(@subjects, $1) if ($line =~ m/$VCS_cmds{"subject_pattern"}/); + } + + for (my $i = 0; $i < @authors; $i++) { + my $exists = 0; + foreach my $ref(@{$commit_author_hash{$authors[$i]}}) { + if (@{$ref}[0] eq $commits[$i] && + @{$ref}[1] eq $subjects[$i]) { + $exists = 1; + last; + } + } + if (!$exists) { + push(@{$commit_author_hash{$authors[$i]}}, + [ ($commits[$i], $subjects[$i]) ]); + } } - print STDERR "\n"; } -sub vcs_email_shortlog { - my $email = shift; - my ($file) = @_; +sub save_commits_by_signer { + my (@lines) = @_; + + my $commit = ""; + my $subject = ""; - my $cmd = $VCS_cmds{"shortlog_cmd"}; - $cmd =~ s/(\$\w+)/$1/eeg; #substitute variables - my @lines = &{$VCS_cmds{"execute_cmd"}}($cmd); - return \@lines; + foreach my $line (@lines) { + $commit = $1 if ($line =~ m/$VCS_cmds{"commit_pattern"}/); + $subject = $1 if ($line =~ m/$VCS_cmds{"subject_pattern"}/); + if ($line =~ /^[ \t]*${signature_pattern}.*\@.*$/) { + my @signatures = ($line); + my ($types_ref, $signers_ref) = extract_formatted_signatures(@signatures); + my @types = @$types_ref; + my @signers = @$signers_ref; + + my $type = $types[0]; + my $signer = $signers[0]; + + my $exists = 0; + foreach my $ref(@{$commit_signer_hash{$signer}}) { + if (@{$ref}[0] eq $commit && + @{$ref}[1] eq $subject && + @{$ref}[2] eq $type) { + $exists = 1; + last; + } + } + if (!$exists) { + push(@{$commit_signer_hash{$signer}}, + [ ($commit, $subject, $type) ]); + } + } + } } sub vcs_assign { @@ -1342,7 +1606,8 @@ sub vcs_file_signoffs { my @signers = (); my $commits; - return if (!vcs_exists()); + $vcs_used = vcs_exists(); + return if (!$vcs_used); my $cmd = $VCS_cmds{"find_signers_cmd"}; $cmd =~ s/(\$\w+)/$1/eeg; # interpolate $cmd @@ -1360,37 +1625,93 @@ sub vcs_file_blame { my $total_commits; my $total_lines; - return if (!vcs_exists()); + $vcs_used = vcs_exists(); + return if (!$vcs_used); @all_commits = vcs_blame($file); @commits = uniq(@all_commits); $total_commits = @commits; $total_lines = @all_commits; - foreach my $commit (@commits) { - my $commit_count; - my @commit_signers = (); + if ($email_git_blame_signatures) { + if (vcs_is_hg()) { + my $commit_count; + my @commit_signers = (); + my $commit = join(" -r ", @commits); + my $cmd; - my $cmd = $VCS_cmds{"find_commit_signers_cmd"}; - $cmd =~ s/(\$\w+)/$1/eeg; #substitute variables in $cmd + $cmd = $VCS_cmds{"find_commit_signers_cmd"}; + $cmd =~ s/(\$\w+)/$1/eeg; #substitute variables in $cmd - ($commit_count, @commit_signers) = vcs_find_signers($cmd); + ($commit_count, @commit_signers) = vcs_find_signers($cmd); - push(@signers, @commit_signers); + push(@signers, @commit_signers); + } else { + foreach my $commit (@commits) { + my $commit_count; + 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) = vcs_find_signers($cmd); + + push(@signers, @commit_signers); + } + } } if ($from_filename) { if ($output_rolestats) { my @blame_signers; - foreach my $commit (@commits) { - my $i; - my $cmd = $VCS_cmds{"find_commit_author_cmd"}; - $cmd =~ s/(\$\w+)/$1/eeg; #interpolate $cmd - my @author = vcs_find_author($cmd); - next if !@author; - my $count = grep(/$commit/, @all_commits); - for ($i = 0; $i < $count ; $i++) { - push(@blame_signers, $author[0]); + if (vcs_is_hg()) {{ # Double brace for last exit + my $commit_count; + my @commit_signers = (); + @commits = uniq(@commits); + @commits = sort(@commits); + my $commit = join(" -r ", @commits); + my $cmd; + + $cmd = $VCS_cmds{"find_commit_author_cmd"}; + $cmd =~ s/(\$\w+)/$1/eeg; #substitute variables in $cmd + + my @lines = (); + + @lines = &{$VCS_cmds{"execute_cmd"}}($cmd); + + if (!$email_git_penguin_chiefs) { + @lines = grep(!/${penguin_chiefs}/i, @lines); + } + + last if !@lines; + + my @authors = (); + foreach my $line (@lines) { + if ($line =~ m/$VCS_cmds{"author_pattern"}/) { + my $author = $1; + my ($name, $address) = parse_email($author); + $author = format_email($name, $address, 1); + push(@authors, $1); + } + } + + save_commits_by_author(@lines) if ($interactive); + save_commits_by_signer(@lines) if ($interactive); + + push(@signers, @authors); + }} + else { + foreach my $commit (@commits) { + my $i; + my $cmd = $VCS_cmds{"find_commit_author_cmd"}; + $cmd =~ s/(\$\w+)/$1/eeg; #interpolate $cmd + my @author = vcs_find_author($cmd); + next if !@author; + my $count = grep(/$commit/, @all_commits); + for ($i = 0; $i < $count ; $i++) { + push(@blame_signers, $author[0]); + } } } if (@blame_signers) { -- cgit v1.2.3-70-g09d2 From 6ef1c52e122b675acc88a8b016d6477f67988b91 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Tue, 26 Oct 2010 14:22:56 -0700 Subject: scripts/get_maintainer.pl: use case insensitive name de-duplication Case insensitive name and email address matching can help reduce duplication when authors don't always use the exact same signature. o Add a --interactive per-file exact_match hash so git history can be checked on per-file only when there is no direct maintainer o Make @interactive_to list global so save_commits_by_ can check email names & addresses against this list for duplication o Don't allow --interactive and --sections o rename subroutine get_maintainer to get_maintainers o Added help text option to --interactive menu prompt Update version to 0.26-beta4 Signed-off-by: Joe Perches Cc: Florian Mickler Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- scripts/get_maintainer.pl | 135 ++++++++++++++++++++++++++++++++++------------ 1 file changed, 101 insertions(+), 34 deletions(-) (limited to 'scripts') diff --git a/scripts/get_maintainer.pl b/scripts/get_maintainer.pl index f51176039ff..61d3bb51bdd 100755 --- a/scripts/get_maintainer.pl +++ b/scripts/get_maintainer.pl @@ -13,7 +13,7 @@ use strict; my $P = $0; -my $V = '0.26-beta3'; +my $V = '0.26-beta4'; use Getopt::Long qw(:config no_auto_abbrev); @@ -242,6 +242,7 @@ if ($sections) { $subsystem = 0; $web = 0; $keywords = 0; + $interactive = 0; } else { my $selections = $email + $scm + $status + $subsystem + $web; if ($selections == 0) { @@ -407,13 +408,15 @@ my @scm = (); my @web = (); my @subsystem = (); my @status = (); +my @interactive_to = (); my $signature_pattern; -my @to = get_maintainer(); +my @maintainers = get_maintainers(); -@to = merge_email(@to); - -output(@to) if (@to); +if (@maintainers) { + @maintainers = merge_email(@maintainers); + output(@maintainers); +} if ($scm) { @scm = uniq(@scm); @@ -437,7 +440,7 @@ if ($web) { exit($exit); -sub get_maintainer { +sub get_maintainers { %email_hash_name = (); %email_hash_address = (); %commit_author_hash = (); @@ -449,7 +452,7 @@ sub get_maintainer { @web = (); @subsystem = (); @status = (); - + @interactive_to = (); if ($email_git_all_signature_types) { $signature_pattern = "(.+?)[Bb][Yy]:"; } else { @@ -458,10 +461,11 @@ sub get_maintainer { # Find responsible parties + my %exact_pattern_match_hash; + foreach my $file (@files) { my %hash; - my $exact_pattern_match = 0; my $tvi = find_first_section(); while ($tvi < @typevalue) { my $start = find_starting_index($tvi); @@ -497,7 +501,9 @@ sub get_maintainer { my $file_pd = ($file =~ tr@/@@); $value_pd++ if (substr($value,-1,1) ne "/"); $value_pd = -1 if ($value =~ /^\.\*/); - $exact_pattern_match = 1 if ($value_pd >= $file_pd); + if ($value_pd >= $file_pd) { + $exact_pattern_match_hash{$file} = 1; + } if ($pattern_depth == 0 || (($file_pd - $value_pd) < $pattern_depth)) { $hash{$tvi} = $value_pd; @@ -530,14 +536,6 @@ sub get_maintainer { print("\n"); } } - - if ($email && ($email_git || - ($email_git_fallback && !$exact_pattern_match))) { - vcs_file_signoffs($file); - } - if ($email && $email_git_blame) { - vcs_file_blame($file); - } } if ($keywords) { @@ -547,6 +545,19 @@ sub get_maintainer { } } + @interactive_to = (@email_to, @list_to); + + foreach my $file (@files) { + if ($email && + ($email_git || ($email_git_fallback && + !$exact_pattern_match_hash{$file}))) { + vcs_file_signoffs($file); + } + if ($email && $email_git_blame) { + vcs_file_blame($file); + } + } + if ($email) { foreach my $chief (@penguin_chief) { if ($chief =~ m/^(.*):(.*)/) { @@ -580,7 +591,10 @@ sub get_maintainer { } } - @to = interactive_get_maintainer(\@to) if ($interactive); + if ($interactive) { + @interactive_to = @to; + @to = interactive_get_maintainers(\@interactive_to); + } return @to; } @@ -899,16 +913,16 @@ sub add_categories { } if ($list_additional =~ m/subscribers-only/) { if ($email_subscriber_list) { - if (!$hash_list_to{$list_address}) { - $hash_list_to{$list_address} = 1; + if (!$hash_list_to{lc($list_address)}) { + $hash_list_to{lc($list_address)} = 1; push(@list_to, [$list_address, "subscriber list${list_role}"]); } } } else { if ($email_list) { - if (!$hash_list_to{$list_address}) { - $hash_list_to{$list_address} = 1; + if (!$hash_list_to{lc($list_address)}) { + $hash_list_to{lc($list_address)} = 1; push(@list_to, [$list_address, "open list${list_role}"]); } @@ -946,8 +960,8 @@ sub email_inuse { my ($name, $address) = @_; return 1 if (($name eq "") && ($address eq "")); - return 1 if (($name ne "") && exists($email_hash_name{$name})); - return 1 if (($address ne "") && exists($email_hash_address{$address})); + return 1 if (($name ne "") && exists($email_hash_name{lc($name)})); + return 1 if (($address ne "") && exists($email_hash_address{lc($address)})); return 0; } @@ -965,8 +979,8 @@ sub push_email_address { push(@email_to, [format_email($name, $address, $email_usename), $role]); } elsif (!email_inuse($name, $address)) { push(@email_to, [format_email($name, $address, $email_usename), $role]); - $email_hash_name{$name}++; - $email_hash_address{$address}++; + $email_hash_name{lc($name)}++; + $email_hash_address{lc($address)}++; } return 1; @@ -1259,7 +1273,7 @@ sub vcs_is_hg { return $vcs_used == 2; } -sub interactive_get_maintainer { +sub interactive_get_maintainers { my ($list_ref) = @_; my @list = @$list_ref; @@ -1269,11 +1283,12 @@ sub interactive_get_maintainer { my %authored; my %signed; my $count = 0; - + my $maintained = 0; #select maintainers by default - foreach my $entry (@list){ + foreach my $entry (@list) { my $role = $entry->[1]; - $selected{$count} = ($role =~ /^(maintainer|supporter|open list)/); + $selected{$count} = ($role =~ /^(maintainer|supporter|open list)/i); + $maintained = 1 if ($role =~ /^(maintainer|supporter)/i); $authored{$count} = 0; $signed{$count} = 0; $count++; @@ -1286,8 +1301,14 @@ sub interactive_get_maintainer { while (!$done) { $count = 0; if ($redraw) { - printf STDERR "\n%1s %2s %-65sauth sign\n", - "*", "#", "email/list and role:stats"; + printf STDERR "\n%1s %2s %-65s", + "*", "#", "email/list and role:stats"; + if ($email_git || + ($email_git_fallback && !$maintained) || + $email_git_blame) { + print STDERR "auth sign"; + } + print STDERR "\n"; foreach my $entry (@list) { my $email = $entry->[0]; my $role = $entry->[1]; @@ -1453,6 +1474,27 @@ sub interactive_get_maintainer { $pattern_depth = $val; $rerun = 1; } + } elsif ($sel eq "h" || $sel eq "?") { + print STDERR <[0]); + if ($email_remove_duplicates && + ((lc($name) eq lc($to_name)) || + (lc($address) eq lc($to_address)))) { + $author = $to->[0]; + $matched = 1; + last; + } + } + $author = format_email($name, $address, 1) if (!$matched); push(@authors, $author); } push(@commits, $1) if ($line =~ m/$VCS_cmds{"commit_pattern"}/); @@ -1539,6 +1592,20 @@ sub save_commits_by_signer { my $type = $types[0]; my $signer = $signers[0]; + my $matched = 0; + my ($name, $address) = parse_email($signer); + foreach my $to (@interactive_to) { + my ($to_name, $to_address) = parse_email($to->[0]); + if ($email_remove_duplicates && + ((lc($name) eq lc($to_name)) || + (lc($address) eq lc($to_address)))) { + $signer = $to->[0]; + $matched = 1; + last; + } + $signer = format_email($name, $address, 1) if (!$matched); + } + my $exists = 0; foreach my $ref(@{$commit_signer_hash{$signer}}) { if (@{$ref}[0] eq $commit && -- cgit v1.2.3-70-g09d2 From 7fa8ff2e0c0f326cdaaa4ae7d00f5d021e43ffa2 Mon Sep 17 00:00:00 2001 From: Florian Mickler Date: Tue, 26 Oct 2010 14:22:56 -0700 Subject: scripts/get_maintainer.pl: fix mailmap handling Implement it, like it is described in git-shortlog. Signed-off-by: Florian Mickler Signed-off-by: Joe Perches Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- scripts/get_maintainer.pl | 147 ++++++++++++++++++++++++++++++++++------------ 1 file changed, 109 insertions(+), 38 deletions(-) (limited to 'scripts') diff --git a/scripts/get_maintainer.pl b/scripts/get_maintainer.pl index 61d3bb51bdd..faeace4e1fd 100755 --- a/scripts/get_maintainer.pl +++ b/scripts/get_maintainer.pl @@ -295,31 +295,76 @@ while (<$maint>) { } close($maint); -my %mailmap; -if ($email_remove_duplicates) { - open(my $mailmap, '<', "${lk_path}.mailmap") +# +# Read mail address map +# + +my $mailmap = read_mailmap(); + +sub read_mailmap { + my $mailmap = { + names => {}, + addresses => {} + }; + + if (!$email_remove_duplicates) { + return $mailmap; + } + + open(my $mailmap_file, '<', "${lk_path}.mailmap") or warn "$P: Can't open .mailmap: $!\n"; - while (<$mailmap>) { - my $line = $_; - next if ($line =~ m/^\s*#/); - next if ($line =~ m/^\s*$/); + while (<$mailmap_file>) { + s/#.*$//; #strip comments + s/^\s+|\s+$//g; #trim - my ($name, $address) = parse_email($line); - $line = format_email($name, $address, $email_usename); + next if (/^\s*$/); #skip empty lines + #entries have one of the following formats: + # name1 + # + # name1 + # name1 name2 + # (see man git-shortlog) + if (/^(.+)<(.+)>$/) { + my $real_name = $1; + my $address = $2; - next if ($line =~ m/^\s*$/); + $real_name =~ s/\s+$//; + $mailmap->{names}->{$address} = $real_name; - if (exists($mailmap{$name})) { - my $obj = $mailmap{$name}; - push(@$obj, $address); - } else { - my @arr = ($address); - $mailmap{$name} = \@arr; + } elsif (/^<([^\s]+)>\s*<([^\s]+)>$/) { + my $real_address = $1; + my $wrong_address = $2; + + $mailmap->{addresses}->{$wrong_address} = $real_address; + + } elsif (/^(.+)<([^\s]+)>\s*<([^\s]+)>$/) { + my $real_name= $1; + my $real_address = $2; + my $wrong_address = $3; + + $real_name =~ s/\s+$//; + + $mailmap->{names}->{$wrong_address} = $real_name; + $mailmap->{addresses}->{$wrong_address} = $real_address; + + } elsif (/^(.+)<([^\s]+)>\s*([^\s].*)<([^\s]+)>$/) { + my $real_name = $1; + my $real_address = $2; + my $wrong_name = $3; + my $wrong_address = $4; + + $real_name =~ s/\s+$//; + $wrong_name =~ s/\s+$//; + + $mailmap->{names}->{format_email($wrong_name,$wrong_address,1)} = $real_name; + $mailmap->{addresses}->{format_email($wrong_name,$wrong_address,1)} = $real_address; } } - close($mailmap); + close($mailmap_file); + + return $mailmap; } ## use the filenames on the command line or find the filenames in the patchfiles @@ -1061,30 +1106,58 @@ sub which_conf { return ""; } -sub mailmap { - my (@lines) = @_; - my %hash; +sub mailmap_email { + my $line = shift; - foreach my $line (@lines) { my ($name, $address) = parse_email($line); - if (!exists($hash{$name})) { - $hash{$name} = $address; - } elsif ($address ne $hash{$name}) { - $address = $hash{$name}; - $line = format_email($name, $address, $email_usename); - } - if (exists($mailmap{$name})) { - my $obj = $mailmap{$name}; - foreach my $map_address (@$obj) { - if (($map_address eq $address) && - ($map_address ne $hash{$name})) { - $line = format_email($name, $hash{$name}, $email_usename); + my $email = format_email($name, $address, 1); + my $real_name = $name; + my $real_address = $address; + + if (exists $mailmap->{names}->{$email} || exists $mailmap->{addresses}->{$email}) { + if (exists $mailmap->{names}->{$email}) { + $real_name = $mailmap->{names}->{$email}; + } + if (exists $mailmap->{addresses}->{$email}) { + $real_address = $mailmap->{addresses}->{$email}; + } + } else { + if (exists $mailmap->{names}->{$address}) { + $real_name = $mailmap->{names}->{$address}; + } + if (exists $mailmap->{addresses}->{$address}) { + $real_address = $mailmap->{addresses}->{$address}; } - } } + return format_email($real_name, $real_address, 1); +} + +sub mailmap { + my (@addresses) = @_; + + my @ret = (); + foreach my $line (@addresses) { + push(@ret, mailmap_email($line), 1); } - return @lines; + merge_by_realname(@ret) if $email_remove_duplicates; + + return @ret; +} + +sub merge_by_realname { + my %address_map; + my (@emails) = @_; + foreach my $email (@emails) { + my ($name, $address) = parse_email($email); + if (!exists $address_map{$name}) { + $address_map{$name} = $address; + } else { + $address = $address_map{$name}; + $email = format_email($name,$address,1); + } + } + } sub git_execute_cmd { @@ -1636,9 +1709,7 @@ sub vcs_assign { $divisor = 1; } - if ($email_remove_duplicates) { - @lines = mailmap(@lines); - } + @lines = mailmap(@lines); return if (@lines <= 0); -- cgit v1.2.3-70-g09d2 From 47abc7225761faf28be52b3ac4dc26ffeac7b750 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Tue, 26 Oct 2010 14:22:57 -0700 Subject: scripts/get_maintainer.pl: correct indentation in a few places And a miscellaneous conversion of You to you in a help message Signed-off-by: Joe Perches Cc: Florian Mickler Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- scripts/get_maintainer.pl | 156 +++++++++++++++++++++++----------------------- 1 file changed, 78 insertions(+), 78 deletions(-) (limited to 'scripts') diff --git a/scripts/get_maintainer.pl b/scripts/get_maintainer.pl index faeace4e1fd..0abfdbc5cdf 100755 --- a/scripts/get_maintainer.pl +++ b/scripts/get_maintainer.pl @@ -306,7 +306,7 @@ sub read_mailmap { my $mailmap = { names => {}, addresses => {} - }; + }; if (!$email_remove_duplicates) { return $mailmap; @@ -327,39 +327,39 @@ sub read_mailmap { # name1 name2 # (see man git-shortlog) if (/^(.+)<(.+)>$/) { - my $real_name = $1; - my $address = $2; + my $real_name = $1; + my $address = $2; - $real_name =~ s/\s+$//; - $mailmap->{names}->{$address} = $real_name; + $real_name =~ s/\s+$//; + $mailmap->{names}->{$address} = $real_name; } elsif (/^<([^\s]+)>\s*<([^\s]+)>$/) { - my $real_address = $1; - my $wrong_address = $2; + my $real_address = $1; + my $wrong_address = $2; - $mailmap->{addresses}->{$wrong_address} = $real_address; + $mailmap->{addresses}->{$wrong_address} = $real_address; } elsif (/^(.+)<([^\s]+)>\s*<([^\s]+)>$/) { - my $real_name= $1; - my $real_address = $2; - my $wrong_address = $3; + my $real_name= $1; + my $real_address = $2; + my $wrong_address = $3; - $real_name =~ s/\s+$//; + $real_name =~ s/\s+$//; - $mailmap->{names}->{$wrong_address} = $real_name; - $mailmap->{addresses}->{$wrong_address} = $real_address; + $mailmap->{names}->{$wrong_address} = $real_name; + $mailmap->{addresses}->{$wrong_address} = $real_address; } elsif (/^(.+)<([^\s]+)>\s*([^\s].*)<([^\s]+)>$/) { - my $real_name = $1; - my $real_address = $2; - my $wrong_name = $3; - my $wrong_address = $4; + my $real_name = $1; + my $real_address = $2; + my $wrong_name = $3; + my $wrong_address = $4; - $real_name =~ s/\s+$//; - $wrong_name =~ s/\s+$//; + $real_name =~ s/\s+$//; + $wrong_name =~ s/\s+$//; - $mailmap->{names}->{format_email($wrong_name,$wrong_address,1)} = $real_name; - $mailmap->{addresses}->{format_email($wrong_name,$wrong_address,1)} = $real_address; + $mailmap->{names}->{format_email($wrong_name,$wrong_address,1)} = $real_name; + $mailmap->{addresses}->{format_email($wrong_name,$wrong_address,1)} = $real_address; } } close($mailmap_file); @@ -743,30 +743,30 @@ EOT } sub top_of_kernel_tree { - my ($lk_path) = @_; + my ($lk_path) = @_; - if ($lk_path ne "" && substr($lk_path,length($lk_path)-1,1) ne "/") { - $lk_path .= "/"; - } - if ( (-f "${lk_path}COPYING") - && (-f "${lk_path}CREDITS") - && (-f "${lk_path}Kbuild") - && (-f "${lk_path}MAINTAINERS") - && (-f "${lk_path}Makefile") - && (-f "${lk_path}README") - && (-d "${lk_path}Documentation") - && (-d "${lk_path}arch") - && (-d "${lk_path}include") - && (-d "${lk_path}drivers") - && (-d "${lk_path}fs") - && (-d "${lk_path}init") - && (-d "${lk_path}ipc") - && (-d "${lk_path}kernel") - && (-d "${lk_path}lib") - && (-d "${lk_path}scripts")) { - return 1; - } - return 0; + if ($lk_path ne "" && substr($lk_path,length($lk_path)-1,1) ne "/") { + $lk_path .= "/"; + } + if ( (-f "${lk_path}COPYING") + && (-f "${lk_path}CREDITS") + && (-f "${lk_path}Kbuild") + && (-f "${lk_path}MAINTAINERS") + && (-f "${lk_path}Makefile") + && (-f "${lk_path}README") + && (-d "${lk_path}Documentation") + && (-d "${lk_path}arch") + && (-d "${lk_path}include") + && (-d "${lk_path}drivers") + && (-d "${lk_path}fs") + && (-d "${lk_path}init") + && (-d "${lk_path}ipc") + && (-d "${lk_path}kernel") + && (-d "${lk_path}lib") + && (-d "${lk_path}scripts")) { + return 1; + } + return 0; } sub parse_email { @@ -1107,29 +1107,30 @@ sub which_conf { } sub mailmap_email { - my $line = shift; + my $line = shift; - my ($name, $address) = parse_email($line); - my $email = format_email($name, $address, 1); - my $real_name = $name; - my $real_address = $address; - - if (exists $mailmap->{names}->{$email} || exists $mailmap->{addresses}->{$email}) { - if (exists $mailmap->{names}->{$email}) { - $real_name = $mailmap->{names}->{$email}; - } - if (exists $mailmap->{addresses}->{$email}) { - $real_address = $mailmap->{addresses}->{$email}; - } - } else { - if (exists $mailmap->{names}->{$address}) { - $real_name = $mailmap->{names}->{$address}; - } - if (exists $mailmap->{addresses}->{$address}) { - $real_address = $mailmap->{addresses}->{$address}; - } + my ($name, $address) = parse_email($line); + my $email = format_email($name, $address, 1); + my $real_name = $name; + my $real_address = $address; + + if (exists $mailmap->{names}->{$email} || + exists $mailmap->{addresses}->{$email}) { + if (exists $mailmap->{names}->{$email}) { + $real_name = $mailmap->{names}->{$email}; + } + if (exists $mailmap->{addresses}->{$email}) { + $real_address = $mailmap->{addresses}->{$email}; + } + } else { + if (exists $mailmap->{names}->{$address}) { + $real_name = $mailmap->{names}->{$address}; + } + if (exists $mailmap->{addresses}->{$address}) { + $real_address = $mailmap->{addresses}->{$address}; } - return format_email($real_name, $real_address, 1); + } + return format_email($real_name, $real_address, 1); } sub mailmap { @@ -1146,18 +1147,17 @@ sub mailmap { } sub merge_by_realname { - my %address_map; - my (@emails) = @_; - foreach my $email (@emails) { - my ($name, $address) = parse_email($email); - if (!exists $address_map{$name}) { - $address_map{$name} = $address; - } else { - $address = $address_map{$name}; - $email = format_email($name,$address,1); - } + my %address_map; + my (@emails) = @_; + foreach my $email (@emails) { + my ($name, $address) = parse_email($email); + if (!exists $address_map{$name}) { + $address_map{$name} = $address; + } else { + $address = $address_map{$name}; + $email = format_email($name,$address,1); } - + } } sub git_execute_cmd { @@ -1555,7 +1555,7 @@ commit signers and mailing lists that could be CC'd on a patch. Any *'d entry is selected. -If you have git or hg installed, You can choose to summarize the commit +If you have git or hg installed, you can choose to summarize the commit history of files in the patch. Also, each line of the current file can be matched to its commit author and that commits signers with blame. -- cgit v1.2.3-70-g09d2 From b9e2331dd1e0e04f7f2a6f8aa0c05bac2a7f0d7b Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Tue, 26 Oct 2010 14:22:58 -0700 Subject: scripts/get_maintainer.pl: use mailmap in name deduplication and other updates Use Florian Mickler's mailmap routine to reduce name duplication. o Add subroutine deduplicate_email to centralize code o Add hashes for deduplicate_(name|address)_hash o Remove now unused @interactive_to o Whitespace neatening o Add command line --help text o Add --mailmap command line option control o Interactive changes: - Add toggles for maintainer, git and list selections - Default selection is all - Add mailmap control Update to 0.26-beta5 Signed-off-by: Joe Perches Cc: Florian Mickler Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- scripts/get_maintainer.pl | 232 +++++++++++++++++++++++++++++----------------- 1 file changed, 148 insertions(+), 84 deletions(-) (limited to 'scripts') diff --git a/scripts/get_maintainer.pl b/scripts/get_maintainer.pl index 0abfdbc5cdf..e822518bc61 100755 --- a/scripts/get_maintainer.pl +++ b/scripts/get_maintainer.pl @@ -13,7 +13,7 @@ use strict; my $P = $0; -my $V = '0.26-beta4'; +my $V = '0.26-beta5'; use Getopt::Long qw(:config no_auto_abbrev); @@ -36,6 +36,7 @@ my $email_git_since = "1-year-ago"; my $email_hg_since = "-365"; my $interactive = 0; my $email_remove_duplicates = 1; +my $email_use_mailmap = 1; my $output_multiline = 1; my $output_separator = ", "; my $output_roles = 0; @@ -192,6 +193,7 @@ if (!GetOptions( 'hg-since=s' => \$email_hg_since, 'i|interactive!' => \$interactive, 'remove-duplicates!' => \$email_remove_duplicates, + 'mailmap!' => \$email_use_mailmap, 'm!' => \$email_maintainer, 'n!' => \$email_usename, 'l!' => \$email_list, @@ -300,17 +302,17 @@ close($maint); # Read mail address map # -my $mailmap = read_mailmap(); +my $mailmap; + +read_mailmap(); sub read_mailmap { - my $mailmap = { + $mailmap = { names => {}, addresses => {} }; - if (!$email_remove_duplicates) { - return $mailmap; - } + return if (!$email_use_mailmap || !(-f "${lk_path}.mailmap")); open(my $mailmap_file, '<', "${lk_path}.mailmap") or warn "$P: Can't open .mailmap: $!\n"; @@ -331,6 +333,7 @@ sub read_mailmap { my $address = $2; $real_name =~ s/\s+$//; + ($real_name, $address) = parse_email("$real_name <$address>"); $mailmap->{names}->{$address} = $real_name; } elsif (/^<([^\s]+)>\s*<([^\s]+)>$/) { @@ -340,12 +343,13 @@ sub read_mailmap { $mailmap->{addresses}->{$wrong_address} = $real_address; } elsif (/^(.+)<([^\s]+)>\s*<([^\s]+)>$/) { - my $real_name= $1; + my $real_name = $1; my $real_address = $2; my $wrong_address = $3; $real_name =~ s/\s+$//; - + ($real_name, $real_address) = + parse_email("$real_name <$real_address>"); $mailmap->{names}->{$wrong_address} = $real_name; $mailmap->{addresses}->{$wrong_address} = $real_address; @@ -356,15 +360,19 @@ sub read_mailmap { my $wrong_address = $4; $real_name =~ s/\s+$//; + ($real_name, $real_address) = + parse_email("$real_name <$real_address>"); + $wrong_name =~ s/\s+$//; + ($wrong_name, $wrong_address) = + parse_email("$wrong_name <$wrong_address>"); - $mailmap->{names}->{format_email($wrong_name,$wrong_address,1)} = $real_name; - $mailmap->{addresses}->{format_email($wrong_name,$wrong_address,1)} = $real_address; + my $wrong_email = format_email($wrong_name, $wrong_address, 1); + $mailmap->{names}->{$wrong_email} = $real_name; + $mailmap->{addresses}->{$wrong_email} = $real_address; } } close($mailmap_file); - - return $mailmap; } ## use the filenames on the command line or find the filenames in the patchfiles @@ -453,7 +461,8 @@ my @scm = (); my @web = (); my @subsystem = (); my @status = (); -my @interactive_to = (); +my %deduplicate_name_hash = (); +my %deduplicate_address_hash = (); my $signature_pattern; my @maintainers = get_maintainers(); @@ -497,7 +506,8 @@ sub get_maintainers { @web = (); @subsystem = (); @status = (); - @interactive_to = (); + %deduplicate_name_hash = (); + %deduplicate_address_hash = (); if ($email_git_all_signature_types) { $signature_pattern = "(.+?)[Bb][Yy]:"; } else { @@ -506,7 +516,7 @@ sub get_maintainers { # Find responsible parties - my %exact_pattern_match_hash; + my %exact_pattern_match_hash = (); foreach my $file (@files) { @@ -590,7 +600,9 @@ sub get_maintainers { } } - @interactive_to = (@email_to, @list_to); + foreach my $email (@email_to, @list_to) { + $email->[0] = deduplicate_email($email->[0]); + } foreach my $file (@files) { if ($email && @@ -637,8 +649,7 @@ sub get_maintainers { } if ($interactive) { - @interactive_to = @to; - @to = interactive_get_maintainers(\@interactive_to); + @to = interactive_get_maintainers(\@to); } return @to; @@ -702,8 +713,9 @@ Output type options: Other options: --pattern-depth => Number of pattern directory traversals (default: 0 (all)) - --keywords => scan patch for keywords (default: 1 (on)) - --sections => print the entire subsystem sections with pattern matches + --keywords => scan patch for keywords (default: $keywords) + --sections => print all of the subsystem sections with pattern matches + --mailmap => use .mailmap file (default: $email_use_mailmap) --version => show version --help => show this help information @@ -1107,7 +1119,7 @@ sub which_conf { } sub mailmap_email { - my $line = shift; + my ($line) = @_; my ($name, $address) = parse_email($line); my $email = format_email($name, $address, 1); @@ -1136,26 +1148,25 @@ sub mailmap_email { sub mailmap { my (@addresses) = @_; - my @ret = (); + my @mapped_emails = (); foreach my $line (@addresses) { - push(@ret, mailmap_email($line), 1); + push(@mapped_emails, mailmap_email($line)); } - - merge_by_realname(@ret) if $email_remove_duplicates; - - return @ret; + merge_by_realname(@mapped_emails) if ($email_use_mailmap); + return @mapped_emails; } sub merge_by_realname { my %address_map; my (@emails) = @_; + foreach my $email (@emails) { my ($name, $address) = parse_email($email); - if (!exists $address_map{$name}) { - $address_map{$name} = $address; - } else { + if (exists $address_map{$name}) { $address = $address_map{$name}; - $email = format_email($name,$address,1); + $email = format_email($name, $address, 1); + } else { + $address_map{$name} = $address; } } } @@ -1194,8 +1205,7 @@ sub extract_formatted_signatures { ## Reformat email addresses (with names) to avoid badly written signatures foreach my $signer (@signature_lines) { - my ($name, $address) = parse_email($signer); - $signer = format_email($name, $address, 1); + $signer = deduplicate_email($signer); } return (\@type, \@signature_lines); @@ -1339,6 +1349,7 @@ sub vcs_exists { } sub vcs_is_git { + vcs_exists(); return $vcs_used == 1; } @@ -1357,11 +1368,9 @@ sub interactive_get_maintainers { my %signed; my $count = 0; my $maintained = 0; - #select maintainers by default foreach my $entry (@list) { - my $role = $entry->[1]; - $selected{$count} = ($role =~ /^(maintainer|supporter|open list)/i); - $maintained = 1 if ($role =~ /^(maintainer|supporter)/i); + $maintained = 1 if ($entry->[1] =~ /^(maintainer|supporter)/i); + $selected{$count} = 1; $authored{$count} = 0; $signed{$count} = 0; $count++; @@ -1418,24 +1427,34 @@ sub interactive_get_maintainers { if ($print_options) { $print_options = 0; if (vcs_exists()) { - print STDERR -"\nVersion Control options:\n" . -"g use git history [$email_git]\n" . -"gf use git-fallback [$email_git_fallback]\n" . -"b use git blame [$email_git_blame]\n" . -"bs use blame signatures [$email_git_blame_signatures]\n" . -"c# minimum commits [$email_git_min_signatures]\n" . -"%# min percent [$email_git_min_percent]\n" . -"d# history to use [$$date_ref]\n" . -"x# max maintainers [$email_git_max_maintainers]\n" . -"t all signature types [$email_git_all_signature_types]\n"; + print STDERR <[1] =~ /^(maintainer|supporter)/i); + } + } elsif (lc($str) eq "g") { + for (my $i = 0; $i < $count; $i++) { + $selected{$i} = !$selected{$i} + if ($list[$i]->[1] =~ /^(author|commit|signer)/i); + } + } elsif (lc($str) eq "l") { + for (my $i = 0; $i < $count; $i++) { + $selected{$i} = !$selected{$i} + if ($list[$i]->[1] =~ /^(open list)/i); + } + } elsif (lc($str) eq "s") { + for (my $i = 0; $i < $count; $i++) { + $selected{$i} = !$selected{$i} + if ($list[$i]->[1] =~ /^(subscriber list)/i); + } + } } elsif ($sel eq "a") { if ($val > 0 && $val <= $count) { $authored{$val - 1} = !$authored{$val - 1}; @@ -1539,6 +1580,10 @@ sub interactive_get_maintainers { } elsif ($sel eq "r") { bool_invert(\$email_remove_duplicates); $rerun = 1; + } elsif ($sel eq "m") { + bool_invert(\$email_use_mailmap); + read_mailmap(); + $rerun = 1; } elsif ($sel eq "k") { bool_invert(\$keywords); $rerun = 1; @@ -1602,6 +1647,36 @@ sub bool_invert { } } +sub deduplicate_email { + my ($email) = @_; + + my $matched = 0; + my ($name, $address) = parse_email($email); + $email = format_email($name, $address, 1); + $email = mailmap_email($email); + + return $email if (!$email_remove_duplicates); + + ($name, $address) = parse_email($email); + + if ($deduplicate_name_hash{lc($name)}) { + $name = $deduplicate_name_hash{lc($name)}->[0]; + $address = $deduplicate_name_hash{lc($name)}->[1]; + $matched = 1; + } elsif ($deduplicate_address_hash{lc($address)}) { + $name = $deduplicate_address_hash{lc($address)}->[0]; + $address = $deduplicate_address_hash{lc($address)}->[1]; + $matched = 1; + } + if (!$matched) { + $deduplicate_name_hash{lc($name)} = [ $name, $address ]; + $deduplicate_address_hash{lc($address)} = [ $name, $address ]; + } + $email = format_email($name, $address, 1); + $email = mailmap_email($email); + return $email; +} + sub save_commits_by_author { my (@lines) = @_; @@ -1611,20 +1686,8 @@ sub save_commits_by_author { foreach my $line (@lines) { if ($line =~ m/$VCS_cmds{"author_pattern"}/) { - my $matched = 0; my $author = $1; - my ($name, $address) = parse_email($author); - foreach my $to (@interactive_to) { - my ($to_name, $to_address) = parse_email($to->[0]); - if ($email_remove_duplicates && - ((lc($name) eq lc($to_name)) || - (lc($address) eq lc($to_address)))) { - $author = $to->[0]; - $matched = 1; - last; - } - } - $author = format_email($name, $address, 1) if (!$matched); + $author = deduplicate_email($author); push(@authors, $author); } push(@commits, $1) if ($line =~ m/$VCS_cmds{"commit_pattern"}/); @@ -1665,19 +1728,7 @@ sub save_commits_by_signer { my $type = $types[0]; my $signer = $signers[0]; - my $matched = 0; - my ($name, $address) = parse_email($signer); - foreach my $to (@interactive_to) { - my ($to_name, $to_address) = parse_email($to->[0]); - if ($email_remove_duplicates && - ((lc($name) eq lc($to_name)) || - (lc($address) eq lc($to_address)))) { - $signer = $to->[0]; - $matched = 1; - last; - } - $signer = format_email($name, $address, 1) if (!$matched); - } + $signer = deduplicate_email($signer); my $exists = 0; foreach my $ref(@{$commit_signer_hash{$signer}}) { @@ -1751,6 +1802,11 @@ sub vcs_file_signoffs { $cmd =~ s/(\$\w+)/$1/eeg; # interpolate $cmd ($commits, @signers) = vcs_find_signers($cmd); + + foreach my $signer (@signers) { + $signer = deduplicate_email($signer); + } + vcs_assign("commit_signer", $commits, @signers); } @@ -1828,9 +1884,8 @@ sub vcs_file_blame { foreach my $line (@lines) { if ($line =~ m/$VCS_cmds{"author_pattern"}/) { my $author = $1; - my ($name, $address) = parse_email($author); - $author = format_email($name, $address, 1); - push(@authors, $1); + $author = deduplicate_email($author); + push(@authors, $author); } } @@ -1846,9 +1901,12 @@ sub vcs_file_blame { $cmd =~ s/(\$\w+)/$1/eeg; #interpolate $cmd my @author = vcs_find_author($cmd); next if !@author; + + my $formatted_author = deduplicate_email($author[0]); + my $count = grep(/$commit/, @all_commits); for ($i = 0; $i < $count ; $i++) { - push(@blame_signers, $author[0]); + push(@blame_signers, $formatted_author); } } } @@ -1856,8 +1914,14 @@ sub vcs_file_blame { vcs_assign("authored lines", $total_lines, @blame_signers); } } + foreach my $signer (@signers) { + $signer = deduplicate_email($signer); + } vcs_assign("commits", $total_commits, @signers); } else { + foreach my $signer (@signers) { + $signer = deduplicate_email($signer); + } vcs_assign("modified commits", $total_commits, @signers); } } -- cgit v1.2.3-70-g09d2 From fae99206769b6bbf8a20ab883726b164945771d7 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Tue, 26 Oct 2010 14:22:58 -0700 Subject: scripts/get_maintainer.pl: don't deduplicate unnamed addresses ie: mailing lists Fix a defect with the first mailing list address being used for each subsequent mailing list. Updated to 0.26-beta6. Signed-off-by: Joe Perches Cc: Florian Mickler Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- scripts/get_maintainer.pl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'scripts') diff --git a/scripts/get_maintainer.pl b/scripts/get_maintainer.pl index e822518bc61..d21ec3a8960 100755 --- a/scripts/get_maintainer.pl +++ b/scripts/get_maintainer.pl @@ -13,7 +13,7 @@ use strict; my $P = $0; -my $V = '0.26-beta5'; +my $V = '0.26-beta6'; use Getopt::Long qw(:config no_auto_abbrev); @@ -1036,7 +1036,7 @@ sub push_email_address { push(@email_to, [format_email($name, $address, $email_usename), $role]); } elsif (!email_inuse($name, $address)) { push(@email_to, [format_email($name, $address, $email_usename), $role]); - $email_hash_name{lc($name)}++; + $email_hash_name{lc($name)}++ if ($name ne ""); $email_hash_address{lc($address)}++; } @@ -1659,7 +1659,7 @@ sub deduplicate_email { ($name, $address) = parse_email($email); - if ($deduplicate_name_hash{lc($name)}) { + if ($name ne "" && $deduplicate_name_hash{lc($name)}) { $name = $deduplicate_name_hash{lc($name)}->[0]; $address = $deduplicate_name_hash{lc($name)}->[1]; $matched = 1; -- cgit v1.2.3-70-g09d2 From 6b4c5bebcebb0a48d29947e9aa749650751a7696 Mon Sep 17 00:00:00 2001 From: Andy Whitcroft Date: Tue, 26 Oct 2010 14:23:11 -0700 Subject: checkpatch: fix regressions in "fix handling of leading spaces" The patch "checkpatch: fix handling of leading spaces" added checks for leading spaces on lines, but this introduces regressions. Firstly it does not correctly detect when we are in a comment. Secondly it does not allow for preprocessor command spacing. Finally it does not allow for label indentation which is required to be less than one tab. Fix these up: Signed-off-by: Andy Whitcroft Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- scripts/checkpatch.pl | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'scripts') diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index 2039acdf512..0a87c7417ad 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -1459,10 +1459,13 @@ sub process { } # check for spaces at the beginning of a line. - if ($rawline =~ /^\+ / && $rawline !~ /\+ +\*/) { +# Exceptions: +# 1) within comments +# 2) indented preprocessor commands +# 3) hanging labels + if ($rawline =~ /^\+ / && $line !~ /\+ *(?:$;|#|$Ident:)/) { my $herevet = "$here\n" . cat_vet($rawline) . "\n"; - WARN("please, no space for starting a line, \ - excluding comments\n" . $herevet); + WARN("please, no spaces at the start of a line\n" . $herevet); } # check we are in a valid C source file if not then ignore this hunk -- cgit v1.2.3-70-g09d2 From e91b6e263ed6735c766cb14bbe63b9c7bd774526 Mon Sep 17 00:00:00 2001 From: Andy Whitcroft Date: Tue, 26 Oct 2010 14:23:11 -0700 Subject: checkpatch: types may sit on a line on their own When the following form is used we have a type which fully fills a line. This means that a type may end at the end of line as well as at the following identifier. int ** foo; Reported-by: Daniel Walker Signed-off-by: Andy Whitcroft Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- scripts/checkpatch.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'scripts') diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index 0a87c7417ad..41f59b1e209 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -843,7 +843,7 @@ sub annotate_values { $av_preprocessor = 0; } - } elsif ($cur =~ /^($Type)\s*(?:$Ident|,|\)|\()/) { + } elsif ($cur =~ /^($Type)\s*(?:$Ident|,|\)|\(|\s*$)/) { print "DECLARE($1)\n" if ($dbg_values > 1); $type = 'T'; -- cgit v1.2.3-70-g09d2 From d2c0a23514d8ac4ed10a8e742467cfb72ca3bed8 Mon Sep 17 00:00:00 2001 From: Andy Whitcroft Date: Tue, 26 Oct 2010 14:23:12 -0700 Subject: checkpatch: suggest cleanpatch and cleanfile when appropriate When we hit types of whitespace which may be fixed by scripts/cleanpatch and scripts/cleanfile suggest their use in our report. Suggested-by: Bartlomiej Zolnierkiewicz Signed-off-by: Andy Whitcroft Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- scripts/checkpatch.pl | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'scripts') diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index 41f59b1e209..32d6a236570 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -103,6 +103,8 @@ for my $key (keys %debug) { die "$@" if ($@); } +my $rpt_cleaners = 0; + if ($terse) { $emacs = 1; $quiet++; @@ -1389,6 +1391,7 @@ sub process { } elsif ($rawline =~ /^\+.*\S\s+$/ || $rawline =~ /^\+\s+$/) { my $herevet = "$here\n" . cat_vet($rawline) . "\n"; ERROR("trailing whitespace\n" . $herevet); + $rpt_cleaners = 1; } # check for Kconfig help text having a real description @@ -1450,6 +1453,7 @@ sub process { $rawline =~ /^\+\s* \s*/) { my $herevet = "$here\n" . cat_vet($rawline) . "\n"; ERROR("code indent should use tabs where possible\n" . $herevet); + $rpt_cleaners = 1; } # check for space before tabs. @@ -2842,6 +2846,15 @@ sub process { print "\n" if ($quiet == 0); } + if ($quiet == 0) { + # If there were whitespace errors which cleanpatch can fix + # then suggest that. + if ($rpt_cleaners) { + print "NOTE: whitespace errors detected, you may wish to use scripts/cleanpatch or\n"; + print " scripts/cleanfile\n\n"; + } + } + if ($clean == 1 && $quiet == 0) { print "$vname has no obvious style problems and is ready for submission.\n" } -- cgit v1.2.3-70-g09d2 From fb2d2c1b5825503d30fb6f2dc328dbe4a47d9794 Mon Sep 17 00:00:00 2001 From: Andy Whitcroft Date: Tue, 26 Oct 2010 14:23:12 -0700 Subject: checkpatch: ensure we do not collapse bracketed sections into constants When determining if a return () sequence is a function style bracketing we simplify the expression one bracket at a time replacing each with a constant. However this can trigger a false merge with expressions as below: return (foo)0; Prevent this false merging. Reported-by: Hitoshi Mitake Signed-off-by: Andy Whitcroft Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- scripts/checkpatch.pl | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'scripts') diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index 32d6a236570..8d010ac0efe 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -2183,15 +2183,16 @@ sub process { my $value = $2; # Flatten any parentheses - $value =~ s/\)\(/\) \(/g; + $value =~ s/\(/ \(/g; + $value =~ s/\)/\) /g; while ($value =~ s/\[[^\{\}]*\]/1/ || $value !~ /(?:$Ident|-?$Constant)\s* $Compare\s* (?:$Ident|-?$Constant)/x && $value =~ s/\([^\(\)]*\)/1/) { } - - if ($value =~ /^(?:$Ident|-?$Constant)$/) { +#print "value<$value>\n"; + if ($value =~ /^\s*(?:$Ident|-?$Constant)\s*$/) { ERROR("return is not a function, parentheses are not required\n" . $herecurr); } elsif ($spacing !~ /\s+/) { -- cgit v1.2.3-70-g09d2 From 9446ef569c288e683225fec8337a0b2b81e75cc5 Mon Sep 17 00:00:00 2001 From: Andy Whitcroft Date: Tue, 26 Oct 2010 14:23:13 -0700 Subject: checkpatch: handle casts better fixing false categorisation of : as binary The following incantation is triggering categorisation of its colon (:) as a binary form, which it is not: return foo ? (s8)bar : baz; Handle casts differently from types in the categoriser, allowing us to better track (s8)bar as a value and not a declaration. Reported-by: Jean Delvare Signed-off-by: Andy Whitcroft Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- scripts/checkpatch.pl | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'scripts') diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index 8d010ac0efe..3cec2990d51 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -845,6 +845,11 @@ sub annotate_values { $av_preprocessor = 0; } + } elsif ($cur =~ /^(\(\s*$Type\s*)\)/) { + print "CAST($1)\n" if ($dbg_values > 1); + push(@av_paren_type, $type); + $type = 'C'; + } elsif ($cur =~ /^($Type)\s*(?:$Ident|,|\)|\(|\s*$)/) { print "DECLARE($1)\n" if ($dbg_values > 1); $type = 'T'; -- cgit v1.2.3-70-g09d2 From 53a3c4487a05b8f26ef72fe434a750a3402c998f Mon Sep 17 00:00:00 2001 From: Andy Whitcroft Date: Tue, 26 Oct 2010 14:23:14 -0700 Subject: checkpatch: returning errno typically should be negative Add a (strict mode only) test to check for non-negative returns of what appear to be errno values as the majority case these should indeed be negative. Suggested-by: Andrew Morton Signed-off-by: Andy Whitcroft Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- scripts/checkpatch.pl | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'scripts') diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index 3cec2990d51..bcdb54bd61a 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -2204,6 +2204,13 @@ sub process { ERROR("space required before the open parenthesis '('\n" . $herecurr); } } +# Return of what appears to be an errno should normally be -'ve + if ($line =~ /^.\s*return\s*(E[A-Z]*)\s*;/) { + my $name = $1; + if ($name ne 'EOF' && $name ne 'ERROR') { + WARN("return of an errno should typically be -ve (return -$1)\n" . $herecurr); + } + } # Need a space before open parenthesis after if, while etc if ($line=~/\b(if|while|for|switch)\(/) { -- cgit v1.2.3-70-g09d2 From 8cf6de7145943caa38c56c61cd83b17687afd900 Mon Sep 17 00:00:00 2001 From: Andy Whitcroft Date: Tue, 26 Oct 2010 14:23:14 -0700 Subject: checkpatch: add check for space after struct, union, and enum Add spacing checks for struct, union, and enum definitions. Check the spacing after type and before the equals (=) and open brace ({). Based on a patch by Joe Perches. Cc: Joe Perches Signed-off-by: Andy Whitcroft Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- scripts/checkpatch.pl | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'scripts') diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index bcdb54bd61a..983ac1816da 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -1905,6 +1905,16 @@ sub process { ERROR("open brace '{' following function declarations go on the next line\n" . $herecurr); } +# missing space after union or struct definition + if ($rawline =~ /^\+\s*(union|struct)\s+$Ident[=\{]/) { + WARN("Missing space after struct or union definition\n" . $herecurr); + } + +# missing space after enum definition + if ($rawline =~ /^\+\s*enum\{/) { + WARN("Missing space after enum definition\n" . $herecurr); + } + # open braces for enum, union and struct go on the same line. if ($line =~ /^.\s*{/ && $prevline =~ /^.\s*(?:typedef\s+)?(enum|union|struct)(?:\s+$Ident)?\s*$/) { -- cgit v1.2.3-70-g09d2 From 0c73b4eb7a825a5aff16d8a9701f6c28056de058 Mon Sep 17 00:00:00 2001 From: Andy Whitcroft Date: Tue, 26 Oct 2010 14:23:15 -0700 Subject: checkpatch: simplify and consolidate "missing space after" checks Commonise the code for missing spaces after struct, union, and enum such that they share the same code. Ensure we cover all the common cases in each case. Check against the sanitised line to ensure we do not report on comments and strings. Signed-off-by: Andy Whitcroft Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- scripts/checkpatch.pl | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) (limited to 'scripts') diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index 983ac1816da..cb19f54b4b2 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -1905,22 +1905,17 @@ sub process { ERROR("open brace '{' following function declarations go on the next line\n" . $herecurr); } -# missing space after union or struct definition - if ($rawline =~ /^\+\s*(union|struct)\s+$Ident[=\{]/) { - WARN("Missing space after struct or union definition\n" . $herecurr); - } - -# missing space after enum definition - if ($rawline =~ /^\+\s*enum\{/) { - WARN("Missing space after enum definition\n" . $herecurr); - } - # open braces for enum, union and struct go on the same line. if ($line =~ /^.\s*{/ && $prevline =~ /^.\s*(?:typedef\s+)?(enum|union|struct)(?:\s+$Ident)?\s*$/) { ERROR("open brace '{' following $1 go on the same line\n" . $hereprev); } +# missing space after union, struct or enum definition + if ($line =~ /^.\s*(?:typedef\s+)?(enum|union|struct)(?:\s+$Ident)?(?:\s+$Ident)?[=\{]/) { + WARN("missing space after $1 definition\n" . $herecurr); + } + # check for spacing round square brackets; allowed: # 1. with a type on the left -- int [] a; # 2. at the beginning of a line for slice initialisers -- [0...10] = 5, -- cgit v1.2.3-70-g09d2 From 9fe287d79b0af983050d24e7916cf3d1f019f553 Mon Sep 17 00:00:00 2001 From: Andy Whitcroft Date: Tue, 26 Oct 2010 14:23:15 -0700 Subject: checkpatch: ensure kconfig help checks only apply when we are adding help When checking the length of the help we need to be sure we are seeing the whole story before erroring. Firstly we only want to check when adding the help in the first place. Second we need to be sure that we are seeing the end of the entry, nominally when there is no context below or that context shows the start of the next entry. Signed-off-by: Andy Whitcroft Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- scripts/checkpatch.pl | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) (limited to 'scripts') diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index cb19f54b4b2..e44ff91e811 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -1400,18 +1400,34 @@ sub process { } # check for Kconfig help text having a real description +# Only applies when adding the entry originally, after that we do not have +# sufficient context to determine whether it is indeed long enough. if ($realfile =~ /Kconfig/ && - $line =~ /\+?\s*(---)?help(---)?$/) { + $line =~ /\+\s*(?:---)?help(?:---)?$/) { my $length = 0; - for (my $l = $linenr; defined($lines[$l]); $l++) { - my $f = $lines[$l]; + my $cnt = $realcnt; + my $ln = $linenr + 1; + my $f; + my $is_end = 0; + while ($cnt > 0 && defined $lines[$ln - 1]) { + $f = $lines[$ln - 1]; + $cnt-- if ($lines[$ln - 1] !~ /^-/); + $is_end = $lines[$ln - 1] =~ /^\+/; + $ln++; + + next if ($f =~ /^-/); + $f =~ s/^.//; $f =~ s/#.*//; $f =~ s/^\s+//; next if ($f =~ /^$/); - last if ($f =~ /^\s*config\s/); + if ($f =~ /^\s*config\s/) { + $is_end = 1; + last; + } $length++; } - WARN("please write a paragraph that describes the config symbol fully\n" . $herecurr) if ($length < 4); + WARN("please write a paragraph that describes the config symbol fully\n" . $herecurr) if ($is_end && $length < 4); + #print "is_end<$is_end> length<$length>\n"; } # check we are in a valid source file if not then ignore this hunk -- cgit v1.2.3-70-g09d2 From 3bf9a009fccea422bc355414a3bdf5f35fff9f36 Mon Sep 17 00:00:00 2001 From: Rabin Vincent Date: Tue, 26 Oct 2010 14:23:16 -0700 Subject: checkpatch: check for incorrect permissions Throw an error when a source file has been given execute permissions using the mode change line present in git diffs. Also alow the filename matching to use the "diff" line in addition to the "+++" line, since the mode change lines appear before any "+++" lines. [apw@canonical.com: simplified filename logic slightly, added tests] Cc: Andy Whitcroft Acked-by: Linus Walleij Signed-off-by: Rabin Vincent Signed-off-by: Andy Whitcroft Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- scripts/checkpatch.pl | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) (limited to 'scripts') diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index e44ff91e811..93fa145671a 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -1315,7 +1315,11 @@ sub process { $here = "#$realline: " if ($file); # extract the filename as it passes - if ($line=~/^\+\+\+\s+(\S+)/) { + if ($line =~ /^diff --git.*?(\S+)$/) { + $realfile = $1; + $realfile =~ s@^([^/]*)/@@; + + } elsif ($line =~ /^\+\+\+\s+(\S+)/) { $realfile = $1; $realfile =~ s@^([^/]*)/@@; @@ -1339,6 +1343,14 @@ sub process { $cnt_lines++ if ($realcnt != 0); +# Check for incorrect file permissions + if ($line =~ /^new (file )?mode.*[7531]\d{0,2}$/) { + my $permhere = $here . "FILE: $realfile\n"; + if ($realfile =~ /(Makefile|Kconfig|\.c|\.h|\.S|\.tmpl)$/) { + ERROR("do not set execute permissions for source files\n" . $permhere); + } + } + #check the patch for a signoff: if ($line =~ /^\s*signed-off-by:/i) { # This is a signoff, if ugly, so do not double report. -- cgit v1.2.3-70-g09d2 From 03f1df7da5696ddfa6e167b37e0c0ce5aad3de79 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Tue, 26 Oct 2010 14:23:16 -0700 Subject: checkpatch: Add additional attribute #defines On Wed, 2010-08-11 at 12:35 -0400, Dave Jones wrote: > I just got this from a patch I merged.. > > ERROR: need consistent spacing around '*' (ctx:WxV) > #121: FILE: arch/x86/kernel/cpu/cpufreq/pcc-cpufreq.c:113: > +static struct pcc_cpu __percpu *pcc_cpu_info; > ^ > which doesn't seem right. Perhaps these need to be added to checkpatch. [apw@canonical.com: added tests] Signed-off-by: Joe Perches Signed-off-by: Andy Whitcroft Cc: Dave Jones Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- scripts/checkpatch.pl | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'scripts') diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index 93fa145671a..c151c9e142a 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -152,6 +152,20 @@ our $Sparse = qr{ # We need \b after 'init' otherwise 'initconst' will cause a false positive in a check our $Attribute = qr{ const| + __percpu| + __nocast| + __safe| + __bitwise__| + __packed__| + __packed2__| + __naked| + __maybe_unused| + __always_unused| + __noreturn| + __used| + __cold| + __noclone| + __deprecated| __read_mostly| __kprobes| __(?:mem|cpu|dev|)(?:initdata|initconst|init\b)| -- cgit v1.2.3-70-g09d2 From 015830be9779aeae7de7060b07a3157a8e41bcb4 Mon Sep 17 00:00:00 2001 From: Andy Whitcroft Date: Tue, 26 Oct 2010 14:23:17 -0700 Subject: checkpatch: update copyright dates Signed-off-by: Andy Whitcroft Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- scripts/checkpatch.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'scripts') diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index c151c9e142a..53b2eaecba0 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -2,7 +2,7 @@ # (c) 2001, Dave Jones. (the file handling bit) # (c) 2005, Joel Schopp (the ugly bit) # (c) 2007,2008, Andy Whitcroft (new conditions, test suite) -# (c) 2008,2009, Andy Whitcroft +# (c) 2008-2010 Andy Whitcroft # Licensed under the terms of the GNU GPL License version 2 use strict; -- cgit v1.2.3-70-g09d2 From 5eaa20b984eb316533b4a098d8de3912e434df6a Mon Sep 17 00:00:00 2001 From: Andy Whitcroft Date: Tue, 26 Oct 2010 14:23:18 -0700 Subject: checkpatch: clean up structure definition macro handline Handle definitions such as the following correctly, it is not a complex statement: #define PREALLOC(NAME, START, END, FLAGS) { \ .name = (NAME), \ .start = (START), \ .end = (END), \ .flags = (FLAGS) \ }, Signed-off-by: Andy Whitcroft Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- scripts/checkpatch.pl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'scripts') diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index 53b2eaecba0..d5361e49aba 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -2476,8 +2476,8 @@ sub process { \.$Ident\s*=\s*| ^\"|\"$ }x; - #print "REST<$rest> dstat<$dstat>\n"; - if ($rest ne '') { + #print "REST<$rest> dstat<$dstat> ctx<$ctx>\n"; + if ($rest ne '' && $rest ne ',') { if ($rest !~ /while\s*\(/ && $dstat !~ /$exceptions/) { -- cgit v1.2.3-70-g09d2 From 3cbf62df3a8ce61cb1aa20b7dae964058988bfdd Mon Sep 17 00:00:00 2001 From: Andy Whitcroft Date: Tue, 26 Oct 2010 14:23:18 -0700 Subject: checkpatch: handle EXPORT_SYMBOL for DEVICE_ATTR and similar Handly definitions similar to below. The definition macro spits out a symbol with a prefix. Add matching of any identifier prefix: DEVICE_ATTR(link_power_management_policy, S_IRUGO | S_IWUSR, ata_scsi_lpm_show, ata_scsi_lpm_put); EXPORT_SYMBOL_GPL(dev_attr_link_power_management_policy); Signed-off-by: Andy Whitcroft Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- scripts/checkpatch.pl | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'scripts') diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index d5361e49aba..8ab45b72b39 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -1822,8 +1822,17 @@ sub process { !defined $suppress_export{$realline_next} && ($lines[$realline_next - 1] =~ /EXPORT_SYMBOL.*\((.*)\)/ || $lines[$realline_next - 1] =~ /EXPORT_UNUSED_SYMBOL.*\((.*)\)/)) { + # Handle definitions which produce identifiers with + # a prefix: + # XXX(foo); + # EXPORT_SYMBOL(something_foo); my $name = $1; - if ($stat !~ /(?: + if ($stat =~ /^.([A-Z_]+)\s*\(\s*($Ident)/ && + $name =~ /^${Ident}_$2/) { +#print "FOO C name<$name>\n"; + $suppress_export{$realline_next} = 1; + + } elsif ($stat !~ /(?: \n.}\s*$| ^.DEFINE_$Ident\(\Q$name\E\)| ^.DECLARE_$Ident\(\Q$name\E\)| -- cgit v1.2.3-70-g09d2 From 01464f30a97c5c30bf9633309b27cce055cef8fd Mon Sep 17 00:00:00 2001 From: Andy Whitcroft Date: Tue, 26 Oct 2010 14:23:19 -0700 Subject: checkpatch: statement/block context analyser should look at sanitised lines When tracking context to find a block or statement we need to use the sanitised lines, else perentheses '(' & ')' and braces '{' & '}' can throw the scanner out. Also fix up a couple of error outputs which include those sanitised lines incorrectly. Signed-off-by: Andy Whitcroft Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- scripts/checkpatch.pl | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'scripts') diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index 8ab45b72b39..d086ffe377d 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -691,15 +691,15 @@ sub ctx_block_get { $blk .= $rawlines[$line]; # Handle nested #if/#else. - if ($rawlines[$line] =~ /^.\s*#\s*(?:ifndef|ifdef|if)\s/) { + if ($lines[$line] =~ /^.\s*#\s*(?:ifndef|ifdef|if)\s/) { push(@stack, $level); - } elsif ($rawlines[$line] =~ /^.\s*#\s*(?:else|elif)\b/) { + } elsif ($lines[$line] =~ /^.\s*#\s*(?:else|elif)\b/) { $level = $stack[$#stack - 1]; - } elsif ($rawlines[$line] =~ /^.\s*#\s*endif\b/) { + } elsif ($lines[$line] =~ /^.\s*#\s*endif\b/) { $level = pop(@stack); } - foreach my $c (split(//, $rawlines[$line])) { + foreach my $c (split(//, $lines[$line])) { ##print "C<$c>L<$level><$open$close>O<$off>\n"; if ($off > 0) { $off--; @@ -1652,7 +1652,7 @@ sub process { if ($ctx !~ /{\s*/ && defined($lines[$ctx_ln -1]) && $lines[$ctx_ln - 1] =~ /^\+\s*{/) { ERROR("that open brace { should be on the previous line\n" . - "$here\n$ctx\n$lines[$ctx_ln - 1]\n"); + "$here\n$ctx\n$rawlines[$ctx_ln - 1]\n"); } if ($level == 0 && $pre_ctx !~ /}\s*while\s*\($/ && $ctx =~ /\)\s*\;\s*$/ && @@ -1661,7 +1661,7 @@ sub process { my ($nlength, $nindent) = line_stats($lines[$ctx_ln - 1]); if ($nindent > $indent) { WARN("trailing semicolon indicates no statements, indent implies otherwise\n" . - "$here\n$ctx\n$lines[$ctx_ln - 1]\n"); + "$here\n$ctx\n$rawlines[$ctx_ln - 1]\n"); } } } -- cgit v1.2.3-70-g09d2 From 267ad8f42644c2fa4ff6c2e7596d2b02c7397c85 Mon Sep 17 00:00:00 2001 From: Andy Whitcroft Date: Tue, 26 Oct 2010 14:23:19 -0700 Subject: checkpatch: version 0.31 Signed-off-by: Andy Whitcroft Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- scripts/checkpatch.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'scripts') diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index d086ffe377d..c1e7fb3eab4 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -10,7 +10,7 @@ use strict; my $P = $0; $P =~ s@.*/@@g; -my $V = '0.30'; +my $V = '0.31'; use Getopt::Long qw(:config no_auto_abbrev); -- cgit v1.2.3-70-g09d2 From cb710eca6820493add0ddd3d7e8e3ee53f2b6e57 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Tue, 26 Oct 2010 14:23:20 -0700 Subject: scripts/checkpatch.pl: add warnings for static char that could be static const char Add warnings for possible missing const uses of static char foo[] = "bar" that could be static const char foo[] = "bar" and static const char *foo[] = {"bar", "baz"} that could be static const char * const foo[] = {"bar", "baz"} Signed-off-by: Joe Perches Cc: Mike Frysinger Cc: Andy Whitcroft Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- scripts/checkpatch.pl | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'scripts') diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index c1e7fb3eab4..2ec5fc6a404 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -1869,6 +1869,18 @@ sub process { $herecurr); } +# check for static const char * arrays. + if ($line =~ /\bstatic\s+const\s+char\s*\*\s*(\w+)\s*\[\s*\]\s*=\s*/) { + WARN("static const char * array should probably be static const char * const\n" . + $herecurr); + } + +# check for static char foo[] = "bar" declarations. + if ($line =~ /\bstatic\s+char\s+(\w+)\s*\[\s*\]\s*=\s*"/) { + WARN("static char array declaration should probably be static const char\n" . + $herecurr); + } + # check for new typedefs, only function parameters and sparse annotations # make sense. if ($line =~ /\btypedef\s/ && -- cgit v1.2.3-70-g09d2 From 93ed0e2d07b25aff4db1d61bfbcd1e82074c0ad5 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Tue, 26 Oct 2010 14:23:21 -0700 Subject: scripts/checkpatch.pl: add check for declaration of pci_device_id Signed-off-by: Joe Perches Cc: Andy Whitcroft Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- scripts/checkpatch.pl | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'scripts') diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index 2ec5fc6a404..90b54d4697f 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -1881,6 +1881,11 @@ sub process { $herecurr); } +# check for declarations of struct pci_device_id + if ($line =~ /\bstruct\s+pci_device_id\s+\w+\s*\[\s*\]\s*\=\s*\{/) { + WARN("Use DEFINE_PCI_DEVICE_TABLE for struct pci_device_id\n" . $herecurr); + } + # check for new typedefs, only function parameters and sparse annotations # make sense. if ($line =~ /\btypedef\s/ && -- cgit v1.2.3-70-g09d2