File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / rsync / packaging / patch-update
Revision 1.1.1.3 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Nov 1 09:54:32 2016 UTC (7 years, 8 months ago) by misho
Branches: rsync, MAIN
CVS tags: v3_1_2p5, HEAD
rsync 3.1.2

    1: #!/usr/bin/perl
    2: # This script is used to turn one or more of the "patch/BASE/*" branches
    3: # into one or more diffs in the "patches" directory.  Pass the option
    4: # --gen if you want generated files in the diffs.  Pass the name of
    5: # one or more diffs if you want to just update a subset of all the
    6: # diffs.
    7: 
    8: use strict;
    9: use warnings;
   10: use Getopt::Long;
   11: 
   12: my $patches_dir = 'patches';
   13: my $tmp_dir = "patches.$$";
   14: my $make_gen_cmd = 'make -f prepare-source.mak conf && ./config.status && make gen';
   15: 
   16: &Getopt::Long::Configure('bundling');
   17: &usage if !&GetOptions(
   18:     'branch|b=s' => \( my $master_branch = 'master' ),
   19:     'skip-check' => \( my $skip_branch_check ),
   20:     'shell|s' => \( my $launch_shell ),
   21:     'gen:s' => \( my $incl_generated_files ),
   22:     'help|h' => \( my $help_opt ),
   23: );
   24: &usage if $help_opt;
   25: 
   26: $ENV{GIT_MERGE_AUTOEDIT} = 'no';
   27: 
   28: if (defined $incl_generated_files) {
   29:     $patches_dir = $incl_generated_files if $incl_generated_files ne '';
   30:     $incl_generated_files = 1;
   31: }
   32: 
   33: die "No '$patches_dir' directory was found.\n" unless -d $patches_dir;
   34: die "No '.git' directory present in the current dir.\n" unless -d '.git';
   35: 
   36: require 'packaging/git-status.pl';
   37: my $starting_branch = check_git_state($master_branch, !$skip_branch_check, 1);
   38: 
   39: my $master_commit;
   40: open PIPE, '-|', "git log -1 --no-color $master_branch" or die $!;
   41: while (<PIPE>) {
   42:     if (/^commit (\S+)/) {
   43: 	$master_commit = $1;
   44: 	last;
   45:     }
   46: }
   47: close PIPE;
   48: die "Unable to determine commit hash for master branch: $master_branch\n" unless defined $master_commit;
   49: 
   50: if ($incl_generated_files) {
   51:     my @extra_files = get_extra_files();
   52:     die "'$tmp_dir' must not exist in the current directory.\n" if -e $tmp_dir;
   53:     mkdir($tmp_dir, 0700) or die "Unable to mkdir($tmp_dir): $!\n";
   54:     system "$make_gen_cmd && rsync -a @extra_files $tmp_dir/master/" and exit 1;
   55: }
   56: our $last_touch = time;
   57: 
   58: my %patches;
   59: 
   60: # Start by finding all patches so that we can load all possible parents.
   61: open(PIPE, '-|', 'git', 'branch', '-l') or die $!;
   62: while (<PIPE>) {
   63:     if (m# patch/\Q$master_branch\E/(.*)#o) {
   64: 	$patches{$1} = 1;
   65:     }
   66: }
   67: close PIPE;
   68: 
   69: my @patches = sort keys %patches;
   70: 
   71: my(%parent, %description);
   72: foreach my $patch (@patches) {
   73:     my $branch = "patch/$master_branch/$patch";
   74:     my $desc = '';
   75:     open(PIPE, '-|', 'git', 'diff', '-U1000', "$master_branch...$branch", '--', "PATCH.$patch") or die $!;
   76:     while (<PIPE>) {
   77: 	last if /^@@ /;
   78:     }
   79:     while (<PIPE>) {
   80: 	next unless s/^[ +]//;
   81: 	if (m#patch -p1 <patches/(\S+)\.diff# && $1 ne $patch) {
   82: 	    my $parent = $parent{$patch} = $1;
   83: 	    if (!$patches{$parent}) {
   84: 		die "Parent of $patch is not a local branch: $parent\n";
   85: 	    }
   86: 	}
   87: 	$desc .= $_;
   88:     }
   89:     close PIPE;
   90:     $description{$patch} = $desc;
   91: }
   92: 
   93: if (@ARGV) {
   94:     # Limit the list of patches to actually process based on @ARGV.
   95:     @patches = ( );
   96:     foreach (@ARGV) {
   97: 	s{^patch(es)?/} {};
   98: 	s{\.diff$} {};
   99: 	if (!$patches{$_}) {
  100: 	    die "Local branch not available for patch: $_\n";
  101: 	}
  102: 	push(@patches, $_);
  103:     }
  104: }
  105: 
  106: my %completed;
  107: foreach my $patch (@patches) {
  108:     next if $completed{$patch}++;
  109:     last unless update_patch($patch);
  110: }
  111: 
  112: if ($incl_generated_files) {
  113:     system "rm -rf $tmp_dir";
  114: }
  115: 
  116: sleep 1 while $last_touch >= time;
  117: system "git checkout $starting_branch" and exit 1;
  118: 
  119: exit;
  120: 
  121: 
  122: sub update_patch
  123: {
  124:     my($patch) = @_;
  125: 
  126:     my $parent = $parent{$patch};
  127:     my $based_on;
  128:     if (defined $parent) {
  129: 	unless ($completed{$parent}++) {
  130: 	    update_patch($parent);
  131: 	}
  132: 	$based_on = $parent = "patch/$master_branch/$parent";
  133:     } else {
  134: 	$parent = $master_branch;
  135: 	$based_on = $master_commit;
  136:     }
  137: 
  138:     print "======== $patch ========\n";
  139: 
  140:     sleep 1 while $incl_generated_files && $last_touch >= time;
  141:     system "git checkout patch/$master_branch/$patch" and return 0;
  142: 
  143:     my $ok = system("git merge $based_on") == 0;
  144:     if (!$ok || $launch_shell) {
  145: 	my($parent_dir) = $parent =~ m{([^/]+)$};
  146: 	print qq|"git merge $based_on" incomplete -- please fix.\n| if !$ok;
  147: 	$ENV{PS1} = "[$parent_dir] $patch: ";
  148: 	while (1) {
  149: 	    if (system($ENV{SHELL}) != 0) {
  150: 		print "Abort? [n/y] ";
  151: 		$_ = <STDIN>;
  152: 		next unless /^y/i;
  153: 		return 0;
  154: 	    }
  155: 	    my($cur_branch, $is_clean, $status) = check_git_status(0);
  156: 	    last if $is_clean;
  157: 	    print $status;
  158: 	}
  159:     }
  160: 
  161:     open(OUT, '>', "$patches_dir/$patch.diff") or die $!;
  162:     print OUT $description{$patch}, "\nbased-on: $based_on\n";
  163: 
  164:     my @extra_files;
  165:     if ($incl_generated_files) {
  166: 	@extra_files = get_extra_files();
  167: 	system "$make_gen_cmd && rsync -a @extra_files $tmp_dir/$patch/" and exit 1;
  168:     }
  169:     $last_touch = time;
  170: 
  171:     open(PIPE, '-|', 'git', 'diff', $based_on) or die $!;
  172:     DIFF: while (<PIPE>) {
  173: 	while (m{^diff --git a/PATCH}) {
  174: 	    while (<PIPE>) {
  175: 		last if m{^diff --git a/};
  176: 	    }
  177: 	    last DIFF if !defined $_;
  178: 	}
  179: 	next if /^index /;
  180: 	print OUT $_;
  181:     }
  182:     close PIPE;
  183: 
  184:     if ($incl_generated_files) {
  185: 	my $parent_dir;
  186: 	if ($parent eq $master_branch) {
  187: 	    $parent_dir = 'master';
  188: 	} else {
  189: 	    ($parent_dir) = $parent =~ m{([^/]+)$};
  190: 	}
  191: 	open(PIPE, '-|', 'diff', '-Nurp', "$tmp_dir/$parent_dir", "$tmp_dir/$patch") or die $!;
  192: 	while (<PIPE>) {
  193: 	    s#^(diff -Nurp) $tmp_dir/[^/]+/(.*?) $tmp_dir/[^/]+/(.*)#$1 a/$2 b/$3#o;
  194: 	    s#^\Q---\E $tmp_dir/[^/]+/([^\t]+)\t.*#--- a/$1#o;
  195: 	    s#^\Q+++\E $tmp_dir/[^/]+/([^\t]+)\t.*#+++ b/$1#o;
  196: 	    print OUT $_;
  197: 	}
  198: 	close PIPE;
  199: 	unlink @extra_files;
  200:     }
  201: 
  202:     close OUT;
  203: 
  204:     1;
  205: }
  206: 
  207: exit;
  208: 
  209: sub get_extra_files
  210: {
  211:     my @extras;
  212: 
  213:     open(IN, '<', 'Makefile.in') or die "Couldn't open Makefile.in: $!\n";
  214:     while (<IN>) {
  215: 	if (s/^GENFILES=//) {
  216: 	    while (s/\\$//) {
  217: 		$_ .= <IN>;
  218: 	    }
  219: 	    @extras = split(' ', $_);
  220: 	    last;
  221: 	}
  222:     }
  223:     close IN;
  224: 
  225:     return @extras;
  226: }
  227: 
  228: sub usage
  229: {
  230:     die <<EOT;
  231: Usage: patch-update [OPTIONS] [patches/DIFF...]
  232: 
  233: Options:
  234: -b, --branch=BRANCH  The master branch to merge into the patch/BASE/* branches.
  235:     --gen[=DIR]      Include generated files.  Optional destination DIR
  236:                      arg overrides the default of using the "patches" dir.
  237:     --skip-check     Skip the check that ensures starting with a clean branch.
  238: -s, --shell          Launch a shell for every patch/BASE/* branch updated, not
  239:                      just when a conflict occurs.
  240: -h, --help           Output this help message.
  241: EOT
  242: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>