diff options
author | Wayne Davison <wayned@samba.org> | 2009-05-23 13:40:34 -0700 |
---|---|---|
committer | Wayne Davison <wayned@samba.org> | 2009-05-23 13:40:34 -0700 |
commit | 06886d36cfdcfb94f0d67f8964d22ee7c7872018 (patch) | |
tree | 916d21a6a556839de737e482ded7365103217476 /packaging/branch-from-patch | |
parent | 9ba4d44fa8a4fb1b3d79602d0d8744d464f5c60c (diff) | |
download | rsync-06886d36cfdcfb94f0d67f8964d22ee7c7872018.tar.gz |
Adding a new script that creates a local patch/* branch
for each file given on the command-line.
Diffstat (limited to 'packaging/branch-from-patch')
-rwxr-xr-x | packaging/branch-from-patch | 183 |
1 files changed, 183 insertions, 0 deletions
diff --git a/packaging/branch-from-patch b/packaging/branch-from-patch new file mode 100755 index 00000000..bf854b17 --- /dev/null +++ b/packaging/branch-from-patch @@ -0,0 +1,183 @@ +#!/usr/bin/perl + +use strict; +use warnings; +use Getopt::Long; + +&Getopt::Long::Configure('bundling'); +&usage if !&GetOptions( + 'branch|b=s' => \( my $master_branch = 'master' ), + 'skip-check' => \( my $skip_branch_check ), + 'delete' => \( my $delete_local_branches ), + 'help|h' => \( my $help_opt ), +); +&usage if $help_opt; + +my %local_branch; +open PIPE, '-|', 'git branch -l' or die "Unable to fork: $!\n"; +while (<PIPE>) { + if (m# patch/(.*)#) { + $local_branch{$1} = 1; + } +} +close PIPE; + +if ($delete_local_branches) { + foreach my $name (sort keys %local_branch) { + my $branch = "patch/$name"; + system 'git', 'branch', '-D', $branch and exit 1; + } + %local_branch = ( ); +} + +open IN, '-|', 'git status' or die $!; +my $status = join('', <IN>); +close IN; +die "The checkout is not clean:\n", $status unless $status =~ /\nnothing to commit \(working directory clean\)/; +die "The checkout is not on the $master_branch branch.\n" unless $status =~ /^# On branch $master_branch\n/; + +my @patch_list; +foreach (@ARGV) { + if (!-f $_) { + die "File not found: $_\n"; + } + die "Filename is not a .diff file: $_\n" unless /\.diff$/; + push @patch_list, $_; +} + +exit unless @patch_list; + +my(%scanned, %created, %info); + +foreach my $patch (@patch_list) { + my($where, $name) = $patch =~ m{^(.*?)([^/]+)\.diff$}; + next if $scanned{$name}++; + + open IN, '<', $patch or die "Unable to open $patch: $!\n"; + + my $info = ''; + my $commit; + while (<IN>) { + if (m#^based-on: (\S+)#) { + $commit = $1; + last; + } + last if m#^index .*\.\..* \d#; + last if m#^diff --git #; + last if m#^--- (old|a)/#; + $info .= $_; + } + close IN; + + $info =~ s/\s+\Z/\n/; + + my $parent = $master_branch; + my @patches = $info =~ m#patch -p1 <patches/(\S+)\.diff#g; + if (@patches) { + if ($patches[-1] eq $name) { + pop @patches; + } else { + warn "No identity patch line in $patch\n"; + } + if (@patches) { + $parent = pop @patches; + if (!$scanned{$parent}) { + unless (-f "$where$parent.diff") { + die "Unknown parent of $patch: $parent\n"; + } + # Add parent to @patch_list so that we will look for the + # parent's parent. Any duplicates will just be ignored. + push @patch_list, "$where$parent.diff"; + } + } + } else { + warn "No patch lines found in $patch\n"; + } + + $info{$name} = [ $parent, $info, $commit ]; +} + +foreach my $patch (@patch_list) { + create_branch($patch); +} + +system 'git', 'checkout', $master_branch and exit 1; + +exit; + +sub create_branch +{ + my($patch) = @_; + my($where, $name) = $patch =~ m{^(.*?)([^/]+)\.diff$}; + + return if $created{$name}++; + + my $ref = $info{$name}; + my($parent, $info, $commit) = @$ref; + + my $parent_branch; + if ($parent eq $master_branch) { + $parent_branch = $master_branch; + $parent_branch = $commit if defined $commit; + } else { + create_branch("$where/$parent.diff"); + $parent_branch = "patch/$parent"; + } + + my $branch = "patch/$name"; + print "\n", '=' x 64, "\nProcessing $branch ($parent_branch)\n"; + + if ($local_branch{$name}) { + system 'git', 'branch', '-D', $branch and exit 1; + } + + system 'git', 'checkout', '-b', $branch, $parent_branch and exit 1; + + open OUT, '>', "PATCH.$name" or die $!; + print OUT $info; + close OUT; + system 'git', 'add', "PATCH.$name" and exit 1; + + open IN, '<', $patch or die "Unable to open $patch: $!\n"; + $_ = join('', <IN>); + close IN; + + open PIPE, '|-', 'patch -p1' or die $!; + print PIPE $_; + close PIPE; + + system 'rm -f *.orig */*.orig'; + + while (m#\nnew file mode (\d+)\s+--- /dev/null\s+\Q+++\E b/(.*)#g) { + chmod oct($1), $2; + system 'git', 'add', $2; + } + + while (1) { + system 'git status'; + print 'Press Enter to commit, Ctrl-C to abort, or type a wild-name to add a new file: '; + $_ = <STDIN>; + last if /^$/; + chomp; + system "git add $_"; + } + + while (system 'git', 'commit', '-a', '-m', "Creating branch from $name.diff.") { + exit 1 if system '/bin/zsh'; + } +} + +sub usage +{ + die <<EOT; +Usage branch-from-patch [OPTIONS] patches/DIFF... + +Options: +-b, --branch=BRANCH Create branches relative to BRANCH if no "based-on" + header was found in the patch file. + --skip-check Skip the check that ensures starting with a clean branch. + --delete Delete all the local patch/* branches, not just the ones + that are being recreated. +-h, --help Output this help message. +EOT +} |