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