9 $cmd =~ s/#(\d)/"\$ARG$1"/g;
10 $ENV{"ARG$_"} = $args[$_-1]
13 open my $fh, '-|', $cmd
14 or die "popen $cmd: $!";
29 revisions_applied => ''
31 my @revisions_applied = (); # array of [first, last] ranges
35 open my $fh, '<', ".patchsets"
40 /^([^=]*?)\s*=\s*(.*?)$/s
42 die "Invalid config item: $1 (allowed: @{[sort keys %conf]})"
43 if not exists $conf{$1};
47 @revisions_applied = map { /^(\d+)-(\d+)$/s or die "Invalid revision spec $_"; [$1, $2]; } split /,/, $conf{revisions_applied};
52 $conf{revisions_applied} = join ',', map { "$_->[0]-$_->[1]" } @revisions_applied;
54 open my $fh, '>', ".patchsets"
55 or die "writing settings: $!";
58 print $fh "$_ = $conf{$_}\n";
64 my ($first, $last) = @_;
65 die "Invalid range" if $first > $last;
67 my @rev = sort { $a->[0] <=> $b->[0] } (@revisions_applied, [$first, $last]);
74 my $c = $rev[$i+1][0];
75 my $d = $rev[$i+1][1];
79 die "overlapping patch: $a-$b overlaps $c-$d";
83 splice @rev, $i, 2, [$a, $d];
89 @revisions_applied = @rev;
94 my ($first, $last) = @_;
95 die "Invalid range" if $first > $last;
97 my @rev = sort { $a->[0] <=> $b->[0] } (@revisions_applied);
105 if($first >= $a && $last <= $b)
110 if($first == $a && $last == $b)
116 @replacement = ([$last + 1, $b]);
120 @replacement = ([$a, $first - 1]);
124 @replacement = ([$a, $first - 1], [$last + 1, $b]);
126 splice @rev, $i, 1, @replacement;
127 @revisions_applied = @rev;
132 die "could not remove range: not in set";
135 sub GetUnappliedRanges($)
141 for(@revisions_applied)
144 if($a - 1 >= $cur + 1)
146 push @unapplied, [$cur + 1, $a - 1];
150 if($lastrev >= $cur + 1)
152 push @unapplied, [$cur + 1, $lastrev];
159 my $svninfo = OutputOf 'svn info #1', $conf{master};
160 $svninfo =~ /^Last Changed Rev: (\d+)$/m
161 or die "could not get svn info";
167 my ($first, $last) = @_;
168 my $log = OutputOf 'svn log -r#1:#2 #3', $first, $last, $conf{master};
178 my ($first, $last) = @_;
179 return OutputOf 'svn diff -r#1:#2 #3', $first-1, $last, $conf{master};
182 my ($cmd, @args) = @ARGV;
183 $cmd = 'help' if not defined $cmd;
188 for(@revisions_applied)
191 print "Applied: $a to $b\n";
193 for(GetUnappliedRanges(GetMasterRev()))
196 print "Unapplied: $a to $b\n";
199 elsif($cmd eq 'unmerged-diff')
203 for(GetUnappliedRanges(GetMasterRev()))
206 my $log = GetLog $a, $b;
209 push @autoadd, [$a, $b];
213 print "Unapplied: $a to $b\n";
215 print GetDiff $a, $b;
221 print "Autofilled revision hole $a to $b\n";
224 WriteSettings() if @autoadd;
226 elsif($cmd eq 'unmerged')
230 for(GetUnappliedRanges(GetMasterRev()))
233 my $log = GetLog $a, $b;
236 push @autoadd, [$a, $b];
240 print "Unapplied: $a to $b\n";
246 print "Autofilled revision hole $a to $b\n";
249 WriteSettings() if @autoadd;
251 elsif($cmd eq 'merge')
253 my ($first, $last, $force) = @args;
254 die "Usage: $0 merge first last [--force]"
255 if not defined $first;
256 $last = $first if not defined $last;
258 die "Usage: $0 merge first last"
259 if "$first$last" =~ /[^0-9]/;
261 die "There is an uncommitted merge"
262 if -f '.commitmsg' and $force ne '--force';
265 AddPatch $first, $last;
267 print OutputOf 'svn merge -r#1:#2 #3', ($first - 1), $last, $conf{master};
268 print "You may also want to run $0 unmerged to fill possible revision holes\n";
269 print "Make sure there are no conflicts, then run $0 commit\n";
270 print "To abort, use $0 revert\n";
272 open my $fh, '>>', '.commitmsg'
273 or die "open .commitmsg";
274 print $fh GetLog $first, $last;
280 elsif($cmd eq 'undo')
282 my ($first, $last, $force) = @args;
283 die "Usage: $0 undo first last"
284 if not defined $first;
285 $last = $first if not defined $last;
287 die "Usage: $0 merge first last"
288 if "$first$last" =~ /[^0-9]/;
290 die "There is an uncommitted merge"
291 if -f '.commitmsg' and $force ne '--force';
294 RemovePatch $first, $last;
296 print OutputOf 'svn merge -r#2:#1 #3', ($first - 1), $last, $conf{master};
297 print "Make sure there are no conflicts, then run $0 commit\n";
298 print "To abort, use $0 revert\n";
300 open my $fh, '>>', '.commitmsg'
301 or die "open .commitmsg";
302 print $fh "undo the following merge:\n", GetLog $first, $last;
307 elsif($cmd eq 'commit')
309 system 'vim .commitmsg';
310 print "Hit Enter if OK to commit, Ctrl-C otherwise...\n";
312 if(!system 'svn commit -F .commitmsg')
317 elsif($cmd eq 'revert')
319 if(!system 'svn revert -R .')
324 elsif($cmd eq 'init')
326 my ($master, $rev) = @args;
327 $conf{master} = $master;
328 @revisions_applied = [1, $rev];
335 $0 init masterrepo rev
339 $0 merge rev1 [rev2] [--force]
340 $0 undo rev1 [rev2] [--force]