|
1 @rem = '--*-Perl-*-- |
|
2 @echo off |
|
3 if "%OS%" == "Windows_NT" goto WinNT |
|
4 perl -x -S "%0" %1 %2 %3 %4 %5 %6 %7 %8 %9 |
|
5 goto endofperl |
|
6 :WinNT |
|
7 perl -x -S %0 %* |
|
8 if NOT "%COMSPEC%" == "%SystemRoot%\system32\cmd.exe" goto endofperl |
|
9 if %errorlevel% == 9009 echo You do not have Perl in your PATH. |
|
10 if errorlevel 1 goto script_failed_so_exit_with_non_zero_val 2>nul |
|
11 goto endofperl |
|
12 @rem '; |
|
13 #!/usr/bin/perl -w |
|
14 #line 15 |
|
15 |
|
16 # Copyright (C) 2005, 2006 Apple Computer, Inc. All rights reserved. |
|
17 # |
|
18 # Redistribution and use in source and binary forms, with or without |
|
19 # modification, are permitted provided that the following conditions |
|
20 # are met: |
|
21 # |
|
22 # 1. Redistributions of source code must retain the above copyright |
|
23 # notice, this list of conditions and the following disclaimer. |
|
24 # 2. Redistributions in binary form must reproduce the above copyright |
|
25 # notice, this list of conditions and the following disclaimer in the |
|
26 # documentation and/or other materials provided with the distribution. |
|
27 # 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of |
|
28 # its contributors may be used to endorse or promote products derived |
|
29 # from this software without specific prior written permission. |
|
30 # |
|
31 # THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY |
|
32 # EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
|
33 # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
|
34 # DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY |
|
35 # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
|
36 # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
|
37 # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
|
38 # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
|
39 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
|
40 # THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|
41 |
|
42 # "unpatch" script for Web Kit Open Source Project, used to remove patches. |
|
43 |
|
44 # Differences from invoking "patch -p0 -R": |
|
45 # |
|
46 # Handles added files (does a svn rm). |
|
47 # Handles added directories (does a svn rm and a rmdir). |
|
48 # Handles removed files (does a svn revert). |
|
49 # Handles removed directories (does a svn revert). |
|
50 # Paths from Index: lines are used rather than the paths on the patch lines, which |
|
51 # makes patches generated by "cvs diff" work (increasingly unimportant since we |
|
52 # use Subversion now). |
|
53 # ChangeLog patches use --fuzz=3 to prevent rejects. |
|
54 # Handles binary files (requires patches made by svn-create-patch). |
|
55 # |
|
56 # Missing features: |
|
57 # |
|
58 # Handle property changes. |
|
59 # Handle file moves (would require patches made by svn-create-patch). |
|
60 # Use version numbers in the patch file and do a 3-way merge. |
|
61 # When reversing an addition, check that the file matches what's being removed. |
|
62 # Notice a patch that's being unapplied at the "wrong level" and make it work anyway. |
|
63 # Do a dry run on the whole patch and don't do anything if part of the patch is |
|
64 # going to fail (probably too strict unless we exclude ChangeLog). |
|
65 |
|
66 use strict; |
|
67 use warnings; |
|
68 |
|
69 use Cwd; |
|
70 use File::Basename; |
|
71 use File::Spec; |
|
72 use Getopt::Long; |
|
73 use FindBin qw($Bin); |
|
74 |
|
75 sub patch($); |
|
76 sub revertDirectories(); |
|
77 sub svnStatus($); |
|
78 sub unapplyPatch($$;$); |
|
79 |
|
80 my $showHelp = 0; |
|
81 if (!GetOptions("help!" => \$showHelp) || $showHelp) { |
|
82 print STDERR basename($0) . " [-h|--help] patch1 [patch2 ...]\n"; |
|
83 exit 1; |
|
84 } |
|
85 |
|
86 my $patch_cmd = "$Bin\\patch.exe"; |
|
87 |
|
88 my %directoriesToCheck; |
|
89 |
|
90 my $indexPath; |
|
91 my $patch; |
|
92 while (<>) { |
|
93 s/\r//g; |
|
94 chomp; |
|
95 if (/^Index: (.*)/) { |
|
96 $indexPath = $1; |
|
97 if ($patch) { |
|
98 patch($patch); |
|
99 $patch = ""; |
|
100 } |
|
101 } |
|
102 if ($indexPath) { |
|
103 # Fix paths on diff, ---, and +++ lines to match preceding Index: line. |
|
104 s/^--- \S+/--- $indexPath/; |
|
105 if (s/^\+\+\+ \S+/+++ $indexPath/) { |
|
106 $indexPath = ""; |
|
107 } |
|
108 } |
|
109 $patch .= $_; |
|
110 $patch .= "\n"; |
|
111 } |
|
112 patch($patch); |
|
113 |
|
114 revertDirectories(); |
|
115 |
|
116 exit 0; |
|
117 |
|
118 sub patch($) |
|
119 { |
|
120 my ($patch) = @_; |
|
121 return if !$patch; |
|
122 |
|
123 $patch =~ m|^Index: ([^\n]+)| or die "Failed to find Index: in \"$patch\"\n"; |
|
124 my $fullPath = $1; |
|
125 $directoriesToCheck{dirname($fullPath)} = 1; |
|
126 |
|
127 my $deletion = 0; |
|
128 my $addition = 0; |
|
129 my $isBinary = 0; |
|
130 |
|
131 $addition = 1 if $patch =~ /\n--- .+\(revision 0\)\n/; |
|
132 $deletion = 1 if $patch =~ /\n@@ .* \+0,0 @@/; |
|
133 $isBinary = 1 if $patch =~ /\nCannot display: file marked as a binary type\./; |
|
134 |
|
135 if (!$addition && !$deletion && !$isBinary) { |
|
136 # Standard patch, patch tool can handle this. |
|
137 if (basename($fullPath) eq "ChangeLog") { |
|
138 my $changeLogDotOrigExisted = -f "${fullPath}.orig"; |
|
139 unapplyPatch($patch, $fullPath, ["--fuzz=3"]); |
|
140 unlink("${fullPath}.orig") if (! $changeLogDotOrigExisted); |
|
141 } else { |
|
142 unapplyPatch($patch, $fullPath); |
|
143 } |
|
144 } else { |
|
145 # Either a deletion, an addition or a binary change. |
|
146 |
|
147 # Reverse change by deleting current copy if it exists first |
|
148 unlink($fullPath) if (-e $fullPath); |
|
149 |
|
150 # Then run svn revert |
|
151 system "svn", "revert", $fullPath; |
|
152 } |
|
153 } |
|
154 |
|
155 sub revertDirectories() |
|
156 { |
|
157 my %checkedDirectories; |
|
158 foreach my $path (reverse sort keys %directoriesToCheck) { |
|
159 my @dirs = File::Spec->splitdir($path); |
|
160 while (scalar @dirs) { |
|
161 my $dir = File::Spec->catdir(@dirs); |
|
162 pop(@dirs); |
|
163 next if (exists $checkedDirectories{$dir}); |
|
164 if (-d $dir) { |
|
165 my $svnOutput = svnStatus($dir); |
|
166 if ($svnOutput && substr($svnOutput, 0, 1) eq "A") { |
|
167 system "svn", "revert", $dir; |
|
168 rmdir $dir; |
|
169 } |
|
170 elsif ($svnOutput && substr($svnOutput, 0, 1) eq "D") { |
|
171 system "svn", "revert", $dir; |
|
172 } |
|
173 else { |
|
174 # Modification |
|
175 print $svnOutput if $svnOutput; |
|
176 } |
|
177 $checkedDirectories{$dir} = 1; |
|
178 } |
|
179 else { |
|
180 die "'$dir' is not a directory"; |
|
181 } |
|
182 } |
|
183 } |
|
184 } |
|
185 |
|
186 sub svnStatus($) |
|
187 { |
|
188 my ($fullPath) = @_; |
|
189 open SVN, "svn status --non-interactive --non-recursive $fullPath |" or die; |
|
190 my $svnStatus = <SVN>; |
|
191 close SVN; |
|
192 return $svnStatus; |
|
193 } |
|
194 |
|
195 sub unapplyPatch($$;$) |
|
196 { |
|
197 my ($patch, $fullPath, $options) = @_; |
|
198 $options = [] if (! $options); |
|
199 my $command = "$patch_cmd " . join(" ", "-p0", "-R", @{$options}); |
|
200 open PATCH, "| $command" or die "Failed to patch $fullPath\n"; |
|
201 print PATCH $patch; |
|
202 close PATCH; |
|
203 } |
|
204 |
|
205 __END__ |
|
206 :endofperl |