| #!/usr/bin/perl -w |
| |
| # Copyright (C) 2005, 2006 Apple Computer, Inc. All rights reserved. |
| # |
| # Redistribution and use in source and binary forms, with or without |
| # modification, are permitted provided that the following conditions |
| # are met: |
| # |
| # 1. Redistributions of source code must retain the above copyright |
| # notice, this list of conditions and the following disclaimer. |
| # 2. Redistributions in binary form must reproduce the above copyright |
| # notice, this list of conditions and the following disclaimer in the |
| # documentation and/or other materials provided with the distribution. |
| # 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of |
| # its contributors may be used to endorse or promote products derived |
| # from this software without specific prior written permission. |
| # |
| # THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY |
| # EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
| # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
| # DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY |
| # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
| # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
| # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
| # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
| # THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| |
| # "patch" script for WebKit Open Source Project, used to apply patches. |
| |
| # Differences from invoking "patch -p0": |
| # |
| # Handles added files (does a svn add). |
| # Handles removed files (does a svn rm). |
| # Has mode where it will roll back to svn version numbers in the patch file so svn |
| # can do a 3-way merge. |
| # Paths from Index: lines are used rather than the paths on the patch lines, which |
| # makes patches generated by "cvs diff" work (increasingly unimportant since we |
| # use Subversion now). |
| # ChangeLog patches use --fuzz=3 to prevent rejects. |
| # |
| # Missing features: |
| # |
| # Handle property changes. |
| # Handle binary files (requires patches made by svn-create-patch). |
| # Handle file moves (requires patches made by svn-create-patch). |
| # When doing a removal, check that old file matches what's being removed. |
| # Notice a patch that's being applied at the "wrong level" and make it work anyway. |
| # Do a dry run on the whole patch and don't do anything if part of the patch is |
| # going to fail (probably too strict unless we do the ChangeLog thing). |
| |
| use strict; |
| use Cwd; |
| use Getopt::Long; |
| |
| my $merge = 0; |
| GetOptions("merge" => \$merge); |
| |
| my $startDir = getcwd(); |
| |
| my @patches; |
| my %versions; |
| |
| my $indexPath; |
| my $patch; |
| while (<>) { |
| s/\r//g; |
| chomp; |
| if (/^Index: (.+)/) { |
| $indexPath = $1; |
| if ($patch) { |
| push @patches, $patch; |
| $patch = ""; |
| } |
| } |
| if ($indexPath) { |
| # Fix paths on diff, ---, and +++ lines to match preceding Index: line. |
| s/\S+$/$indexPath/ if /^diff/; |
| s/^--- \S+/--- $indexPath/; |
| if (s/^\+\+\+ \S+/+++ $indexPath/) { |
| $indexPath = ""; |
| } |
| } |
| if (/^--- .+\(revision (\d+)\)$/) { |
| $versions{$indexPath} = $1 if( $1 != 0 ); |
| } |
| $patch .= $_; |
| $patch .= "\n"; |
| } |
| |
| push @patches, $patch if $patch; |
| |
| if ($merge) { |
| for my $file (sort keys %versions) { |
| print "Getting version $versions{$file} of $file\n"; |
| $file =~ m|^(([^/\n]*/)*)([^/\n]+)$| or die; |
| my ($prefix, $base) = ($1, $3); |
| if ($prefix) { |
| chdir $prefix or die; |
| } |
| system "svn update -r $versions{$file} $base"; |
| chdir $startDir; |
| } |
| } |
| |
| for $patch (@patches) { |
| patch($patch); |
| } |
| |
| sub applyPatch |
| { |
| my ($patch, $fullpath, $options) = @_; |
| $options = [] if (! $options); |
| my $command = "patch " . join(" ", "-p0", @{$options}); |
| open PATCH, "| $command" or die "Failed to patch $fullpath\n"; |
| print PATCH $patch; |
| close PATCH; |
| } |
| |
| sub patch |
| { |
| my ($patch) = @_; |
| return if !$patch; |
| |
| $patch =~ m|^Index: ((([^/\n]*/)*)([^/\n]+))| or die "Failed to find Index: in \"$patch\"\n"; |
| my ($fullpath, $prefix, $base) = ($1, $2, $4); |
| |
| my $deletion = 0; |
| my $addition = 0; |
| |
| $addition = 1 if $patch =~ /\n--- .+\(revision 0\)\n/; |
| $deletion = 1 if $patch =~ /\n@@ .* \+0,0 @@/; |
| |
| if (!$addition && !$deletion) { |
| # Standard patch, patch tool can handle this. |
| if ($base eq "ChangeLog") { |
| my $changeLogDotOrigExisted = -f "${fullpath}.orig"; |
| applyPatch($patch, $fullpath, ["--fuzz=3"]); |
| unlink("${fullpath}.orig") if (! $changeLogDotOrigExisted); |
| } |
| else { |
| applyPatch($patch, $fullpath); |
| } |
| } else { |
| # Either a deletion or an addition. |
| |
| # Change directory down into the directory in question. |
| chdirAddingDirectoriesIfNeeded($prefix); |
| |
| if ($deletion) { |
| # Deletion. |
| system "svn", "rm", $base; |
| } else { |
| # Addition. |
| my $file = $patch; |
| if ($file !~ s/^(.*\n)*@@[^\n]+@@\n//) { |
| # Empty file. |
| $file = ""; |
| } else { |
| # Non-empty file: Remove leading + signs. |
| $file =~ s/^\+//; |
| $file =~ s/\n\+/\n/g; |
| } |
| open FILE, ">", $base or die; |
| print FILE $file; |
| close FILE; |
| system "svn", "add", "$base"; |
| } |
| |
| chdir $startDir if $prefix; |
| } |
| } |
| |
| sub chdirAddingDirectoriesIfNeeded |
| { |
| my $path = shift; |
| my @dirs = split('/', $path); |
| while (my $dir = shift @dirs) { |
| if (!-x $dir) { |
| mkdir $dir or die "Failed create required directory: $dir for path: $path\n"; |
| system "svn", "add", "$dir"; |
| } |
| chdir $dir or die "Failed to chdir to $dir\n"; |
| } |
| } |