diff options
author | Ben Murdoch <benm@google.com> | 2009-08-11 17:01:47 +0100 |
---|---|---|
committer | Ben Murdoch <benm@google.com> | 2009-08-11 18:21:02 +0100 |
commit | 0bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5 (patch) | |
tree | 2943df35f62d885c89d01063cc528dd73b480fea /WebKitTools/Scripts/svn-apply | |
parent | 7e7a70bfa49a1122b2597a1e6367d89eb4035eca (diff) | |
download | external_webkit-0bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5.zip external_webkit-0bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5.tar.gz external_webkit-0bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5.tar.bz2 |
Merge in WebKit r47029.
Diffstat (limited to 'WebKitTools/Scripts/svn-apply')
-rwxr-xr-x | WebKitTools/Scripts/svn-apply | 167 |
1 files changed, 132 insertions, 35 deletions
diff --git a/WebKitTools/Scripts/svn-apply b/WebKitTools/Scripts/svn-apply index 009bdd0..4b88a37 100755 --- a/WebKitTools/Scripts/svn-apply +++ b/WebKitTools/Scripts/svn-apply @@ -7,13 +7,13 @@ # are met: # # 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. +# 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. +# 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 @@ -59,7 +59,6 @@ use strict; use warnings; -use Cwd; use Digest::MD5; use File::Basename; use File::Spec; @@ -67,6 +66,10 @@ use Getopt::Long; use MIME::Base64; use POSIX qw(strftime); +use FindBin; +use lib $FindBin::Bin; +use VCSUtils; + sub addDirectoriesIfNeeded($); sub applyPatch($$;$); sub checksum($); @@ -79,20 +82,41 @@ sub removeDirectoriesIfNeeded(); sub setChangeLogDateAndReviewer($$); sub svnStatus($); +# These should be replaced by an scm class/module: +sub scmKnowsOfFile($); +sub scmCopy($$); +sub scmAdd($); +sub scmRemove($); + + # Project time zone for Cupertino, CA, US my $changeLogTimeZone = "PST8PDT"; my $merge = 0; my $showHelp = 0; my $reviewer; -if (!GetOptions("merge!" => \$merge, "help!" => \$showHelp, "reviewer=s" => \$reviewer) || $showHelp) { - print STDERR basename($0) . " [-h|--help] [-m|--merge] [-r|--reviewer name] patch1 [patch2 ...]\n"; +my $force = 0; + +my $optionParseSuccess = GetOptions( + "merge!" => \$merge, + "help!" => \$showHelp, + "reviewer=s" => \$reviewer, + "force!" => \$force +); + +if (!$optionParseSuccess || $showHelp) { + print STDERR basename($0) . " [-h|--help] [--force] [-m|--merge] [-r|--reviewer name] patch1 [patch2 ...]\n"; exit 1; } +my $isGit = isGitDirectory("."); +my $isSVN = isSVNDirectory("."); +$isSVN || $isGit || die "Couldn't determine your version control system."; + my %removeDirectoryIgnoreList = ( '.' => 1, '..' => 1, + '.git' => 1, '.svn' => 1, '_svn' => 1, ); @@ -148,6 +172,8 @@ if ($patch && !$copiedFromPath) { } if ($merge) { + die "--merge is currently only supported for SVN" unless $isSVN; + # How do we handle Git patches applied to an SVN checkout here? for my $file (sort keys %versions) { print "Getting version $versions{$file} of $file\n"; system "svn", "update", "-r", $versions{$file}, $file; @@ -157,7 +183,7 @@ if ($merge) { # Handle copied and moved files first since moved files may have their source deleted before the move. for my $file (keys %copiedFiles) { addDirectoriesIfNeeded(dirname($file)); - system "svn", "copy", $copiedFiles{$file}, $file; + scmCopy($copiedFiles{$file}, $file); } for $patch (@patches) { @@ -178,18 +204,21 @@ sub addDirectoriesIfNeeded($) next if exists $checkedDirectories{$dir}; if (! -e $dir) { mkdir $dir or die "Failed to create required directory '$dir' for path '$path'\n"; - system "svn", "add", $dir; + scmAdd($dir); $checkedDirectories{$dir} = 1; } elsif (-d $dir) { - my $svnOutput = svnStatus($dir); - if ($svnOutput && $svnOutput =~ m#\?\s+$dir\n#) { - system "svn", "add", $dir; + # SVN prints "svn: warning: 'directory' is already under version control" + # if you try and add a directory which is already in the repository. + # Git will ignore the add, but re-adding large directories can be sloooow. + # So we check first to see if the directory is under version control first. + if (!scmKnowsOfFile($dir)) { + scmAdd($dir); } $checkedDirectories{$dir} = 1; } else { - die "'$dir' is not a directory"; + die "'$dir' exists, but is not a directory"; } } } @@ -202,6 +231,12 @@ sub applyPatch($$;$) open PATCH, "| $command" or die "Failed to patch $fullPath\n"; print PATCH $patch; close PATCH; + + my $exitCode = $? >> 8; + if ($exitCode != 0) { + print "patch -p0 \"$fullPath\" returned $exitCode. Pass --force to ignore patch failures.\n"; + exit($exitCode); + } } sub checksum($) @@ -219,7 +254,7 @@ sub fixChangeLogPatch($) my $patch = shift; my $contextLineCount = 3; - return $patch if $patch !~ /\n@@ -1,(\d+) \+1,(\d+) @@\n( .*\n)+(\+.*\n)+( .*\n){$contextLineCount}$/m; + return $patch if $patch !~ /\n@@ -1,(\d+) \+1,(\d+) @@\r?\n( .*\r?\n)+(\+.*\r?\n)+( .*\r?\n){$contextLineCount}$/m; my ($oldLineCount, $newLineCount) = ($1, $2); return $patch if $oldLineCount <= $contextLineCount; @@ -290,17 +325,13 @@ sub handleBinaryChange($$) open FILE, ">", $fullPath or die; print FILE decode_base64($1); close FILE; - my $svnOutput = svnStatus($fullPath); - if ($svnOutput && substr($svnOutput, 0, 1) eq "?") { + if (!scmKnowsOfFile($fullPath)) { # Addition - system "svn", "add", $fullPath; - } else { - # Modification - print $svnOutput if $svnOutput; + scmAdd($fullPath); } } else { # Deletion - system "svn", "rm", $fullPath; + scmRemove($fullPath); } } @@ -314,8 +345,7 @@ sub isDirectoryEmptyForRemoval($) if (! -d File::Spec->catdir($dir, $item)) { $directoryIsEmpty = 0; } else { - my $svnOutput = svnStatus(File::Spec->catdir($dir, $item)); - next if $svnOutput && substr($svnOutput, 0, 1) eq "D"; + next if (scmWillDeleteFile(File::Spec->catdir($dir, $item))); $directoryIsEmpty = 0; } } @@ -328,7 +358,7 @@ sub patch($) my ($patch) = @_; return if !$patch; - unless ($patch =~ m|^Index: ([^\n]+)|) { + unless ($patch =~ m|^Index: ([^\r\n]+)|) { my $separator = '-' x 67; warn "Failed to find 'Index:' in:\n$separator\n$patch\n$separator\n"; return; @@ -339,7 +369,7 @@ sub patch($) my $addition = 0; my $isBinary = 0; - $addition = 1 if ($patch =~ /\n--- .+\(revision 0\)\n/ || $patch =~ /\n@@ -0,0 .* @@/); + $addition = 1 if ($patch =~ /\n--- .+\(revision 0\)\r?\n/ || $patch =~ /\n@@ -0,0 .* @@/); $deletion = 1 if $patch =~ /\n@@ .* \+0,0 @@/; $isBinary = 1 if $patch =~ /\nCannot display: file marked as a binary type\./; @@ -363,14 +393,15 @@ sub patch($) } elsif ($deletion) { # Deletion applyPatch($patch, $fullPath, ["--force"]); - system "svn", "rm", "--force", $fullPath; + scmRemove($fullPath); } else { # Addition rename($fullPath, "$fullPath.orig") if -e $fullPath; applyPatch($patch, $fullPath); unlink("$fullPath.orig") if -e "$fullPath.orig" && checksum($fullPath) eq checksum("$fullPath.orig"); - system "svn", "add", $fullPath; - system "svn", "stat", "$fullPath.orig" if -e "$fullPath.orig"; + scmAdd($fullPath); + # What is this for? + system "svn", "stat", "$fullPath.orig" if $isSVN && -e "$fullPath.orig"; } } } @@ -379,14 +410,7 @@ sub removeDirectoriesIfNeeded() { foreach my $dir (reverse sort keys %checkedDirectories) { if (isDirectoryEmptyForRemoval($dir)) { - my $svnOutput; - open SVN, "svn rm '$dir' |" or die; - # Only save the last line since Subversion lists all changed statuses below $dir - while (<SVN>) { - $svnOutput = $_; - } - close SVN; - print $svnOutput if $svnOutput; + scmRemove($dir); } } } @@ -423,7 +447,8 @@ sub svnStatus($) # be first (since any files with unknown status will be listed first). my $normalizedFullPath = File::Spec->catdir(File::Spec->splitdir($fullPath)); while (<SVN>) { - chomp; + # Input may use a different EOL sequence than $/, so avoid chomp. + $_ =~ s/[\r\n]+$//g; my $normalizedStatPath = File::Spec->catdir(File::Spec->splitdir(substr($_, 7))); if ($normalizedFullPath eq $normalizedStatPath) { $svnStatus = $_; @@ -441,3 +466,75 @@ sub svnStatus($) close SVN; return $svnStatus; } + +# This could be made into a more general "status" call, except svn and git +# have different ideas about "moving" files which might get confusing. +sub scmWillDeleteFile($) +{ + my ($path) = @_; + if ($isSVN) { + my $svnOutput = svnStatus($path); + return 1 if $svnOutput && substr($svnOutput, 0, 1) eq "D"; + } elsif ($isGit) { + my $gitOutput = `git diff-index --name-status HEAD -- $path`; + return 1 if $gitOutput && substr($gitOutput, 0, 1) eq "D"; + } + return 0; +} + +sub scmKnowsOfFile($) +{ + my ($path) = @_; + if ($isSVN) { + my $svnOutput = svnStatus($path); + # This will match more than intended. ? might not be the first field in the status + if ($svnOutput && $svnOutput =~ m#\?\s+$path\n#) { + return 0; + } + # This does not handle errors well. + return 1; + } elsif ($isGit) { + `git ls-files --error-unmatch -- $path`; + my $exitCode = $? >> 8; + return $exitCode == 0; + } +} + +sub scmCopy($$) +{ + my ($source, $destination) = @_; + if ($isSVN) { + system "svn", "copy", $source, $destination; + } elsif ($isGit) { + system "cp", $source, $destination; + system "git", "add", $destination; + } +} + +sub scmAdd($) +{ + my ($path) = @_; + if ($isSVN) { + system "svn", "add", $path; + } elsif ($isGit) { + system "git", "add", $path; + } +} + +sub scmRemove($) +{ + my ($path) = @_; + if ($isSVN) { + # SVN is very verbose when removing directories. Squelch all output except the last line. + my $svnOutput; + open SVN, "svn rm --force '$path' |" or die "svn rm --force '$path' failed!"; + # Only print the last line. Subversion outputs all changed statuses below $dir + while (<SVN>) { + $svnOutput = $_; + } + close SVN; + print $svnOutput if $svnOutput; + } elsif ($isGit) { + system "git", "rm", "--force", $path; + } +} |