diff options
Diffstat (limited to 'WebKitTools/Scripts')
62 files changed, 11419 insertions, 0 deletions
diff --git a/WebKitTools/Scripts/SpacingHeuristics.pm b/WebKitTools/Scripts/SpacingHeuristics.pm new file mode 100644 index 0000000..7de0172 --- /dev/null +++ b/WebKitTools/Scripts/SpacingHeuristics.pm @@ -0,0 +1,101 @@ +#!/usr/bin/perl -w + +# Copyright (C) 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. + +# Used for helping remove extra blank lines from files when processing. +# see split-class for an example usage (or other scripts in bugzilla) + +BEGIN { + use Exporter (); + our ($VERSION, @ISA, @EXPORT, @EXPORT_OK, %EXPORT_TAGS); + $VERSION = 1.00; + @ISA = qw(Exporter); + @EXPORT = qw(&resetSpacingHeuristics &isOnlyWhiteSpace &applySpacingHeuristicsAndPrint &setPreviousAllowedLine &setPreviousAllowedLine &printPendingEmptyLines &ignoringLine); + %EXPORT_TAGS = (); + @EXPORT_OK = (); +} + +our @EXPORT_OK; + +my $justFoundEmptyLine = 0; +my $previousLineWasDisallowed = 0; +my $previousAllowedLine = ""; +my $pendingEmptyLines = ""; + +sub resetSpacingHeuristics +{ + $justFoundEmptyLine = 0; + $previousLineWasDisallowed = 0; + $previousAllowedLine = ""; + $pendingEmptyLines = ""; +} + +sub isOnlyWhiteSpace +{ + my $line = shift; + my $isOnlyWhiteSpace = ($line =~ m/^\s+$/); + $pendingEmptyLines .= $line if ($isOnlyWhiteSpace); + return $isOnlyWhiteSpace; +} + +sub applySpacingHeuristicsAndPrint +{ + my ($out, $line) = @_; + + printPendingEmptyLines($out, $line); + $previousLineWasDisallowed = 0; + print $out $line; +} + +sub setPreviousAllowedLine +{ + my $line = shift; + $previousAllowedLine = $line; +} + +sub printPendingEmptyLines +{ + my $out = shift; + my $line = shift; + if ($previousLineWasDisallowed) { + if (!($pendingEmptyLines eq "") && !($previousAllowedLine =~ m/{\s*$/) && !($line =~ m/^\s*}/)) { + $pendingEmptyLines = "\n"; + } else { + $pendingEmptyLines = ""; + } + } + print $out $pendingEmptyLines; + $pendingEmptyLines = ""; +} + +sub ignoringLine +{ + # my $line = shift; # ignoring input argument + $previousLineWasDisallowed = 1; +} + +1;
\ No newline at end of file diff --git a/WebKitTools/Scripts/VCSUtils.pm b/WebKitTools/Scripts/VCSUtils.pm new file mode 100644 index 0000000..26401f4 --- /dev/null +++ b/WebKitTools/Scripts/VCSUtils.pm @@ -0,0 +1,121 @@ +# Copyright (C) 2007 Apple 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. + +# Module to share code to work with various version control systems. + +use strict; +use warnings; +use File::Spec; +use webkitdirs; + +BEGIN { + use Exporter (); + our ($VERSION, @ISA, @EXPORT, @EXPORT_OK, %EXPORT_TAGS); + $VERSION = 1.00; + @ISA = qw(Exporter); + @EXPORT = qw(&isGitDirectory &isGit &isSVNDirectory &isSVN &makeFilePathRelative); + %EXPORT_TAGS = ( ); + @EXPORT_OK = (); +} + +our @EXPORT_OK; + +my $isGit; +my $isSVN; +my $gitBranch; +my $isGitBranchBuild; + +sub isGitDirectory($) +{ + my ($dir) = @_; + return system("cd $dir && git rev-parse > /dev/null 2>&1") == 0; +} + +sub isGit() +{ + return $isGit if defined $isGit; + + $isGit = isGitDirectory("."); + return $isGit; +} + +sub gitBranch() +{ + unless (defined $gitBranch) { + chomp($gitBranch = `git symbolic-ref -q HEAD`); + $gitBranch = "" if exitStatus($?); + $gitBranch =~ s#^refs/heads/##; + $gitBranch = "" if $gitBranch eq "master"; + } + + return $gitBranch; +} + +sub isGitBranchBuild() +{ + my $branch = gitBranch(); + chomp(my $override = `git config --bool branch.$branch.webKitBranchBuild`); + return 1 if $override eq "true"; + return 0 if $override eq "false"; + + unless (defined $isGitBranchBuild) { + chomp(my $gitBranchBuild = `git config --bool core.webKitBranchBuild`); + $isGitBranchBuild = $gitBranchBuild eq "true"; + } + + return $isGitBranchBuild; +} + +sub isSVNDirectory($) +{ + my ($dir) = @_; + + return -d File::Spec->catdir($dir, ".svn"); +} + +sub isSVN() +{ + return $isSVN if defined $isSVN; + + $isSVN = isSVNDirectory("."); + return $isSVN; +} + +my $gitRoot; +sub makeFilePathRelative($) +{ + my ($path) = @_; + return $path unless isGit(); + + unless (defined $gitRoot) { + chomp($gitRoot = `git rev-parse --git-dir`); + $gitRoot =~ s/\.git$//; + } + my $result = File::Spec->abs2rel(File::Spec->rel2abs($path, $gitRoot)); + return $result; +} + +1; diff --git a/WebKitTools/Scripts/bisect-builds b/WebKitTools/Scripts/bisect-builds new file mode 100755 index 0000000..43e3889 --- /dev/null +++ b/WebKitTools/Scripts/bisect-builds @@ -0,0 +1,417 @@ +#!/usr/bin/perl -w + +# Copyright (C) 2007 Apple 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. + +# This script attempts to find the point at which a regression (or progression) +# of behavior occurred by searching WebKit nightly builds. + +# To override the location where the nightly builds are downloaded or the path +# to the Safari web browser, create a ~/.bisect-buildsrc file with one or more of +# the following lines (use "~/" to specify a path from your home directory): +# +# $branch = "branch-name"; +# $nightlyDownloadDirectory = "~/path/to/nightly/downloads"; +# $safariPath = "/path/to/Safari.app"; + +use strict; + +use File::Basename; +use File::Path; +use File::Spec; +use File::Temp; +use Getopt::Long; +use Time::HiRes qw(usleep); + +sub createTempFile($); +sub downloadNightly($$$); +sub findMacOSXVersion(); +sub findNearestNightlyIndex(\@$$); +sub findSafariVersion($); +sub loadSettings(); +sub makeNightlyList($$$$); +sub mountAndRunNightly($$$$); +sub parseRevisions($$;$); +sub printStatus($$$); +sub promptForTest($); + +loadSettings(); + +my %validBranches = map { $_ => 1 } qw(feature-branch trunk); +my $branch = $Settings::branch; +my $nightlyDownloadDirectory = $Settings::nightlyDownloadDirectory; +my $safariPath = $Settings::safariPath; + +my @nightlies; + +my $isProgression; +my $localOnly; +my @revisions; +my $sanityCheck; +my $showHelp; +my $testURL; + +# Fix up -r switches in @ARGV +@ARGV = map { /^(-r)(.+)$/ ? ($1, $2) : $_ } @ARGV; + +my $result = GetOptions( + "b|branch=s" => \$branch, + "d|download-directory=s" => \$nightlyDownloadDirectory, + "h|help" => \$showHelp, + "l|local!" => \$localOnly, + "p|progression!" => \$isProgression, + "r|revisions=s" => \&parseRevisions, + "safari-path=s" => \$safariPath, + "s|sanity-check!" => \$sanityCheck, +); +$testURL = shift @ARGV; + +$branch = "feature-branch" if $branch eq "feature"; +if (!exists $validBranches{$branch}) { + print STDERR "ERROR: Invalid branch '$branch'\n"; + $showHelp = 1; +} + +if (!$result || $showHelp || scalar(@ARGV) > 0) { + print STDERR "Search WebKit nightly builds for changes in behavior.\n"; + print STDERR "Usage: " . basename($0) . " [options] [url]\n"; + print STDERR <<END; + [-b|--branch name] name of the nightly build branch (default: trunk) + [-d|--download-directory dir] nightly build download directory (default: ~/Library/Caches/WebKit-Nightlies) + [-h|--help] show this help message + [-l|--local] only use local (already downloaded) nightlies + [-p|--progression] searching for a progression, not a regression + [-r|--revision M[:N]] specify starting (and optional ending) revisions to search + [--safari-path path] path to Safari application bundle (default: /Applications/Safari.app) + [-s|--sanity-check] verify both starting and ending revisions before bisecting +END + exit 1; +} + +my $nightlyWebSite = "http://nightly.webkit.org"; +my $nightlyBuildsURLBase = $nightlyWebSite . File::Spec->catdir("/builds", $branch, "mac"); +my $nightlyFilesURLBase = $nightlyWebSite . File::Spec->catdir("/files", $branch, "mac"); + +$nightlyDownloadDirectory = glob($nightlyDownloadDirectory) if $nightlyDownloadDirectory =~ /^~/; +$safariPath = glob($safariPath) if $safariPath =~ /^~/; +$safariPath = File::Spec->catdir($safariPath, "Contents/MacOS/Safari") if $safariPath =~ m#\.app/*#; + +$nightlyDownloadDirectory = File::Spec->catdir($nightlyDownloadDirectory, $branch); +if (! -d $nightlyDownloadDirectory) { + mkpath($nightlyDownloadDirectory, 0, 0755) || die "Could not create $nightlyDownloadDirectory: $!"; +} + +@nightlies = makeNightlyList($localOnly, $nightlyDownloadDirectory, findMacOSXVersion(), findSafariVersion($safariPath)); + +my $startIndex = $revisions[0] ? findNearestNightlyIndex(@nightlies, $revisions[0], 'ceil') : 0; +my $endIndex = $revisions[1] ? findNearestNightlyIndex(@nightlies, $revisions[1], 'floor') : $#nightlies; + +my $tempFile = createTempFile($testURL); + +if ($sanityCheck) { + my $didReproduceBug; + + do { + printf "\nChecking starting revision (r%s)...\n", + $nightlies[$startIndex]->{rev}; + downloadNightly($nightlies[$startIndex]->{file}, $nightlyFilesURLBase, $nightlyDownloadDirectory); + mountAndRunNightly($nightlies[$startIndex]->{file}, $nightlyDownloadDirectory, $safariPath, $tempFile); + $didReproduceBug = promptForTest($nightlies[$startIndex]->{rev}); + $startIndex-- if $didReproduceBug < 0; + } while ($didReproduceBug < 0); + die "ERROR: Bug reproduced in starting revision! Do you need to test an earlier revision or for a progression?" + if $didReproduceBug && !$isProgression; + die "ERROR: Bug not reproduced in starting revision! Do you need to test an earlier revision or for a regression?" + if !$didReproduceBug && $isProgression; + + do { + printf "\nChecking ending revision (r%s)...\n", + $nightlies[$endIndex]->{rev}; + downloadNightly($nightlies[$endIndex]->{file}, $nightlyFilesURLBase, $nightlyDownloadDirectory); + mountAndRunNightly($nightlies[$endIndex]->{file}, $nightlyDownloadDirectory, $safariPath, $tempFile); + $didReproduceBug = promptForTest($nightlies[$endIndex]->{rev}); + $endIndex++ if $didReproduceBug < 0; + } while ($didReproduceBug < 0); + die "ERROR: Bug NOT reproduced in ending revision! Do you need to test a later revision or for a progression?" + if !$didReproduceBug && !$isProgression; + die "ERROR: Bug reproduced in ending revision! Do you need to test a later revision or for a regression?" + if $didReproduceBug && $isProgression; +} + +printStatus($nightlies[$startIndex]->{rev}, $nightlies[$endIndex]->{rev}, $isProgression); + +my %brokenRevisions = (); +while (abs($endIndex - $startIndex) > 1) { + my $index = $startIndex + int(($endIndex - $startIndex) / 2); + + my $didReproduceBug; + do { + if (exists $nightlies[$index]) { + printf "\nChecking revision (r%s)...\n", $nightlies[$index]->{rev}; + downloadNightly($nightlies[$index]->{file}, $nightlyFilesURLBase, $nightlyDownloadDirectory); + mountAndRunNightly($nightlies[$index]->{file}, $nightlyDownloadDirectory, $safariPath, $tempFile); + $didReproduceBug = promptForTest($nightlies[$index]->{rev}); + } + if ($didReproduceBug < 0) { + $brokenRevisions{$nightlies[$index]->{rev}} = $nightlies[$index]->{file}; + delete $nightlies[$index]; + $endIndex--; + $index = $startIndex + int(($endIndex - $startIndex) / 2); + } + } while ($didReproduceBug < 0); + + if ($didReproduceBug && !$isProgression || !$didReproduceBug && $isProgression) { + $endIndex = $index; + } else { + $startIndex = $index; + } + + print "\nBroken revisions skipped: r" . join(", r", keys %brokenRevisions) . "\n" + if scalar keys %brokenRevisions > 0; + printStatus($nightlies[$startIndex]->{rev}, $nightlies[$endIndex]->{rev}, $isProgression); +} + +unlink $tempFile if $tempFile; + +exit 0; + +sub createTempFile($) +{ + my ($url) = @_; + + return undef if !$url; + + my $fh = new File::Temp( + DIR => ($ENV{'TMPDIR'} || "/tmp"), + SUFFIX => ".html", + TEMPLATE => basename($0) . "-XXXXXXXX", + UNLINK => 0, + ); + my $tempFile = $fh->filename(); + print $fh "<meta http-equiv=\"refresh\" content=\"0; $url\">\n"; + close($fh); + + return $tempFile; +} + +sub downloadNightly($$$) +{ + my ($filename, $urlBase, $directory) = @_; + my $path = File::Spec->catfile($directory, $filename); + if (! -f $path) { + print "Downloading $filename to $directory...\n"; + `curl -# -o '$path' '$urlBase/$filename'`; + } +} + +sub findMacOSXVersion() +{ + my $version; + open(SW_VERS, "-|", "/usr/bin/sw_vers") || die; + while (<SW_VERS>) { + $version = $1 if /^ProductVersion:\s+([^\s]+)/; + } + close(SW_VERS); + return $version; +} + +sub findNearestNightlyIndex(\@$$) +{ + my ($nightlies, $revision, $round) = @_; + + my $lowIndex = 0; + my $highIndex = $#{$nightlies}; + + return $highIndex if uc($revision) eq 'HEAD' || $revision >= $nightlies->[$highIndex]->{rev}; + return $lowIndex if $revision <= $nightlies->[$lowIndex]->{rev}; + + while (abs($highIndex - $lowIndex) > 1) { + my $index = $lowIndex + int(($highIndex - $lowIndex) / 2); + if ($revision < $nightlies->[$index]->{rev}) { + $highIndex = $index; + } elsif ($revision > $nightlies->[$index]->{rev}) { + $lowIndex = $index; + } else { + return $index; + } + } + + return ($round eq "floor") ? $lowIndex : $highIndex; +} + +sub findSafariVersion($) +{ + my ($path) = @_; + my $versionPlist = File::Spec->catdir(dirname(dirname($path)), "version.plist"); + my $version; + open(PLIST, "< $versionPlist") || die; + while (<PLIST>) { + if (m#^\s*<key>CFBundleShortVersionString</key>#) { + $version = <PLIST>; + $version =~ s#^\s*<string>(.+)</string>\s*[\r\n]*#$1#; + } + } + close(PLIST); + return $version; +} + +sub loadSettings() +{ + package Settings; + + our $branch = "trunk"; + our $nightlyDownloadDirectory = File::Spec->catdir($ENV{HOME}, "Library/Caches/WebKit-Nightlies"); + our $safariPath = "/Applications/Safari.app"; + + my $rcfile = File::Spec->catdir($ENV{HOME}, ".bisect-buildsrc"); + return if !-f $rcfile; + + my $result = do $rcfile; + die "Could not parse $rcfile: $@" if $@; +} + +sub makeNightlyList($$$$) +{ + my ($useLocalFiles, $localDirectory, $macOSXVersion, $safariVersion) = @_; + my @files; + + if ($useLocalFiles) { + opendir(DIR, $localDirectory) || die "$!"; + foreach my $file (readdir(DIR)) { + if ($file =~ /^WebKit-SVN-r([0-9]+)\.dmg$/) { + push(@files, +{ rev => $1, file => $file }); + } + } + closedir(DIR); + } else { + open(NIGHTLIES, "curl -s $nightlyBuildsURLBase/all |") || die; + + while (my $line = <NIGHTLIES>) { + chomp $line; + my ($revision, $timestamp, $url) = split(/,/, $line); + my $nightly = basename($url); + push(@files, +{ rev => $revision, file => $nightly }); + } + close(NIGHTLIES); + } + + if (eval "v$macOSXVersion" ge v10.5) { + if (eval "v$safariVersion" ge v3.0) { + @files = grep { $_->{rev} >= 25124 } @files; + } elsif (eval "v$safariVersion" ge v2.0) { + @files = grep { $_->{rev} >= 19594 } @files; + } else { + die "Requires Safari 2.0 or newer"; + } + } elsif (eval "v$macOSXVersion" ge v10.4) { + if (eval "v$safariVersion" ge v3.0) { + @files = grep { $_->{rev} >= 19992 } @files; + } elsif (eval "v$safariVersion" ge v2.0) { + @files = grep { $_->{rev} >= 11976 } @files; + } else { + die "Requires Safari 2.0 or newer"; + } + } else { + die "Requires Mac OS X 10.4 (Tiger) or 10.5 (Leopard)"; + } + + my $nightlycmp = sub { return $a->{rev} <=> $b->{rev}; }; + + return sort $nightlycmp @files; +} + +sub mountAndRunNightly($$$$) +{ + my ($filename, $directory, $safari, $tempFile) = @_; + my $mountPath = "/Volumes/WebKit"; + my $webkitApp = File::Spec->catfile($mountPath, "WebKit.app"); + my $diskImage = File::Spec->catfile($directory, $filename); + + my $i = 0; + while (-e $mountPath) { + $i++; + usleep 100 if $i > 1; + `hdiutil detach '$mountPath' 2> /dev/null`; + die "Could not unmount $diskImage at $mountPath" if $i > 100; + } + die "Can't mount $diskImage: $mountPath already exists!" if -e $mountPath; + + print "Mounting disk image and running WebKit...\n"; + `hdiutil attach '$diskImage'`; + $i = 0; + while (! -e $webkitApp) { + usleep 100; + $i++; + die "Could not mount $diskImage at $mountPath" if $i > 100; + } + + my $frameworkPath; + if (-d "/Volumes/WebKit/WebKit.app/Contents/Frameworks") { + my $osXVersion = join('.', (split(/\./, findMacOSXVersion()))[0..1]); + $frameworkPath = "/Volumes/WebKit/WebKit.app/Contents/Frameworks/$osXVersion"; + } else { + $frameworkPath = "/Volumes/WebKit/WebKit.app/Contents/Resources"; + } + + $tempFile ||= ""; + `DYLD_FRAMEWORK_PATH=$frameworkPath WEBKIT_UNSET_DYLD_FRAMEWORK_PATH=YES $safari $tempFile`; + + `hdiutil detach '$mountPath' 2> /dev/null`; +} + +sub parseRevisions($$;$) +{ + my ($optionName, $value, $ignored) = @_; + + if ($value =~ /^r?([0-9]+|HEAD):?$/i) { + push(@revisions, $1); + die "Too many revision arguments specified" if scalar @revisions > 2; + } elsif ($value =~ /^r?([0-9]+):?r?([0-9]+|HEAD)$/i) { + $revisions[0] = $1; + $revisions[1] = $2; + } else { + die "Unknown revision '$value': expected 'M' or 'M:N'"; + } +} + +sub printStatus($$$) +{ + my ($startRevision, $endRevision, $isProgression) = @_; + printf "\n%s: r%s %s: r%s\n", + $isProgression ? "Fails" : "Works", $startRevision, + $isProgression ? "Works" : "Fails", $endRevision; +} + +sub promptForTest($) +{ + my ($revision) = @_; + print "Did the bug reproduce in r$revision (yes/no/broken)? "; + my $answer = <STDIN>; + return 1 if $answer =~ /^(1|y.*)$/i; + return -1 if $answer =~ /^(-1|b.*)$/i; # Broken + return 0; +} + diff --git a/WebKitTools/Scripts/build-drawtest b/WebKitTools/Scripts/build-drawtest new file mode 100755 index 0000000..fa9b7c2 --- /dev/null +++ b/WebKitTools/Scripts/build-drawtest @@ -0,0 +1,48 @@ +#!/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. + +# Simplified build script for WebKit Open Source Project. +# Modified copy of build-dumprendertree. Perhaps these could share code. + +use strict; +use FindBin; +use lib $FindBin::Bin; +use webkitdirs; + +checkRequiredSystemConfig(); +setConfiguration(); +chdirWebKit(); +my @options = XcodeOptions(); + +# Check to see that all the frameworks are built (w/ SVG support). +checkFrameworks(); +checkWebCoreSVGSupport(1); + +# Build +chdir "WebKitTools/DrawTest" or die; +exit system "xcodebuild", "-project", "DrawTest.xcodeproj", @options; diff --git a/WebKitTools/Scripts/build-drosera b/WebKitTools/Scripts/build-drosera new file mode 100755 index 0000000..f3b1144 --- /dev/null +++ b/WebKitTools/Scripts/build-drosera @@ -0,0 +1,53 @@ +#!/usr/bin/perl -w + +# Copyright (C) 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. + +# Simplified build script for Web Kit Open Source Project. +# Modified copy of build-webkit. Perhaps these could share code. +# Currently only works for the Deployment build style. + +use strict; +use FindBin; +use lib $FindBin::Bin; +use webkitdirs; +use POSIX; + +checkRequiredSystemConfig(); +setConfiguration(); +chdirWebKit(); +my @options = XcodeOptions(); + +# Build +chdir "WebKitTools/Drosera/mac" or die; +my $result; +if (isOSX()) { + print "xcodebuild -project Drosera.xcodeproj ", join(" ", @options), "\n"; + $result = system "xcodebuild", "-project", "Drosera.xcodeproj", @options; +} else { + die "Building not defined for this platform!\n"; +} +exit exitStatus($result); diff --git a/WebKitTools/Scripts/build-dumprendertree b/WebKitTools/Scripts/build-dumprendertree new file mode 100755 index 0000000..7f48a59 --- /dev/null +++ b/WebKitTools/Scripts/build-dumprendertree @@ -0,0 +1,54 @@ +#!/usr/bin/perl -w + +# Copyright (C) 2005 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. + + +use strict; +use FindBin; +use lib $FindBin::Bin; +use webkitdirs; +use POSIX; + +checkRequiredSystemConfig(); +setConfiguration(); +chdirWebKit(); +my @options = XcodeOptions(); + +# Build +chdir "WebKitTools/DumpRenderTree" or die; +my $result; +if (isOSX()) { + $result = system "xcodebuild", "-project", "DumpRenderTree.xcodeproj", @options; +} elsif (isCygwin()) { + $result = buildVisualStudioProject("DumpRenderTree.sln"); +} elsif (isQt() || isGtk()) { + # Qt and Gtk build everything in one shot. No need to build anything here. + $result = 0; +} else { + die "Building not defined for this platform!\n"; +} +exit exitStatus($result); diff --git a/WebKitTools/Scripts/build-testkjs b/WebKitTools/Scripts/build-testkjs new file mode 100755 index 0000000..5dc28ad --- /dev/null +++ b/WebKitTools/Scripts/build-testkjs @@ -0,0 +1,54 @@ +#!/usr/bin/perl -w + +# Copyright (C) 2005 Apple Computer, Inc. All rights reserved. +# Copyright (C) 2007 Eric Seidel <eric@webkit.org> +# +# 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. + + +use strict; +use FindBin; +use lib $FindBin::Bin; +use webkitdirs; +use POSIX; + +checkRequiredSystemConfig(); +setConfiguration(); +chdirWebKit(); +my @options = XcodeOptions(); + +chdir "JavaScriptCore" or die "Can't find JavaScriptCore directory to build from"; +my $result; +if (isOSX()) { + $result = system "sh", "-c", 'xcodebuild -project JavaScriptCore.xcodeproj -target testkjs "$@" | grep -v setenv && exit ${PIPESTATUS[0]}', "xcodebuild", @options, @ARGV; +} elsif (isCygwin()) { + $result = buildVisualStudioProject("JavaScriptCore.vcproj/JavaScriptCore.sln"); +} elsif (isQt() or isGtk() or isWx()) { + # Qt and Gtk build everything in one-shot. No need to build anything here. + $result = 0; +} else { + die "Building not defined for this platform!\n"; +} +exit exitStatus($result); diff --git a/WebKitTools/Scripts/build-webkit b/WebKitTools/Scripts/build-webkit new file mode 100755 index 0000000..f4c99e6 --- /dev/null +++ b/WebKitTools/Scripts/build-webkit @@ -0,0 +1,351 @@ +#!/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. + +# Simplified build script for Web Kit Open Source Project. + +use strict; +use File::Basename; +use File::Spec; +use FindBin; +use Getopt::Long qw(:config pass_through); +use lib $FindBin::Bin; +use webkitdirs; +use POSIX; + +my $originalWorkingDirectory = getcwd(); + +my $crossDocumentMessagingSupport = 1; +my $databaseSupport = 1; +my $iconDatabaseSupport = 1; +my $svgSupport = 1; +my $svgExperimentalSupport = 0; +my $svgAnimationSupport = $svgExperimentalSupport; +my $svgFiltersSupport = $svgExperimentalSupport; +my $svgForeignObjectSupport = 1; +my $svgUseSupport = 1; +my $svgFontsSupport = 1; +my $svgAsImageSupport = 1; +my $xpathSupport = 1; +my $xsltSupport = 1; +my $coverageSupport = 0; +my $videoSupport = isOSX() || isCygwin(); # Enable by default on OSX and Windows +my $showHelp = 0; +my $clean = 0; +my $buildUniversal = 0; +my $buildSixtyFourBit = 0; + +my $programName = basename($0); +my $usage = <<EOF; +Usage: $programName [options] [options to pass to build system] + --help Show this help message + --clean Perform a clean build + --universal Build 2-way universal (PPC and Intel 32-bit) + --64-bit Build 64-bit, combine with --universal to build 4-way universal + --[no-]cross-document-messaging Toggle cross-document messaging support (default: $crossDocumentMessagingSupport) + --[no-]database Toggle Database Support (default: $databaseSupport) + --[no-]icon-database Toggle Icon database support (default: $iconDatabaseSupport) + --[no-]svg Toggle SVG support (default: $svgSupport) + --[no-]svg-experimental Toggle SVG experimental features support (default: $svgExperimentalSupport, + implies SVG Support) + --[no-]svg-animation Toggle SVG animation support (default: $svgAnimationSupport, implies SVG Support) + --[no-]svg-filters Toggle SVG filters support (default: $svgFiltersSupport, implies SVG Support) + --[no-]svg-foreign-object Toggle SVG forgeing object support (default: $svgForeignObjectSupport, implies SVG Support) + --[no-]svg-fonts Toggle SVG fonts support (default: $svgFontsSupport, implies SVG Support) + --[no-]svg-as-image Toggle SVG as Image support (default: $svgAsImageSupport, implies SVG Support) + --[no-]svg-use Toggle SVG use element support (default: $svgUseSupport, implies SVG Support) + --[no-]xpath Toggle XPath support (default: $xpathSupport) + --[no-]xslt Toggle XSLT support (default: $xsltSupport) + --[no-]video Toggle Video support (default: $videoSupport) + --[no-]coverage Toggle code coverage support (default: $coverageSupport) +EOF + +GetOptions('cross-document-messaging!' => \$crossDocumentMessagingSupport, + 'database!' => \$databaseSupport, + 'icon-database!' => \$iconDatabaseSupport, + 'svg!' => \$svgSupport, + 'svg-experimental!' => \$svgExperimentalSupport, + 'svg-animation!' => \$svgAnimationSupport, + 'svg-filters!' => \$svgFiltersSupport, + 'svg-foreign-object!' => \$svgForeignObjectSupport, + 'svg-fonts!' => \$svgFontsSupport, + 'svg-as-image!' => \$svgAsImageSupport, + 'svg-use!' => \$svgUseSupport, + 'xpath!' => \$xpathSupport, + 'xslt!' => \$xsltSupport, + 'video!' => \$videoSupport, + 'coverage!' => \$coverageSupport, + 'help' => \$showHelp, + 'universal' => \$buildUniversal, + '64-bit' => \$buildSixtyFourBit, + 'clean' => \$clean); + +if ($showHelp) { + print STDERR $usage; + exit 1; +} + +$svgExperimentalSupport = 0 unless $svgSupport; +$svgAnimationSupport = 0 unless $svgSupport; +$svgFiltersSupport = 0 unless $svgSupport; +$svgForeignObjectSupport = 0 unless $svgSupport; +$svgFontsSupport = 0 unless $svgSupport; +$svgAsImageSupport = 0 unless $svgSupport; +$svgUseSupport = 0 unless $svgSupport; + +if ($svgExperimentalSupport) { + $svgAnimationSupport = 1; + $svgFiltersSupport = 1; + $svgForeignObjectSupport = 1; + $svgFontsSupport = 1; + $svgAsImageSupport = 1; + $svgUseSupport = 1; +} + +checkRequiredSystemConfig(); +setConfiguration(); +chdirWebKit(); + +# FIXME: Migrate build-wxwebkit commands into build-webkit. +if (isWx()) { + my @opts = (); + $ENV{"WEBKITOUTPUTDIR"} = productDir(); + foreach (@ARGV) { + if ($_ eq "wxgc" || $_ eq "wxpython") { + push(@opts, $_); + } + } + if ($clean) { + push(@opts, "clean"); + } + system "WebKitTools/wx/build-wxwebkit @opts"; + exit exitStatus($?); +} + + +my $productDir = productDir(); +my @overrideFeatureDefinesOption = (); + +push @overrideFeatureDefinesOption, "ENABLE_CROSS_DOCUMENT_MESSAGING" if $crossDocumentMessagingSupport; +push @overrideFeatureDefinesOption, "ENABLE_DATABASE" if $databaseSupport; +push @overrideFeatureDefinesOption, "ENABLE_ICONDATABASE" if $iconDatabaseSupport; +push @overrideFeatureDefinesOption, "ENABLE_SVG" if $svgSupport; +push @overrideFeatureDefinesOption, "ENABLE_SVG_ANIMATION" if $svgAnimationSupport; +push @overrideFeatureDefinesOption, "ENABLE_SVG_FILTERS" if $svgFiltersSupport; +push @overrideFeatureDefinesOption, "ENABLE_SVG_FOREIGN_OBJECT" if $svgForeignObjectSupport; +push @overrideFeatureDefinesOption, "ENABLE_SVG_FONTS" if $svgFontsSupport; +push @overrideFeatureDefinesOption, "ENABLE_SVG_AS_IMAGE" if $svgAsImageSupport; +push @overrideFeatureDefinesOption, "ENABLE_SVG_USE" if $svgUseSupport; +push @overrideFeatureDefinesOption, "ENABLE_XPATH" if $xpathSupport; +push @overrideFeatureDefinesOption, "ENABLE_XSLT" if $xsltSupport; +push @overrideFeatureDefinesOption, "ENABLE_VIDEO" if $videoSupport; +my $overrideFeatureDefinesString = "FEATURE_DEFINES=" . join(" ", @overrideFeatureDefinesOption); + +my @coverageSupportOption = (); +if ($coverageSupport) { + push @coverageSupportOption, "GCC_GENERATE_TEST_COVERAGE_FILES=YES"; + push @coverageSupportOption, "GCC_INSTRUMENT_PROGRAM_FLOW_ARCS=YES"; + push @coverageSupportOption, "EXTRA_LINK= -ftest-coverage -fprofile-arcs"; + push @coverageSupportOption, "OTHER_CFLAGS= -MD"; + push @coverageSupportOption, "OTHER_LDFLAGS=\$(OTHER_LDFLAGS) -ftest-coverage -fprofile-arcs -framework AppKit"; +} + +# Check that all the project directories are there. +my @projects = ("JavaScriptCore", "JavaScriptGlue", "WebCore", "WebKit"); +my @otherDirs = ("WebKitLibraries"); +for my $dir (@projects, @otherDirs) { + if (! -d $dir) { + die "Error: No $dir directory found. Please do a fresh checkout.\n"; + } +} + +my @options = (); + +if ($clean && isOSX()) { + push(@options, "-alltargets"); + push(@options, "clean"); +} + +if ($buildSixtyFourBit && isOSX()) { + my $cpuVendor = `sysctl -n machdep.cpu.vendor`; + chomp $cpuVendor; + + if ($buildUniversal) { + push(@options, "ARCHS=ppc ppc64 i386 x86_64"); + } elsif ($cpuVendor eq "GenuineIntel") { + push(@options, "ARCHS=i386 x86_64"); + } else { + push(@options, "ARCHS=ppc ppc64"); + } +} elsif ($buildUniversal && isOSX()) { + push(@options, "ARCHS=ppc i386"); +} + +# enable autotool options accordingly +if ($ENV{WEBKITAUTOTOOLS}) { + push @options, autotoolsFlag($crossDocumentMessagingSupport, "cross-document-messaging"); + push @options, autotoolsFlag($databaseSupport, "database"); + push @options, autotoolsFlag($iconDatabaseSupport, "icon-database"); + push @options, autotoolsFlag($svgSupport, "svg"); + push @options, autotoolsFlag($svgAnimationSupport, "svg-animation"); + push @options, autotoolsFlag($svgFiltersSupport, "svg-filters"); + push @options, autotoolsFlag($svgForeignObjectSupport, "svg-foreign-object"); + push @options, autotoolsFlag($svgFontsSupport, "svg-fonts"); + push @options, autotoolsFlag($svgAsImageSupport, "svg-as-image"); + push @options, autotoolsFlag($svgUseSupport, "svg-use-element"); + push @options, autotoolsFlag($xpathSupport, "xpath"); + push @options, autotoolsFlag($xsltSupport, "xslt"); + push @options, autotoolsFlag($videoSupport, "video"); + push @options, autotoolsFlag($coverageSupport, "coverage"); +} + +if (isOSX()) { + + push(@options, XcodeOptions()); + + # Copy library and header from WebKitLibraries to a findable place in the product directory. + my $srcLib = "WebKitLibraries/libWebKitSystemInterfaceTiger.a"; + my $lib = "$productDir/libWebKitSystemInterfaceTiger.a"; + if (!-e $lib || -M $lib > -M $srcLib) { + print "Updating $lib\n"; + system "ditto", $srcLib, $lib; + system "ranlib", $lib; + } + + $srcLib = "WebKitLibraries/libWebKitSystemInterfaceLeopard.a"; + $lib = "$productDir/libWebKitSystemInterfaceLeopard.a"; + if (!-e $lib || -M $lib > -M $srcLib) { + print "Updating $lib\n"; + system "ditto", $srcLib, $lib; + system "ranlib", $lib; + } + + my $srcHeader = "WebKitLibraries/WebKitSystemInterface.h"; + my $header = "$productDir/usr/local/include/WebKitSystemInterface.h"; + if (!-e $header || -M $header > -M $srcHeader) { + print "Updating $header\n"; + system "mkdir", "-p", "$productDir/usr/local/include"; + system "ditto", $srcHeader, $header; + } + + $srcLib = "WebKitLibraries/libWebCoreSQLite3.a"; + $lib = "$productDir/libWebCoreSQLite3.a"; + if (!-e $lib || -M $lib > -M $srcLib) { + print "Updating $lib\n"; + system "ditto", $srcLib, $lib; + system "ranlib", $lib; + } + + my $srcHeaderDir = "WebKitLibraries/WebCoreSQLite3"; + my $headerDir = "$productDir/WebCoreSQLite3"; + if (!-e $headerDir || -M $headerDir > -M $srcHeaderDir) { + print "Updating $headerDir\n"; + system "ditto", $srcHeaderDir, $headerDir; + } +} + +if (isGtk() && isDarwin() && !$ENV{WEBKITAUTOTOOLS} && !$ENV{QMAKESPEC}) { + # The qmake from Trolltech's binary "QT for Mac" distribution tries to + # create xcode projects, not Makefiles + $ENV{QMAKESPEC} = "macx-g++"; +} + +if (isCygwin()) { + # Copy WebKitSupportLibrary to the correct location in WebKitLibraries so it can be found. + # Will fail if WebKitSupportLibrary.zip is not in source root. + (system("perl WebKitTools/Scripts/update-webkit-support-libs") == 0) or die; +} + +# Force re-link of existing libraries if different than expected +removeLibraryDependingOnSVG("WebCore", $svgSupport); + +# Build, and abort if the build fails. +for my $dir (@projects) { + chdir $dir or die; + my $result = 0; + + if (isGtk()) { + if ($dir ne "WebKit") { + chdir ".." or die; + next; + } + + $result = buildGtkProject($dir, $clean, @options); + } elsif (isQt()) { + if ($dir ne "WebKit") { + chdir ".." or die; + next; + } + $result = buildQMakeQtProject($dir, $clean); + } elsif (isOSX()) { + $result = system "xcodebuild", "-project", "$dir.xcodeproj", @options, $overrideFeatureDefinesString, @coverageSupportOption, @ARGV; + } elsif (isCygwin()) { + if ($dir eq "WebKit") { + $result = buildVisualStudioProject("win/WebKit.vcproj/WebKit.sln", $clean); + } + } + + if (exitStatus($result)) { + if (isCygwin()) { + print "\n\n===== BUILD FAILED ======\n\n"; + my $scriptDir = relativeScriptsDir(); + print "Please ensure you have run $scriptDir/update-webkit to install depenedencies.\n\n"; + my $baseProductDir = baseProductDir(); + print "You can view build errors by checking the BuildLog.htm files located at:\n$baseProductDir/obj/<project>/<config>.\n"; + } + exit exitStatus($result); + } + chdir ".." or die; +} + +# Don't report the "WebKit is now built" message after a clean operation. +exit if $clean; + +# Write out congratulations message. + +my $launcherPath = launcherPath(); +my $launcherName = launcherName(); + +print "\n"; +print "===========================================================\n"; +print " WebKit is now built. To run $launcherName with this newly-built\n"; +print " code, use the \"$launcherPath\" script.\n"; +if ($svgSupport) { + print "\n NOTE: WebKit has been built with SVG support enabled.\n"; + print " $launcherName will have SVG viewing capabilities.\n"; +} +if ($svgAnimationSupport or $svgFiltersSupport or $svgForeignObjectSupport or $svgFontsSupport or $svgAsImageSupport or $svgUseSupport) { + print "\n NOTE: WebKit has been built with experimental SVG features enabled.\n"; + print " Your build supports: \n"; + print " * Basic SVG animation.\n" if $svgAnimationSupport; + print " * SVG filters.\n" if $svgFiltersSupport; + print " * SVG foreign object.\n" if $svgForeignObjectSupport; + print " * SVG fonts.\n" if $svgFontsSupport; + print " * SVG as image.\n" if $svgAsImageSupport; + print " * SVG <use> support.\n" if $svgUseSupport; +} +print "===========================================================\n"; diff --git a/WebKitTools/Scripts/check-dom-results b/WebKitTools/Scripts/check-dom-results new file mode 100755 index 0000000..0b32406 --- /dev/null +++ b/WebKitTools/Scripts/check-dom-results @@ -0,0 +1,141 @@ +#!/usr/bin/perl -w + +# Copyright (C) 2005 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. + +# Script to check status of W3C DOM tests that are part of the WebKit tests. + +use strict; +use FindBin; +use Cwd; +use lib $FindBin::Bin; +use webkitdirs; + +chdirWebKit(); + +my $verbose = $ARGV[0] && $ARGV[0] eq "-v"; + +my $workingDir = getcwd(); +my $testDirectory = "$workingDir/LayoutTests"; + +my @suites = ( {"name" => "DOM Level 1 Core (html)", "directory" => "dom/html/level1/core"}, + {"name" => "DOM Level 2 Core (html)", "directory" => "dom/html/level2/core"}, + {"name" => "DOM Level 2 Events (html)", "directory" => "dom/html/level2/events"}, + {"name" => "DOM Level 2 HTML (html)", "directory" => "dom/html/level2/html"}, + {"name" => "DOM Level 1 Core (xhtml)", "directory" => "dom/xhtml/level1/core"}, + {"name" => "DOM Level 2 Core (xhtml)", "directory" => "dom/xhtml/level2/core"}, + {"name" => "DOM Level 2 Events (xhtml)", "directory" => "dom/xhtml/level2/events"}, + {"name" => "DOM Level 2 HTML (xhtml)", "directory" => "dom/xhtml/level2/html"}, + {"name" => "DOM Level 3 Core (xhtml)", "directory" => "dom/xhtml/level3/core"}, + {"name" => "DOM Level 3 XPath (svg)", "directory" => "dom/svg/level3/xpath"}); + +my $totalCount = 0; +my $totalSuccesses = 0; +my $totalDisabled = 0; +my $totalFailed = 0; + +foreach my $suite (@suites) { + + my %suite = %$suite; + my $directory = $suite{"directory"}; + my $name = $suite{"name"}; + my @results = `find "${testDirectory}/${directory}" -name "*-expected.txt"`; + my @disabled = `find "${testDirectory}/${directory}" -name "*-disabled"`; + + my @failures = (); + my $count = 0; + + foreach my $result (@results) { + $count++; + my $success = 0; + open RESULT, "<$result"; + while (<RESULT>) { + if (/Success/) { + $success = 1; + last; + } + } + close RESULT; + if (!$success) { + push @failures, $result; + } + } + + my $disabledCount = (scalar @disabled); + my $failureCount = (scalar @failures); + + $count += $disabledCount; + + my $successCount = $count - $failureCount - $disabledCount; + my $percentage = (sprintf "%.1f", ($successCount * 100.0 / $count)); + + if ($percentage == 100) { + print "${name}: all ${count} tests succeeded"; + } else { + print "${name}: ${successCount} out of ${count} tests succeeded (${percentage}%)"; + } + print " ($disabledCount disabled)" if $disabledCount; + print "\n"; + if ($verbose) { + print "\n"; + if (@disabled) { + print " Disabled:\n"; + + foreach my $failure (sort @disabled) { + $failure =~ s|.*/||; + $failure =~ s|-disabled||; + print " ${directory}/${failure}"; + } + } + if (@failures) { + print " Failed:\n"; + + foreach my $failure (sort @failures) { + $directory =~ m|^dom/(\w+)|; + my $extension = $1; + $failure =~ s|.*/||; + $failure =~ s|-expected\.txt|.${extension}|; + print " ${directory}/${failure}"; + } + } + + print "\n"; + } + + $totalCount += $count; + $totalSuccesses += $successCount; + $totalDisabled += $disabledCount; + $totalFailed += $failureCount; +} + + +my $totalPercentage = (sprintf "%.1f", ($totalSuccesses * 100.0 / $totalCount)); +my $totalDisabledPercentage = (sprintf "%.1f", ($totalDisabled * 100.0 / $totalCount)); +my $totalFailedPercentage = (sprintf "%.1f", ($totalFailed * 100.0 / $totalCount)); + +print "Total: ${totalSuccesses} out of ${totalCount} tests succeeded (${totalPercentage}%)\n"; +print " ${totalDisabled} tests disabled (${totalDisabledPercentage}%)\n"; +print " ${totalFailed} tests failed (${totalFailedPercentage}%)\n"; diff --git a/WebKitTools/Scripts/check-for-global-initializers b/WebKitTools/Scripts/check-for-global-initializers new file mode 100755 index 0000000..c73b8cc --- /dev/null +++ b/WebKitTools/Scripts/check-for-global-initializers @@ -0,0 +1,131 @@ +#!/usr/bin/perl + +# Copyright (C) 2006, 2007, 2008 Apple 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. + +# "check-for-global-initializers" script for Web Kit Open Source Project + +# Intended to be invoked from an Xcode build step to check if there are +# any global initializers in a target. + +use warnings; +use strict; + +use File::Basename; + +sub touch($); + +my $arch = $ENV{'CURRENT_ARCH'}; +my $configuration = $ENV{'CONFIGURATION'}; +my $target = $ENV{'TARGET_NAME'}; +my $variant = $ENV{'CURRENT_VARIANT'}; +my $coverageBuild = $ENV{'WEBKIT_COVERAGE_BUILD'}; +my $debugRoot = $ENV{'WEBKIT_DEBUG_ROOT'}; + +$arch = $ENV{'NATIVE_ARCH'} if !$arch; # for Xcode 2.1, which does not have CURRENT_ARCH +$variant = "normal" if !$variant; # for Xcode 2.1, which does not have CURRENT_VARIANT + +my $executablePath = "$ENV{'TARGET_BUILD_DIR'}/$ENV{'EXECUTABLE_PATH'}"; + +my $buildTimestampPath = $ENV{'TARGET_TEMP_DIR'} . "/" . basename($0) . ".timestamp"; +my $buildTimestampAge = -M $buildTimestampPath; + +touch($buildTimestampPath); + +my $list = $ENV{"LINK_FILE_LIST_${variant}_${arch}"}; + +if (!open LIST, $list) { + print "Could not open $list\n"; + exit 1; +} + +my @files = <LIST>; +chomp @files; +close LIST; + +my $sawError = 0; + +for my $file (sort @files) { + if (defined $buildTimestampAge) { + my $fileAge = -M $file; + next if defined $fileAge && $fileAge > $buildTimestampAge; + } + if (!open NM, "(nm '$file' | sed 's/^/STDOUT:/') 2>&1 |") { + print "Could not open $file\n"; + $sawError = 1; + next; + } + my $sawGlobal = 0; + while (<NM>) { + if (/^STDOUT:/) { + $sawGlobal = 1 if /__GLOBAL__I/; + } else { + print STDERR if $_ ne "nm: no name list\n"; + } + } + close NM; + if ($sawGlobal) { + my $shortName = $file; + $shortName =~ s/.*\///; + + # Special cases for files that have initializers in debug builds. + if ($configuration eq "Debug" or $debugRoot ) { + if ($target eq "JavaScriptCore") { + next if $shortName eq "nodes.o"; + next if $shortName eq "AllInOneFile.o"; + } + if ($target eq "WebCore") { + next if $shortName eq "CachedPage.o"; + next if $shortName eq "Frame.o"; + next if $shortName eq "JSCustomSQLTransactionCallback.o"; + next if $shortName eq "Node.o"; + next if $shortName eq "Page.o"; + next if $shortName eq "Range.o"; + next if $shortName eq "RenderObject.o"; + next if $shortName eq "SubresourceLoader.o"; + next if $shortName eq "bidi.o"; + next if $shortName eq "kjs_events.o"; + } + } + + print "$shortName has a global initializer in it! ($file)\n"; + $sawError = 1; + } +} + +if ($sawError and !$coverageBuild) { + unlink $executablePath; + exit 1; +} + +exit 0; + +sub touch($) +{ + my ($path) = @_; + open(TOUCH, ">", $path) or die "$!"; + close(TOUCH); +} diff --git a/WebKitTools/Scripts/clean-header-guards b/WebKitTools/Scripts/clean-header-guards new file mode 100755 index 0000000..2bad046 --- /dev/null +++ b/WebKitTools/Scripts/clean-header-guards @@ -0,0 +1,53 @@ +#!/usr/bin/ruby + +require 'find' +require 'optparse' + +options = {} +OptionParser.new do |opts| + opts.banner = "Usage: clean-header-guards [options]" + + opts.on("--prefix [PREFIX]", "Append a header prefix to all guards") do |prefix| + options[:prefix] = prefix + end +end.parse! + +IgnoredFilenamePatterns = [ + # ignore headers which are known not to have guard + /WebCorePrefix/, + /ForwardingHeaders/, + %r|bindings/objc|, + /vcproj/, # anything inside a vcproj is in the windows wasteland + + # we don't own any of these headers + %r|icu/unicode|, + %r|platform/graphics/cairo|, + %r|platform/image-decoders|, + + /config.h/ # changing this one sounds scary +].freeze + +IgnoreFileNamesPattern = Regexp.union(*IgnoredFilenamePatterns).freeze + +Find::find(".") do |filename| + next unless filename =~ /\.h$/ + next if filename.match(IgnoreFileNamesPattern) + + File.open(filename, "r+") do |file| + contents = file.read + match_results = contents.match(/#ifndef (\S+)\n#define \1/s) + if match_results + current_guard = match_results[1] + new_guard = File.basename(filename).sub('.', '_') + new_guard = options[:prefix] + '_' + new_guard if options[:prefix] + contents.gsub!(/#{current_guard}\b/, new_guard) + else + puts "Ignoring #{filename}, failed to find existing header guards." + end + tmp_filename = filename + ".tmp" + File.open(tmp_filename, "w+") do |new_file| + new_file.write(contents) + end + File.rename tmp_filename, filename + end +end diff --git a/WebKitTools/Scripts/commit-log-editor b/WebKitTools/Scripts/commit-log-editor new file mode 100755 index 0000000..e7ee5155 --- /dev/null +++ b/WebKitTools/Scripts/commit-log-editor @@ -0,0 +1,189 @@ +#!/usr/bin/perl -w + +# Copyright (C) 2006, 2007 Apple 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. + +# Script to put change log comments in as default check-in comment. + +use strict; +use File::Basename; +use File::Spec; +use FindBin; +use lib $FindBin::Bin; +use VCSUtils; +use webkitdirs; + +my $log = $ARGV[0]; + +my $baseDir = baseProductDir(); + +my $editor = $ENV{SVN_LOG_EDITOR}; +if (!$editor) { + $editor = $ENV{CVS_LOG_EDITOR}; +} +if (!$editor) { + my $builtEditorApplication = "$baseDir/Release/Commit Log Editor.app/Contents/MacOS/Commit Log Editor"; + $editor = $builtEditorApplication if -x $builtEditorApplication; +} +if (!$editor) { + my $builtEditorApplication = "$baseDir/Debug/Commit Log Editor.app/Contents/MacOS/Commit Log Editor"; + $editor = $builtEditorApplication if -x $builtEditorApplication; +} +if (!$editor) { + my $installedEditorApplication = "$ENV{HOME}/Applications/Commit Log Editor.app/Contents/MacOS/Commit Log Editor"; + $editor = $installedEditorApplication if -x $installedEditorApplication; +} +if (!$editor) { + $editor = $ENV{EDITOR} || "/usr/bin/vi"; +} + +my $inChangesToBeCommitted = !isGit(); +my @changeLogs = (); +my $logContents = ""; +my $existingLog = 0; +open LOG, $log or die; +while (<LOG>) { + if (isGit()) { + if (/^# Changes to be committed:$/) { + $inChangesToBeCommitted = 1; + } elsif ($inChangesToBeCommitted && /^# \S/) { + $inChangesToBeCommitted = 0; + } + } + + $logContents .= $_; + $existingLog = isGit() && !(/^#/ || /^\s*$/) unless $existingLog; + + push @changeLogs, makeFilePathRelative($1) if $inChangesToBeCommitted && (/^M....(.*ChangeLog)$/ || /^#\tmodified: (.*ChangeLog)/) && !/-ChangeLog/; +} +close LOG; + +# Don't change anything if there's already a log message +# (as can happen with git-commit --amend) +exec $editor, @ARGV if $existingLog; + +my $topLevel = topLevelSourceDirectory(); + +my %changeLogSort; +my %changeLogContents; +for my $changeLog (@changeLogs) { + open CHANGELOG, $changeLog or die "Can't open $changeLog"; + my $contents = ""; + my $blankLines = ""; + while (<CHANGELOG>) { + if (/^\S/) { + last if $contents; + next; + } elsif (/\S/) { + $contents .= $blankLines if $contents; + $blankLines = ""; + $contents .= $_; + } else { + $blankLines .= $_; + } + } + close CHANGELOG; + + $changeLog = File::Spec->abs2rel(File::Spec->rel2abs($changeLog), $topLevel); + + my $label = dirname($changeLog); + $label = "top level" unless length $label; + + my $sortKey = lc $label; + if ($label eq "top level") { + $sortKey = ""; + } elsif ($label eq "Tools") { + $sortKey = "-, just after top level"; + } elsif ($label eq "WebBrowser") { + $sortKey = lc "WebKit, WebBrowser after"; + } elsif ($label eq "WebCore") { + $sortKey = lc "WebFoundation, WebCore after"; + } elsif ($label eq "LayoutTests") { + $sortKey = lc "~, LayoutTests last"; + } + + $changeLogSort{$sortKey} = $label; + $changeLogContents{$label} = $contents; +} + +my $first = 1; +open NEWLOG, ">$log.edit" or die; +for my $sortKey (sort keys %changeLogSort) { + my $label = $changeLogSort{$sortKey}; + if (keys %changeLogSort > 1) { + print NEWLOG "\n" if !$first; + $first = 0; + print NEWLOG "$label:\n\n"; + } + print NEWLOG $changeLogContents{$label}; +} +print NEWLOG $logContents; +close NEWLOG; + +system $editor, "$log.edit"; + +open NEWLOG, "$log.edit" or exit; +my $foundComment = 0; +while (<NEWLOG>) { + $foundComment = 1 if (/\S/ && !/^CVS:/); +} +close NEWLOG; + +if ($foundComment) { + open NEWLOG, "$log.edit" or die; + open LOG, ">$log" or die; + while (<NEWLOG>) { + print LOG; + } + close LOG; + close NEWLOG; +} + +unlink "$log.edit"; + +sub topLevelSourceDirectory +{ + if (isGit()) { + chomp(my $gitDir = `git rev-parse --git-dir`); + return dirname($gitDir); + } elsif (isSVN()) { + open(INFO, "-|", qw(svn info)) or die; + my ($root, $url); + while (my $line = <INFO>) { + if ($line =~ /^Repository Root: (.*)$/) { + $root = $1; + } elsif ($line =~ /^URL: (.*)$/) { + $url = $1; + } + } + close(INFO); + + my $path = $url; + $path =~ s/^\Q$root\E//; + $path =~ s/^\/?(branches\/[^\/]*|trunk)\/?//; + return File::Spec->rel2abs(File::Spec->catdir(map { ".." } File::Spec->splitdir($path))); + } +} diff --git a/WebKitTools/Scripts/compare-timing-files b/WebKitTools/Scripts/compare-timing-files new file mode 100755 index 0000000..11b470b --- /dev/null +++ b/WebKitTools/Scripts/compare-timing-files @@ -0,0 +1,88 @@ +#!/usr/bin/perl + +# Copyright (C) 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. + +# This script takes two files that are lists of timings and compares them. + +use warnings; +use strict; +use Getopt::Long; + +my $usage = "compare-timing-files [-c|--count results] oldFile newFile"; + +my $count = 1; +GetOptions("c|count=i" => \$count); + +my ($file1, $file2) = @ARGV; +die "$usage\n" unless ($file1 && $file2 && @ARGV == 2); + +my ($oldAverage, $oldRange, $oldRangePercent) = parseResults($file1); +my ($newAverage, $newRange, $newRangePercent) = parseResults($file2); + +print "\n===== $file1 =====\n"; +if ($count == 1) { + print("fastest run: $oldAverage\n"); +} else { + print("average of fastest $count runs: $oldAverage\n"); + printf("range of fastest $count runs: %.2f%% (%d)\n", $oldRangePercent, $oldRange); +} + +print "\n===== $file2 =====\n"; +if ($count == 1) { + print("fastest run: $newAverage\n"); +} else { + print("average of fastest $count runs: $newAverage\n"); + printf("range of fastest $count runs: %.2f%% (%d)\n", $newRangePercent, $newRange); +} + +my $gainOrLoss = $newAverage <= $oldAverage ? "GAIN" : "LOSS"; +my $difference = abs($newAverage - $oldAverage); +my $differencePercent = $difference / $oldAverage * 100; +printf("\nperformance %s of %.2f%% (%.1f / %.1f)\n", $gainOrLoss, $differencePercent, $difference, $oldAverage); +print "\n"; + +sub parseResults +{ + my ($file) = @_; + + open(FILE, $file) or die "Couldn't open file: $file"; + my @results = <FILE>; + close(FILE); + + @results = sort(@results); + my $total = 0; + for (my $i = 0; $i < $count; $i++) { + $results[$i] =~ s/\D*//; # cut out non-digits + $total += $results[$i]; + } + my $average = $total / $count; + my $range = $results[$count - 1] - $results[0]; + my $rangePercent = $range / $results[$count - 1] * 100; + + return ($average, $range, $rangePercent); +} + diff --git a/WebKitTools/Scripts/debug-safari b/WebKitTools/Scripts/debug-safari new file mode 100755 index 0000000..52e97fe --- /dev/null +++ b/WebKitTools/Scripts/debug-safari @@ -0,0 +1,38 @@ +#!/usr/bin/perl -w + +# Copyright (C) 2007 Apple 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. + +# Script to run Safari in the platform's debugger for the WebKit Open Source Project. + +use strict; +use FindBin; +use lib $FindBin::Bin; +use webkitdirs; + +setConfiguration(); + +exit exitStatus(runSafari(1)); diff --git a/WebKitTools/Scripts/do-file-rename b/WebKitTools/Scripts/do-file-rename new file mode 100755 index 0000000..23a460c --- /dev/null +++ b/WebKitTools/Scripts/do-file-rename @@ -0,0 +1,110 @@ +#!/usr/bin/perl -w + +# Copyright (C) 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. + +# Script to do file renaming. + +use strict; +use FindBin; +use lib $FindBin::Bin; +use webkitdirs; +use File::Find; + +setConfiguration(); +chdirWebKit(); + +my %words; + +# find all files we want to process + +my @paths; +find(\&wanted, "WebCore"); + +sub wanted +{ + my $file = $_; + + if ($file eq "icu") { + $File::Find::prune = 1; + return; + } + + if ($file =~ /^\../) { + $File::Find::prune = 1; + return; + } + + return if $file =~ /^ChangeLog/; + return if -d $file; + + push @paths, $File::Find::name; +} + +my %renames = ( + "xxx.mm" => "yyy.mm", +); + +# rename files + +my %newFile; +for my $file (sort @paths) { + my $f = $file; + $f = "$1$renames{$2}" if $f =~ /^(.*\/)(\w+\.\w+)$/ && $renames{$2}; + $newFile{$file} = $f if $f ne $file; +} + +for my $file (sort @paths) { + if ($newFile{$file}) { + my $newFile = $newFile{$file}; + print "Renaming $file to $newFile\n"; + system "svn move $file $newFile"; + } +} + +# change all file contents + +for my $file (sort @paths) { + $file = $newFile{$file} if $newFile{$file}; + my $contents; + { + local $/; + open FILE, $file or die; + $contents = <FILE>; + close FILE; + } + my $newContents = $contents; + + for my $from (keys %renames) { + $newContents =~ s/\b\Q$from\E(?!["\w])/$renames{$from}/g; # this " unconfuses Xcode syntax highlighting + } + + if ($newContents ne $contents) { + open FILE, ">", $file or die; + print FILE $newContents; + close FILE; + } +} diff --git a/WebKitTools/Scripts/do-webcore-rename b/WebKitTools/Scripts/do-webcore-rename new file mode 100755 index 0000000..36f894a --- /dev/null +++ b/WebKitTools/Scripts/do-webcore-rename @@ -0,0 +1,345 @@ +#!/usr/bin/perl -w + +# Copyright (C) 2006, 2007, 2008 Apple 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. + +# Script to do a rename in JavaScriptCore, WebCore, and WebKit. + +use strict; +use FindBin; +use lib $FindBin::Bin; +use webkitdirs; +use File::Find; + +setConfiguration(); +chdirWebKit(); + +my %words; + +# find all files we want to process + +my @paths; +find(\&wanted, "JavaScriptCore"); +find(\&wanted, "JavaScriptGlue"); +find(\&wanted, "WebCore"); +find(\&wanted, "WebKit"); + +sub wanted +{ + my $file = $_; + + if ($file eq "icu") { + $File::Find::prune = 1; + return; + } + + if ($file =~ /^\../) { + $File::Find::prune = 1; + return; + } + + return if $file =~ /^ChangeLog/; + return if -d $file; + + push @paths, $File::Find::name; +} + +my %renames = ( + "XSLTProcessorPrototypeTable" => "JSXSLTProcessorPrototypeTable", + "ActivationImp" => "Activation", + "ActivationImpData" => "ActivationData", + "ArrayInstance" => "JSArray", + "ArrayObjectImp" => "ArrayConstructor", + "ArrayProtoFuncConcat" => "ArrayFunctionConcat", + "ArrayProtoFuncEvery" => "ArrayFunctionEvery", + "ArrayProtoFuncFilter" => "ArrayFunctionFilter", + "ArrayProtoFuncForEach" => "ArrayFunctionForEach", + "ArrayProtoFuncIndexOf" => "ArrayFunctionIndexOf", + "ArrayProtoFuncJoin" => "ArrayFunctionJoin", + "ArrayProtoFuncLastIndexOf" => "ArrayFunctionLastIndexOf", + "ArrayProtoFuncMap" => "ArrayFunctionMap", + "ArrayProtoFuncPop" => "ArrayFunctionPop", + "ArrayProtoFuncPush" => "ArrayFunctionPush", + "ArrayProtoFuncReverse" => "ArrayFunctionReverse", + "ArrayProtoFuncShift" => "ArrayFunctionShift", + "ArrayProtoFuncSlice" => "ArrayFunctionSlice", + "ArrayProtoFuncSome" => "ArrayFunctionSome", + "ArrayProtoFuncSort" => "ArrayFunctionSort", + "ArrayProtoFuncSplice" => "ArrayFunctionSplice", + "ArrayProtoFuncToLocaleString" => "ArrayFunctionToLocaleString", + "ArrayProtoFuncToString" => "ArrayFunctionToString", + "ArrayProtoFuncUnShift" => "ArrayFunctionUnshift", + "BooleanInstance" => "BooleanObject", + "BooleanObjectImp" => "BooleanConstructor", + "BooleanProtoFunc" => "BooleanFunction", + "DateObjectFuncImp" => "DateFunction", + "DateObjectImp" => "DateConstructor", + "DateProtoFuncGetDate" => "DateFunctionGetDate", + "DateProtoFuncGetDay" => "DateFunctionGetDay", + "DateProtoFuncGetFullYear" => "DateFunctionGetFullYear", + "DateProtoFuncGetHours" => "DateFunctionGetHours", + "DateProtoFuncGetMilliSeconds" => "DateFunctionGetMilliSeconds", + "DateProtoFuncGetMinutes" => "DateFunctionGetMinutes", + "DateProtoFuncGetMonth" => "DateFunctionGetMonth", + "DateProtoFuncGetSeconds" => "DateFunctionGetSeconds", + "DateProtoFuncGetTime" => "DateFunctionGetTime", + "DateProtoFuncGetTimezoneOffset" => "DateFunctionGetTimezoneOffset", + "DateProtoFuncGetUTCDate" => "DateFunctionGetUTCDate", + "DateProtoFuncGetUTCDay" => "DateFunctionGetUTCDay", + "DateProtoFuncGetUTCFullYear" => "DateFunctionGetUTCFullYear", + "DateProtoFuncGetUTCHours" => "DateFunctionGetUTCHours", + "DateProtoFuncGetUTCMilliseconds" => "DateFunctionGetUTCMilliseconds", + "DateProtoFuncGetUTCMinutes" => "DateFunctionGetUTCMinutes", + "DateProtoFuncGetUTCMonth" => "DateFunctionGetUTCMonth", + "DateProtoFuncGetUTCSeconds" => "DateFunctionGetUTCSeconds", + "DateProtoFuncGetYear" => "DateFunctionGetYear", + "DateProtoFuncSetDate" => "DateFunctionSetDate", + "DateProtoFuncSetFullYear" => "DateFunctionSetFullYear", + "DateProtoFuncSetHours" => "DateFunctionSetHours", + "DateProtoFuncSetMilliSeconds" => "DateFunctionSetMilliSeconds", + "DateProtoFuncSetMinutes" => "DateFunctionSetMinutes", + "DateProtoFuncSetMonth" => "DateFunctionSetMonth", + "DateProtoFuncSetSeconds" => "DateFunctionSetSeconds", + "DateProtoFuncSetTime" => "DateFunctionSetTime", + "DateProtoFuncSetUTCDate" => "DateFunctionSetUTCDate", + "DateProtoFuncSetUTCFullYear" => "DateFunctionSetUTCFullYear", + "DateProtoFuncSetUTCHours" => "DateFunctionSetUTCHours", + "DateProtoFuncSetUTCMilliseconds" => "DateFunctionSetUTCMilliseconds", + "DateProtoFuncSetUTCMinutes" => "DateFunctionSetUTCMinutes", + "DateProtoFuncSetUTCMonth" => "DateFunctionSetUTCMonth", + "DateProtoFuncSetUTCSeconds" => "DateFunctionSetUTCSeconds", + "DateProtoFuncSetYear" => "DateFunctionSetYear", + "DateProtoFuncToDateString" => "DateFunctionToDateString", + "DateProtoFuncToGMTString" => "DateFunctionToGMTString", + "DateProtoFuncToLocaleDateString" => "DateFunctionToLocaleDateString", + "DateProtoFuncToLocaleString" => "DateFunctionToLocaleString", + "DateProtoFuncToLocaleTimeString" => "DateFunctionToLocaleTimeString", + "DateProtoFuncToString" => "DateFunctionToString", + "DateProtoFuncToTimeString" => "DateFunctionToTimeString", + "DateProtoFuncToUTCString" => "DateFunctionToUTCString", + "DateProtoFuncValueOf" => "DateFunctionValueOf", + "DebuggerImp" => "DebuggerData", + "ErrorObjectImp" => "ErrorConstructor", + "ErrorProtoFuncToString" => "ErrorFunction", + "FRAMES_ON_STACK" => "numFramesOnStack", + "FTPDirectoryTokenizer" => "FTPDirectoryDocumentBuilder", + "FunctionImp" => "JSFunction", + "FunctionObjectImp" => "FunctionConstructor", + "FunctionProtoFunc" => "FunctionFunction", + "GetterSetterImp" => "JSGetterSetter", + "GlobalFuncImp" => "GlobalFunction", + "GlobalImp" => "TestGlobalObject", + "HTMLGenericFormElement" => "HTMLFormControlElement", + "HTMLGenericFormElement_h" => "HTMLFormControlElement_h", + "HTMLTokenizer" => "HTMLDocumentBuilder", + "ImageConstructorImp" => "JSImageConstructor", + "ImageTokenizer" => "ImageDocumentBuilder", + "InternalFunctionImp" => "InternalFunction", + "JSXMLHttpRequestConstructorImp" => "JSXMLHttpRequestConstructor", + "KURL" => "URL", + "KURLCFNet" => "URLCF", + "KURLMac" => "URLMac", + "KURL_H_" => "URL_h", + "List" => "JSArgumentList", + "MathObjectImp" => "MathObject", + "MathProtoFuncACos" => "MathFunctionACos", + "MathProtoFuncASin" => "MathFunctionASin", + "MathProtoFuncATan" => "MathFunctionATan", + "MathProtoFuncATan2" => "MathFunctionATan2", + "MathProtoFuncAbs" => "MathFunctionAbs", + "MathProtoFuncCeil" => "MathFunctionCeil", + "MathProtoFuncCos" => "MathFunctionCos", + "MathProtoFuncExp" => "MathFunctionExp", + "MathProtoFuncFloor" => "MathFunctionFloor", + "MathProtoFuncLog" => "MathFunctionLog", + "MathProtoFuncMax" => "MathFunctionMax", + "MathProtoFuncMin" => "MathFunctionMin", + "MathProtoFuncPow" => "MathFunctionPow", + "MathProtoFuncRandom" => "MathFunctionRandom", + "MathProtoFuncRound" => "MathFunctionRound", + "MathProtoFuncSin" => "MathFunctionSin", + "MathProtoFuncSqrt" => "MathFunctionSqrt", + "MathProtoFuncTan" => "MathFunctionTan", + "NativeErrorImp" => "NativeErrorConstructor", + "Navigator" => "JSNavigator", + "NumberImp" => "JSNumberCell", + "NumberInstance" => "NumberObject", + "NumberObjectImp" => "NumberConstructor", + "NumberProtoFunc" => "NumberFunction", + "ObjcFallbackObjectImp" => "ObjCFallbackObject", + "ObjectObjectImp" => "ObjectConstructor", + "ObjectProtoFunc" => "ObjectFunction", + "PluginTokenizer" => "PluginDocumetBuilder", + "RECURSIVE_MATCH_STARTNG_NEW_GROUP" => "RECURSIVE_MATCH_NEW_GROUP", + "RegExpImp" => "RegExpObject", + "RegExpObjectImp" => "RegExpConstructor", + "RegExpObjectImpPrivate" => "RegExpConstructorPrivate", + "RegExpProtoFunc" => "RegExpFunction", + "RuntimeObjectImp" => "ForeignObject", + "StringImp" => "JSString", + "StringImpl" => "SharedString", + "StringInstance" => "StringObject", + "StringInstanceThatMasqueradesAsUndefined" => "StringObjectThatMasqueradesAsUndefined", + "StringObjectFuncImp" => "StringConstructorFunction", + "StringObjectImp" => "StringConstructor", + "StringProtoFuncAnchor" => "StringFunctionAnchor", + "StringProtoFuncBig" => "StringFunctionBig", + "StringProtoFuncBlink" => "StringFunctionBlink", + "StringProtoFuncBold" => "StringFunctionBold", + "StringProtoFuncCharAt" => "StringFunctionCharAt", + "StringProtoFuncCharCodeAt" => "StringFunctionCharCodeAt", + "StringProtoFuncConcat" => "StringFunctionConcat", + "StringProtoFuncFixed" => "StringFunctionFixed", + "StringProtoFuncFontcolor" => "StringFunctionFontcolor", + "StringProtoFuncFontsize" => "StringFunctionFontsize", + "StringProtoFuncIndexOf" => "StringFunctionIndexOf", + "StringProtoFuncItalics" => "StringFunctionItalics", + "StringProtoFuncLastIndexOf" => "StringFunctionLastIndexOf", + "StringProtoFuncLink" => "StringFunctionLink", + "StringProtoFuncLocaleCompare" => "StringFunctionLocaleCompare", + "StringProtoFuncMatch" => "StringFunctionMatch", + "StringProtoFuncReplace" => "StringFunctionReplace", + "StringProtoFuncSearch" => "StringFunctionSearch", + "StringProtoFuncSlice" => "StringFunctionSlice", + "StringProtoFuncSmall" => "StringFunctionSmall", + "StringProtoFuncSplit" => "StringFunctionSplit", + "StringProtoFuncStrike" => "StringFunctionStrike", + "StringProtoFuncSub" => "StringFunctionSub", + "StringProtoFuncSubstr" => "StringFunctionSubstr", + "StringProtoFuncSubstring" => "StringFunctionSubstring", + "StringProtoFuncSup" => "StringFunctionSup", + "StringProtoFuncToLocaleLowerCase" => "StringFunctionToLocaleLowerCase", + "StringProtoFuncToLocaleUpperCase" => "StringFunctionToLocaleUpperCase", + "StringProtoFuncToLowerCase" => "StringFunctionToLowerCase", + "StringProtoFuncToString" => "StringFunctionToString", + "StringProtoFuncToUpperCase" => "StringFunctionToUpperCase", + "StringProtoFuncValueOf" => "StringFunctionValueOf", + "TestFunctionImp" => "TestFunction", + "TextTokenizer" => "TextDocumentBuilder", + "ThreadSafeShared" => "ThreadSafeRefCounted", + "Tokenizer" => "DocumentBuilder", + "Tokenizer_h" => "DocumentBuilder_h", + "XMLTokenizer" => "XMLDocumentBuilder", + "XSLTProcessorConstructorImp" => "JSXSLTProcessorConstructor", + "XSLTProcessorPrototype" => "JSXSLTProcessorPrototype", + "animationController" => "animation", + "branchfirstbyte" => "branchFirstByte", + "branchreqbyte" => "branchReqByte", + "class_charcount" => "classCharCount", + "class_lastchar" => "classLastChar", + "codeptr" => "codePtr", + "createTokenizer" => "createBuilder", + "domString" => "string", + "equalIgnoringCase" => "equalFoldingCase", + "errorcodeptr" => "errorCodePtr", + "errorptr" => "errorPtr", + "first_byte" => "firstByte", + "first_byte_caseless" => "firstByteIsCaseless", + "first_char" => "firstChar", + "firstbyte" => "firstByte", + "groupsetfirstbyte" => "didGroupSetFirstByte", + "isHTMLTokenizer" => "isHTMLDocumentBuilder", + "is_quantifier" => "isQuantifier", + "isclass" => "isClass", + "kjs_binding" => "JSDOMBinding", + "kjs_binding_h" => "JSDOMBinding_h", + "kjs_css" => "JSRGBColor", + "kjs_css_h" => "JSRGBColor_h", + "kjs_proxy" => "ScriptController", + "kjs_proxy_h" => "ScriptController_h", + "last_branch" => "lastBranch", + "m_tokenizer" => "m_builder", + "mclength" => "mcLength", + "negate_class" => "negateClass", + "offsetcount" => "offsetCount", + "op_type" => "opType", + "prev_length" => "prevLength", + "ptrptr" => "ptrPtr", + "repeat_min" => "repeatMin", + "repeat_type" => "repeatType", + "req_byte" => "reqByte", + "req_byte2" => "reqByte2", + "req_byte_caseless" => "reqByteIsCaseless", + "req_caseopt" => "reqCaseOpt", + "req_varyopt" => "reqVaryOpt", + "reqbyte" => "reqByte", + "resetcount" => "resetCount", + "scriptProxy" => "script", + "selectionController" => "selection", + "should_flip_negation" => "shouldFlipNegation", + "skipbytes" => "skipBytes", + "subfirstbyte" => "subFirstByte", + "subreqbyte" => "subReqByte", + "tokenizerProcessedData" => "documentBuilderProcessedData", + "top_backref" => "topBackref", + "top_bracket" => "topBracket", + "using_temporary_offsets" => "usingTemporaryOffsets", + "zerofirstbyte" => "zeroFirstByte", + "zeroreqbyte" => "zeroReqByte", +); + +# rename files + +my %newFile; +for my $file (sort @paths) { + my $f = $file; + $f = "$1$renames{$2}$3" if $f =~ /^(.*\/)(\w+)(\.\w+)$/ && $renames{$2}; + if ($f ne $file) { + $newFile{$file} = $f; + } +} + +for my $file (sort @paths) { + if ($newFile{$file}) { + my $newFile = $newFile{$file}; + print "Renaming $file to $newFile\n"; + system "svn move $file $newFile"; + } +} + +# change all file contents + +for my $file (sort @paths) { + $file = $newFile{$file} if $newFile{$file}; + my $contents; + { + local $/; + open FILE, $file or die; + $contents = <FILE>; + close FILE; + } + my $newContents = $contents; + + for my $from (keys %renames) { + $newContents =~ s/\b$from(?!["\w])/$renames{$from}/g; # this " unconfuses Xcode syntax highlighting + } + + if ($newContents ne $contents) { + open FILE, ">", $file or die; + print FILE $newContents; + close FILE; + } +} diff --git a/WebKitTools/Scripts/extract-localizable-strings b/WebKitTools/Scripts/extract-localizable-strings new file mode 100755 index 0000000..15d6782 --- /dev/null +++ b/WebKitTools/Scripts/extract-localizable-strings @@ -0,0 +1,359 @@ +#!/usr/bin/perl -w + +# Copyright (C) 2006, 2007 Apple 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. + +# This script is like the genstrings tool (minus most of the options) with these differences. +# +# 1) It uses the names UI_STRING and UI_STRING_WITH_KEY for the macros, rather than the macros +# from NSBundle.h, and doesn't support tables (although they would be easy to add). +# 2) It supports UTF-8 in key strings (and hence uses "" strings rather than @"" strings; +# @"" strings only reliably support ASCII since they are decoded based on the system encoding +# at runtime, so give different results on US and Japanese systems for example). +# 3) It looks for strings that are not marked for localization, using both macro names that are +# known to be used for debugging in Intrigue source code and an exceptions file. +# 4) It finds the files to work on rather than taking them as parameters, and also uses a +# hardcoded location for both the output file and the exceptions file. +# It would have been nice to use the project to find the source files, but it's too hard to +# locate source files after parsing a .pbxproj file. + +# The exceptions file has a list of strings in quotes, filenames, and filename/string pairs separated by :. + +use strict; + +my $stringsFile = "English.lproj/Localizable.strings"; +my %isDebugMacro = ( ASSERT_WITH_MESSAGE => 1, LOG_ERROR => 1, ERROR => 1, NSURL_ERROR => 1, FATAL => 1, LOG => 1, dprintf => 1, NSException => 1, NSLog => 1, printf => 1 ); + +@ARGV >= 1 or die "Usage: extract-localizable-strings <exceptions file> [ directory... ]\nDid you mean to run extract-webkit-localizable-strings instead?\n"; + +my $exceptionsFile = shift @ARGV; +-f $exceptionsFile or die "Couldn't find exceptions file $exceptionsFile\n"; + +my @directories = (); +my @directoriesToSkip = (); +if (@ARGV < 1) { + push(@directories, "."); +} else { + for my $dir (@ARGV) { + if ($dir =~ /^-(.*)$/) { + push @directoriesToSkip, $1; + } else { + push @directories, $dir; + } + } +} + +my $sawError = 0; + +my $localizedCount = 0; +my $keyCollisionCount = 0; +my $notLocalizedCount = 0; +my $NSLocalizeCount = 0; + +my %exception; +my %usedException; + +if (open EXCEPTIONS, $exceptionsFile) { + while (<EXCEPTIONS>) { + chomp; + if (/^"([^\\"]|\\.)*"$/ or /^[-_\/\w.]+.(h|m|mm|c|cpp)$/ or /^[-_\/\w.]+.(h|m|mm|c|cpp):"([^\\"]|\\.)*"$/) { + if ($exception{$_}) { + print "$exceptionsFile:$.:exception for $_ appears twice\n"; + print "$exceptionsFile:$exception{$_}:first appearance\n"; + } else { + $exception{$_} = $.; + } + } else { + print "$exceptionsFile:$.:syntax error\n"; + } + } + close EXCEPTIONS; +} + +my $quotedDirectoriesString = '"' . join('" "', @directories) . '"'; +for my $dir (@directoriesToSkip) { + $quotedDirectoriesString .= ' -path "' . $dir . '" -prune'; +} + +my @files = ( split "\n", `find $quotedDirectoriesString -name "*.h" -o -name "*.m" -o -name "*.mm" -o -name "*.c" -o -name "*.cpp"` ); + +for my $file (sort @files) { + next if $file =~ /\/WebLocalizableStrings\.h$/; + next if $file =~ /\/icu\//; + + $file =~ s-^./--; + + open SOURCE, $file or die "can't open $file\n"; + + my $inComment = 0; + + my $expected = ""; + my $macroLine; + my $macro; + my $UIString; + my $key; + my $comment; + + my $string; + my $stringLine; + my $nestingLevel; + + my $previousToken = ""; + + while (<SOURCE>) { + chomp; + + # Handle continued multi-line comment. + if ($inComment) { + next unless s-.*\*/--; + $inComment = 0; + } + + # Handle all the tokens in the line. + while (s-^\s*([#\w]+|/\*|//|[^#\w/'"()\[\],]+|.)--) { + my $token = $1; + + if ($token eq "\"") { + if ($expected and $expected ne "a quoted string") { + print "$file:$.:ERROR:found a quoted string but expected $expected\n"; + $sawError = 1; + $expected = ""; + } + if (s-^(([^\\$token]|\\.)*?)$token--) { + if (!defined $string) { + $stringLine = $.; + $string = $1; + } else { + $string .= $1; + } + } else { + print "$file:$.:ERROR:mismatched quotes\n"; + $sawError = 1; + $_ = ""; + } + next; + } + + if (defined $string) { +handleString: + if ($expected) { + if (!defined $UIString) { + # FIXME: Validate UTF-8 here? + $UIString = $string; + $expected = ","; + } elsif (($macro eq "UI_STRING_KEY" or $macro eq "LPCTSTR_UI_STRING_KEY") and !defined $key) { + # FIXME: Validate UTF-8 here? + $key = $string; + $expected = ","; + } elsif (!defined $comment) { + # FIXME: Validate UTF-8 here? + $comment = $string; + $expected = ")"; + } + } else { + if (defined $nestingLevel) { + # In a debug macro, no need to localize. + } elsif ($previousToken eq "#include" or $previousToken eq "#import") { + # File name, no need to localize. + } elsif ($previousToken eq "extern" and $string eq "C") { + # extern "C", no need to localize. + } elsif ($string eq "") { + # Empty string can sometimes be localized, but we need not complain if not. + } elsif ($exception{$file}) { + $usedException{$file} = 1; + } elsif ($exception{"\"$string\""}) { + $usedException{"\"$string\""} = 1; + } elsif ($exception{"$file:\"$string\""}) { + $usedException{"$file:\"$string\""} = 1; + } else { + print "$file:$stringLine:\"$string\" is not marked for localization\n"; + $notLocalizedCount++; + } + } + $string = undef; + last if !defined $token; + } + + $previousToken = $token; + + if ($token =~ /^NSLocalized/ && $token !~ /NSLocalizedDescriptionKey/ && $token !~ /NSLocalizedStringFromTableInBundle/) { + print "$file:$.:ERROR:found a use of an NSLocalized macro; not supported\n"; + $nestingLevel = 0 if !defined $nestingLevel; + $sawError = 1; + $NSLocalizeCount++; + } elsif ($token eq "/*") { + if (!s-^.*?\*/--) { + $_ = ""; # If the comment doesn't end, discard the result of the line and set flag + $inComment = 1; + } + } elsif ($token eq "//") { + $_ = ""; # Discard the rest of the line + } elsif ($token eq "'") { + if (!s-([^\\]|\\.)'--) { #' <-- that single quote makes the Project Builder editor less confused + print "$file:$.:ERROR:mismatched single quote\n"; + $sawError = 1; + $_ = ""; + } + } else { + if ($expected and $expected ne $token) { + print "$file:$.:ERROR:found $token but expected $expected\n"; + $sawError = 1; + $expected = ""; + } + if ($token eq "UI_STRING" or $token eq "UI_STRING_KEY" or $token eq "LPCTSTR_UI_STRING" or $token eq "LPCTSTR_UI_STRING_KEY") { + $expected = "("; + $macro = $token; + $UIString = undef; + $key = undef; + $comment = undef; + $macroLine = $.; + } elsif ($token eq "(" or $token eq "[") { + ++$nestingLevel if defined $nestingLevel; + $expected = "a quoted string" if $expected; + } elsif ($token eq ",") { + $expected = "a quoted string" if $expected; + } elsif ($token eq ")" or $token eq "]") { + $nestingLevel = undef if defined $nestingLevel && !--$nestingLevel; + if ($expected) { + $key = $UIString if !defined $key; + HandleUIString($UIString, $key, $comment, $file, $macroLine); + $macro = ""; + $expected = ""; + $localizedCount++; + } + } elsif ($isDebugMacro{$token}) { + $nestingLevel = 0 if !defined $nestingLevel; + } + } + } + + } + + goto handleString if defined $string; + + if ($expected) { + print "$file:ERROR:reached end of file but expected $expected\n"; + $sawError = 1; + } + + close SOURCE; +} + +my %stringByKey; +my %commentByKey; +my %fileByKey; +my %lineByKey; + +sub HandleUIString +{ + my ($string, $key, $comment, $file, $line) = @_; + + my $bad = 0; + if (grep { $_ == 0xFFFD } unpack "U*", $string) { + print "$file:$line:ERROR:string for translation has illegal UTF-8 -- most likely a problem with the Text Encoding of the source file\n"; + $bad = 1; + } + if ($string ne $key && grep { $_ == 0xFFFD } unpack "U*", $key) { + print "$file:$line:ERROR:key has illegal UTF-8 -- most likely a problem with the Text Encoding of the source file\n"; + $bad = 1; + } + if (grep { $_ == 0xFFFD } unpack "U*", $comment) { + print "$file:$line:ERROR:comment for translation has illegal UTF-8 -- most likely a problem with the Text Encoding of the source file\n"; + $bad = 1; + } + if ($bad) { + $sawError = 1; + return; + } + + if ($stringByKey{$key} && $stringByKey{$key} ne $string) { + print "$file:$line:encountered the same key, \"$key\", twice, with different strings\n"; + print "$fileByKey{$key}:$lineByKey{$key}:previous occurrence\n"; + $keyCollisionCount++; + return; + } + if ($commentByKey{$key} && $commentByKey{$key} ne $comment) { + print "$file:$line:encountered the same key, \"$key\", twice, with different comments\n"; + print "$fileByKey{$key}:$lineByKey{$key}:previous occurrence\n"; + $keyCollisionCount++; + return; + } + + $fileByKey{$key} = $file; + $lineByKey{$key} = $line; + $stringByKey{$key} = $string; + $commentByKey{$key} = $comment; +} + +print "\n" if $sawError || $notLocalizedCount || $NSLocalizeCount; + +my @unusedExceptions = sort grep { !$usedException{$_} } keys %exception; +if (@unusedExceptions) { + for my $unused (@unusedExceptions) { + print "$exceptionsFile:$exception{$unused}:exception $unused not used\n"; + } + print "\n"; +} + +print "$localizedCount localizable strings\n" if $localizedCount; +print "$keyCollisionCount key collisions\n" if $keyCollisionCount; +print "$notLocalizedCount strings not marked for localization\n" if $notLocalizedCount; +print "$NSLocalizeCount uses of NSLocalize\n" if $NSLocalizeCount; +print scalar(@unusedExceptions), " unused exceptions\n" if @unusedExceptions; + +if ($sawError) { + print "\nErrors encountered. Exiting without writing a $stringsFile file.\n"; + exit 1; +} + +my $localizedStrings = ""; + +for my $key (sort keys %commentByKey) { + $localizedStrings .= "/* $commentByKey{$key} */\n\"$key\" = \"$stringByKey{$key}\";\n\n"; +} + +# Write out the strings file in UTF-16 with a BOM. +utf8::decode($localizedStrings) if $^V ge chr(5).chr(8); +my $output = pack "n*", (0xFEFF, unpack "U*", $localizedStrings); +foreach my $directory (@directories) { + if (-e "$directory/mac/$stringsFile") { + open STRINGS, ">", "$directory/mac/$stringsFile" or die; + print STRINGS $output; + close STRINGS; + } + + if (-e "$directory/win/$stringsFile") { + open STRINGS, ">", "$directory/win/$stringsFile" or die; + print STRINGS $output; + close STRINGS; + } + + if (-e "$directory/$stringsFile") { + open STRINGS, ">", "$directory/$stringsFile" or die; + print STRINGS $output; + close STRINGS; + } +} diff --git a/WebKitTools/Scripts/find-extra-includes b/WebKitTools/Scripts/find-extra-includes new file mode 100755 index 0000000..1286cd5 --- /dev/null +++ b/WebKitTools/Scripts/find-extra-includes @@ -0,0 +1,102 @@ +#!/usr/bin/perl -w + +# Copyright (C) 2005 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. + +# "find-extra-includes" script for Web Kit Open Source Project + +use strict; +use File::Find; + +find(\&wanted, @ARGV ? @ARGV : "."); + +my %paths; +my %includes; + +sub wanted +{ + my $file = $_; + + if ($file eq "icu") { + $File::Find::prune = 1; + return; + } + + if ($file !~ /^\./ && $file =~ /\.(h|cpp|c|mm|m)$/) { + $paths{$file} = $File::Find::name; + open FILE, $file or die; + while (<FILE>) { + if (m-^\s*#\s*(include|import)\s+["<]((\S+/)*)(\S+)[">]-) { + my $include = ($2 eq "sys/" ? $2 : "") . $4; + $includes{$file}{$include}++; + } + } + close FILE; + } +} + +my %totalIncludes; + +sub fillOut +{ + my ($file) = @_; + + return if defined $totalIncludes{$file}; + + for my $include (keys %{ $includes{$file} }) { + $totalIncludes{$file}{$include} = 1; + fillOut($include); + for my $i (keys %{ $totalIncludes{$include} }) { + $totalIncludes{$file}{$i} = 1; + } + } +} + +sub check +{ + my ($file) = @_; + + for my $include (keys %{ $includes{$file} }) { + fillOut($include); + } + for my $i1 (sort keys %{ $includes{$file} }) { + for my $i2 (keys %{ $includes{$file} }) { + next if $i1 eq $i2; + if ($totalIncludes{$i2}{$i1}) { + my $b1 = $i1; + my $b2 = $file; + $b1 =~ s/\..+$//; + $b2 =~ s/\..+$//; + print "$paths{$file} does not need to include $i1, because $i2 does\n" if $b1 ne $b2; + last; + } + } + } +} + +for my $file (sort keys %includes) { + check($file); +} diff --git a/WebKitTools/Scripts/find-included-framework-headers b/WebKitTools/Scripts/find-included-framework-headers new file mode 100755 index 0000000..3e7aaf6 --- /dev/null +++ b/WebKitTools/Scripts/find-included-framework-headers @@ -0,0 +1,10 @@ +#!/bin/sh + +FILE_EXTENSIONS_TO_SEARCH="cpp h m mm" + +for framework in $*; do + echo -e "\n$framework\n==================" + for ext in ${FILE_EXTENSIONS_TO_SEARCH}; do + find . -name "*.$ext" -exec grep $framework {} ';' | grep '\(include\|import\)' | sed -e 's|.*/\(.*\.h\).*|\1|' + done | sort | uniq +done diff --git a/WebKitTools/Scripts/gdb-drosera b/WebKitTools/Scripts/gdb-drosera new file mode 100644 index 0000000..fcde476 --- /dev/null +++ b/WebKitTools/Scripts/gdb-drosera @@ -0,0 +1,59 @@ +#!/usr/bin/perl -w + +# Copyright (C) 2007 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. + +# Simplified "run under gdb" script for Web Kit Open Source Project. + +use strict; +use Getopt::Long; +use FindBin; +use lib $FindBin::Bin; +use webkitdirs; +use File::Temp qw/:mktemp/; + +setConfiguration(); +my $productDir = productDir(); +my $droseraPath = "$productDir/Drosera.app/Contents/MacOS/Drosera"; + +# Check to see that gdb is in the usual place. +my $gdbPath = "/usr/bin/gdb"; +die "Can't find gdb executable. Is gdb installed?\n" unless -x $gdbPath; + +# Check to see that all the frameworks are built. +checkFrameworks(); + +# Put a command to set DYLD_FRAMEWORK_PATH in a temp file. +my ($fh, $path) = mkstemp("/tmp/gdb-drosera-XXXX"); +print $fh "set env DYLD_FRAMEWORK_PATH $productDir\n"; + +# Start up Drosera. +print "Start Drosera under gdb with DYLD_FRAMEWORK_PATH set to point to built WebKit in $productDir.\n"; +exec $gdbPath, "-x", $path, $droseraPath or die; + +# Delete the temporary file. +unlink0($fh, $path) or die "Error unlinking file $path safely"; + diff --git a/WebKitTools/Scripts/gdb-safari b/WebKitTools/Scripts/gdb-safari new file mode 100755 index 0000000..b94dc12 --- /dev/null +++ b/WebKitTools/Scripts/gdb-safari @@ -0,0 +1,61 @@ +#!/usr/bin/perl -w + +# Copyright (C) 2005 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. + +# Simplified "run under gdb" script for Web Kit Open Source Project. + +use strict; +use Getopt::Long; +use FindBin; +use lib $FindBin::Bin; +use webkitdirs; +use File::Temp qw/:mktemp/; + +setConfiguration(); +my $productDir = productDir(); +my $safariPath = safariPath(); + +# Check to see that gdb is in the usual place. +my $gdbPath = "/usr/bin/gdb"; +die "Can't find gdb executable. Is gdb installed?\n" unless -x $gdbPath; + +# Check to see that all the frameworks are built. +checkFrameworks(); + +# Put a command to set DYLD_FRAMEWORK_PATH in a temp file. +# Also set WEBKIT_UNSET_DYLD_FRAMEWORK_PATH to YES in this environment, so that +# executables launched by Safari don't inherit using the new frameworks. +my ($fh, $path) = mkstemp("/tmp/gdb-safari-XXXX"); +print $fh "set env DYLD_FRAMEWORK_PATH $productDir\n"; +print $fh "set env WEBKIT_UNSET_DYLD_FRAMEWORK_PATH YES\n"; + +# Start up Safari. +print "Start Safari under gdb with DYLD_FRAMEWORK_PATH set to point to built WebKit in $productDir.\n"; +exec $gdbPath, "-x", $path, $safariPath or die; + +# Delete the temporary file. +unlink0($fh, $path) or die "Error unlinking file $path safely"; diff --git a/WebKitTools/Scripts/generate-coverage-data b/WebKitTools/Scripts/generate-coverage-data new file mode 100755 index 0000000..7ed36aa --- /dev/null +++ b/WebKitTools/Scripts/generate-coverage-data @@ -0,0 +1,71 @@ +#!/usr/bin/perl -w + +# Copyright (C) 2005, 2006 Apple Computer, Inc. All rights reserved. +# Copyright (C) 2007 Holger Hans Peter Freyther. 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. + +# Simple script to build, run and visualize coverage information + +use strict; +use File::Basename; +use File::Spec; +use FindBin; +use Getopt::Long qw(:config pass_through); +use lib $FindBin::Bin; +use webkitdirs; +use POSIX; + +# Generate a name for our results +my $svnVersion = determineCurrentSVNRevision(); +my @timeData = localtime(time); +my $resultName = $svnVersion . "-" . join('_', @timeData); +my @otherOptions = (); + +# Move to the source directory +# Delete old gcov files +# Compile WebKit and run the tests +# Generate the coverage graph... +# Upload + +$ENV{'WEBKIT_COVERAGE_BUILD'} = 1; +chdirWebKit(); + +# Clean-up old files +print "Cleaning up\n"; +system("if [ -d WebKitBuild ]; then find WebKitBuild -name '*.gcda' -delete; fi;") == 0 or die; + + +print "Building and testing\n"; +system("WebKitTools/Scripts/build-webkit", "--coverage", @ARGV) == 0 or die; +system "WebKitTools/Scripts/run-webkit-tests", "--no-launch-safari"; +system "WebKitTools/Scripts/run-javascriptcore-tests", "--coverage", @ARGV; + +# Collect the data and generate a report +print "Collecting coverage data\n"; +system("WebKitTools/CodeCoverage/run-generate-coverage-data", $resultName, "WebKitBuild/Coverage") == 0 or die; +system("WebKitTools/CodeCoverage/regenerate-coverage-display", "WebKitBuild/Coverage", "WebKitBuild/Coverage/html") == 0 or die; + +print "Done\n"; diff --git a/WebKitTools/Scripts/make-js-test-wrappers b/WebKitTools/Scripts/make-js-test-wrappers new file mode 100755 index 0000000..b58978f --- /dev/null +++ b/WebKitTools/Scripts/make-js-test-wrappers @@ -0,0 +1,103 @@ +#!/usr/bin/perl -w + +# Copyright (C) 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. + +# Script to generate HTML wrappers for JavaScript tests from templates + +use strict; +use FindBin; +use lib $FindBin::Bin; +use webkitdirs; + +setConfiguration(); +my $productDir = productDir(); + +use strict; + +chdirWebKit(); + +my @templates = `find LayoutTests -name "TEMPLATE.html"`; + +for my $tfile (@templates) { + + chomp $tfile; + + my $tpath = $tfile; + $tpath =~ s:/resources/TEMPLATE.html$::; + + print "${tpath}\n"; + + chdirWebKit(); + chdir($tpath); + + my @files = `find resources -name "*.js"`; + + open TEMPLATE, "<resources/TEMPLATE.html"; + my $template = do { local $/; <TEMPLATE> }; + close TEMPLATE; + + my $templateNegative = $template; + if (-e "resources/TEMPLATE-n.html") { + open TEMPLATE, "<resources/TEMPLATE-n.html"; + $templateNegative = do { local $/; <TEMPLATE> }; + close TEMPLATE; + } + + for my $file (@files) { + chomp $file; + next if $file =~ /js-test-.*\.js$/; + next if $file =~ /SVGTestCase\.js/; + next if $file =~ m:resources/attr-case-sensitivity\.js$:; + next if $file =~ m:resources/frame-loading-via-document-write\.js$:; + next if $file =~ m:resources/intersectsNode\.js$:; + next if $file =~ m:resources/script-element-gc\.js$:; + next if $file =~ m:resources/script-element-gc\.js$:; + next if $file =~ m:resources/script3\.js$:; + next if $file =~ m:resources/script4\.js$:; + next if $file =~ m:resources/script5\.js$:; + next if $file =~ m:resources/select-options-remove\.js$:; + next if $file =~ m:resources/wrapper-identity-base\.js$:; + + my $html = $file; + $html =~ s:resources/(.*)\.js:$1.html:; + next if -f "$html-disabled"; + + system("grep -q 'successfullyParsed =' $file"); + if ($? != 0) { + `echo "" >> "${file}"`; + `echo "var successfullyParsed = true;" >> "${file}"`; + } + + print " ${html}\n"; + open HTML, ">$html"; + my $output = ($file =~ /-n\.js/) ? $templateNegative : $template; + $output =~ s:YOUR_JS_FILE_HERE:$file:; + print HTML $output; + + close HTML; + } +} diff --git a/WebKitTools/Scripts/num-cpus b/WebKitTools/Scripts/num-cpus new file mode 100755 index 0000000..c5f28a1 --- /dev/null +++ b/WebKitTools/Scripts/num-cpus @@ -0,0 +1,16 @@ +#!/usr/bin/perl + +use strict; +use warnings; + +use Win32API::Registry 0.21 qw( :ALL ); + + +my $key; +my $i = 0; +while (RegOpenKeyEx(HKEY_LOCAL_MACHINE, "HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\$i", 0, KEY_READ, $key)) { + $i++; + RegCloseKey($key); +} + +print "$i\n"; diff --git a/WebKitTools/Scripts/parallelcl b/WebKitTools/Scripts/parallelcl new file mode 100755 index 0000000..532079f --- /dev/null +++ b/WebKitTools/Scripts/parallelcl @@ -0,0 +1,224 @@ +#!/usr/bin/perl + +use strict; +use warnings; + +use File::Basename; +use File::Spec; +use File::Temp; +use POSIX; + +sub makeJob(\@$); +sub forkAndCompileFiles(\@$); +sub Exec($); +sub waitForChild(\@); +sub cleanup(\@); + +my $debug = 0; + +chomp(my $clexe = `cygpath -u '$ENV{'VS80COMNTOOLS'}/../../VC/bin/cl.exe'`); + +if ($debug) { + print STDERR "Received " . @ARGV . " arguments:\n"; + foreach my $arg (@ARGV) { + print STDERR "$arg\n"; + } +} + +my $commandFile; +foreach my $arg (@ARGV) { + if ($arg =~ /^[\/-](E|EP|P)$/) { + print STDERR "The invoking process wants preprocessed source, so let's hand off this whole command to the real cl.exe\n" if $debug; + Exec("\"$clexe\" \"" . join('" "', @ARGV) . "\""); + } elsif ($arg =~ /^@(.*)$/) { + chomp($commandFile = `cygpath -u '$1'`); + } +} + +die "No command file specified!" unless $commandFile; +die "Couldn't find $commandFile!" unless -f $commandFile; + +my @sources; + +open(COMMAND, '<:raw:encoding(UTF16-LE):crlf:utf8', $commandFile) or die "Couldn't open $commandFile!"; + +# The first line of the command file contains all the options to cl.exe plus the first (possibly quoted) filename +my $firstLine = <COMMAND>; +$firstLine =~ s/\r?\n$//; + +# To find the start of the first filename, look for either the last space on the line. +# If the filename is quoted, the last character on the line will be a quote, so look for the quote before that. +my $firstFileIndex; +print STDERR "Last character of first line = '" . substr($firstLine, -1, 1) . "'\n" if $debug; +if (substr($firstLine, -1, 1) eq '"') { + print STDERR "First file is quoted\n" if $debug; + $firstFileIndex = rindex($firstLine, '"', length($firstLine) - 2); +} else { + print STDERR "First file is NOT quoted\n" if $debug; + $firstFileIndex = rindex($firstLine, ' ') + 1; +} + +my $options = substr($firstLine, 0, $firstFileIndex) . join(' ', @ARGV[1 .. $#ARGV]); +my $possibleFirstFile = substr($firstLine, $firstFileIndex); +if ($possibleFirstFile =~ /\.(cpp|c)/) { + push(@sources, $possibleFirstFile); +} else { + $options .= " $possibleFirstFile"; +} + +print STDERR "######## Found options $options ##########\n" if $debug; +print STDERR "####### Found first source file $sources[0] ########\n" if @sources && $debug; + +# The rest of the lines of the command file just contain source files, one per line +while (my $source = <COMMAND>) { + chomp($source); + $source =~ s/^\s+//; + $source =~ s/\s+$//; + push(@sources, $source) if length($source); +} +close(COMMAND); + +my $numSources = @sources; +exit unless $numSources > 0; + +my $numJobs; +if ($options =~ s/-j\s*([0-9]+)//) { + $numJobs = $1; +} else { + chomp($numJobs = `num-cpus`); +} + +print STDERR "\n\n####### RUNNING AT MOST $numJobs PARALLEL INSTANCES OF cl.exe ###########\n\n";# if $debug; + +# Magic determination of job size +# The hope is that by splitting the source files up into 2*$numJobs pieces, we +# won't suffer too much if one job finishes much more quickly than another. +# However, we don't want to split it up too much due to cl.exe overhead, so set +# the minimum job size to 5. +my $jobSize = POSIX::ceil($numSources / (2 * $numJobs)); +$jobSize = $jobSize < 5 ? 5 : $jobSize; + +print STDERR "######## jobSize = $jobSize ##########\n" if $debug; + +# Sort the source files randomly so that we don't end up with big clumps of large files (aka SVG) +sub fisher_yates_shuffle(\@) +{ + my ($array) = @_; + for (my $i = @{$array}; --$i; ) { + my $j = int(rand($i+1)); + next if $i == $j; + @{$array}[$i,$j] = @{$array}[$j,$i]; + } +} + +fisher_yates_shuffle(@sources); # permutes @array in place + +my @children; +my @tmpFiles; +my $status = 0; +while (@sources) { + while (@sources && @children < $numJobs) { + my $pid; + my $tmpFile; + my $job = makeJob(@sources, $jobSize); + ($pid, $tmpFile) = forkAndCompileFiles(@{$job}, $options); + + print STDERR "####### Spawned child with PID $pid and tmpFile $tmpFile ##########\n" if $debug; + push(@children, $pid); + push(@tmpFiles, $tmpFile); + } + + $status |= waitForChild(@children); +} + +while (@children) { + $status |= waitForChild(@children); +} +cleanup(@tmpFiles); + +exit WEXITSTATUS($status); + + +sub makeJob(\@$) +{ + my ($files, $jobSize) = @_; + + my @job; + if (@{$files} > ($jobSize * 1.5)) { + @job = splice(@{$files}, -$jobSize); + } else { + # Compile all the remaining files in this job to avoid having a small job later + @job = splice(@{$files}); + } + + return \@job; +} + +sub forkAndCompileFiles(\@$) +{ + print STDERR "######## forkAndCompileFiles()\n" if $debug; + my ($files, $options) = @_; + + if ($debug) { + foreach my $file (@{$files}) { + print STDERR "######## $file\n"; + } + } + + my (undef, $tmpFile) = File::Temp::tempfile('clcommandXXXXX', DIR => File::Spec->tmpdir, OPEN => 0); + + my $pid = fork(); + die "Fork failed" unless defined($pid); + + unless ($pid) { + # Child process + open(TMP, '>:raw:encoding(UTF16-LE):crlf:utf8', $tmpFile) or die "Couldn't open $tmpFile"; + print TMP "$options\n"; + foreach my $file (@{$files}) { + print TMP "$file\n"; + } + close(TMP); + + chomp(my $winTmpFile = `cygpath -m $tmpFile`); + Exec "\"$clexe\" \@\"$winTmpFile\""; + } else { + return ($pid, $tmpFile); + } +} + +sub Exec($) +{ + my ($command) = @_; + + print STDERR "Exec($command)\n" if $debug; + + exec($command); +} + +sub waitForChild(\@) +{ + my ($children) = @_; + + return unless @{$children}; + + my $deceased = wait(); + my $status = $?; + print STDERR "######## Child with PID $deceased finished ###########\n" if $debug; + for (my $i = 0; $i < @{$children}; $i++) { + if ($children->[$i] == $deceased) { + splice(@{$children}, $i, 1); + last; + } + } + + return $status; +} + +sub cleanup(\@) +{ + my ($tmpFiles) = @_; + + foreach my $file (@{$tmpFiles}) { + unlink $file; + } +} diff --git a/WebKitTools/Scripts/parse-malloc-history b/WebKitTools/Scripts/parse-malloc-history new file mode 100755 index 0000000..76ca74b --- /dev/null +++ b/WebKitTools/Scripts/parse-malloc-history @@ -0,0 +1,154 @@ +#!/usr/bin/perl + +# Copyright (C) 2007 Apple 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. + +# Parses the callstacks in a file with malloc_history formatted content, sorting +# based on total number of bytes allocated, and filtering based on command-line +# parameters. + +use Getopt::Long; +use File::Basename; + +use strict; +use warnings; + +sub commify($); + +sub main() +{ + my $usage = + "Usage: " . basename($0) . " [options] malloc_history.txt\n" . + " --grep-regexp Include only call stacks that match this regular expression.\n" . + " --byte-minimum Include only call stacks with allocation sizes >= this value.\n" . + " --merge-regexp Merge all call stacks that match this regular expression.\n" . + " --merge-depth Merge all call stacks that match at this stack depth and above.\n"; + + my $grepRegexp = ""; + my $byteMinimum = ""; + my @mergeRegexps = (); + my $mergeDepth = ""; + my $getOptionsResult = GetOptions( + "grep-regexp:s" => \$grepRegexp, + "byte-minimum:i" => \$byteMinimum, + "merge-regexp:s" => \@mergeRegexps, + "merge-depth:i" => \$mergeDepth + ); + my $fileName = $ARGV[0]; + die $usage if (!$getOptionsResult || !$fileName); + + open FILE, "<$fileName" or die "bad file: $fileName"; + my @file = <FILE>; + close FILE; + + my %callstacks = (); + my $byteCountTotal = 0; + + for (my $i = 0; $i < @file; $i++) { + my $line = $file[$i]; + my ($callCount, $byteCount); + + next if $line =~ /^\-/; + + # First try malloc_history format + # 6 calls for 664 bytes thread_ffffffff |0x0 | start + ($callCount, $byteCount) = ($line =~ /(\d+) calls for (\d+) bytes/); + + # Then try leaks format + # Leak: 0x0ac3ca40 size=48 + # 0x00020001 0x00000001 0x00000000 0x00000000 ................ + # Call stack: [thread ffffffff]: | 0x0 | start + if (!$callCount || !$byteCount) { + $callCount = 1; + ($byteCount) = ($line =~ /Leak: [x[:xdigit:]]* size=(\d+)/); + + if ($byteCount) { + while (!($line =~ "Call stack: ")) { + $i++; + $line = $file[$i]; + } + } + } + + # Then give up + next if (!$callCount || !$byteCount); + + $byteCountTotal += $byteCount; + + next if ($grepRegexp && !($line =~ $grepRegexp)); + + my $callstackBegin = 0; + if ($mergeDepth) { + # count stack frames backwards from end of callstack + $callstackBegin = length($line); + for (my $pipeCount = 0; $pipeCount < $mergeDepth; $pipeCount++) { + my $rindexResult = rindex($line, "|", $callstackBegin - 1); + last if $rindexResult == -1; + $callstackBegin = $rindexResult; + } + } else { + # start at beginning of callstack + $callstackBegin = index($line, "|"); + } + + my $callstack = substr($line, $callstackBegin + 2); # + 2 skips "| " + for my $regexp (@mergeRegexps) { + if ($callstack =~ $regexp) { + $callstack = $regexp . "\n"; + last; + } + } + + if (!$callstacks{$callstack}) { + $callstacks{$callstack} = {"callCount" => 0, "byteCount" => 0}; + } + + $callstacks{$callstack}{"callCount"} += $callCount; + $callstacks{$callstack}{"byteCount"} += $byteCount; + } + + my $byteCountTotalReported = 0; + for my $callstack (sort { $callstacks{$b}{"byteCount"} <=> $callstacks{$a}{"byteCount"} } keys %callstacks) { + my $callCount = $callstacks{$callstack}{"callCount"}; + my $byteCount = $callstacks{$callstack}{"byteCount"}; + last if ($byteMinimum && $byteCount < $byteMinimum); + + $byteCountTotalReported += $byteCount; + print commify($callCount) . " calls for " . commify($byteCount) . " bytes: $callstack\n"; + } + + print "total: " . commify($byteCountTotalReported) . " bytes (" . commify($byteCountTotal - $byteCountTotalReported) . " bytes excluded).\n"; +} + +exit(main()); + +# Copied from perldoc -- please excuse the style +sub commify($) +{ + local $_ = shift; + 1 while s/^([-+]?\d+)(\d{3})/$1,$2/; + return $_; +} diff --git a/WebKitTools/Scripts/pdevenv b/WebKitTools/Scripts/pdevenv new file mode 100755 index 0000000..8072adf --- /dev/null +++ b/WebKitTools/Scripts/pdevenv @@ -0,0 +1,24 @@ +#!/usr/bin/perl -w + +use strict; +use warnings; + +use File::Temp qw/tempfile/; +use FindBin; + +my ($fh, $path) = tempfile(UNLINK => 0, SUFFIX => '.cmd') or die; + +chomp(my $vcBin = `cygpath -w "$FindBin::Bin/../vcbin"`); + +print $fh "\@echo off\n\n"; +print $fh "call \"\%VS80COMNTOOLS\%\\vsvars32.bat\"\n\n"; +print $fh "set PATH=$vcBin;\%PATH\%\n\n"; +print $fh "devenv.com /useenv " . join(" ", @ARGV) . "\n"; + +close $fh; + +chmod 0755, $path; + +chomp($path = `cygpath -w -s '$path'`); + +exec("cmd /c \"call $path\""); diff --git a/WebKitTools/Scripts/prepare-ChangeLog b/WebKitTools/Scripts/prepare-ChangeLog new file mode 100755 index 0000000..913eea5 --- /dev/null +++ b/WebKitTools/Scripts/prepare-ChangeLog @@ -0,0 +1,1256 @@ +#!/usr/bin/perl -w +# -*- Mode: perl; indent-tabs-mode: nil; c-basic-offset: 2 -*- + +# +# Copyright (C) 2000, 2001 Eazel, Inc. +# Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 Apple Inc. All rights reserved. +# +# prepare-ChangeLog is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public +# License as published by the Free Software Foundation; either +# version 2 of the License, or (at your option) any later version. +# +# prepare-ChangeLog is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public +# License along with this program; if not, write to the Free +# Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +# + + +# Perl script to create a ChangeLog entry with names of files +# and functions from a diff. +# +# Darin Adler <darin@bentspoon.com>, started 20 April 2000 +# Java support added by Maciej Stachowiak <mjs@eazel.com> +# Objective-C, C++ and Objective-C++ support added by Maciej Stachowiak <mjs@apple.com> +# Git support added by Adam Roben <aroben@apple.com> + + +# +# TODO: +# List functions that have been removed too. +# Decide what a good logical order is for the changed files +# other than a normal text "sort" (top level first?) +# (group directories?) (.h before .c?) +# Handle yacc source files too (other languages?). +# Help merge when there are ChangeLog conflicts or if there's +# already a partly written ChangeLog entry. +# Add command line option to put the ChangeLog into a separate +# file or just spew it out stdout. +# Add SVN version numbers for commit (can't do that until +# the changes are checked in, though). +# Work around diff stupidity where deleting a function that starts +# with a comment makes diff think that the following function +# has been changed (if the following function starts with a comment +# with the same first line, such as /**) +# Work around diff stupidity where deleting an entire function and +# the blank lines before it makes diff think you've changed the +# previous function. + +use strict; +use warnings; + +use File::Basename; +use File::Spec; +use FindBin; +use Getopt::Long; +use lib $FindBin::Bin; +use POSIX qw(strftime); +use VCSUtils; + +sub changeLogDate($); +sub firstDirectoryOrCwd(); +sub diffFromToString(); +sub diffCommand(@); +sub statusCommand(@); +sub createPatchCommand($); +sub diffHeaderFormat(); +sub findOriginalFileFromSvn($); +sub generateFileList(\@\@\%); +sub gitConfig($); +sub isModifiedStatus($); +sub isAddedStatus($); +sub isConflictStatus($); +sub statusDescription($$); +sub extractLineRange($); +sub canonicalizePath($); +sub testListForChangeLog(@); +sub get_function_line_ranges($$); +sub get_function_line_ranges_for_c($$); +sub get_function_line_ranges_for_java($$); +sub method_decl_to_selector($); +sub processPaths(\@); +sub reviewerAndDescriptionForGitCommit($); + +# Project time zone for Cupertino, CA, US +my $changeLogTimeZone = "PST8PDT"; + +my $gitCommit = 0; +my $gitReviewer = ""; +my $openChangeLogs = 0; +my $showHelp = 0; +my $spewDiff = $ENV{"PREPARE_CHANGELOG_DIFF"}; +my $updateChangeLogs = 1; +my $parseOptionsResult = + GetOptions("diff|d!" => \$spewDiff, + "git-commit:s" => \$gitCommit, + "git-reviewer:s" => \$gitReviewer, + "help|h!" => \$showHelp, + "open|o!" => \$openChangeLogs, + "update!" => \$updateChangeLogs); +if (!$parseOptionsResult || $showHelp) { + print STDERR basename($0) . " [-d|--diff] [-h|--help] [-o|--open] [--git-commit=<committish>] [--git-reviewer=<name>] [svndir1 [svndir2 ...]]\n"; + print STDERR " -d|--diff Spew diff to stdout when running\n"; + print STDERR " --git-commit Populate the ChangeLogs from the specified git commit\n"; + print STDERR " --git-reviewer When populating the ChangeLogs from a git commit claim that the spcified name reviewed the change.\n"; + print STDERR " This option is useful when the git commit lacks a Signed-Off-By: line\n"; + print STDERR " -h|--help Show this help message\n"; + print STDERR " -o|--open Open ChangeLogs in an editor when done\n"; + print STDERR " --[no-]update Update ChangeLogs from svn before adding entry (default: update)\n"; + exit 1; +} + +my %paths = processPaths(@ARGV); + +my $isGit = isGitDirectory(firstDirectoryOrCwd()); +my $isSVN = isSVNDirectory(firstDirectoryOrCwd()); + +$isSVN || $isGit || die "Couldn't determine your version control system."; + +# Find the list of modified files +my @changed_files; +my $changed_files_string; +my %changed_line_ranges; +my %function_lists; +my @conflict_files; + +my $SVN = "svn"; +my $GIT = "git"; + +my %supportedTestExtensions = map { $_ => 1 } qw(html shtml svg xml xhtml pl php); +my @addedRegressionTests = (); +my $didChangeRegressionTests = 0; + +generateFileList(@changed_files, @conflict_files, %function_lists); + +if (!@changed_files && !@conflict_files && !keys %function_lists) { + print STDERR " No changes found.\n"; + exit 1; +} + +if (@conflict_files) { + print STDERR " The following files have conflicts. Run prepare-ChangeLog again after fixing the conflicts:\n"; + print STDERR join("\n", @conflict_files), "\n"; + exit 1; +} + +if (@changed_files) { + $changed_files_string = "'" . join ("' '", @changed_files) . "'"; + + # For each file, build a list of modified lines. + # Use line numbers from the "after" side of each diff. + print STDERR " Reviewing diff to determine which lines changed.\n"; + my $file; + open DIFF, "-|", diffCommand(@changed_files) or die "The diff failed: $!.\n"; + while (<DIFF>) { + $file = makeFilePathRelative($1) if $_ =~ diffHeaderFormat(); + if (defined $file) { + my ($start, $end) = extractLineRange($_); + if ($start >= 0 && $end >= 0) { + push @{$changed_line_ranges{$file}}, [ $start, $end ]; + } elsif (/DO_NOT_COMMIT/) { + print STDERR "WARNING: file $file contains the string DO_NOT_COMMIT, line $.\n"; + } + } + } + close DIFF; +} + +# For each source file, convert line range to function list. +if (%changed_line_ranges) { + print STDERR " Extracting affected function names from source files.\n"; + foreach my $file (keys %changed_line_ranges) { + # Only look for function names in .c files. + next unless $file =~ /\.(c|cpp|m|mm|h|java)/; + + # Find all the functions in the file. + open SOURCE, $file or next; + my @function_ranges = get_function_line_ranges(\*SOURCE, $file); + close SOURCE; + + # Find all the modified functions. + my @functions; + my %saw_function; + my @change_ranges = (@{$changed_line_ranges{$file}}, []); + my @change_range = (0, 0); + FUNCTION: foreach my $function_range_ref (@function_ranges) { + my @function_range = @$function_range_ref; + + # Advance to successive change ranges. + for (;; @change_range = @{shift @change_ranges}) { + last FUNCTION unless @change_range; + + # If past this function, move on to the next one. + next FUNCTION if $change_range[0] > $function_range[1]; + + # If an overlap with this function range, record the function name. + if ($change_range[1] >= $function_range[0] + and $change_range[0] <= $function_range[1]) { + if (!$saw_function{$function_range[2]}) { + $saw_function{$function_range[2]} = 1; + push @functions, $function_range[2]; + } + next FUNCTION; + } + } + } + + # Format the list of functions now. + + if (@functions) { + $function_lists{$file} = "" if !defined $function_lists{$file}; + $function_lists{$file} .= "\n (" . join("):\n (", @functions) . "):"; + } + } +} + +# Get some parameters for the ChangeLog we are about to write. +my $date = changeLogDate($changeLogTimeZone); +my $name = $ENV{CHANGE_LOG_NAME} + || $ENV{REAL_NAME} + || gitConfig("user.name") + || (split /\s*,\s*/, (getpwuid $<)[6])[0] + || "set REAL_NAME environment variable"; +my $email_address = $ENV{CHANGE_LOG_EMAIL_ADDRESS} + || $ENV{EMAIL_ADDRESS} + || gitConfig("user.email") + || "set EMAIL_ADDRESS environment variable"; + +if ($gitCommit) { + $name = `$GIT log --max-count=1 --pretty=\"format:%an\" \"$gitCommit\"`; + $email_address = `$GIT log --max-count=1 --pretty=\"format:%ae\" \"$gitCommit\"`; +} + +# Remove trailing parenthesized notes from user name (bit of hack). +$name =~ s/\(.*?\)\s*$//g; + +# Find the change logs. +my %has_log; +my %files; +foreach my $file (sort keys %function_lists) { + my $prefix = $file; + my $has_log = 0; + while ($prefix) { + $prefix =~ s-/[^/]+/?$-/- or $prefix = ""; + $has_log = $has_log{$prefix}; + if (!defined $has_log) { + $has_log = -f "${prefix}ChangeLog"; + $has_log{$prefix} = $has_log; + } + last if $has_log; + } + if (!$has_log) { + print STDERR "No ChangeLog found for $file.\n"; + } else { + push @{$files{$prefix}}, $file; + } +} + +# Get the latest ChangeLog files from svn. +my @logs = (); +foreach my $prefix (sort keys %files) { + push @logs, File::Spec->catfile($prefix || ".", "ChangeLog"); +} + +if (@logs && $updateChangeLogs && $isSVN) { + print STDERR " Running 'svn update' to update ChangeLog files.\n"; + open ERRORS, "-|", $SVN, "update", @logs + or die "The svn update of ChangeLog files failed: $!.\n"; + my @conflictedChangeLogs; + while (my $line = <ERRORS>) { + print STDERR " ", $line; + push @conflictedChangeLogs, $1 if $line =~ m/^C\s+(.+)\s*$/; + } + close ERRORS; + + if (@conflictedChangeLogs) { + print STDERR " Attempting to merge conflicted ChangeLogs.\n"; + my $resolveChangeLogsPath = File::Spec->catfile(dirname($0), "resolve-ChangeLogs"); + open RESOLVE, "-|", $resolveChangeLogsPath, "--no-warnings", @conflictedChangeLogs + or die "Could not open resolve-ChangeLogs script: $!.\n"; + print STDERR " $_" while <RESOLVE>; + close RESOLVE; + } +} + +# Write out a new ChangeLog file. +foreach my $prefix (sort keys %files) { + my $changeLogPath = File::Spec->catfile($prefix || ".", "ChangeLog"); + print STDERR " Editing the ${changeLogPath} file.\n"; + open OLD_CHANGE_LOG, ${changeLogPath} or die "Could not open ${changeLogPath} file: $!.\n"; + # It's less efficient to read the whole thing into memory than it would be + # to read it while we prepend to it later, but I like doing this part first. + my @old_change_log = <OLD_CHANGE_LOG>; + close OLD_CHANGE_LOG; + open CHANGE_LOG, "> ${changeLogPath}" or die "Could not write ${changeLogPath}\n."; + print CHANGE_LOG "$date $name <$email_address>\n\n"; + + my ($reviewer, $description) = reviewerAndDescriptionForGitCommit($gitCommit) if $gitCommit; + $reviewer = "NOBODY (OO" . "PS!)" if !$reviewer; + + print CHANGE_LOG " Reviewed by $reviewer.\n\n"; + print CHANGE_LOG $description . "\n" if $description; + + if ($prefix =~ m/WebCore/ || `pwd` =~ m/WebCore/) { + if ($didChangeRegressionTests) { + print CHANGE_LOG testListForChangeLog(sort @addedRegressionTests); + } else { + print CHANGE_LOG " WARNING: NO TEST CASES ADDED OR CHANGED\n\n"; + } + } + + foreach my $file (sort @{$files{$prefix}}) { + my $file_stem = substr $file, length $prefix; + print CHANGE_LOG " * $file_stem:$function_lists{$file}\n"; + } + print CHANGE_LOG "\n", @old_change_log; + close CHANGE_LOG; +} + +# Write out another diff. +if ($spewDiff && @changed_files) { + print STDERR " Running diff to help you write the ChangeLog entries.\n"; + local $/ = undef; # local slurp mode + open DIFF, "-|", createPatchCommand($changed_files_string) or die "The diff failed: $!.\n"; + print <DIFF>; + close DIFF; +} + +# Open ChangeLogs. +if ($openChangeLogs && @logs) { + print STDERR " Opening the edited ChangeLog files.\n"; + my $editor = $ENV{"CHANGE_LOG_EDIT_APPLICATION"}; + if ($editor) { + system "open", "-a", $editor, @logs; + } else { + system "open", "-e", @logs; + } +} + +# Done. +exit; + +sub canonicalizePath($) +{ + my ($file) = @_; + + # Remove extra slashes and '.' directories in path + $file = File::Spec->canonpath($file); + + # Remove '..' directories in path + my @dirs = (); + foreach my $dir (File::Spec->splitdir($file)) { + if ($dir eq '..' && $#dirs >= 0 && $dirs[$#dirs] ne '..') { + pop(@dirs); + } else { + push(@dirs, $dir); + } + } + return ($#dirs >= 0) ? File::Spec->catdir(@dirs) : "."; +} + +sub changeLogDate($) +{ + my ($timeZone) = @_; + my $savedTimeZone = $ENV{'TZ'}; + # Set TZ temporarily so that localtime() is in that time zone + $ENV{'TZ'} = $timeZone; + my $date = strftime("%Y-%m-%d", localtime()); + if (defined $savedTimeZone) { + $ENV{'TZ'} = $savedTimeZone; + } else { + delete $ENV{'TZ'}; + } + return $date; +} + +sub get_function_line_ranges($$) +{ + my ($file_handle, $file_name) = @_; + + if ($file_name =~ /\.(c|cpp|m|mm|h)$/) { + return get_function_line_ranges_for_c ($file_handle, $file_name); + } elsif ($file_name =~ /\.java$/) { + return get_function_line_ranges_for_java ($file_handle, $file_name); + } + return (); +} + + +sub method_decl_to_selector($) +{ + (my $method_decl) = @_; + + $_ = $method_decl; + + if ((my $comment_stripped) = m-([^/]*)(//|/*).*-) { + $_ = $comment_stripped; + } + + s/,\s*...//; + + if (/:/) { + my @components = split /:/; + pop @components if (scalar @components > 1); + $_ = (join ':', map {s/.*[^[:word:]]//; scalar $_;} @components) . ':'; + } else { + s/\s*$//; + s/.*[^[:word:]]//; + } + + return $_; +} + + + +# Read a file and get all the line ranges of the things that look like C functions. +# A function name is the last word before an open parenthesis before the outer +# level open brace. A function starts at the first character after the last close +# brace or semicolon before the function name and ends at the close brace. +# Comment handling is simple-minded but will work for all but pathological cases. +# +# Result is a list of triples: [ start_line, end_line, function_name ]. + +sub get_function_line_ranges_for_c($$) +{ + my ($file_handle, $file_name) = @_; + + my @ranges; + + my $in_comment = 0; + my $in_macro = 0; + my $in_method_declaration = 0; + my $in_parentheses = 0; + my $in_braces = 0; + my $brace_start = 0; + my $brace_end = 0; + my $skip_til_brace_or_semicolon = 0; + + my $word = ""; + my $interface_name = ""; + + my $potential_method_char = ""; + my $potential_method_spec = ""; + + my $potential_start = 0; + my $potential_name = ""; + + my $start = 0; + my $name = ""; + + my $next_word_could_be_namespace = 0; + my $potential_namespace = ""; + my @namespaces; + + while (<$file_handle>) { + # Handle continued multi-line comment. + if ($in_comment) { + next unless s-.*\*/--; + $in_comment = 0; + } + + # Handle continued macro. + if ($in_macro) { + $in_macro = 0 unless /\\$/; + next; + } + + # Handle start of macro (or any preprocessor directive). + if (/^\s*\#/) { + $in_macro = 1 if /^([^\\]|\\.)*\\$/; + next; + } + + # Handle comments and quoted text. + while (m-(/\*|//|\'|\")-) { # \' and \" keep emacs perl mode happy + my $match = $1; + if ($match eq "/*") { + if (!s-/\*.*?\*/--) { + s-/\*.*--; + $in_comment = 1; + } + } elsif ($match eq "//") { + s-//.*--; + } else { # ' or " + if (!s-$match([^\\]|\\.)*?$match--) { + warn "mismatched quotes at line $. in $file_name\n"; + s-$match.*--; + } + } + } + + + # continued method declaration + if ($in_method_declaration) { + my $original = $_; + my $method_cont = $_; + + chomp $method_cont; + $method_cont =~ s/[;\{].*//; + $potential_method_spec = "${potential_method_spec} ${method_cont}"; + + $_ = $original; + if (/;/) { + $potential_start = 0; + $potential_method_spec = ""; + $potential_method_char = ""; + $in_method_declaration = 0; + s/^[^;\{]*//; + } elsif (/{/) { + my $selector = method_decl_to_selector ($potential_method_spec); + $potential_name = "${potential_method_char}\[${interface_name} ${selector}\]"; + + $potential_method_spec = ""; + $potential_method_char = ""; + $in_method_declaration = 0; + + $_ = $original; + s/^[^;{]*//; + } elsif (/\@end/) { + $in_method_declaration = 0; + $interface_name = ""; + $_ = $original; + } else { + next; + } + } + + + # start of method declaration + if ((my $method_char, my $method_spec) = m&^([-+])([^0-9;][^;]*);?$&) { + my $original = $_; + + if ($interface_name) { + chomp $method_spec; + $method_spec =~ s/\{.*//; + + $potential_method_char = $method_char; + $potential_method_spec = $method_spec; + $potential_start = $.; + $in_method_declaration = 1; + } else { + warn "declaring a method but don't have interface on line $. in $file_name\n"; + } + $_ = $original; + if (/\{/) { + my $selector = method_decl_to_selector ($potential_method_spec); + $potential_name = "${potential_method_char}\[${interface_name} ${selector}\]"; + + $potential_method_spec = ""; + $potential_method_char = ""; + $in_method_declaration = 0; + $_ = $original; + s/^[^{]*//; + } elsif (/\@end/) { + $in_method_declaration = 0; + $interface_name = ""; + $_ = $original; + } else { + next; + } + } + + + # Find function, interface and method names. + while (m&((?:[[:word:]]+::)*operator(?:[ \t]*\(\)|[^()]*)|[[:word:]:~]+|[(){}:;])|\@(?:implementation|interface|protocol)\s+(\w+)[^{]*&g) { + # interface name + if ($2) { + $interface_name = $2; + next; + } + + # Open parenthesis. + if ($1 eq "(") { + $potential_name = $word unless $in_parentheses || $skip_til_brace_or_semicolon; + $in_parentheses++; + next; + } + + # Close parenthesis. + if ($1 eq ")") { + $in_parentheses--; + next; + } + + # C++ constructor initializers + if ($1 eq ":") { + $skip_til_brace_or_semicolon = 1 unless ($in_parentheses || $in_braces); + } + + # Open brace. + if ($1 eq "{") { + $skip_til_brace_or_semicolon = 0; + + if ($potential_namespace) { + push @namespaces, $potential_namespace; + $potential_namespace = ""; + next; + } + + # Promote potential name to real function name at the + # start of the outer level set of braces (function body?). + if (!$in_braces and $potential_start) { + $start = $potential_start; + $name = $potential_name; + if (@namespaces && (length($name) < 2 || substr($name,1,1) ne "[")) { + $name = join ('::', @namespaces, $name); + } + } + + $in_method_declaration = 0; + + $brace_start = $. if (!$in_braces); + $in_braces++; + next; + } + + # Close brace. + if ($1 eq "}") { + if (!$in_braces && @namespaces) { + pop @namespaces; + next; + } + + $in_braces--; + $brace_end = $. if (!$in_braces); + + # End of an outer level set of braces. + # This could be a function body. + if (!$in_braces and $name) { + push @ranges, [ $start, $., $name ]; + $name = ""; + } + + $potential_start = 0; + $potential_name = ""; + next; + } + + # Semicolon. + if ($1 eq ";") { + $skip_til_brace_or_semicolon = 0; + $potential_start = 0; + $potential_name = ""; + $in_method_declaration = 0; + next; + } + + # Ignore "const" method qualifier. + if ($1 eq "const") { + next; + } + + if ($1 eq "namespace" || $1 eq "class" || $1 eq "struct") { + $next_word_could_be_namespace = 1; + next; + } + + # Word. + $word = $1; + if (!$skip_til_brace_or_semicolon) { + if ($next_word_could_be_namespace) { + $potential_namespace = $word; + $next_word_could_be_namespace = 0; + } elsif ($potential_namespace) { + $potential_namespace = ""; + } + + if (!$in_parentheses) { + $potential_start = 0; + $potential_name = ""; + } + if (!$potential_start) { + $potential_start = $.; + $potential_name = ""; + } + } + } + } + + warn "missing close braces in $file_name (probable start at $brace_start)\n" if ($in_braces > 0); + warn "too many close braces in $file_name (probable start at $brace_end)\n" if ($in_braces < 0); + + warn "mismatched parentheses in $file_name\n" if $in_parentheses; + + return @ranges; +} + + + +# Read a file and get all the line ranges of the things that look like Java +# classes, interfaces and methods. +# +# A class or interface name is the word that immediately follows +# `class' or `interface' when followed by an open curly brace and not +# a semicolon. It can appear at the top level, or inside another class +# or interface block, but not inside a function block +# +# A class or interface starts at the first character after the first close +# brace or after the function name and ends at the close brace. +# +# A function name is the last word before an open parenthesis before +# an open brace rather than a semicolon. It can appear at top level or +# inside a class or interface block, but not inside a function block. +# +# A function starts at the first character after the first close +# brace or after the function name and ends at the close brace. +# +# Comment handling is simple-minded but will work for all but pathological cases. +# +# Result is a list of triples: [ start_line, end_line, function_name ]. + +sub get_function_line_ranges_for_java($$) +{ + my ($file_handle, $file_name) = @_; + + my @current_scopes; + + my @ranges; + + my $in_comment = 0; + my $in_macro = 0; + my $in_parentheses = 0; + my $in_braces = 0; + my $in_non_block_braces = 0; + my $class_or_interface_just_seen = 0; + + my $word = ""; + + my $potential_start = 0; + my $potential_name = ""; + my $potential_name_is_class_or_interface = 0; + + my $start = 0; + my $name = ""; + my $current_name_is_class_or_interface = 0; + + while (<$file_handle>) { + # Handle continued multi-line comment. + if ($in_comment) { + next unless s-.*\*/--; + $in_comment = 0; + } + + # Handle continued macro. + if ($in_macro) { + $in_macro = 0 unless /\\$/; + next; + } + + # Handle start of macro (or any preprocessor directive). + if (/^\s*\#/) { + $in_macro = 1 if /^([^\\]|\\.)*\\$/; + next; + } + + # Handle comments and quoted text. + while (m-(/\*|//|\'|\")-) { # \' and \" keep emacs perl mode happy + my $match = $1; + if ($match eq "/*") { + if (!s-/\*.*?\*/--) { + s-/\*.*--; + $in_comment = 1; + } + } elsif ($match eq "//") { + s-//.*--; + } else { # ' or " + if (!s-$match([^\\]|\\.)*?$match--) { + warn "mismatched quotes at line $. in $file_name\n"; + s-$match.*--; + } + } + } + + # Find function names. + while (m-(\w+|[(){};])-g) { + # Open parenthesis. + if ($1 eq "(") { + if (!$in_parentheses) { + $potential_name = $word; + $potential_name_is_class_or_interface = 0; + } + $in_parentheses++; + next; + } + + # Close parenthesis. + if ($1 eq ")") { + $in_parentheses--; + next; + } + + # Open brace. + if ($1 eq "{") { + # Promote potential name to real function name at the + # start of the outer level set of braces (function/class/interface body?). + if (!$in_non_block_braces + and (!$in_braces or $current_name_is_class_or_interface) + and $potential_start) { + if ($name) { + push @ranges, [ $start, ($. - 1), + join ('.', @current_scopes) ]; + } + + + $current_name_is_class_or_interface = $potential_name_is_class_or_interface; + + $start = $potential_start; + $name = $potential_name; + + push (@current_scopes, $name); + } else { + $in_non_block_braces++; + } + + $potential_name = ""; + $potential_start = 0; + + $in_braces++; + next; + } + + # Close brace. + if ($1 eq "}") { + $in_braces--; + + # End of an outer level set of braces. + # This could be a function body. + if (!$in_non_block_braces) { + if ($name) { + push @ranges, [ $start, $., + join ('.', @current_scopes) ]; + + pop (@current_scopes); + + if (@current_scopes) { + $current_name_is_class_or_interface = 1; + + $start = $. + 1; + $name = $current_scopes[$#current_scopes-1]; + } else { + $current_name_is_class_or_interface = 0; + $start = 0; + $name = ""; + } + } + } else { + $in_non_block_braces-- if $in_non_block_braces; + } + + $potential_start = 0; + $potential_name = ""; + next; + } + + # Semicolon. + if ($1 eq ";") { + $potential_start = 0; + $potential_name = ""; + next; + } + + if ($1 eq "class" or $1 eq "interface") { + $class_or_interface_just_seen = 1; + next; + } + + # Word. + $word = $1; + if (!$in_parentheses) { + if ($class_or_interface_just_seen) { + $potential_name = $word; + $potential_start = $.; + $class_or_interface_just_seen = 0; + $potential_name_is_class_or_interface = 1; + next; + } + } + if (!$potential_start) { + $potential_start = $.; + $potential_name = ""; + } + $class_or_interface_just_seen = 0; + } + } + + warn "mismatched braces in $file_name\n" if $in_braces; + warn "mismatched parentheses in $file_name\n" if $in_parentheses; + + return @ranges; +} + +sub processPaths(\@) +{ + my ($paths) = @_; + return ("." => 1) if (!@{$paths}); + + my %result = (); + + for my $file (@{$paths}) { + die "can't handle absolute paths like \"$file\"\n" if File::Spec->file_name_is_absolute($file); + die "can't handle empty string path\n" if $file eq ""; + die "can't handle path with single quote in the name like \"$file\"\n" if $file =~ /'/; # ' (keep Xcode syntax highlighting happy) + + my $untouchedFile = $file; + + $file = canonicalizePath($file); + + die "can't handle paths with .. like \"$untouchedFile\"\n" if $file =~ m|/\.\./|; + + $result{$file} = 1; + } + + return ("." => 1) if ($result{"."}); + + # Remove any paths that also have a parent listed. + for my $path (keys %result) { + for (my $parent = dirname($path); $parent ne '.'; $parent = dirname($parent)) { + if ($result{$parent}) { + delete $result{$path}; + last; + } + } + } + + return %result; +} + +sub diffFromToString() +{ + return "" if $isSVN; + return $gitCommit if $gitCommit =~ m/.+\.\..+/; + return "\"$gitCommit^\" \"$gitCommit\"" if $gitCommit; + return "HEAD" if $isGit; +} + +sub diffCommand(@) +{ + my @paths = @_; + + my $pathsString = "'" . join("' '", @paths) . "'"; + + my $command; + if ($isSVN) { + $command = "$SVN diff --diff-cmd diff -x -N $pathsString"; + } elsif ($isGit) { + $command = "$GIT diff " . diffFromToString(); + $command .= " -- $pathsString" unless $gitCommit; + } + + return $command; +} + +sub statusCommand(@) +{ + my @files = @_; + + my $filesString = "'" . join ("' '", @files) . "'"; + my $command; + if ($isSVN) { + $command = "$SVN stat $filesString"; + } elsif ($isGit) { + $command = "$GIT diff -r --name-status -C -C -M " . diffFromToString(); + $command .= " -- $filesString" unless $gitCommit; + } + + return "$command 2>&1"; +} + +sub createPatchCommand($) +{ + my ($changedFilesString) = @_; + + my $command; + if ($isSVN) { + $command = "'$FindBin::Bin/svn-create-patch' $changedFilesString"; + } elsif ($isGit) { + $command = "$GIT diff -C -C -M " . diffFromToString(); + $command .= " -- $changedFilesString" unless $gitCommit; + } + + return $command; +} + +sub diffHeaderFormat() +{ + return qr/^Index: (\S+)$/ if $isSVN; + return qr/^diff --git a\/.+ b\/(.+)$/ if $isGit; +} + +sub findOriginalFileFromSvn($) +{ + my ($file) = @_; + my $baseUrl; + open INFO, "$SVN info . |" or die; + while (<INFO>) { + if (/^URL: (.+)/) { + $baseUrl = $1; + last; + } + } + close INFO; + my $sourceFile; + open INFO, "$SVN info '$file' |" or die; + while (<INFO>) { + if (/^Copied From URL: (.+)/) { + $sourceFile = File::Spec->abs2rel($1, $baseUrl); + last; + } + } + close INFO; + return $sourceFile; +} + +sub generateFileList(\@\@\%) +{ + my ($changedFiles, $conflictFiles, $functionLists) = @_; + print STDERR " Running status to find changed, added, or removed files.\n"; + open STAT, "-|", statusCommand(keys %paths) or die "The status failed: $!.\n"; + my $inGitCommitSection = 0; + while (<STAT>) { + my $status; + my $original; + my $file; + + if ($isSVN) { + if (/^([ACDMR]).{5} (.+)$/) { + $status = $1; + $file = $2; + $original = findOriginalFileFromSvn($file) if substr($_, 3, 1) eq "+"; + } else { + print; # error output from svn stat + } + } elsif ($isGit) { + if (/^([ADM])\t(.+)$/) { + $status = $1; + $file = $2; + } elsif (/^([CR])[0-9]{1,3}\t([^\t]+)\t([^\t\n]+)$/) { # for example: R90% newfile oldfile + $status = $1; + $original = $2; + $file = $3; + } else { + print; # error output from git diff + } + } + + next unless $status; + + $file = makeFilePathRelative($file); + + if (isModifiedStatus($status) || isAddedStatus($status)) { + my @components = File::Spec->splitdir($file); + if ($components[0] eq "LayoutTests") { + $didChangeRegressionTests = 1; + push @addedRegressionTests, $file + if isAddedStatus($status) + && $file =~ /\.([a-zA-Z]+)$/ + && $supportedTestExtensions{lc($1)} + && !scalar(grep(/^resources$/i, @components)); + } + push @{$changedFiles}, $file if $components[$#components] ne "ChangeLog"; + } elsif (isConflictStatus($status)) { + push @{$conflictFiles}, $file; + } + my $description = statusDescription($status, $original); + $functionLists->{$file} = $description if defined $description; + } + close STAT; +} + +sub gitConfig($) +{ + return unless $isGit; + + my ($config) = @_; + + my $result = `$GIT config $config`; + if (($? >> 8) != 0) { + $result = `$GIT repo-config $config`; + } + chomp $result; + return $result; +} + +sub isModifiedStatus($) +{ + my ($status) = @_; + + my %statusCodes = ( + "M" => 1, + ); + + return $statusCodes{$status}; +} + +sub isAddedStatus($) +{ + my ($status) = @_; + + my %statusCodes = ( + "A" => 1, + "C" => $isGit, + "R" => 1, + ); + + return $statusCodes{$status}; +} + +sub isConflictStatus($) +{ + my ($status) = @_; + + my %svn = ( + "C" => 1, + ); + + my %git = ( + "U" => 1, + ); + + return 0 if $gitCommit; # an existing commit cannot have conflicts + return $svn{$status} if $isSVN; + return $git{$status} if $isGit; +} + +sub statusDescription($$) +{ + my ($status, $original) = @_; + + my %svn = ( + "A" => defined $original ? " Copied from \%s." : " Added.", + "D" => " Removed.", + "M" => "", + "R" => defined $original ? " Replaced with \%s." : " Replaced.", + ); + + my %git = %svn; + $git{"A"} = " Added."; + $git{"C"} = " Copied from \%s."; + $git{"R"} = " Renamed from \%s."; + + return sprintf($svn{$status}, $original) if $isSVN && exists $svn{$status}; + return sprintf($git{$status}, $original) if $isGit && exists $git{$status}; + return undef; +} + +sub extractLineRange($) +{ + my ($string) = @_; + + my ($start, $end) = (-1, -1); + + if ($isSVN && $string =~ /^\d+(,\d+)?[acd](\d+)(,(\d+))?/) { + $start = $2; + $end = $4 || $2; + } elsif ($isGit && $string =~ /^@@ -\d+,\d+ \+(\d+),(\d+) @@/) { + $start = $1; + $end = $1 + $2 - 1; + + # git-diff shows 3 lines of context above and below the actual changes, + # so we need to subtract that context to find the actual changed range. + + # FIXME: This won't work if there's a change at the very beginning or + # very end of a file. + + $start += 3; + $end -= 6; + } + + return ($start, $end); +} + +sub firstDirectoryOrCwd() +{ + my $dir = "."; + my @dirs = keys(%paths); + + $dir = -d $dirs[0] ? $dirs[0] : dirname($dirs[0]) if @dirs; + + return $dir; +} + +sub testListForChangeLog(@) +{ + my (@tests) = @_; + + return "" unless @tests; + + my $leadString = " Test" . (@tests == 1 ? "" : "s") . ": "; + my $list = $leadString; + foreach my $i (0..$#tests) { + $list .= " " x length($leadString) if $i; + my $test = $tests[$i]; + $test =~ s/^LayoutTests\///; + $list .= "$test\n"; + } + $list .= "\n"; + + return $list; +} + +sub reviewerAndDescriptionForGitCommit($) +{ + my ($commit) = @_; + + my $description = ''; + my $reviewer; + + my @args = qw(rev-list --pretty); + push @args, '-1' if $commit !~ m/.+\.\..+/; + my $gitLog; + { + local $/ = undef; + open(GIT, "-|", $GIT, @args, $commit) || die; + $gitLog = <GIT>; + close(GIT); + } + + my @commitLogs = split(/^[Cc]ommit [a-f0-9]{40}/m, $gitLog); + shift @commitLogs; # Remove initial blank commit log + my $commitLogCount = 0; + foreach my $commitLog (@commitLogs) { + $description .= "\n" if $commitLogCount; + $commitLogCount++; + my $inHeader = 1; + my @lines = split(/\n/, $commitLog); + shift @lines; # Remove initial blank line + foreach my $line (@lines) { + if ($inHeader) { + if (!$line) { + $inHeader = 0; + } + next; + } elsif ($line =~ /[Ss]igned-[Oo]ff-[Bb]y: (.+)/) { + if (!$reviewer) { + $reviewer = $1; + } else { + $reviewer .= ", " . $1; + } + } elsif (length $line == 0) { + $description = $description . "\n"; + } else { + $line =~ s/^\s*//; + $description = $description . " " . $line . "\n"; + } + } + } + if (!$reviewer) { + $reviewer = $gitReviewer; + } + + return ($reviewer, $description); +} diff --git a/WebKitTools/Scripts/report-include-statistics b/WebKitTools/Scripts/report-include-statistics new file mode 100755 index 0000000..f81c3c3 --- /dev/null +++ b/WebKitTools/Scripts/report-include-statistics @@ -0,0 +1,114 @@ +#!/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. + +# "report-include-statistics" script for Web Kit Open Source Project + +use strict; +use File::Find; + +find(\&wanted, @ARGV ? @ARGV : "."); + +my %paths; +my %sources; +my %includes; + +sub wanted +{ + my $file = $_; + + if ($file eq "icu") { + $File::Find::prune = 1; + return; + } + + if ($file !~ /^\./ && $file =~ /\.(h|cpp|c|mm|m)$/) { + $paths{$file} = $File::Find::name; + $sources{$file} = $File::Find::name if $file !~ /\.h/; + open FILE, $file or die; + while (<FILE>) { + if (m-^\s*#\s*(include|import)\s+["<]((\S+/)*)(\S+)[">]-) { + my $include = ($2 eq "sys/" ? $2 : "") . $4; + $includes{$file}{$include}++; + } + } + close FILE; + } +} + +my %totalIncludes; + +sub fillOut +{ + my ($file) = @_; + + return if defined $totalIncludes{$file}; + + for my $include (keys %{ $includes{$file} }) { + $totalIncludes{$file}{$include} = 1; + fillOut($include); + for my $i (keys %{ $totalIncludes{$include} }) { + $totalIncludes{$file}{$i} = 1; + } + } +} + +my %inclusionCounts; +for my $file (keys %includes) { + $inclusionCounts{$file} = 0; + fillOut($file); +} + +for my $file (keys %sources) { + for my $include (keys %{ $totalIncludes{$file} }) { + $inclusionCounts{$include}++; + } +} + +for my $file (sort mostincludedcmp keys %includes) { + next if !$paths{$file}; + my $count = $inclusionCounts{$file}; + my $numIncludes = keys %{ $includes{$file} }; + my $numTotalIncludes = keys %{ $totalIncludes{$file} }; + print "$file is included $count times, includes $numIncludes files directly, $numTotalIncludes files total.\n" +} + +# Sort most-included files first. +sub mostincludedcmp($$) +{ + my ($filea, $fileb) = @_; + + my $counta = $inclusionCounts{$filea} || 0; + my $countb = $inclusionCounts{$fileb} || 0; + return $countb <=> $counta if $counta != $countb; + + my $ta = keys %{ $totalIncludes{$filea} }; + my $tb = keys %{ $totalIncludes{$fileb} }; + return $ta <=> $tb if $ta != $tb; + + return $filea cmp $fileb; +} diff --git a/WebKitTools/Scripts/resolve-ChangeLogs b/WebKitTools/Scripts/resolve-ChangeLogs new file mode 100755 index 0000000..fa01243 --- /dev/null +++ b/WebKitTools/Scripts/resolve-ChangeLogs @@ -0,0 +1,305 @@ +#!/usr/bin/perl -w + +# Copyright (C) 2007 Apple 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. + +# Merge and resolve ChangeLog conflicts for svn and git repositories + +use strict; + +use FindBin; +use lib $FindBin::Bin; + +use File::Basename; +use File::Spec; +use Getopt::Long; +use VCSUtils; + +sub conflictFiles($); +sub fixChangeLogPatch($); +sub mergeChanges($$$); +sub resolveConflict($); +sub showStatus($;$); + +my $SVN = "svn"; +my $GIT = "git"; + +my $printWarnings = 1; +my $showHelp; + +my $getOptionsResult = GetOptions( + 'h|help' => \$showHelp, + 'w|warnings!' => \$printWarnings, +); + +sub findChangeLog { + return $_ if basename($_) eq "ChangeLog"; + + my $file = File::Spec->catfile($_, "ChangeLog"); + return $file if -d $_ and -e $file; + + return undef; +} + +my @changeLogFiles = grep { defined $_ } map { findChangeLog($_) } @ARGV; + +if (scalar(@changeLogFiles) != scalar(@ARGV)) { + print STDERR "ERROR: Files listed on command-line that are not ChangeLogs.\n"; + undef $getOptionsResult; +} elsif (scalar(@changeLogFiles) == 0) { + print STDERR "ERROR: No ChangeLog files listed on command-line.\n"; + undef $getOptionsResult; +} + +if (!$getOptionsResult || $showHelp) { + print STDERR <<__END__; +Usage: @{[ basename($0) ]} [options] path/to/ChangeLog [path/to/another/ChangeLog ...] + -h|--help show this help message + -w|--[no-]warnings show or suppress warnings (default: show warnings) +__END__ + exit 1; +} + +for my $file (@changeLogFiles) { + my ($fileMine, $fileOlder, $fileNewer) = conflictFiles($file); + if (!$fileMine || !$fileOlder || !$fileNewer) { + next; + } + if (mergeChanges($fileMine, $fileOlder, $fileNewer)) { + if ($file ne $fileNewer) { + unlink($file); + rename($fileNewer, $file) || die; + } + unlink($fileMine, $fileOlder); + resolveConflict($file); + showStatus($file, 1); + } else { + showStatus($file); + print STDERR "WARNING: ${file} could not be merged using fuzz level 3.\n" if $printWarnings; + unlink($fileMine, $fileOlder, $fileNewer) if isGit(); + } +} + +exit 0; + +sub conflictFiles($) +{ + my ($file) = @_; + my $fileMine; + my $fileOlder; + my $fileNewer; + + if (-e $file && -e "$file.orig" && -e "$file.rej") { + return ("$file.rej", "$file.orig", $file); + } + + if (isSVN()) { + open STAT, "-|", $SVN, "status", $file || die; + my $status = <STAT>; + close STAT; + if (!$status || $status !~ m/^C\s+/) { + print STDERR "WARNING: ${file} is not in a conflicted state.\n" if $printWarnings; + return (); + } + + $fileMine = "${file}.mine" if -e "${file}.mine"; + + my $currentRevision; + open INFO, "-|", $SVN, "info", $file || die; + while (my $line = <INFO>) { + $currentRevision = $1 if $line =~ m/^Revision: ([0-9]+)/; + } + close INFO; + $fileNewer = "${file}.r${currentRevision}" if -e "${file}.r${currentRevision}"; + + my @matchingFiles = grep { $_ ne $fileNewer } glob("${file}.r[0-9][0-9]*"); + if (scalar(@matchingFiles) > 1) { + print STDERR "WARNING: Too many conflict files exist for ${file}!\n" if $printWarnings; + } else { + $fileOlder = shift @matchingFiles; + } + } elsif (isGit()) { + my $gitPrefix = `$GIT rev-parse --show-prefix`; + chomp $gitPrefix; + open GIT, "-|", $GIT, "ls-files", "--unmerged", $file || die; + while (my $line = <GIT>) { + my ($mode, $hash, $stage, $fileName) = split(' ', $line); + my $outputFile; + if ($stage == 1) { + $fileOlder = "${file}.BASE.$$"; + $outputFile = $fileOlder; + } elsif ($stage == 2) { + $fileNewer = "${file}.LOCAL.$$"; + $outputFile = $fileNewer; + } elsif ($stage == 3) { + $fileMine = "${file}.REMOTE.$$"; + $outputFile = $fileMine; + } else { + die "Unknown file stage: $stage"; + } + system("$GIT cat-file blob :${stage}:${gitPrefix}${file} > $outputFile"); + } + close GIT; + } else { + die "Unknown version control system"; + } + + if (!$fileMine && !$fileOlder && !$fileNewer) { + print STDERR "WARNING: ${file} does not need merging.\n" if $printWarnings; + } elsif (!$fileMine || !$fileOlder || !$fileNewer) { + print STDERR "WARNING: ${file} is missing some conflict files.\n" if $printWarnings; + } + + return ($fileMine, $fileOlder, $fileNewer); +} + +sub fixChangeLogPatch($) +{ + my $patch = shift; + my $contextLineCount = 3; + + return $patch if $patch !~ /\n@@ -1,(\d+) \+1,(\d+) @@\n( .*\n)+(\+.*\n)+( .*\n){$contextLineCount}$/m; + my ($oldLineCount, $newLineCount) = ($1, $2); + return $patch if $oldLineCount <= $contextLineCount; + + # The diff(1) command is greedy when matching lines, so a new ChangeLog entry will + # have lines of context at the top of a patch when the existing entry has the same + # date and author as the new entry. This nifty loop alters a ChangeLog patch so + # that the added lines ("+") in the patch always start at the beginning of the + # patch and there are no initial lines of context. + my $newPatch; + my $lineCountInState = 0; + my $oldContentLineCountReduction = $oldLineCount - $contextLineCount; + my $newContentLineCountWithoutContext = $newLineCount - $oldLineCount - $oldContentLineCountReduction; + my ($stateHeader, $statePreContext, $stateNewChanges, $statePostContext) = (1..4); + my $state = $stateHeader; + foreach my $line (split(/\n/, $patch)) { + $lineCountInState++; + if ($state == $stateHeader && $line =~ /^@@ -1,$oldLineCount \+1,$newLineCount @\@$/) { + $line = "@@ -1,$contextLineCount +1," . ($newLineCount - $oldContentLineCountReduction) . " @@"; + $lineCountInState = 0; + $state = $statePreContext; + } elsif ($state == $statePreContext && substr($line, 0, 1) eq " ") { + $line = "+" . substr($line, 1); + if ($lineCountInState == $oldContentLineCountReduction) { + $lineCountInState = 0; + $state = $stateNewChanges; + } + } elsif ($state == $stateNewChanges && substr($line, 0, 1) eq "+") { + # No changes to these lines + if ($lineCountInState == $newContentLineCountWithoutContext) { + $lineCountInState = 0; + $state = $statePostContext; + } + } elsif ($state == $statePostContext) { + if (substr($line, 0, 1) eq "+" && $lineCountInState <= $oldContentLineCountReduction) { + $line = " " . substr($line, 1); + } elsif ($lineCountInState > $contextLineCount && substr($line, 0, 1) eq " ") { + next; # Discard + } + } + $newPatch .= $line . "\n"; + } + + return $newPatch; +} + +sub mergeChanges($$$) +{ + my ($fileMine, $fileOlder, $fileNewer) = @_; + + my $traditionalReject = $fileMine =~ /\.rej$/ ? 1 : 0; + + local $/ = undef; + + my $patch; + if ($traditionalReject) { + open(DIFF, "<", $fileMine); + $patch = <DIFF>; + close(DIFF); + rename($fileMine, "$fileMine.save"); + rename($fileOlder, "$fileOlder.save"); + } else { + open(DIFF, "-|", qw(diff -u), $fileOlder, $fileMine) || die; + $patch = <DIFF>; + close(DIFF); + } + + unlink("${fileNewer}.orig"); + unlink("${fileNewer}.rej"); + + open(PATCH, "| patch --fuzz=3 $fileNewer > /dev/null") || die; + print PATCH fixChangeLogPatch($patch); + close(PATCH); + + my $result; + + # Refuse to merge the patch if it did not apply cleanly + if (-e "${fileNewer}.rej") { + unlink("${fileNewer}.rej"); + unlink($fileNewer); + rename("${fileNewer}.orig", $fileNewer); + $result = 0; + } else { + unlink("${fileNewer}.orig"); + $result = 1; + } + + if ($traditionalReject) { + rename("$fileMine.save", $fileMine); + rename("$fileOlder.save", $fileOlder); + } + + return $result; +} + +sub resolveConflict($) +{ + my ($file) = @_; + + if (isSVN()) { + system($SVN, "resolved", $file); + } elsif (isGit()) { + system($GIT, "add", $file); + } else { + die "Unknown version control system"; + } +} + +sub showStatus($;$) +{ + my ($file, $isConflictResolved) = @_; + + if (isSVN()) { + system($SVN, "status", $file); + } elsif (isGit()) { + my @args = qw(--name-status); + unshift @args, qw(--cached) if $isConflictResolved; + system($GIT, "diff", @args, $file); + } else { + die "Unknown version control system"; + } +} diff --git a/WebKitTools/Scripts/run-drawtest b/WebKitTools/Scripts/run-drawtest new file mode 100755 index 0000000..2cd61de --- /dev/null +++ b/WebKitTools/Scripts/run-drawtest @@ -0,0 +1,47 @@ +#!/usr/bin/perl -w + +# Copyright (C) 2005 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. + +# Simplified "run" script for WebKit Open Source Project. + +use strict; +use FindBin; +use lib $FindBin::Bin; +use webkitdirs; + +setConfiguration(); +my $productDir = productDir(); + +# Check to see that all the frameworks are built (w/ SVG support). +checkFrameworks(); +checkWebCoreSVGSupport(1); + +# Set up DYLD_FRAMEWORK_PATH to point to the product directory. +print "Start DrawTest with DYLD_FRAMEWORK_PATH set to point to built WebKit in $productDir.\n"; +$ENV{DYLD_FRAMEWORK_PATH} = $productDir; +my $drawtestPath = "$productDir/DrawTest.app/Contents/MacOS/DrawTest"; +exec $drawtestPath or die; diff --git a/WebKitTools/Scripts/run-drosera b/WebKitTools/Scripts/run-drosera new file mode 100644 index 0000000..925293c --- /dev/null +++ b/WebKitTools/Scripts/run-drosera @@ -0,0 +1,41 @@ +#!/usr/bin/perl -w + +# Copyright (C) 2005, 2007 Apple 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. + +# Simplified "run" script for Web Kit Open Source Project. + +use strict; +use FindBin; +use lib $FindBin::Bin; +use webkitdirs; + +setConfiguration(); + +# Check to see that all the frameworks are built. +checkFrameworks(); + +exit exitStatus(runDrosera()); diff --git a/WebKitTools/Scripts/run-drosera-nightly.cmd b/WebKitTools/Scripts/run-drosera-nightly.cmd new file mode 100644 index 0000000..4f547fb --- /dev/null +++ b/WebKitTools/Scripts/run-drosera-nightly.cmd @@ -0,0 +1,12 @@ +@echo off +set script="%TMP%\run-drosera-nightly2.cmd" +set vsvars="%VS80COMNTOOLS%\vsvars32.bat" +if exist %vsvars% ( + copy %vsvars% "%script%" +) else ( + del "%script%" +) + +FindSafari.exe %1 /printSafariEnvironment >> "%script%" +echo Drosera.exe >> "%script%" +call %script% diff --git a/WebKitTools/Scripts/run-drosera.cmd b/WebKitTools/Scripts/run-drosera.cmd new file mode 100755 index 0000000..3b6e1f0 --- /dev/null +++ b/WebKitTools/Scripts/run-drosera.cmd @@ -0,0 +1,5 @@ +@echo off +set script="%TMP%\run-drosera2.cmd" +FindSafari.exe %1 /printSafariEnvironment > "%script%" +call %script% +Drosera.exe diff --git a/WebKitTools/Scripts/run-iexploder-tests b/WebKitTools/Scripts/run-iexploder-tests new file mode 100755 index 0000000..6acff18 --- /dev/null +++ b/WebKitTools/Scripts/run-iexploder-tests @@ -0,0 +1,170 @@ +#!/usr/bin/perl + +# Copyright (C) 2006 Alexey Proskuryakov (ap@nypop.com) +# +# 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. + +# A script to semi-automatically run iExploder tests. + +use strict; +use warnings; + +use Cwd; +use FindBin; +use Getopt::Long; +use IPC::Open2; + +use lib $FindBin::Bin; +use webkitdirs; + +sub openHTTPDIfNeeded(); +sub closeHTTPD(); +sub runSafari(); + +# Argument handling +my $guardMalloc = ''; +my $httpdPort = 8000; +my $downloadTest; + +GetOptions( + 'guard-malloc|g' => \$guardMalloc, + 'get=s' => \$downloadTest, + 'port=i' => \$httpdPort +); + + +setConfiguration(); +my $productDir = productDir(); + +chdirWebKit(); + +checkFrameworks(); + +my $httpdOpen = 0; +openHTTPDIfNeeded(); + +if ($downloadTest) { + system "/usr/bin/curl -o ~/Desktop/iexploder$downloadTest.html \"http://127.0.0.1:$httpdPort/iexploder.cgi?lookup=1&test=$downloadTest\""; + print "Saved the test as iexploder$downloadTest.html on the desktop\n"; +} else { + runSafari(); + print "Last generated tests:\n"; + system "grep 'iexploder.cgi' /tmp/WebKit/access_log.txt | tail -n -5 | awk -F'[ =&\\?]' '{if (\$8 == \"lookup\") print \$11; else print \$9}'"; +} + +closeHTTPD(); + + +sub runSafari() +{ + my $redirectTo; + if (@ARGV) { + $redirectTo = "http://127.0.0.1:$httpdPort/iexploder.cgi?lookup=1&test=$ARGV[0]"; + } else { + $redirectTo = "http://127.0.0.1:$httpdPort/index.html"; + } + + open REDIRECT_HTML, ">", "/tmp/WebKit/redirect.html" or die; + print REDIRECT_HTML "<html>\n"; + print REDIRECT_HTML " <head>\n"; + print REDIRECT_HTML " <meta http-equiv=\"refresh\" content=\"1;URL=$redirectTo\" />\n"; + print REDIRECT_HTML " <script type=\"text/javascript\">\n"; + print REDIRECT_HTML " document.location = \"$redirectTo\";\n"; + print REDIRECT_HTML " </script>\n"; + print REDIRECT_HTML " </head>\n"; + print REDIRECT_HTML " <body>\n"; + print REDIRECT_HTML " </body>\n"; + print REDIRECT_HTML "</html>\n"; + close REDIRECT_HTML; + + local %ENV; + $ENV{DYLD_INSERT_LIBRARIES} = "/usr/lib/libgmalloc.dylib" if $guardMalloc; + system "WebKitTools/Scripts/run-safari", "-NSOpen", "/tmp/WebKit/redirect.html"; +} + +sub openHTTPDIfNeeded() +{ + return if $httpdOpen; + + mkdir "/tmp/WebKit"; + + if (-f "/tmp/WebKit/httpd.pid") { + my $oldPid = `cat /tmp/WebKit/httpd.pid`; + chomp $oldPid; + if (0 != kill 0, $oldPid) { + print "\nhttpd is already running: pid $oldPid, killing...\n"; + kill 15, $oldPid; + + my $retryCount = 20; + while ((0 != kill 0, $oldPid) && $retryCount) { + sleep 1; + --$retryCount; + } + + die "Timed out waiting for httpd to quit" unless $retryCount; + } + } + + my $testDirectory = getcwd() . "/LayoutTests"; + my $iExploderDirectory = getcwd() . "/WebKitTools/iExploder"; + my $httpdPath = "/usr/sbin/httpd"; + my $httpdConfig = "$testDirectory/http/conf/httpd.conf"; + $httpdConfig = "$testDirectory/http/conf/apache2-httpd.conf" if `$httpdPath -v` =~ m|Apache/2|; + my $documentRoot = "$iExploderDirectory/htdocs"; + my $typesConfig = "$testDirectory/http/conf/mime.types"; + my $listen = "127.0.0.1:$httpdPort"; + + open2(\*HTTPDIN, \*HTTPDOUT, $httpdPath, + "-f", "$httpdConfig", + "-C", "DocumentRoot \"$documentRoot\"", + "-C", "Listen $listen", + "-c", "TypesConfig \"$typesConfig\"", + "-c", "CustomLog \"/tmp/WebKit/access_log.txt\" common", + "-c", "ErrorLog \"/tmp/WebKit/error_log.txt\"", + # Apache wouldn't run CGIs with permissions==700 otherwise + "-c", "User \"#$<\""); + + my $retryCount = 20; + while (system("/usr/bin/curl -q --silent --stderr - --output /dev/null $listen") && $retryCount) { + sleep 1; + --$retryCount; + } + + die "Timed out waiting for httpd to start" unless $retryCount; + + $httpdOpen = 1; +} + +sub closeHTTPD() +{ + return if !$httpdOpen; + + close HTTPDIN; + close HTTPDOUT; + + kill 15, `cat /tmp/WebKit/httpd.pid` if -f "/tmp/WebKit/httpd.pid"; + + $httpdOpen = 0; +} diff --git a/WebKitTools/Scripts/run-javascriptcore-tests b/WebKitTools/Scripts/run-javascriptcore-tests new file mode 100755 index 0000000..16522ca --- /dev/null +++ b/WebKitTools/Scripts/run-javascriptcore-tests @@ -0,0 +1,173 @@ +#!/usr/bin/perl -w + +# Copyright (C) 2005 Apple Computer, Inc. All rights reserved. +# Copyright (C) 2007 Eric Seidel <eric@webkit.org> +# +# 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. + +# Script to run the Web Kit Open Source Project JavaScriptCore tests (adapted from Mozilla). + +use strict; +use FindBin; +use Getopt::Long qw(:config pass_through); +use lib $FindBin::Bin; +use webkitdirs; +use POSIX; + +my $coverageSupport = 0; +GetOptions('coverage!' => \$coverageSupport); + +my @coverageSupportOption = (); +if ($coverageSupport) { + push @coverageSupportOption, "GCC_GENERATE_TEST_COVERAGE_FILES=YES"; + push @coverageSupportOption, "GCC_INSTRUMENT_PROGRAM_FLOW_ARCS=YES"; + push @coverageSupportOption, "EXTRA_LINK= -ftest-coverage -fprofile-arcs"; + push @coverageSupportOption, "OTHER_CFLAGS= -MD"; + push @coverageSupportOption, "OTHER_LDFLAGS= -ftest-coverage -fprofile-arcs -framework AppKit"; +} + +# determine configuration +my $configuration; +setConfiguration(); +$configuration = configuration(); + +my @jsArgs; +my @xcodeArgs; +my $root; + +# pre-evaluate arguments. jsDriver args have - preceding, xcode args do not. +# special arguments +# --root=<path to webkit root> use pre-built root +# --gtk build gtk +foreach my $arg(@ARGV) { + print $arg."\n"; + if( $arg =~ /root=(.*)/ ){ + $root = $1; + } elsif( $arg =~ /^--gtk$/i || $arg =~ /^--qt$/i || $arg =~ /^--wx$/i ){ + } elsif( $arg =~ /^-/ or !($arg =~/=/)){ + push( @jsArgs, $arg ); + } else { + push( @xcodeArgs, $arg ); + } +} + +setConfigurationProductDir(Cwd::abs_path($root)) if (defined($root)); + +if(!defined($root)){ + chdirWebKit(); + push(@xcodeArgs, "--" . $configuration); + + # FIXME: These should be stored per-config and ignored here + push(@xcodeArgs, "--qt") if isQt(); + push(@xcodeArgs, "--gtk") if isGtk(); + push(@xcodeArgs, "--wx") if isWx(); + + my $buildResult = system "perl", "WebKitTools/Scripts/build-testkjs", @xcodeArgs; + if ($buildResult) { + print STDERR "Compiling testkjs failed!\n"; + exit exitStatus($buildResult); + } +} + +# Find JavaScriptCore directory +chdirWebKit(); +chdir("JavaScriptCore"); + +my $productDir = productDir(); +chdir "tests/mozilla" or die; + +$productDir .= "/JavaScriptCore" if (isQt() or isGtk()); +$ENV{DYLD_FRAMEWORK_PATH} = $productDir; +setPathForRunningWebKitApp(\%ENV) if isCygwin(); + +sub testKJSPath($) +{ + my ($productDir) = @_; + my $testkjsName = "testkjs"; + $testkjsName .= "_debug" if (isCygwin() && ($configuration eq "Debug")); + return "$productDir/$testkjsName"; +} + +my $result = system "perl", "jsDriver.pl", "-e", "kjs", "-s", testKJSPath($productDir), "-f", "actual.html", @jsArgs; +exit exitStatus($result) if $result; + +my %failures; + +open EXPECTED, "expected.html" or die; +while (<EXPECTED>) { + last if /failures reported\.$/; +} +while (<EXPECTED>) { + chomp; + $failures{$_} = 1; +} +close EXPECTED; + +my %newFailures; + +open ACTUAL, "actual.html" or die; +while (<ACTUAL>) { + last if /failures reported\.$/; +} +while (<ACTUAL>) { + chomp; + if ($failures{$_}) { + delete $failures{$_}; + } else { + $newFailures{$_} = 1; + } +} +close ACTUAL; + +my $numNewFailures = keys %newFailures; +if ($numNewFailures) { + print "\n** Danger, Will Robinson! Danger! The following failures have been introduced:\n"; + foreach my $failure (sort keys %newFailures) { + print "\t$failure\n"; + } +} + +my $numOldFailures = keys %failures; +if ($numOldFailures) { + print "\nYou fixed the following test"; + print "s" if $numOldFailures != 1; + print ":\n"; + foreach my $failure (sort keys %failures) { + print "\t$failure\n"; + } +} + +print "\n"; + +print "$numNewFailures regression"; +print "s" if $numNewFailures != 1; +print " found.\n"; + +print "$numOldFailures test"; +print "s" if $numOldFailures != 1; +print " fixed.\n"; + +print "OK.\n" if $numNewFailures == 0; +exit(1) if $numNewFailures; diff --git a/WebKitTools/Scripts/run-launcher b/WebKitTools/Scripts/run-launcher new file mode 100755 index 0000000..60f3c86 --- /dev/null +++ b/WebKitTools/Scripts/run-launcher @@ -0,0 +1,75 @@ +#!/usr/bin/perl -w + +# Copyright (C) 2007 Apple Computer, Inc. All rights reserved. +# Copyright (C) 2007 Staikos Computing Services, Inc. <info@staikos.net> +# +# 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. + +# Simplified "run" script for Web Kit Open Source Project. + +use strict; +use File::Spec::Functions qw/catdir/; +use File::Temp qw/tempfile/; +use FindBin; +use lib $FindBin::Bin; +use webkitdirs; + +setConfiguration(); +my $productDir = productDir(); +my $launcherPath = productDir(); +my @args = @ARGV; + +# Check to see that all the frameworks are built. +checkFrameworks(); + +# Set paths according to the build system used +if (!$ENV{WEBKITAUTOTOOLS}) { + my $libDir = catdir(productDir(), 'lib'); + + if (isGtk()) { + $launcherPath = catdir($launcherPath, "WebKitTools", "GtkLauncher", "GtkLauncher"); + # Strip --gtk from the arg-list, since otherwise GtkLauncher will try to + # interpret it as a URL. + @args = grep(!/^(--gtk)$/, @args); + } elsif (isQt()) { + $launcherPath = catdir($launcherPath, "bin", "QtLauncher"); + } + + # Set up LD_LIBRARY_PATH to point to the product directory. + print "Starting webkit launcher with LD_LIBRARY_PATH set to point to built WebKit in $libDir.\n"; + + $ENV{LD_LIBRARY_PATH} = $ENV{LD_LIBRARY_PATH} ? "$libDir:$ENV{LD_LIBRARY_PATH}" : $libDir; +} else { + + if (isGtk()) { + $launcherPath = catdir($launcherPath, "Programs", "GtkLauncher"); + @args = grep(!/^(--gtk)$/, @args); + } + + print "Starting webkit launcher.\n"; +} + +exec $launcherPath, @args or die; + diff --git a/WebKitTools/Scripts/run-leaks b/WebKitTools/Scripts/run-leaks new file mode 100755 index 0000000..d8f89d3 --- /dev/null +++ b/WebKitTools/Scripts/run-leaks @@ -0,0 +1,212 @@ +#!/usr/bin/perl + +# Copyright (C) 2007 Apple 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. + +# Script to run the Mac OS X leaks tool with more expressive '-exclude' lists. + +use strict; +use warnings; + +use File::Basename; +use Getopt::Long; + +sub runLeaks($); +sub parseLeaksOutput(\@); +sub removeMatchingRecords(\@$\@); +sub reportError($); + +sub main() +{ + # Read options. + my $usage = + "Usage: " . basename($0) . " [options] pid | executable name\n" . + " --exclude-callstack regexp Exclude leaks whose call stacks match the regular expression 'regexp'.\n" . + " --exclude-type regexp Exclude leaks whose data types match the regular expression 'regexp'.\n" . + " --help Show this help message.\n"; + + my @callStacksToExclude = (); + my @typesToExclude = (); + my $help = 0; + + my $getOptionsResult = GetOptions( + 'exclude-callstack:s' => \@callStacksToExclude, + 'exclude-type:s' => \@typesToExclude, + 'help' => \$help + ); + my $pidOrExecutableName = $ARGV[0]; + + if (!$getOptionsResult || $help) { + print STDERR $usage; + return 1; + } + + if (!$pidOrExecutableName) { + reportError("Missing argument: pid | executable."); + print STDERR $usage; + return 1; + } + + # Run leaks tool. + my $leaksOutput = runLeaks($pidOrExecutableName); + if (!$leaksOutput) { + return 1; + } + + my $leakList = parseLeaksOutput(@$leaksOutput); + if (!$leakList) { + return 1; + } + + # Filter output. + my $leakCount = @$leakList; + removeMatchingRecords(@$leakList, "callStack", @callStacksToExclude); + removeMatchingRecords(@$leakList, "type", @typesToExclude); + my $excludeCount = $leakCount - @$leakList; + + # Dump results. + print $leaksOutput->[0]; + print $leaksOutput->[1]; + foreach my $leak (@$leakList) { + print $leak->{"leaksOutput"}; + } + + if ($excludeCount) { + print "$excludeCount leaks excluded (not printed)\n"; + } + + return 0; +} + +exit(main()); + +# Returns the output of the leaks tool in list form. +sub runLeaks($) +{ + my ($pidOrExecutableName) = @_; + + my @leaksOutput = `leaks $pidOrExecutableName`; + if (!@leaksOutput) { + reportError("Error running leaks tool."); + return; + } + + return \@leaksOutput; +} + +# Returns a list of hash references with the keys { address, size, type, callStack, leaksOutput } +sub parseLeaksOutput(\@) +{ + my ($leaksOutput) = @_; + + # Format: + # Process 00000: 1234 nodes malloced for 1234 KB + # Process 00000: XX leaks for XXX total leaked bytes. + # Leak: 0x00000000 size=1234 [instance of 'blah'] + # 0x00000000 0x00000000 0x00000000 0x00000000 a..d.e.e + # ... + # Call stack: leak_caller() | leak() | malloc + # + # We treat every line except for Process 00000: and Leak: as optional + + my ($leakCount) = ($leaksOutput->[1] =~ /[[:blank:]]+([0-9]+)[[:blank:]]+leaks?/); + if (!defined($leakCount)) { + reportError("Could not parse leak count reported by leaks tool."); + return; + } + + my @leakList = (); + for my $line (@$leaksOutput) { + next if $line =~ /^Process/; + next if $line =~ /^node buffer added/; + + if ($line =~ /^Leak: /) { + my ($address) = ($line =~ /Leak: ([[:xdigit:]x]+)/); + if (!defined($address)) { + reportError("Could not parse Leak address."); + return; + } + + my ($size) = ($line =~ /size=([[:digit:]]+)/); + if (!defined($size)) { + reportError("Could not parse Leak size."); + return; + } + + my ($type) = ($line =~ /'([^']+)'/); #' + if (!defined($type)) { + $type = ""; # The leaks tool sometimes omits the type. + } + + my %leak = ( + "address" => $address, + "size" => $size, + "type" => $type, + "callStack" => "", # The leaks tool sometimes omits the call stack. + "leaksOutput" => $line + ); + push(@leakList, \%leak); + } else { + $leakList[$#leakList]->{"leaksOutput"} .= $line; + if ($line =~ /Call stack:/) { + $leakList[$#leakList]->{"callStack"} = $line; + } + } + } + + if (@leakList != $leakCount) { + my $parsedLeakCount = @leakList; + reportError("Parsed leak count($parsedLeakCount) does not match leak count reported by leaks tool($leakCount)."); + return; + } + + return \@leakList; +} + +sub removeMatchingRecords(\@$\@) +{ + my ($recordList, $key, $regexpList) = @_; + + RECORD: for (my $i = 0; $i < @$recordList;) { + my $record = $recordList->[$i]; + + foreach my $regexp (@$regexpList) { + if ($record->{$key} =~ $regexp) { + splice(@$recordList, $i, 1); + next RECORD; + } + } + + $i++; + } +} + +sub reportError($) +{ + my ($errorMessage) = @_; + + print STDERR basename($0) . ": $errorMessage\n"; +} diff --git a/WebKitTools/Scripts/run-mangleme-tests b/WebKitTools/Scripts/run-mangleme-tests new file mode 100755 index 0000000..78b5d14 --- /dev/null +++ b/WebKitTools/Scripts/run-mangleme-tests @@ -0,0 +1,173 @@ +#!/usr/bin/perl + +# Copyright (C) 2006 Alexey Proskuryakov (ap@nypop.com) +# +# 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. + +# A script to semi-automatically run mangleme tests. + +use strict; +use warnings; + +use Cwd; +use FindBin; +use Getopt::Long; +use IPC::Open2; + +use lib $FindBin::Bin; +use webkitdirs; + +sub openHTTPDIfNeeded(); +sub closeHTTPD(); +sub runSafari(); + +# Argument handling +my $guardMalloc = ''; +my $httpdPort = 8000; +my $downloadTest; + +GetOptions( + 'guard-malloc|g' => \$guardMalloc, + 'get=s' => \$downloadTest, + 'port=i' => \$httpdPort +); + + +setConfiguration(); +my $productDir = productDir(); + +chdirWebKit(); + +checkFrameworks(); + +mkdir "WebKitBuild/mangleme"; +(system "/usr/bin/make", "-C", "WebKitTools/mangleme") == 0 or die; + +my $httpdOpen = 0; +openHTTPDIfNeeded(); + +if ($downloadTest) { + system "/usr/bin/curl -o ~/Desktop/mangleme$downloadTest.html http://127.0.0.1:$httpdPort/remangle.cgi?$downloadTest"; + print "Saved the test as mangleme$downloadTest.html on the desktop\n"; +} else { + runSafari(); + print "Last generated tests:\n"; + system "grep 'Mangle attempt' /tmp/WebKit/error_log.txt | tail -n -5 | awk ' {print \$4}'"; +} + +closeHTTPD(); + + +sub runSafari() +{ + my $redirectTo; + if (@ARGV) { + $redirectTo = "http://127.0.0.1:$httpdPort/remangle.cgi?$ARGV[0]"; + } else { + $redirectTo = "http://127.0.0.1:$httpdPort/mangle.cgi"; + } + + open REDIRECT_HTML, ">", "/tmp/WebKit/redirect.html" or die; + print REDIRECT_HTML "<html>\n"; + print REDIRECT_HTML " <head>\n"; + print REDIRECT_HTML " <meta http-equiv=\"refresh\" content=\"1;URL=$redirectTo\" />\n"; + print REDIRECT_HTML " <script type=\"text/javascript\">\n"; + print REDIRECT_HTML " document.location = \"$redirectTo\";\n"; + print REDIRECT_HTML " </script>\n"; + print REDIRECT_HTML " </head>\n"; + print REDIRECT_HTML " <body>\n"; + print REDIRECT_HTML " </body>\n"; + print REDIRECT_HTML "</html>\n"; + close REDIRECT_HTML; + + local %ENV; + $ENV{DYLD_INSERT_LIBRARIES} = "/usr/lib/libgmalloc.dylib" if $guardMalloc; + system "WebKitTools/Scripts/run-safari", "-NSOpen", "/tmp/WebKit/redirect.html"; +} + +sub openHTTPDIfNeeded() +{ + return if $httpdOpen; + + mkdir "/tmp/WebKit"; + + if (-f "/tmp/WebKit/httpd.pid") { + my $oldPid = `cat /tmp/WebKit/httpd.pid`; + chomp $oldPid; + if (0 != kill 0, $oldPid) { + print "\nhttpd is already running: pid $oldPid, killing...\n"; + kill 15, $oldPid; + + my $retryCount = 20; + while ((0 != kill 0, $oldPid) && $retryCount) { + sleep 1; + --$retryCount; + } + + die "Timed out waiting for httpd to quit" unless $retryCount; + } + } + + my $testDirectory = getcwd() . "/LayoutTests"; + my $manglemeDirectory = getcwd() . "/WebKitBuild/mangleme"; + my $httpdPath = "/usr/sbin/httpd"; + my $httpdConfig = "$testDirectory/http/conf/httpd.conf"; + $httpdConfig = "$testDirectory/http/conf/apache2-httpd.conf" if `$httpdPath -v` =~ m|Apache/2|; + my $documentRoot = "$manglemeDirectory"; + my $typesConfig = "$testDirectory/http/conf/mime.types"; + my $listen = "127.0.0.1:$httpdPort"; + + open2(\*HTTPDIN, \*HTTPDOUT, $httpdPath, + "-f", "$httpdConfig", + "-C", "DocumentRoot \"$documentRoot\"", + "-C", "Listen $listen", + "-c", "TypesConfig \"$typesConfig\"", + "-c", "CustomLog \"/tmp/WebKit/access_log.txt\" common", + "-c", "ErrorLog \"/tmp/WebKit/error_log.txt\"", + # Apache wouldn't run CGIs with permissions==700 otherwise + "-c", "User \"#$<\""); + + my $retryCount = 20; + while (system("/usr/bin/curl -q --silent --stderr - --output /dev/null $listen") && $retryCount) { + sleep 1; + --$retryCount; + } + + die "Timed out waiting for httpd to start" unless $retryCount; + + $httpdOpen = 1; +} + +sub closeHTTPD() +{ + return if !$httpdOpen; + + close HTTPDIN; + close HTTPDOUT; + + kill 15, `cat /tmp/WebKit/httpd.pid` if -f "/tmp/WebKit/httpd.pid"; + + $httpdOpen = 0; +} diff --git a/WebKitTools/Scripts/run-pageloadtest b/WebKitTools/Scripts/run-pageloadtest new file mode 100755 index 0000000..ad6daa1 --- /dev/null +++ b/WebKitTools/Scripts/run-pageloadtest @@ -0,0 +1,92 @@ +#!/usr/bin/perl + +# Copyright (C) 2006 Eric Seidel (eric@webkit.org) +# +# 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. + +# Script to run the WebKit Open Source Project page load tests (PLTs). + +# Run all the tests passed in on the command line. + +use strict; +use warnings; + +use File::Basename; +use File::Spec; +use FindBin; +use Getopt::Long; + +use lib $FindBin::Bin; +use webkitdirs; + +# Argument handling +my $testName = 'svg'; +my $showHelp = 0; + +my $usage = + "Usage: " . basename($0) . "[options] testName\n" . + " --help Show this help message\n"; + +my $getOptionsResult = GetOptions('help' => \$showHelp); + +if (!$getOptionsResult || $showHelp) { + print STDERR $usage; + exit 1; +} + +$testName = shift @ARGV if (@ARGV); + +my $safariExecutablePath = safariPath(); +my $safariResourcePath = File::Spec->catdir(dirname(dirname($safariExecutablePath)), "Resources"); + +# Check to see that all the frameworks are built. +checkFrameworks(); + +chdirWebKit(); + +if ($testName eq 'svg') { + my $suiteFile = "PageLoadTests/$testName/$testName.pltsuite"; + my $webkitPath = sourceDir(); + `cat "$suiteFile" | perl -pe 's|WEBKIT_PATH|$webkitPath|' > $safariResourcePath/$testName.pltsuite` +} + +die "Please copy ${testName}.pltsuite to ${safariResourcePath}/${testName}.pltsuite" + if (! -f "${safariResourcePath}/${testName}.pltsuite"); + +setConfiguration(); + +my $productDir = productDir(); + +# Set up DYLD_FRAMEWORK_PATH to point to the product directory. +print "Starting Safari with DYLD_FRAMEWORK_PATH set to point to built WebKit in $productDir.\n"; +$ENV{DYLD_FRAMEWORK_PATH} = $productDir; +$ENV{WEBKIT_UNSET_DYLD_FRAMEWORK_PATH} = "YES"; + +my @testCommands = ('activate'); +# Autovicki would clear history, we skip that here as this is likely an active user account +@testCommands = (@testCommands, ("run $testName", 'emptyCache', 'wait 30')); +@testCommands = (@testCommands, (("run $testName", 'wait 10') x 3)); +my $testCommandsString = join('; ', @testCommands); +exec $safariExecutablePath, '--test-commands', $testCommandsString or die; diff --git a/WebKitTools/Scripts/run-safari b/WebKitTools/Scripts/run-safari new file mode 100755 index 0000000..4474b69 --- /dev/null +++ b/WebKitTools/Scripts/run-safari @@ -0,0 +1,41 @@ +#!/usr/bin/perl -w + +# Copyright (C) 2005, 2007 Apple 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. + +# Simplified "run" script for Web Kit Open Source Project. + +use strict; +use FindBin; +use lib $FindBin::Bin; +use webkitdirs; + +setConfiguration(); + +# Check to see that all the frameworks are built. +checkFrameworks(); + +exit exitStatus(runSafari()); diff --git a/WebKitTools/Scripts/run-sunspider b/WebKitTools/Scripts/run-sunspider new file mode 100755 index 0000000..8dfeabb --- /dev/null +++ b/WebKitTools/Scripts/run-sunspider @@ -0,0 +1,123 @@ +#!/usr/bin/perl -w + +# Copyright (C) 2007 Apple Inc. All rights reserved. +# Copyright (C) 2007 Eric Seidel <eric@webkit.org> +# +# 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. +# +# THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 COMPUTER, INC. OR +# 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. + +use strict; +use FindBin; +use Getopt::Long qw(:config pass_through); +use lib $FindBin::Bin; +use webkitdirs; +use POSIX; + +# determine configuration, but default to "Release" instead of last-used configuration +setConfiguration("Release"); +setConfiguration(); +my $configuration = configuration(); + +my $root; +my $testRuns = 10; # This number may be different from what sunspider defaults to (that's OK) +my $runShark = 0; +my $runShark20 = 0; +my $runSharkCache = 0; +my $setBaseline = 0; +my $showHelp = 0; +my $testsPattern; + +my $programName = basename($0); +my $usage = <<EOF; +Usage: $programName [options] [options to pass to build system] + --help Show this help message + --set-baseline Set baseline for future comparisons + --root Path to root tools build + --runs Number of times to run tests (default: $testRuns) + --tests Only run tests matching provided pattern + --shark Sample with the Mac OS X "Shark" performance testing tool (implies --runs=1) + --shark20 Like --shark, but with a 20 microsecond sampling interval + --shark-cache Like --shark, but performs a L2 cache-miss sample instead of time sample +EOF + +GetOptions('root=s' => sub { my ($value) = @_; $root = $value; setConfigurationProductDir(Cwd::abs_path($root)); }, + 'runs=i' => \$testRuns, + 'set-baseline' => \$setBaseline, + 'shark' => \$runShark, + 'shark20' => \$runShark20, + 'shark-cache' => \$runSharkCache, + 'tests=s' => \$testsPattern, + 'help' => \$showHelp); + +if ($showHelp) { + print STDERR $usage; + exit 1; +} + +sub buildTestKJS +{ + if (!defined($root)){ + push(@ARGV, "--" . $configuration); + + chdirWebKit(); + my $buildResult = system "WebKitTools/Scripts/build-testkjs", @ARGV; + if ($buildResult) { + print STDERR "Compiling testkjs failed!\n"; + exit exitStatus($buildResult); + } + } +} + +sub setupEnvironmentForExecution($) +{ + my ($productDir) = @_; + print "Starting sunspider with DYLD_FRAMEWORK_PATH set to point to built JavaScriptCore in $productDir.\n"; + $ENV{DYLD_FRAMEWORK_PATH} = $productDir; + # FIXME: Other platforms may wish to augment this method to use LD_LIBRARY_PATH, etc. +} + +sub testKJSPath($) +{ + my ($productDir) = @_; + my $testkjsName = "testkjs"; + $testkjsName .= "_debug" if (isCygwin() && ($configuration eq "Debug")); + return "$productDir/$testkjsName"; +} + +buildTestKJS(); + +chdirWebKit(); +chdir("SunSpider"); + +my $productDir = productDir(); +# FIXME: This hack should be pushed down into productDir() +$productDir .= "/JavaScriptCore" if (isQt() or isGtk()); + +setupEnvironmentForExecution($productDir); +my @args = ("--shell", testKJSPath($productDir), "--runs", $testRuns); +# This code could be removed if we chose to pass extra args to sunspider instead of Xcode +push @args, "--set-baseline" if $setBaseline; +push @args, "--shark" if $runShark; +push @args, "--shark20" if $runShark20; +push @args, "--shark-cache" if $runSharkCache; +push @args, "--tests", $testsPattern if $testsPattern; + +exec "./sunspider", @args; diff --git a/WebKitTools/Scripts/run-testkjs b/WebKitTools/Scripts/run-testkjs new file mode 100755 index 0000000..5610bad --- /dev/null +++ b/WebKitTools/Scripts/run-testkjs @@ -0,0 +1,58 @@ +#!/usr/bin/perl + +# Copyright (C) 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. + +# This script runs a list of scripts through testkjs a specified number of times. + +use strict; +use warnings; +use FindBin; +use lib $FindBin::Bin; +use Getopt::Long; +use webkitdirs; + +my $usage = "Usage: run-testkjs [--count run_count] [--verbose] shell_file [file2...]"; + +my $count = 1; +my $verbose = 0; +GetOptions("count|c=i" => \$count, + "verbose|v" => \$verbose); +die "$usage\n" if (@ARGV < 1); + +my $testkjs = productDir() . "/testkjs @ARGV"; +$testkjs .= " 2> /dev/null" unless $verbose; + +my $dyld = productDir(); + +$ENV{"DYLD_FRAMEWORK_PATH"} = $dyld; +print STDERR "Running $count time(s): DYLD_FRAMEWORK_PATH=$dyld $testkjs\n"; +while ($count--) { + if (system("$testkjs") != 0) { + last; + } +} + diff --git a/WebKitTools/Scripts/run-webkit-app b/WebKitTools/Scripts/run-webkit-app new file mode 100755 index 0000000..36b9a58 --- /dev/null +++ b/WebKitTools/Scripts/run-webkit-app @@ -0,0 +1,50 @@ +#!/usr/bin/perl -w + +# Copyright (C) 2005 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. + +# Simplified "run" script for Web Kit Open Source Project. + +use strict; +use FindBin; +use lib $FindBin::Bin; +use webkitdirs; + +setConfiguration(); +my $productDir = productDir(); + +die "Did not specify an application to open (e.g. run-webkit-app AppName).\n" unless length($ARGV[0]) > 0; + +# Check to see that all the frameworks are built. +checkFrameworks(); + +# Set up DYLD_FRAMEWORK_PATH to point to the product directory. +print "Start $ARGV[0] with DYLD_FRAMEWORK_PATH set to point to built WebKit in $productDir.\n"; +$ENV{DYLD_FRAMEWORK_PATH} = $productDir; +$ENV{WEBKIT_UNSET_DYLD_FRAMEWORK_PATH} = "YES"; + +unshift(@ARGV, "-a"); +exec "open", @ARGV; diff --git a/WebKitTools/Scripts/run-webkit-httpd b/WebKitTools/Scripts/run-webkit-httpd new file mode 100755 index 0000000..a64eef6 --- /dev/null +++ b/WebKitTools/Scripts/run-webkit-httpd @@ -0,0 +1,127 @@ +#!/usr/bin/perl + +# Copyright (C) 2005, 2006, 2007 Apple Inc. All rights reserved. +# Copyright (C) 2006 Alexey Proskuryakov (ap@nypop.com) +# +# 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 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. + +# Script to run Apache with the same configuration as used in http layout tests. + +use strict; +use warnings; + +use Cwd; +use File::Basename; +use Getopt::Long; +use FindBin; + +use lib $FindBin::Bin; +use webkitdirs; + +# Argument handling +my $httpdPort = 8000; +my $allInterfaces = 0; +my $showHelp; + +my $result = GetOptions( + 'all-interfaces|a' => \$allInterfaces, + 'help|h' => \$showHelp, + 'port=i' => \$httpdPort, +); + +if (!$result || @ARGV || $showHelp) { + print "Usage: " . basename($0) . " [options]\n"; + print " -a|--all-interfaces Bind to all interfaces\n"; + print " -h|--help Show this help message\n"; + print " -p|--port NNNN Bind to port NNNN\n"; + exit 1; +} + +setConfiguration(); +my $productDir = productDir(); +chdirWebKit(); + +mkdir "/tmp/WebKit"; + +if (-f "/tmp/WebKit/httpd.pid") { + my $oldPid = `cat /tmp/WebKit/httpd.pid`; + chomp $oldPid; + if (0 != kill 0, $oldPid) { + print "\nhttpd is already running: pid $oldPid, killing...\n"; + kill 15, $oldPid; + + my $retryCount = 20; + while ((0 != kill 0, $oldPid) && $retryCount) { + sleep 1; + --$retryCount; + } + + die "Timed out waiting for httpd to quit" unless $retryCount; + } +} + +my $testDirectory = getcwd() . "/LayoutTests"; +my $httpdPath = "/usr/sbin/httpd"; +$httpdPath = "/usr/sbin/apache2" if isDebianBased(); +my $httpdConfig = "$testDirectory/http/conf/httpd.conf"; +$httpdConfig = "$testDirectory/http/conf/cygwin-httpd.conf" if isCygwin(); +$httpdConfig = "$testDirectory/http/conf/apache2-httpd.conf" if `$httpdPath -v` =~ m|Apache/2|; +$httpdConfig = "$testDirectory/http/conf/apache2-debian-httpd.conf" if isDebianBased(); +my $documentRoot = "$testDirectory/http/tests"; +my $typesConfig = "$testDirectory/http/conf/mime.types"; +my $sslCertificate = "$testDirectory/http/conf/webkit-httpd.pem"; + +my $listen = "127.0.0.1:$httpdPort"; +$listen = "$httpdPort" if ($allInterfaces); + +if ($allInterfaces) { + print "Starting httpd on port $httpdPort (all interfaces)...\n"; +} else { + print "Starting httpd on <http://$listen/>...\n"; +} +print "Press Ctrl+C to stop it.\n\n"; + +my @args = ( + "-f", "$httpdConfig", + "-C", "DocumentRoot \"$documentRoot\"", + "-C", "Listen $listen", + "-c", "TypesConfig \"$typesConfig\"", + "-c", "CustomLog |/usr/bin/tee common", + "-c", "ErrorLog |/usr/bin/tee", + # Apache wouldn't run CGIs with permissions==700 otherwise. + "-c", "User \"#$<\"", + # Run in single-process mode, do not detach from the controlling terminal. + "-X", + # Disable Keep-Alive support. Makes testing in multiple browsers easier (no need to wait + # for another browser's connection to expire). + "-c", "KeepAlive 0" +); + +# FIXME: Enable this on Windows once <rdar://problem/5345985> is fixed +push(@args, "-c", "SSLCertificateFile \"$sslCertificate\"") unless isCygwin(); + +system($httpdPath, @args); + +unlink "/tmp/WebKit/httpd.pid"; diff --git a/WebKitTools/Scripts/run-webkit-nightly.cmd b/WebKitTools/Scripts/run-webkit-nightly.cmd new file mode 100755 index 0000000..93037ab --- /dev/null +++ b/WebKitTools/Scripts/run-webkit-nightly.cmd @@ -0,0 +1,10 @@ +@echo off +set script="%TMP%\run-webkit-nightly2.cmd" +set vsvars="%VS80COMNTOOLS%\vsvars32.bat" +if exist %vsvars% ( + copy %vsvars% "%script%" +) else ( + del "%script%" +) +FindSafari.exe %1 /printSafariLauncher >> "%script%" +call %script% diff --git a/WebKitTools/Scripts/run-webkit-tests b/WebKitTools/Scripts/run-webkit-tests new file mode 100755 index 0000000..3b6bbb3 --- /dev/null +++ b/WebKitTools/Scripts/run-webkit-tests @@ -0,0 +1,1627 @@ +#!/usr/bin/perl + +# Copyright (C) 2005, 2006, 2007 Apple Inc. All rights reserved. +# Copyright (C) 2006 Alexey Proskuryakov (ap@nypop.com) +# Copyright (C) 2007 Matt Lilek (pewtermoose@gmail.com) +# Copyright (C) 2007 Eric Seidel <eric@webkit.org> +# +# 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. + +# Script to run the Web Kit Open Source Project layout tests. + +# Run all the tests passed in on the command line. +# If no tests are passed, find all the .html, .shtml, .xml, .xhtml, .pl, .php (and svg) files in the test directory. + +# Run each text. +# Compare against the existing file xxx-expected.txt. +# If there is a mismatch, generate xxx-actual.txt and xxx-diffs.txt. + +# At the end, report: +# the number of tests that got the expected results +# the number of tests that ran, but did not get the expected results +# the number of tests that failed to run +# the number of tests that were run but had no expected results to compare against + +use strict; +use warnings; + +use Cwd; +use File::Basename; +use File::Copy; +use File::Find; +use File::Path; +use File::Spec; +use File::Spec::Functions; +use FindBin; +use Getopt::Long; +use IPC::Open2; +use IPC::Open3; +use Time::HiRes qw(time); + +use List::Util 'shuffle'; + +use lib $FindBin::Bin; +use webkitdirs; +use POSIX; + +sub openDumpTool(); +sub closeDumpTool(); +sub dumpToolDidCrash(); +sub closeHTTPD(); +sub countAndPrintLeaks($$$); +sub fileNameWithNumber($$); +sub numericcmp($$); +sub openHTTPDIfNeeded(); +sub pathcmp($$); +sub processIgnoreTests($); +sub slowestcmp($$); +sub splitpath($); +sub stripExtension($); +sub isTextOnlyTest($); +sub expectedDirectoryForTest($;$;$); +sub printFailureMessageForTest($$); +sub toURL($); +sub toWindowsPath($); +sub closeCygpaths(); +sub validateSkippedArg($$;$); +sub htmlForExpectedAndActualResults($); +sub deleteExpectedAndActualResults($); +sub recordActualResultsAndDiff($$); +sub buildPlatformHierarchy(); +sub epiloguesAndPrologues($$); +sub parseLeaksandPrintUniqueLeaks(); + +# Argument handling +my $addPlatformExceptions = 0; +my $configuration = configuration(); +my $guardMalloc = ''; +my $httpdPort = 8000; +my $httpdSSLPort = 8443; +my $ignoreTests = ''; +my $launchSafari = 1; +my $platform; +my $pixelTests = ''; +my $quiet = ''; +my $repaintSweepHorizontally = ''; +my $repaintTests = ''; +my $report10Slowest = 0; +my $resetResults = 0; +my $shouldCheckLeaks = 0; +my $showHelp = 0; +my $testsPerDumpTool = 1000; +my $testHTTP = 1; +my $testMedia = 1; +my $testResultsDirectory = "/tmp/layout-test-results"; +my $threaded = 0; +my $threshold = 0; +my $treatSkipped = "default"; +my $verbose = 0; +my $useValgrind = 0; +my $strictTesting = 0; +my $generateNewResults = 1; +my $stripEditingCallbacks = isCygwin(); +my $root; +my $reverseTests = 0; +my $randomizeTests = 0; +my $mergeDepth; +my @leaksFilenames; + +# Default to --no-http for Qt, Gtk and wx for now. +$testHTTP = 0 if (isQt() || isGtk() || isWx()); + +my $expectedTag = "expected"; +my $actualTag = "actual"; +my $diffsTag = "diffs"; +my $errorTag = "stderr"; + +if (isTiger()) { + $platform = "mac-tiger"; +} elsif (isLeopard()) { + $platform = "mac-leopard"; +} elsif (isOSX()) { + $platform = "mac"; +} elsif (isQt()) { + $platform = "qt"; +} elsif (isGtk()) { + $platform = "gtk"; +} elsif (isCygwin()) { + $platform = "win"; +} + +if (!defined($platform)) { + print "WARNING: Your platform is not recognized. Any platform-specific results will be generated in platform/undefined.\n"; + $platform = "undefined"; +} + +my $programName = basename($0); +my $launchSafariDefault = $launchSafari ? "launch" : "do not launch"; +my $httpDefault = $testHTTP ? "run" : "do not run"; + +# FIXME: "--strict" should be renamed to qt-mac-comparison, or something along those lines. +my $usage = <<EOF; +Usage: $programName [options] [testdir|testpath ...] + --add-platform-exceptions Put new results for non-platform-specific failing tests into the platform-specific results directory + -c|--configuration config Set DumpRenderTree build configuration + -g|--guard-malloc Enable malloc guard + --help Show this help message + -h|--horizontal-sweep Change repaint to sweep horizontally instead of vertically (implies --repaint-tests) + --[no-]http Run (or do not run) http tests (default: $httpDefault) + -i|--ignore-tests Comma-separated list of directories or tests to ignore + --[no-]launch-safari Launch (or do not launch) Safari to display test results (default: $launchSafariDefault) + -l|--leaks Enable leaks checking + --[no-]new-test-results Generate results for new tests + -p|--pixel-tests Enable pixel tests + --platform Override the detected platform to use for tests and results (default: $platform) + --port Web server port to use with http tests + -q|--quiet Less verbose output + -r|--repaint-tests Run repaint tests (implies --pixel-tests) + --reset-results Reset ALL results (including pixel tests if --pixel-tests is set) + -o|--results-directory Output results directory (default: $testResultsDirectory) + --random Run the tests in a random order + --reverse Run the tests in reverse alphabetical order + --root Path to root tools build + -1|--singly Isolate each test case run (implies --verbose) + --skipped=[default|ignore|only] Specifies how to treat the Skipped file + default: Tests/directories listed in the Skipped file are not tested + ignore: The Skipped file is ignored + only: Only those tests/directories listed in the Skipped file will be run + --slowest Report the 10 slowest tests + --strict Do a comparison with the output on Mac (Qt only) + --[no-]strip-editing-callbacks Remove editing callbacks from expected results + -t|--threaded Run a concurrent JavaScript thead with each test + --threshold t Ignore pixel value deviations less than or equal to t + --valgrind Run DumpRenderTree inside valgrind (Qt/Linux only) + -v|--verbose More verbose output (overrides --quiet) + -m|--merge-leak-depth arg Merges leak callStacks and prints the number of unique leaks beneath a callstack depth of arg. Defaults to 5. +EOF + +my $getOptionsResult = GetOptions( + 'c|configuration=s' => \$configuration, + 'debug|devel' => sub { $configuration = "Debug" }, + 'guard-malloc|g' => \$guardMalloc, + 'help' => \$showHelp, + 'horizontal-sweep|h' => \$repaintSweepHorizontally, + 'http!' => \$testHTTP, + 'ignore-tests|i=s' => \$ignoreTests, + 'launch-safari!' => \$launchSafari, + 'leaks|l' => \$shouldCheckLeaks, + 'pixel-tests|p' => \$pixelTests, + 'platform=s' => \$platform, + 'port=i' => \$httpdPort, + 'quiet|q' => \$quiet, + 'release|deploy' => sub { $configuration = "Release" }, + 'repaint-tests|r' => \$repaintTests, + 'reset-results' => \$resetResults, + 'new-test-results!' => \$generateNewResults, + 'results-directory|o=s' => \$testResultsDirectory, + 'singly|1' => sub { $testsPerDumpTool = 1; }, + 'nthly=i' => \$testsPerDumpTool, + 'skipped=s' => \&validateSkippedArg, + 'slowest' => \$report10Slowest, + 'threaded|t' => \$threaded, + 'threshold=i' => \$threshold, + 'verbose|v' => \$verbose, + 'valgrind' => \$useValgrind, + 'strict' => \$strictTesting, + 'strip-editing-callbacks!' => \$stripEditingCallbacks, + 'random' => \$randomizeTests, + 'reverse' => \$reverseTests, + 'root=s' => \$root, + 'add-platform-exceptions' => \$addPlatformExceptions, + 'merge-leak-depth|m:5' => \$mergeDepth, +); + +if (!$getOptionsResult || $showHelp) { + print STDERR $usage; + exit 1; +} + +my $ignoreSkipped = $treatSkipped eq "ignore"; +my $skippedOnly = $treatSkipped eq "only"; + +!$skippedOnly || @ARGV == 0 or die "--skipped=only cannot be used when tests are specified on the command line."; + +setConfiguration($configuration); + +my $configurationOption = "--" . lc($configuration); + +$repaintTests = 1 if $repaintSweepHorizontally; + +$pixelTests = 1 if $repaintTests; +$pixelTests = 1 if $threshold > 0; + +$verbose = 1 if $testsPerDumpTool == 1; + +if ($shouldCheckLeaks && $testsPerDumpTool > 1000) { + print STDERR "\nWARNING: Running more than 1000 tests at a time with MallocStackLogging enabled may cause a crash.\n\n"; +} + +# Stack logging does not play well with QuickTime on Tiger (rdar://problem/5537157) +$testMedia = 0 if $shouldCheckLeaks && isTiger(); + +setConfigurationProductDir(Cwd::abs_path($root)) if (defined($root)); +my $productDir = productDir(); +$productDir .= "/bin" if (isQt()); + +if (isGtk()) { + if ($ENV{WEBKITAUTOTOOLS}) { + $productDir .= "/Programs"; + } else { + $productDir .= "/WebKitTools/DumpRenderTree/gtk"; + } +} + +chdirWebKit(); + +if(!defined($root)){ + # Push the parameters to build-dumprendertree as an array + my @args; + push(@args, "--" . $configuration); + push(@args, "--qt") if isQt(); + push(@args, "--gtk") if isGtk(); + + my $buildResult = system "WebKitTools/Scripts/build-dumprendertree", @args; + if ($buildResult) { + print STDERR "Compiling DumpRenderTree failed!\n"; + exit exitStatus($buildResult); + } +} + +my $dumpToolName = "DumpRenderTree"; +$dumpToolName .= "_debug" if isCygwin() && $configuration ne "Release"; +my $dumpTool = "$productDir/$dumpToolName"; +die "can't find executable $dumpToolName (looked in $productDir)\n" unless -x $dumpTool; + +my $imageDiffTool = "$productDir/ImageDiff"; +die "can't find executable $imageDiffTool (looked in $productDir)\n" if $pixelTests && !-x $imageDiffTool; + +checkFrameworks() unless isCygwin(); + +my $layoutTestsName = "LayoutTests"; +my $testDirectory = File::Spec->rel2abs($layoutTestsName); +my $expectedDirectory = $testDirectory; +my $platformBaseDirectory = catdir($testDirectory, "platform"); +my $platformTestDirectory = catdir($platformBaseDirectory, $platform); +my @platformHierarchy = buildPlatformHierarchy(); + +$expectedDirectory = $ENV{"WebKitExpectedTestResultsDirectory"} if $ENV{"WebKitExpectedTestResultsDirectory"}; + +my $testResults = catfile($testResultsDirectory, "results.html"); + +print "Running tests from $testDirectory\n"; + +my @tests = (); +my %testType = (); + +system "ln", "-s", $testDirectory, "/tmp/LayoutTests" unless -x "/tmp/LayoutTests"; + +my %ignoredFiles = (); +my %ignoredDirectories = map { $_ => 1 } qw(platform); +my %ignoredLocalDirectories = map { $_ => 1 } qw(.svn _svn resources); +my %supportedFileExtensions = map { $_ => 1 } qw(html shtml xml xhtml pl php); +if (checkWebCoreSVGSupport(0)) { + $supportedFileExtensions{'svg'} = 1; +} elsif (isCygwin()) { + # FIXME: We should fix webkitdirs.pm:hasSVGSupport() to do the correct + # check for Windows instead of forcing this here. + $supportedFileExtensions{'svg'} = 1; +} else { + $ignoredLocalDirectories{'svg'} = 1; +} +if (!$testHTTP) { + $ignoredDirectories{'http'} = 1; +} + +if (!$testMedia) { + $ignoredDirectories{'media'} = 1; + $ignoredDirectories{'http/tests/media'} = 1; +} + +if ($ignoreTests) { + processIgnoreTests($ignoreTests); +} + +if (!$ignoreSkipped) { + foreach my $level (@platformHierarchy) { + if (open SKIPPED, "<", "$level/Skipped") { + if ($verbose && !$skippedOnly) { + my ($dir, $name) = splitpath($level); + print "Skipped tests in $name:\n"; + } + + while (<SKIPPED>) { + my $skipped = $_; + chomp $skipped; + $skipped =~ s/^[ \n\r]+//; + $skipped =~ s/[ \n\r]+$//; + if ($skipped && $skipped !~ /^#/) { + if ($skippedOnly) { + push(@ARGV, $skipped); + } else { + if ($verbose) { + print " $skipped\n"; + } + processIgnoreTests($skipped); + } + } + } + close SKIPPED; + } + } +} + + +my $directoryFilter = sub { + return () if exists $ignoredLocalDirectories{basename($File::Find::dir)}; + return () if exists $ignoredDirectories{File::Spec->abs2rel($File::Find::dir, $testDirectory)}; + return @_; +}; + +my $fileFilter = sub { + my $filename = $_; + if ($filename =~ /\.([^.]+)$/) { + if (exists $supportedFileExtensions{$1}) { + my $path = File::Spec->abs2rel(catfile($File::Find::dir, $filename), $testDirectory); + push @tests, $path if !exists $ignoredFiles{$path}; + } + } +}; + +for my $test (@ARGV) { + $test =~ s/^($layoutTestsName|$testDirectory)\///; + my $fullPath = catfile($testDirectory, $test); + if (file_name_is_absolute($test)) { + print "can't run test $test outside $testDirectory\n"; + } elsif (-f $fullPath) { + my ($filename, $pathname, $fileExtension) = fileparse($test, qr{\.[^.]+$}); + if (!exists $supportedFileExtensions{substr($fileExtension, 1)}) { + print "test $test does not have a supported extension\n"; + } elsif ($testHTTP || $pathname !~ /^http\//) { + push @tests, $test; + } + } elsif (-d $fullPath) { + find({ preprocess => $directoryFilter, wanted => $fileFilter }, $fullPath); + + for my $level (@platformHierarchy) { + my $platformPath = catfile($level, $test); + find({ preprocess => $directoryFilter, wanted => $fileFilter }, $platformPath) if (-d $platformPath); + } + } else { + print "test $test not found\n"; + } +} +if (!scalar @ARGV) { + find({ preprocess => $directoryFilter, wanted => $fileFilter }, $testDirectory); + + for my $level (@platformHierarchy) { + find({ preprocess => $directoryFilter, wanted => $fileFilter }, $level); + } +} + +die "no tests to run\n" if !@tests; + +@tests = sort pathcmp @tests; + +my %counts; +my %tests; +my %imagesPresent; +my %imageDifferences; +my %durations; +my $count = 0; +my $leaksOutputFileNumber = 1; +my $totalLeaks = 0; + +my @toolArgs = (); +push @toolArgs, "--dump-all-pixels" if $pixelTests && $resetResults; +push @toolArgs, "--pixel-tests" if $pixelTests; +push @toolArgs, "--repaint" if $repaintTests; +push @toolArgs, "--horizontal-sweep" if $repaintSweepHorizontally; +push @toolArgs, "--threaded" if $threaded; +push @toolArgs, "-"; + +my @diffToolArgs = (); +push @diffToolArgs, "--threshold", $threshold; + +$| = 1; + +my $imageDiffToolPID; +if ($pixelTests) { + local %ENV; + $ENV{MallocStackLogging} = 1 if $shouldCheckLeaks; + $imageDiffToolPID = open2(\*DIFFIN, \*DIFFOUT, $imageDiffTool, @diffToolArgs) or die "unable to open $imageDiffTool\n"; +} + +my $dumpToolPID; +my $isDumpToolOpen = 0; +my $dumpToolCrashed = 0; + +my $atLineStart = 1; +my $lastDirectory = ""; + +my $isHttpdOpen = 0; + +sub catch_pipe { $dumpToolCrashed = 1; } +$SIG{"PIPE"} = "catch_pipe"; + +print "Testing ", scalar @tests, " test cases.\n"; +my $overallStartTime = time; + +my %expectedResultDirectory; + +# Reverse the tests +@tests = reverse @tests if $reverseTests; + +# Shuffle the array +@tests = shuffle(@tests) if $randomizeTests; + +for my $test (@tests) { + next if $test eq 'results.html'; + + my $newDumpTool = not $isDumpToolOpen; + openDumpTool(); + + my $base = stripExtension($test); + + my $dir = $base; + $dir =~ s|/[^/]+$||; + + if ($newDumpTool || $dir ne $lastDirectory) { + foreach my $logue (epiloguesAndPrologues($newDumpTool ? "" : $lastDirectory, $dir)) { + if (isCygwin()) { + $logue = toWindowsPath($logue); + } else { + $logue = canonpath($logue); + } + if ($verbose) { + print "running epilogue or prologue $logue\n"; + } + print OUT "$logue\n"; + # Discard the output. + while (<IN>) { + last if /#EOF/; + } + } + } + + if ($verbose) { + print "running $test -> "; + $atLineStart = 0; + } elsif (!$quiet) { + if ($dir ne $lastDirectory) { + print "\n" unless $atLineStart; + print "$dir "; + } + print "."; + $atLineStart = 0; + } + + $lastDirectory = $dir; + + my $result; + + my $startTime = time if $report10Slowest; + + if ($test !~ /^http\//) { + my $testPath = "$testDirectory/$test"; + if (isCygwin()) { + $testPath = toWindowsPath($testPath); + } else { + $testPath = canonpath($testPath); + } + print OUT "$testPath\n"; + } else { + openHTTPDIfNeeded(); + if ($test !~ /^http\/tests\/local\// && $test !~ /^http\/tests\/ssl\// && $test !~ /^http\/tests\/media\//) { + my $path = canonpath($test); + $path =~ s/^http\/tests\///; + print OUT "http://127.0.0.1:$httpdPort/$path\n"; + } elsif ($test =~ /^http\/tests\/ssl\//) { + my $path = canonpath($test); + $path =~ s/^http\/tests\///; + print OUT "https://127.0.0.1:$httpdSSLPort/$path\n"; + } else { + my $testPath = "$testDirectory/$test"; + if (isCygwin()) { + $testPath = toWindowsPath($testPath); + } else { + $testPath = canonpath($testPath); + } + print OUT "$testPath\n"; + } + } + + my $actual = ""; + while (<IN>) { + last if /#EOF/; + $actual .= $_; + } + + my $isText = isTextOnlyTest($actual); + + $durations{$test} = time - $startTime if $report10Slowest; + + my $expected; + my $expectedDir = expectedDirectoryForTest($base, $isText, 0); + $expectedResultDirectory{$base} = $expectedDir; + + if (!$resetResults && open EXPECTED, "<", "$expectedDir/$base-$expectedTag.txt") { + $expected = ""; + while (<EXPECTED>) { + next if $stripEditingCallbacks && $_ =~ /^EDITING DELEGATE:/; + $expected .= $_; + } + close EXPECTED; + } + my $expectedMac; + if (!isOSX() && $strictTesting && !$isText) { + if (!$resetResults && open EXPECTED, "<", "$testDirectory/platform/mac/$base-$expectedTag.txt") { + $expectedMac = ""; + while (<EXPECTED>) { + $expectedMac .= $_; + } + close EXPECTED; + } + } + + if ($shouldCheckLeaks && $testsPerDumpTool == 1) { + print " $test -> "; + } + + my $actualPNG = ""; + my $diffPNG = ""; + my $diffPercentage = ""; + my $diffResult = "passed"; + + if ($pixelTests) { + my $expectedPixelDir = expectedDirectoryForTest($base, $isText, 1); + + my $actualHash = ""; + my $expectedHash = ""; + my $actualPNGSize = 0; + + while (<IN>) { + last if /#EOF/; + if (/ActualHash: ([a-f0-9]{32})/) { + $actualHash = $1; + } elsif (/BaselineHash: ([a-f0-9]{32})/) { + $expectedHash = $1; + } elsif (/Content-length: (\d+)\s*/) { + $actualPNGSize = $1; + read(IN, $actualPNG, $actualPNGSize); + } + } + + if ($expectedHash ne $actualHash && -f "$expectedPixelDir/$base-$expectedTag.png") { + my $expectedPNGSize = -s "$expectedPixelDir/$base-$expectedTag.png"; + my $expectedPNG = ""; + open EXPECTEDPNG, "$expectedPixelDir/$base-$expectedTag.png"; + read(EXPECTEDPNG, $expectedPNG, $expectedPNGSize); + + print DIFFOUT "Content-length: $actualPNGSize\n"; + print DIFFOUT $actualPNG; + + print DIFFOUT "Content-length: $expectedPNGSize\n"; + print DIFFOUT $expectedPNG; + + while (<DIFFIN>) { + last if /^error/ || /^diff:/; + if (/Content-length: (\d+)\s*/) { + read(DIFFIN, $diffPNG, $1); + } + } + + if (/^diff: (.+)% (passed|failed)/) { + $diffPercentage = $1; + $imageDifferences{$base} = $diffPercentage; + $diffResult = $2; + } + } + + if ($actualPNGSize && ($resetResults || !-f "$expectedPixelDir/$base-$expectedTag.png")) { + mkpath catfile($expectedPixelDir, dirname($base)) if $testDirectory ne $expectedPixelDir; + open EXPECTED, ">", "$expectedPixelDir/$base-expected.png" or die "could not create $expectedPixelDir/$base-expected.png\n"; + print EXPECTED $actualPNG; + close EXPECTED; + } + + # update the expected hash if the image diff said that there was no difference + if ($actualHash ne "" && ($resetResults || !-f "$expectedPixelDir/$base-$expectedTag.checksum")) { + open EXPECTED, ">", "$expectedPixelDir/$base-$expectedTag.checksum" or die "could not create $expectedPixelDir/$base-$expectedTag.checksum\n"; + print EXPECTED $actualHash; + close EXPECTED; + } + } + + if (!isOSX() && $strictTesting && !$isText) { + if (defined $expectedMac) { + my $simplified_actual; + $simplified_actual = $actual; + $simplified_actual =~ s/at \(-?[0-9]+,-?[0-9]+\) *//g; + $simplified_actual =~ s/size -?[0-9]+x-?[0-9]+ *//g; + $simplified_actual =~ s/text run width -?[0-9]+: //g; + $simplified_actual =~ s/text run width -?[0-9]+ [a-zA-Z ]+: //g; + $simplified_actual =~ s/RenderButton {BUTTON} .*/RenderButton {BUTTON}/g; + $simplified_actual =~ s/RenderImage {INPUT} .*/RenderImage {INPUT}/g; + $simplified_actual =~ s/RenderBlock {INPUT} .*/RenderBlock {INPUT}/g; + $simplified_actual =~ s/RenderTextControl {INPUT} .*/RenderTextControl {INPUT}/g; + $simplified_actual =~ s/\([0-9]+px/px/g; + $simplified_actual =~ s/ *" *\n +" */ /g; + $simplified_actual =~ s/" +$/"/g; + + $simplified_actual =~ s/- /-/g; + $simplified_actual =~ s/\n( *)"\s+/\n$1"/g; + $simplified_actual =~ s/\s+"\n/"\n/g; + + $expectedMac =~ s/at \(-?[0-9]+,-?[0-9]+\) *//g; + $expectedMac =~ s/size -?[0-9]+x-?[0-9]+ *//g; + $expectedMac =~ s/text run width -?[0-9]+: //g; + $expectedMac =~ s/text run width -?[0-9]+ [a-zA-Z ]+: //g; + $expectedMac =~ s/RenderButton {BUTTON} .*/RenderButton {BUTTON}/g; + $expectedMac =~ s/RenderImage {INPUT} .*/RenderImage {INPUT}/g; + $expectedMac =~ s/RenderBlock {INPUT} .*/RenderBlock {INPUT}/g; + $expectedMac =~ s/RenderTextControl {INPUT} .*/RenderTextControl {INPUT}/g; + $expectedMac =~ s/\([0-9]+px/px/g; + $expectedMac =~ s/ *" *\n +" */ /g; + $expectedMac =~ s/" +$/"/g; + + $expectedMac =~ s/- /-/g; + $expectedMac =~ s/\n( *)"\s+/\n$1"/g; + $expectedMac =~ s/\s+"\n/"\n/g; + + if ($simplified_actual ne $expectedMac) { + open ACTUAL, ">", "/tmp/actual.txt" or die; + print ACTUAL $simplified_actual; + close ACTUAL; + open ACTUAL, ">", "/tmp/expected.txt" or die; + print ACTUAL $expectedMac; + close ACTUAL; + system "diff -u \"/tmp/expected.txt\" \"/tmp/actual.txt\" > \"/tmp/simplified.diff\""; + + $diffResult = "failed"; + if($verbose) { + print "\n"; + system "cat /tmp/simplified.diff"; + print "failed!!!!!"; + } + } + } + } + + if (dumpToolDidCrash()) { + $result = "crash"; + + printFailureMessageForTest($test, "crashed"); + + my $dir = "$testResultsDirectory/$base"; + $dir =~ s|/([^/]+)$|| or die "Failed to find test name from base\n"; + mkpath $dir; + + deleteExpectedAndActualResults($base); + + open CRASH, ">", "$testResultsDirectory/$base-$errorTag.txt" or die; + print CRASH <ERROR>; + close CRASH; + + recordActualResultsAndDiff($base, $actual); + + closeDumpTool(); + } elsif (!defined $expected) { + if ($verbose) { + print "new " . ($resetResults ? "result" : "test") ."\n"; + $atLineStart = 1; + } + $result = "new"; + + if ($generateNewResults || $resetResults) { + mkpath catfile($expectedDir, dirname($base)) if $testDirectory ne $expectedDir; + open EXPECTED, ">", "$expectedDir/$base-$expectedTag.txt" or die "could not create $expectedDir/$base-$expectedTag.txt\n"; + print EXPECTED $actual; + close EXPECTED; + } + deleteExpectedAndActualResults($base); + unless ($resetResults) { + # Always print the file name for new tests, as they will probably need some manual inspection. + # in verbose mode we already printed the test case, so no need to do it again. + unless ($verbose) { + print "\n" unless $atLineStart; + print "$test -> "; + } + my $resultsDir = catdir($expectedDir, dirname($base)); + print "new (results generated in $resultsDir)\n"; + $atLineStart = 1; + } + } elsif ($actual eq $expected && $diffResult eq "passed") { + if ($verbose) { + print "succeeded\n"; + $atLineStart = 1; + } + $result = "match"; + deleteExpectedAndActualResults($base); + } else { + $result = "mismatch"; + + my $message = $actual eq $expected ? "pixel test failed" : "failed"; + + if ($actual ne $expected && $addPlatformExceptions) { + my $testBase = catfile($testDirectory, $base); + my $expectedBase = catfile($expectedDir, $base); + my $testIsMaximallyPlatformSpecific = $testBase =~ m|^\Q$platformTestDirectory\E/|; + my $expectedResultIsMaximallyPlatformSpecific = $expectedBase =~ m|^\Q$platformTestDirectory\E/|; + if (!$testIsMaximallyPlatformSpecific && !$expectedResultIsMaximallyPlatformSpecific) { + mkpath catfile($platformTestDirectory, dirname($base)); + my $expectedFile = catfile($platformTestDirectory, "$base-$expectedTag.txt"); + open EXPECTED, ">", $expectedFile or die "could not create $expectedFile\n"; + print EXPECTED $actual; + close EXPECTED; + $message .= " (results generated in $platformTestDirectory)"; + } + } + + printFailureMessageForTest($test, $message); + + my $dir = "$testResultsDirectory/$base"; + $dir =~ s|/([^/]+)$|| or die "Failed to find test name from base\n"; + my $testName = $1; + mkpath $dir; + + deleteExpectedAndActualResults($base); + recordActualResultsAndDiff($base, $actual); + + if ($pixelTests && $diffPNG && $diffPNG ne "") { + $imagesPresent{$base} = 1; + + open ACTUAL, ">", "$testResultsDirectory/$base-$actualTag.png" or die; + print ACTUAL $actualPNG; + close ACTUAL; + + open DIFF, ">", "$testResultsDirectory/$base-$diffsTag.png" or die; + print DIFF $diffPNG; + close DIFF; + + copy("$expectedDir/$base-$expectedTag.png", "$testResultsDirectory/$base-$expectedTag.png"); + + open DIFFHTML, ">$testResultsDirectory/$base-$diffsTag.html" or die; + print DIFFHTML "<html>\n"; + print DIFFHTML "<head>\n"; + print DIFFHTML "<title>$base Image Compare</title>\n"; + print DIFFHTML "<script language=\"Javascript\" type=\"text/javascript\">\n"; + print DIFFHTML "var currentImage = 0;\n"; + print DIFFHTML "var imageNames = new Array(\"Actual\", \"Expected\");\n"; + print DIFFHTML "var imagePaths = new Array(\"$testName-$actualTag.png\", \"$testName-$expectedTag.png\");\n"; + if (-f "$testDirectory/$base-w3c.png") { + copy("$testDirectory/$base-w3c.png", "$testResultsDirectory/$base-w3c.png"); + print DIFFHTML "imageNames.push(\"W3C\");\n"; + print DIFFHTML "imagePaths.push(\"$testName-w3c.png\");\n"; + } + print DIFFHTML "function animateImage() {\n"; + print DIFFHTML " var image = document.getElementById(\"animatedImage\");\n"; + print DIFFHTML " var imageText = document.getElementById(\"imageText\");\n"; + print DIFFHTML " image.src = imagePaths[currentImage];\n"; + print DIFFHTML " imageText.innerHTML = imageNames[currentImage] + \" Image\";\n"; + print DIFFHTML " currentImage = (currentImage + 1) % imageNames.length;\n"; + print DIFFHTML " setTimeout('animateImage()',2000);\n"; + print DIFFHTML "}\n"; + print DIFFHTML "</script>\n"; + print DIFFHTML "</head>\n"; + print DIFFHTML "<body onLoad=\"animateImage();\">\n"; + print DIFFHTML "<table>\n"; + if ($diffPercentage) { + print DIFFHTML "<tr>\n"; + print DIFFHTML "<td>Difference between images: <a href=\"$testName-$diffsTag.png\">$diffPercentage%</a></td>\n"; + print DIFFHTML "</tr>\n"; + } + print DIFFHTML "<tr>\n"; + print DIFFHTML "<td><a href=\"" . toURL("$testDirectory/$test") . "\">test file</a></td>\n"; + print DIFFHTML "</tr>\n"; + print DIFFHTML "<tr>\n"; + print DIFFHTML "<td id=\"imageText\" style=\"text-weight: bold;\">Actual Image</td>\n"; + print DIFFHTML "</tr>\n"; + print DIFFHTML "<tr>\n"; + print DIFFHTML "<td><img src=\"$testName-$actualTag.png\" id=\"animatedImage\"></td>\n"; + print DIFFHTML "</tr>\n"; + print DIFFHTML "</table>\n"; + print DIFFHTML "</body>\n"; + print DIFFHTML "</html>\n"; + } + } + + if (($count + 1) % $testsPerDumpTool == 0 || $count == $#tests) { + if ($shouldCheckLeaks) { + my $fileName; + if ($testsPerDumpTool == 1) { + $fileName = "$testResultsDirectory/$base-leaks.txt"; + } else { + $fileName = "$testResultsDirectory/" . fileNameWithNumber($dumpToolName, $leaksOutputFileNumber) . "-leaks.txt"; + } + my $leakCount = countAndPrintLeaks($dumpToolName, $dumpToolPID, $fileName); + $totalLeaks += $leakCount; + $leaksOutputFileNumber++ if ($leakCount); + } + + closeDumpTool(); + } + + $count++; + $counts{$result}++; + push @{$tests{$result}}, $test; + $testType{$test} = $isText; +} +printf "\n%0.2fs total testing time\n", (time - $overallStartTime) . ""; + +!$isDumpToolOpen || die "Failed to close $dumpToolName.\n"; + +closeHTTPD(); + +# Because multiple instances of this script are running concurrently we cannot +# safely delete this symlink. +# system "rm /tmp/LayoutTests"; + +# FIXME: Do we really want to check the image-comparison tool for leaks every time? +if ($shouldCheckLeaks && $pixelTests) { + $totalLeaks += countAndPrintLeaks("ImageDiff", $imageDiffToolPID, "$testResultsDirectory/ImageDiff-leaks.txt"); +} + +if ($totalLeaks) { + if ($mergeDepth) { + parseLeaksandPrintUniqueLeaks(); + } + else { + print "\nWARNING: $totalLeaks total leaks found!\n"; + print "See above for individual leaks results.\n" if ($leaksOutputFileNumber > 2); + } +} + +close IN; +close OUT; +close ERROR; + +if ($report10Slowest) { + print "\n\nThe 10 slowest tests:\n\n"; + my $count = 0; + for my $test (sort slowestcmp keys %durations) { + printf "%0.2f secs: %s\n", $durations{$test}, $test; + last if ++$count == 10; + } +} + +print "\n"; + +if ($skippedOnly && $counts{"match"}) { + print "The following tests are in the Skipped file (" . File::Spec->abs2rel("$platformTestDirectory/Skipped", $testDirectory) . "), but succeeded:\n"; + foreach my $test (@{$tests{"match"}}) { + print " $test\n"; + } +} + +if ($resetResults || ($counts{match} && $counts{match} == $count)) { + print "all $count test cases succeeded\n"; + unlink $testResults; + exit; +} + + +my %text = ( + match => "succeeded", + mismatch => "had incorrect layout", + new => "were new", + crash => "crashed", +); + +for my $type ("match", "mismatch", "new", "crash") { + my $c = $counts{$type}; + if ($c) { + my $t = $text{$type}; + my $message; + if ($c == 1) { + $t =~ s/were/was/; + $message = sprintf "1 test case (%d%%) %s\n", 1 * 100 / $count, $t; + } else { + $message = sprintf "%d test cases (%d%%) %s\n", $c, $c * 100 / $count, $t; + } + $message =~ s-\(0%\)-(<1%)-; + print $message; + } +} + +mkpath $testResultsDirectory; + +open HTML, ">", $testResults or die; +print HTML "<html>\n"; +print HTML "<head>\n"; +print HTML "<title>Layout Test Results</title>\n"; +print HTML "</head>\n"; +print HTML "<body>\n"; + +if ($counts{mismatch}) { + print HTML "<p>Tests where results did not match expected results:</p>\n"; + print HTML "<table>\n"; + for my $test (@{$tests{mismatch}}) { + my $base = stripExtension($test); + print HTML "<tr>\n"; + print HTML "<td><a href=\"" . toURL("$testDirectory/$test") . "\">$test</a></td>\n"; + print HTML htmlForExpectedAndActualResults($base); + if ($pixelTests) { + if ($imagesPresent{$base}) { + print HTML "<td><a href=\"$base-$expectedTag.png\">expected image</a></td>\n"; + print HTML "<td><a href=\"$base-$diffsTag.html\">image diffs</a>\n"; + print HTML "<a href=\"$base-$diffsTag.png\">$imageDifferences{$base}%</a></td>\n"; + } else { + print HTML "<td></td><td></td>\n"; + } + } + print HTML "</tr>\n"; + } + print HTML "</table>\n"; +} + +if ($counts{crash}) { + print HTML "<p>Tests that caused the DumpRenderTree tool to crash:</p>\n"; + print HTML "<table>\n"; + for my $test (@{$tests{crash}}) { + my $base = stripExtension($test); + my $expectedDir = $expectedResultDirectory{$base}; + print HTML "<tr>\n"; + print HTML "<td><a href=\"" . toURL("$testDirectory/$test") . "\">$base</a></td>\n"; + print HTML htmlForExpectedAndActualResults($base); + print HTML "<td><a href=\"$base-$errorTag.txt\">stderr</a></td>\n"; + print HTML "</tr>\n"; + } + print HTML "</table>\n"; +} + +if ($counts{new}) { + print HTML "<p>Tests that had no expected results (probably new):</p>\n"; + print HTML "<table>\n"; + for my $test (@{$tests{new}}) { + my $base = stripExtension($test); + my $expectedDir = $expectedResultDirectory{$base}; + print HTML "<tr>\n"; + print HTML "<td><a href=\"" . toURL("$testDirectory/$test") . "\">$base</a></td>\n"; + print HTML "<td><a href=\"" . toURL("$expectedDir/$base-$expectedTag.txt") . "\">results</a></td>\n"; + if ($pixelTests && -f "$expectedDir/$base-$expectedTag.png") { + print HTML "<td><a href=\"" . toURL("$expectedDir/$base-$expectedTag.png") . "\">image</a></td>\n"; + } + print HTML "</tr>\n"; + } + print HTML "</table>\n"; +} + +print HTML "</body>\n"; +print HTML "</html>\n"; +close HTML; + +if (isQt()) { + system "konqueror", $testResults if $launchSafari; +} elsif (isGtk()) { + system "WebKitTools/Scripts/run-launcher", "--gtk", $configurationOption, $testResults if $launchSafari; +} elsif (isCygwin()) { + system "cygstart", $testResults if $launchSafari; +} else { + system "WebKitTools/Scripts/run-safari", $configurationOption, "-NSOpen", $testResults if $launchSafari; +} + +closeCygpaths() if isCygwin(); + +exit 1; + +sub countAndPrintLeaks($$$) +{ + my ($dumpToolName, $dumpToolPID, $leaksFilePath) = @_; + + print "\n" unless $atLineStart; + $atLineStart = 1; + + # We are excluding the following reported leaks so they don't get in our way when looking for WebKit leaks: + # This allows us ignore known leaks and only be alerted when new leaks occur. Some leaks are in the old + # versions of the system frameworks that are being used by the leaks bots. Even though a leak has been + # fixed, it will be listed here until the bot has been updated with the newer frameworks. + + my @typesToExclude = ( + ); + + my @callStacksToExclude = ( + "Flash_EnforceLocalSecurity" # leaks in Flash plug-in code, rdar://problem/4449747 + ); + + if (isTiger()) { + # Leak list for the version of Tiger used on the build bot. + push @callStacksToExclude, ( + "CFRunLoopRunSpecific \\| malloc_zone_malloc", "CFRunLoopRunSpecific \\| CFAllocatorAllocate ", # leak in CFRunLoopRunSpecific, rdar://problem/4670839 + "CGImageSourceGetPropertiesAtIndex", # leak in ImageIO, rdar://problem/4628809 + "FOGetCoveredUnicodeChars", # leak in ATS, rdar://problem/3943604 + "GetLineDirectionPreference", "InitUnicodeUtilities", # leaks tool falsely reporting leak in CFNotificationCenterAddObserver, rdar://problem/4964790 + "ICCFPrefWrapper::GetPrefDictionary", # leaks in Internet Config. code, rdar://problem/4449794 + "NSHTTPURLProtocol setResponseHeader:", # leak in multipart/mixed-replace handling in Foundation, no Radar, but fixed in Leopard + "NSURLCache cachedResponseForRequest", # leak in CFURL cache, rdar://problem/4768430 + "PCFragPrepareClosureFromFile", # leak in Code Fragment Manager, rdar://problem/3426998 + "WebCore::Selection::toRange", # bug in 'leaks', rdar://problem/4967949 + "WebCore::SubresourceLoader::create", # bug in 'leaks', rdar://problem/4985806 + "_CFPreferencesDomainDeepCopyDictionary", # leak in CFPreferences, rdar://problem/4220786 + "_objc_msgForward", # leak in NSSpellChecker, rdar://problem/4965278 + "gldGetString", # leak in OpenGL, rdar://problem/5013699 + "_setDefaultUserInfoFromURL", # leak in NSHTTPAuthenticator, rdar://problem/5546453 + "SSLHandshake", # leak in SSL, rdar://problem/5546440 + "SecCertificateCreateFromData", # leak in SSL code, rdar://problem/4464397 + ); + push @typesToExclude, ( + "THRD", # bug in 'leaks', rdar://problem/3387783 + "DRHT", # ditto (endian little hate i) + ); + } + + if (isLeopard()) { + # Leak list for the version of Leopard used on the build bot. + push @callStacksToExclude, ( + "CFHTTPMessageAppendBytes", # leak in CFNetwork, rdar://problem/5435912 + "sendDidReceiveDataCallback", # leak in CFNetwork, rdar://problem/5441619 + "_CFHTTPReadStreamReadMark", # leak in CFNetwork, rdar://problem/5441468 + "httpProtocolStart", # leak in CFNetwork, rdar://problem/5468837 + "_CFURLConnectionSendCallbacks", # leak in CFNetwork, rdar://problem/5441600 + "DispatchQTMsg", # leak in Quicktime, PPC only, <rdar://problem/5667132> + "QTMovieContentView createVisualContext", # leak in Quicktime, PPC only, <rdar://problem/5667132> + ); + } + + my $leaksTool = sourceDir() . "/WebKitTools/Scripts/run-leaks"; + my $excludeString = "--exclude-callstack '" . (join "' --exclude-callstack '", @callStacksToExclude) . "'"; + $excludeString .= " --exclude-type '" . (join "' --exclude-type '", @typesToExclude) . "'" if @typesToExclude; + + print " ? checking for leaks in $dumpToolName\n"; + my $leaksOutput = `$leaksTool $excludeString $dumpToolPID`; + my ($count, $bytes) = $leaksOutput =~ /Process $dumpToolPID: (\d+) leaks? for (\d+) total/; + my ($excluded) = $leaksOutput =~ /(\d+) leaks? excluded/; + + my $adjustedCount = $count; + $adjustedCount -= $excluded if $excluded; + + if (!$adjustedCount) { + print " - no leaks found\n"; + unlink $leaksFilePath; + return 0; + } else { + my $dir = $leaksFilePath; + $dir =~ s|/[^/]+$|| or die; + mkpath $dir; + + if ($excluded) { + print " + $adjustedCount leaks ($bytes bytes including $excluded excluded leaks) were found, details in $leaksFilePath\n"; + } else { + print " + $count leaks ($bytes bytes) were found, details in $leaksFilePath\n"; + } + + open LEAKS, ">", $leaksFilePath or die; + print LEAKS $leaksOutput; + close LEAKS; + + push( @leaksFilenames, $leaksFilePath ); + } + + return $adjustedCount; +} + +# Break up a path into the directory (with slash) and base name. +sub splitpath($) +{ + my ($path) = @_; + + my $pathSeparator = "/"; + my $dirname = dirname($path) . $pathSeparator; + $dirname = "" if $dirname eq "." . $pathSeparator; + + return ($dirname, basename($path)); +} + +# Sort first by directory, then by file, so all paths in one directory are grouped +# rather than being interspersed with items from subdirectories. +# Use numericcmp to sort directory and filenames to make order logical. +sub pathcmp($$) +{ + my ($patha, $pathb) = @_; + + my ($dira, $namea) = splitpath($patha); + my ($dirb, $nameb) = splitpath($pathb); + + return numericcmp($dira, $dirb) if $dira ne $dirb; + return numericcmp($namea, $nameb); +} + +# Sort numeric parts of strings as numbers, other parts as strings. +# Makes 1.33 come after 1.3, which is cool. +sub numericcmp($$) +{ + my ($aa, $bb) = @_; + + my @a = split /(\d+)/, $aa; + my @b = split /(\d+)/, $bb; + + # Compare one chunk at a time. + # Each chunk is either all numeric digits, or all not numeric digits. + while (@a && @b) { + my $a = shift @a; + my $b = shift @b; + + # Use numeric comparison if chunks are non-equal numbers. + return $a <=> $b if $a =~ /^\d/ && $b =~ /^\d/ && $a != $b; + + # Use string comparison if chunks are any other kind of non-equal string. + return $a cmp $b if $a ne $b; + } + + # One of the two is now empty; compare lengths for result in this case. + return @a <=> @b; +} + +# Sort slowest tests first. +sub slowestcmp($$) +{ + my ($testa, $testb) = @_; + + my $dura = $durations{$testa}; + my $durb = $durations{$testb}; + return $durb <=> $dura if $dura != $durb; + return pathcmp($testa, $testb); +} + +sub openDumpTool() +{ + return if $isDumpToolOpen; + + # Save some requires variables for the linux environment... + my $homeDir = $ENV{'HOME'}; + my $libraryPath = $ENV{'LD_LIBRARY_PATH'}; + my $dyldLibraryPath = $ENV{'DYLD_LIBRARY_PATH'}; + my $dbusAddress = $ENV{'DBUS_SESSION_BUS_ADDRESS'}; + my $display = $ENV{'DISPLAY'}; + my $testfonts = $ENV{'WEBKIT_TESTFONTS'}; + + my $homeDrive = $ENV{'HOMEDRIVE'}; + my $homePath = $ENV{'HOMEPATH'}; + + local %ENV; + if (isQt() || isGtk()) { + if (defined $display) { + $ENV{DISPLAY} = $display; + } else { + $ENV{DISPLAY} = ":1"; + } + $ENV{'WEBKIT_TESTFONTS'} = $testfonts if defined($testfonts); + $ENV{HOME} = $homeDir; + if (defined $libraryPath) { + $ENV{LD_LIBRARY_PATH} = $libraryPath; + } + if (defined $dyldLibraryPath) { + $ENV{DYLD_LIBRARY_PATH} = $dyldLibraryPath; + } + if (defined $dbusAddress) { + $ENV{DBUS_SESSION_BUS_ADDRESS} = $dbusAddress; + } + } + $ENV{DYLD_FRAMEWORK_PATH} = $productDir; + $ENV{XML_CATALOG_FILES} = ""; # work around missing /etc/catalog <rdar://problem/4292995> + $ENV{MallocStackLogging} = 1 if $shouldCheckLeaks; + $ENV{DYLD_INSERT_LIBRARIES} = "/usr/lib/libgmalloc.dylib" if $guardMalloc; + + if (isCygwin()) { + $ENV{HOMEDRIVE} = $homeDrive; + $ENV{HOMEPATH} = $homePath; + if ($testfonts) { + $ENV{WEBKIT_TESTFONTS} = $testfonts; + } + setPathForRunningWebKitApp(\%ENV) if isCygwin(); + } + + my @args = (); + if ($useValgrind) { + push @args, $dumpTool; + } + push @args, @toolArgs; + if ($useValgrind) { + $dumpTool = "valgrind"; + } + $dumpToolPID = open3(\*OUT, \*IN, \*ERROR, $dumpTool, @args) or die "Failed to start tool: $dumpTool\n"; + $isDumpToolOpen = 1; + $dumpToolCrashed = 0; +} + +sub closeDumpTool() +{ + return if !$isDumpToolOpen; + + close IN; + close OUT; + close ERROR; + waitpid $dumpToolPID, 0; + $isDumpToolOpen = 0; +} + +sub dumpToolDidCrash() +{ + return 1 if $dumpToolCrashed; + return 0 unless $isDumpToolOpen; + + my $pid = waitpid(-1, WNOHANG); + return $pid == $dumpToolPID; +} + +sub openHTTPDIfNeeded() +{ + return if $isHttpdOpen; + + mkdir "/tmp/WebKit"; + + if (-f "/tmp/WebKit/httpd.pid") { + my $oldPid = `cat /tmp/WebKit/httpd.pid`; + chomp $oldPid; + if (0 != kill 0, $oldPid) { + print "\nhttpd is already running: pid $oldPid, killing...\n"; + kill 15, $oldPid; + + my $retryCount = 20; + while ((0 != kill 0, $oldPid) && $retryCount) { + sleep 1; + --$retryCount; + } + + die "Timed out waiting for httpd to quit" unless $retryCount; + } + } + + my $httpdPath = "/usr/sbin/httpd"; + my $httpdConfig; + if (isCygwin()) { + my $windowsConfDirectory = "$testDirectory/http/conf/"; + unless (-x "/usr/lib/apache/libphp4.dll") { + copy("$windowsConfDirectory/libphp4.dll", "/usr/lib/apache/libphp4.dll"); + chmod(0755, "/usr/lib/apache/libphp4.dll"); + } + $httpdConfig = "$windowsConfDirectory/cygwin-httpd.conf"; + } elsif (isDebianBased()) { + $httpdPath = "/usr/sbin/apache2"; + $httpdConfig = "$testDirectory/http/conf/apache2-debian-httpd.conf"; + } else { + $httpdConfig = "$testDirectory/http/conf/httpd.conf"; + $httpdConfig = "$testDirectory/http/conf/apache2-httpd.conf" if `$httpdPath -v` =~ m|Apache/2|; + } + my $documentRoot = "$testDirectory/http/tests"; + my $typesConfig = "$testDirectory/http/conf/mime.types"; + my $listen = "127.0.0.1:$httpdPort"; + my $absTestResultsDirectory = File::Spec->rel2abs(glob $testResultsDirectory); + my $sslCertificate = "$testDirectory/http/conf/webkit-httpd.pem"; + + mkpath $absTestResultsDirectory; + + my @args = ( + "-f", "$httpdConfig", + "-C", "DocumentRoot \"$documentRoot\"", + "-C", "Listen $listen", + "-c", "TypesConfig \"$typesConfig\"", + "-c", "CustomLog \"$absTestResultsDirectory/access_log.txt\" common", + "-c", "ErrorLog \"$absTestResultsDirectory/error_log.txt\"", + # Apache wouldn't run CGIs with permissions==700 otherwise + "-c", "User \"#$<\"" + ); + + # FIXME: Enable this on Windows once <rdar://problem/5345985> is fixed + push(@args, "-c", "SSLCertificateFile \"$sslCertificate\"") unless isCygwin(); + + open2(\*HTTPDIN, \*HTTPDOUT, $httpdPath, @args); + + my $retryCount = 20; + while (system("/usr/bin/curl -q --silent --stderr - --output /dev/null $listen") && $retryCount) { + sleep 1; + --$retryCount; + } + + die "Timed out waiting for httpd to start" unless $retryCount; + + $isHttpdOpen = 1; +} + +sub closeHTTPD() +{ + return if !$isHttpdOpen; + + close HTTPDIN; + close HTTPDOUT; + + kill 15, `cat /tmp/WebKit/httpd.pid` if -f "/tmp/WebKit/httpd.pid"; + + $isHttpdOpen = 0; +} + +sub fileNameWithNumber($$) +{ + my ($base, $number) = @_; + return "$base$number" if ($number > 1); + return $base; +} + +sub processIgnoreTests($) { + my @ignoreList = split(/\s*,\s*/, shift); + my $addIgnoredDirectories = sub { + return () if exists $ignoredLocalDirectories{basename($File::Find::dir)}; + $ignoredDirectories{File::Spec->abs2rel($File::Find::dir, $testDirectory)} = 1; + return @_; + }; + foreach my $item (@ignoreList) { + my $path = catfile($testDirectory, $item); + if (-d $path) { + $ignoredDirectories{$item} = 1; + find({ preprocess => $addIgnoredDirectories, wanted => sub {} }, $path); + } + elsif (-f $path) { + $ignoredFiles{$item} = 1; + } + else { + print "ignoring '$item' on ignore-tests list\n"; + } + } +} + +sub stripExtension($) +{ + my ($test) = @_; + + $test =~ s/\.[a-zA-Z]+$//; + return $test; +} + +sub isTextOnlyTest($) +{ + my ($actual) = @_; + my $isText; + if ($actual =~ /^layer at/ms) { + $isText = 0; + } else { + $isText = 1; + } + return $isText; +} + +sub expectedDirectoryForTest($;$;$) +{ + my ($base, $isText, $isPixelTest) = @_; + + my @directories = @platformHierarchy; + push @directories, map { catdir($platformBaseDirectory, $_) } qw(mac-leopard mac) if isCygwin(); + push @directories, $expectedDirectory; + + # If we already have expected results, just return their location. + if ($isPixelTest) { + foreach my $directory (@directories) { + return $directory if (-f "$directory/$base-$expectedTag.png"); + } + } else { + foreach my $directory (@directories) { + return $directory if (-f "$directory/$base-$expectedTag.txt"); + } + } + + # For platform-specific tests, the results should go right next to the test itself. + # Note: The return value of this subroutine will be concatenated with $base + # to determine the location of the new results, so returning $expectedDirectory + # will put the results right next to the test. + # FIXME: We want to allow platform/mac tests with platform/mac-leopard results, + # so this needs to be enhanced. + return $expectedDirectory if $base =~ /^platform/; + + # For cross-platform tests, text-only results should go in the cross-platform directory, + # while render tree dumps should go in the least-specific platform directory. + return $isText ? $expectedDirectory : $platformHierarchy[$#platformHierarchy]; +} + +sub printFailureMessageForTest($$) +{ + my ($test, $description) = @_; + + unless ($verbose) { + print "\n" unless $atLineStart; + print "$test -> "; + } + print "$description\n"; + $atLineStart = 1; +} + +my %cygpaths = (); + +sub openCygpathIfNeeded($) +{ + my ($options) = @_; + + return unless isCygwin(); + return $cygpaths{$options} if $cygpaths{$options} && $cygpaths{$options}->{"open"}; + + local (*CYGPATHIN, *CYGPATHOUT); + my $pid = open2(\*CYGPATHIN, \*CYGPATHOUT, "cygpath -f - $options"); + my $cygpath = { + "pid" => $pid, + "in" => *CYGPATHIN, + "out" => *CYGPATHOUT, + "open" => 1 + }; + + $cygpaths{$options} = $cygpath; + + return $cygpath; +} + +sub closeCygpaths() +{ + return unless isCygwin(); + + foreach my $cygpath (values(%cygpaths)) { + close $cygpath->{"in"}; + close $cygpath->{"out"}; + waitpid($cygpath->{"pid"}, 0); + $cygpath->{"open"} = 0; + + } +} + +sub convertPathUsingCygpath($$) +{ + my ($path, $options) = @_; + + my $cygpath = openCygpathIfNeeded($options); + local *inFH = $cygpath->{"in"}; + local *outFH = $cygpath->{"out"}; + print outFH $path . "\n"; + chomp(my $convertedPath = <inFH>); + return $convertedPath; +} + +sub toWindowsPath($) +{ + my ($path) = @_; + return unless isCygwin(); + + return convertPathUsingCygpath($path, "-w"); +} + +sub toURL($) +{ + my ($path) = @_; + return $path unless isCygwin(); + + return "file:///" . convertPathUsingCygpath($path, "-m"); +} + +sub validateSkippedArg($$;$) +{ + my ($option, $value, $value2) = @_; + my %validSkippedValues = map { $_ => 1 } qw(default ignore only); + $value = lc($value); + die "Invalid argument '" . $value . "' for option $option" unless $validSkippedValues{$value}; + $treatSkipped = $value; +} + +sub htmlForExpectedAndActualResults($) +{ + my ($base) = @_; + + return "<td></td><td></td><td></td>\n" unless -s "$testResultsDirectory/$base-$diffsTag.txt"; + + return "<td><a href=\"$base-$expectedTag.txt\">expected</a></td>\n" + . "<td><a href=\"$base-$actualTag.txt\">actual</a></td>\n" + . "<td><a href=\"$base-$diffsTag.txt\">diffs</a></td>\n"; +} + +sub deleteExpectedAndActualResults($) +{ + my ($base) = @_; + + unlink "$testResultsDirectory/$base-$actualTag.txt"; + unlink "$testResultsDirectory/$base-$diffsTag.txt"; + unlink "$testResultsDirectory/$base-$errorTag.txt"; +} + +sub recordActualResultsAndDiff($$) +{ + my ($base, $actual) = @_; + + return unless length($actual); + + open ACTUAL, ">", "$testResultsDirectory/$base-$actualTag.txt" or die "Couldn't open actual results file for $base"; + print ACTUAL $actual; + close ACTUAL; + + my $expectedDir = $expectedResultDirectory{$base}; + copy("$expectedDir/$base-$expectedTag.txt", "$testResultsDirectory/$base-$expectedTag.txt"); + + system "diff -u \"$testResultsDirectory/$base-$expectedTag.txt\" \"$testResultsDirectory/$base-$actualTag.txt\" > \"$testResultsDirectory/$base-$diffsTag.txt\""; +} + +sub buildPlatformHierarchy() +{ + mkpath($platformTestDirectory) if ($platform eq "undefined" && !-d "$platformTestDirectory"); + + my @platforms = split('-', $platform); + my @hierarchy; + for (my $i=0; $i < @platforms; $i++) { + my $scoped = catdir($platformBaseDirectory, join('-', @platforms[0..($#platforms - $i)])); + push(@hierarchy, $scoped) if (-d $scoped); + } + + return @hierarchy; +} + +sub epiloguesAndPrologues($$) { + my ($lastDirectory, $directory) = @_; + my @lastComponents = split('/', $lastDirectory); + my @components = split('/', $directory); + + while (@lastComponents) { + if ($lastComponents[0] ne $components[0]) { + last; + } + shift @components; + shift @lastComponents; + } + + my @result; + my $leaving = $lastDirectory; + foreach (@lastComponents) { + my $epilogue = $leaving . "/resources/run-webkit-tests-epilogue.html"; + foreach (@platformHierarchy) { + push @result, catdir($_, $epilogue) if (stat(catdir($_, $epilogue))); + } + push @result, catdir($testDirectory, $epilogue) if (stat(catdir($testDirectory, $epilogue))); + $leaving =~ s|(^\|/)[^/]+$||; + } + + my $entering = $leaving; + foreach (@components) { + $entering .= '/' . $_; + my $prologue = $entering . "/resources/run-webkit-tests-prologue.html"; + push @result, catdir($testDirectory, $prologue) if (stat(catdir($testDirectory, $prologue))); + foreach (reverse @platformHierarchy) { + push @result, catdir($_, $prologue) if (stat(catdir($_, $prologue))); + } + } + return @result; +} + +sub parseLeaksandPrintUniqueLeaks() { + return unless @leaksFilenames; + + my $mergedFilenames = join " ", @leaksFilenames; + my $parseMallocHistoryTool = sourceDir() . "/WebKitTools/Scripts/parse-malloc-history"; + + open MERGED_LEAKS, "cat $mergedFilenames | $parseMallocHistoryTool --merge-depth $mergeDepth - |" ; + my @leakLines = <MERGED_LEAKS>; + close MERGED_LEAKS; + + my $uniqueLeakCount = 0; + my $totalBytes; + foreach my $line (@leakLines) { + ++$uniqueLeakCount if ($line =~ /^(\d*)\scalls/); + $totalBytes = $1 if $line =~ /^total\:\s(.*)\s\(/; + } + + print "\nWARNING: $totalLeaks total leaks found for a total of $totalBytes!\n"; + print "WARNING: $uniqueLeakCount unique leaks found!\n"; + print "See above for individual leaks results.\n" if ($leaksOutputFileNumber > 2); + +} diff --git a/WebKitTools/Scripts/set-webkit-configuration b/WebKitTools/Scripts/set-webkit-configuration new file mode 100755 index 0000000..8735140 --- /dev/null +++ b/WebKitTools/Scripts/set-webkit-configuration @@ -0,0 +1,41 @@ +#!/usr/bin/perl -w + +# Copyright (C) 2005 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. + +use strict; +use FindBin; +use lib $FindBin::Bin; +use webkitdirs; + +my $configuration = passedConfiguration(); +die "Please specify either --debug or --release.\n" if !$configuration; + +my $baseProductDir = baseProductDir(); +system "mkdir", "-p", "$baseProductDir"; +open CONFIGURATION, ">", "$baseProductDir/Configuration" or die; +print CONFIGURATION $configuration; +close CONFIGURATION; diff --git a/WebKitTools/Scripts/sort-Xcode-project-file b/WebKitTools/Scripts/sort-Xcode-project-file new file mode 100755 index 0000000..e9b7a56 --- /dev/null +++ b/WebKitTools/Scripts/sort-Xcode-project-file @@ -0,0 +1,115 @@ +#!/usr/bin/perl -w + +# Copyright (C) 2007 Apple 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. + +# Script to sort "files=(...);" sections in Xcode project.pbxproj files + +use strict; + +use File::Basename; +use File::Temp; +use Getopt::Long; + +sub sortByFileName($$); + +my $printWarnings = 1; +my $showHelp; + +my $getOptionsResult = GetOptions( + 'h|help' => \$showHelp, + 'w|warnings!' => \$printWarnings, +); + +if (scalar(@ARGV) == 0) { + print STDERR "ERROR: No Xcode project files (project.pbxproj) listed on command-line.\n"; + undef $getOptionsResult; +} + +if (!$getOptionsResult || $showHelp) { + print STDERR <<__END__; +Usage: @{[ basename($0) ]} [options] path/to/project.pbxproj [path/to/project.pbxproj ...] + -h|--help show this help message + -w|--[no-]warnings show or suppress warnings (default: show warnings) +__END__ + exit 1; +} + +for my $projectFile (@ARGV) { + if (basename($projectFile) ne "project.pbxproj") { + print STDERR "WARNING: Not an Xcode project file: $projectFile\n" if $printWarnings; + next; + } + + my $OUT = new File::Temp( + DIR => dirname($projectFile), + TEMPLATE => basename($projectFile) . "-XXXXXXXX", + UNLINK => 0, + ); + my $tempFileName = $OUT->filename(); + + # Clean up temp file in case of die() + $SIG{__DIE__} = sub { + close(IN); + close($OUT); + unlink($tempFileName); + }; + + open(IN, "< $projectFile") || die "Could not open $projectFile: $!"; + while (my $line = <IN>) { + if ($line =~ /^(\s*)files = \(\s*$/) { + print $OUT $line; + my $endMarker = $1 . ");"; + my @files; + while (my $fileLine = <IN>) { + if ($fileLine =~ /^\Q$endMarker\E\s*$/) { + $endMarker = $fileLine; + last; + } + push @files, $fileLine; + } + print $OUT sort sortByFileName @files; + print $OUT $endMarker; + } else { + print $OUT $line; + } + } + close(IN); + close($OUT); + + unlink($projectFile) || die "Could not delete $projectFile: $!"; + rename($tempFileName, $projectFile) || die "Could not rename $tempFileName to $projectFile: $!"; +} + +exit 0; + +sub sortByFileName($$) +{ + my ($a, $b) = @_; + my $aFileName = $1 if $a =~ /^\s*[A-Z0-9]{24} \/\* (.+) in /; + my $bFileName = $1 if $b =~ /^\s*[A-Z0-9]{24} \/\* (.+) in /; + return $aFileName cmp $bFileName; +} diff --git a/WebKitTools/Scripts/split-file-by-class b/WebKitTools/Scripts/split-file-by-class new file mode 100755 index 0000000..b6aeb68 --- /dev/null +++ b/WebKitTools/Scripts/split-file-by-class @@ -0,0 +1,159 @@ +#!/usr/bin/perl -w + +# Copyright (C) 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. + +# Used for splitting a single file into multiple class files +# Usage: split-class <header file> + +use strict; +use File::Copy; +use FindBin; +use lib $FindBin::Bin; +use SpacingHeuristics; + + +for my $filename (@ARGV) { + + $filename =~ m/^(\w+)\.h$/ or die "Command line args must be .h files.\n"; + my $basename = $1; + + open(OLDFILE, "<", $filename) or die "File does not exist: $filename\n"; + print "Splitting class $filename.{h,cpp}:\n"; + + my $currentClassName = ""; + my $classIndent = ""; + my $fileContent = ""; + my %classDefs = (); + while (my $line = <OLDFILE>) { + if ($currentClassName) { + $classDefs{$currentClassName} .= $line; + if ($line =~ /^$classIndent};\s*$/) { + $currentClassName = ""; + } + } else { + if ($line =~ /^(\s*)class\s+(\w+)\s+[^;]*$/) { + $classIndent = $1; + $currentClassName = $2; + $classDefs{$currentClassName} .= $line; + $fileContent .= "###CLASS###$currentClassName\n"; + } else { + $fileContent .= $line; + } + } + } + close(OLDFILE); + + if (scalar(keys(%classDefs)) == 1) { # degenerate case + my ($classname) = keys(%classDefs); + if (!($classname eq $basename)) { + print "Skipping $filename, already correctly named.\n"; + } else { + print "$filename only includes one class, renaming to $classname.h\n"; + system("svn rm --force $classname.h") if (-r "$classname.h"); + system "svn mv $basename.h $classname.h"; + } + } else { + while (my ($classname, $classDef) = each(%classDefs)) { + if (($classname eq $basename)) { + print "Skipping $filename, already correctly named.\n"; + } else { + print "Using SVN to copy $basename.{h,cpp} to $classname.{h,cpp}\n"; + + system("svn rm --force $classname.h") if (-r "$classname.h"); + system "svn cp $basename.h $classname.h"; + + system("svn rm --force $classname.cpp") if (-r "$classname.cpp"); + system "svn cp $basename.cpp $classname.cpp"; + } + + print "Fixing $classname.h as much as possible.\n"; + open(NEWHEADER, ">", "$classname.h") or die "File does not exist: $filename\n"; + my @lines = split("\n", $fileContent); + foreach my $line (@lines) { + if ($line =~ /^###CLASS###(\w+)/) { + if ($1 eq $classname) { + print NEWHEADER $classDef . "\n"; + } + } else { + print NEWHEADER $line . "\n"; + } + } + close(NEWHEADER); + + print "Fixing $classname.cpp as much as possible.\n"; + copy("$classname.cpp", "$classname.cpp.original"); + open(OLDCPP, "<", "$classname.cpp.original") or die "Failed to copy file for reading: $filename\n"; + open(NEWCPP, ">", "$classname.cpp") or die "File does not exist: $filename\n"; + my $insideMemberFunction = 0; + my $shouldPrintMemberFunction = 0; + resetSpacingHeuristics(); + while (my $line = <OLDCPP>) { + if ($insideMemberFunction) { + if ($shouldPrintMemberFunction) { + print NEWCPP $line; + #setPreviousAllowedLine($line); + } else { + ignoringLine($line); + } + if ($line =~ /^}\s*$/) { + $insideMemberFunction = 0; + } + } elsif ($line =~ /$filename/) { + print NEWCPP "#include \"config.h\"\n"; + print NEWCPP "#include \"$classname.h\"\n"; + } elsif ($line =~ /#include/ || $line =~ /#import/) { + next; # skip includes, they're generally wrong or unecessary anyway. + } else { + $line =~ s/DOM:://; + $line =~ s/khtml:://; + $line =~ s/namespace DOM/namespace WebCore/; + $line =~ s/namespace khtml/namespace WebCore/; + + if ($line =~ /^(.*?\s+)?(\*|&)?(\w+)::(~)?\w+\s*\(/) { + $insideMemberFunction = 1; + $shouldPrintMemberFunction = ($classname eq $3); + if ($shouldPrintMemberFunction) { + printPendingEmptyLines(*NEWCPP, $line); + print NEWCPP $line; + } + } else { + next if isOnlyWhiteSpace($line); + next if ($line =~ m/------------/); + printPendingEmptyLines(*NEWCPP, $line); + applySpacingHeuristicsAndPrint(*NEWCPP, $line); + } + } + } + close(NEWCPP); + close(OLDCPP); + unlink("$classname.cpp.original"); + } + } + + print "Opening new files...\n"; + system("open " . join(".* ", keys(%classDefs)) . ".*"); +}
\ No newline at end of file diff --git a/WebKitTools/Scripts/sunspider-compare-results b/WebKitTools/Scripts/sunspider-compare-results new file mode 100755 index 0000000..cf18aae --- /dev/null +++ b/WebKitTools/Scripts/sunspider-compare-results @@ -0,0 +1,101 @@ +#!/usr/bin/perl -w + +# Copyright (C) 2007 Apple Inc. All rights reserved. +# Copyright (C) 2007 Eric Seidel <eric@webkit.org> +# +# 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. +# +# THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 COMPUTER, INC. OR +# 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. + +use strict; +use File::Spec; +use FindBin; +use Getopt::Long qw(:config pass_through); +use lib $FindBin::Bin; +use webkitdirs; +use POSIX; + +# determine configuration, but default to "Release" instead of last-used configuration to match run-sunspider +setConfiguration("Release"); +setConfiguration(); +my $configuration = configuration(); + +my $root; +my $showHelp = 0; + +my $programName = basename($0); +my $usage = <<EOF; +Usage: $programName [options] FILE FILE + --help Show this help message + --root Path to root tools build +EOF + +GetOptions('root=s' => sub { my ($argName, $value); setConfigurationProductDir(Cwd::abs_path($value)); }, + 'help' => \$showHelp); + +if ($showHelp) { + print STDERR $usage; + exit 1; +} + +@ARGV = map { File::Spec->rel2abs($_) } @ARGV; + +sub buildTestKJS +{ + if (!defined($root)){ + chdirWebKit(); + my $buildResult = system "WebKitTools/Scripts/build-testkjs", "--" . $configuration; + if ($buildResult) { + print STDERR "Compiling testkjs failed!\n"; + exit WEXITSTATUS($buildResult); + } + } +} + +sub setupEnvironmentForExecution($) +{ + my ($productDir) = @_; + print "Starting sunspider-compare-results with DYLD_FRAMEWORK_PATH set to point to built JavaScriptCore in $productDir.\n"; + $ENV{DYLD_FRAMEWORK_PATH} = $productDir; + # FIXME: Other platforms may wish to augment this method to use LD_LIBRARY_PATH, etc. +} + +sub testKJSPath($) +{ + my ($productDir) = @_; + my $testkjsName = "testkjs"; + $testkjsName .= "_debug" if (isCygwin() && ($configuration eq "Debug")); + return "$productDir/$testkjsName"; +} + +buildTestKJS(); + +chdirWebKit(); +chdir("SunSpider"); + +my $productDir = productDir(); +# FIXME: This hack should be pushed down into productDir() +$productDir .= "/JavaScriptCore" if (isQt() or isGtk()); + +setupEnvironmentForExecution($productDir); +my @args = ("--shell", testKJSPath($productDir)); +# This code could be removed if we chose to pass extra args to sunspider instead of Xcode + +exec "./sunspider-compare-results", @args, @ARGV; diff --git a/WebKitTools/Scripts/svn-apply b/WebKitTools/Scripts/svn-apply new file mode 100755 index 0000000..5845917 --- /dev/null +++ b/WebKitTools/Scripts/svn-apply @@ -0,0 +1,438 @@ +#!/usr/bin/perl -w + +# Copyright (C) 2005, 2006, 2007 Apple 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 with logic to handle local changes). +# Handles added directories (does a svn add). +# Handles removed files (does a svn rm with logic to handle local changes). +# Handles removed directories--those with no more files or directories left in them +# (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, and the entry date is set in +# the patch to today's date using $changeLogTimeZone. +# Handles binary files (requires patches made by svn-create-patch). +# Handles copied and moved files (requires patches made by svn-create-patch). +# Handles git-diff patches (without binary changes) created at the top-level directory +# +# Missing features: +# +# Handle property changes. +# Handle copied and moved directories (would require 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 exclude ChangeLog). +# Handle git-diff patches with binary changes + +use strict; +use warnings; + +use Cwd; +use Digest::MD5; +use File::Basename; +use File::Spec; +use Getopt::Long; +use MIME::Base64; +use POSIX qw(strftime); + +sub addDirectoriesIfNeeded($); +sub applyPatch($$;$); +sub checksum($); +sub fixChangeLogPatch($); +sub gitdiff2svndiff($); +sub handleBinaryChange($$); +sub isDirectoryEmptyForRemoval($); +sub patch($); +sub removeDirectoriesIfNeeded(); +sub setChangeLogDate($); +sub svnStatus($); + +# Project time zone for Cupertino, CA, US +my $changeLogTimeZone = "PST8PDT"; + +my $merge = 0; +my $showHelp = 0; +if (!GetOptions("merge!" => \$merge, "help!" => \$showHelp) || $showHelp) { + print STDERR basename($0) . " [-h|--help] [-m|--merge] patch1 [patch2 ...]\n"; + exit 1; +} + +my %removeDirectoryIgnoreList = ( + '.' => 1, + '..' => 1, + '.svn' => 1, + '_svn' => 1, +); + +my %checkedDirectories; +my %copiedFiles; +my @patches; +my %versions; + +my $copiedFromPath; +my $filter; +my $indexPath; +my $patch; +while (<>) { + s/\r//g; + chomp; + if (!defined($indexPath) && m#^diff --git a/#) { + $filter = \&gitdiff2svndiff; + } + $_ = &$filter($_) if $filter; + if (/^Index: (.+)/) { + $indexPath = $1; + if ($patch) { + if (!$copiedFromPath) { + push @patches, $patch; + } + $copiedFromPath = ""; + $patch = ""; + } + } + if ($indexPath) { + # Fix paths on diff, ---, and +++ lines to match preceding Index: line. + s/\S+$/$indexPath/ if /^diff/; + s/^--- \S+/--- $indexPath/; + if (/^--- .+\(from (\S+):(\d+)\)$/) { + $copiedFromPath = $1; + $copiedFiles{$indexPath} = $copiedFromPath; + $versions{$copiedFromPath} = $2 if ($2 != 0); + } + elsif (/^--- .+\(revision (\d+)\)$/) { + $versions{$indexPath} = $1 if ($1 != 0); + } + if (s/^\+\+\+ \S+/+++ $indexPath/) { + $indexPath = ""; + } + } + $patch .= $_; + $patch .= "\n"; +} + +if ($patch && !$copiedFromPath) { + push @patches, $patch; +} + +if ($merge) { + for my $file (sort keys %versions) { + print "Getting version $versions{$file} of $file\n"; + system "svn", "update", "-r", $versions{$file}, $file; + } +} + +# 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; +} + +for $patch (@patches) { + patch($patch); +} + +removeDirectoriesIfNeeded(); + +exit 0; + +sub addDirectoriesIfNeeded($) +{ + my ($path) = @_; + my @dirs = File::Spec->splitdir($path); + my $dir = "."; + while (scalar @dirs) { + $dir = File::Spec->catdir($dir, shift @dirs); + 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; + $checkedDirectories{$dir} = 1; + } + elsif (-d $dir) { + my $svnOutput = svnStatus($dir); + if ($svnOutput && $svnOutput =~ m#\?\s+$dir\n#) { + system "svn", "add", $dir; + } + $checkedDirectories{$dir} = 1; + } + else { + die "'$dir' is not a directory"; + } + } +} + +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 checksum($) +{ + my $file = shift; + open(FILE, $file) or die "Can't open '$file': $!"; + binmode(FILE); + my $checksum = Digest::MD5->new->addfile(*FILE)->hexdigest(); + close(FILE); + return $checksum; +} + +sub fixChangeLogPatch($) +{ + my $patch = shift; + my $contextLineCount = 3; + + return $patch if $patch !~ /\n@@ -1,(\d+) \+1,(\d+) @@\n( .*\n)+(\+.*\n)+( .*\n){$contextLineCount}$/m; + my ($oldLineCount, $newLineCount) = ($1, $2); + return $patch if $oldLineCount <= $contextLineCount; + + # The diff(1) command is greedy when matching lines, so a new ChangeLog entry will + # have lines of context at the top of a patch when the existing entry has the same + # date and author as the new entry. This nifty loop alters a ChangeLog patch so + # that the added lines ("+") in the patch always start at the beginning of the + # patch and there are no initial lines of context. + my $newPatch; + my $lineCountInState = 0; + my $oldContentLineCountReduction = $oldLineCount - $contextLineCount; + my $newContentLineCountWithoutContext = $newLineCount - $oldLineCount - $oldContentLineCountReduction; + my ($stateHeader, $statePreContext, $stateNewChanges, $statePostContext) = (1..4); + my $state = $stateHeader; + foreach my $line (split(/\n/, $patch)) { + $lineCountInState++; + if ($state == $stateHeader && $line =~ /^@@ -1,$oldLineCount \+1,$newLineCount @\@$/) { + $line = "@@ -1,$contextLineCount +1," . ($newLineCount - $oldContentLineCountReduction) . " @@"; + $lineCountInState = 0; + $state = $statePreContext; + } elsif ($state == $statePreContext && substr($line, 0, 1) eq " ") { + $line = "+" . substr($line, 1); + if ($lineCountInState == $oldContentLineCountReduction) { + $lineCountInState = 0; + $state = $stateNewChanges; + } + } elsif ($state == $stateNewChanges && substr($line, 0, 1) eq "+") { + # No changes to these lines + if ($lineCountInState == $newContentLineCountWithoutContext) { + $lineCountInState = 0; + $state = $statePostContext; + } + } elsif ($state == $statePostContext) { + if (substr($line, 0, 1) eq "+" && $lineCountInState <= $oldContentLineCountReduction) { + $line = " " . substr($line, 1); + } elsif ($lineCountInState > $contextLineCount && substr($line, 0, 1) eq " ") { + next; # Discard + } + } + $newPatch .= $line . "\n"; + } + + return $newPatch; +} + +sub gitdiff2svndiff($) +{ + $_ = shift @_; + if (m#^diff --git a/(.+) b/(.+)#) { + return "Index: $1"; + } elsif (m/^new file.*/) { + return ""; + } elsif (m#^index [0-9a-f]{7}\.\.[0-9a-f]{7} [0-9]{6}#) { + return "==================================================================="; + } elsif (m#^--- a/(.+)#) { + return "--- $1"; + } elsif (m#^\+\+\+ b/(.+)#) { + return "+++ $1"; + } + return $_; +} + +sub handleBinaryChange($$) +{ + my ($fullPath, $contents) = @_; + if ($contents =~ m#((\n[A-Za-z0-9+/]{76})+\n[A-Za-z0-9+/=]{4,76}\n)#) { + # Addition or Modification + open FILE, ">", $fullPath or die; + print FILE decode_base64($1); + close FILE; + my $svnOutput = svnStatus($fullPath); + if ($svnOutput && substr($svnOutput, 0, 1) eq "?") { + # Addition + system "svn", "add", $fullPath; + } else { + # Modification + print $svnOutput if $svnOutput; + } + } else { + # Deletion + system "svn", "rm", $fullPath; + } +} + +sub isDirectoryEmptyForRemoval($) +{ + my ($dir) = @_; + my $directoryIsEmpty = 1; + opendir DIR, $dir or die "Could not open '$dir' to list files: $?"; + for (my $item = readdir DIR; $item && $directoryIsEmpty; $item = readdir DIR) { + next if exists $removeDirectoryIgnoreList{$item}; + 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"; + $directoryIsEmpty = 0; + } + } + closedir DIR; + return $directoryIsEmpty; +} + +sub patch($) +{ + my ($patch) = @_; + return if !$patch; + + unless ($patch =~ m|^Index: ([^\n]+)|) { + my $separator = '-' x 67; + warn "Failed to find 'Index:' in:\n$separator\n$patch\n$separator\n"; + return; + } + my $fullPath = $1; + + my $deletion = 0; + my $addition = 0; + my $isBinary = 0; + + $addition = 1 if $patch =~ /\n--- .+\(revision 0\)\n/; + $deletion = 1 if $patch =~ /\n@@ .* \+0,0 @@/; + $isBinary = 1 if $patch =~ /\nCannot display: file marked as a binary type\./; + + if (!$addition && !$deletion && !$isBinary) { + # Standard patch, patch tool can handle this. + if (basename($fullPath) eq "ChangeLog") { + my $changeLogDotOrigExisted = -f "${fullPath}.orig"; + applyPatch(setChangeLogDate(fixChangeLogPatch($patch)), $fullPath, ["--fuzz=3"]); + unlink("${fullPath}.orig") if (! $changeLogDotOrigExisted); + } else { + applyPatch($patch, $fullPath); + } + } else { + # Either a deletion, an addition or a binary change. + + addDirectoriesIfNeeded(dirname($fullPath)); + + if ($isBinary) { + # Binary change + handleBinaryChange($fullPath, $patch); + } elsif ($deletion) { + # Deletion + applyPatch($patch, $fullPath, ["--force"]); + system "svn", "rm", "--force", $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"; + } + } +} + +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; + } + } +} + +sub setChangeLogDate($) +{ + my $patch = shift; + my $savedTimeZone = $ENV{'TZ'}; + # Set TZ temporarily so that localtime() is in that time zone + $ENV{'TZ'} = $changeLogTimeZone; + my $newDate = strftime("%Y-%m-%d", localtime()); + if (defined $savedTimeZone) { + $ENV{'TZ'} = $savedTimeZone; + } else { + delete $ENV{'TZ'}; + } + $patch =~ s/(\n\+)\d{4}-[^-]{2}-[^-]{2}( )/$1$newDate$2/; + return $patch; +} + +sub svnStatus($) +{ + my ($fullPath) = @_; + my $svnStatus; + open SVN, "svn status --non-interactive --non-recursive '$fullPath' |" or die; + if (-d $fullPath) { + # When running "svn stat" on a directory, we can't assume that only one + # status will be returned (since any files with a status below the + # directory will be returned), and we can't assume that the directory will + # be first (since any files with unknown status will be listed first). + my $normalizedFullPath = File::Spec->catdir(File::Spec->splitdir($fullPath)); + while (<SVN>) { + chomp; + my $normalizedStatPath = File::Spec->catdir(File::Spec->splitdir(substr($_, 7))); + if ($normalizedFullPath eq $normalizedStatPath) { + $svnStatus = $_; + last; + } + } + # Read the rest of the svn command output to avoid a broken pipe warning. + local $/ = undef; + <SVN>; + } + else { + # Files will have only one status returned. + $svnStatus = <SVN>; + } + close SVN; + return $svnStatus; +} diff --git a/WebKitTools/Scripts/svn-create-patch b/WebKitTools/Scripts/svn-create-patch new file mode 100755 index 0000000..365737a --- /dev/null +++ b/WebKitTools/Scripts/svn-create-patch @@ -0,0 +1,442 @@ +#!/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. + +# Extended "svn diff" script for WebKit Open Source Project, used to make patches. + +# Differences from standard "svn diff": +# +# Uses the real diff, not svn's built-in diff. +# Always passes "-p" to diff so it will try to include function names. +# Handles binary files (encoded as a base64 chunk of text). +# Sorts the diffs alphabetically by text files, then binary files. +# Handles copied and moved files. +# +# Missing features: +# +# Handle copied and moved directories. + +use strict; +use warnings; + +use Config; +use Cwd; +use File::Basename; +use File::Spec; +use File::stat; +use Getopt::Long; +use MIME::Base64; +use POSIX qw(:errno_h); +use Time::gmtime; + +sub binarycmp($$); +sub canonicalizePath($); +sub findBaseUrl($); +sub findMimeType($;$); +sub findModificationType($); +sub findSourceFileAndRevision($); +sub fixChangeLogPatch($); +sub generateDiff($); +sub generateFileList($\%); +sub isBinaryMimeType($); +sub manufacturePatchForAdditionWithHistory($); +sub numericcmp($$); +sub outputBinaryContent($); +sub patchpathcmp($$); +sub pathcmp($$); +sub processPaths(\@); +sub splitpath($); +sub testfilecmp($$); + +$ENV{'LC_ALL'} = 'C'; + +my $showHelp; + +my $result = GetOptions( + "help" => \$showHelp, +); +if (!$result || $showHelp) { + print STDERR basename($0) . " [-h|--help] [svndir1 [svndir2 ...]]\n"; + exit 1; +} + +# Sort the diffs for easier reviewing. +my %paths = processPaths(@ARGV); + +# Generate a list of files requiring diffs. +my %diffFiles; +for my $path (keys %paths) { + generateFileList($path, %diffFiles); +} + +# Generate the diffs, in a order chosen for easy reviewing. +for my $path (sort patchpathcmp values %diffFiles) { + generateDiff($path); +} + +exit 0; + +# Overall sort, considering multiple criteria. +sub patchpathcmp($$) +{ + my ($a, $b) = @_; + + # All binary files come after all non-binary files. + my $result = binarycmp($a, $b); + return $result if $result; + + # All test files come after all non-test files. + $result = testfilecmp($a, $b); + return $result if $result; + + # Final sort is a "smart" sort by directory and file name. + return pathcmp($a, $b); +} + +# Sort so text files appear before binary files. +sub binarycmp($$) +{ + my ($fileDataA, $fileDataB) = @_; + return $fileDataA->{isBinary} <=> $fileDataB->{isBinary}; +} + +sub canonicalizePath($) +{ + my ($file) = @_; + + # Remove extra slashes and '.' directories in path + $file = File::Spec->canonpath($file); + + # Remove '..' directories in path + my @dirs = (); + foreach my $dir (File::Spec->splitdir($file)) { + if ($dir eq '..' && $#dirs >= 0 && $dirs[$#dirs] ne '..') { + pop(@dirs); + } else { + push(@dirs, $dir); + } + } + return ($#dirs >= 0) ? File::Spec->catdir(@dirs) : "."; +} + +sub findBaseUrl($) +{ + my ($infoPath) = @_; + my $baseUrl; + open INFO, "svn info '$infoPath' |" or die; + while (<INFO>) { + if (/^URL: (.+)/) { + $baseUrl = $1; + last; + } + } + close INFO; + return $baseUrl; +} + +sub findMimeType($;$) +{ + my ($file, $revision) = @_; + my $args = $revision ? "--revision $revision" : ""; + open PROPGET, "svn propget svn:mime-type $args '$file' |" or die; + my $mimeType = <PROPGET>; + close PROPGET; + chomp $mimeType if $mimeType; + return $mimeType; +} + +sub findModificationType($) +{ + my ($stat) = @_; + my $fileStat = substr($stat, 0, 1); + my $propertyStat = substr($stat, 1, 1); + if ($fileStat eq "A") { + my $additionWithHistory = substr($stat, 3, 1); + return $additionWithHistory eq "+" ? "additionWithHistory" : "addition"; + } + return "modification" if ($fileStat eq "M" || $propertyStat eq "M"); + return "deletion" if ($fileStat eq "D"); + return undef; +} + +sub findSourceFileAndRevision($) +{ + my ($file) = @_; + my $baseUrl = findBaseUrl("."); + my $sourceFile; + my $sourceRevision; + open INFO, "svn info '$file' |" or die; + while (<INFO>) { + if (/^Copied From URL: (.+)/) { + $sourceFile = File::Spec->abs2rel($1, $baseUrl); + } elsif (/^Copied From Rev: ([0-9]+)/) { + $sourceRevision = $1; + } + } + close INFO; + return ($sourceFile, $sourceRevision); +} + +sub fixChangeLogPatch($) +{ + my $patch = shift; + my $contextLineCount = 3; + + return $patch if $patch !~ /\n@@ -1,(\d+) \+1,(\d+) @@\n( .*\n)+(\+.*\n)+( .*\n){$contextLineCount}$/m; + my ($oldLineCount, $newLineCount) = ($1, $2); + return $patch if $oldLineCount <= $contextLineCount; + + # The diff(1) command is greedy when matching lines, so a new ChangeLog entry will + # have lines of context at the top of a patch when the existing entry has the same + # date and author as the new entry. This nifty loop alters a ChangeLog patch so + # that the added lines ("+") in the patch always start at the beginning of the + # patch and there are no initial lines of context. + my $newPatch; + my $lineCountInState = 0; + my $oldContentLineCountReduction = $oldLineCount - $contextLineCount; + my $newContentLineCountWithoutContext = $newLineCount - $oldLineCount - $oldContentLineCountReduction; + my ($stateHeader, $statePreContext, $stateNewChanges, $statePostContext) = (1..4); + my $state = $stateHeader; + foreach my $line (split(/\n/, $patch)) { + $lineCountInState++; + if ($state == $stateHeader && $line =~ /^@@ -1,$oldLineCount \+1,$newLineCount @\@$/) { + $line = "@@ -1,$contextLineCount +1," . ($newLineCount - $oldContentLineCountReduction) . " @@"; + $lineCountInState = 0; + $state = $statePreContext; + } elsif ($state == $statePreContext && substr($line, 0, 1) eq " ") { + $line = "+" . substr($line, 1); + if ($lineCountInState == $oldContentLineCountReduction) { + $lineCountInState = 0; + $state = $stateNewChanges; + } + } elsif ($state == $stateNewChanges && substr($line, 0, 1) eq "+") { + # No changes to these lines + if ($lineCountInState == $newContentLineCountWithoutContext) { + $lineCountInState = 0; + $state = $statePostContext; + } + } elsif ($state == $statePostContext) { + if (substr($line, 0, 1) eq "+" && $lineCountInState <= $oldContentLineCountReduction) { + $line = " " . substr($line, 1); + } elsif ($lineCountInState > $contextLineCount && substr($line, 0, 1) eq " ") { + next; # Discard + } + } + $newPatch .= $line . "\n"; + } + + return $newPatch; +} + +sub generateDiff($) +{ + my ($fileData) = @_; + my $file = $fileData->{path}; + my $patch; + if ($fileData->{modificationType} eq "additionWithHistory") { + manufacturePatchForAdditionWithHistory($fileData); + } + open DIFF, "svn diff --diff-cmd diff -x -uaNp '$file' |" or die; + while (<DIFF>) { + $patch .= $_; + } + close DIFF; + $patch = fixChangeLogPatch($patch) if basename($file) eq "ChangeLog"; + print $patch if $patch; + if ($fileData->{isBinary}) { + print "\n" if ($patch && $patch =~ m/\n\S+$/m); + outputBinaryContent($file); + } +} + +sub generateFileList($\%) +{ + my ($statPath, $diffFiles) = @_; + my %testDirectories = map { $_ => 1 } qw(LayoutTests); + open STAT, "svn stat '$statPath' |" or die; + while (my $line = <STAT>) { + chomp $line; + my $stat = substr($line, 0, 7); + my $path = substr($line, 7); + next if -d $path; + my $modificationType = findModificationType($stat); + if ($modificationType) { + $diffFiles->{$path}->{path} = $path; + $diffFiles->{$path}->{modificationType} = $modificationType; + $diffFiles->{$path}->{isBinary} = isBinaryMimeType($path); + $diffFiles->{$path}->{isTestFile} = exists $testDirectories{(File::Spec->splitdir($path))[0]} ? 1 : 0; + if ($modificationType eq "additionWithHistory") { + my ($sourceFile, $sourceRevision) = findSourceFileAndRevision($path); + $diffFiles->{$path}->{sourceFile} = $sourceFile; + $diffFiles->{$path}->{sourceRevision} = $sourceRevision; + } + } else { + print STDERR $line, "\n"; + } + } + close STAT; +} + +sub isBinaryMimeType($) +{ + my ($file) = @_; + my $mimeType = findMimeType($file); + return 0 if (!$mimeType || substr($mimeType, 0, 5) eq "text/"); + return 1; +} + +sub manufacturePatchForAdditionWithHistory($) +{ + my ($fileData) = @_; + my $file = $fileData->{path}; + print "Index: ${file}\n"; + print "=" x 67, "\n"; + my $sourceFile = $fileData->{sourceFile}; + my $sourceRevision = $fileData->{sourceRevision}; + print "--- ${file}\t(revision ${sourceRevision})\t(from ${sourceFile}:${sourceRevision})\n"; + print "+++ ${file}\t(working copy)\n"; + if ($fileData->{isBinary}) { + print "\nCannot display: file marked as a binary type.\n"; + my $mimeType = findMimeType($file, $sourceRevision); + print "svn:mime-type = ${mimeType}\n\n"; + } else { + print `svn cat ${sourceFile} | diff -u /dev/null - | tail -n +3`; + } +} + +# Sort numeric parts of strings as numbers, other parts as strings. +# Makes 1.33 come after 1.3, which is cool. +sub numericcmp($$) +{ + my ($aa, $bb) = @_; + + my @a = split /(\d+)/, $aa; + my @b = split /(\d+)/, $bb; + + # Compare one chunk at a time. + # Each chunk is either all numeric digits, or all not numeric digits. + while (@a && @b) { + my $a = shift @a; + my $b = shift @b; + + # Use numeric comparison if chunks are non-equal numbers. + return $a <=> $b if $a =~ /^\d/ && $b =~ /^\d/ && $a != $b; + + # Use string comparison if chunks are any other kind of non-equal string. + return $a cmp $b if $a ne $b; + } + + # One of the two is now empty; compare lengths for result in this case. + return @a <=> @b; +} + +sub outputBinaryContent($) +{ + my ($path) = @_; + # Deletion + return if (! -e $path); + # Addition or Modification + my $buffer; + open BINARY, $path or die; + while (read(BINARY, $buffer, 60*57)) { + print encode_base64($buffer); + } + close BINARY; + print "\n"; +} + +# Sort first by directory, then by file, so all paths in one directory are grouped +# rather than being interspersed with items from subdirectories. +# Use numericcmp to sort directory and filenames to make order logical. +# Also include a special case for ChangeLog, which comes first in any directory. +sub pathcmp($$) +{ + my ($fileDataA, $fileDataB) = @_; + + my ($dira, $namea) = splitpath($fileDataA->{path}); + my ($dirb, $nameb) = splitpath($fileDataB->{path}); + + return numericcmp($dira, $dirb) if $dira ne $dirb; + return -1 if $namea eq "ChangeLog" && $nameb ne "ChangeLog"; + return +1 if $namea ne "ChangeLog" && $nameb eq "ChangeLog"; + return numericcmp($namea, $nameb); +} + +sub processPaths(\@) +{ + my ($paths) = @_; + return ("." => 1) if (!@{$paths}); + + my %result = (); + + for my $file (@{$paths}) { + die "can't handle absolute paths like \"$file\"\n" if File::Spec->file_name_is_absolute($file); + die "can't handle empty string path\n" if $file eq ""; + die "can't handle path with single quote in the name like \"$file\"\n" if $file =~ /'/; # ' (keep Xcode syntax highlighting happy) + + my $untouchedFile = $file; + + $file = canonicalizePath($file); + + die "can't handle paths with .. like \"$untouchedFile\"\n" if $file =~ m|/\.\./|; + + $result{$file} = 1; + } + + return ("." => 1) if ($result{"."}); + + # Remove any paths that also have a parent listed. + for my $path (keys %result) { + for (my $parent = dirname($path); $parent ne '.'; $parent = dirname($parent)) { + if ($result{$parent}) { + delete $result{$path}; + last; + } + } + } + + return %result; +} + +# Break up a path into the directory (with slash) and base name. +sub splitpath($) +{ + my ($path) = @_; + + my $pathSeparator = "/"; + my $dirname = dirname($path) . $pathSeparator; + $dirname = "" if $dirname eq "." . $pathSeparator; + + return ($dirname, basename($path)); +} + +# Sort so source code files appear before test files. +sub testfilecmp($$) +{ + my ($fileDataA, $fileDataB) = @_; + return $fileDataA->{isTestFile} <=> $fileDataB->{isTestFile}; +} diff --git a/WebKitTools/Scripts/svn-unapply b/WebKitTools/Scripts/svn-unapply new file mode 100755 index 0000000..05910ad --- /dev/null +++ b/WebKitTools/Scripts/svn-unapply @@ -0,0 +1,374 @@ +#!/usr/bin/perl -w + +# Copyright (C) 2005, 2006, 2007 Apple 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. + +# "unpatch" script for Web Kit Open Source Project, used to remove patches. + +# Differences from invoking "patch -p0 -R": +# +# Handles added files (does a svn revert with additional logic to handle local changes). +# Handles added directories (does a svn revert and a rmdir). +# Handles removed files (does a svn revert with additional logic to handle local changes). +# Handles removed directories (does a svn revert). +# 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, and the entry date is reset in +# the patch before it is applied (svn-apply sets it when applying a patch). +# Handles binary files (requires patches made by svn-create-patch). +# Handles copied and moved files (requires patches made by svn-create-patch). +# Handles git-diff patches (without binary changes) created at the top-level directory +# +# Missing features: +# +# Handle property changes. +# Handle copied and moved directories (would require patches made by svn-create-patch). +# Use version numbers in the patch file and do a 3-way merge. +# When reversing an addition, check that the file matches what's being removed. +# Notice a patch that's being unapplied 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 exclude ChangeLog). +# Handle git-diff patches with binary changes + +use strict; +use warnings; + +use Cwd; +use Digest::MD5; +use Fcntl qw(:DEFAULT :seek); +use File::Basename; +use File::Spec; +use File::Temp qw(tempfile); +use Getopt::Long; + +sub checksum($); +sub fixChangeLogPatch($); +sub gitdiff2svndiff($); +sub patch($); +sub revertDirectories(); +sub svnStatus($); +sub unapplyPatch($$;$); +sub unsetChangeLogDate($$); + +my $showHelp = 0; +if (!GetOptions("help!" => \$showHelp) || $showHelp) { + print STDERR basename($0) . " [-h|--help] patch1 [patch2 ...]\n"; + exit 1; +} + +my @copiedFiles; +my %directoriesToCheck; + +my $copiedFromPath; +my $filter; +my $indexPath; +my $patch; +while (<>) { + s/\r//g; + chomp; + if (!defined($indexPath) && m#^diff --git a/#) { + $filter = \&gitdiff2svndiff; + } + $_ = &$filter($_) if $filter; + if (/^Index: (.*)/) { + $indexPath = $1; + if ($patch) { + if ($copiedFromPath) { + push @copiedFiles, $patch; + } else { + patch($patch); + } + $copiedFromPath = ""; + $patch = ""; + } + } + if ($indexPath) { + # Fix paths on diff, ---, and +++ lines to match preceding Index: line. + s/^--- \S+/--- $indexPath/; + if (/^--- .+\(from (\S+):\d+\)$/) { + $copiedFromPath = $1; + } + if (s/^\+\+\+ \S+/+++ $indexPath/) { + $indexPath = ""; + } + } + $patch .= $_; + $patch .= "\n"; +} + +if ($patch) { + if ($copiedFromPath) { + push @copiedFiles, $patch; + } else { + patch($patch); + } +} + +# Handle copied and moved files last since they may have had post-copy changes that have now been unapplied +for $patch (@copiedFiles) { + patch($patch); +} + +revertDirectories(); + +exit 0; + +sub checksum($) +{ + my $file = shift; + open(FILE, $file) or die "Can't open '$file': $!"; + binmode(FILE); + my $checksum = Digest::MD5->new->addfile(*FILE)->hexdigest(); + close(FILE); + return $checksum; +} + +sub fixChangeLogPatch($) +{ + my $patch = shift; + my $contextLineCount = 3; + + return $patch if $patch !~ /\n@@ -1,(\d+) \+1,(\d+) @@\n( .*\n)+(\+.*\n)+( .*\n){$contextLineCount}$/m; + my ($oldLineCount, $newLineCount) = ($1, $2); + return $patch if $oldLineCount <= $contextLineCount; + + # The diff(1) command is greedy when matching lines, so a new ChangeLog entry will + # have lines of context at the top of a patch when the existing entry has the same + # date and author as the new entry. This nifty loop alters a ChangeLog patch so + # that the added lines ("+") in the patch always start at the beginning of the + # patch and there are no initial lines of context. + my $newPatch; + my $lineCountInState = 0; + my $oldContentLineCountReduction = $oldLineCount - $contextLineCount; + my $newContentLineCountWithoutContext = $newLineCount - $oldLineCount - $oldContentLineCountReduction; + my ($stateHeader, $statePreContext, $stateNewChanges, $statePostContext) = (1..4); + my $state = $stateHeader; + foreach my $line (split(/\n/, $patch)) { + $lineCountInState++; + if ($state == $stateHeader && $line =~ /^@@ -1,$oldLineCount \+1,$newLineCount @\@$/) { + $line = "@@ -1,$contextLineCount +1," . ($newLineCount - $oldContentLineCountReduction) . " @@"; + $lineCountInState = 0; + $state = $statePreContext; + } elsif ($state == $statePreContext && substr($line, 0, 1) eq " ") { + $line = "+" . substr($line, 1); + if ($lineCountInState == $oldContentLineCountReduction) { + $lineCountInState = 0; + $state = $stateNewChanges; + } + } elsif ($state == $stateNewChanges && substr($line, 0, 1) eq "+") { + # No changes to these lines + if ($lineCountInState == $newContentLineCountWithoutContext) { + $lineCountInState = 0; + $state = $statePostContext; + } + } elsif ($state == $statePostContext) { + if (substr($line, 0, 1) eq "+" && $lineCountInState <= $oldContentLineCountReduction) { + $line = " " . substr($line, 1); + } elsif ($lineCountInState > $contextLineCount && substr($line, 0, 1) eq " ") { + next; # Discard + } + } + $newPatch .= $line . "\n"; + } + + return $newPatch; +} + +sub gitdiff2svndiff($) +{ + $_ = shift @_; + if (m#^diff --git a/(.+) b/(.+)#) { + return "Index: $1"; + } elsif (m/^new file.*/) { + return ""; + } elsif (m#^index [0-9a-f]{7}\.\.[0-9a-f]{7} [0-9]{6}#) { + return "==================================================================="; + } elsif (m#^--- a/(.+)#) { + return "--- $1"; + } elsif (m#^\+\+\+ b/(.+)#) { + return "+++ $1"; + } + return $_; +} + +sub patch($) +{ + my ($patch) = @_; + return if !$patch; + + unless ($patch =~ m|^Index: ([^\n]+)|) { + my $separator = '-' x 67; + warn "Failed to find 'Index:' in:\n$separator\n$patch\n$separator\n"; + return; + } + my $fullPath = $1; + $directoriesToCheck{dirname($fullPath)} = 1; + + my $deletion = 0; + my $addition = 0; + my $isBinary = 0; + + $addition = 1 if ($patch =~ /\n--- .+\(revision 0\)\n/ || $patch =~ /\n@@ -0,0 .* @@/); + $deletion = 1 if $patch =~ /\n@@ .* \+0,0 @@/; + $isBinary = 1 if $patch =~ /\nCannot display: file marked as a binary type\./; + + if (!$addition && !$deletion && !$isBinary) { + # Standard patch, patch tool can handle this. + if (basename($fullPath) eq "ChangeLog") { + my $changeLogDotOrigExisted = -f "${fullPath}.orig"; + unapplyPatch(unsetChangeLogDate($fullPath, fixChangeLogPatch($patch)), $fullPath, ["--fuzz=3"]); + unlink("${fullPath}.orig") if (! $changeLogDotOrigExisted); + } else { + unapplyPatch($patch, $fullPath); + } + } else { + # Either a deletion, an addition or a binary change. + + if ($isBinary) { + # Reverse binary change + unlink($fullPath) if (-e $fullPath); + system "svn", "revert", $fullPath; + } elsif ($deletion) { + # Reverse deletion + rename($fullPath, "$fullPath.orig") if -e $fullPath; + + unapplyPatch($patch, $fullPath); + + # If we don't ask for the filehandle here, we always get a warning. + my ($fh, $tempPath) = tempfile(basename($fullPath) . "-XXXXXXXX", + DIR => dirname($fullPath), UNLINK => 1); + close($fh); + + # Keep the version from the patch in case it's different from svn. + rename($fullPath, $tempPath); + system "svn", "revert", $fullPath; + rename($tempPath, $fullPath); + + # This works around a bug in the svn client. + # [Issue 1960] file modifications get lost due to FAT 2s time resolution + # http://subversion.tigris.org/issues/show_bug.cgi?id=1960 + system "touch", $fullPath; + + # Remove $fullPath.orig if it is the same as $fullPath + unlink("$fullPath.orig") if -e "$fullPath.orig" && checksum($fullPath) eq checksum("$fullPath.orig"); + + # Show status if the file is modifed + system "svn", "stat", $fullPath; + } else { + # Reverse addition + unapplyPatch($patch, $fullPath, ["--force"]); + unlink($fullPath) if -z $fullPath; + system "svn", "revert", $fullPath; + } + } +} + +sub revertDirectories() +{ + my %checkedDirectories; + foreach my $path (reverse sort keys %directoriesToCheck) { + my @dirs = File::Spec->splitdir($path); + while (scalar @dirs) { + my $dir = File::Spec->catdir(@dirs); + pop(@dirs); + next if (exists $checkedDirectories{$dir}); + if (-d $dir) { + my $svnOutput = svnStatus($dir); + if ($svnOutput && $svnOutput =~ m#A\s+$dir\n#) { + system "svn", "revert", $dir; + rmdir $dir; + } + elsif ($svnOutput && $svnOutput =~ m#D\s+$dir\n#) { + system "svn", "revert", $dir; + } + else { + # Modification + print $svnOutput if $svnOutput; + } + $checkedDirectories{$dir} = 1; + } + else { + die "'$dir' is not a directory"; + } + } + } +} + +sub svnStatus($) +{ + my ($fullPath) = @_; + my $svnStatus; + open SVN, "svn status --non-interactive --non-recursive '$fullPath' |" or die; + if (-d $fullPath) { + # When running "svn stat" on a directory, we can't assume that only one + # status will be returned (since any files with a status below the + # directory will be returned), and we can't assume that the directory will + # be first (since any files with unknown status will be listed first). + my $normalizedFullPath = File::Spec->catdir(File::Spec->splitdir($fullPath)); + while (<SVN>) { + chomp; + my $normalizedStatPath = File::Spec->catdir(File::Spec->splitdir(substr($_, 7))); + if ($normalizedFullPath eq $normalizedStatPath) { + $svnStatus = $_; + last; + } + } + # Read the rest of the svn command output to avoid a broken pipe warning. + local $/ = undef; + <SVN>; + } + else { + # Files will have only one status returned. + $svnStatus = <SVN>; + } + close SVN; + return $svnStatus; +} + +sub unapplyPatch($$;$) +{ + my ($patch, $fullPath, $options) = @_; + $options = [] if (! $options); + my $command = "patch " . join(" ", "-p0", "-R", @{$options}); + open PATCH, "| $command" or die "Failed to patch $fullPath: $!"; + print PATCH $patch; + close PATCH; +} + +sub unsetChangeLogDate($$) +{ + my $fullPath = shift; + my $patch = shift; + my $newDate; + sysopen(CHANGELOG, $fullPath, O_RDONLY) or die "Failed to open $fullPath: $!"; + sysseek(CHANGELOG, 0, SEEK_SET); + my $byteCount = sysread(CHANGELOG, $newDate, 10); + die "Failed reading $fullPath: $!" if !$byteCount || $byteCount != 10; + close(CHANGELOG); + $patch =~ s/(\n\+)\d{4}-[^-]{2}-[^-]{2}( )/$1$newDate$2/; + return $patch; +} diff --git a/WebKitTools/Scripts/update-iexploder-cssproperties b/WebKitTools/Scripts/update-iexploder-cssproperties new file mode 100755 index 0000000..b7ae6cb --- /dev/null +++ b/WebKitTools/Scripts/update-iexploder-cssproperties @@ -0,0 +1,112 @@ +#!/usr/bin/perl + +# Copyright (C) 2007 Apple 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 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. + +# This script updates WebKitTools/iExploder/htdocs/cssproperties.in based on +# WebCore/css/CSSPropertyNames.in. + +use warnings; +use strict; + +use FindBin; +use lib $FindBin::Bin; +use webkitdirs; + +use File::Spec; + +sub generateSectionFromCSSPropertyNamesFile(); +sub readiExploderFile(); +sub svnRevision($); +sub writeiExploderFile(); + +my $iExploderFile = File::Spec->catfile(sourceDir(), split("/", "WebKitTools/iExploder/htdocs/cssproperties.in")); +my $cssPropertyNamesFile = File::Spec->catfile(sourceDir(), split("/", "WebCore/css/CSSPropertyNames.in")); + +my @sections = readiExploderFile(); +$sections[0] = generateSectionFromCSSPropertyNamesFile(); +writeiExploderFile(); + +print `svn stat $iExploderFile`; +print "Successfully updated!\n"; + +exit 0; + +sub generateSectionFromCSSPropertyNamesFile() +{ + my $revision = svnRevision($cssPropertyNamesFile); + my $path = File::Spec->abs2rel($cssPropertyNamesFile, sourceDir()); + my $result = "# From WebKit svn r" . $revision . " (" . $path . ")\n"; + + my @properties = (); + + open(IN, $cssPropertyNamesFile) || die "$!"; + while (my $l = <IN>) { + chomp $l; + next if $l =~ m/^\s*#/ || $l =~ m/^\s*$/; + push(@properties, $l); + } + close(IN); + + $result .= join("\n", sort { $a cmp $b } @properties) . "\n\n"; + + return $result; +} + +sub readiExploderFile() +{ + my @sections = (); + local $/ = "\n\n"; + + open(IN, $iExploderFile) || die "$!"; + @sections = <IN>; + close(IN); + + return @sections; +} + +sub svnRevision($) +{ + my ($file) = @_; + my $revision = ""; + + open INFO, "svn info '$file' |" or die; + while (<INFO>) { + if (/^Revision: (.+)/) { + $revision = $1; + } + } + close INFO; + + return $revision ? $revision : "UNKNOWN"; +} + +sub writeiExploderFile() +{ + open(OUT, "> $iExploderFile") || die "$!"; + print OUT join("", @sections); + close(OUT); +} diff --git a/WebKitTools/Scripts/update-javascriptcore-test-results b/WebKitTools/Scripts/update-javascriptcore-test-results new file mode 100755 index 0000000..dd8b9b6 --- /dev/null +++ b/WebKitTools/Scripts/update-javascriptcore-test-results @@ -0,0 +1,73 @@ +#!/usr/bin/perl -w + +# Copyright (C) 2005, 2007 Apple 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. + +use strict; +use FindBin; +use Getopt::Long; +use lib $FindBin::Bin; +use webkitdirs; + +chdirWebKit(); +chdir "JavaScriptCore/tests/mozilla" or die; + +my $force = 0; +GetOptions('force' => \$force); + +open EXPECTED, "expected.html" or die; +while (<EXPECTED>) { + last if /failures reported\.$/; +} +my %expected; +while (<EXPECTED>) { + chomp; + $expected{$_} = 1; +} +close EXPECTED; + +open ACTUAL, "actual.html" or die; +my $actual; +while (<ACTUAL>) { + $actual .= $_; + last if /failures reported\.$/; +} +my $failed = 0; +while (<ACTUAL>) { + $actual .= $_; + chomp; + if (!$expected{$_}) { + $failed = 1; + print "failure not expected: $_\n"; + } +} +close ACTUAL; + +die "won't update, failures introduced\n" if $failed && !$force; + +open EXPECTED, ">expected.html"; +print EXPECTED $actual; +close EXPECTED; diff --git a/WebKitTools/Scripts/update-webkit b/WebKitTools/Scripts/update-webkit new file mode 100755 index 0000000..6d974b1 --- /dev/null +++ b/WebKitTools/Scripts/update-webkit @@ -0,0 +1,92 @@ +#!/usr/bin/perl -w + +# Copyright (C) 2005, 2006, 2007, 2008 Apple 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. + +# Update script for Web Kit Open Source Project. + +use strict; +use FindBin; +use lib $FindBin::Bin; +use File::Basename; +use File::Spec; +use Getopt::Long; +use webkitdirs; + +sub runSvnUpdate(); + +# Handle options +my $quiet = ''; +my $showHelp; + +my $getOptionsResult = GetOptions( + 'h|help' => \$showHelp, + 'q|quiet' => \$quiet, +); + +if (!$getOptionsResult || $showHelp) { + print STDERR <<__END__; +Usage: @{[ basename($0) ]} [options] + -h|--help show the help message + -q|--quiet pass -q to svn update for quiet updates +__END__ + exit 1; +} + +my @svnOptions = (); +push @svnOptions, '-q' if $quiet; + +chdirWebKit(); +print "Updating OpenSource\n" unless $quiet; +runSvnUpdate(); + +if (-d "../Internal") { + chdir("../Internal"); + print "Updating Internal\n" unless $quiet; + runSvnUpdate(); +} elsif (isCygwin()) { + system("perl", "WebKitTools/Scripts/update-webkit-auxiliary-libs") == 0 or die; +} + +exit 0; + +sub runSvnUpdate() +{ + open UPDATE, "-|", "svn", "update", @svnOptions or die; + my @conflictedChangeLogs; + while (my $line = <UPDATE>) { + print $line; + push @conflictedChangeLogs, $1 if $line =~ m/^C\s+(.+)\s*$/ && basename($1) eq "ChangeLog"; + } + close UPDATE; + + if (@conflictedChangeLogs) { + print "Attempting to merge conflicted ChangeLogs.\n"; + my $resolveChangeLogsPath = File::Spec->catfile(dirname($0), "resolve-ChangeLogs"); + (system($resolveChangeLogsPath, "--no-warnings", @conflictedChangeLogs) == 0) + or die "Could not open resolve-ChangeLogs script: $!.\n"; + } +} diff --git a/WebKitTools/Scripts/update-webkit-auxiliary-libs b/WebKitTools/Scripts/update-webkit-auxiliary-libs new file mode 100755 index 0000000..1d6943c --- /dev/null +++ b/WebKitTools/Scripts/update-webkit-auxiliary-libs @@ -0,0 +1,121 @@ +#!/usr/bin/perl -w + +# Copyright (C) 2005, 2006, 2007 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. + +# Updates a development environment to the new WebKitAuxiliaryLibrary + +use strict; +use warnings; + +use HTTP::Date qw(str2time); +use File::Find; +use File::Temp; +use File::Spec; +use FindBin; +use lib $FindBin::Bin; +use webkitdirs; + +sub lastModifiedToUnixTime($); + +# Time in seconds that the new zip file must be newer than the old for us to +# consider them to be different. If the difference in modification time is less +# than this threshold, we assume that the files are the same. We need this +# because the zip file is served from a set of mirrors with slightly different +# Last-Modified times. +my $newnessThreshold = 30; + +my $sourceDir = sourceDir(); +my $file = "WebKitAuxiliaryLibrary"; +my $zipFile = "$file.zip"; +my $auxiliaryLibsURL = "http://developer.apple.com/opensource/internet/$zipFile"; +my $webkitLibrariesDir = toUnixPath($ENV{'WEBKITLIBRARIESDIR'}) || "$sourceDir/WebKitLibraries/win"; +my $tmpDir = File::Spec->rel2abs(File::Temp::tempdir("webkitlibsXXXXXXX", TMPDIR => 1, CLEANUP => 1)); + +print "Checking Last-Modified date of $zipFile...\n"; + +my $result = system "curl -s -I $auxiliaryLibsURL | grep Last-Modified > \"$tmpDir/$file.headers\""; +print STDERR "Couldn't check Last-Modified date of new $zipFile.\n" if $result; + +if (!$result && open NEW, "$tmpDir/$file.headers") { + my $new = lastModifiedToUnixTime(<NEW>); + close NEW; + + if (defined $new && open OLD, "$webkitLibrariesDir/$file.headers") { + my $old = lastModifiedToUnixTime(<OLD>); + close OLD; + if (defined $old && abs($new - $old) < $newnessThreshold) { + print "Current $file is up to date\n"; + exit 0; + } + } +} + +print "Downloading $zipFile...\n\n"; +$result = system "curl -o \"$tmpDir/$zipFile\" $auxiliaryLibsURL"; +die "Couldn't download $zipFile!" if $result; + +$result = system "unzip", "-q", "-d", $tmpDir, "$tmpDir/$zipFile"; +die "Couldn't unzip $zipFile." if $result; + +print "\nInstalling $file...\n"; + +sub wanted +{ + my $relativeName = File::Spec->abs2rel($File::Find::name, "$tmpDir/$file/win"); + my $destination = "$webkitLibrariesDir/$relativeName"; + + if (-d $_) { + mkdir $destination; + return; + } + + system "cp", $_, $destination; +} + +File::Find::find(\&wanted, "$tmpDir/$file"); + +$result = system "mv", "$tmpDir/$file.headers", $webkitLibrariesDir; +print STDERR "Couldn't move $file.headers to $webkitLibrariesDir" . ".\n" if $result; + +print "The $file has been sucessfully installed in\n $webkitLibrariesDir\n"; +exit; + +sub toUnixPath +{ + my $path = shift; + return unless $path; + chomp($path = `cygpath -u '$path'`); + return $path; +} + +sub lastModifiedToUnixTime($) +{ + my ($str) = @_; + + $str =~ /^Last-Modified: (.*)$/ or return; + return str2time($1); +} diff --git a/WebKitTools/Scripts/update-webkit-localizable-strings b/WebKitTools/Scripts/update-webkit-localizable-strings new file mode 100755 index 0000000..53037a6 --- /dev/null +++ b/WebKitTools/Scripts/update-webkit-localizable-strings @@ -0,0 +1,45 @@ +#!/usr/bin/perl -w + +# Copyright (C) 2006, 2007 Apple 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. + +use strict; +use warnings; + +use File::Basename; +use FindBin; +use lib $FindBin::Bin; +use webkitdirs; + +my @directoriesToScan = ("WebKit/mac", "WebKit/win"); +my $exceptionsFile = "WebKit/StringsNotToBeLocalized.txt"; + +@ARGV == 0 or die "Usage: " . basename($0) . "\n"; + +chdirWebKit(); + +system "sort -u $exceptionsFile -o $exceptionsFile"; +exec "extract-localizable-strings", $exceptionsFile, @directoriesToScan; diff --git a/WebKitTools/Scripts/update-webkit-support-libs b/WebKitTools/Scripts/update-webkit-support-libs new file mode 100755 index 0000000..e9c302b --- /dev/null +++ b/WebKitTools/Scripts/update-webkit-support-libs @@ -0,0 +1,105 @@ +#!/usr/bin/perl -w + +# Copyright (C) 2005, 2006, 2007 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. + +# Updates a development environment to the new WebKitSupportLibrary + +use strict; +use warnings; + +use File::Find; +use File::Temp; +use File::Spec; +use FindBin; +use lib $FindBin::Bin; +use webkitdirs; + +my $sourceDir = sourceDir(); +my $file = "WebKitSupportLibrary"; +my $zipFile = "$file.zip"; +my $zipDirectory = toUnixPath($ENV{'WEBKITSUPPORTLIBRARIESZIPDIR'}) || $sourceDir; +my $pathToZip = File::Spec->catfile($zipDirectory, $zipFile); +my $webkitLibrariesDir = toUnixPath($ENV{'WEBKITLIBRARIESDIR'}) || "$sourceDir/WebKitLibraries/win"; +my $tmpDir = File::Spec->rel2abs(File::Temp::tempdir("webkitlibsXXXXXXX", TMPDIR => 1, CLEANUP => 1)); + +# Make sure the file zipfile exists before doing anything. +die "$zipFile could not be found in your root source directory. Please\n" . + "download it from http://developer.apple.com/opensource/internet/webkit_sptlib_agree.html and place it in \n" . + "$sourceDir\n and then run update-webkit again.\n" unless (-f "$pathToZip"); + +print "Checking mod-date of $zipFile...\n"; +open MOD, ">$tmpDir/$file.modified" or die "Couldn't open $tmpDir/$file.modified for writing"; +print MOD (stat $pathToZip)[9] . "\n"; +close MOD; + +if (open NEW, "$tmpDir/$file.modified") { + my $new = <NEW>; + close NEW; + + if (open OLD, "$webkitLibrariesDir/$file.modified") { + my $old = <OLD>; + close OLD; + if ($old eq $new) { + print "Current $file is up to date\n"; + exit 0; + } + } +} + +my $result = system "unzip", "-q", "-d", $tmpDir, $pathToZip; +die "Couldn't unzip $zipFile." if $result; + +print "\nInstalling $file...\n"; + +sub wanted +{ + my $relativeName = File::Spec->abs2rel($File::Find::name, "$tmpDir/$file/win"); + my $destination = "$webkitLibrariesDir/$relativeName"; + + if (-d $_) { + mkdir $destination; + return; + } + + system "cp", $_, $destination; +} + +File::Find::find(\&wanted, "$tmpDir/$file"); + +$result = system "mv", "$tmpDir/$file.modified", $webkitLibrariesDir; +print STDERR "Couldn't move $file.modified to $webkitLibrariesDir" . ".\n" if $result; + +print "The $file has been sucessfully installed in\n $webkitLibrariesDir\n"; +exit; + +sub toUnixPath +{ + my $path = shift; + return unless $path; + chomp($path = `cygpath -u '$path'`); + return $path; +} diff --git a/WebKitTools/Scripts/webkitdirs.pm b/WebKitTools/Scripts/webkitdirs.pm new file mode 100644 index 0000000..478da8a --- /dev/null +++ b/WebKitTools/Scripts/webkitdirs.pm @@ -0,0 +1,947 @@ +# Copyright (C) 2005, 2006, 2007 Apple 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. + +# Module to share code to get to WebKit directories. + +use strict; +use warnings; +use FindBin; +use File::Basename; +use POSIX; +use VCSUtils; + +BEGIN { + use Exporter (); + our ($VERSION, @ISA, @EXPORT, @EXPORT_OK, %EXPORT_TAGS); + $VERSION = 1.00; + @ISA = qw(Exporter); + @EXPORT = qw(&chdirWebKit &baseProductDir &productDir &XcodeOptions &XcodeOptionString &XcodeOptionStringNoConfig &passedConfiguration &setConfiguration &safariPath &checkFrameworks ¤tSVNRevision); + %EXPORT_TAGS = ( ); + @EXPORT_OK = (); +} + +our @EXPORT_OK; + +my $baseProductDir; +my @baseProductDirOption; +my $configuration; +my $configurationForVisualStudio; +my $configurationProductDir; +my $sourceDir; +my $currentSVNRevision; +my $osXVersion; +my $isQt; +my $isGtk; +my $isWx; + +# Variables for Win32 support +my $vcBuildPath; +my $windowsTmpPath; + +sub determineSourceDir +{ + return if $sourceDir; + $sourceDir = $FindBin::Bin; + + # walks up path checking each directory to see if it is the main WebKit project dir, + # defined by containing JavaScriptCore, WebCore, and WebKit + until ((-d "$sourceDir/JavaScriptCore" && -d "$sourceDir/WebCore" && -d "$sourceDir/WebKit") || (-d "$sourceDir/Internal" && -d "$sourceDir/OpenSource")) + { + if ($sourceDir !~ s|/[^/]+$||) { + die "Could not find top level webkit directory above source directory using FindBin.\n"; + } + } + + $sourceDir = "$sourceDir/OpenSource" if -d "$sourceDir/OpenSource"; +} + +# used for scripts which are stored in a non-standard location +sub setSourceDir($) +{ + ($sourceDir) = @_; +} + +sub determineBaseProductDir +{ + return if defined $baseProductDir; + determineSourceDir(); + if (isOSX()) { + open PRODUCT, "defaults read com.apple.Xcode PBXApplicationwideBuildSettings 2> /dev/null |" or die; + $baseProductDir = join '', <PRODUCT>; + close PRODUCT; + + $baseProductDir = $1 if $baseProductDir =~ /SYMROOT\s*=\s*\"(.*?)\";/s; + undef $baseProductDir unless $baseProductDir =~ /^\//; + + if (!defined($baseProductDir)) { + open PRODUCT, "defaults read com.apple.Xcode PBXProductDirectory 2> /dev/null |" or die; + $baseProductDir = <PRODUCT>; + close PRODUCT; + if ($baseProductDir) { + chomp $baseProductDir; + undef $baseProductDir unless $baseProductDir =~ /^\//; + } + } + } else { + $baseProductDir = $ENV{"WEBKITOUTPUTDIR"}; + if (isCygwin() && $baseProductDir) { + my $unixBuildPath = `cygpath --unix \"$baseProductDir\"`; + chomp $unixBuildPath; + $baseProductDir = $unixBuildPath; + } + } + + if ($baseProductDir && isOSX()) { + $baseProductDir =~ s|^\Q$(SRCROOT)/..\E$|$sourceDir|; + $baseProductDir =~ s|^\Q$(SRCROOT)/../|$sourceDir/|; + $baseProductDir =~ s|^~/|$ENV{HOME}/|; + die "Can't handle Xcode product directory with a ~ in it.\n" if $baseProductDir =~ /~/; + die "Can't handle Xcode product directory with a variable in it.\n" if $baseProductDir =~ /\$/; + @baseProductDirOption = (); + } + + if (!defined($baseProductDir)) { + $baseProductDir = "$sourceDir/WebKitBuild"; + + if (isGit() && isGitBranchBuild()) { + my $branch = gitBranch(); + $baseProductDir = "$baseProductDir/$branch"; + } + + @baseProductDirOption = ("SYMROOT=$baseProductDir", "OBJROOT=$baseProductDir") if (isOSX()); + if (isCygwin()) { + my $dosBuildPath = `cygpath --windows \"$baseProductDir\"`; + chomp $dosBuildPath; + $ENV{"WEBKITOUTPUTDIR"} = $dosBuildPath; + } + } +} + +sub setBaseProductDir($) +{ + ($baseProductDir) = @_; +} + +sub determineConfiguration +{ + return if defined $configuration; + determineBaseProductDir(); + if (open CONFIGURATION, "$baseProductDir/Configuration") { + $configuration = <CONFIGURATION>; + close CONFIGURATION; + } + if ($configuration) { + chomp $configuration; + # compatibility for people who have old Configuration files + $configuration = "Release" if $configuration eq "Deployment"; + $configuration = "Debug" if $configuration eq "Development"; + } else { + $configuration = "Release"; + } +} + +sub determineConfigurationForVisualStudio +{ + return if defined $configurationForVisualStudio; + determineConfiguration(); + $configurationForVisualStudio = $configuration; + return unless $configuration eq "Debug"; + setupCygwinEnv(); + chomp(my $dir = `cygpath -ua '$ENV{WEBKITLIBRARIESDIR}'`); + $configurationForVisualStudio = "Debug_Internal" if -f "$dir/bin/CoreFoundation_debug.dll"; +} + +sub determineConfigurationProductDir +{ + return if defined $configurationProductDir; + determineBaseProductDir(); + if(isCygwin() && !isWx()) { + $configurationProductDir = "$baseProductDir/bin"; + } else { + determineConfiguration(); + $configurationProductDir = "$baseProductDir/$configuration"; + } +} + +sub setConfigurationProductDir($) +{ + ($configurationProductDir) = @_; +} + +sub determineCurrentSVNRevision +{ + return if defined $currentSVNRevision; + determineSourceDir(); + my $svnInfo = `LC_ALL=C svn info $sourceDir | grep Revision:`; + ($currentSVNRevision) = ($svnInfo =~ m/Revision: (\d+).*/g); + die "Unable to determine current SVN revision in $sourceDir" unless (defined $currentSVNRevision); + return $currentSVNRevision; +} + + +sub chdirWebKit +{ + determineSourceDir(); + chdir $sourceDir or die; +} + +sub baseProductDir +{ + determineBaseProductDir(); + return $baseProductDir; +} + +sub sourceDir +{ + determineSourceDir(); + return $sourceDir; +} + +sub productDir +{ + determineConfigurationProductDir(); + return $configurationProductDir; +} + +sub configuration() +{ + determineConfiguration(); + return $configuration; +} + +sub configurationForVisualStudio() +{ + determineConfigurationForVisualStudio(); + return $configurationForVisualStudio; +} + +sub currentSVNRevision +{ + determineCurrentSVNRevision(); + return $currentSVNRevision; +} + +sub XcodeOptions +{ + determineBaseProductDir(); + determineConfiguration(); + return (@baseProductDirOption, "-configuration", $configuration); +} + +sub XcodeOptionString +{ + return join " ", XcodeOptions(); +} + +sub XcodeOptionStringNoConfig +{ + return join " ", @baseProductDirOption; +} + +my $passedConfiguration; +my $searchedForPassedConfiguration; +sub determinePassedConfiguration +{ + return if $searchedForPassedConfiguration; + $searchedForPassedConfiguration = 1; + for my $i (0 .. $#ARGV) { + my $opt = $ARGV[$i]; + if ($opt =~ /^--debug$/i || $opt =~ /^--devel/i) { + splice(@ARGV, $i, 1); + $passedConfiguration = "Debug"; + return; + } + if ($opt =~ /^--release$/i || $opt =~ /^--deploy/i) { + splice(@ARGV, $i, 1); + $passedConfiguration = "Release"; + return; + } + } + $passedConfiguration = undef; +} + +sub passedConfiguration +{ + determinePassedConfiguration(); + return $passedConfiguration; +} + +sub setConfiguration +{ + if (my $config = shift @_) { + $configuration = $config; + return; + } + + determinePassedConfiguration(); + $configuration = $passedConfiguration if $passedConfiguration; +} + +sub safariPathFromSafariBundle +{ + my ($safariBundle) = @_; + + return "$safariBundle/Contents/MacOS/Safari" if isOSX(); + return $safariBundle if isCygwin(); +} + +sub installedSafariPath +{ + my $safariBundle; + + if (isOSX()) { + $safariBundle = "/Applications/Safari.app"; + } elsif (isCygwin()) { + $safariBundle = `"$configurationProductDir/FindSafari.exe"`; + $safariBundle =~ s/[\r\n]+$//; + $safariBundle = `cygpath -u '$safariBundle'`; + $safariBundle =~ s/[\r\n]+$//; + $safariBundle .= "Safari.exe"; + } + + return safariPathFromSafariBundle($safariBundle); +} + +# Locate Safari. +sub safariPath +{ + # Use WEBKIT_SAFARI environment variable if present. + my $safariBundle = $ENV{WEBKIT_SAFARI}; + if (!$safariBundle) { + determineConfigurationProductDir(); + # Use Safari.app in product directory if present (good for Safari development team). + if (isOSX() && -d "$configurationProductDir/Safari.app") { + $safariBundle = "$configurationProductDir/Safari.app"; + } elsif (isCygwin() && -x "$configurationProductDir/bin/Safari.exe") { + $safariBundle = "$configurationProductDir/bin/Safari.exe"; + } else { + return installedSafariPath(); + } + } + my $safariPath = safariPathFromSafariBundle($safariBundle); + die "Can't find executable at $safariPath.\n" if isOSX() && !-x $safariPath; + return $safariPath; +} + +sub builtDylibPathForName +{ + my $framework = shift; + determineConfigurationProductDir(); + if (isQt() or isGtk()) { + return "$configurationProductDir/$framework"; + } + if (isOSX()) { + return "$configurationProductDir/$framework.framework/Versions/A/$framework"; + } + if (isCygwin()) { + if ($framework eq "JavaScriptCore") { + return "$baseProductDir/lib/$framework.lib"; + } else { + return "$baseProductDir/$framework.intermediate/$configuration/$framework.intermediate/$framework.lib"; + } + } + + die "Unsupported platform, can't determine built library locations."; +} + +# Check to see that all the frameworks are built. +sub checkFrameworks +{ + return if isCygwin(); + my @frameworks = ("JavaScriptCore", "WebCore"); + push(@frameworks, "WebKit") if isOSX(); + for my $framework (@frameworks) { + my $path = builtDylibPathForName($framework); + die "Can't find built framework at \"$path\".\n" unless -x $path; + } +} + +sub hasSVGSupport +{ + return 0 if isCygwin(); + + my $path = shift; + + if (isQt()) { + return 1; + } + + if (isGtk() and $path =~ /WebCore/) { + $path .= "/../lib/libWebKitGtk.so" if !$ENV{WEBKITAUTOTOOLS}; + $path .= "/../.libs/libWebKitGtk.so" if $ENV{WEBKITAUTOTOOLS}; + } + + my $hasSVGSupport = 0; + if (-e $path) { + open NM, "-|", "nm", $path or die; + while (<NM>) { + $hasSVGSupport = 1 if /SVGElement/; + } + close NM; + } + return $hasSVGSupport; +} + +sub removeLibraryDependingOnSVG +{ + my $frameworkName = shift; + my $shouldHaveSVG = shift; + + my $path = builtDylibPathForName($frameworkName); + return unless -x $path; + + my $hasSVG = hasSVGSupport($path); + system "rm -f $path" if ($shouldHaveSVG xor $hasSVG); +} + +sub checkWebCoreSVGSupport +{ + my $required = shift; + my $framework = "WebCore"; + my $path = builtDylibPathForName($framework); + my $hasSVG = hasSVGSupport($path); + if ($required && !$hasSVG) { + die "$framework at \"$path\" does not include SVG Support, please run build-webkit --svg\n"; + } + return $hasSVG; +} + +sub isQt() +{ + determineIsQt(); + return $isQt; +} + +sub checkArgv($) +{ + my $argToCheck = shift; + foreach my $opt (@ARGV) { + if ($opt =~ /^$argToCheck/i ) { + @ARGV = grep(!/^$argToCheck/i, @ARGV); + return 1; + } + } + return 0; +} + +sub determineIsQt() +{ + return if defined($isQt); + + # Allow override in case QTDIR is not set. + if (checkArgv("--qt")) { + $isQt = 1; + return; + } + + # The presence of QTDIR only means Qt if --gtk is not on the command-line + if (isGtk()) { + $isQt = 0; + return; + } + + $isQt = defined($ENV{'QTDIR'}); +} + +sub isGtk() +{ + determineIsGtk(); + return $isGtk; +} + +sub determineIsGtk() +{ + return if defined($isGtk); + + if (checkArgv("--gtk")) { + $isGtk = 1; + } else { + $isGtk = 0; + } +} + +sub isWx() +{ + determineIsWx(); + return $isWx; +} + +sub determineIsWx() +{ + return if defined($isWx); + + if (checkArgv("--wx")) { + $isWx = 1; + } else { + $isWx = 0; + } +} + +# Determine if this is debian, ubuntu, linspire, or something similar. +sub isDebianBased() +{ + return -e "/etc/debian_version"; +} + +sub isCygwin() +{ + return ($^O eq "cygwin"); +} + +sub isDarwin() +{ + return ($^O eq "darwin"); +} + +sub isOSX() +{ + return isDarwin() unless (isQt() or isGtk() or isWx()); + return 0; +} + +sub determineOSXVersion() +{ + return if $osXVersion; + + if (!isOSX()) { + $osXVersion = -1; + return; + } + + my $version = `sw_vers -productVersion`; + my @splitVersion = split(/\./, $version); + @splitVersion >= 2 or die "Invalid version $version"; + $osXVersion = { + "major" => $splitVersion[0], + "minor" => $splitVersion[1], + "subminor" => (defined($splitVersion[2]) ? $splitVersion[2] : 0), + }; +} + +sub osXVersion() +{ + determineOSXVersion(); + return $osXVersion; +} + +sub isTiger() +{ + return isOSX() && osXVersion()->{"minor"} == 4; +} + +sub isLeopard() +{ + return isOSX() && osXVersion()->{"minor"} == 5; +} + +sub relativeScriptsDir() +{ + my $scriptDir = File::Spec->catpath("", File::Spec->abs2rel(dirname($0), getcwd()), ""); + if ($scriptDir eq "") { + $scriptDir = "."; + } + return $scriptDir; +} + +sub launcherPath() +{ + my $relativeScriptsPath = relativeScriptsDir(); + if (isGtk() || isQt()) { + return "$relativeScriptsPath/run-launcher"; + } elsif (isOSX() || isCygwin()) { + return "$relativeScriptsPath/run-safari"; + } +} + +sub launcherName() +{ + if (isGtk()) { + return "GtkLauncher"; + } elsif (isQt()) { + return "QtLauncher"; + } elsif (isOSX() || isCygwin()) { + return "Safari"; + } +} + +sub checkRequiredSystemConfig +{ + if (isOSX()) { + chomp(my $productVersion = `sw_vers -productVersion`); + if ($productVersion lt "10.4") { + print "*************************************************************\n"; + print "Mac OS X Version 10.4.0 or later is required to build WebKit.\n"; + print "You have " . $productVersion . ", thus the build will most likely fail.\n"; + print "*************************************************************\n"; + } + my $xcodeVersion = `xcodebuild -version`; + if ($xcodeVersion !~ /DevToolsCore-(\d+)/ || $1 < 747) { + print "*************************************************************\n"; + print "Xcode Version 2.3 or later is required to build WebKit.\n"; + print "You have an earlier version of Xcode, thus the build will\n"; + print "most likely fail. The latest Xcode is available from the web:\n"; + print "http://developer.apple.com/tools/xcode\n"; + print "*************************************************************\n"; + } + } elsif (isGtk() or isQt() or isWx()) { + my @cmds = qw(flex bison gperf); + my @missing = (); + foreach my $cmd (@cmds) { + if (not `$cmd --version`) { + push @missing, $cmd; + } + } + if (@missing) { + my $list = join ", ", @missing; + die "ERROR: $list missing but required to build WebKit.\n"; + } + } + # Win32 and other platforms may want to check for minimum config +} + +sub setupCygwinEnv() +{ + return if !isCygwin(); + return if $vcBuildPath; + + my $programFilesPath = `cygpath "$ENV{'PROGRAMFILES'}"`; + chomp $programFilesPath; + $vcBuildPath = "$programFilesPath/Microsoft Visual Studio 8/Common7/IDE/devenv.com"; + if (! -e $vcBuildPath) { + # VC++ not found, try VC++ Express + my $vsInstallDir; + if ($ENV{'VSINSTALLDIR'}) { + $vsInstallDir = $ENV{'VSINSTALLDIR'}; + } else { + $programFilesPath = $ENV{'PROGRAMFILES'} || "C:\\Program Files"; + $vsInstallDir = "$programFilesPath/Microsoft Visual Studio 8"; + } + $vsInstallDir = `cygpath "$vsInstallDir"`; + chomp $vsInstallDir; + $vcBuildPath = "$vsInstallDir/Common7/IDE/VCExpress.exe"; + if (! -e $vcBuildPath) { + print "*************************************************************\n"; + print "Cannot find '$vcBuildPath'\n"; + print "Please execute the file 'vcvars32.bat' from\n"; + print "'$programFilesPath\\Microsoft Visual Studio 8\\VC\\bin\\'\n"; + print "to setup the necessary environment variables.\n"; + print "*************************************************************\n"; + die; + } + } + + my $qtSDKPath = "$programFilesPath/QuickTime SDK"; + if (0 && ! -e $qtSDKPath) { + print "*************************************************************\n"; + print "Cannot find '$qtSDKPath'\n"; + print "Please download the QuickTime SDK for Windows from\n"; + print "http://developer.apple.com/quicktime/download/\n"; + print "*************************************************************\n"; + die; + } + + chomp($ENV{'WEBKITLIBRARIESDIR'} = `cygpath -wa "$sourceDir/WebKitLibraries/win"`) unless $ENV{'WEBKITLIBRARIESDIR'}; + + $windowsTmpPath = `cygpath -w /tmp`; + chomp $windowsTmpPath; + print "Building results into: ", baseProductDir(), "\n"; + print "WEBKITOUTPUTDIR is set to: ", $ENV{"WEBKITOUTPUTDIR"}, "\n"; + print "WEBKITLIBRARIESDIR is set to: ", $ENV{"WEBKITLIBRARIESDIR"}, "\n"; +} + +sub buildVisualStudioProject +{ + my ($project, $clean) = @_; + setupCygwinEnv(); + + my $config = configurationForVisualStudio(); + + chomp(my $winProjectPath = `cygpath -w "$project"`); + + my $command = "/build"; + if ($clean) { + $command = "/clean"; + } + + print "$vcBuildPath $winProjectPath /build $config\n"; + return system $vcBuildPath, $winProjectPath, $command, $config; +} + +sub qtMakeCommand($) +{ + my ($qmakebin) = @_; + chomp(my $mkspec = `$qmakebin -query QMAKE_MKSPECS`); + $mkspec .= "/default"; + + my $compiler = ""; + open SPEC, "<$mkspec/qmake.conf" or return "make"; + while (<SPEC>) { + if ($_ =~ /QMAKE_CC\s*=\s*([^\s]+)/) { + $compiler = $1; + } + } + close SPEC; + + #print "default spec: " . $mkspec . "\n"; + #print "compiler found: " . $compiler . "\n"; + + if ($compiler eq "cl") { + return "nmake"; + } + + return "make"; +} + +sub autotoolsFlag($$) +{ + my ($flag, $feature) = @_; + my $prefix = $flag ? "--enable" : "--disable"; + + return $prefix . '-' . $feature; +} + +sub buildAutotoolsProject($@) +{ + my ($clean, @buildArgs) = @_; + + my $make = 'make'; + my $dir = productDir(); + my $config = passedConfiguration() || configuration(); + my $prefix = $ENV{"WebKitInstallationPrefix"}; + + # check if configuration is Debug + if ($config =~ m/debug/i) { + push @buildArgs, "--enable-debug"; + } else { + push @buildArgs, "--disable-debug"; + } + + if (! -d $dir) { + system "mkdir", "-p", "$dir"; + if (! -d $dir) { + die "Failed to create build directory " . $dir; + } + } + + chdir $dir or die "Failed to cd into " . $dir . "\n"; + + my $result; + if ($clean) { + $result = system $make, "distclean"; + return $result; + } + + print "Calling configure in " . $dir . "\n\n"; + print "Installation directory: $prefix\n" if(defined($prefix)); + + $result = system "$sourceDir/autogen.sh", @buildArgs; + if ($result ne 0) { + die "Failed to setup build environment using 'autotools'!\n"; + } + + $result = system $make; + if ($result ne 0) { + die "\nFailed to build WebKit using '$make'!\n"; + } + + chdir ".." or die; + return $result; +} + +sub buildQMakeProject($@) +{ + my ($clean, @buildArgs) = @_; + + push @buildArgs, "-r"; + + my $qmakebin = "qmake"; # Allow override of the qmake binary from $PATH + for my $i (0 .. $#ARGV) { + my $opt = $ARGV[$i]; + if ($opt =~ /^--qmake=(.*)/i ) { + $qmakebin = $1; + } elsif ($opt =~ /^--qmakearg=(.*)/i ) { + push @buildArgs, $1; + } + } + + my $make = qtMakeCommand($qmakebin); + my $config = configuration(); + my $prefix = $ENV{"WebKitInstallationPrefix"}; + + push @buildArgs, "OUTPUT_DIR=" . baseProductDir() . "/$config"; + push @buildArgs, sourceDir() . "/WebKit.pro"; + if ($config =~ m/debug/i) { + push @buildArgs, "CONFIG-=release"; + push @buildArgs, "CONFIG+=debug"; + } else { + push @buildArgs, "CONFIG+=release"; + push @buildArgs, "CONFIG-=debug"; + } + + my $dir = baseProductDir(); + if (! -d $dir) { + system "mkdir", "-p", "$dir"; + if (! -d $dir) { + die "Failed to create product directory " . $dir; + } + } + $dir = $dir . "/$config"; + if (! -d $dir) { + system "mkdir", "-p", "$dir"; + if (! -d $dir) { + die "Failed to create build directory " . $dir; + } + } + + chdir $dir or die "Failed to cd into " . $dir . "\n"; + + print "Calling '$qmakebin @buildArgs' in " . $dir . "\n\n"; + print "Installation directory: $prefix\n" if(defined($prefix)); + + my $result = system $qmakebin, @buildArgs; + if ($result ne 0) { + die "Failed to setup build environment using $qmakebin!\n"; + } + + if ($clean) { + $result = system "$make distclean"; + } else { + $result = system "$make"; + } + + chdir ".." or die; + return $result; +} + +sub buildQMakeQtProject($$) +{ + my ($project, $clean) = @_; + + my @buildArgs = ("CONFIG+=qt-port"); + return buildQMakeProject($clean, @buildArgs); +} + +sub buildGtkProject($$@) +{ + my ($project, $clean, @buildArgs) = @_; + + if ($project ne "WebKit") { + die "The Gtk port builds JavaScriptCore, WebCore and WebKit in one shot! Only call it for 'WebKit'.\n"; + } + + if ($ENV{WEBKITAUTOTOOLS}) { + return buildAutotoolsProject($clean, @buildArgs); + } else { + my @buildArgs = ("CONFIG+=gtk-port", "CONFIG-=qt"); + return buildQMakeProject($clean, @buildArgs); + } +} + +sub setPathForRunningWebKitApp +{ + my ($env) = @_; + + return unless isCygwin(); + + $env->{PATH} = join(':', productDir(), dirname(installedSafariPath()), $env->{PATH} || ""); +} + +sub exitStatus($) +{ + my ($returnvalue) = @_; + if ($^O eq "MSWin32") { + return $returnvalue >> 8; + } + return WEXITSTATUS($returnvalue); +} + +sub runSafari +{ + my ($debugger) = @_; + + if (isOSX()) { + return system "$FindBin::Bin/gdb-safari", @ARGV if $debugger; + + my $productDir = productDir(); + print "Starting Safari with DYLD_FRAMEWORK_PATH set to point to built WebKit in $productDir.\n"; + $ENV{DYLD_FRAMEWORK_PATH} = $productDir; + $ENV{WEBKIT_UNSET_DYLD_FRAMEWORK_PATH} = "YES"; + return system safariPath(), @ARGV; + } + + if (isCygwin()) { + my $script = "run-webkit-nightly.cmd"; + my $result = system "cp", "$FindBin::Bin/$script", productDir(); + return $result if $result; + + my $cwd = getcwd(); + chdir productDir(); + + my $debuggerFlag = $debugger ? "/debugger" : ""; + $result = system "cmd", "/c", "call $script $debuggerFlag"; + chdir $cwd; + return $result; + } + + return 1; +} + +sub runDrosera +{ + my ($debugger) = @_; + + if (isOSX()) { + return system "$FindBin::Bin/gdb-drosera", @ARGV if $debugger; + + my $productDir = productDir(); + print "Starting Drosera with DYLD_FRAMEWORK_PATH set to point to built WebKit in $productDir.\n"; + $ENV{DYLD_FRAMEWORK_PATH} = $productDir; + $ENV{WEBKIT_UNSET_DYLD_FRAMEWORK_PATH} = "YES"; + + my $droseraPath = "$productDir/Drosera.app/Contents/MacOS/Drosera"; + return system $droseraPath, @ARGV; + } + + if (isCygwin()) { + print "Running Drosera\n"; + my $script = "run-drosera-nightly.cmd"; + my $prodDir = productDir(); + my $result = system "cp", "$FindBin::Bin/$script", $prodDir; + return $result if $result; + + my $cwd = getcwd(); + chdir $prodDir; + + my $debuggerFlag = $debugger ? "/debugger" : ""; + $result = system "cmd", "/c", "call $script $debuggerFlag"; + chdir $cwd; + return $result; + } + + return 1; +} + +1; diff --git a/WebKitTools/Scripts/wkstyle b/WebKitTools/Scripts/wkstyle new file mode 100755 index 0000000..690b5fa --- /dev/null +++ b/WebKitTools/Scripts/wkstyle @@ -0,0 +1,66 @@ + +# Copyright (C) 2006 Michael Emmel<mike.emmel@gmail.com> 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. + +astyle \ +--style=linux \ +--indent=spaces=4 \ +--convert-tabs \ +$@ + +#astyle does not support unpadding so we use sed +for i in $@ +do +echo $i +#first print the changes we are making +sed -n -e ' +/( .*/p +s/( /(/gp +/*. )/p +s/ )/)/gp +#supress printing this +#/^namespace WebCore/{ +#N +#s/\n{/ {/p +#} +' $i + +#do it for real +sed -e ' +#unpad leading spaces +s/( /(/g +#unpad traling spaces +s/ )/)/g +#fixup the namspec decl +/^namespace WebCore/{ +N +s/\n{/ {/ +} +' $i > $i.sed +mv $i.sed $i +done + + |