File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / rsync / packaging / branch-from-patch
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Mon Oct 14 07:51:14 2013 UTC (10 years, 8 months ago) by misho
Branches: rsync, MAIN
CVS tags: v3_1_2p5, RSYNC3_1_0, HEAD
v 3.1.0

    1: #!/usr/bin/perl
    2: 
    3: use strict;
    4: use warnings;
    5: use Getopt::Long;
    6: 
    7: &Getopt::Long::Configure('bundling');
    8: &usage if !&GetOptions(
    9:     'branch|b=s' => \( my $master_branch = 'master' ),
   10:     'skip-check' => \( my $skip_branch_check ),
   11:     'delete' => \( my $delete_local_branches ),
   12:     'help|h' => \( my $help_opt ),
   13: );
   14: &usage if $help_opt;
   15: 
   16: require 'packaging/git-status.pl';
   17: check_git_state($master_branch, !$skip_branch_check, 1);
   18: 
   19: my %local_branch;
   20: open PIPE, '-|', 'git branch -l' or die "Unable to fork: $!\n";
   21: while (<PIPE>) {
   22:     if (m# patch/\Q$master_branch\E/(.*)#o) {
   23: 	$local_branch{$1} = 1;
   24:     }
   25: }
   26: close PIPE;
   27: 
   28: if ($delete_local_branches) {
   29:     foreach my $name (sort keys %local_branch) {
   30: 	my $branch = "patch/$master_branch/$name";
   31: 	system 'git', 'branch', '-D', $branch and exit 1;
   32:     }
   33:     %local_branch = ( );
   34: }
   35: 
   36: my @patch_list;
   37: foreach (@ARGV) {
   38:     if (!-f $_) {
   39: 	die "File not found: $_\n";
   40:     }
   41:     die "Filename is not a .diff file: $_\n" unless /\.diff$/;
   42:     push @patch_list, $_;
   43: }
   44: 
   45: exit unless @patch_list;
   46: 
   47: my(%scanned, %created, %info);
   48: 
   49: foreach my $patch (@patch_list) {
   50:     my($where, $name) = $patch =~ m{^(.*?)([^/]+)\.diff$};
   51:     next if $scanned{$name}++;
   52: 
   53:     open IN, '<', $patch or die "Unable to open $patch: $!\n";
   54: 
   55:     my $info = '';
   56:     my $commit;
   57:     while (<IN>) {
   58: 	if (m#^based-on: (\S+)#) {
   59: 	    $commit = $1;
   60: 	    last;
   61: 	}
   62: 	last if m#^index .*\.\..* \d#;
   63: 	last if m#^diff --git #;
   64: 	last if m#^--- (old|a)/#;
   65: 	$info .= $_;
   66:     }
   67:     close IN;
   68: 
   69:     $info =~ s/\s+\Z/\n/;
   70: 
   71:     my $parent = $master_branch;
   72:     my @patches = $info =~ m#patch -p1 <patches/(\S+)\.diff#g;
   73:     if (@patches) {
   74: 	if ($patches[-1] eq $name) {
   75: 	    pop @patches;
   76: 	} else {
   77: 	    warn "No identity patch line in $patch\n";
   78: 	}
   79: 	if (@patches) {
   80: 	    $parent = pop @patches;
   81: 	    if (!$scanned{$parent}) {
   82: 		unless (-f "$where$parent.diff") {
   83: 		    die "Unknown parent of $patch: $parent\n";
   84: 		}
   85: 		# Add parent to @patch_list so that we will look for the
   86: 		# parent's parent.  Any duplicates will just be ignored.
   87: 		push @patch_list, "$where$parent.diff";
   88: 	    }
   89: 	}
   90:     } else {
   91: 	warn "No patch lines found in $patch\n";
   92:     }
   93: 
   94:     $info{$name} = [ $parent, $info, $commit ];
   95: }
   96: 
   97: foreach my $patch (@patch_list) {
   98:     create_branch($patch);
   99: }
  100: 
  101: system 'git', 'checkout', $master_branch and exit 1;
  102: 
  103: exit;
  104: 
  105: sub create_branch
  106: {
  107:     my($patch) = @_;
  108:     my($where, $name) = $patch =~ m{^(.*?)([^/]+)\.diff$};
  109: 
  110:     return if $created{$name}++;
  111: 
  112:     my $ref = $info{$name};
  113:     my($parent, $info, $commit) = @$ref;
  114: 
  115:     my $parent_branch;
  116:     if ($parent eq $master_branch) {
  117: 	$parent_branch = $master_branch;
  118: 	$parent_branch = $commit if defined $commit;
  119:     } else {
  120: 	create_branch("$where/$parent.diff");
  121: 	$parent_branch = "patch/$master_branch/$parent";
  122:     }
  123: 
  124:     my $branch = "patch/$master_branch/$name";
  125:     print "\n", '=' x 64, "\nProcessing $branch ($parent_branch)\n";
  126: 
  127:     if ($local_branch{$name}) {
  128: 	system 'git', 'branch', '-D', $branch and exit 1;
  129:     }
  130: 
  131:     system 'git', 'checkout', '-b', $branch, $parent_branch and exit 1;
  132: 
  133:     open OUT, '>', "PATCH.$name" or die $!;
  134:     print OUT $info;
  135:     close OUT;
  136:     system 'git', 'add', "PATCH.$name" and exit 1;
  137: 
  138:     open IN, '<', $patch or die "Unable to open $patch: $!\n";
  139:     $_ = join('', <IN>);
  140:     close IN;
  141: 
  142:     open PIPE, '|-', 'patch -p1' or die $!;
  143:     print PIPE $_;
  144:     close PIPE;
  145: 
  146:     system 'rm -f *.orig */*.orig';
  147: 
  148:     while (m#\nnew file mode (\d+)\s+--- /dev/null\s+\Q+++\E b/(.*)#g) {
  149: 	chmod oct($1), $2;
  150: 	system 'git', 'add', $2;
  151:     }
  152: 
  153:     while (1) {
  154: 	system 'git status';
  155: 	print 'Press Enter to commit, Ctrl-C to abort, or type a wild-name to add a new file: ';
  156: 	$_ = <STDIN>;
  157: 	last if /^$/;
  158: 	chomp;
  159: 	system "git add $_";
  160:     }
  161: 
  162:     while (system 'git', 'commit', '-a', '-m', "Creating branch from $name.diff.") {
  163: 	exit 1 if system '/bin/zsh';
  164:     }
  165: }
  166: 
  167: sub usage
  168: {
  169:     die <<EOT;
  170: Usage branch-from-patch [OPTIONS] patches/DIFF...
  171: 
  172: Options:
  173: -b, --branch=BRANCH  Create branches relative to BRANCH if no "based-on"
  174:                      header was found in the patch file.
  175:     --skip-check     Skip the check that ensures starting with a clean branch.
  176:     --delete         Delete all the local patch/BASE/* branches, not just the ones
  177:                      that are being recreated.
  178: -h, --help           Output this help message.
  179: EOT
  180: }

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