3 # Copyright (C) 2005, 2006 Apple Computer, Inc. All rights reserved.
5 # Redistribution and use in source and binary forms, with or without
6 # modification, are permitted provided that the following conditions
9 # 1. Redistributions of source code must retain the above copyright
10 # notice, this list of conditions and the following disclaimer.
11 # 2. Redistributions in binary form must reproduce the above copyright
12 # notice, this list of conditions and the following disclaimer in the
13 # documentation and/or other materials provided with the distribution.
14 # 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
15 # its contributors may be used to endorse or promote products derived
16 # from this software without specific prior written permission.
18 # THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
19 # EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 # DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
22 # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25 # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 # THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 # "patch" script for WebKit Open Source Project, used to apply patches.
31 # Differences from invoking "patch -p0":
33 # Handles added files (does a svn add).
34 # Handles removed files (does a svn rm).
35 # Has mode where it will roll back to svn version numbers in the patch file so svn
36 # can do a 3-way merge.
37 # Paths from Index: lines are used rather than the paths on the patch lines, which
38 # makes patches generated by "cvs diff" work (increasingly unimportant since we
39 # use Subversion now).
40 # ChangeLog patches use --fuzz=3 to prevent rejects.
41 # Handles binary files (requires patches made by svn-create-patch).
45 # Handle property changes.
46 # Handle file moves (requires patches made by svn-create-patch).
47 # When doing a removal, check that old file matches what's being removed.
48 # Notice a patch that's being applied at the "wrong level" and make it work anyway.
49 # Do a dry run on the whole patch and don't do anything if part of the patch is
50 # going to fail (probably too strict unless we do the ChangeLog thing).
58 GetOptions("merge" => \$merge);
60 my $startDir = getcwd();
73 push @patches, $patch;
78 # Fix paths on diff, ---, and +++ lines to match preceding Index: line.
79 s/\S+$/$indexPath/ if /^diff/;
80 s/^--- \S+/--- $indexPath/;
81 if (s/^\+\+\+ \S+/+++ $indexPath/) {
85 if (/^--- .+\(revision (\d+)\)$/) {
86 $versions{$indexPath} = $1 if( $1 != 0 );
92 push @patches, $patch if $patch;
95 for my $file (sort keys %versions) {
96 print "Getting version $versions{$file} of $file\n";
97 $file =~ m|^(([^/\n]*/)*)([^/\n]+)$| or die;
98 my ($prefix, $base) = ($1, $3);
100 chdir $prefix or die;
102 system "svn update -r $versions{$file} $base";
107 for $patch (@patches) {
113 my ($patch, $fullpath, $options) = @_;
114 $options = [] if (! $options);
115 my $command = "patch " . join(" ", "-p0", @{$options});
116 open PATCH, "| $command" or die "Failed to patch $fullpath\n";
126 $patch =~ m|^Index: ((([^/\n]*/)*)([^/\n]+))| or die "Failed to find Index: in \"$patch\"\n";
127 my ($fullpath, $prefix, $base) = ($1, $2, $4);
133 $addition = 1 if $patch =~ /\n--- .+\(revision 0\)\n/;
134 $deletion = 1 if $patch =~ /\n@@ .* \+0,0 @@/;
135 $isBinary = 1 if $patch =~ /\nCannot display: file marked as a binary type\./;
137 if (!$addition && !$deletion && !$isBinary) {
138 # Standard patch, patch tool can handle this.
139 if ($base eq "ChangeLog") {
140 my $changeLogDotOrigExisted = -f "${fullpath}.orig";
141 applyPatch($patch, $fullpath, ["--fuzz=3"]);
142 unlink("${fullpath}.orig") if (! $changeLogDotOrigExisted);
144 applyPatch($patch, $fullpath);
147 # Either a deletion, an addition or a binary change.
149 # Change directory down into the directory in question.
150 chdirAddingDirectoriesIfNeeded($prefix);
154 handleBinaryChange($base, $patch);
155 } elsif ($deletion) {
157 system "svn", "rm", $base;
160 my $contents = $patch;
161 if ($contents !~ s/^(.*\n)*@@[^\n]+@@\n//) {
165 # Non-empty contents: Remove leading + signs.
166 $contents =~ s/^\+//;
167 $contents =~ s/\n\+/\n/g;
169 open FILE, ">", $base or die;
170 print FILE $contents;
172 system "svn", "add", "$base";
175 chdir $startDir if $prefix;
179 sub handleBinaryChange
181 my ($base, $contents) = @_;
182 if ($contents =~ m#((\n[A-Za-z0-9+/]{76})+\n[A-Za-z0-9+/=]{4,76}\n)\n#) {
183 # Addition or Modification
184 open FILE, ">", $base or die;
185 print FILE decode_base64($1);
187 open SVN, "svn stat '$base' |" or die;
188 my $svnStatus = <SVN>;
190 if (substr($svnStatus, 0 ,1) eq "?") {
192 system "svn", "add", "$base";
199 system "svn", "rm", "$base";
203 sub chdirAddingDirectoriesIfNeeded
206 my @dirs = split('/', $path);
207 while (my $dir = shift @dirs) {
209 mkdir $dir or die "Failed create required directory: $dir for path: $path\n";
210 system "svn", "add", "$dir";
212 chdir $dir or die "Failed to chdir to $dir\n";