Transformed shell script into perl script and improved it to allow
[rsync/rsync-patches.git] / verify-patches
1 #!/usr/bin/perl
2
3 use strict;
4
5 chdir('patches') if -d 'patches';
6
7 if (!-f 'verify-patches') {
8     die <<EOT;
9 Please run this script from the root of the rsync dir or
10 from inside the patches subdir.
11 EOT
12 }
13
14 $ENV{'TZ'} = 'GMT';
15
16 my($has_dependencies, @new);
17
18 END {
19     &restore_cvsdir;
20 };
21
22 my $root;
23 open(IN, '../CVS/Root') or die $!;
24 chomp($root = <IN>);
25 close IN;
26
27 my $tmpdir = ',tmp-for-patch-tests';
28
29 mkdir($tmpdir, 0777) unless -d $tmpdir;
30 chdir($tmpdir) or die "Unable to chdir to $tmpdir";
31
32 mkdir('workdir') unless -d 'workdir';
33 open(OUT, '>exclude') or die $!;
34 print OUT <<EOT;
35 proto.h
36 configure
37 config.h.in
38 rsync.1
39 rsyncd.conf.5
40 EOT
41 close OUT;
42
43 print "Using CVS to update the $tmpdir/cvsdir copy of the source.\n";
44 system qq|cvs -d "$root" co -d cvsdir rsync|;
45
46 @ARGV = glob('../*.diff') unless @ARGV;
47
48 DIFF:
49 foreach my $diff (@ARGV) {
50     next unless $diff =~ /\.diff$/;
51     next if $diff =~ /gzip-rsyncable\.diff$/;
52     $diff =~ s#^(patches|\.\.)/##;
53
54     open(IN, "../$diff") or die $!;
55     while (<IN>) {
56         last if /^--- /;
57         if (/^Depends-On-Patch: (\S+.diff)$/) {
58             my $dep = $1;
59             $has_dependencies = 1;
60             print "\nApplying dependency patch $dep\n";
61             if (system("patch -d cvsdir -p0 -b -Vt -Z <../$dep") != 0) {
62                 print "Unable to cleanly apply depenency patch -- skipping $diff\n";
63                 &restore_cvsdir;
64                 next DIFF;
65             }
66         }
67     }
68     close IN;
69
70     my $apply = 1;
71     my(@rejects, $default);
72     while (1) {
73         print "\n----------- $diff ------------\n";
74         if ($apply) {
75             undef @new;
76             $default = 'N';
77             system "rsync -a --delete cvsdir/ workdir";
78             open(IN, "patch -d workdir -p0 --no-backup-if-mismatch -Z <../$diff |") or die $!;
79             while (<IN>) {
80                 print $_;
81                 chomp;
82                 if (s/^patching file //) {
83                     push(@new, $_) unless -f "cvsdir/$_";
84                 } elsif (s/.* saving rejects to file //) {
85                     push(@rejects, $_);
86                 } elsif (/^Hunk #\d+ FAILED/) {
87                     $default = 'F';
88                 } elsif (/^Hunk #\d+ succeeded/) {
89                     $default = 'E' unless $default eq 'F';
90                 }
91             }
92             close IN;
93             if ($default eq 'N') {
94                 generate_new_patch($diff);
95                 if (system("diff ../$diff new.patch >/dev/null") == 0) {
96                     print "\n(New patch is identical to old.)\n";
97                 }
98             }
99             $apply = 0;
100         }
101         print "\nFix rejects, Edit both diffs, Update patch,\n",
102             "Apply patch again, Next, Quit: [$default] ";
103         my $ans = <STDIN>;
104         chomp $ans;
105         $ans = $default unless $ans =~ s/^(\w)/$1/;
106         if ($ans =~ /E/i) {
107             generate_new_patch($diff);
108             chdir('workdir') or die $!;
109             system "vim -d ../../$diff ../new.patch";
110             chdir('..') or die $!;
111             $default = 'U';
112         } elsif ($ans =~ /F/i) {
113             chdir('workdir') or die $!;
114             system "vim @rejects";
115             chdir('..') or die $!;
116             $default = 'E';
117         } elsif ($ans =~ /U/i) {
118             system "cp -p new.patch ../$diff";
119             print "\nUpdated $diff from new.patch\n";
120             $default = 'A';
121         } elsif ($ans =~ /A/i) {
122             $apply = 1;
123         } elsif ($ans =~ /N/i) {
124             last;
125         } elsif ($ans =~ /Q/i) {
126             exit;
127         }
128     }
129
130     &restore_cvsdir;
131 }
132
133 exit;
134
135
136 sub generate_new_patch
137 {
138     my($diff) = @_;
139
140     foreach (@new) {
141         system "touch -r workdir/$_ cvsdir/$_";
142     }
143     open(IN, "../$diff") or die $!;
144     open(OUT, '>new.patch') or die $!;
145     while (<IN>) {
146         last if /^--- /;
147         print OUT $_;
148     }
149     close IN;
150     open(IN, 'diff --exclude-from=exclude -upr cvsdir workdir |') or die $!;
151     while (<IN>) {
152         next if /^(diff -|Index: |Only in )/;
153         s#^\Q--- cvsdir/\E#--- orig/#;
154         s#^\Q+++ workdir/\E#+++ #;
155         s#(\.000000000)? \+0000$##;
156         print OUT $_;
157     }
158     close IN;
159     close OUT;
160     foreach (@new) {
161         unlink("cvsdir/$_");
162     }
163 }
164
165 sub restore_cvsdir
166 {
167     return unless $has_dependencies;
168     $has_dependencies = 0;
169
170     foreach (glob('*.~[1-9]~'), glob('*/*.~[1-9]~')) {
171         my $fn;
172         ($fn = $_) =~ s/\.~1~$//;
173         if ($fn eq $_) {
174             unlink($_);
175         } elsif (-r $fn) {
176             rename($_,  $fn);
177         } else {
178             unlink($_);
179             unlink($fn);
180         }
181     }
182 }