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};
176 my ($cmd, @args) = @ARGV;
177 $cmd = 'help' if not defined $cmd;
182 for(@revisions_applied)
185 print "Applied: $a to $b\n";
187 for(GetUnappliedRanges(GetMasterRev()))
190 print "Unapplied: $a to $b\n";
193 elsif($cmd eq 'unmerged')
197 for(GetUnappliedRanges(GetMasterRev()))
200 my $log = GetLog $a, $b;
203 push @autoadd, [$a, $b];
207 print "Unapplied: $a to $b\n";
213 print "Autofilled revision hole $a to $b\n";
216 WriteSettings() if @autoadd;
218 elsif($cmd eq 'merge')
220 my ($first, $last) = @args;
221 $last = $first if not defined $last;
223 die "There is an uncommitted merge"
227 AddPatch $first, $last;
229 print OutputOf 'svn merge -r#1:#2 #3', ($first - 1), $last, $conf{master};
230 print "You may also want to run $0 unmerged to fill possible revision holes\n";
231 print "Make sure there are no conflicts, then run $0 commit\n";
232 print "To abort, use $0 revert\n";
234 open my $fh, '>', '.commitmsg'
235 or die "open .commitmsg";
236 print $fh GetLog $first, $last;
241 elsif($cmd eq 'undo')
243 my ($first, $last) = @args;
244 $last = $first if not defined $last;
246 die "There is an uncommitted merge"
250 RemovePatch $first, $last;
252 print OutputOf 'svn merge -r#2:#1 #3', ($first - 1), $last, $conf{master};
253 print "Make sure there are no conflicts, then run $0 commit\n";
254 print "To abort, use $0 revert\n";
256 open my $fh, '>', '.commitmsg'
257 or die "open .commitmsg";
258 print $fh "undo the following merge:\n", GetLog $first, last;
263 elsif($cmd eq 'commit')
265 system 'vim .commitmsg';
266 print "Hit Enter if OK to commit, Ctrl-C otherwise...\n";
268 if(!system 'svn commit -F .commitmsg')
273 elsif($cmd eq 'revert')
275 if(!system 'svn revert -R .')
280 elsif($cmd eq 'init')
282 my ($master, $rev) = @args;
283 $conf{master} = $master;
284 @revisions_applied = [1, $rev];
291 $0 init masterrepo rev