Annotation of embedaddon/rsync/packaging/patch-update, revision 1.1.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>