9 $cmd =~ s/#(\d)/"\$ARG$1"/g;
10 $ENV{"ARG$_"} = $args[$_-1]
13 open my $fh, '-|', $cmd
14 or die "popen $cmd: $!";
28 my ($cmd, @args) = @_;
29 $cmd =~ s/#(\d)/"\$ARG$1"/g;
30 $ENV{"ARG$_"} = $args[$_-1]
32 my $ret = system $cmd;
43 revisions_applied => ''
45 my @revisions_applied = (); # array of [first, last] ranges
49 open my $fh, '<', ".patchsets"
54 /^([^=]*?)\s*=\s*(.*?)$/s
56 die "Invalid config item: $1 (allowed: @{[sort keys %conf]})"
57 if not exists $conf{$1};
61 @revisions_applied = map { /^(\d+)-(\d+)$/s or die "Invalid revision spec $_"; [$1, $2]; } split /,/, $conf{revisions_applied};
66 $conf{revisions_applied} = join ',', map { "$_->[0]-$_->[1]" } @revisions_applied;
68 open my $fh, '>', ".patchsets"
69 or die "writing settings: $!";
72 print $fh "$_ = $conf{$_}\n";
78 my ($first, $last) = @_;
79 die "Invalid range" if $first > $last;
81 my @rev = sort { $a->[0] <=> $b->[0] } (@revisions_applied, [$first, $last]);
88 my $c = $rev[$i+1][0];
89 my $d = $rev[$i+1][1];
93 die "overlapping patch: $a-$b overlaps $c-$d";
97 splice @rev, $i, 2, [$a, $d];
103 @revisions_applied = @rev;
108 my ($first, $last) = @_;
109 die "Invalid range" if $first > $last;
111 my @rev = sort { $a->[0] <=> $b->[0] } (@revisions_applied);
119 if($first >= $a && $last <= $b)
124 if($first == $a && $last == $b)
130 @replacement = ([$last + 1, $b]);
134 @replacement = ([$a, $first - 1]);
138 @replacement = ([$a, $first - 1], [$last + 1, $b]);
140 splice @rev, $i, 1, @replacement;
141 @revisions_applied = @rev;
146 die "could not remove range: not in set";
149 sub GetUnappliedRanges($)
155 for(@revisions_applied)
158 if($a - 1 >= $cur + 1)
160 push @unapplied, [$cur + 1, $a - 1];
164 if($lastrev >= $cur + 1)
166 push @unapplied, [$cur + 1, $lastrev];
173 my $svninfo = OutputOf 'svn info #1', $conf{master};
174 $svninfo =~ /^Last Changed Rev: (\d+)$/m
175 or die "could not get svn info";
181 my ($first, $last) = @_;
182 my $log = OutputOf 'svn log -r#1:#2 #3', $first, $last, $conf{master};
192 my ($first, $last) = @_;
193 return OutputOf 'svn diff -r#1:#2 #3', $first-1, $last, $conf{master};
196 my ($cmd, @args) = @ARGV;
197 $cmd = 'help' if not defined $cmd;
202 for(@revisions_applied)
205 print "Applied: $a to $b\n";
207 for(GetUnappliedRanges(GetMasterRev()))
210 print "Unapplied: $a to $b\n";
213 elsif($cmd eq 'unmerged-diff')
217 for(GetUnappliedRanges(GetMasterRev()))
220 my $log = GetLog $a, $b;
223 push @autoadd, [$a, $b];
227 print "Unapplied: $a to $b\n";
229 print GetDiff $a, $b;
235 print "Autofilled revision hole $a to $b\n";
238 WriteSettings() if @autoadd;
240 elsif($cmd eq 'unmerged')
244 for(GetUnappliedRanges(GetMasterRev()))
247 my $log = GetLog $a, $b;
250 push @autoadd, [$a, $b];
254 print "Unapplied: $a to $b\n";
260 print "Autofilled revision hole $a to $b\n";
263 WriteSettings() if @autoadd;
265 elsif($cmd eq 'merge')
267 my ($first, $last, $force) = @args;
268 die "Usage: $0 merge first last [--force]"
269 if not defined $first;
270 $last = $first if not defined $last;
272 die "Usage: $0 merge first last"
273 if "$first$last" =~ /[^0-9]/;
275 die "There is an uncommitted merge"
276 if -f '.commitmsg' and $force ne '--force';
279 AddPatch $first, $last;
281 StatusOf 'svn merge -r#1:#2 #3', ($first - 1), $last, $conf{master};
282 print "You may also want to run $0 unmerged to fill possible revision holes\n";
283 print "Make sure there are no conflicts, then run $0 commit\n";
284 print "To abort, use $0 revert\n";
286 open my $fh, '>>', '.commitmsg'
287 or die "open .commitmsg";
288 print $fh GetLog $first, $last;
294 elsif($cmd eq 'undo')
296 my ($first, $last, $force) = @args;
297 die "Usage: $0 undo first last"
298 if not defined $first;
299 $last = $first if not defined $last;
301 die "Usage: $0 merge first last"
302 if "$first$last" =~ /[^0-9]/;
304 die "There is an uncommitted merge"
305 if -f '.commitmsg' and $force ne '--force';
308 RemovePatch $first, $last;
310 print OutputOf 'svn merge -r#2:#1 #3', ($first - 1), $last, $conf{master};
311 print "Make sure there are no conflicts, then run $0 commit\n";
312 print "To abort, use $0 revert\n";
314 open my $fh, '>>', '.commitmsg'
315 or die "open .commitmsg";
316 print $fh "undo the following merge:\n", GetLog $first, $last;
321 elsif($cmd eq 'commit')
323 system 'vim .commitmsg';
324 print "Hit Enter if OK to commit, Ctrl-C otherwise...\n";
326 if(!system 'svn commit -F .commitmsg')
331 elsif($cmd eq 'revert')
333 if(!system 'svn revert -R .')
338 elsif($cmd eq 'init')
340 my ($master, $rev) = @args;
341 $conf{master} = $master;
342 @revisions_applied = [1, $rev];
349 $0 init masterrepo rev
353 $0 merge rev1 [rev2] [--force]
354 $0 undo rev1 [rev2] [--force]