Annotation of embedaddon/rsync/packaging/branch-from-patch, revision 1.1
1.1 ! misho 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>