[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [PATCH for-4.11 v2 2/2] Add new add_maintainers.pl script to optimise the workflow when using git format-patch with get_maintainer.pl
The tool covers step 2 of the following workflow Step 1: git format-patch ... -o <patchdir> ... Step 2: ./scripts/add_maintainers.pl -d <patchdir> This overwrites *.patch files in <patchdir> Step 3: git send-email -to xen-devel@xxxxxxxxxxxxxxxxxxxx <patchdir>/*.patch I manually tested all options and the most common combinations on Mac. Changes in v2 - Added RAB (indicated by Juergen on IRC that this is OK) - Remove trailing whitespaces - Renamed --prefix to --reroll-count - Cleaned up short options -v, ... to be in line with git - Added --tags|-t option to add AB, RAB and RB emails to CC list - Added --insert|-i mode to allow for people adding CCs to commit message instead of the e-mail header (the header is the default) - Moved common code into functions - Added logic, such that the tool only insert's To: and Cc: statements which were not there before, allowing for running the tool multiple times on the same <patchdir> Cc: Andrew Cooper <andrew.cooper3@xxxxxxxxxx> Cc: George Dunlap <George.Dunlap@xxxxxxxxxxxxx> Cc: Ian Jackson <ian.jackson@xxxxxxxxxxxxx> Cc: Jan Beulich <jbeulich@xxxxxxxx> Cc: Julien Grall <julien.grall@xxxxxxx> Cc: Konrad Rzeszutek Wilk <konrad.wilk@xxxxxxxxxx> Cc: Stefano Stabellini <sstabellini@xxxxxxxxxx> Cc: Tim Deegan <tim@xxxxxxx> Cc: Wei Liu <wei.liu2@xxxxxxxxxx> Cc: Juergen Gross <jgross@xxxxxxxx> Signed-off-by: Lars Kurth <lars.kurth@xxxxxxxxxx> Release-acked-by: Juergen Gross <jgross@xxxxxxxx> --- scripts/add_maintainers.pl | 380 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 380 insertions(+) create mode 100755 scripts/add_maintainers.pl diff --git a/scripts/add_maintainers.pl b/scripts/add_maintainers.pl new file mode 100755 index 0000000000..616c13caa1 --- /dev/null +++ b/scripts/add_maintainers.pl @@ -0,0 +1,380 @@ +#!/usr/bin/perl -w +# (c) 2018, Lars Kurth <lars.kurth@xxxxxxxxxx> +# +# Add maintainers to patches generated with git format-patch +# +# Usage: perl scripts/add_maintainers.pl [OPTIONS] -patchdir <patchdir> +# +# Prerequisites: Execute +# git format-patch ... -o <patchdir> ... +# +# ./scripts/get_maintainer.pl is present in the tree +# +# Licensed under the terms of the GNU GPL License version 2 + +use strict; + +use Getopt::Long qw(:config no_auto_abbrev); +use File::Basename; +use List::MoreUtils qw(uniq); + +# Tool Variables +my $tool = $0; +my $toolversion = "1.0"; + +# Arguments / Options +my $version = 0; +my $help = 0; +my $patch_dir = 0; +my $get_maintainer_args = ""; +my $verbose = 0; +my $rerollcount = 0; +my $patch_prefix = "0"; # Use a 0, such that v* does not get picked up + # Obviously this will only work for series with + # < 999 patches, which should be fine +my $mode = "top"; +my @modes = ("top", "ccbody"); +my $tags = 0; + +# Constants +my @tags = ("Acked-by:", + "Release-acked-by:", + "Reviewed-by:"); +my $CC = "Cc:"; # Note: git-send-mail requires Cc: +my $TO = "To:"; +my $AT = "@"; +my $cc_insert_before = "Signed-off-by:"; +my $to_insert_before = "Date:"; +my $cover_letter = "0000-cover-letter.patch"; +my $get_maintainer = "./scripts/get_maintainer.pl"; +my $patch_ext = ".patch"; +my $mailing_lists = $AT."lists."; + +my @lists; #Needed for <<EOT +my $usage = <<EOT; +USAGE: $tool [options] (--patchdir|-d) <patchdir> +VERSION: $toolversion + +OPTIONS: +-------- + [(--reroll-count|-v) <n>] + Choose patch files for specific version. This results into the + following filters on <patchdir> + 0: default - *.patch + >1: v<n>*.patch + [(--insert|-i) (top|ccbody)] + top: default - insert everything in the e-mail header + ccbody: insert CCs into body (this means the CC list will be stored in + the commit message + [(--tags|-t)] + Read email addresses from tags and add to CC list. + [(--args|-a) <arguments>] + Arguments passed on to $get_maintainer + [--verbose] + Show more output + [--version] + Show version + --h|help|usage + Show this help information + +WORKFLOW: +--------- + This script is intended to be used as part of the following workflow + + Step 1: git format-patch ... -o <patchdir> ... + Step 2: ./scripts/add_maintainers.pl -d <patchdir> + This overwrites *.patch files in <patchdir> but makes a backup + Step 3: git send-email -to xen-devel@xxxxxxxxxxxxxxxxxxxx <patchdir>/*.patch +EOT + +if (!GetOptions( + 'd|patchdir=s' => \$patch_dir, + 'v|reroll-count=i' => \$rerollcount, + 'i|insert=s' => \$mode, + 't|tags' => \$tags, + 'a|args=s' => \$get_maintainer_args, + 'verbose' => \$verbose, + 'version' => \$version, + 'h|help|usage' => \$help, + )) { + die "$tool: invalid argument - use --help if necessary\n"; +} + +if ($help != 0) { + print $usage; + exit 0; +} + +if ($version != 0) { + print("$tool: version $toolversion\n"); + exit 0; +} + +if (! -e $get_maintainer) { + die "$tool: The tool requires $get_maintainer\n"; +} + +if (!$patch_dir) { + die "$tool: Directory -d|--patchdir not specified\n"; +} + +if (! -e $patch_dir) { + die "$tool: Directory $patch_dir does not exist\n"; +} + +if ($rerollcount > 0) { + $patch_prefix = "v".$rerollcount; +} + +if ( ! grep $_ eq $mode, @modes ) { + die "$tool: Invalid (-i|--insert) value\n"; +} + +# Get the list of patches +my $pattern = $patch_dir.'/'.$patch_prefix.'*'.$patch_ext; +my @patches = glob($pattern); +my $has_cover_letter = 0; +my $cover_letter_file; + +if (!scalar @patches) { + die "$tool: Directory $patch_dir contains no patches\n"; +} + +# Do the actual processing +my $file; +my @combined_to; +my @combined_cc; + +foreach my $file (@patches) { + if (index($file, $cover_letter) != -1) { + $has_cover_letter = 1; + $cover_letter_file = $file; + } else { + print "Processing: ".basename($file)."\n"; + my @to; # To: lists returned by get_maintainers.pl + my @topatch; # To: entries in *.patch + my @cc; # Cc: maintainers returned by get_maintainers.pl + my @ccpatch; # Cc: entries in *.patch + my @extrapatch; # Cc: for AB, RB, RAB in *.patch + + # Read tags from output of get_maintainers.pl + getmaintainers($file, \@to, \@cc); + + # Read all lines with CC & TO from the patch file (these will + # likely come from the commit message). Also read tags. + gettagsfrompatch($file, \@topatch, \@ccpatch, \@extrapatch); + + # With -t|--tags add @extrapatch to @cc and @combined_cc + if ($tags) { + push @cc, @extrapatch; + push @combined_cc, @extrapatch; + } + + # In this section we normalize the lists. We remove entries + # that are already in the patch, from @cc and @to + my @to_only = normalize(\@to, \@topatch); + my @cc_only = normalize(\@cc, \@ccpatch); + + # Insert CC's and TO's at the top of the *.patch file + if ($mode eq "top") { + my $insert = join("\n", uniq (@to_only, @cc_only))."\n"; + # Insert snippets into files + # $insert before "Signed-off-by:" + insert_before($file , $insert, $to_insert_before); + } + elsif ($mode eq "ccbody") { + my $to = join("\n", uniq @to_only)."\n"; + my $cc = join("\n", uniq @cc_only)."\n"; + + # Insert snippets into files + # $cc before "Signed-off-by:"f + insert_before($file , $cc, $cc_insert_before); + # $to before suitable header line + insert_before($file , $to, $to_insert_before); + } + } +} + +# Deal with the cover letter +if ($has_cover_letter) { + my @topatch; # To: entries in *.patch + my @ccpatch; # Cc: entries in *.patch + + # Read all lines with CC & TO from the patch file such that subsequent + # calls don't lead to duplication + gettagsfrompatch($cover_letter_file, \@topatch, \@ccpatch); + + # In this section we normalize the lists. We remove entries + # that are already in the patch, from @cc and @to + my @to_only = normalize(\@combined_to, \@topatch); + my @cc_only = normalize(\@combined_cc, \@ccpatch); + + my $insert = join("\n", uniq (@to_only, @cc_only))."\n"; + + print "Processing: ".basename($cover_letter_file)."\n"; + + # Insert snippets into files + # $to and $cc before suitable header line + insert_before($cover_letter_file, $insert, $to_insert_before); + + print "\nDon't forget to add the subject and message to ". + $cover_letter_file."\n"; +} + +print "Then perform:\n". + "git send-email -to xen-devel".$AT."lists.xenproject.org ". + $patch_dir.'/'.$patch_prefix."*.patch"."\n"; + +exit 1; + +sub getmaintainers { + my ($file, $rto, $rcc) = @_; + my $cmd = $get_maintainer." ".$get_maintainer_args." < ".$file; + my $fh; + + open($fh, "$cmd|") + or die "Failed to open '$cmd'\n"; + while(<$fh>) { + chomp; + # Keep lists and CC's separately as we dont want them in + # the commit message under a Cc: line + if (index($_, $mailing_lists) != -1) { + push @{$rto}, $TO." ".$_; + push @combined_to, $TO." ".$_; + } else { + push @{$rcc}, $CC." ".$_; + push @combined_cc, $CC." ".$_; + } + } + close $fh; +} + +sub gettagsfrompatch { + my ($file, $rto, $rcc, $rextra) = @_; + my $fh; + + open($fh, "<", $file) + or die "Failed to open '$file'\n"; + while(<$fh>) { + chomp; + my $line = $_; + my $nline; + + if (hastag($line, $TO, \$nline)) { + push @{$rto}, $nline; + push @combined_to, $nline; + } + if (hastag($line, $CC, \$nline)) { + push @{$rcc}, $nline; + push @combined_cc, $nline; + } + # If there is an $rextra, then get various tags and add + # email addresses to the CC list + if ($rextra) { + my $item; + foreach $item (@tags) { + if (hastag($line, $item, \$nline)) { + # Replace tag with CC, then push + $nline =~ s/$item/$CC/; + push @{$rextra}, $nline; + } + } + } + } + close $fh; +} + +sub hastag () +{ + my ($line, $tag, $rline) = @_; + my $index = index(lc $line, lc $tag); + if ($index != -1) { + if ($index == 0) { + # If at first position, then just return + ${$rline} = $line; + return 1; + } else { + # If not at first position, then remove white + # spaces before the tag and return a normalized + # string + if (substr($line, 0, $index) =~ /^\s*$/) { + ${$rline} = substr($line, $index); + return 1; + } + } + } + return 0; +} + +sub normalize { + # Note: you cannot pass two arrays to a subroutine without loosing the + # information which entry belongs to which array. Thus, pass as references. + my ($ra, $rb) = @_; + my @aonly = (); + my %seen; + my $item; + + foreach $item (@{$rb}) { + $seen{$item} = 1; + } + foreach $item (@{$ra}) { + unless ($seen{$item}) { + # it's not in %seen, so add to @aonly + push @aonly, $item; + } + } + + return @aonly; +} + +sub readfile { + my ($file) = @_; + my $fh; + my $content; + open($fh, "<", $file) + or die "Could not open file '$file' $!"; + $content = do { local $/; <$fh> }; + close $fh; + + return $content; +} + +sub writefile { + my ($content, $file) = @_; + my $fh; + open($fh, ">", $file) + or die "Could not open file '$file' $!"; + print $fh $content; + close $fh; + + return 1; +} + +sub insert_before { + my ($file, $ins, $before) = @_; + my $content; + + if ($ins eq "\n") { + # Not inserting anything + # I added this here such that I don't have to run the check + # when calling the function. + return 0; + } + + # Read file + $content = readfile($file); + + # Split the string and generate new content + my $i = index($content, $before); + my $p1 = substr $content, 0, $i; + my $p2 = substr $content, $i; + + writefile($p1.$ins.$p2, $file); + + if ($verbose) { + print "\nInserted into ".basename($file).' before "'.$before."'". + "\n-----\n".$ins."-----\n"; + } + + return 1; +} -- 2.13.0 _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxxxxxxxxx https://lists.xenproject.org/mailman/listinfo/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |