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) = @args;
254 die "Usage: $0 merge first last"
255 if not defined $first;
256 $last = $first if not defined $last;
258 die "There is an uncommitted merge"
262 AddPatch $first, $last;
264 print OutputOf 'svn merge -r#1:#2 #3', ($first - 1), $last, $conf{master};
265 print "You may also want to run $0 unmerged to fill possible revision holes\n";
266 print "Make sure there are no conflicts, then run $0 commit\n";
267 print "To abort, use $0 revert\n";
269 open my $fh, '>', '.commitmsg'
270 or die "open .commitmsg";
271 print $fh GetLog $first, $last;
276 elsif($cmd eq 'undo')
278 my ($first, $last) = @args;
279 die "Usage: $0 undo first last"
280 if not defined $first;
281 $last = $first if not defined $last;
283 die "There is an uncommitted merge"
287 RemovePatch $first, $last;
289 print OutputOf 'svn merge -r#2:#1 #3', ($first - 1), $last, $conf{master};
290 print "Make sure there are no conflicts, then run $0 commit\n";
291 print "To abort, use $0 revert\n";
293 open my $fh, '>', '.commitmsg'
294 or die "open .commitmsg";
295 print $fh "undo the following merge:\n", GetLog $first, last;
300 elsif($cmd eq 'commit')
302 system 'vim .commitmsg';
303 print "Hit Enter if OK to commit, Ctrl-C otherwise...\n";
305 if(!system 'svn commit -F .commitmsg')
310 elsif($cmd eq 'revert')
312 if(!system 'svn revert -R .')
317 elsif($cmd eq 'init')
319 my ($master, $rev) = @args;
320 $conf{master} = $master;
321 @revisions_applied = [1, $rev];
328 $0 init masterrepo rev