|
[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 |