#!/usr/bin/perl use strict; chdir('patches') if -d 'patches'; if (!-f 'verify-patches') { die <); close IN; mkdir('tmp', 0777) unless -d 'tmp'; chdir('tmp') or die "Unable to chdir to 'tmp'"; mkdir('workdir') unless -d 'workdir'; open(OUT, '>exclude') or die $!; print OUT <) { last if /^--- /; if (/^Depends-On-Patch: (\S+.diff)$/) { my $dep = $1; $has_dependencies = 1; print "\nApplying dependency patch $dep...\n"; if (system("patch -d cvsdir -p0 -b -Vt -Zf <../$dep") != 0) { print "Unable to cleanly apply depenency patch -- skipping $diff\n"; system "rm -f cvsdir/*.rej cvsdir/*/*.rej"; &restore_cvsdir; next DIFF; } } } close IN; my $default = apply_patch($diff); if ($default =~ s/^D,// || $default eq 'N') { generate_new_patch($diff); } PROMPT: while (1) { print "\n----------- $diff ------------\n", "\nFix rejects, Diff create, Edit both diffs, Update patch,\n", "Apply patch again, !(CMD), Build rsync, Next, Quit: [$default] "; my $ans = ; chomp $ans; $ans = $default if $ans eq ''; while ($ans =~ s/^\s*(!|\w)((?workdir/Makefile') or die $!; print OUT "srcdir=.\n\n"; while () { last if /^gen:/; } print OUT $_; while () { last if /^clean:/; print OUT $_; } close IN; close OUT; } chdir('workdir') or die $!; system "make gen; ./configure $CONF_OPTS; make"; chdir('..') or die $!; $default = '!make test'; next; } if ($cmd eq 'D') { $default = generate_new_patch($diff); next; } if ($cmd eq 'E') { chdir('workdir') or die $!; system "vim -d ../../$diff ../new.patch"; chdir('..') or die $!; $default = 'U,A,D'; next; } if ($cmd eq 'F') { chdir('workdir') or die $!; system "vim @rejects"; chdir('..') or die $!; $default = 'D,E'; next; } if ($cmd eq 'N') { last PROMPT; } if ($cmd eq 'Q') { exit; } if ($cmd eq 'U') { system "cp -p new.patch ../$diff"; print "\nUpdated $diff from new.patch\n"; $default = 'A'; next; } } } &restore_cvsdir; } exit; sub apply_patch { my($diff) = @_; undef @new; my $def = 'N'; system "rsync -a --delete --exclude='*~' cvsdir/ workdir/"; print "\nApplying patch $diff...\n"; undef @rejects; open(IN, "patch -d workdir -p0 --no-backup-if-mismatch -Zf <../$diff |") or die $!; while () { print $_; chomp; if (s/^patching file //) { push(@new, $_) unless -f "cvsdir/$_"; } elsif (s/.* saving rejects to file //) { push(@rejects, $_); } elsif (/^Hunk #\d+ FAILED/) { $def = 'F,D,E'; } elsif (/^Hunk #\d+ succeeded/) { $def = 'D,E' unless $def =~ /F/; } } close IN; $def; } sub generate_new_patch { my($diff) = @_; foreach (@new) { system "touch -r workdir/$_ cvsdir/$_"; } open(IN, "../$diff") or die $!; open(OUT, '>new.patch') or die $!; while () { last if /^--- /; print OUT $_; } close IN; open(IN, 'diff --exclude-from=exclude -upr cvsdir workdir |') or die $!; while () { next if /^(diff -|Index: |Only in )/; s#^\Q--- cvsdir/\E#--- orig/#; s#^\Q+++ workdir/\E#+++ #; s#(\.000000000)? \+0000$##; print OUT $_; } close IN; close OUT; foreach (@new) { unlink("cvsdir/$_"); } print "\nDiffing... "; if (system("diff ../$diff new.patch >/dev/null") == 0) { print "new patch is identical to old.\n"; return 'N'; } print "New patch DIFFERS from old.\n"; 'E'; } sub restore_cvsdir { return unless $has_dependencies; $has_dependencies = 0; foreach (glob('*.~[1-9]~'), glob('*/*.~[1-9]~')) { my $fn; ($fn = $_) =~ s/\.~1~$//; if ($fn eq $_) { unlink($_); } elsif (-r $fn) { rename($_, $fn); } else { unlink($_); unlink($fn); } } }