summaryrefslogtreecommitdiffstats
path: root/WebKitTools
diff options
context:
space:
mode:
authorSteve Block <steveblock@google.com>2009-12-15 10:12:09 +0000
committerSteve Block <steveblock@google.com>2009-12-17 17:41:10 +0000
commit643ca7872b450ea4efacab6188849e5aac2ba161 (patch)
tree6982576c228bcd1a7efe98afed544d840751094c /WebKitTools
parentd026980fde6eb3b01c1fe49441174e89cd1be298 (diff)
downloadexternal_webkit-643ca7872b450ea4efacab6188849e5aac2ba161.zip
external_webkit-643ca7872b450ea4efacab6188849e5aac2ba161.tar.gz
external_webkit-643ca7872b450ea4efacab6188849e5aac2ba161.tar.bz2
Merge webkit.org at r51976 : Initial merge by git.
Change-Id: Ib0e7e2f0fb4bee5a186610272edf3186f0986b43
Diffstat (limited to 'WebKitTools')
-rw-r--r--WebKitTools/BuildSlaveSupport/build.webkit.org-config/config.json37
-rw-r--r--WebKitTools/BuildSlaveSupport/build.webkit.org-config/master.cfg83
-rw-r--r--WebKitTools/ChangeLog3944
-rw-r--r--WebKitTools/DumpRenderTree/AccessibilityController.cpp9
-rw-r--r--WebKitTools/DumpRenderTree/AccessibilityUIElement.cpp174
-rw-r--r--WebKitTools/DumpRenderTree/AccessibilityUIElement.h27
-rw-r--r--WebKitTools/DumpRenderTree/GCController.cpp30
-rw-r--r--WebKitTools/DumpRenderTree/GCController.h1
-rw-r--r--WebKitTools/DumpRenderTree/LayoutTestController.cpp68
-rw-r--r--WebKitTools/DumpRenderTree/LayoutTestController.h3
-rw-r--r--WebKitTools/DumpRenderTree/TestNetscapePlugIn.subproj/PluginObject.cpp137
-rw-r--r--WebKitTools/DumpRenderTree/TestNetscapePlugIn.subproj/PluginObject.h5
-rw-r--r--WebKitTools/DumpRenderTree/TestNetscapePlugIn.subproj/main.cpp21
-rw-r--r--WebKitTools/DumpRenderTree/gtk/AccessibilityControllerGtk.cpp6
-rw-r--r--WebKitTools/DumpRenderTree/gtk/AccessibilityUIElementGtk.cpp102
-rw-r--r--WebKitTools/DumpRenderTree/gtk/DumpRenderTree.cpp65
-rw-r--r--WebKitTools/DumpRenderTree/gtk/EventSender.cpp34
-rw-r--r--WebKitTools/DumpRenderTree/gtk/LayoutTestControllerGtk.cpp35
-rw-r--r--WebKitTools/DumpRenderTree/mac/AccessibilityUIElementMac.mm156
-rw-r--r--WebKitTools/DumpRenderTree/mac/DumpRenderTree.mm35
-rw-r--r--WebKitTools/DumpRenderTree/mac/DumpRenderTreeMac.h3
-rw-r--r--WebKitTools/DumpRenderTree/mac/DumpRenderTreeWindow.h4
-rw-r--r--WebKitTools/DumpRenderTree/mac/DumpRenderTreeWindow.mm34
-rw-r--r--WebKitTools/DumpRenderTree/mac/FrameLoadDelegate.mm47
-rw-r--r--WebKitTools/DumpRenderTree/mac/LayoutTestControllerMac.mm65
-rw-r--r--WebKitTools/DumpRenderTree/mac/UIDelegate.mm12
-rw-r--r--WebKitTools/DumpRenderTree/pthreads/JavaScriptThreadingPthreads.cpp1
-rw-r--r--WebKitTools/DumpRenderTree/qt/DumpRenderTree.cpp344
-rw-r--r--WebKitTools/DumpRenderTree/qt/DumpRenderTree.h76
-rw-r--r--WebKitTools/DumpRenderTree/qt/DumpRenderTree.pro19
-rw-r--r--WebKitTools/DumpRenderTree/qt/EventSenderQt.cpp19
-rw-r--r--WebKitTools/DumpRenderTree/qt/ImageDiff.pro3
-rw-r--r--WebKitTools/DumpRenderTree/qt/LayoutTestControllerQt.cpp63
-rw-r--r--WebKitTools/DumpRenderTree/qt/LayoutTestControllerQt.h12
-rw-r--r--WebKitTools/DumpRenderTree/qt/TestNetscapePlugin/TestNetscapePlugin.pro8
-rw-r--r--WebKitTools/DumpRenderTree/qt/WorkQueue.cpp102
-rw-r--r--WebKitTools/DumpRenderTree/qt/WorkQueue.h54
-rw-r--r--WebKitTools/DumpRenderTree/qt/WorkQueueItem.h21
-rw-r--r--WebKitTools/DumpRenderTree/qt/jsobjects.cpp5
-rw-r--r--WebKitTools/DumpRenderTree/qt/main.cpp23
-rw-r--r--WebKitTools/DumpRenderTree/unix/TestNetscapePlugin/ForwardingHeaders/WebKit/npapi.h (renamed from WebKitTools/DumpRenderTree/gtk/TestNetscapePlugin/ForwardingHeaders/WebKit/npapi.h)0
-rw-r--r--WebKitTools/DumpRenderTree/unix/TestNetscapePlugin/ForwardingHeaders/WebKit/npfunctions.h (renamed from WebKitTools/DumpRenderTree/gtk/TestNetscapePlugin/ForwardingHeaders/WebKit/npfunctions.h)0
-rw-r--r--WebKitTools/DumpRenderTree/unix/TestNetscapePlugin/ForwardingHeaders/WebKit/npruntime.h (renamed from WebKitTools/DumpRenderTree/gtk/TestNetscapePlugin/ForwardingHeaders/WebKit/npruntime.h)0
-rw-r--r--WebKitTools/DumpRenderTree/unix/TestNetscapePlugin/TestNetscapePlugin.cpp (renamed from WebKitTools/DumpRenderTree/gtk/TestNetscapePlugin/TestNetscapePlugin.cpp)28
-rw-r--r--WebKitTools/DumpRenderTree/win/AccessibilityUIElementWin.cpp121
-rw-r--r--WebKitTools/DumpRenderTree/win/DRTDesktopNotificationPresenter.cpp1
-rw-r--r--WebKitTools/DumpRenderTree/win/DumpRenderTree.cpp62
-rw-r--r--WebKitTools/DumpRenderTree/win/DumpRenderTree.vcproj12
-rw-r--r--WebKitTools/DumpRenderTree/win/DumpRenderTreeWin.h3
-rw-r--r--WebKitTools/DumpRenderTree/win/FrameLoadDelegate.cpp53
-rw-r--r--WebKitTools/DumpRenderTree/win/FrameLoadDelegate.h19
-rw-r--r--WebKitTools/DumpRenderTree/win/LayoutTestControllerWin.cpp106
-rw-r--r--WebKitTools/DumpRenderTree/win/TestNetscapePlugin/main.cpp22
-rw-r--r--WebKitTools/DumpRenderTree/wscript64
-rw-r--r--WebKitTools/DumpRenderTree/wx/LayoutTestControllerWx.cpp36
-rw-r--r--WebKitTools/GNUmakefile.am12
-rw-r--r--WebKitTools/QueueStatusServer/app.yaml (renamed from WebKitTools/CommitQueueStatus/app.yaml)0
-rw-r--r--WebKitTools/QueueStatusServer/filters/__init__.py (renamed from WebKitTools/CommitQueueStatus/filters/__init__.py)0
-rw-r--r--WebKitTools/QueueStatusServer/filters/webkit_extras.py (renamed from WebKitTools/CommitQueueStatus/filters/webkit_extras.py)0
-rw-r--r--WebKitTools/QueueStatusServer/index.html (renamed from WebKitTools/CommitQueueStatus/index.html)1
-rw-r--r--WebKitTools/QueueStatusServer/index.yaml (renamed from WebKitTools/CommitQueueStatus/index.yaml)13
-rw-r--r--WebKitTools/QueueStatusServer/queue_status.py (renamed from WebKitTools/CommitQueueStatus/queue_status.py)89
-rw-r--r--WebKitTools/QueueStatusServer/status_bubble.html36
-rw-r--r--WebKitTools/QueueStatusServer/stylesheets/main.css (renamed from WebKitTools/CommitQueueStatus/stylesheets/main.css)0
-rw-r--r--WebKitTools/QueueStatusServer/update_status.html (renamed from WebKitTools/CommitQueueStatus/update_status.html)10
-rw-r--r--WebKitTools/Scripts/VCSUtils.pm258
-rwxr-xr-xWebKitTools/Scripts/bisect-builds5
-rwxr-xr-xWebKitTools/Scripts/bugzilla-tool918
-rwxr-xr-xWebKitTools/Scripts/build-webkit19
-rwxr-xr-xWebKitTools/Scripts/commit-log-editor5
-rwxr-xr-xWebKitTools/Scripts/do-webcore-rename244
-rw-r--r--WebKitTools/Scripts/modules/bugzilla.py149
-rw-r--r--WebKitTools/Scripts/modules/bugzilla_unittest.py91
-rw-r--r--WebKitTools/Scripts/modules/buildbot.py3
-rw-r--r--WebKitTools/Scripts/modules/buildsteps.py254
-rw-r--r--WebKitTools/Scripts/modules/commands/__init__.py1
-rw-r--r--WebKitTools/Scripts/modules/commands/commandtest.py42
-rw-r--r--WebKitTools/Scripts/modules/commands/download.py370
-rw-r--r--WebKitTools/Scripts/modules/commands/download_unittest.py77
-rw-r--r--WebKitTools/Scripts/modules/commands/early_warning_system.py66
-rw-r--r--WebKitTools/Scripts/modules/commands/queries.py135
-rw-r--r--WebKitTools/Scripts/modules/commands/queries_unittest.py68
-rw-r--r--WebKitTools/Scripts/modules/commands/queues.py216
-rw-r--r--WebKitTools/Scripts/modules/commands/queues_unittest.py66
-rw-r--r--WebKitTools/Scripts/modules/commands/upload.py246
-rw-r--r--WebKitTools/Scripts/modules/commands/upload_unittest.py42
-rw-r--r--WebKitTools/Scripts/modules/committers.py144
-rw-r--r--WebKitTools/Scripts/modules/committers_unittest.py24
-rw-r--r--WebKitTools/Scripts/modules/cpp_style.py179
-rw-r--r--WebKitTools/Scripts/modules/cpp_style_unittest.py146
-rw-r--r--WebKitTools/Scripts/modules/executive.py124
-rw-r--r--WebKitTools/Scripts/modules/grammar.py43
-rw-r--r--WebKitTools/Scripts/modules/landingsequence.py113
-rw-r--r--WebKitTools/Scripts/modules/logging.py36
-rw-r--r--WebKitTools/Scripts/modules/logging_unittest.py2
-rw-r--r--WebKitTools/Scripts/modules/mock.py309
-rw-r--r--WebKitTools/Scripts/modules/mock_bugzillatool.py153
-rw-r--r--WebKitTools/Scripts/modules/multicommandtool.py253
-rw-r--r--WebKitTools/Scripts/modules/multicommandtool_unittest.py158
-rw-r--r--WebKitTools/Scripts/modules/outputcapture.py53
-rw-r--r--WebKitTools/Scripts/modules/patchcollection.py71
-rw-r--r--WebKitTools/Scripts/modules/scm.py161
-rw-r--r--WebKitTools/Scripts/modules/scm_unittest.py284
-rw-r--r--WebKitTools/Scripts/modules/statusbot.py39
-rw-r--r--WebKitTools/Scripts/modules/stepsequence.py68
-rw-r--r--WebKitTools/Scripts/modules/webkitport.py118
-rw-r--r--WebKitTools/Scripts/modules/webkitport_unittest.py56
-rw-r--r--WebKitTools/Scripts/modules/workqueue.py159
-rw-r--r--WebKitTools/Scripts/modules/workqueue_unittest.py176
-rwxr-xr-xWebKitTools/Scripts/prepare-ChangeLog73
-rwxr-xr-xWebKitTools/Scripts/run-webkit-tests194
-rwxr-xr-xWebKitTools/Scripts/run-webkit-unittests7
-rwxr-xr-xWebKitTools/Scripts/run-webkit-websocketserver96
-rwxr-xr-xWebKitTools/Scripts/svn-apply52
-rwxr-xr-xWebKitTools/Scripts/svn-unapply9
-rwxr-xr-xWebKitTools/Scripts/update-webkit20
-rwxr-xr-x[-rw-r--r--]WebKitTools/Scripts/update-webkit-chromium2
-rwxr-xr-xWebKitTools/Scripts/validate-committer-lists252
-rw-r--r--WebKitTools/Scripts/webkitdirs.pm165
-rw-r--r--WebKitTools/pywebsocket/example/echo_client.py18
-rw-r--r--WebKitTools/pywebsocket/example/echo_wsh.py5
-rw-r--r--WebKitTools/pywebsocket/mod_pywebsocket/__init__.py3
-rw-r--r--WebKitTools/pywebsocket/mod_pywebsocket/dispatch.py29
-rw-r--r--WebKitTools/pywebsocket/mod_pywebsocket/msgutil.py39
-rw-r--r--WebKitTools/pywebsocket/mod_pywebsocket/standalone.py124
-rw-r--r--WebKitTools/pywebsocket/mod_pywebsocket/util.py7
-rw-r--r--WebKitTools/pywebsocket/setup.py2
-rw-r--r--WebKitTools/pywebsocket/test/test_dispatch.py21
-rw-r--r--WebKitTools/pywebsocket/test/test_msgutil.py7
-rw-r--r--WebKitTools/pywebsocket/test/test_util.py6
-rw-r--r--WebKitTools/wx/browser/wscript2
-rw-r--r--WebKitTools/wx/build/build_utils.py2
-rw-r--r--WebKitTools/wx/build/settings.py2
-rw-r--r--WebKitTools/wx/packaging/build-debian-installer.py36
-rw-r--r--WebKitTools/wx/packaging/debian/changelog1
-rw-r--r--WebKitTools/wx/packaging/debian/compat1
-rw-r--r--WebKitTools/wx/packaging/debian/control29
-rw-r--r--WebKitTools/wx/packaging/debian/copyright18
-rw-r--r--WebKitTools/wx/packaging/debian/python-webkitwx.install1
-rw-r--r--WebKitTools/wx/packaging/debian/rules75
140 files changed, 12115 insertions, 1902 deletions
diff --git a/WebKitTools/BuildSlaveSupport/build.webkit.org-config/config.json b/WebKitTools/BuildSlaveSupport/build.webkit.org-config/config.json
index 2b8faf6..69ff238 100644
--- a/WebKitTools/BuildSlaveSupport/build.webkit.org-config/config.json
+++ b/WebKitTools/BuildSlaveSupport/build.webkit.org-config/config.json
@@ -22,10 +22,14 @@
{ "name": "apple-windows-4", "platform": "win"},
{ "name": "gtk-linux-slave-1", "platform": "gtk"},
+ { "name": "gtk-linux-slave-2", "platform": "gtk"},
+ { "name": "gtk-linux-slave-3", "platform": "gtk"},
{ "name": "szeged-linux-1", "platform": "qt"},
- { "name": "google-slave-1", "platform": "chromium-win" }
+ { "name": "google-windows-1", "platform": "chromium" },
+ { "name": "google-mac-1", "platform": "chromium" },
+ { "name": "google-linux-1", "platform": "chromium" }
],
"builders": [ { "name": "Tiger Intel Release", "type": "BuildAndTest", "builddir": "tiger-intel-release",
@@ -93,14 +97,34 @@
"slavenames": ["gtk-linux-slave-1"]
},
{
+ "name": "GTK Linux 32-bit Debug", "type": "BuildAndTest", "builddir": "gtk-linux-32-debug",
+ "platform": "gtk", "configuration": "debug", "architectures": ["i386"],
+ "slavenames": ["gtk-linux-slave-2"]
+ },
+ {
+ "name": "GTK Linux 64-bit Debug", "type": "BuildAndTest", "builddir": "gtk-linux-64-debug",
+ "platform": "gtk", "configuration": "debug", "architectures": ["x86_64"],
+ "slavenames": ["gtk-linux-slave-3"]
+ },
+ {
"name": "Qt Linux Release", "type": "BuildAndTest", "builddir": "qt-linux-release",
"platform": "qt", "configuration": "release", "architectures": ["i386"],
"slavenames": ["szeged-linux-1"]
},
{
- "name": "Chromium Win Release", "type": "ChromiumBuild", "builddir": "chromium-win-release",
- "platform": "chromium-win", "configuration": "release", "architectures": ["i386"],
- "slavenames": ["google-slave-1"]
+ "name": "Chromium Win Release", "type": "Build", "builddir": "chromium-win-release",
+ "platform": "chromium", "configuration": "release", "architectures": ["i386"],
+ "slavenames": ["google-windows-1"]
+ },
+ {
+ "name": "Chromium Mac Release", "type": "Build", "builddir": "chromium-mac-release",
+ "platform": "chromium", "configuration": "release", "architectures": ["i386"],
+ "slavenames": ["google-mac-1"]
+ },
+ {
+ "name": "Chromium Linux Release", "type": "Build", "builddir": "chromium-linux-release",
+ "platform": "chromium", "configuration": "release", "architectures": ["i386"],
+ "slavenames": ["google-linux-1"]
}
],
@@ -108,8 +132,9 @@
"builderNames": ["Tiger Intel Release", "Leopard Intel Release (Build)", "Leopard Intel Debug (Build)",
"SnowLeopard Intel Release (Build)", "SnowLeopard Intel Leaks",
"Windows Release (Build)", "Windows Debug (Build)",
- "GTK Linux Release", "Qt Linux Release",
- "Chromium Win Release"]
+ "GTK Linux Release", "GTK Linux 32-bit Debug", "GTK Linux 64-bit Debug",
+ "Qt Linux Release",
+ "Chromium Win Release", "Chromium Mac Release", "Chromium Linux Release"]
},
{ "type": "Triggerable", "name": "leopard-intel-release-tests",
"builderNames": ["Leopard Intel Release (Tests)"]
diff --git a/WebKitTools/BuildSlaveSupport/build.webkit.org-config/master.cfg b/WebKitTools/BuildSlaveSupport/build.webkit.org-config/master.cfg
index 6219b0d..cd81108 100644
--- a/WebKitTools/BuildSlaveSupport/build.webkit.org-config/master.cfg
+++ b/WebKitTools/BuildSlaveSupport/build.webkit.org-config/master.cfg
@@ -48,63 +48,22 @@ class CheckOutSource(source.SVN):
source.SVN.__init__(self, baseURL=self.baseURL, defaultBranch="trunk", mode=self.mode, *args, **kwargs)
-# FIXME: Remove this step once Chromium WebKit port build system is decoupled from
-# Chromium (https://bugs.webkit.org/show_bug.cgi?id=28396)
-class UpdateChromiumSource(shell.ShellCommand):
- command = ["gclient", "sync"]
- name = "update-chromium"
- description = ["updating chromium source"]
- descriptionDone = ["updated"]
- haltOnFailure = True
-
- def createSummary(self, log):
- scraper = re.compile(r"^________ running '[^\n]+third_party[/\\]WebKit[^\n]+$\n(?:^[UA]\W+[^\n]+$\n)*^(?:Updated to|At) revision (\d+)", re.DOTALL | re.MULTILINE)
- revisions = scraper.findall(log.getText())
- gotRevision = "??" # This matches SVN unknown revision response.
- if len(revisions):
- gotRevision = "r%s" % revisions[-1]
- self.descriptionDone = ["updated", gotRevision]
-
- def start(self):
- os = self.getProperty("fullPlatform").split('-')[1]
- if os == "win":
- self.setCommand(["gclient.bat", "sync"])
- revision = self.getProperty("revision")
- if revision:
- command = self.command[:]
- command.append("--revision=src/third_party/WebKit@%d" % revision)
- self.setCommand(command)
- return shell.ShellCommand.start(self)
-
-
-# FIXME: Remove this step once Chromium WebKit port build system is decoupled from
-# Chromium (https://bugs.webkit.org/show_bug.cgi?id=28396)
-class CompileChromiumWebKit(shell.ShellCommand):
- command = ["python", "../../../scripts/slave/compile.py"]
- name = "build-chromium"
- description = ["compiling"]
- descriptionDone = ["compiled"]
- haltOnFailure = True
-
- def start(self):
- os = self.getProperty("fullPlatform").split('-')[1]
- command = self.command[:]
- if os == "win":
- command.extend(["--solution=webkit.sln", "--build-dir=src\\webkit", "--", "/project", "webcore"])
- elif os == "mac":
- command.extend(["--solution=__solution__", "--build-dir=src/build", "--", "-project", "../webkit/webkit.xcodeproj", "-target", "webcore"])
- self.setCommand(command)
- return shell.ShellCommand.start(self)
-
-
class InstallWin32Dependencies(shell.Compile):
description = ["installing dependencies"]
descriptionDone = ["installed dependencies"]
command = ["perl", "./WebKitTools/Scripts/update-webkit-auxiliary-libs"]
+class InstallChromiumDependencies(shell.ShellCommand):
+ name = "gclient"
+ description = ["updating chromium dependencies"]
+ descriptionDone = ["updated chromium dependencies"]
+ command = ["perl", "./WebKitTools/Scripts/update-webkit-chromium"]
+ haltOnFailure = True
+
+
def appendCustomBuildFlags(step, platform):
- if platform in ('gtk', 'wx', 'qt'):
+ if platform in ('gtk', 'wx', 'qt', 'chromium'):
step.setCommand(step.command + ['--' + platform])
@@ -215,7 +174,7 @@ class RunWebKitTests(shell.Test):
descriptionDone = ["layout-tests"]
command = ["perl", "./WebKitTools/Scripts/run-webkit-tests", "--no-launch-safari", "--no-new-test-results",
"--no-sample-on-timeout", "--results-directory", "layout-test-results", "--use-remote-links-to-tests",
- WithProperties("--%(configuration)s")]
+ WithProperties("--%(configuration)s"), "--exit-after-n-failures", "20"]
def __init__(self, skipBuild=False, *args, **kwargs):
self.skipBuild = skipBuild
@@ -240,6 +199,8 @@ class RunWebKitTests(shell.Test):
incorrectLayoutLines.append(line)
elif line.startswith("WARNING:") and line.find(' leak') >= 0:
incorrectLayoutLines.append(line.replace('WARNING: ', ''))
+ elif line.find('Exiting early') >= 0:
+ incorrectLayoutLines.append(line)
# FIXME: Detect and summarize leaks of RefCounted objects
@@ -318,23 +279,17 @@ class Factory(factory.BuildFactory):
self.addStep(CheckOutSource)
if platform == "win":
self.addStep(InstallWin32Dependencies)
-
-# FIXME: Remove this factory once Chromium WebKit port build system is decoupled from
-# Chromium (https://bugs.webkit.org/show_bug.cgi?id=28396)
-class ChromiumBuildFactory(factory.BuildFactory):
- def __init__(self, platform, configuration, architectures):
- factory.BuildFactory.__init__(self)
- self.addStep(ConfigureBuild, platform=platform, configuration=configuration, architecture=" ".join(architectures), buildOnly=True)
- self.addStep(UpdateChromiumSource)
- self.addStep(CompileChromiumWebKit)
+ if platform == "chromium":
+ self.addStep(InstallChromiumDependencies)
class BuildFactory(Factory):
- def __init__(self, platform, configuration, architectures, triggers):
+ def __init__(self, platform, configuration, architectures, triggers=None):
Factory.__init__(self, platform, configuration, architectures, True)
self.addStep(CompileWebKit)
- self.addStep(ArchiveBuiltProduct)
- self.addStep(UploadBuiltProduct)
- self.addStep(trigger.Trigger, schedulerNames=triggers)
+ if triggers:
+ self.addStep(ArchiveBuiltProduct)
+ self.addStep(UploadBuiltProduct)
+ self.addStep(trigger.Trigger, schedulerNames=triggers)
class TestFactory(Factory):
def __init__(self, platform, configuration, architectures):
diff --git a/WebKitTools/ChangeLog b/WebKitTools/ChangeLog
index 7dcbf6c..c55009d 100644
--- a/WebKitTools/ChangeLog
+++ b/WebKitTools/ChangeLog
@@ -1,3 +1,3947 @@
+2009-12-10 Eric Seidel <eric@webkit.org>
+
+ No review, just updating unit tests to match recent checkins.
+
+ * Scripts/modules/mock_bugzillatool.py:
+ - Add missing red_core_builders_names method causing exception.
+ * Scripts/modules/workqueue_unittest.py:
+ - processutils is dead, use executive.py instead.
+
+2009-12-10 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Move run_command onto Executive to make code which uses run_command testable
+ https://bugs.webkit.org/show_bug.cgi?id=32396
+
+ * Scripts/modules/executive.py:
+ - Move run_command and error handlers onto Executive.
+ * Scripts/modules/scm.py:
+ * Scripts/modules/scm_unittest.py:
+
+2009-12-09 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ bugzilla-tool needs a command to list patches needing cq+
+ https://bugs.webkit.org/show_bug.cgi?id=32351
+
+ * Scripts/modules/bugzilla.py:
+ - Parse attacher_email from attachment xml.
+ * Scripts/modules/bugzilla_unittest.py:
+ - Test new attacher_email parsing.
+ * Scripts/modules/commands/queries.py:
+ - Add PatchesToCommitQueue
+ * Scripts/modules/commands/queries_unittest.py:
+ - Tests for PatchesToCommitQueue
+ * Scripts/modules/mock_bugzillatool.py:
+ - Add necessary mock methods for running PatchesToCommitQueue
+
+2009-12-10 Adam Barth <abarth@webkit.org>
+
+ Unreviewed. Turns out every StepSequence command needs a --quiet
+ option.
+
+ * Scripts/modules/stepsequence.py:
+
+2009-12-10 Eric Z. Ayers <zundel@google.com>
+
+ Reviewed by Pavel Feldman.
+
+ Implements displayWebView() to force an invalidation and repaint.
+ This fixes a problem running the timeline-paint.html unit test.
+
+ https://bugs.webkit.org/show_bug.cgi?id=31729
+
+ * DumpRenderTree/gtk/DumpRenderTree.cpp:
+ (displayWebView):
+
+2009-12-10 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ [bzt] Convert more commands to StepSequences
+ https://bugs.webkit.org/show_bug.cgi?id=32362
+
+ We should eventually convert all the commands, but I'm starting with
+ the easy ones.
+
+ * Scripts/modules/commands/download.py:
+
+2009-12-10 Xan Lopez <xlopez@igalia.com>
+
+ Reviewed by Jan Alonzo.
+
+ [GTK] editing/selection/shrink-selection-after-shift-pagedown.html failing
+ https://bugs.webkit.org/show_bug.cgi?id=31103
+
+ Give focus to the webviews when we create them, since some tests expect this.
+
+ * DumpRenderTree/gtk/DumpRenderTree.cpp:
+ (main):
+
+2009-12-10 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ bugzilla-tool "builders are red" error should tell you which builders
+ https://bugs.webkit.org/show_bug.cgi?id=32211
+
+ * Scripts/modules/buildsteps.py:
+
+2009-12-09 Marwan Al Jubeh <marwan.aljubeh@gmail.com>
+
+ Reviewed by Adam Roben.
+
+ Fixes: https://bugs.webkit.org/show_bug.cgi?id=31228
+ Set the WebKitOutputDir, WebKitLibrariesDir and Cygwin environment variables automatically
+ in Windows as part of running update_webkit.
+
+ * Scripts/update-webkit:
+ - Run setupAppleWinEnv() on Apple's Windows port.
+ * Scripts/webkitdirs.pm:
+ - Added functions that return the source directory, libraries directory and default build directory on Windows.
+ - Added isWindowsNT() which tests if the current Windows version is from the Windows NT family.
+ - Implemented setupAppleWinEnv() which sets the environment variables WebKitOutputDir, WebKitLibrariesDir
+ and Cygwin to their desired values.
+
+2009-12-09 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ exception thrown when running apply-patches
+ https://bugs.webkit.org/show_bug.cgi?id=32344
+
+ The update step now takes a port option. Once we finish the Steps
+ refactoring, we won't have to worry about this kind of bug again.
+
+ * Scripts/modules/commands/download.py:
+
+2009-12-09 Adam Barth <abarth@webkit.org>
+
+ Unreviewed. Fix ScriptError includes. I don't understand why these
+ didn't throw during unit testing...
+
+ * Scripts/modules/commands/download.py:
+ * Scripts/modules/logging_unittest.py:
+ * Scripts/modules/workqueue.py:
+
+2009-12-09 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ [bzt] Remove unused PatchCollection class
+ https://bugs.webkit.org/show_bug.cgi?id=32312
+
+ It's dead code.
+
+ * Scripts/modules/patchcollection.py:
+ * Scripts/modules/patchcollection_unittest.py: Removed.
+
+2009-12-09 Adam Barth <abarth@webkit.org>
+
+ Unreviewed "build" fix. CheckStyle needs a --no-upate option.
+
+ * Scripts/modules/commands/download.py:
+
+2009-12-09 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ [bzt] Convert Build to use Sequence
+ https://bugs.webkit.org/show_bug.cgi?id=32310
+
+ So much prettier.
+
+ * Scripts/modules/buildsteps.py:
+ * Scripts/modules/commands/download.py:
+ * Scripts/modules/landingsequence.py:
+ * Scripts/modules/stepsequence.py: Added.
+
+2009-12-09 Adam Barth <abarth@webkit.org>
+
+ Add missing file.
+
+ * Scripts/modules/executive.py: Added.
+
+2009-12-09 Adam Barth <abarth@webkit.org>
+
+ Unreviewed "build" fix.
+
+ * Scripts/modules/landingsequence.py:
+
+2009-12-09 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ [bzt] Implement abstract Steps
+ https://bugs.webkit.org/show_bug.cgi?id=32212
+
+ This is a fairly disruptive change that refactors how we build
+ commands. Instead of using a landing sequence, we can now assemble a
+ sequence of steps directly. We still use the landing sequence in the
+ interim, but this will be removed soon.
+
+ * Scripts/bugzilla-tool:
+ * Scripts/modules/buildsteps.py:
+ * Scripts/modules/commands/download.py:
+ * Scripts/modules/commands/early_warning_system.py:
+ * Scripts/modules/commands/queues.py:
+ * Scripts/modules/commands/queues_unittest.py:
+ * Scripts/modules/landingsequence.py:
+ * Scripts/modules/mock_bugzillatool.py:
+ * Scripts/modules/processutils.py: Removed.
+ * Scripts/modules/scm.py:
+ * Scripts/modules/scm_unittest.py:
+ * Scripts/modules/webkitport.py:
+
+2009-12-08 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ run_command and ScriptError should move into processutils.py
+ https://bugs.webkit.org/show_bug.cgi?id=32305
+
+ Turns out there are a zillion callers to run_command.
+
+ * Scripts/modules/commands/download.py:
+ * Scripts/modules/commands/early_warning_system.py:
+ * Scripts/modules/commands/queues.py:
+ * Scripts/modules/landingsequence.py:
+ * Scripts/modules/logging_unittest.py:
+ * Scripts/modules/processutils.py:
+ * Scripts/modules/scm.py:
+ * Scripts/modules/scm_unittest.py:
+ * Scripts/modules/workqueue.py:
+ * Scripts/modules/workqueue_unittest.py:
+
+2009-12-08 Kevin Watters <kevinwatters@gmail.com>
+
+ Reviewed by Kevin Ollivier.
+
+ [wx] Mac plugins support.
+
+ https://bugs.webkit.org/show_bug.cgi?id=32236
+
+ * wx/browser/wscript:
+
+2009-12-08 David Levin <levin@chromium.org>
+
+ Reviewed by Adam Barth.
+
+ [check-webkit-style] False positive for DEFINE_OPCODE(op_jtrue) {
+ https://bugs.webkit.org/show_bug.cgi?id=32193
+
+ * Scripts/modules/cpp_style.py: For the function { rule, if there is space
+ at the beginning of line, ignore lines which then have a macro.
+ * Scripts/modules/cpp_style_unittest.py: Add tests to verify the
+ new behavior.
+
+2009-12-08 Dmitry Titov <dimich@chromium.org>
+
+ Rubber-stamped by David Levin.
+
+ Revert and reopen "Add asserts to RefCounted to make sure ref/deref happens on the right thread."
+ It may have caused massive increase of reported leaks on the bots.
+ https://bugs.webkit.org/show_bug.cgi?id=31639
+
+ * DumpRenderTree/ForwardingHeaders/wtf/ThreadVerifier.h: Removed.
+
+2009-12-08 Dmitry Titov <dimich@chromium.org>
+
+ Reviewed by Darin Adler.
+
+ Add asserts to RefCounted to make sure ref/deref happens on the right thread.
+ https://bugs.webkit.org/show_bug.cgi?id=31639
+
+ * DumpRenderTree/ForwardingHeaders/wtf/ThreadVerifier.h: Added.
+
+2009-12-08 David Levin <levin@chromium.org>
+
+ Reviewed by Adam Barth.
+
+ [check-webkit-style] False positive for camel case of JSC op codes
+ https://bugs.webkit.org/show_bug.cgi?id=32192
+
+ * Scripts/modules/cpp_style.py: Added an exception for the JSC op
+ code functions and const_iterator as well since I noticed a false
+ positive there when testing the fix.
+ * Scripts/modules/cpp_style_unittest.py: Added tests for these
+ changes.
+
+2009-12-08 Nikolas Zimmermann <nzimmermann@rim.com>
+
+ Rubber-stamped by Maciej Stachowiak.
+
+ Turn on (SVG) Filters for Win.
+ https://bugs.webkit.org/show_bug.cgi?id=32224
+
+ * Scripts/webkitdirs.pm:
+
+2009-12-08 Nikolas Zimmermann <nzimmermann@rim.com>
+
+ Rubber-stamped by Maciej Stachowiak.
+
+ Turn on (SVG) Filters for Gtk.
+ https://bugs.webkit.org/show_bug.cgi?id=32224
+
+ * Scripts/build-webkit:
+
+2009-12-07 Shinichiro Hamaji <hamaji@chromium.org>
+
+ Reviewed by David Levin.
+
+ [check-webkit-style] S_OK is a fine identifier
+ https://bugs.webkit.org/show_bug.cgi?id=32225
+
+ * Scripts/modules/cpp_style.py:
+ * Scripts/modules/cpp_style_unittest.py:
+
+2009-12-07 Nikolas Zimmermann <nzimmermann@rim.com>
+
+ Rubber-stamped by Maciej Stachowiak.
+
+ Turn on (SVG) Filters for Qt.
+ https://bugs.webkit.org/show_bug.cgi?id=32224
+
+ * Scripts/build-webkit:
+
+2009-12-07 Yuzo Fujishima <yuzo@google.com>
+
+ Reviewed by Alexey Proskuryakov.
+
+ Make run-webkit-websocketserver log to stderr rather than to a file.
+ https://bugs.webkit.org/show_bug.cgi?id=32234
+
+ * Scripts/run-webkit-websocketserver:
+
+2009-12-07 Dmitry Titov <dimich@chromium.org>
+
+ Rubber-stamped by Darin Adler.
+
+ Remove ENABLE_SHARED_SCRIPT flags
+ https://bugs.webkit.org/show_bug.cgi?id=32245
+ This patch was obtained by "git revert" command and then un-reverting of ChangeLog files.
+
+ * Scripts/build-webkit:
+
+2009-12-07 Simon Fraser <simon.fraser@apple.com>
+
+ Reviewed by Darin Adler.
+
+ <rdar://problem/7450481> One compositing test keeps DRT in "compositing mode", breaks repaint tests
+
+ The counter that WebView used to keep track of the number of enclosed WebHTMLViews using
+ accelerated compositing was hard to manage, and maintained incorrectly in a number of cases.
+ This caused one compositing test make DumpRenderTree think that all subsequent tests
+ were compositing too.
+
+ Replace this counter with notifications, which are only fired if a client (DRT) requests them. The
+ notification informs the client that a WebHTMLView entered compositing mode (or an already-
+ compositing WebHTML was added); it does not say when a view becomes uncomposited, or all
+ compositing subviews were removed, since this is tricky to get right.
+
+ DumpRenderTreeWindow listens for this notification, and uses it to turn on window
+ autodisplay, which is necessary to kick-start Core Animation rendering and animations.
+ We ensure that window autodisplay is turned off before every test.
+
+ * DumpRenderTree/mac/DumpRenderTree.mm:
+ (createWebViewAndOffscreenWindow):
+ (resetWebViewToConsistentStateBeforeTesting):
+ * DumpRenderTree/mac/DumpRenderTreeWindow.h:
+ * DumpRenderTree/mac/DumpRenderTreeWindow.mm:
+ (-[DumpRenderTreeWindow close]):
+ (-[DumpRenderTreeWindow startListeningForAcceleratedCompositingChanges]):
+ (-[DumpRenderTreeWindow webViewStartedAcceleratedCompositing:]):
+
+2009-12-07 Nikolas Zimmermann <nzimmermann@rim.com>
+
+ Reviewed by Holger Hans Peter Freyther.
+
+ Turn on (SVG) Filters support, by default.
+ https://bugs.webkit.org/show_bug.cgi?id=32224
+
+ For now only enable FILTERS build flag on WebKit/mac. Other platforms will follow soon.
+
+ * Scripts/build-webkit:
+
+2009-12-07 Yaar Schnitman <yaar@chromium.org>
+
+ Reviewed by Darin Fisher.
+
+ Chromium buildbots are not red when they fail
+ https://bugs.webkit.org/show_bug.cgi?id=32235
+
+ * Scripts/build-webkit:
+
+2009-12-07 Yaar Schnitman <yaar@chromium.org>
+
+ Reviewed by Darin Fisher.
+
+ Typo in chromium linux builder
+ https://bugs.webkit.org/show_bug.cgi?id=32238
+
+ * Scripts/webkitdirs.pm:
+
+2009-12-07 Yaar Schnitman <yaar@chromium.org>
+
+ Reviewed by Darin Fisher.
+
+ fixes to build-webkit --chromium
+ https://bugs.webkit.org/show_bug.cgi?id=32179
+
+ * Scripts/webkitdirs.pm:
+
+2009-12-07 Eric Seidel <eric@webkit.org>
+
+ No review, just adding two recently approved committers.
+
+ * Scripts/modules/committers.py:
+
+2009-12-07 Alexey Proskuryakov <ap@apple.com>
+
+ * Scripts/run-webkit-websocketserver: Added property svn:executable.
+
+2009-12-07 Yuzo Fujishima <yuzo@google.com>
+
+ Reviewed by Alexey Proskuryakov.
+
+ Add run-webkit-websocketserver
+
+ https://bugs.webkit.org/show_bug.cgi?id=31390
+
+ * Scripts/run-webkit-websocketserver: Added.
+
+2009-12-07 Steve Falkenburg <sfalken@apple.com>
+
+ Build fix. Be flexible about which version of ICU is used on Windows.
+
+ * DumpRenderTree/win/DumpRenderTree.vcproj: Add optional xcopy commands to copy ICU 4.2.
+
+2009-12-07 Dirk Schulze <krit@webkit.org>
+
+ Not reviewed, adding myself to the reviewers list.
+
+ * Scripts/modules/committers.py:
+
+2009-12-06 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Add an API for uploading results files to StatusBot
+ https://bugs.webkit.org/show_bug.cgi?id=32210
+
+ Add Content-Type: plain/text which was forgotten
+ from the previous commit when I landed with land-patches
+ instead of land-diff.
+
+ * QueueStatusServer/queue_status.py:
+
+2009-12-06 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Status Server needs a way to handle uploaded results
+ https://bugs.webkit.org/show_bug.cgi?id=32209
+
+ * QueueStatusServer/queue_status.py: Add a ShowResults (results/*) command
+ * QueueStatusServer/update_status.html: Add file upload.
+
+2009-12-06 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Add an API for uploading results files to StatusBot
+ https://bugs.webkit.org/show_bug.cgi?id=32210
+
+ * Scripts/modules/statusbot.py:
+
+2009-12-06 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Status Server needs a way to handle uploaded results
+ https://bugs.webkit.org/show_bug.cgi?id=32209
+
+ * QueueStatusServer/queue_status.py: Add a ShowResults (results/*) command
+ * QueueStatusServer/update_status.html: Add file upload.
+
+2009-12-06 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ [bzt] BuildAttachment should not check the builders
+ https://bugs.webkit.org/show_bug.cgi?id=32207
+
+ This is code that got copied here by accident when the class was created.
+
+ * Scripts/modules/commands/download.py:
+
+2009-12-06 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ [bzt] Make LandingSequence.update aware of ports
+ https://bugs.webkit.org/show_bug.cgi?id=32208
+
+ This is required to make build work on the Chromium port because
+ Chromium has a custom update-webkit.
+
+ * Scripts/modules/landingsequence.py:
+
+2009-12-06 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Add early warning system commands to bugzilla-tool.
+
+ * Scripts/bugzilla-tool:
+ * Scripts/modules/landingsequence.py:
+ * Scripts/modules/webkitport.py:
+
+2009-12-06 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ [bzt] Implement Qt EarlyWarningSystem and Chromium EarlyWarningSystem
+ https://bugs.webkit.org/show_bug.cgi?id=32205
+
+ * Scripts/modules/commands/early_warning_system.py: Added.
+ * Scripts/modules/commands/queues.py:
+
+2009-12-06 Dan Bernstein <mitz@apple.com>
+
+ Reviewed by Adele Peterson.
+
+ REGRESSION (r51728): update-webkit fails when the current directory is
+ not inside a Subversion working copy
+ https://bugs.webkit.org/show_bug.cgi?id=32204
+
+ * Scripts/update-webkit: Invoke isSVN() in the correct working
+ directory.
+
+2009-12-06 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ [bzt] Rename AbstractTryQueue to AbstractReviewQueue
+ https://bugs.webkit.org/show_bug.cgi?id=32202
+
+ * Scripts/modules/commands/queues.py:
+
+2009-12-05 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ [bzt] Implement ChromiumPort
+ https://bugs.webkit.org/show_bug.cgi?id=32182
+
+ * Scripts/modules/webkitport.py:
+ * Scripts/modules/webkitport_unittest.py:
+
+2009-12-05 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Move update-webkit into BuildSteps
+ https://bugs.webkit.org/show_bug.cgi?id=32181
+
+ We need to move update-webkit out of SCM.py because SCM isn't supposed to know
+ that WebKit exists. The proper place for the knowledge of the existence of
+ update-webkit is in WebKitPort because some ports have specialized update
+ scripts (analogous to build-webkit).
+
+ * Scripts/modules/buildsteps.py:
+ * Scripts/modules/commands/download.py:
+ * Scripts/modules/landingsequence.py:
+ * Scripts/modules/scm.py:
+ * Scripts/modules/webkitport.py:
+
+2009-12-05 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ update-webkit should call git svn rebase and resolve-ChangeLogs -f
+ https://bugs.webkit.org/show_bug.cgi?id=27162
+
+ Teach update-webkit about Git. I didn't add the call to
+ resolve-ChangeLogs -f because sometimes that script goes bananas. We
+ can iterate from here, however.
+
+ * Scripts/update-webkit:
+
+2009-12-04 Yael Aharon <yael.aharon@nokia.com>
+
+ Unreviewed build fix.
+
+ [Qt] build fix after r51634 removed unused QBoxLayout include which included limits.h.
+
+ * DumpRenderTree/qt/DumpRenderTree.cpp:
+
+2009-12-04 Kenneth Rohde Christiansen <kenneth@webkit.org>
+
+ Reviewed by Adam Treat.
+
+ Add some missing methods for showing and hiding the
+ Web Inspector.
+
+ * DumpRenderTree/qt/DumpRenderTree.cpp:
+ (WebCore::WebPage::WebPage):
+ (WebCore::WebPage::~WebPage):
+ (WebCore::WebPage::webInspector):
+ * DumpRenderTree/qt/DumpRenderTree.h:
+ * DumpRenderTree/qt/LayoutTestControllerQt.cpp:
+ (LayoutTestController::showWebInspector):
+ (LayoutTestController::hideWebInspector):
+ * DumpRenderTree/qt/LayoutTestControllerQt.h:
+
+2009-12-04 Kenneth Rohde Christiansen <kenneth@webkit.org>
+
+ Reviewed by Adam Treat.
+
+ Implement the setAllowUniversalAccessFromFileURLs method
+ for the Qt LayoutTestController.
+
+ * DumpRenderTree/qt/DumpRenderTree.cpp:
+ (WebCore::WebPage::resetSettings):
+ * DumpRenderTree/qt/LayoutTestControllerQt.cpp:
+ (LayoutTestController::setAllowUniversalAccessFromFileURLs):
+ * DumpRenderTree/qt/LayoutTestControllerQt.h:
+
+2009-12-04 Chris Fleizach <cfleizach@apple.com>
+
+ Reviewed by Darin Adler.
+
+ REGRESSION: AX: buttons now extremely repetitive
+ https://bugs.webkit.org/show_bug.cgi?id=32164
+
+ * DumpRenderTree/AccessibilityUIElement.cpp:
+ (isAttributeSupportedCallback):
+ (AccessibilityUIElement::getJSClass):
+ * DumpRenderTree/AccessibilityUIElement.h:
+ * DumpRenderTree/gtk/AccessibilityUIElementGtk.cpp:
+ (AccessibilityUIElement::isAttributeSupported):
+ * DumpRenderTree/mac/AccessibilityUIElementMac.mm:
+ (AccessibilityUIElement::isAttributeSupported):
+ * DumpRenderTree/win/AccessibilityUIElementWin.cpp:
+ (AccessibilityUIElement::isAttributeSupported):
+
+2009-12-03 Shinichiro Hamaji <hamaji@chromium.org>
+
+ Reviewed by David Levin.
+
+ check-webkit-style should check for camelCase variable names
+ https://bugs.webkit.org/show_bug.cgi?id=32051
+
+ * Scripts/modules/cpp_style.py:
+ * Scripts/modules/cpp_style_unittest.py:
+
+2009-12-03 Chris Fleizach <cfleizach@apple.com>
+
+ Reviewed by Eric Seidel.
+
+ AX: VO just says "term" on many web sites
+ https://bugs.webkit.org/show_bug.cgi?id=32139
+
+ * DumpRenderTree/AccessibilityUIElement.cpp:
+ (getRoleDescriptionCallback):
+ (AccessibilityUIElement::getJSClass):
+ * DumpRenderTree/AccessibilityUIElement.h:
+ * DumpRenderTree/gtk/AccessibilityUIElementGtk.cpp:
+ (AccessibilityUIElement::roleDescription):
+ * DumpRenderTree/mac/AccessibilityUIElementMac.mm:
+ (AccessibilityUIElement::roleDescription):
+ * DumpRenderTree/win/AccessibilityUIElementWin.cpp:
+ (AccessibilityUIElement::roleDescription):
+
+2009-12-03 Chris Fleizach <cfleizach@apple.com>
+
+ Reviewed by Beth Dakin.
+
+ Implement WAI-ARIA scrollbar role and related property aria-orientation
+ https://bugs.webkit.org/show_bug.cgi?id=32126
+
+ * DumpRenderTree/AccessibilityUIElement.cpp:
+ (getOrientationCallback):
+ (AccessibilityUIElement::getJSClass):
+ * DumpRenderTree/AccessibilityUIElement.h:
+ * DumpRenderTree/gtk/AccessibilityUIElementGtk.cpp:
+ (AccessibilityUIElement::orientation):
+ * DumpRenderTree/mac/AccessibilityUIElementMac.mm:
+ (AccessibilityUIElement::orientation):
+ * DumpRenderTree/win/AccessibilityUIElementWin.cpp:
+ (AccessibilityUIElement::orientation):
+
+2009-12-03 Eric Carlson <eric.carlson@apple.com>
+
+ Reviewed by Adam Roben.
+
+ Minor correction to r51663.
+
+ * DumpRenderTree/win/DumpRenderTree.cpp:
+ (addQTDirToPATH):
+ GetEnvironmentVariable -> GetEnvironmentVariableW.
+
+2009-12-03 Eric Carlson <eric.carlson@apple.com>
+
+ Reviewed by Adam Roben.
+
+ ~96 regression tests fail when using QuickTime 7.6 (they pass with QuickTime 7.3)
+ https://bugs.webkit.org/show_bug.cgi?id=30256
+
+ Add the QuickTime dll directory to the PATH environment variable so
+ inialization can succeed.
+
+ * DumpRenderTree/win/DumpRenderTree.cpp:
+ (addQTDirToPATH):
+ (initialize):
+
+2009-12-03 Shu Chang <Chang.Shu@nokia.com>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ [Qt] After revision 32643, sender() is of type QWebPage instead of QWebFrame.
+
+ * DumpRenderTree/qt/LayoutTestControllerQt.cpp:
+ (LayoutTestController::maybeDump):
+
+2009-12-03 Yuzo Fujishima <yuzo@google.com>
+
+ Reviewed by Eric Seidel.
+
+ Update pywebsocket to 0.4.3
+ This version logs friendlier and higher-level messages in WARN level, which is used for LayoutTests.
+ Stack trace is logged now in INFO level.
+ https://bugs.webkit.org/show_bug.cgi?id=32097
+
+ * pywebsocket/mod_pywebsocket/dispatch.py:
+ * pywebsocket/mod_pywebsocket/msgutil.py:
+ * pywebsocket/mod_pywebsocket/standalone.py:
+ * pywebsocket/mod_pywebsocket/util.py:
+ * pywebsocket/setup.py:
+ * pywebsocket/test/test_dispatch.py:
+ * pywebsocket/test/test_util.py:
+
+2009-12-03 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Gavin Barraclough.
+
+ Fix JSClassRef leak.
+
+ * DumpRenderTree/AccessibilityController.cpp:
+ (AccessibilityController::makeWindowObject):
+ * DumpRenderTree/GCController.cpp:
+ (GCController::makeWindowObject):
+ * DumpRenderTree/LayoutTestController.cpp:
+ (LayoutTestController::makeWindowObject):
+
+2009-12-03 Brady Eidson <beidson@apple.com>
+
+ Reviewed by Sam Weinig.
+
+ <rdar://problem/7214236> and http://webkit.org/b/32052 - Implement HTML5 state object history API
+
+ Keep DRT-win building...
+
+ * DumpRenderTree/win/FrameLoadDelegate.h:
+ (FrameLoadDelegate::didPushStateWithinPageForFrame):
+ (FrameLoadDelegate::didReplaceStateWithinPageForFrame):
+ (FrameLoadDelegate::didPopStateWithinPageForFrame):
+
+2009-12-03 Andras Becsi <abecsi@inf.u-szeged.hu>
+
+ Unreviewed build fix.
+
+ [Qt] ARM-Linux build fix after r51634 removed unused QBoxLayout include which included limits.h on ARM.
+
+ * DumpRenderTree/qt/DumpRenderTree.cpp:
+
+2009-12-03 Andras Becsi <abecsi@inf.u-szeged.hu>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ [Qt] Refactor DRT to not crash on tests which open child windows from javascript.
+ Prevent DRT from showing the main view if these childs get deleted.
+ This fixes https://bugs.webkit.org/show_bug.cgi?id=31591.
+
+ * DumpRenderTree/qt/DumpRenderTree.cpp:
+ (WebCore::WebPage::WebPage):
+ (WebCore::DumpRenderTree::DumpRenderTree):
+ (WebCore::DumpRenderTree::~DumpRenderTree):
+ (WebCore::DumpRenderTree::resetToConsistentStateBeforeTesting):
+ (WebCore::DumpRenderTree::open):
+ (WebCore::DumpRenderTree::closeRemainingWindows):
+ (WebCore::DumpRenderTree::createWindow):
+ (WebCore::DumpRenderTree::windowCount):
+ * DumpRenderTree/qt/DumpRenderTree.h:
+
+2009-12-02 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ REGRESSION(51595): commit-queue is throwing exceptions
+ https://bugs.webkit.org/show_bug.cgi?id=32083
+
+ * Scripts/modules/commands/queues.py:
+ - Don't use default value of [] as it ends up getting shared.
+ - Make log_progress accept arrays of ints as well as strings.
+ - Return an exit code from execute()
+ * Scripts/modules/commands/queues_unittest.py: Added.
+ - Test to make sure log_progress will accept ints.
+ - Test to make sure run_bugzilla_tool will accept ints.
+ * Scripts/modules/workqueue.py:
+ - Print the stack trace on unexpected exceptions for easier debugging.
+ * Scripts/run-webkit-unittests:
+ - Add queues_unittest.
+
+ * Scripts/modules/commands/queues.py:
+ * Scripts/modules/commands/queues_unittest.py: Copied from WebKitTools/Scripts/modules/commands/commandtest.py.
+ * Scripts/modules/mock_bugzillatool.py:
+ * Scripts/modules/workqueue.py:
+ * Scripts/run-webkit-unittests:
+
+2009-12-02 David Levin <levin@chromium.org>
+
+ Reviewed by Adam Barth.
+
+ check-webkit-style is too noisy about namespace indenting issues.
+ https://bugs.webkit.org/show_bug.cgi?id=32096
+
+ * Scripts/modules/cpp_style.py:
+ Added a _FileState object to be able to track file level information. In this
+ case, it simply tracks whether the error has already been given, so that it isn't
+ done again.
+ * Scripts/modules/cpp_style_unittest.py:
+ Modified test cases to pass in the _FileState object and fix a test that expected
+ to see the namespace error twice (now it only occurs once). No new tests because
+ existing tests cover the change in functionality.
+
+2009-12-01 Kevin Ollivier <kevino@theolliviers.com>
+
+ Reviewed by Eric Seidel.
+
+ [wx] Get DumpRenderTree building after waf switch.
+
+ https://bugs.webkit.org/show_bug.cgi?id=32041
+
+ * DumpRenderTree/wscript: Added.
+ * DumpRenderTree/wx/LayoutTestControllerWx.cpp:
+ (LayoutTestController::setTimelineProfilingEnabled):
+ (LayoutTestController::evaluateScriptInIsolatedWorld):
+ (LayoutTestController::disableImageLoading):
+ (LayoutTestController::whiteListAccessFromOrigin):
+ (LayoutTestController::counterValueForElementById):
+ * Scripts/build-webkit:
+
+2009-12-02 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ [bzt] build-attachment shouldn't check whether the builders are red
+ https://bugs.webkit.org/show_bug.cgi?id=32062
+
+ build-attachment doesn't touch the remote repository, so there isn't a
+ need to hold off when the builders are red.
+
+ * Scripts/modules/commands/download.py:
+ * Scripts/modules/landingsequence.py:
+
+2009-12-02 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ REGRESSION(51590): style-queue and build-queue think their empty when they are not
+ https://bugs.webkit.org/show_bug.cgi?id=32061
+
+ * Scripts/modules/bugzilla.py: make all id lookups return ints instead of strings.
+ * Scripts/modules/bugzilla_unittest.py: Add and update unit tests to use ints.
+
+2009-12-02 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ build-queue is throwing exceptions and complaining about
+ lack of --no-update on build-attachment. Make it stop.
+
+ * Scripts/modules/buildsteps.py:
+ * Scripts/modules/commands/download.py:
+
+2009-12-02 Adam Barth <abarth@webkit.org>
+
+ Unreviewed "build" fix. Forgot to declare my variables. :(
+
+ * QueueStatusServer/queue_status.py:
+
+2009-12-02 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ [bzt] Implement status bubble view
+ https://bugs.webkit.org/show_bug.cgi?id=32057
+
+ The status bubble is a compact representation of the queue status for a
+ given patch. This will eventually help us reduce the comment spam from
+ the queues.
+
+ * QueueStatusServer/index.html: Added HTML5 doctype for sanity.
+ * QueueStatusServer/queue_status.py:
+ * QueueStatusServer/status_bubble.html: Added.
+
+2009-12-02 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ trim commands/*.py includes now that commands are unit tested
+ https://bugs.webkit.org/show_bug.cgi?id=32056
+
+ In the course of ensuring that the unit tests still
+ passed after this change, I had to actually make them
+ pass in the first place.
+
+ * Scripts/modules/bugzilla.py:
+ - Fix _parse_attachment_ids_request_query to return ints instead of strings.
+ * Scripts/modules/commands/download.py: Remove unneeded imports.
+ * Scripts/modules/commands/queries.py: Ditto.
+ * Scripts/modules/commands/queues.py: Ditto.
+ * Scripts/modules/commands/upload.py: Ditto.
+ * Scripts/modules/scm_unittest.py:
+ - Fix to expect the \n after the path since echo adds an \n.
+
+2009-12-01 Yaar Schnitman <yaar@chromium.org>
+
+ build-webkit: Remove flex,bison,gperf check for chromium
+ https://bugs.webkit.org/show_bug.cgi?id=32043
+
+ * Scripts/webkitdirs.pm:
+
+2009-12-01 Chris Fleizach <cfleizach@apple.com>
+
+ Build fixage for Windows/GTK for DumpRenderTree.
+
+ WAI-ARIA: implement support for ARIA drag and drop
+ https://bugs.webkit.org/show_bug.cgi?id=32007
+
+ * DumpRenderTree/gtk/AccessibilityUIElementGtk.cpp:
+ (AccessibilityUIElement::ariaIsGrabbed):
+ (AccessibilityUIElement::ariaDropEffects):
+ * DumpRenderTree/win/AccessibilityUIElementWin.cpp:
+ (AccessibilityUIElement::ariaIsGrabbed):
+ (AccessibilityUIElement::ariaDropEffects):
+
+2009-12-01 Chris Fleizach <cfleizach@apple.com>
+
+ Reviewed by Darin Adler.
+
+ WAI-ARIA: implement support for ARIA drag and drop
+ https://bugs.webkit.org/show_bug.cgi?id=32007
+
+ * DumpRenderTree/AccessibilityUIElement.cpp:
+ (getARIADropEffectsCallback):
+ (getARIAIsGrabbedCallback):
+ (AccessibilityUIElement::getJSClass):
+ * DumpRenderTree/AccessibilityUIElement.h:
+ * DumpRenderTree/mac/AccessibilityUIElementMac.mm:
+ (AccessibilityUIElement::ariaIsGrabbed):
+ (AccessibilityUIElement::ariaDropEffects):
+
+2009-12-01 Nikolas Zimmermann <nzimmermann@rim.com>
+
+ Not reviewed. GTK DRT try 2.
+
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp:
+ (LayoutTestController::sampleSVGAnimationForElementAtTime):
+
+2009-12-01 Nikolas Zimmermann <nzimmermann@rim.com>
+
+ Not reviewed. Try to fix gtk DRT build.
+
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp:
+
+2009-12-01 David Levin <levin@chromium.org>
+
+ Reviewed by Eric Seidel.
+
+ check-webkit-style does not understand (Prefix)Foo(Custom|Gtk|CG|Mac).cpp including Foo.h
+ https://bugs.webkit.org/show_bug.cgi?id=32033
+
+ * Scripts/modules/cpp_style.py: Changed check for a possible primary header to use find
+ instead of startswith.
+ * Scripts/modules/cpp_style_unittest.py: Added a unit test for the new behavior.
+
+2009-12-01 Nikolas Zimmermann <nzimmermann@rim.com>
+
+ Not reviewed. Qt build almost fixed, DumpRenderTree should compile now as well.
+
+ * DumpRenderTree/qt/LayoutTestControllerQt.h: Update old function signature.
+
+2009-12-01 Nikolas Zimmermann <nzimmermann@rim.com>
+
+ Reviewed by Simon Fraser.
+
+ Add SVG animation test framework with 'snapshot' functionality
+ https://bugs.webkit.org/show_bug.cgi?id=31897
+
+ Add new 'sampleSVGAnimationForElementAtTime' DRT method,
+ used by the new SVG animation testing framework, implemented
+ for qt/gtk/win/mac.
+
+ * DumpRenderTree/LayoutTestController.cpp:
+ (sampleSVGAnimationForElementAtTimeCallback):
+ (LayoutTestController::staticFunctions):
+ * DumpRenderTree/LayoutTestController.h:
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp:
+ (LayoutTestController::sampleSVGAnimationForElementAtTime):
+ * DumpRenderTree/mac/LayoutTestControllerMac.mm:
+ (LayoutTestController::sampleSVGAnimationForElementAtTime):
+ * DumpRenderTree/qt/LayoutTestControllerQt.cpp:
+ (LayoutTestController::sampleSVGAnimationForElementAtTime):
+ * DumpRenderTree/qt/LayoutTestControllerQt.h:
+ * DumpRenderTree/win/LayoutTestControllerWin.cpp:
+ (LayoutTestController::sampleSVGAnimationForElementAtTime):
+ * DumpRenderTree/wx/LayoutTestControllerWx.cpp:
+ (LayoutTestController::sampleSVGAnimationForElementAtTime):
+
+2009-12-01 Adam Roben <aroben@apple.com>
+
+ Remove user content before running each test on Windows
+
+ Fixes <http://webkit.org/b/31479> Make websocket tests work on Windows
+
+ Reviewed by Alexey Proskuryakov.
+
+ * DumpRenderTree/win/DumpRenderTree.cpp:
+ (resetWebViewToConsistentStateBeforeTesting): Remove all user content
+ before each test, which matches Mac.
+
+2009-12-01 Yuzo Fujishima <yuzo@google.com>
+
+ Reviewed by Alexey Proskuryakov.
+
+ Make pywebsocket log errors to a file
+ https://bugs.webkit.org/show_bug.cgi?id=31604
+
+ * Scripts/run-webkit-tests: Log output to a pywebsocket_log.txt file in results directory
+ (by passing the path to the server via a recently added -l option).
+
+2009-12-01 Adam Roben <aroben@apple.com>
+
+ Fix tests that use the TestNetscapePlugin in Debug_Internal builds
+
+ Reviewed by Ada Chan.
+
+ Fixes <http://webkit.org/b/32027> REGRESSION (r49705): Tests that use
+ TestNetscapePlugin fail in Debug_Internal builds
+
+ * DumpRenderTree/win/DumpRenderTree.cpp: Use the "_Debug" plugin
+ directory in Debug and Debug_All builds, but not in Debug_Internal
+ builds.
+
+2009-12-01 Adam Roben <aroben@apple.com>
+
+ Re-enable DRT's watchdog timer on Windows
+
+ It was accidentally disabled in r50907.
+
+ * DumpRenderTree/win/LayoutTestControllerWin.cpp:
+ (LayoutTestController::setWaitToDump): Remove a "false &&" that snuck
+ into an if condition.
+
+2009-12-01 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ check-webkit-style complains about #imports with / in them
+ https://bugs.webkit.org/show_bug.cgi?id=32022
+
+ We need to exclude #import directives in addition to #include from the
+ binary operator whitespace checks.
+
+ * Scripts/modules/cpp_style.py:
+ * Scripts/modules/cpp_style_unittest.py:
+
+2009-11-30 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ check-webkit-style is slightly too verbose
+ https://bugs.webkit.org/show_bug.cgi?id=32010
+
+ check-webkit-style prints out a bunch of "done" lines that seem redundant,
+ especially for the style-queue.
+
+ * Scripts/modules/cpp_style.py:
+
+2009-11-30 Alejandro G. Castro <alex@igalia.com>
+
+ Reviewed by Eric Seidel.
+
+ [GTK] Moved the functions that are closing the result log of the
+ tests to the last line of the runTest function, this avoids
+ reporting crashes in the wrong test if there is a problem when
+ reseting the state after the test.
+
+ * DumpRenderTree/gtk/DumpRenderTree.cpp:
+ (dump):
+ (runTest):
+
+2009-11-30 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Geoffrey Garen.
+
+ Fix for https://bugs.webkit.org/show_bug.cgi?id=31286
+ fast/js/date-proto-generic-invocation breaks another test
+
+ Don't cache JSClassRefs, a change to the prototype chain will
+ last between tests.
+
+ * DumpRenderTree/AccessibilityController.cpp:
+ (AccessibilityController::getJSClass):
+ * DumpRenderTree/GCController.cpp:
+ (GCController::getJSClass):
+ * DumpRenderTree/GCController.h:
+ * DumpRenderTree/LayoutTestController.cpp:
+ (LayoutTestController::getJSClass):
+
+2009-11-30 Yuzo Fujishima <yuzo@google.com>
+
+ Reviewed by Alexey Proskuryakov.
+
+ Update pywebsocket to 0.4.2.1.
+ This is to fix a bug that some messages are logged to stderr even when the log file is specified.
+ https://bugs.webkit.org/show_bug.cgi?id=31976
+
+ * pywebsocket/mod_pywebsocket/standalone.py:
+ * pywebsocket/setup.py:
+
+2009-11-30 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ [bzt] Generate pass messages for style-queue
+ https://bugs.webkit.org/show_bug.cgi?id=31995
+
+ With this change, the style-queue posts "pass" messages to bugs as
+ well. Also, added more information to the state store w.r.t. passing
+ and failing.
+
+ * Scripts/modules/commands/queues.py:
+ * Scripts/modules/patchcollection.py:
+
+2009-11-30 Gustavo Noronha Silva <gustavo.noronha@collabora.co.uk>
+
+ Reviewed by Simon Fraser.
+
+ Check for WEBKIT_TESTFONTS environment variable in
+ run-webkit-tests, for GTK+, to have a more prominent error
+ message.
+
+ * Scripts/run-webkit-tests:
+
+2009-11-30 Yaar Schnitman <yaar@chromium.org>
+
+ Reviewed by Dimitri Glazkov.
+
+ update-webkit --chromium forces gclient sync
+
+ https://bugs.webkit.org/show_bug.cgi?id=31967
+
+ * Scripts/update-webkit-chromium:
+
+2009-11-29 Eric Seidel <eric@webkit.org>
+
+ Add Erik Arvidsson to committers.py since by r51326 he clear has commit rights.
+
+ * Scripts/modules/committers.py:
+
+2009-11-29 Eric Seidel <eric@webkit.org>
+
+ No review, just adding missing svn property.
+
+ Set svn:executable property on new scripts.
+ These were added by commit-queue commits, but the executable
+ property was lost due to a bug in svn-apply:
+ https://bugs.webkit.org/show_bug.cgi?id=27204
+
+ * Scripts/update-webkit-chromium: Added property svn:executable.
+ * Scripts/validate-committer-lists: Added property svn:executable.
+
+2009-11-29 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Need a way to validate that committers.py includes all committers/reviewers
+ https://bugs.webkit.org/show_bug.cgi?id=30970
+
+ Add a script which knows how to compare our public committer/reviewer
+ lists and show discrepancies between them.
+
+ Validates mailing lists vs. committers.py:
+ - committers.py committers missing from webkit-committers@lists
+ - webkit-committers@lists members missing from committers.py
+ - committers.py reviewers missing from webkit-reviewers@lists
+ - webkit-reviewers@lists members missing from committers.py
+ - webkit-reviewers@lists members missing from committers.py reviewer list
+
+ Validates committers.py vs. trunk/ SVN history:
+ - committers who have not committed in over a year
+ - SVN committers missing from committers.py
+ - committers.py members who have no record in SVN.
+
+ All of these lists still show "false positives" until a few more committers.py updates are made, like:
+ https://bugs.webkit.org/show_bug.cgi?id=31366
+
+ * Scripts/validate-committer-lists: Added.
+
+2009-11-28 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ [bzt] style-queue sends ~100 requests to QueueStatusServer every 5 minutes
+ https://bugs.webkit.org/show_bug.cgi?id=31950
+
+ Now we cache the last status that we get back from QueueStatusServer.
+ Eventually we'll have to do something more fancy if we want to support
+ a "try again" button on QueueStatusServer, but we can cross that bridge
+ when we come to it.
+
+ * Scripts/modules/patchcollection.py:
+
+2009-11-28 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ StyleQueue scans ~100 bug pages every 5 minutes
+ https://bugs.webkit.org/show_bug.cgi?id=31947
+
+ Instead of getting the pending-review attachment ids by scanning each
+ bug (which results in a network request), we should just get them all
+ from webkit.org/pending-review in one shot.
+
+ * Scripts/modules/bugzilla.py:
+ * Scripts/modules/bugzilla_unittest.py:
+ * Scripts/modules/commands/queries.py:
+ * Scripts/modules/commands/queries_unittest.py:
+ * Scripts/modules/commands/queues.py:
+ * Scripts/modules/mock_bugzillatool.py:
+ * Scripts/modules/patchcollection.py:
+
+2009-11-28 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ [bzt] CC webkit-bot-watchers whenever the bots touch bugs
+ https://bugs.webkit.org/show_bug.cgi?id=31952
+
+ The mailing list is open for anyone to subscribe.
+
+ * Scripts/modules/bugzilla.py:
+ * Scripts/modules/commands/queues.py:
+
+2009-11-28 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ [bzt] style-queue should report style errors to bugzilla
+ https://bugs.webkit.org/show_bug.cgi?id=31945
+
+ Currently, we're just logging the style errors locally. With this
+ patch we'll actually log the errors to bugzilla. Note: I plan to run
+ with the "local-only" logging during development.
+
+ * Scripts/modules/commands/queues.py:
+ * Scripts/modules/scm.py:
+
+2009-11-28 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ [bzt] style-queue shouldn't reject patches from the commit-queue
+ https://bugs.webkit.org/show_bug.cgi?id=31944
+
+ Currently the style-queue subprocess gets confused and thinks its the
+ commit-queue. If the patch has an error, it rejects it from the
+ commit-queue. Instead, we should have style-queue specific logic.
+ This patch doesn't add that logic, but it gives us a callback we can
+ use to add that logic.
+
+ * Scripts/modules/buildsteps.py:
+ * Scripts/modules/commands/queues.py:
+ * Scripts/modules/landingsequence.py:
+
+2009-11-27 Adam Barth <abarth@webkit.org>
+
+ Rubber stamped by Eric Seidel.
+
+ Rename CommitQueueStatus to QueueStatusServer to allow for more queues.
+
+ * CommitQueueStatus: Removed.
+ * CommitQueueStatus/app.yaml: Removed.
+ * CommitQueueStatus/filters: Removed.
+ * CommitQueueStatus/filters/__init__.py: Removed.
+ * CommitQueueStatus/filters/webkit_extras.py: Removed.
+ * CommitQueueStatus/index.html: Removed.
+ * CommitQueueStatus/index.yaml: Removed.
+ * CommitQueueStatus/queue_status.py: Removed.
+ * CommitQueueStatus/stylesheets: Removed.
+ * CommitQueueStatus/stylesheets/main.css: Removed.
+ * CommitQueueStatus/update_status.html: Removed.
+ * QueueStatusServer: Copied from WebKitTools/CommitQueueStatus.
+
+2009-11-27 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ style-queue should only process each patch once
+ https://bugs.webkit.org/show_bug.cgi?id=31939
+
+ Actually address reviewer comments!
+
+ * Scripts/bugzilla-tool:
+
+2009-11-27 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ [bzt] style-queue fails to apply a bunch of patches for no reason
+ https://bugs.webkit.org/show_bug.cgi?id=31942
+
+ By passing --non-interactive to check-style, we convince check-style
+ to pass --force to svn-apply, which lets it apply more patches.
+
+ * Scripts/modules/commands/queues.py:
+
+2009-11-27 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ [bzt] Support --status-host in style-queue
+ https://bugs.webkit.org/show_bug.cgi?id=31941
+
+ * Scripts/modules/commands/queues.py:
+ * Scripts/modules/statusbot.py:
+
+2009-11-27 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ style-queue should only process each patch once
+ https://bugs.webkit.org/show_bug.cgi?id=31939
+
+ Before processing a patch, the try-queues now ask the web service
+ whether they have already processed the patch. This is an initial cut
+ of this functionality. I expect we're make it richer over time.
+
+ * Scripts/bugzilla-tool:
+ * Scripts/modules/commands/queues.py:
+ * Scripts/modules/patchcollection.py:
+
+2009-11-27 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ PatchStatus does not return status
+ https://bugs.webkit.org/show_bug.cgi?id=31938
+
+ We need to parse attachment_id as an int. Otherwise, we can't find
+ anything in the datastore.
+
+ * CommitQueueStatus/queue_status.py:
+
+2009-11-27 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Make commit-queue status not throw an exception where there is not
+ status
+ https://bugs.webkit.org/show_bug.cgi?id=31936
+
+ We need to actually fetch the results of the query to see what's in the
+ datastore.
+
+ * CommitQueueStatus/queue_status.py:
+
+2009-11-27 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ [bzt] unit test ApplyPatches and ApplyAttachment
+ https://bugs.webkit.org/show_bug.cgi?id=31935
+
+ * Scripts/modules/commands/download.py:
+ * Scripts/modules/commands/download_unittest.py:
+
+2009-11-27 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ [bzt] Unit test download commands
+ https://bugs.webkit.org/show_bug.cgi?id=31923
+
+ Adds download_unittest and fixes a bug found while testing.
+
+ * Scripts/modules/commands/commandtest.py:
+ * Scripts/modules/commands/download.py:
+ Fixed a bug where we'd throw an error because [].append returns
+ None.
+ * Scripts/modules/commands/download_unittest.py: Added.
+ * Scripts/modules/mock_bugzillatool.py:
+ * Scripts/run-webkit-unittests:
+
+2009-11-27 Adam Barth <abarth@webkit.org>
+
+ Unreviewed "build" fix found while writing unit tests.
+
+ * Scripts/modules/commands/download.py:
+
+2009-11-27 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ [bzt] Kill WebKitLandingScripts
+ https://bugs.webkit.org/show_bug.cgi?id=31904
+
+ Step 6: Kill the rest.
+
+ * Scripts/modules/buildsteps.py:
+ * Scripts/modules/commands/download.py:
+ * Scripts/modules/commands/queries.py:
+ * Scripts/modules/commands/upload.py:
+ * Scripts/modules/landingsequence.py:
+ * Scripts/modules/scm.py:
+ * Scripts/modules/webkitlandingscripts.py: Removed.
+
+2009-11-27 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ [bzt] Unit test upload commands
+ https://bugs.webkit.org/show_bug.cgi?id=31903
+
+ Adds unit tests for all but two of the upload commands. The two
+ remaining ones are more difficult. I'll return to them later. The
+ goal of these tests is just to run the commands. We can test more
+ detailed behavior later.
+
+ * Scripts/modules/commands/commandtest.py:
+ * Scripts/modules/commands/upload.py:
+ * Scripts/modules/commands/upload_unittest.py:
+ * Scripts/modules/mock.py: Added.
+ * Scripts/modules/mock_bugzillatool.py:
+
+2009-11-26 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ [bzt] Kill WebKitLandingScripts
+ https://bugs.webkit.org/show_bug.cgi?id=31904
+
+ Step 5: Kill run_and_throw_if_fail.
+
+ * Scripts/modules/buildsteps.py:
+ * Scripts/modules/processutils.py: Added.
+ * Scripts/modules/webkitlandingscripts.py:
+
+2009-11-26 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ [bzt] Kill WebKitLandingScripts
+ https://bugs.webkit.org/show_bug.cgi?id=31904
+
+ Step 4: Kill run_webkit_script.
+
+ * Scripts/modules/buildsteps.py:
+ * Scripts/modules/commands/download.py:
+ * Scripts/modules/webkitlandingscripts.py:
+
+2009-11-26 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ [bzt] Kill WebKitLandingScripts
+ https://bugs.webkit.org/show_bug.cgi?id=31904
+
+ Step 3: Kill build_webkit.
+
+ * Scripts/modules/buildsteps.py:
+ * Scripts/modules/landingsequence.py:
+ * Scripts/modules/webkitlandingscripts.py:
+
+2009-11-26 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ [bzt] Kill WebKitLandingScripts
+ https://bugs.webkit.org/show_bug.cgi?id=31904
+
+ Step 2: Kill ensure_builders_are_green.
+
+ * Scripts/modules/buildsteps.py:
+ * Scripts/modules/commands/download.py:
+ * Scripts/modules/landingsequence.py:
+ * Scripts/modules/webkitlandingscripts.py:
+
+2009-11-26 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ [bzt] Kill WebKitLandingScripts
+ https://bugs.webkit.org/show_bug.cgi?id=31904
+
+ Step 1: Kill prepare_clean_working_directory and run_webkit_tests.
+
+ * Scripts/bugzilla-tool:
+ * Scripts/modules/buildsteps.py: Added.
+ * Scripts/modules/commands/download.py:
+ * Scripts/modules/landingsequence.py:
+ * Scripts/modules/webkitlandingscripts.py:
+
+2009-11-26 Zoltan Horvath <zoltan@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Remove directory prefixes from linux commands
+
+ SCM unittests can cause errors on some systems if we use absolute reference to
+ the commands, so directory prefixes have been removed.
+
+ * Scripts/modules/scm_unittest.py:
+
+2009-11-21 Holger Hans Peter Freyther <zecke@selfish.org>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ Link DumpRenderTree to the Qt Ui Tools
+ https://bugs.webkit.org/show_bug.cgi?id=31203
+
+ Implement QWebPage::createPlugin using the Qt Ui Tools
+ to be able to create classes like QProgressBar from within
+ the <object></object> tags This is required for the
+ new automatic test of Qt Plugins.
+
+ * DumpRenderTree/qt/DumpRenderTree.cpp:
+ (WebCore::WebPage::createPlugin):
+ * DumpRenderTree/qt/DumpRenderTree.h:
+ * DumpRenderTree/qt/DumpRenderTree.pro:
+
+2009-11-25 Yuzo Fujishima <yuzo@google.com>
+
+ Reviewed by Eric Seidel.
+
+ Update pywebsocket to 0.4.2
+
+ Update pywebsocket to 0.4.2
+ https://bugs.webkit.org/show_bug.cgi?id=31861
+
+ * pywebsocket/example/echo_client.py:
+ * pywebsocket/example/echo_wsh.py:
+ * pywebsocket/mod_pywebsocket/__init__.py:
+ * pywebsocket/mod_pywebsocket/dispatch.py:
+ * pywebsocket/mod_pywebsocket/msgutil.py:
+ * pywebsocket/mod_pywebsocket/standalone.py:
+ * pywebsocket/setup.py:
+ * pywebsocket/test/test_dispatch.py:
+ * pywebsocket/test/test_msgutil.py:
+
+2009-11-25 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Add unit test for mark-fixed
+ https://bugs.webkit.org/show_bug.cgi?id=31896
+
+ * Scripts/modules/commands/commandtest.py: Added.
+ * Scripts/modules/commands/queries_unittest.py:
+ * Scripts/modules/commands/upload_unittest.py: Added.
+ * Scripts/modules/mock_bugzillatool.py:
+ * Scripts/run-webkit-unittests:
+
+2009-11-25 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ bugzilla-tool should have a mark-fixed command
+ https://bugs.webkit.org/show_bug.cgi?id=31853
+
+ Pretty simple stuff.
+
+ * Scripts/modules/commands/upload.py:
+
+2009-11-25 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ 'bugzilla-tool help' should only show common commands like how 'git help' does
+ https://bugs.webkit.org/show_bug.cgi?id=31772
+
+ I also took this opportunity to make 'help' a real Command.
+ Making 'help' a real command required adding Command.tool (which we've wanted to do for a while).
+
+ * Scripts/bugzilla-tool:
+ - change should_show_command_help to should_show_in_main_help
+ * Scripts/modules/commands/download.py:
+ - Mark commands as being shown in main help or not.
+ - show_in_main_help = False is not required (default is false),
+ but it seemed to make the commands more self-documenting.
+ * Scripts/modules/commands/queries.py: ditto
+ * Scripts/modules/commands/queues.py: ditto
+ * Scripts/modules/commands/upload.py: ditto
+ * Scripts/modules/multicommandtool.py:
+ - Make Command hold a pointer to tool in self.tool. Most Command
+ subclasses do not take advantage of this yet, but it was required
+ for HelpCommand to be able to reach the tool from _help_epilog().
+ - Move MultiCommandTool._standalone_help_for_command to Command.standalone_help
+ - Move MultiCommandTool._help_epilog to Command._help_epilog
+ - Move "help" logic into HelpCommand.execute()
+ - Change should_show_command_help to should_show_in_main_help and add a default implementation.
+ * Scripts/modules/multicommandtool_unittest.py:
+ - Test hiding of Commands in --help, and that all commands are shown in 'help --all-commands'
+
+2009-11-25 Brian Weinstein <bweinstein@apple.com>
+
+ Reviewed by Dan Bernstein.
+
+ Patch by Mark Rowe.
+
+ The buildbots are failing on Windows because when they were upgraded
+ to 4.0.4, Apple Application Support was not in their path. Add it to
+ the path to fix the buildots.
+
+ * Scripts/webkitdirs.pm:
+
+2009-11-25 Csaba Osztrogonác <ossy@webkit.org>
+
+ Reviewed by David Kilzer.
+
+ run-webkit-tests doesn't accept directories/files with --skipped=only parameter
+ https://bugs.webkit.org/show_bug.cgi?id=31799
+
+ * Scripts/run-webkit-tests: Fixed.
+
+2009-11-25 Zoltan Horvath <zoltan@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Change run_command to give back stderr by default
+ https://bugs.webkit.org/show_bug.cgi?id=31734
+
+ Change run_command to give back stderr by default.
+ Set run_commands's 'svn-create-patch' calling to put only the stdout into the patches.
+ Change the related unittest call.
+
+ * Scripts/modules/scm.py:
+ * Scripts/modules/scm_unittest.py:
+
+2009-11-25 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Centralize required argument parsing in Command
+ https://bugs.webkit.org/show_bug.cgi?id=31872
+
+ * Scripts/modules/commands/download.py: remove custom required arg message.
+ * Scripts/modules/commands/upload.py: ditto.
+ * Scripts/modules/multicommandtool.py:
+ - Add _parse_required_arguments.
+ - Pass program name off to OptionParser.
+ - Add name() for access to tool name.
+ - Add check_arguments_and_execute and make it return a return code.
+ - Replace a couple uses of + with %.
+ * Scripts/modules/multicommandtool_unittest.py: test _parse_required_arguments
+
+2009-11-25 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Abstract out capturing stdout/stderr into a new OutputCapture class for re-use among the various unit tests.
+ https://bugs.webkit.org/show_bug.cgi?id=31870
+
+ * Scripts/modules/commands/queries_unittest.py: Use the new class.
+ * Scripts/modules/multicommandtool_unittest.py: Ditto.
+ * Scripts/modules/outputcapture.py: Added.
+
+2009-11-24 Dmitry Titov <dimich@chromium.org>
+
+ Reviewed by Eric Seidel.
+
+ Add ENABLE_SHARED_SCRIPT feature define and flag for build-webkit
+ https://bugs.webkit.org/show_bug.cgi?id=31444
+
+ * Scripts/build-webkit:
+
+2009-11-24 Chris Marrin <cmarrin@apple.com>
+
+ Reviewed by Simon Fraser.
+
+ Changes the way 3D_RENDERING and ACCELERATED_COMPOSITING related tests are excluded
+ https://bugs.webkit.org/show_bug.cgi?id=27314
+
+ Now the script allows the directories with these tests to be included on all
+ platforms but Mac, where they behave the same as always. For all other platforms
+ the tests need to be excluded using the Skipped files, which is currently done
+ for all platforms (including win since we're not turned on yet)
+
+ * Scripts/webkitdirs.pm:
+
+2009-11-24 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ queries_unittest.py should test command output
+ https://bugs.webkit.org/show_bug.cgi?id=31845
+
+ * Scripts/modules/commands/queries_unittest.py:
+ - Capture stdout and stderr and compare with expected strings.
+
+2009-11-24 Simon Fraser <simon.fraser@apple.com>
+
+ No Review.
+
+ Fix spelling error ("depenedencies").
+
+ * Scripts/build-webkit:
+
+2009-11-24 Mark Rowe <mrowe@apple.com>
+
+ Land the configuration that includes the two debug GTK Linux builders.
+
+ * BuildSlaveSupport/build.webkit.org-config/config.json:
+
+2009-11-24 David Kilzer <ddkilzer@apple.com>
+
+ <http://webkit.org/b/31840> bisect-builds broke after r50080
+
+ Reviewed by Dan Bernstein.
+
+ * Scripts/bisect-builds:
+ (mountAndRunNightly): Switched back to using backticks to run
+ the hdiutil command since exec() will terminate the existing
+ script, which is not what we want. Store the output of
+ File::Spec->devnull() in a variable for use in the hdiutil
+ detach commands.
+
+2009-11-23 Laszlo Gombos <laszlo.1.gombos@nokia.com>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ Include "config.h" to meet Coding Style Guidelines
+ https://bugs.webkit.org/show_bug.cgi?id=31792
+
+ * DumpRenderTree/pthreads/JavaScriptThreadingPthreads.cpp:
+ * DumpRenderTree/qt/jsobjects.cpp:
+ * DumpRenderTree/win/DRTDesktopNotificationPresenter.cpp:
+
+2009-11-23 Gustavo Noronha Silva <gustavo.noronha@collabora.co.uk>
+
+ Reviewed by Oliver Hunt.
+
+ Implement new required function to pass test we used to pass. This
+ change is required since r51294.
+
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp:
+ (LayoutTestController::setAllowUniversalAccessFromFileURLs):
+
+2009-11-23 Jakub Wieczorek <faw217@gmail.com>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ [Qt] DRT: dumpBackForwardList() does not work properly with non-file URLs.
+ https://bugs.webkit.org/show_bug.cgi?id=31775
+
+ LayoutTestController::dumpBackForwardList() should work with local URLs
+ as well as with normal URLs (in http tests for instance).
+ Currently it does not output the latter properly.
+
+ Unskip a bunch of passing http/navigation tests.
+
+ * DumpRenderTree/qt/DumpRenderTree.cpp:
+ (WebCore::dumpHistoryItem):
+
+2009-11-22 Chris Fleizach <cfleizach@apple.com>
+
+ Reviewed by Oliver Hunt.
+
+ ARIA: support aria-flowto
+ https://bugs.webkit.org/show_bug.cgi?id=31762
+
+ * DumpRenderTree/AccessibilityUIElement.cpp:
+ (ariaFlowToElementAtIndexCallback):
+ (AccessibilityUIElement::getJSClass):
+ * DumpRenderTree/AccessibilityUIElement.h:
+ * DumpRenderTree/gtk/AccessibilityUIElementGtk.cpp:
+ (AccessibilityUIElement::ariaFlowToElementAtIndex):
+ * DumpRenderTree/mac/AccessibilityUIElementMac.mm:
+ (AccessibilityUIElement::ariaFlowToElementAtIndex):
+ * DumpRenderTree/win/AccessibilityUIElementWin.cpp:
+ (AccessibilityUIElement::ariaFlowToElementAtIndex):
+
+2009-11-22 Antonio Gomes <tonikitoo@webkit.org>
+
+ Reviewed by Kenneth Christiansen.
+
+ [Qt] fast/history/back-forward-reset-after-error-handling.html failing due to WorkQueue not being un-frozen
+ https://bugs.webkit.org/show_bug.cgi?id=31638
+
+ Unfreeze WorkQueue after each test execution.
+
+ * DumpRenderTree/qt/DumpRenderTree.cpp:
+ (WebCore::DumpRenderTree::resetToConsistentStateBeforeTesting):
+
+2009-11-22 Jakub Wieczorek <faw217@gmail.com>
+
+ Reviewed by Adam Barth.
+
+ [Qt] DumpRenderTree should explicitly ignore any SSL certificate errors
+ for localhost and 127.0.0.1.
+ https://bugs.webkit.org/show_bug.cgi?id=31783
+
+ Unskip the http/tests/ssl/verify-ssl-enabled.php test, which is passing now.
+
+ * DumpRenderTree/qt/DumpRenderTree.cpp:
+ (WebCore::NetworkAccessManager::NetworkAccessManager):
+ (WebCore::NetworkAccessManager::sslErrorsEncountered):
+ (WebCore::WebPage::WebPage):
+ * DumpRenderTree/qt/DumpRenderTree.h:
+
+2009-11-22 Chris Evans <cevans@chromium.org>
+
+ Reviewed by Adam Barth.
+
+ Disable access to file:/// directory listings
+ https://bugs.webkit.org/show_bug.cgi?id=31329
+
+ Implemented setAllowUniversalAccessFromFileURLs to support testing of
+ file URL security.
+
+ * DumpRenderTree/LayoutTestController.cpp:
+ (setAllowUniversalAccessFromFileURLsCallback):
+ (LayoutTestController::staticFunctions):
+ * DumpRenderTree/LayoutTestController.h:
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp:
+ (LayoutTestController::setAllowUniversalAccessFromFileURLs):
+ * DumpRenderTree/mac/LayoutTestControllerMac.mm:
+ (LayoutTestController::setAllowUniversalAccessFromFileURLs):
+ * DumpRenderTree/win/LayoutTestControllerWin.cpp:
+ (LayoutTestController::setAllowUniversalAccessFromFileURLs):
+ * DumpRenderTree/wx/LayoutTestControllerWx.cpp:
+ (LayoutTestController::setAllowUniversalAccessFromFileURLs):
+
+2009-11-22 Jakub Wieczorek <faw217@gmail.com>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ [Qt] Fix the timeout of fast/frames/frame-navigation.html
+ https://bugs.webkit.org/show_bug.cgi?id=31638
+
+ The test is timeouting, because it uses the WorkQueue to load a document in one
+ of the child frames and once the loading is finished, the DRT does not dump the
+ tree. This is because it waits for the QWebFrame::loadFinished() signal from
+ the main frame, while it should connect to QWebPage::loadFinished().
+
+ * DumpRenderTree/qt/DumpRenderTree.cpp:
+ (WebCore::DumpRenderTree::DumpRenderTree):
+
+2009-11-21 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ bugzilla-tool --help spews way too much text
+ https://bugs.webkit.org/show_bug.cgi?id=31771
+
+ * Scripts/bugzilla-tool:
+ - Remove self.cached_scm initialization hack.
+ * Scripts/modules/buildbot.py:
+ - Make default_host accessible to callers.
+ * Scripts/modules/commands/download.py:
+ - Phrase help for all commands consistently and remove spurious help text punctuation.
+ * Scripts/modules/commands/queries.py: Ditto.
+ * Scripts/modules/commands/queues.py: Ditto.
+ * Scripts/modules/commands/upload.py: Ditto.
+ * Scripts/modules/multicommandtool.py:
+ - Add HelpPrintingOptionParser.format_epilog to replace
+ NonWrappingEpilogIndentedHelpFormatter and allow us to lazily initialize
+ per-command help (thus removing the need for the cached_scm hack in BugzillaTool).
+ - Make --help only show a list of commands like "svn help" and "git help" do --
+ previously --help was listing all commands and options.
+ - Sort list of commands alphabetically.
+
+2009-11-21 Eric Seidel <eric@webkit.org>
+
+ No review. Fixing a typo from the previous patch for bug 31767.
+
+ AbstractQueue.run_bugzilla_tool throws an exception
+ https://bugs.webkit.org/show_bug.cgi?id=31769
+
+ * Scripts/modules/commands/queues.py:
+
+2009-11-21 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ commit-queue fails to run with "permissions error" due to bad bugzilla-tool path
+ https://bugs.webkit.org/show_bug.cgi?id=31767
+
+ What we really want to test is BugzillaTool.path() instead of TrivialTool.path().
+ Since we don't have a good way to test BugzillaTool pieces, I've
+ left out a test for now.
+
+ * Scripts/bugzilla-tool:
+ - Add a path() implementation to expose bugzilla-tool's __file__ path to commit-queue.
+ * Scripts/modules/commands/queues.py:
+ - Use tool.path() instead of __file__.
+ * Scripts/modules/multicommandtool.py:
+ - Add a new path() method to MultiComandTool.
+ * Scripts/modules/multicommandtool_unittest.py:
+ - Provide a path() method. Little point in testing this mock implementation.
+
+2009-11-21 Adam Barth <abarth@webkit.org>
+
+ Unreviewed "build" fix. Turns out I was testing the wrong copy of
+ WebKitTools.
+
+ * Scripts/modules/commands/download.py:
+
+2009-11-21 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Convert check-style to use LandingSequence
+ https://bugs.webkit.org/show_bug.cgi?id=31763
+
+ Instead of manipulating the working copy by hand, we should use the
+ LandingSequence in CheckStyle. This will make this code eaiser to
+ test.
+
+ * Scripts/modules/commands/download.py:
+
+2009-11-20 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Unit test query commands
+ https://bugs.webkit.org/show_bug.cgi?id=31755
+
+ These tests are pretty rough, but hopefully they'll grow.
+
+ * Scripts/modules/commands/queries_unittest.py: Added.
+ * Scripts/modules/mock_bugzillatool.py: Added.
+ * Scripts/run-webkit-unittests:
+
+2009-11-20 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Fix a bunch of unit test regressions from our recent bugzilla-toll hacking
+ https://bugs.webkit.org/show_bug.cgi?id=31758
+
+ * Scripts/modules/multicommandtool.py:
+ - Allow passing of explicit commands to MultiCommandTool.__init__
+ * Scripts/modules/multicommandtool_unittest.py:
+ - Use new Command.name naming system.
+ - Test Command auto-discovery.
+ * Scripts/modules/workqueue.py:
+ - bug_id no longer exists, use patch['bug_id'] instead.
+ * Scripts/modules/workqueue_unittest.py:
+ - WorkQueues require names now.
+ - should_proceed_with_work_item must return a patch object.
+
+2009-11-20 Chris Fleizach <cfleizach@apple.com>
+
+ Reviewed by Beth Dakin.
+
+ WAI-ARIA: add support for aria-owns
+ https://bugs.webkit.org/show_bug.cgi?id=31702
+
+ * DumpRenderTree/AccessibilityUIElement.cpp:
+ (ariaOwnsElementAtIndexCallback):
+ (AccessibilityUIElement::getJSClass):
+ * DumpRenderTree/AccessibilityUIElement.h:
+ * DumpRenderTree/gtk/AccessibilityUIElementGtk.cpp:
+ (AccessibilityUIElement::ariaOwnsElementAtIndex):
+ * DumpRenderTree/mac/AccessibilityUIElementMac.mm:
+ (AccessibilityUIElement::ariaOwnsElementAtIndex):
+ * DumpRenderTree/win/AccessibilityUIElementWin.cpp:
+ (AccessibilityUIElement::ariaOwnsElementAtIndex):
+
+2009-11-20 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Fix exception thrown when running the commit-queue.
+
+ * Scripts/modules/statusbot.py: patch is optional.
+ * Scripts/modules/workqueue.py: WorkQUeue requires a name.
+
+2009-11-20 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Teach the StatusBot how to support more than just the commit-queue
+ https://bugs.webkit.org/show_bug.cgi?id=31754
+
+ * Scripts/modules/workqueue.py: Another typo.
+
+2009-11-20 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Teach the StatusBot how to support more than just the commit-queue
+ https://bugs.webkit.org/show_bug.cgi?id=31754
+
+ * Scripts/modules/commands/queues.py: Fix silly typo.
+
+2009-11-20 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Teach the StatusBot how to support more than just the commit-queue
+ https://bugs.webkit.org/show_bug.cgi?id=31754
+
+ * CommitQueueStatus/index.yaml:
+ - Add indices required for the new queries.
+ * CommitQueueStatus/queue_status.py:
+ - Add a patch-status page and move update_status to update-status.
+ - Only display "commit-queue" status records for the commit-queue.
+ - Add support for a queue_name property on status records.
+ - Fix _int_from_request to actually work.
+ * CommitQueueStatus/update_status.html:
+ - Add support for a queue_name on status records.
+ - Remove unused list of bug ids.
+ * Scripts/modules/commands/queues.py
+ - Make the queues pass the patch instead of the bug_id to StatusBot.
+ * Scripts/modules/statusbot.py:
+ - Support passing the queue_name to the status updates.
+ - Support fetching patch status with patch_status().
+ * Scripts/modules/workqueue.py:
+ - Pass the patch to the StatusBot instead of the bug_id.
+ - Let WorkQueues have a name.
+
+2009-11-20 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Move bugzilla-tool commands into their own file
+ https://bugs.webkit.org/show_bug.cgi?id=31752
+
+ This will let us write unit tests.
+
+ * Scripts/bugzilla-tool:
+ * Scripts/modules/commands/__init__.py: Added.
+ * Scripts/modules/commands/download.py: Added.
+ * Scripts/modules/commands/queries.py: Added.
+ * Scripts/modules/commands/queues.py: Added.
+ * Scripts/modules/commands/upload.py: Added.
+ * Scripts/modules/grammar.py: Added.
+
+2009-11-20 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ BuildQueue should check if the tree is currently buildable
+ https://bugs.webkit.org/show_bug.cgi?id=31744
+
+ * Scripts/bugzilla-tool:
+ * Scripts/modules/landingsequence.py:
+ * Scripts/modules/webkitlandingscripts.py:
+
+2009-11-20 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Move prepare_clean_working_directory into the LandingSequence
+ https://bugs.webkit.org/show_bug.cgi?id=31743
+
+ * Scripts/bugzilla-tool:
+ * Scripts/modules/landingsequence.py:
+
+2009-11-20 Yael Aharon <yael.aharon@nokia.com>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ NPN_ReloadPlugins does not reload the page even if reloadPages is true.
+ https://bugs.webkit.org/show_bug.cgi?id=30460
+
+ Added code for calling NPN_ReloadPlugins with reloadPages true and false.
+
+ * DumpRenderTree/TestNetscapePlugIn.subproj/PluginObject.cpp:
+ (pluginInvoke):
+
+2009-11-20 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Pass the port information to the child process
+ https://bugs.webkit.org/show_bug.cgi?id=31736
+
+ We need to do this so the child process knows what to build!
+
+ * Scripts/bugzilla-tool:
+ * Scripts/modules/landingsequence.py:
+ * Scripts/modules/webkitport.py:
+ * Scripts/modules/webkitport_unittest.py:
+
+2009-11-20 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Support Qt port in build-queue
+ https://bugs.webkit.org/show_bug.cgi?id=31733
+
+ * Scripts/bugzilla-tool:
+
+2009-11-20 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Implement a build-queue
+ https://bugs.webkit.org/show_bug.cgi?id=31725
+
+ Currently this just builds the first 10 patches in the review queue.
+ We'll want to do something smarter soon.
+
+ * Scripts/bugzilla-tool:
+
+2009-11-20 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Make commit-queue and style-queue show up in help
+ https://bugs.webkit.org/show_bug.cgi?id=31724
+
+ We need to store their names on their class to make these commands
+ properly register themselves with MultiCommandTool.
+
+ * Scripts/bugzilla-tool:
+
+2009-11-20 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Implement bugzilla-tool build-attachment
+ https://bugs.webkit.org/show_bug.cgi?id=31722
+
+ This command builds an attachment from bugzilla. It leaves the built
+ patch in the working copy.
+
+ * Scripts/bugzilla-tool:
+ * Scripts/modules/landingsequence.py:
+ * Scripts/modules/webkitlandingscripts.py:
+
+2009-11-20 Alejandro G. Castro <alex@igalia.com>
+
+ Reviewed by Xan Lopez.
+
+ [GTK] DRT release event does not create the state correctly
+ https://bugs.webkit.org/show_bug.cgi?id=31717
+
+ * WebKitTools/DumpRenderTree/gtk/EventSender.cpp:
+
+2009-11-20 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ MultiCommandTool should find Command objects automatically instead of with a manual list
+ https://bugs.webkit.org/show_bug.cgi?id=31710
+
+ * Scripts/bugzilla-tool:
+ * Scripts/modules/multicommandtool.py:
+ - Use some wild python-fu to crawl all the known subclasses of Command.
+
+2009-11-20 Adam Barth <abarth@webkit.org>
+
+ Unreviewed "build" fix. Added missing import.
+
+ * Scripts/bugzilla-tool:
+
+2009-11-20 Adam Barth <abarth@webkit.org>
+
+ Unreviewed "build" fix. I failed to update LandingSequence.test
+ properly.
+
+ * Scripts/modules/landingsequence.py:
+
+2009-11-20 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Create LandingSequence as the all-sing, all-dance landing class
+ https://bugs.webkit.org/show_bug.cgi?id=31709
+
+ Client can inherit from this class to carefully control exactly which
+ steps they wish to have happen in the landing sequence.
+
+ * Scripts/bugzilla-tool:
+ * Scripts/modules/landingsequence.py: Added.
+ * Scripts/modules/webkitlandingscripts.py: Added.
+
+2009-11-19 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Abstract AbstractPatchProcessingCommand from AbstractPatchLandingCommand
+ https://bugs.webkit.org/show_bug.cgi?id=31707
+
+ This is to help when we implement build-attachment.
+
+ * Scripts/bugzilla-tool:
+
+2009-11-19 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Support Qt port in bugzilla-tool
+ https://bugs.webkit.org/show_bug.cgi?id=31701
+
+ Now we support building with Qt!
+
+ * Scripts/bugzilla-tool:
+ * Scripts/modules/webkitport.py: Added.
+ * Scripts/modules/webkitport_unittest.py: Added.
+ * Scripts/run-webkit-unittests:
+
+2009-11-19 Zoltan Horvath <zoltan@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Remove inserting stderr into patch in bugzilla-tool
+ https://bugs.webkit.org/show_bug.cgi?id=29914
+
+ Modify SCM python module's run_command function to avoid return of stderr
+ by default, so stderr won't be inserted into the patches.
+ Modify the related unit test.
+
+ * Scripts/modules/scm.py:
+ * Scripts/modules/scm_unittest.py:
+
+2009-11-19 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ bugzilla-tool needs per-command help
+ https://bugs.webkit.org/show_bug.cgi?id=31697
+
+ Added support for "bugzilla-tool help command-name"
+ and a unit test to make sure it works.
+
+ * Scripts/modules/multicommandtool.py:
+ * Scripts/modules/multicommandtool_unittest.py:
+
+2009-11-19 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Move MultiCommandTool and Command into a separate file and add some basic unit tests
+ https://bugs.webkit.org/show_bug.cgi?id=31695
+
+ * Scripts/bugzilla-tool:
+ * Scripts/modules/multicommandtool.py: Added.
+ * Scripts/modules/multicommandtool_unittest.py: Added.
+ * Scripts/run-webkit-unittests:
+
+2009-11-19 Eric Seidel <eric@webkit.org>
+
+ No review, just adding a FIXME.
+
+ Split out command parsing and help printing from BugzillaTool
+ https://bugs.webkit.org/show_bug.cgi?id=31688
+
+ * Scripts/bugzilla-tool: Add an extra comment about current design failures.
+
+2009-11-19 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Split out command parsing and help printing from BugzillaTool
+ https://bugs.webkit.org/show_bug.cgi?id=31688
+
+ * Scripts/bugzilla-tool:
+ - Add new MultiCommandTool class to contain option parsing and help printing logic.
+ - Rename private methods to use _ pattern.
+ - MultiCommandTool has two abstract methods should_show_command_help and should_execute_command.
+ -
+
+2009-11-19 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Re-factor help printing to use modern python idioms
+ https://bugs.webkit.org/show_bug.cgi?id=31685
+
+ * Scripts/bugzilla-tool:
+
+2009-11-19 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Darin Adler.
+
+ commit-queue empty queue logs twice
+ https://bugs.webkit.org/show_bug.cgi?id=31679
+
+ * Scripts/bugzilla-tool:
+
+2009-11-19 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Darin Adler.
+
+ bugzilla-tool's reviewer/committer rejection message should be clearer
+ https://bugs.webkit.org/show_bug.cgi?id=31126
+
+ Add more explanatory prose to bugzilla-tool's flag permission rejection message.
+
+ * Scripts/modules/bugzilla.py:
+
+2009-11-19 Eric Z. Ayers <zundel@google.com>
+
+ Reviewed by Pavel Feldman.
+
+ Forces a WM_PAINT event on calling layoutTestController.display()
+ in order to enable the timeline-paint.html test on Windows.
+ ::UpdateWindow() does not force an event becaue the window is
+ not visible.
+
+ https://bugs.webkit.org/show_bug.cgi?id=31402
+
+ * DumpRenderTree/win/DumpRenderTree.cpp:
+ (displayWebView):
+
+2009-11-19 Michelangelo De Simone <michelangelo@webkit.org>
+
+ No review needed.
+
+ Added myself to committers list.
+
+ * Scripts/modules/committers.py:
+
+2009-11-19 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Bugzilla-tool command classes should match command names
+ https://bugs.webkit.org/show_bug.cgi?id=31666
+
+ I renamed all the commands except CommitMessageForCurrentDiff because
+ the new name would conflict with an existing class.
+
+ * Scripts/bugzilla-tool:
+
+2009-11-19 Pavel Feldman <pfeldman@chromium.org>
+
+ Reviewed by Gustavo Noronha Silva.
+
+ Web Inspector: Implement "show inspector" in WebKit GTK
+ API and enable console tests.
+
+ https://bugs.webkit.org/show_bug.cgi?id=31669
+
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp:
+ (LayoutTestController::showWebInspector):
+
+2009-11-19 Kenneth Rohde Christiansen <kenneth@webkit.org>
+
+ Reviewed by Simon Hausmann.
+
+ Minor refactoring + more documentation.
+
+ * DumpRenderTree/qt/DumpRenderTree.cpp:
+ (WebCore::clearHistory):
+ (WebCore::DumpRenderTree::resetToConsistentStateBeforeTesting):
+
+2009-11-19 Fumitoshi Ukai <ukai@chromium.org>
+
+ Reviewed by Eric Seidel.
+
+ Ignore websocket tests when --no-http is specified.
+ https://bugs.webkit.org/show_bug.cgi?id=31662
+
+ * Scripts/run-webkit-tests:
+
+2009-11-18 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Normalize ' and " in bugzilla-tool
+ https://bugs.webkit.org/show_bug.cgi?id=31655
+
+ We decided " is better than ' and we should be consistent.
+
+ * Scripts/bugzilla-tool:
+
+2009-11-18 Laszlo Gombos <laszlo.1.gombos@nokia.com>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ [Qt] Remove support for Qt v4.3 or older versions
+ https://bugs.webkit.org/show_bug.cgi?id=29469
+
+ * DumpRenderTree/qt/DumpRenderTree.pro:
+ * DumpRenderTree/qt/ImageDiff.pro:
+
+2009-11-18 Shinichiro Hamaji <hamaji@chromium.org>
+
+ Reviewed by Eric Seidel.
+
+ GitTest.test_create_binary_patch fails if /tmp is symlink
+ https://bugs.webkit.org/show_bug.cgi?id=31536
+
+ * Scripts/modules/scm_unittest.py:
+
+2009-11-18 Yaar Schnitman <yaar@chromium.org>
+
+ Reviewed by Darin Adler.
+
+ Configuration for Chromium Build Slaves.
+
+ https://bugs.webkit.org/show_bug.cgi?id=31442
+
+ * BuildSlaveSupport/build.webkit.org-config/config.json:
+ * BuildSlaveSupport/build.webkit.org-config/master.cfg:
+
+2009-11-18 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Darin Adler.
+
+ workqueue.py results in totally broken commit-queue UI
+ https://bugs.webkit.org/show_bug.cgi?id=31645
+
+ * Scripts/bugzilla-tool:
+ - Remove unneeded use of PatchCollection.
+ - Grab a new copy of the cq'd patches every run of the queue.
+
+2009-11-18 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Anders Carlsson.
+
+ Make the Mac Geolocation API async.
+
+ Update DRT to use the new async Mac Geolocation API.
+
+ * DumpRenderTree/mac/UIDelegate.mm:
+ (-[UIDelegate webView:decidePolicyForGeolocationRequestFromOrigin:frame:listener:]):
+
+2009-11-18 Laszlo Gombos <laszlo.1.gombos@nokia.com>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ Add and option to toggle HTML5 datalist support to build-webkit
+ https://bugs.webkit.org/show_bug.cgi?id=31599
+
+ * Scripts/build-webkit:
+
+2009-11-18 Kevin Watters <kevinwatters@gmail.com>
+
+ Reviewed by Kevin Ollivier.
+
+ Enable wx plugin support using the Windows implementation as a base.
+
+ https://bugs.webkit.org/show_bug.cgi?id=31636
+
+ * wx/build/settings.py:
+
+2009-11-18 Kenneth Rohde Christiansen <kenneth@webkit.org>
+
+ Reviewed by Simon Hausmann.
+
+ Change the initialization order so that the controllers
+ will be created before exporting them to the JS DOM window.
+
+ * DumpRenderTree/qt/DumpRenderTree.cpp:
+ (WebCore::DumpRenderTree::DumpRenderTree):
+
+2009-11-18 Kenneth Rohde Christiansen <kenneth@webkit.org>
+
+ Reviewed by Simon Hausmann.
+
+ Fix a code copy and paste error. m_page should be page.
+
+ * DumpRenderTree/qt/DumpRenderTree.cpp:
+ (WebCore::DumpRenderTree::createWindow):
+
+2009-11-17 Mark Rowe <mrowe@apple.com>
+
+ Reviewed by Alexey Proskuryakov.
+
+ <http://webkit.org/b/31603> WebSocket server is confused if WebKit tests run from within /tmp on Mac OS X
+
+ * pywebsocket/mod_pywebsocket/dispatch.py: Use os.path.realpath as it returns the canonical path of a file.
+ This prevents symlinks from confusing the descendant check.
+
+2009-11-17 Mark Rowe <mrowe@apple.com>
+
+ Reviewed by Alexey Proskuryakov.
+
+ <http://webkit.org/b/31602> Failing to start the WebSocket server shouldn’t terminate entire test run
+
+ If the WebSocket server fails to start have DRT load an error page in place of tests that require the
+ server to be up rather than having run-webkit-tests abort immediately.
+
+ * Scripts/run-webkit-tests:
+
+2009-11-17 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Darin Adler.
+
+ commit-queue is failing to set reviewer in ChangeLogs
+ https://bugs.webkit.org/show_bug.cgi?id=31592
+
+ * Scripts/bugzilla-tool: Clarify the "applying" log message.
+ * Scripts/modules/bugzilla.py:
+ - Add a new _validate_committer_and_reviewer function as a
+ temporary solution until we can make a real Attachment object
+ which knows how to fill in its committer/reviewer fields automatically.
+
+2009-11-17 Kenneth Rohde Christiansen <kenneth@webkit.org>
+
+ Unreviewed buildbot fix.
+
+ Revert part of earlier patch and add comment, as it
+ was causing timeouts on the buildbot.
+
+ * DumpRenderTree/qt/LayoutTestControllerQt.cpp:
+ (LayoutTestController::notifyDone):
+
+2009-11-17 Kenneth Rohde Christiansen <kenneth@webkit.org>
+
+ Reviewed by Oliver Hunt.
+
+ Make the timeout 15 sec as for the other DRT's and make
+ it print out the same output when a test timeout.
+
+ * DumpRenderTree/qt/LayoutTestControllerQt.cpp:
+ (LayoutTestController::waitUntilDone):
+ (LayoutTestController::notifyDone):
+ (LayoutTestController::timerEvent):
+
+2009-11-17 Joseph Pecoraro <joepeck@webkit.org>
+
+ Reviewed by Timothy Hatcher.
+
+ Fixed typos in comments.
+
+ * Scripts/modules/committers.py:
+
+2009-11-17 Pavel Feldman <pfeldman@chromium.org>
+
+ Reviewed by Timothy Hatcher.
+
+ Web Inspector: Make DRT show web inspector for tests in inspector/ folder.
+ - Updated DRT to show/close inspector for all tests under /inspector
+ - Introduced LayoutTestController::setTimelineProfilingEnabled and
+ WebInspector::setTimelineProfilingEnabled beside setJavaScriptProfilingEnabled
+ - Removed reload on each inspector test
+ - Renamed fast/inspector to fast/inspector-support in order not to trigger
+ inspector for those.
+ - Reimplemented timeline tests in order to get rid of reload there.
+ - Moved tests that don't require harness into the fast group.
+
+ https://bugs.webkit.org/show_bug.cgi?id=31472
+
+ * DumpRenderTree/LayoutTestController.cpp:
+ (setTimelineProfilingEnabledCallback):
+ (closeWebInspectorCallback):
+ (LayoutTestController::staticFunctions):
+ * DumpRenderTree/LayoutTestController.h:
+ * DumpRenderTree/gtk/DumpRenderTree.cpp:
+ (shouldOpenWebInspector):
+ (runTest):
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp:
+ (LayoutTestController::setTimelineProfilingEnabled):
+ * DumpRenderTree/mac/DumpRenderTree.mm:
+ (shouldOpenWebInspector):
+ (runTest):
+ * DumpRenderTree/mac/LayoutTestControllerMac.mm:
+ (LayoutTestController::setTimelineProfilingEnabled):
+ * DumpRenderTree/win/DumpRenderTree.cpp:
+ (shouldOpenWebInspector):
+ (runTest):
+ * DumpRenderTree/win/LayoutTestControllerWin.cpp:
+ (LayoutTestController::setTimelineProfilingEnabled):
+
+2009-11-17 Oliver Hunt <oliver@apple.com>
+
+ Reviewed by Maciej Stachowiak.
+
+ Incorrect use of JavaScriptCore API in DumpRenderTree
+ https://bugs.webkit.org/show_bug.cgi?id=31577
+
+ Return undefined rather than a literal null.
+
+ * DumpRenderTree/AccessibilityUIElement.cpp:
+ (setSelectedTextRangeCallback):
+ (incrementCallback):
+ (decrementCallback):
+ (showMenuCallback):
+
+2009-11-16 Chris Fleizach <cfleizach@apple.com>
+
+ Reviewed by Beth Dakin.
+
+ AX: aria-labelledby duplicates some of its WAI-ARIA label
+ https://bugs.webkit.org/show_bug.cgi?id=31565
+
+ * DumpRenderTree/AccessibilityUIElement.cpp:
+ (titleUIElementCallback):
+ (getIsValidCallback):
+ (AccessibilityUIElement::getJSClass):
+
+2009-11-16 Kenneth Rohde Christiansen <kenneth@webkit.org>
+
+ Reviewed by Simon Hausmann.
+
+ r50942 broke output from created windows. Make the
+ m_enableTextOutput a member of the DRT and not the
+ WebPage.
+
+ * DumpRenderTree/qt/DumpRenderTree.cpp:
+ (WebCore::WebPage::WebPage):
+ (WebCore::WebPage::javaScriptAlert):
+ (WebCore::WebPage::javaScriptConsoleMessage):
+ (WebCore::WebPage::javaScriptConfirm):
+ (WebCore::WebPage::javaScriptPrompt):
+ (WebCore::WebPage::acceptNavigationRequest):
+ (WebCore::DumpRenderTree::DumpRenderTree):
+ (WebCore::DumpRenderTree::open):
+ (WebCore::DumpRenderTree::createWindow):
+ * DumpRenderTree/qt/DumpRenderTree.h:
+ (WebCore::DumpRenderTree::setTextOutputEnabled):
+ (WebCore::DumpRenderTree::isTextOutputEnabled):
+ (WebCore::WebPage::shouldInterruptJavaScript):
+ (WebCore::WebPage::isTextOutputEnabled):
+ (WebCore::WebPage::setViewGeometry):
+
+2009-11-16 Kenneth Rohde Christiansen <kenneth@webkit.org>
+
+ Reviewed by Gustavo Noronha Silva.
+
+ Moved DumpRenderTree/gtk/TestNetscapePlugin to DumpRenderTree/unix/TestNetscapePlugin
+ as the implementation is being used by at least Qt and Gtk+.
+
+ Update buildsystems as well.
+
+ * DumpRenderTree/qt/TestNetscapePlugin/TestNetscapePlugin.pro:
+ * DumpRenderTree/unix/TestNetscapePlugin/ForwardingHeaders/WebKit/npapi.h:
+ * DumpRenderTree/unix/TestNetscapePlugin/ForwardingHeaders/WebKit/npfunctions.h:
+ * DumpRenderTree/unix/TestNetscapePlugin/ForwardingHeaders/WebKit/npruntime.h:
+ * DumpRenderTree/unix/TestNetscapePlugin/TestNetscapePlugin.cpp:
+ * GNUmakefile.am:
+
+2009-11-16 Yuzo Fujishima <yuzo@google.com>
+
+ Reviewed by Alexey Proskuryakov.
+
+ Disable wss until all platforms support pyOpenSSL
+
+ https://bugs.webkit.org/show_bug.cgi?id=31479
+
+ * Scripts/run-webkit-tests:
+
+2009-11-14 Antonio Gomes <tonikitoo@webkit.org>
+
+ Reviewed by Kenneth Christiansen.
+
+ [Qt] Implement load error pages support for Qt's DRT.
+ https://bugs.webkit.org/show_bug.cgi?id=31509
+
+ For now, it will not be a default feature, and layout tests
+ that want to make use of this have to explicitily call
+ 'handleErrorPages();' for the test source.
+
+ Any of the other DumpRenderTree's (mac, win and gtk)
+ support handling error pages. Qt's will be the first.
+
+ * DumpRenderTree/qt/DumpRenderTree.cpp:
+ (WebCore::WebPage::supportsExtension):
+ (WebCore::WebPage::extension):
+ * DumpRenderTree/qt/LayoutTestControllerQt.cpp:
+ (LayoutTestController::reset):
+ * DumpRenderTree/qt/LayoutTestControllerQt.h:
+ (LayoutTestController::shouldHandleErrorPages):
+ (LayoutTestController::handleErrorPages):
+
+2009-11-16 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Rename the --commit-queue flag on land-* now that the commit-queue needs no special treatment
+ https://bugs.webkit.org/show_bug.cgi?id=31549
+
+ Renamed --commit-queue to --non-interactive in most places
+ and remove the code in land-patches which is no longer needed.
+
+ * Scripts/bugzilla-tool:
+
+2009-11-16 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ The commit-queue should use land-attachment
+ https://bugs.webkit.org/show_bug.cgi?id=31548
+
+ * Scripts/bugzilla-tool:
+
+2009-11-16 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Convert CommitQueue over to PatchCollection
+ https://bugs.webkit.org/show_bug.cgi?id=31547
+
+ Also fixes a bug in workqueue and adds a test!
+
+ * Scripts/bugzilla-tool:
+ * Scripts/modules/workqueue.py:
+ * Scripts/modules/workqueue_unittest.py:
+
+2009-11-16 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Move StyleQueue over to using PatchCollection
+ https://bugs.webkit.org/show_bug.cgi?id=31544
+
+ That's what the class it's for.
+
+ * Scripts/bugzilla-tool:
+ * Scripts/modules/patchcollection.py:
+ * Scripts/modules/patchcollection_unittest.py:
+
+2009-11-16 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ bugzilla-tool needs a land-attachment command
+ https://bugs.webkit.org/show_bug.cgi?id=31546
+
+ * Scripts/bugzilla-tool:
+ - Move all the logic into AbstractLandingCommand and
+ add a new LandAttachment command subclass.
+ - Split out _collect_patches_by_bug logging from _fetch_list_of_patches_to_land.
+
+2009-11-16 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Move more patch-landing code into WebKitLandingScripts in preparation for land-attachment
+ https://bugs.webkit.org/show_bug.cgi?id=31543
+
+ Just moving code and updating the one caller to use WebKitLandingScripts instead of 'self'.
+
+ * Scripts/bugzilla-tool:
+
+2009-11-16 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Disable the style queue from posting to the commit queue status page.
+
+ * Scripts/bugzilla-tool:
+
+2009-11-16 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Implement PatchCollection
+ https://bugs.webkit.org/show_bug.cgi?id=31541
+
+ This class holds a set of patches and lets clients iterate through
+ them. Optionally, clients can install a filter.
+
+ * Scripts/modules/patchcollection.py: Added.
+ * Scripts/modules/patchcollection_unittest.py: Added.
+ * Scripts/run-webkit-unittests:
+
+2009-11-16 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ bugzilla-tool land-patches will close bugs with patches r=?
+ https://bugs.webkit.org/show_bug.cgi?id=28230
+
+ The commit-queue shouldn't close patches with outstanding reviews on them,
+ even if many reviewers seem to be against multi-patch bugs.
+
+ * Scripts/bugzilla-tool:
+
+2009-11-16 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ bugzilla-tool check-style should work with attachment ids instead of bug ids
+ https://bugs.webkit.org/show_bug.cgi?id=31540
+
+ * Scripts/bugzilla-tool:
+
+2009-11-16 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ WorkQueue is the only place that should know about special exit codes
+ https://bugs.webkit.org/show_bug.cgi?id=31534
+
+ Move LandPatchesFromBugs.handled_error to WorkQueue.exit_after_handled_error
+ and add tests for handling exit codes.
+ I also cleaned up workqueue_unittest.py more.
+
+ * Scripts/bugzilla-tool:
+ * Scripts/modules/workqueue.py:
+ * Scripts/modules/workqueue_unittest.py:
+
+2009-11-16 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Re-factor workqueue_unittest to allow for more than one test.
+ https://bugs.webkit.org/show_bug.cgi?id=31535
+
+ * Scripts/modules/workqueue_unittest.py:
+
+2009-11-16 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ land-patches needs to be re-factored into smaller chunks
+ https://bugs.webkit.org/show_bug.cgi?id=31532
+
+ * Scripts/bugzilla-tool: fix a couple obvious typos.
+
+2009-11-16 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ land-patches needs to be re-factored into smaller chunks
+ https://bugs.webkit.org/show_bug.cgi?id=31532
+
+ The next patch will move these methods into WebKitLandingScripts.
+
+ * Scripts/bugzilla-tool:
+ - Split out _land_patch and _close_bug_if_no_active_patches.
+
+2009-11-16 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Fix silly copy-and-paste code. I am a terrible coder.
+
+ * Scripts/modules/bugzilla.py:
+
+2009-11-16 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Implement a StyleQueue
+ https://bugs.webkit.org/show_bug.cgi?id=31537
+
+ The first iteration of the style queue only produces output locally.
+ There is also a limit of 10 patches because it's not that useful to
+ iterate through the entire review queue at this point. We can remove
+ the limit later.
+
+ * Scripts/bugzilla-tool:
+ * Scripts/modules/bugzilla.py:
+
+2009-11-16 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Unit test WorkQueue
+ https://bugs.webkit.org/show_bug.cgi?id=31531
+
+ Adds basic unit testing for WorkQueue. Just runs through one cycle.
+
+ * Scripts/bugzilla-tool:
+ * Scripts/modules/statusbot.py:
+ * Scripts/modules/workqueue.py:
+ * Scripts/modules/workqueue_unittest.py: Added.
+ * Scripts/run-webkit-unittests:
+
+2009-11-16 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ bugzilla-tool land-diff should know how to parse bug ids out of ChangeLogs
+ https://bugs.webkit.org/show_bug.cgi?id=31530
+
+ * Scripts/bugzilla-tool:
+
+2009-11-16 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ bugzilla-tool needs apply-attachment
+ https://bugs.webkit.org/show_bug.cgi?id=31528
+
+ * Scripts/bugzilla-tool:
+ - Add ApplyAttachment command.
+ - Abstract applying code into WebKitApplyingScripts.
+ - Rename setup_for_landing to prepare_clean_working_directory and make local_commit checking optional.
+ * Scripts/modules/bugzilla.py:
+ - Add fetch_attachment and bug_id_for_attachment_id.
+ * Scripts/modules/bugzilla_unittest.py:
+ - Add test for new parsing.
+ - Fix previous parsing test which broke with Adam's check-style patch (bug 31515).
+
+2009-11-16 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Document check-style's use of force_clean.
+
+ * Scripts/bugzilla-tool:
+ * Scripts/modules/scm.py:
+
+2009-11-16 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Move WorkQueue to its own file
+ https://bugs.webkit.org/show_bug.cgi?id=31529
+
+ WorkQueue and WorkQueueDelegate are separate concerns from
+ bugzilla-tool. Also added a missing include to logging.py.
+
+ * Scripts/bugzilla-tool:
+ * Scripts/modules/logging.py:
+ * Scripts/modules/workqueue.py:
+
+2009-11-16 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Move OutputTee to logging.py.
+
+ * Scripts/bugzilla-tool:
+ * Scripts/modules/logging.py:
+
+2009-11-15 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Refactor bugzilla-tool to allow for multiple queues
+ https://bugs.webkit.org/show_bug.cgi?id=31513
+
+ Divide the commit queue class into three class to make creating
+ additional queues easier.
+
+ * Scripts/bugzilla-tool:
+
+2009-11-15 Shinichiro Hamaji <hamaji@chromium.org>
+
+ Reviewed by Eric Seidel.
+
+ svn-apply may not handle git patches created by bugzilla-tool
+ https://bugs.webkit.org/show_bug.cgi?id=31457
+
+ * Scripts/modules/scm.py:
+ * Scripts/modules/scm_unittest.py:
+
+2009-11-15 Shinichiro Hamaji <hamaji@chromium.org>
+
+ Reviewed by Eric Seidel.
+
+ bugzilla-tool should post git binary diff
+ https://bugs.webkit.org/show_bug.cgi?id=31458
+
+ Add --binary option to Git.create_patch.
+
+ * Scripts/modules/scm.py:
+ * Scripts/modules/scm_unittest.py:
+
+2009-11-15 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Darin Adler.
+
+ Add bugzilla-tool check-style
+ https://bugs.webkit.org/show_bug.cgi?id=31515
+
+ * Scripts/bugzilla-tool:
+ * Scripts/modules/bugzilla.py:
+
+2009-11-13 Kenneth Rohde Christiansen <kenneth@webkit.org>
+
+ Reviewed by Simon Hausmann.
+
+ Make the Qt Linux only --valgrind feature, suppress errors
+ defined in the SuppressedValgrindErrors file.
+
+ * Scripts/run-webkit-tests:
+
+2009-11-13 Kenneth Rohde Christiansen <kenneth@webkit.org>
+
+ Reviewed by Simon Hausmann.
+
+ Set the locale to C and not to the current one in use on the system.
+
+ * DumpRenderTree/qt/DumpRenderTree.cpp:
+ (WebCore::DumpRenderTree::resetToConsistentStateBeforeTesting):
+
+2009-11-13 Adam Roben <aroben@apple.com>
+
+ Add support for
+ http/tests/security/isolatedWorld/didClearWindowObject.html
+
+ Fixes <http://webkit.org/b/31124> Tell the WebFrameLoadDelegate when
+ window objects in isolated worlds are cleared
+
+ Reviewed by Dave Hyatt.
+
+ * DumpRenderTree/mac/DumpRenderTreeMac.h: Declared worldIDForWorld.
+
+ * DumpRenderTree/mac/FrameLoadDelegate.mm:
+ (-[FrameLoadDelegate didClearWindowObjectInStandardWorldForFrame:]):
+ Added. Moved code here from -webView:didClearWindowObject:forFrame:.
+ (-[FrameLoadDelegate didClearWindowObjectForFrame:inIsolatedWorld:]):
+ Added. Sets a __worldID property on the global object whose value is
+ the ID of this world.
+ (-[FrameLoadDelegate webView:didClearWindowObjectForFrame:inScriptWorld:]):
+ Respond to this new delegate callback by calling through to one of the
+ above new methods.
+ * DumpRenderTree/mac/LayoutTestControllerMac.mm:
+ (worldMap): Added. Returns a HashMap containing all the worlds we've
+ created.
+ (worldIDForWorld): Added. Returns the ID for this world, or 0 if we
+ haven't kept track of this world.
+ (LayoutTestController::evaluateScriptInIsolatedWorld): Use worldMap()
+ instead of declaring our own.
+
+ * DumpRenderTree/win/DumpRenderTreeWin.h: Declared worldIDForWorld.
+
+ * DumpRenderTree/win/FrameLoadDelegate.cpp:
+ (FrameLoadDelegate::didClearWindowObject): Moved code from hear to
+ didClearWindowObjectForFrameInStandardWorld.
+ (FrameLoadDelegate::didClearWindowObjectForFrameInScriptWorld):
+ Respond to this new delegate callback by calling through to one of the
+ below new methods.
+ (FrameLoadDelegate::didClearWindowObjectForFrameInIsolatedWorld):
+ Added. Sets a __worldID property on the gobal object whose value is
+ the ID of this world.
+ (FrameLoadDelegate::didClearWindowObjectForFrameInStandardWorld):
+ Added. Moved code here from didClearWindowObject.
+
+ * DumpRenderTree/win/FrameLoadDelegate.h: Added the
+ didClearWindowObjectForFrame* functions.
+
+ * DumpRenderTree/win/LayoutTestControllerWin.cpp:
+ (worldMap): Added. Returns a HashMap containing all the worlds we've
+ created.
+ (worldIDForWorld): Added. Returns the ID of this world, or 0 if we
+ haven't kept track of this world.
+ (LayoutTestController::evaluateScriptInIsolatedWorld): Use worldMap()
+ instead of declaring our own.
+
+2009-11-13 Adam Roben <aroben@apple.com>
+
+ Finish replacing worldIDs with world objects
+
+ The only remaining use of worldIDs was in a method only used by DRT
+ for the isolated worlds tests.
+
+ Fixes <http://webkit.org/b/31414> Replace worldIDs with world objects
+
+ Reviewed by Mark Rowe.
+
+ * DumpRenderTree/mac/LayoutTestControllerMac.mm:
+ (LayoutTestController::evaluateScriptInIsolatedWorld):
+ * DumpRenderTree/win/LayoutTestControllerWin.cpp:
+ (LayoutTestController::evaluateScriptInIsolatedWorld):
+ Updated for changes to WebFrame. Now holds the map of worldID -> world
+ at this level instead of making WebKit do it.
+
+2009-11-13 Tor Arne Vestbø <tor.arne.vestbo@nokia.com>
+
+ Reviewed by Simon Hausmann.
+
+ [Qt] Ensure the DRT does not output anything until first test is run
+
+ * DumpRenderTree/qt/DumpRenderTree.cpp:
+ * DumpRenderTree/qt/DumpRenderTree.h:
+
+2009-11-13 Kenneth Rohde Christiansen <kenneth@webkit.org>
+
+ Reviewed by Tor Arne Vestbø.
+
+ Clear the undo stack in before each new test run.
+
+ Locally fixes 3 incorrect layouts, 9 timeouts and 7 crashes.
+
+ * DumpRenderTree/qt/DumpRenderTree.cpp:
+ (WebCore::DumpRenderTree::resetToConsistentStateBeforeTesting):
+
+2009-11-13 Andras Becsi <becsi.andras@stud.u-szeged.hu>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ [Qt] Add WebKitUsesPageCachePreferenceKey overriding support to DRT's LayoutTestController.
+
+ * DumpRenderTree/qt/DumpRenderTree.cpp:
+ (WebCore::WebPage::resetSettings):
+ * DumpRenderTree/qt/LayoutTestControllerQt.cpp:
+ (LayoutTestController::overridePreference):
+
+2009-11-13 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Update committers.py based on svn records
+ https://bugs.webkit.org/show_bug.cgi?id=31366
+
+ This list was generated using validate-committer-lists from
+ https://bugs.webkit.org/show_bug.cgi?id=30970
+ and makes committers.py current for committers who have
+ committed in the last 3 years.
+
+ * Scripts/modules/committers.py:
+
+2009-11-12 Anantanarayanan G Iyengar <ananta@chromium.org>
+
+ Reviewed by Adam Barth.
+
+ The document-open.html test was flaky at times. The test invokes the layout test plugin
+ which in its destroy stream handler opens a new document. This basically tears down the
+ stream and the associated plugin instance. The pluginLog function in the layout test
+ plugin attempts to retrieve the window script object on a torn down plugin instance
+ which crashed consistently on windows in the debugger. The functions which issue
+ these logs already have a valid window script object. We now have variants of the pluginLog
+ function which take in a window script object with and without variable arguments.
+
+ https://bugs.webkit.org/show_bug.cgi?id=31067
+
+ * DumpRenderTree/TestNetscapePlugIn.subproj/PluginObject.cpp:
+ (pluginLogWithWindowObject):
+ (pluginLogWithWindowObjectVariableArgs):
+ (pluginLog):
+ (notifyTestCompletion):
+ (testDocumentOpen):
+ (testWindowOpen):
+
+2009-11-12 Joanmarie Diggs <joanmarie.diggs@gmail.com>
+
+ Reviewed by Gustavo Noronha Silva.
+
+ https://bugs.webkit.org/show_bug.cgi?id=30997
+ [Gtk] Implemment AtkDocument
+
+ Added testing support.
+
+ * DumpRenderTree/AccessibilityUIElement.cpp:
+ * DumpRenderTree/AccessibilityUIElement.h:
+ (getDocumentEncodingCallback):
+ (getDocumentURICallback):
+ (AccessibilityUIElement::getJSClass):
+ * DumpRenderTree/gtk/AccessibilityUIElementGtk.cpp:
+ * DumpRenderTree/mac/AccessibilityUIElementMac.mm:
+ * DumpRenderTree/win/AccessibilityUIElementWin.cpp:
+ (AccessibilityUIElement::documentEncoding):
+ (AccessibilityUIElement::documentURI):
+
+2009-11-12 Adam Roben <aroben@apple.com>
+
+ Replace worldIDs with world objects
+
+ Part of <http://webkit.org/b/31414> Implement new SPI for dealing with
+ user scripts/stylesheets and isolated worlds
+
+ Reviewed by Sam Weinig.
+
+ * DumpRenderTree/mac/LayoutTestControllerMac.mm:
+ (LayoutTestController::addUserScript):
+ (LayoutTestController::addUserStyleSheet):
+ * DumpRenderTree/win/LayoutTestControllerWin.cpp:
+ (LayoutTestController::addUserScript):
+ (LayoutTestController::addUserStyleSheet):
+ Changed these functions to create a new WebJSWorld each time they're
+ called and to pass that world to WebKit.
+
+2009-11-11 Chris Fleizach <cfleizach@apple.com>
+
+ Reviewed by Oliver Hunt.
+
+ need to implement aria tree roles
+ https://bugs.webkit.org/show_bug.cgi?id=31284
+
+ * DumpRenderTree/AccessibilityUIElement.cpp:
+ (disclosedRowAtIndexCallback):
+ (selectedRowAtIndexCallback):
+ (isEqualCallback):
+ (isAttributeSettableCallback):
+ (isActionSupportedCallback):
+ (disclosedByRowCallback):
+ (hierarchicalLevelCallback):
+ (AccessibilityUIElement::getJSClass):
+ * DumpRenderTree/AccessibilityUIElement.h:
+ (AccessibilityUIElement::isEqual):
+ * DumpRenderTree/gtk/AccessibilityUIElementGtk.cpp:
+ (AccessibilityUIElement::hierarchicalLevel):
+ (AccessibilityUIElement::disclosedRowAtIndex):
+ (AccessibilityUIElement::selectedRowAtIndex):
+ (AccessibilityUIElement::disclosedByRow):
+ * DumpRenderTree/mac/AccessibilityUIElementMac.mm:
+ (AccessibilityUIElement::getChildAtIndex):
+ (AccessibilityUIElement::disclosedRowAtIndex):
+ (AccessibilityUIElement::selectedRowAtIndex):
+ (AccessibilityUIElement::titleUIElement):
+ (AccessibilityUIElement::parentElement):
+ (AccessibilityUIElement::disclosedByRow):
+ (AccessibilityUIElement::hierarchicalLevel):
+ * DumpRenderTree/win/AccessibilityUIElementWin.cpp:
+ (AccessibilityUIElement::hierarchicalLevel):
+ (AccessibilityUIElement::disclosedRowAtIndex):
+ (AccessibilityUIElement::selectedRowAtIndex):
+ (AccessibilityUIElement::disclosedByRow):
+
+2009-11-11 Shinichiro Hamaji <hamaji@chromium.org>
+
+ Reviewed by Darin Adler.
+
+ svn-apply can not handle git binary diffs
+ https://bugs.webkit.org/show_bug.cgi?id=26830
+
+ Support "literal" type git binary diffs.
+
+ * Scripts/VCSUtils.pm:
+ * Scripts/modules/scm_unittest.py:
+ * Scripts/svn-apply:
+
+2009-11-11 Dmitry Titov <dimich@chromium.org>
+
+ Not reviewed, removing duplicate entry for myself in committers.py.
+
+ * Scripts/modules/committers.py:
+
+2009-11-11 Alexey Proskuryakov <ap@apple.com>
+
+ Reviewed by Darin Adler and Mark Rowe.
+
+ https://bugs.webkit.org/show_bug.cgi?id=31200
+ Tests in http/tests/security/mixedContent start to fail when new tests are added
+
+ * DumpRenderTree/mac/DumpRenderTree.mm: (dumpRenderTree): Added a workaround for Tiger bug.
+
+2009-11-11 Gustavo Noronha Silva <gustavo.noronha@collabora.co.uk>
+
+ Reviewed by Jan Alonzo.
+
+ Create, and display a window for the inspector, for inspector
+ tests.
+
+ Need to also show/hide the inspector window to avoid having
+ problems with code assuming it is realized
+ https://bugs.webkit.org/show_bug.cgi?id=31347
+
+ * DumpRenderTree/gtk/DumpRenderTree.cpp:
+ (webInspectorShowWindow):
+ (webInspectorCloseWindow):
+ (webInspectorInspectWebView):
+ (createWebView):
+
+2009-11-11 Kenneth Rohde Christiansen <kenneth@webkit.org>
+
+ Unreviewed Qt buildbot fix.
+
+ My previous fix was wrong, so revert that change and fix it by
+ returning when the document of the frame has no document element.
+ Idea is borrowed from mac and win DRT.
+
+ * DumpRenderTree/qt/DumpRenderTree.cpp:
+ (WebCore::DumpRenderTree::dumpFramesAsText):
+
+2009-11-11 Eric Seidel <eric@webkit.org>
+
+ Reviewed byg Kenneth Rohde Christiansen.
+
+ Update Kenneth's committer record to include the email he
+ uses on lists.webkit.org.
+
+ * Scripts/modules/committers.py:
+
+2009-11-11 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Gustavo Noronha Silva.
+
+ Several committers use separate email addresses for bugzilla and svn.webkit.org
+ https://bugs.webkit.org/show_bug.cgi?id=31364
+
+ Update records for existing committers to include email addresses
+ used in svn.webkit.org and lists.webkit.org.
+ Most committers use the same email address in all 3 places, but some use
+ separate addresses. committers.py needs record of each of these addresses.
+
+ * Scripts/modules/committers.py:
+
+2009-11-11 Eric Seidel <eric@webkit.org>
+
+ No review, adding second email address for an existing committer.
+
+ Add Yong Li's second bugzilla account to his committer record.
+ See: https://bugs.webkit.org/show_bug.cgi?id=27371#c27
+
+ * Scripts/modules/committers.py:
+
+2009-11-11 Kenneth Rohde Christiansen <kenneth@webkit.org>
+
+ Reviewed by Simon Hausmann.
+
+ If the frame has no innerText don't append it, and
+ do not add a newline which breaks some cross platform
+ results.
+
+ * DumpRenderTree/qt/DumpRenderTree.cpp:
+ (WebCore::DumpRenderTree::dumpFramesAsText):
+
+2009-11-11 Kenneth Rohde Christiansen <kenneth@webkit.org>
+
+ Reviewed by Simon Hausmann.
+
+ Implement missing functionality in the Gtk/Qt TestNetscapePlugin.
+
+ * DumpRenderTree/gtk/TestNetscapePlugin/TestNetscapePlugin.cpp:
+ (webkit_test_plugin_new_instance):
+ (webkit_test_plugin_destroy_instance):
+ (webkit_test_plugin_destroy_stream):
+
+2009-11-11 Kenneth Rohde Christiansen <kenneth@webkit.org>
+
+ Reviewed by Mark Rowe.
+
+ Implement the functionality needed by plugins/window-open.html
+
+ * DumpRenderTree/gtk/TestNetscapePlugin/TestNetscapePlugin.cpp:
+ (webkit_test_plugin_new_instance):
+ (webkit_test_plugin_set_window):
+
+2009-11-11 Tor Arne Vestbø <tor.arne.vestbo@nokia.com>
+
+ Reviewed by Simon Hausmann.
+
+ [Qt] Force -graphicssystem raster and -style windows when running DRT
+
+ * DumpRenderTree/qt/main.cpp:
+ * Scripts/run-webkit-tests:
+
+2009-11-11 Tor Arne Vestbø <tor.arne.vestbo@nokia.com>
+
+ Reviewed by Simon Hausmann.
+
+ Compute correct library paths for Qt
+
+ * Scripts/webkitdirs.pm:
+
+2009-11-10 Mark Rowe <mrowe@apple.com>
+
+ Reviewed by Sam Weinig.
+
+ <http://webkit.org/b/31200> Tests in http/tests/security/mixedContent start to fail when new tests are added
+
+ The first request to an HTTPS URL results in didFailProvisionalLoadWithError being called with an error
+ about the validity of the self-signed certificates used in the regression tests. We would then add the
+ host to the ignore list for SSL certificate errors and retry the request. If this happened during a test
+ that had enabled frame load delegate logging this would result in extra log messages being generated,
+ causing the test to fail.
+
+ We address this by explicitly ignoring SSL certificate errors for localhost and 127.0.0.1 before running any
+ tests.
+
+ * DumpRenderTree/mac/DumpRenderTree.mm:
+ (dumpRenderTree):
+ * DumpRenderTree/mac/FrameLoadDelegate.mm:
+ (-[FrameLoadDelegate webView:didFailProvisionalLoadWithError:forFrame:]):
+
+2009-11-10 Andras Becsi <becsi.andras@stud.u-szeged.hu>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ [Qt] Remove obsolete scrollbar policy settings from DRT constructor.
+
+ * DumpRenderTree/qt/DumpRenderTree.cpp:
+ (WebCore::DumpRenderTree::DumpRenderTree):
+
+2009-11-10 Philippe Normand <pnormand@igalia.com>
+
+ Reviewed by Jan Alonzo.
+
+ [GTK] Remove WebSocket configuration from WebKitWebSettings
+ https://bugs.webkit.org/show_bug.cgi?id=31244
+
+ Follow-up of r50724. Don't set the enable-web-socket property
+ anymore.
+
+ * DumpRenderTree/gtk/DumpRenderTree.cpp:
+ (resetDefaultsToConsistentValues):
+
+2009-11-10 Oliver Hunt <oliver@apple.com>
+
+ Reviewed by Maciej Stachowiak.
+
+ Rename 3D Canvas related classes to use WebGL prefix
+ https://bugs.webkit.org/show_bug.cgi?id=29095
+
+ Checkin new version of do-webcore-rename used to do the WebGL type rename,
+ and upate webkitdirs script to new method of testing for WebGL.
+
+ * Scripts/do-webcore-rename:
+ * Scripts/webkitdirs.pm:
+
+2009-11-09 Oliver Hunt <oliver@apple.com>
+
+ Reviewed by Geoff Garen.
+
+ Make do-webcore-rename work with git.
+
+ * Scripts/do-webcore-rename:
+
+2009-11-09 Simon Hausmann <simon.hausmann@nokia.com>
+
+ Adding Kenneth to the reviewers list.
+
+ * Scripts/modules/committers.py:
+
+2009-11-09 Martin Robinson <martin.james.robinson@gmail.com>
+
+ Reviewed by Jan Alonzo.
+
+ [GTK] Expose Page::tabKeyCyclesThroughElements in the API
+ https://bugs.webkit.org/show_bug.cgi?id=30482
+
+ LayoutTestControllerGtk now uses the exposed
+ Page::tabKeyCyclesThroughElements API
+
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp:
+ (LayoutTestController::setTabKeyCyclesThroughElements):
+
+2009-11-08 Shu Chang <Chang.Shu@nokia.com>
+
+ Reviewed by Holger Freyther.
+
+ [Qt] Added support for key code 8 (backspace) in EventSenderQt.
+ This helps to pass the test case below. Also replaced hardcoded
+ code numbers with defined constants.
+ https://bugs.webkit.org/show_bug.cgi?id=31185
+
+ Test: editing/undo/undo-deleteWord.html
+
+ * DumpRenderTree/qt/EventSenderQt.cpp:
+ (EventSender::keyDown):
+
+2009-11-07 Antonio Gomes <tonikitoo@webkit.org>
+
+ Reviewed by Holger Freyther.
+
+ [Qt] [DRT] Fix wrong logic in LayoutTestController processWork
+ https://bugs.webkit.org/show_bug.cgi?id=31164
+
+ Fixed wrong logic to assume WorkQueue is done in QT's DRT.
+
+ * DumpRenderTree/qt/LayoutTestControllerQt.cpp:
+ (LayoutTestController::processWork):
+
+2009-11-05 Antonio Gomes <tonikitoo@webkit.org>
+
+ Reviewed by Holger Freyther.
+
+ [Qt][DRT] Replace queueScript by queueNonLoadingScript and queueLoadingScript method
+ https://bugs.webkit.org/show_bug.cgi?id=31158
+
+ By invoking a script queue'd by queueScript(), 'true' was beeing returned
+ always, which from WorkQueue prospective means that a load has been started
+ and the queue processing should stop and wait for the load to finish.
+ Spinning it off into a loading and a non-loading variants was the solution
+ adopted by Mac's DRT to work around this problem. The former keeps returning
+ 'true' while the later executes the script synchronously and returns 'false'
+ making it possible to the WorkQueue to proceed right away.
+
+ * DumpRenderTree/qt/LayoutTestControllerQt.cpp:
+ (LayoutTestController::processWork):
+ (LayoutTestController::queueLoadingScript):
+ (LayoutTestController::queueNonLoadingScript):
+ * DumpRenderTree/qt/LayoutTestControllerQt.h:
+ * DumpRenderTree/qt/WorkQueueItem.h:
+ (LoadingScriptItem::LoadingScriptItem):
+ (LoadingScriptItem::invoke):
+ (NonLoadingScriptItem::NonLoadingScriptItem):
+ (NonLoadingScriptItem::invoke):
+
+2009-11-07 Mark Rowe <mrowe@apple.com>
+
+ Rubber-stamped by Cameron Zwarich.
+
+ Invoke prepare-ChangeLog via an absolute path rather than assuming it can be found in PATH.
+
+ * Scripts/commit-log-editor:
+
+2009-11-07 Mark Rowe <mrowe@apple.com>
+
+ Reviewed by Darin Adler.
+
+ Fix <https://bugs.webkit.org/show_bug.cgi?id=28168>.
+ commit-log-editor does not support all the email address configurations that prepare-Changelog supports
+
+ Move logic for determining the name and email address to use in a ChangeLog entry from
+ prepare-ChangeLog to VCSUtils so that commit-log-editor can use it. It wants to check
+ whether the author of the patch matches committer, and therefore needs access to the
+ email address that would be used in a ChangeLog entry.
+
+ Based on a patch by Pierre d'Herbemont.
+
+ * Scripts/VCSUtils.pm:
+ * Scripts/commit-log-editor:
+ * Scripts/prepare-ChangeLog:
+ * Scripts/webkitdirs.pm:
+
+2009-11-06 Anantanarayanan G Iyengar <ananta@chromium.org>
+
+ Reviewed by Adam Barth.
+
+ Added functionality to the layout test plugin to invoke document.open and
+ window.open with default arguments. The associated webkit bug is
+ https://bugs.webkit.org/show_bug.cgi?id=31067, which affects Chromium. Basically
+ window.open and document.open calls issued by NPAPI plugins via NPN_Invoke don't
+ work in Chromium (V8) if there is no calling javascript context. To achieve this
+ effect we invoke these functions in the layout test plugin in the NPP_SetWindow
+ for the window.open test case and in NPP_DestroyStream for the document.open test case.
+
+ * DumpRenderTree/TestNetscapePlugIn.subproj/PluginObject.cpp:
+ (testDocumentOpen):
+ (testWindowOpen):
+ (pluginAllocate):
+ * DumpRenderTree/TestNetscapePlugIn.subproj/PluginObject.h:
+ * DumpRenderTree/TestNetscapePlugIn.subproj/main.cpp:
+ (NPP_New):
+ (NPP_SetWindow):
+ (NPP_DestroyStream):
+ * DumpRenderTree/win/TestNetscapePlugin/main.cpp:
+ (NPP_New):
+ (NPP_SetWindow):
+ (NPP_NewStream):
+ (NPP_DestroyStream):
+
+2009-11-06 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ bugzilla-tool crashed with exception
+ https://bugs.webkit.org/show_bug.cgi?id=31092
+
+ * Scripts/modules/bugzilla.py: Change a ',' to a '%' to fix the error.
+
+2009-11-04 Eric Seidel <eric@webkit.org>
+
+ No review, just add a line which got left out of the patch uploaded for commit.
+
+ commit-queue is crashing when trying to reject patches after unknown failures
+ https://bugs.webkit.org/show_bug.cgi?id=31091
+
+ * Scripts/bugzilla-tool: Set bug_log = None after closing to we don't re-close and crash.
+
+2009-11-04 Adam Roben <aroben@apple.com>
+
+ Remove bogus else clause in bugzilla-tool
+
+ Fixes <http://webkit.org/b/31125> REGRESSION (r47121): bugzilla-tool
+ create-bug raises exception after entering bug description
+
+ Reviewed by David Kilzer.
+
+ * Scripts/bugzilla-tool:
+ (CreateBug): else clauses are only hit if no exception is raised, so
+ it makes no sense to try to re-raise the exception in an else clause.
+ The exception will automatically be re-raised if it doesn't match any
+ of the except clauses, so we don't have to do anything special here at
+ all to get the desired behavior.
+
+2009-11-04 Eric Seidel <eric@webkit.org>
+
+ Reviewed by David Kilzer.
+
+ svn-apply's fixChangeLogPatch function seems broken
+ https://bugs.webkit.org/show_bug.cgi?id=30683
+
+ Update fixChangeLogPatch to be able to handle patches which
+ don't start at line 1.
+ Add unit tests for svn-apply to scm_unittest.py.
+
+ * Scripts/VCSUtils.pm:
+ * Scripts/modules/scm_unittest.py:
+
+2009-11-04 Chris Fleizach <cfleizach@apple.com>
+
+ Reviewed by Beth Dakin.
+
+ Need to implement ARIA role="combobox"
+ https://bugs.webkit.org/show_bug.cgi?id=31096
+
+ * DumpRenderTree/AccessibilityUIElement.cpp:
+ (showMenuCallback):
+ (getIsExpandedCallback):
+ (AccessibilityUIElement::getJSClass):
+ * DumpRenderTree/AccessibilityUIElement.h:
+ * DumpRenderTree/gtk/AccessibilityUIElementGtk.cpp:
+ (AccessibilityUIElement::isExpanded):
+ (AccessibilityUIElement::showMenu):
+ * DumpRenderTree/mac/AccessibilityUIElementMac.mm:
+ (AccessibilityUIElement::isExpanded):
+ (AccessibilityUIElement::showMenu):
+ * DumpRenderTree/win/AccessibilityUIElementWin.cpp:
+ (AccessibilityUIElement::isSelected):
+ (AccessibilityUIElement::isExpanded):
+ (AccessibilityUIElement::showMenu):
+
+2009-11-04 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ commit-queue is crashing when trying to reject patches after unknown failures
+ https://bugs.webkit.org/show_bug.cgi?id=31091
+
+ * Scripts/bugzilla-tool:
+ - patch['id'] was a copy/paste mistake. This code has no 'patch' variable
+ so we have to find out what the current patch is by asking bugzilla again.
+ - Discovered that this code was also leaking file descriptors, so fixed that.
+
+2009-11-04 Adam Roben <aroben@apple.com>
+
+ Make run-webkit-tests work for the Debug_Internal Windows
+ configuration
+
+ In Debug_Internal, DumpRenderTree.exe and ImageDiff.exe have no _debug
+ suffix.
+
+ Fixes <http://webkit.org/b/31123>.
+
+ Reviewed by Sam Weinig.
+
+ * Scripts/run-webkit-tests: Don't add the _debug suffix in
+ Debug_Internal, either.
+
+2009-11-04 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ committers.py needs a way to store non-bugzilla email addresses
+ https://bugs.webkit.org/show_bug.cgi?id=31037
+
+ Make Committer and Reviewer constructors take a single email or a list of emails.
+ Change committer_by_bugzilla_email functions to committer_by_email to support lookup by any email.
+ Expose reviewers(), used by validate-committer-lists on bug 30970.
+
+ * Scripts/modules/committers.py:
+ * Scripts/modules/committers_unittest.py: Added tests for the new code.
+
+2009-11-03 Yuzo Fujishima <yuzo@google.com>
+
+ Reviewed by David Levin.
+
+ Start/Stop Web Socket and Web Socket Secure servers for layout tests.
+ https://bugs.webkit.org/show_bug.cgi?id=27491
+
+ The test path determination logic is changed to handle websocket and websocket/ssl cases.
+ The logic for non-http (and now also non-websocket) tests is moved toward the end of the if-elsif statement.
+
+ Functions to start or stop Web Socket servers are added.
+
+ * Scripts/run-webkit-tests:
+
+2009-11-03 Eric Seidel <eric@webkit.org>
+
+ No review, just changing wording of log message.
+
+ Change log string to say "failed" instead of "rejected"
+ when a commit fails due to an out of date checkout.
+ This makes grepping the commit-queue log for rejected patches easier.
+
+ * Scripts/bugzilla-tool:
+
+2009-11-03 Eric Seidel <eric@webkit.org>
+
+ No review, adding commonly known committers missing from the file.
+
+ * Scripts/modules/committers.py: Add committers found by looking at SVN records.
+
+2009-11-03 Eric Seidel <eric@webkit.org>
+
+ No review, just sort-order cleanup.
+
+ * Scripts/modules/committers.py: Sort committers/reviewers alphabetically.
+
+2009-11-03 Stephen White <senorblanco@chromium.org>
+
+ (Unreviewed).
+
+ Add myself to committers.py.
+
+ * Scripts/modules/committers.py:
+
+2009-11-03 Robin Dunn <robin@alldunn.com>
+
+ Reviewed by Kevin Ollviier.
+
+ Add packaging scripts for Debian-based Linux distros.
+
+ https://bugs.webkit.org/show_bug.cgi?id=31075
+
+ * wx/packaging/build-debian-installer.py: Added.
+ * wx/packaging/debian: Added.
+
+2009-11-03 Dan Bernstein <mitz@apple.com>
+
+ Reviewed by Anders Carlsson and Beth Dakin.
+
+ https://bugs.webkit.org/show_bug.cgi?id=31070
+
+ Added an 'ondestroy' parameter to the test plug-in. When the plug-in is
+ destroyed, it executes the value of the 'ondestroy' parameter as a
+ script.
+
+ * DumpRenderTree/TestNetscapePlugIn.subproj/PluginObject.cpp:
+ (pluginAllocate): Initialize onDestroy.
+ * DumpRenderTree/TestNetscapePlugIn.subproj/PluginObject.h: Define
+ onDestroy.
+ * DumpRenderTree/TestNetscapePlugIn.subproj/main.cpp:
+ (NPP_New): Set onDestroy to the value of the 'ondestroy' parameter, if
+ specified.
+ (NPP_Destroy): Execute the value of 'ondestroy' as a script.
+
+2009-11-02 Joanmarie Diggs <joanmarie.diggs@gmail.com>
+
+ Reviewed by Xan Lopez.
+
+ https://bugs.webkit.org/show_bug.cgi?id=31035
+ [GTK] some accessibility tests hitting assertion in debug builds
+
+ Get the correct Gtk+ object before attempting to turn it into an AtkObject.
+
+ * DumpRenderTree/gtk/AccessibilityControllerGtk.cpp:
+ (AccessibilityController::rootElement):
+
+2009-11-02 Chris Fleizach <cfleizach@apple.com>
+
+ Reviewed by Beth Dakin.
+
+ Support ARIA "tab" roles
+ https://bugs.webkit.org/show_bug.cgi?id=30842
+
+ * DumpRenderTree/AccessibilityUIElement.cpp:
+ * DumpRenderTree/AccessibilityUIElement.h:
+ * DumpRenderTree/gtk/AccessibilityUIElementGtk.cpp:
+ * DumpRenderTree/mac/AccessibilityUIElementMac.mm:
+ * DumpRenderTree/win/AccessibilityUIElementWin.cpp:
+
+2009-11-01 Eric Seidel <eric@webkit.org>
+
+ Reviewed by David Levin.
+
+ buildbots should use --exit-after-N-failures
+ https://bugs.webkit.org/show_bug.cgi?id=30809
+
+ Make the bots exit after 20 failures to prevent never-ending
+ test runs where every test spends a minute crashing.
+
+ * BuildSlaveSupport/build.webkit.org-config/master.cfg:
+
+2009-11-01 Laszlo Gombos <laszlo.1.gombos@nokia.com>
+
+ Reviewed by Eric Seidel.
+
+ Turn on warnings for QtWebKit for gcc
+ https://bugs.webkit.org/show_bug.cgi?id=30958
+
+ * DumpRenderTree/qt/main.cpp:
+ (crashHandler): Mark function NO_RETURN
+
+2009-11-01 Jessie Berlin <jberlin@webkit.org>
+
+ Adding myself to the committers list.
+
+ * Scripts/modules/committers.py:
+
+2009-10-30 Jon Honeycutt <jhoneycutt@apple.com>
+
+ Fix an issue that Adam noticed in DRT.
+
+ Reviewed by Darin Adler.
+
+ * DumpRenderTree/win/AccessibilityUIElementWin.cpp:
+ (AccessibilityUIElement::role):
+ Get the length of the role text, and create a buffer dynamically.
+
+2009-10-30 Eric Seidel <eric@webkit.org>
+
+ No review, rolling out r50105.
+ http://trac.webkit.org/changeset/50105
+
+ This commit was causing:
+ https://bugs.webkit.org/show_bug.cgi?id=30869
+ We'll re-implement the feature a different way.
+
+ * Scripts/bugzilla-tool:
+
+2009-10-29 Jon Honeycutt <jhoneycutt@apple.com>
+
+ Test for MSAA: Accessibility of headings is not correct
+
+ https://bugs.webkit.org/show_bug.cgi?id=30937
+
+ Reviewed by Adam Roben.
+
+ * DumpRenderTree/win/AccessibilityUIElementWin.cpp:
+ (AccessibilityUIElement::role):
+ Allow the role returned to be a BSTR.
+ (AccessibilityUIElement::description):
+ Fix a copy/paste error.
+
+2009-10-29 Jon Honeycutt <jhoneycutt@apple.com>
+
+ Test for MSAA: Accessibility of links is wrong
+
+ https://bugs.webkit.org/show_bug.cgi?id=30928
+
+ Reviewed by Darin Adler.
+
+ * DumpRenderTree/AccessibilityUIElement.cpp:
+ (getAccessibilityValueCallback):
+ Return the accessibility value.
+ (AccessibilityUIElement::getJSClass):
+ Added "accessibilityValue" value.
+
+ * DumpRenderTree/AccessibilityUIElement.h:
+
+ * DumpRenderTree/gtk/AccessibilityUIElementGtk.cpp:
+ (AccessibilityUIElement::accessibilityValue):
+ Stubbed.
+
+ * DumpRenderTree/mac/AccessibilityUIElementMac.mm:
+ (AccessibilityUIElement::accessibilityValue):
+ Stubbed.
+
+ * DumpRenderTree/win/AccessibilityUIElementWin.cpp:
+ (AccessibilityUIElement::accessibilityValue):
+ Get the object's value, and return it as a JS string.
+
+2009-10-30 Kevin Ollivier <kevino@theolliviers.com>
+
+ Fix typo in command name used by wx build system.
+
+ * wx/build/build_utils.py:
+
+2009-10-30 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Darin Adler.
+
+ Patch v1 is a dumb default name for patches
+ https://bugs.webkit.org/show_bug.cgi?id=30952
+
+ Let's use "Patch" instead.
+
+ * Scripts/bugzilla-tool:
+
+2009-10-30 Andras Becsi <becsi.andras@stud.u-szeged.hu>
+
+ Unreviewed trivial buildfix.
+
+ [Qt] Buildfix for r50333.
+
+ * DumpRenderTree/qt/DumpRenderTree.pro:
+
+2009-10-30 Antonio Gomes <tonikitoo@webkit.org>
+
+ Reviewed by Holger Freyther.
+
+ [Qt] Remove qt/WorkQueue.cpp|h in favor of platform independent WorkQueue
+ https://bugs.webkit.org/show_bug.cgi?id=30953
+
+ DumpRenderTree/WorkQueue and DumpRenderTree/qt/WorkQueue share mostly the
+ same implementation. Some Q_ASSERTs differ from ASSERTs basically. Patch
+ makes qt DRT to share this implementation (as gtk and mac ports do).
+
+ * DumpRenderTree/qt/DumpRenderTree.pro:
+ * DumpRenderTree/qt/WorkQueue.cpp: Removed.
+ * DumpRenderTree/qt/WorkQueue.h: Removed.
+
+2009-10-30 Kenneth Rohde Christiansen <kenneth@webkit.org>
+
+ Unreviewed potential buildbot fix.
+
+ Second try: Reset page history before running each test.
+
+ Apparently the QWebHistory::clear() keeps the current page
+ in history which is not what we want, so we not additionally
+ sets the history capacity to 0 (forces removing everything)
+ and then sets it back to its original value.
+
+ * DumpRenderTree/qt/DumpRenderTree.cpp:
+ (WebCore::DumpRenderTree::resetToConsistentStateBeforeTesting):
+
+2009-10-30 Kenneth Rohde Christiansen <kenneth@webkit.org>
+
+ Unreviewed potential buildbot fix.
+
+ Reset page history before running each test.
+
+ * DumpRenderTree/qt/DumpRenderTree.cpp:
+ (WebCore::DumpRenderTree::resetToConsistentStateBeforeTesting):
+
+2009-10-30 Roland Steiner <rolandsteiner@chromium.org>
+
+ Reviewed by Eric Seidel.
+
+ Remove ENABLE_RUBY guards as discussed with Dave Hyatt and Maciej Stachowiak.
+
+ Bug 28420 - Implement HTML5 <ruby> rendering
+ (https://bugs.webkit.org/show_bug.cgi?id=28420)
+
+ No new tests (no functional change).
+
+ * Scripts/build-webkit:
+
+2009-10-29 Dan Bernstein <mitz@apple.com>
+
+ Reviewed by Mark Rowe.
+
+ Fix “Undefined subroutine” errors in svn-*apply by moving the removeEOL subroutine
+ from the two scripts that define it but don’t use it to the script that uses it but doesn’t
+ define it.
+
+ * Scripts/VCSUtils.pm:
+ * Scripts/svn-apply:
+ * Scripts/svn-unapply:
+
+2009-10-29 Xan Lopez <xlopez@igalia.com>
+
+ Reviewed by Gustavo Noronha.
+
+ Use the GTK+ main loop instead of rolling our own mini-version of
+ it.
+
+ * DumpRenderTree/gtk/DumpRenderTree.cpp:
+ (dump):
+ (runTest):
+ (webViewLoadFinished):
+
+2009-10-29 Kenneth Rohde Christiansen <kenneth@webkit.org>
+
+ Reviewed by Oliver Hunt.
+
+ Implement the Qt version of DRT dumpBackForwardList().
+
+ * DumpRenderTree/qt/DumpRenderTree.cpp:
+ (WebCore::dumpHistoryItem):
+ (WebCore::DumpRenderTree::dumpBackForwardList):
+
+2009-10-29 Kenneth Rohde Christiansen <kenneth@webkit.org>
+
+ Reviewed by Adam Roben.
+
+ Implement DRT functionality for Qt introduced in
+ r28690 and r28705.
+
+ - Implemented pathToLocalResource which exposes the functionality of
+ converting a given unix path to the correct location on Windows.
+ - Implemented a way to remove machine-dependent information from paths
+ in layout test results.
+
+ * DumpRenderTree/qt/DumpRenderTree.cpp:
+ (WebCore::urlSuitableForTestResult):
+ (WebCore::WebPage::javaScriptConsoleMessage):
+ * DumpRenderTree/qt/LayoutTestControllerQt.cpp:
+ (LayoutTestController::pathToLocalResource):
+ * DumpRenderTree/qt/LayoutTestControllerQt.h:
+
2009-10-28 Roland Steiner <rolandsteiner@chromium.org>
Adding myself to the committers list.
diff --git a/WebKitTools/DumpRenderTree/AccessibilityController.cpp b/WebKitTools/DumpRenderTree/AccessibilityController.cpp
index af1daf6..d3688f4 100644
--- a/WebKitTools/DumpRenderTree/AccessibilityController.cpp
+++ b/WebKitTools/DumpRenderTree/AccessibilityController.cpp
@@ -48,7 +48,11 @@ static JSValueRef getRootElementCallback(JSContextRef context, JSObjectRef thisO
void AccessibilityController::makeWindowObject(JSContextRef context, JSObjectRef windowObject, JSValueRef* exception)
{
JSRetainPtr<JSStringRef> accessibilityControllerStr(Adopt, JSStringCreateWithUTF8CString("accessibilityController"));
- JSValueRef accessibilityControllerObject = JSObjectMake(context, getJSClass(), this);
+
+ JSClassRef classRef = getJSClass();
+ JSValueRef accessibilityControllerObject = JSObjectMake(context, classRef, this);
+ JSClassRelease(classRef);
+
JSObjectSetProperty(context, windowObject, accessibilityControllerStr.get(), accessibilityControllerObject, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete, exception);
}
@@ -85,8 +89,7 @@ JSClassRef AccessibilityController::getJSClass()
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
- static JSClassRef accessibilityControllerClass = JSClassCreate(&classDefinition);
- return accessibilityControllerClass;
+ return JSClassCreate(&classDefinition);
}
void AccessibilityController::resetToConsistentState()
diff --git a/WebKitTools/DumpRenderTree/AccessibilityUIElement.cpp b/WebKitTools/DumpRenderTree/AccessibilityUIElement.cpp
index 5958ccb..8c59252 100644
--- a/WebKitTools/DumpRenderTree/AccessibilityUIElement.cpp
+++ b/WebKitTools/DumpRenderTree/AccessibilityUIElement.cpp
@@ -161,6 +161,53 @@ static JSValueRef childAtIndexCallback(JSContextRef context, JSObjectRef functio
return AccessibilityUIElement::makeJSAccessibilityUIElement(context, toAXElement(thisObject)->getChildAtIndex(indexNumber));
}
+static JSValueRef disclosedRowAtIndexCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ int indexNumber = 0;
+ if (argumentCount == 1)
+ indexNumber = JSValueToNumber(context, arguments[0], exception);
+
+ return AccessibilityUIElement::makeJSAccessibilityUIElement(context, toAXElement(thisObject)->disclosedRowAtIndex(indexNumber));
+}
+
+static JSValueRef ariaOwnsElementAtIndexCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ int indexNumber = 0;
+ if (argumentCount == 1)
+ indexNumber = JSValueToNumber(context, arguments[0], exception);
+
+ return AccessibilityUIElement::makeJSAccessibilityUIElement(context, toAXElement(thisObject)->ariaOwnsElementAtIndex(indexNumber));
+}
+
+static JSValueRef ariaFlowToElementAtIndexCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ int indexNumber = 0;
+ if (argumentCount == 1)
+ indexNumber = JSValueToNumber(context, arguments[0], exception);
+
+ return AccessibilityUIElement::makeJSAccessibilityUIElement(context, toAXElement(thisObject)->ariaFlowToElementAtIndex(indexNumber));
+}
+
+static JSValueRef selectedRowAtIndexCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ int indexNumber = 0;
+ if (argumentCount == 1)
+ indexNumber = JSValueToNumber(context, arguments[0], exception);
+
+ return AccessibilityUIElement::makeJSAccessibilityUIElement(context, toAXElement(thisObject)->selectedRowAtIndex(indexNumber));
+}
+
+static JSValueRef isEqualCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ JSObjectRef otherElement = 0;
+ if (argumentCount == 1)
+ otherElement = JSValueToObject(context, arguments[0], exception);
+ else
+ return JSValueMakeBoolean(context, false);
+
+ return JSValueMakeBoolean(context, toAXElement(thisObject)->isEqual(toAXElement(otherElement)));
+}
+
static JSValueRef elementAtPointCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
{
int x = 0;
@@ -173,13 +220,23 @@ static JSValueRef elementAtPointCallback(JSContextRef context, JSObjectRef funct
return AccessibilityUIElement::makeJSAccessibilityUIElement(context, toAXElement(thisObject)->elementAtPoint(x, y));
}
+static JSValueRef isAttributeSupportedCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ JSStringRef attribute = 0;
+ if (argumentCount == 1)
+ attribute = JSValueToStringCopy(context, arguments[0], exception);
+ JSValueRef result = JSValueMakeBoolean(context, toAXElement(thisObject)->isAttributeSupported(attribute));
+ if (attribute)
+ JSStringRelease(attribute);
+ return result;
+}
static JSValueRef isAttributeSettableCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
{
- JSStringRef attribute = NULL;
+ JSStringRef attribute = 0;
if (argumentCount == 1)
attribute = JSValueToStringCopy(context, arguments[0], exception);
- JSValueRef result = JSValueMakeNumber(context, toAXElement(thisObject)->isAttributeSettable(attribute));
+ JSValueRef result = JSValueMakeBoolean(context, toAXElement(thisObject)->isAttributeSettable(attribute));
if (attribute)
JSStringRelease(attribute);
return result;
@@ -191,7 +248,7 @@ static JSValueRef isActionSupportedCallback(JSContextRef context, JSObjectRef fu
JSStringRef action = 0;
if (argumentCount == 1)
action = JSValueToStringCopy(context, arguments[0], exception);
- JSValueRef result = JSValueMakeNumber(context, toAXElement(thisObject)->isActionSupported(action));
+ JSValueRef result = JSValueMakeBoolean(context, toAXElement(thisObject)->isActionSupported(action));
if (action)
JSStringRelease(action);
return result;
@@ -199,7 +256,7 @@ static JSValueRef isActionSupportedCallback(JSContextRef context, JSObjectRef fu
static JSValueRef attributeValueCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
{
- JSStringRef attribute = NULL;
+ JSStringRef attribute = 0;
if (argumentCount == 1)
attribute = JSValueToStringCopy(context, arguments[0], exception);
JSRetainPtr<JSStringRef> attributeValue(Adopt, toAXElement(thisObject)->attributeValue(attribute));
@@ -230,6 +287,11 @@ static JSValueRef parentElementCallback(JSContextRef context, JSObjectRef functi
return AccessibilityUIElement::makeJSAccessibilityUIElement(context, toAXElement(thisObject)->parentElement());
}
+static JSValueRef disclosedByRowCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ return AccessibilityUIElement::makeJSAccessibilityUIElement(context, toAXElement(thisObject)->disclosedByRow());
+}
+
static JSValueRef setSelectedTextRangeCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
{
unsigned location = UINT_MAX, length = 0;
@@ -239,24 +301,51 @@ static JSValueRef setSelectedTextRangeCallback(JSContextRef context, JSObjectRef
}
toAXElement(thisObject)->setSelectedTextRange(location, length);
- return 0;
+ return JSValueMakeUndefined(context);
}
static JSValueRef incrementCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
{
toAXElement(thisObject)->increment();
- return 0;
+ return JSValueMakeUndefined(context);
}
static JSValueRef decrementCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
{
toAXElement(thisObject)->decrement();
- return 0;
+ return JSValueMakeUndefined(context);
}
+static JSValueRef showMenuCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ toAXElement(thisObject)->showMenu();
+ return JSValueMakeUndefined(context);
+}
// Static Value Getters
+static JSValueRef getARIADropEffectsCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception)
+{
+ JSRetainPtr<JSStringRef> dropEffects(Adopt, toAXElement(thisObject)->ariaDropEffects());
+ return JSValueMakeString(context, dropEffects.get());
+}
+
+static JSValueRef getARIAIsGrabbedCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception)
+{
+ return JSValueMakeBoolean(context, toAXElement(thisObject)->ariaIsGrabbed());
+}
+
+static JSValueRef getIsValidCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception)
+{
+ AccessibilityUIElement* uiElement = toAXElement(thisObject);
+ if (!uiElement->platformUIElement())
+ return JSValueMakeBoolean(context, false);
+
+ // There might be other platform logic that one could check here...
+
+ return JSValueMakeBoolean(context, true);
+}
+
static JSValueRef getRoleCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception)
{
JSRetainPtr<JSStringRef> role(Adopt, toAXElement(thisObject)->role());
@@ -269,6 +358,12 @@ static JSValueRef getSubroleCallback(JSContextRef context, JSObjectRef thisObjec
return JSValueMakeString(context, role.get());
}
+static JSValueRef getRoleDescriptionCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception)
+{
+ JSRetainPtr<JSStringRef> roleDesc(Adopt, toAXElement(thisObject)->roleDescription());
+ return JSValueMakeString(context, roleDesc.get());
+}
+
static JSValueRef getTitleCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception)
{
JSRetainPtr<JSStringRef> title(Adopt, toAXElement(thisObject)->title());
@@ -281,12 +376,24 @@ static JSValueRef getDescriptionCallback(JSContextRef context, JSObjectRef thisO
return JSValueMakeString(context, description.get());
}
+static JSValueRef getStringValueCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception)
+{
+ JSRetainPtr<JSStringRef> stringValue(Adopt, toAXElement(thisObject)->stringValue());
+ return JSValueMakeString(context, stringValue.get());
+}
+
static JSValueRef getLanguageCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception)
{
JSRetainPtr<JSStringRef> language(Adopt, toAXElement(thisObject)->language());
return JSValueMakeString(context, language.get());
}
+static JSValueRef getOrientationCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception)
+{
+ JSRetainPtr<JSStringRef> orientation(Adopt, toAXElement(thisObject)->orientation());
+ return JSValueMakeString(context, orientation.get());
+}
+
static JSValueRef getChildrenCountCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception)
{
return JSValueMakeNumber(context, toAXElement(thisObject)->childrenCount());
@@ -358,12 +465,45 @@ static JSValueRef getIsRequiredCallback(JSContextRef context, JSObjectRef thisOb
return JSValueMakeBoolean(context, toAXElement(thisObject)->isRequired());
}
+static JSValueRef getIsSelectedCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef, JSValueRef*)
+{
+ return JSValueMakeBoolean(context, toAXElement(thisObject)->isSelected());
+}
+
+static JSValueRef getIsExpandedCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef, JSValueRef*)
+{
+ return JSValueMakeBoolean(context, toAXElement(thisObject)->isExpanded());
+}
+
+static JSValueRef hierarchicalLevelCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef, JSValueRef*)
+{
+ return JSValueMakeNumber(context, toAXElement(thisObject)->hierarchicalLevel());
+}
+
static JSValueRef getValueDescriptionCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception)
{
JSRetainPtr<JSStringRef> valueDescription(Adopt, toAXElement(thisObject)->valueDescription());
return JSValueMakeString(context, valueDescription.get());
}
+static JSValueRef getAccessibilityValueCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception)
+{
+ JSRetainPtr<JSStringRef> accessibilityValue(Adopt, toAXElement(thisObject)->accessibilityValue());
+ return JSValueMakeString(context, accessibilityValue.get());
+}
+
+static JSValueRef getDocumentEncodingCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception)
+{
+ JSRetainPtr<JSStringRef> documentEncoding(Adopt, toAXElement(thisObject)->documentEncoding());
+ return JSValueMakeString(context, documentEncoding.get());
+}
+
+static JSValueRef getDocumentURICallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception)
+{
+ JSRetainPtr<JSStringRef> documentURI(Adopt, toAXElement(thisObject)->documentURI());
+ return JSValueMakeString(context, documentURI.get());
+}
+
// Destruction
static void finalize(JSObjectRef thisObject)
@@ -381,11 +521,14 @@ JSObjectRef AccessibilityUIElement::makeJSAccessibilityUIElement(JSContextRef co
JSClassRef AccessibilityUIElement::getJSClass()
{
static JSStaticValue staticValues[] = {
+ { "accessibilityValue", getAccessibilityValueCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "role", getRoleCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "subrole", getSubroleCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "roleDescription", getRoleDescriptionCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "title", getTitleCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "description", getDescriptionCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "language", getLanguageCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "stringValue", getStringValueCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "x", getXCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "y", getYCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "width", getWidthCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
@@ -400,7 +543,16 @@ JSClassRef AccessibilityUIElement::getJSClass()
{ "selectedTextRange", getSelectedTextRangeCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "isEnabled", getIsEnabledCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "isRequired", getIsRequiredCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "isSelected", getIsSelectedCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "isExpanded", getIsExpandedCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "valueDescription", getValueDescriptionCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "hierarchicalLevel", hierarchicalLevelCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "documentEncoding", getDocumentEncodingCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "documentURI", getDocumentURICallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "isValid", getIsValidCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "orientation", getOrientationCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "ariaIsGrabbed", getARIAIsGrabbedCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "ariaDropEffects", getARIADropEffectsCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ 0, 0, 0, 0 }
};
@@ -428,11 +580,19 @@ JSClassRef AccessibilityUIElement::getJSClass()
{ "titleUIElement", titleUIElementCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "setSelectedTextRange", setSelectedTextRangeCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "attributeValue", attributeValueCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "isAttributeSupported", isAttributeSupportedCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "isAttributeSettable", isAttributeSettableCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "isActionSupported", isActionSupportedCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "parentElement", parentElementCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "disclosedByRow", disclosedByRowCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "increment", incrementCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "decrement", decrementCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "showMenu", showMenuCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "disclosedRowAtIndex", disclosedRowAtIndexCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "ariaOwnsElementAtIndex", ariaOwnsElementAtIndexCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "ariaFlowToElementAtIndex", ariaFlowToElementAtIndexCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "selectedRowAtIndex", selectedRowAtIndexCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "isEqual", isEqualCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ 0, 0, 0 }
};
diff --git a/WebKitTools/DumpRenderTree/AccessibilityUIElement.h b/WebKitTools/DumpRenderTree/AccessibilityUIElement.h
index fffdad8..9985523 100644
--- a/WebKitTools/DumpRenderTree/AccessibilityUIElement.h
+++ b/WebKitTools/DumpRenderTree/AccessibilityUIElement.h
@@ -61,6 +61,8 @@ public:
static JSObjectRef makeJSAccessibilityUIElement(JSContextRef, const AccessibilityUIElement&);
+ bool isEqual(AccessibilityUIElement* otherElement) { return platformUIElement() == otherElement->platformUIElement(); }
+
void getLinkedUIElements(Vector<AccessibilityUIElement>&);
void getDocumentLinks(Vector<AccessibilityUIElement>&);
void getChildren(Vector<AccessibilityUIElement>&);
@@ -80,16 +82,22 @@ public:
JSStringRef parameterizedAttributeNames();
void increment();
void decrement();
+ void showMenu();
// Attributes - platform-independent implementations
JSStringRef attributeValue(JSStringRef attribute);
+ bool isAttributeSupported(JSStringRef attribute);
bool isAttributeSettable(JSStringRef attribute);
bool isActionSupported(JSStringRef action);
JSStringRef role();
JSStringRef subrole();
+ JSStringRef roleDescription();
JSStringRef title();
JSStringRef description();
JSStringRef language();
+ JSStringRef stringValue();
+ JSStringRef accessibilityValue() const;
+ JSStringRef orientation() const;
double x();
double y();
double width();
@@ -102,8 +110,13 @@ public:
JSStringRef selectedTextRange();
bool isEnabled();
bool isRequired() const;
+ bool isSelected() const;
+ bool isExpanded() const;
+ int hierarchicalLevel() const;
double clickPointX();
double clickPointY();
+ JSStringRef documentEncoding();
+ JSStringRef documentURI();
// Table-specific attributes
JSStringRef attributesOfColumnHeaders();
@@ -116,6 +129,20 @@ public:
JSStringRef rowIndexRange();
JSStringRef columnIndexRange();
+ // Tree/Outline specific attributes
+ AccessibilityUIElement selectedRowAtIndex(unsigned);
+ AccessibilityUIElement disclosedByRow();
+ AccessibilityUIElement disclosedRowAtIndex(unsigned);
+
+ // ARIA specific
+ AccessibilityUIElement ariaOwnsElementAtIndex(unsigned);
+ AccessibilityUIElement ariaFlowToElementAtIndex(unsigned);
+
+ // ARIA Drag and Drop
+ bool ariaIsGrabbed() const;
+ // A space concatentated string of all the drop effects.
+ JSStringRef ariaDropEffects() const;
+
// Parameterized attributes
int lineForIndex(int);
JSStringRef boundsForRange(unsigned location, unsigned length);
diff --git a/WebKitTools/DumpRenderTree/GCController.cpp b/WebKitTools/DumpRenderTree/GCController.cpp
index fe84a58..06a04fb 100644
--- a/WebKitTools/DumpRenderTree/GCController.cpp
+++ b/WebKitTools/DumpRenderTree/GCController.cpp
@@ -74,28 +74,15 @@ static JSValueRef getJSObjectCountCallback(JSContextRef context, JSObjectRef fun
void GCController::makeWindowObject(JSContextRef context, JSObjectRef windowObject, JSValueRef* exception)
{
JSRetainPtr<JSStringRef> gcControllerStr(Adopt, JSStringCreateWithUTF8CString("GCController"));
- JSValueRef gcControllerObject = JSObjectMake(context, getJSClass(), this);
- JSObjectSetProperty(context, windowObject, gcControllerStr.get(), gcControllerObject, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete, exception);
-}
-
-JSClassRef GCController::getJSClass()
-{
- static JSClassRef gcControllerClass = 0;
- if (!gcControllerClass) {
- JSStaticFunction* staticFunctions = GCController::staticFunctions();
- JSClassDefinition classDefinition = {
- 0, kJSClassAttributeNone, "GCController", 0, 0, staticFunctions,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
- };
+ JSClassRef classRef = getJSClass();
+ JSValueRef gcControllerObject = JSObjectMake(context, classRef, this);
+ JSClassRelease(classRef);
- gcControllerClass = JSClassCreate(&classDefinition);
- }
-
- return gcControllerClass;
+ JSObjectSetProperty(context, windowObject, gcControllerStr.get(), gcControllerObject, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete, exception);
}
-JSStaticFunction* GCController::staticFunctions()
+JSClassRef GCController::getJSClass()
{
static JSStaticFunction staticFunctions[] = {
{ "collect", collectCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
@@ -104,5 +91,10 @@ JSStaticFunction* GCController::staticFunctions()
{ 0, 0, 0 }
};
- return staticFunctions;
+ static JSClassDefinition classDefinition = {
+ 0, kJSClassAttributeNone, "GCController", 0, 0, staticFunctions,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ };
+
+ return JSClassCreate(&classDefinition);
}
diff --git a/WebKitTools/DumpRenderTree/GCController.h b/WebKitTools/DumpRenderTree/GCController.h
index 4284275..afc1de0 100644
--- a/WebKitTools/DumpRenderTree/GCController.h
+++ b/WebKitTools/DumpRenderTree/GCController.h
@@ -45,7 +45,6 @@ public:
private:
static JSClassRef getJSClass();
- static JSStaticFunction* staticFunctions();
};
#endif // GCController_h
diff --git a/WebKitTools/DumpRenderTree/LayoutTestController.cpp b/WebKitTools/DumpRenderTree/LayoutTestController.cpp
index daf888f..572d610 100644
--- a/WebKitTools/DumpRenderTree/LayoutTestController.cpp
+++ b/WebKitTools/DumpRenderTree/LayoutTestController.cpp
@@ -838,6 +838,18 @@ static JSValueRef setXSSAuditorEnabledCallback(JSContextRef context, JSObjectRef
return JSValueMakeUndefined(context);
}
+static JSValueRef setAllowUniversalAccessFromFileURLsCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ // Has mac & windows implementation
+ if (argumentCount < 1)
+ return JSValueMakeUndefined(context);
+
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ controller->setAllowUniversalAccessFromFileURLs(JSValueToBoolean(context, arguments[0]));
+
+ return JSValueMakeUndefined(context);
+}
+
static JSValueRef setTabKeyCyclesThroughElementsCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
{
// Has mac & windows implementation
@@ -850,6 +862,16 @@ static JSValueRef setTabKeyCyclesThroughElementsCallback(JSContextRef context, J
return JSValueMakeUndefined(context);
}
+static JSValueRef setTimelineProfilingEnabledCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ if (argumentCount < 1)
+ return JSValueMakeUndefined(context);
+
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ controller->setTimelineProfilingEnabled(JSValueToBoolean(context, arguments[0]));
+ return JSValueMakeUndefined(context);
+}
+
static JSValueRef setUseDashboardCompatibilityModeCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
{
// Has mac implementation
@@ -979,6 +1001,7 @@ static JSValueRef showWebInspectorCallback(JSContextRef context, JSObjectRef fun
static JSValueRef closeWebInspectorCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
{
LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ controller->setTimelineProfilingEnabled(false);
controller->closeWebInspector();
return JSValueMakeUndefined(context);
}
@@ -1050,6 +1073,22 @@ static JSValueRef pauseTransitionAtTimeOnElementWithIdCallback(JSContextRef cont
return JSValueMakeBoolean(context, controller->pauseTransitionAtTimeOnElementWithId(propertyName.get(), time, elementId.get()));
}
+static JSValueRef sampleSVGAnimationForElementAtTimeCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ if (argumentCount != 3)
+ return JSValueMakeUndefined(context);
+
+ JSRetainPtr<JSStringRef> animationId(Adopt, JSValueToStringCopy(context, arguments[0], exception));
+ ASSERT(!*exception);
+ double time = JSValueToNumber(context, arguments[1], exception);
+ ASSERT(!*exception);
+ JSRetainPtr<JSStringRef> elementId(Adopt, JSValueToStringCopy(context, arguments[2], exception));
+ ASSERT(!*exception);
+
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ return JSValueMakeBoolean(context, controller->sampleSVGAnimationForElementAtTime(animationId.get(), time, elementId.get()));
+}
+
static JSValueRef numberOfActiveAnimationsCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
{
if (argumentCount != 0)
@@ -1150,26 +1189,24 @@ void LayoutTestController::makeWindowObject(JSContextRef context, JSObjectRef wi
{
JSRetainPtr<JSStringRef> layoutTestContollerStr(Adopt, JSStringCreateWithUTF8CString("layoutTestController"));
ref();
- JSValueRef layoutTestContollerObject = JSObjectMake(context, getJSClass(), this);
+
+ JSClassRef classRef = getJSClass();
+ JSValueRef layoutTestContollerObject = JSObjectMake(context, classRef, this);
+ JSClassRelease(classRef);
+
JSObjectSetProperty(context, windowObject, layoutTestContollerStr.get(), layoutTestContollerObject, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete, exception);
}
JSClassRef LayoutTestController::getJSClass()
{
- static JSClassRef layoutTestControllerClass;
-
- if (!layoutTestControllerClass) {
- JSStaticValue* staticValues = LayoutTestController::staticValues();
- JSStaticFunction* staticFunctions = LayoutTestController::staticFunctions();
- JSClassDefinition classDefinition = {
- 0, kJSClassAttributeNone, "LayoutTestController", 0, staticValues, staticFunctions,
- 0, layoutTestControllerObjectFinalize, 0, 0, 0, 0, 0, 0, 0, 0, 0
- };
-
- layoutTestControllerClass = JSClassCreate(&classDefinition);
- }
+ static JSStaticValue* staticValues = LayoutTestController::staticValues();
+ static JSStaticFunction* staticFunctions = LayoutTestController::staticFunctions();
+ static JSClassDefinition classDefinition = {
+ 0, kJSClassAttributeNone, "LayoutTestController", 0, staticValues, staticFunctions,
+ 0, layoutTestControllerObjectFinalize, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ };
- return layoutTestControllerClass;
+ return JSClassCreate(&classDefinition);
}
JSStaticValue* LayoutTestController::staticValues()
@@ -1227,6 +1264,7 @@ JSStaticFunction* LayoutTestController::staticFunctions()
{ "pathToLocalResource", pathToLocalResourceCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "pauseAnimationAtTimeOnElementWithId", pauseAnimationAtTimeOnElementWithIdCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "pauseTransitionAtTimeOnElementWithId", pauseTransitionAtTimeOnElementWithIdCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "sampleSVGAnimationForElementAtTime", sampleSVGAnimationForElementAtTimeCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "printToPDF", dumpAsPDFCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "queueBackNavigation", queueBackNavigationCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "queueForwardNavigation", queueForwardNavigationCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
@@ -1237,6 +1275,7 @@ JSStaticFunction* LayoutTestController::staticFunctions()
{ "removeAllVisitedLinks", removeAllVisitedLinksCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "repaintSweepHorizontally", repaintSweepHorizontallyCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "setAcceptsEditing", setAcceptsEditingCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "setAllowUniversalAccessFromFileURLs", setAllowUniversalAccessFromFileURLsCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "setAlwaysAcceptCookies", setAlwaysAcceptCookiesCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "setAppCacheMaximumSize", setAppCacheMaximumSizeCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "setAuthenticationPassword", setAuthenticationPasswordCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
@@ -1264,6 +1303,7 @@ JSStaticFunction* LayoutTestController::staticFunctions()
{ "setSmartInsertDeleteEnabled", setSmartInsertDeleteEnabledCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "setStopProvisionalFrameLoads", setStopProvisionalFrameLoadsCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "setTabKeyCyclesThroughElements", setTabKeyCyclesThroughElementsCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "setTimelineProfilingEnabled", setTimelineProfilingEnabledCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "setUseDashboardCompatibilityMode", setUseDashboardCompatibilityModeCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "setUserStyleSheetEnabled", setUserStyleSheetEnabledCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "setUserStyleSheetLocation", setUserStyleSheetLocationCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
diff --git a/WebKitTools/DumpRenderTree/LayoutTestController.h b/WebKitTools/DumpRenderTree/LayoutTestController.h
index 79ffb99..7e18dce 100644
--- a/WebKitTools/DumpRenderTree/LayoutTestController.h
+++ b/WebKitTools/DumpRenderTree/LayoutTestController.h
@@ -67,6 +67,7 @@ public:
void removeAllVisitedLinks();
void setAcceptsEditing(bool acceptsEditing);
void setAppCacheMaximumSize(unsigned long long quota);
+ void setAllowUniversalAccessFromFileURLs(bool);
void setAuthorAndUserStylesEnabled(bool);
void setCacheModel(int);
void setCustomPolicyDelegate(bool setDelegate, bool permissive);
@@ -201,6 +202,7 @@ public:
bool pauseAnimationAtTimeOnElementWithId(JSStringRef animationName, double time, JSStringRef elementId);
bool pauseTransitionAtTimeOnElementWithId(JSStringRef propertyName, double time, JSStringRef elementId);
+ bool sampleSVGAnimationForElementAtTime(JSStringRef animationId, double time, JSStringRef elementId);
unsigned numberOfActiveAnimations() const;
void whiteListAccessFromOrigin(JSStringRef sourceOrigin, JSStringRef destinationProtocol, JSStringRef destinationHost, bool allowDestinationSubdomains);
@@ -214,6 +216,7 @@ public:
void showWebInspector();
void closeWebInspector();
+ void setTimelineProfilingEnabled(bool enabled);
void evaluateInWebInspector(long callId, JSStringRef script);
void evaluateScriptInIsolatedWorld(unsigned worldId, JSObjectRef globalObject, JSStringRef script);
diff --git a/WebKitTools/DumpRenderTree/TestNetscapePlugIn.subproj/PluginObject.cpp b/WebKitTools/DumpRenderTree/TestNetscapePlugIn.subproj/PluginObject.cpp
index 14280ba..fa8aed1 100644
--- a/WebKitTools/DumpRenderTree/TestNetscapePlugIn.subproj/PluginObject.cpp
+++ b/WebKitTools/DumpRenderTree/TestNetscapePlugIn.subproj/PluginObject.cpp
@@ -34,25 +34,12 @@
#include <string.h>
#include <stdlib.h>
-void pluginLog(NPP instance, const char* format, ...)
+// Helper function which takes in the plugin window object for logging to the console object.
+static void pluginLogWithWindowObject(NPObject* windowObject, NPP instance, const char* message)
{
- va_list args;
- va_start(args, format);
- char message[2048] = "PLUGIN: ";
- vsprintf(message + strlen(message), format, args);
- va_end(args);
-
- NPObject* windowObject = 0;
- NPError error = browser->getvalue(instance, NPNVWindowNPObject, &windowObject);
- if (error != NPERR_NO_ERROR) {
- fprintf(stderr, "Failed to retrieve window object while logging: %s\n", message);
- return;
- }
-
NPVariant consoleVariant;
if (!browser->getproperty(instance, windowObject, browser->getstringidentifier("console"), &consoleVariant)) {
fprintf(stderr, "Failed to retrieve console object while logging: %s\n", message);
- browser->releaseobject(windowObject);
return;
}
@@ -65,12 +52,43 @@ void pluginLog(NPP instance, const char* format, ...)
if (!browser->invoke(instance, consoleObject, browser->getstringidentifier("log"), &messageVariant, 1, &result)) {
fprintf(stderr, "Failed to invoke console.log while logging: %s\n", message);
browser->releaseobject(consoleObject);
- browser->releaseobject(windowObject);
return;
}
browser->releasevariantvalue(&result);
browser->releaseobject(consoleObject);
+}
+
+// Helper function which takes in the plugin window object for logging to the console object. This function supports variable
+// arguments.
+static void pluginLogWithWindowObjectVariableArgs(NPObject* windowObject, NPP instance, const char* format, ...)
+{
+ va_list args;
+ va_start(args, format);
+ char message[2048] = "PLUGIN: ";
+ vsprintf(message + strlen(message), format, args);
+ va_end(args);
+
+ pluginLogWithWindowObject(windowObject, instance, message);
+}
+
+// Helper function to log to the console object.
+void pluginLog(NPP instance, const char* format, ...)
+{
+ va_list args;
+ va_start(args, format);
+ char message[2048] = "PLUGIN: ";
+ vsprintf(message + strlen(message), format, args);
+ va_end(args);
+
+ NPObject* windowObject = 0;
+ NPError error = browser->getvalue(instance, NPNVWindowNPObject, &windowObject);
+ if (error != NPERR_NO_ERROR) {
+ fprintf(stderr, "Failed to retrieve window object while logging: %s\n", message);
+ return;
+ }
+
+ pluginLogWithWindowObject(windowObject, instance, message);
browser->releaseobject(windowObject);
}
@@ -152,6 +170,8 @@ enum {
ID_TEST_THROW_EXCEPTION_METHOD,
ID_TEST_FAIL_METHOD,
ID_DESTROY_NULL_STREAM,
+ ID_TEST_RELOAD_PLUGINS_NO_PAGES,
+ ID_TEST_RELOAD_PLUGINS_AND_PAGES,
NUM_METHOD_IDENTIFIERS
};
@@ -177,7 +197,9 @@ static const NPUTF8 *pluginMethodIdentifierNames[NUM_METHOD_IDENTIFIERS] = {
"testConstruct",
"testThrowException",
"testFail",
- "destroyNullStream"
+ "destroyNullStream",
+ "reloadPluginsNoPages",
+ "reloadPluginsAndPages"
};
static NPUTF8* createCStringFromNPVariant(const NPVariant* variant)
@@ -643,6 +665,76 @@ static bool testConstruct(PluginObject* obj, const NPVariant* args, uint32_t arg
return browser->construct(obj->npp, NPVARIANT_TO_OBJECT(args[0]), args + 1, argCount - 1, result);
}
+// Helper function to notify the layout test controller that the test completed.
+void notifyTestCompletion(NPP npp, NPObject* object)
+{
+ NPVariant result;
+ NPString script;
+ script.UTF8Characters = "javascript:window.layoutTestController.notifyDone();";
+ script.UTF8Length = strlen("javascript:window.layoutTestController.notifyDone();");
+ browser->evaluate(npp, object, &script, &result);
+ browser->releasevariantvalue(&result);
+}
+
+bool testDocumentOpen(NPP npp)
+{
+ NPIdentifier documentId = browser->getstringidentifier("document");
+ NPIdentifier openId = browser->getstringidentifier("open");
+
+ NPObject *windowObject = NULL;
+ browser->getvalue(npp, NPNVWindowNPObject, &windowObject);
+ if (!windowObject)
+ return false;
+
+ NPVariant docVariant;
+ browser->getproperty(npp, windowObject, documentId, &docVariant);
+ if (docVariant.type != NPVariantType_Object)
+ return false;
+
+ NPObject *documentObject = NPVARIANT_TO_OBJECT(docVariant);
+
+ NPVariant openArgs[2];
+ STRINGZ_TO_NPVARIANT("text/html", openArgs[0]);
+ STRINGZ_TO_NPVARIANT("_blank", openArgs[1]);
+
+ NPVariant result;
+ browser->invoke(npp, documentObject, openId, openArgs, 2, &result);
+ browser->releaseobject(documentObject);
+
+ if (result.type == NPVariantType_Object) {
+ pluginLogWithWindowObjectVariableArgs(windowObject, npp, "DOCUMENT OPEN SUCCESS");
+ notifyTestCompletion(npp, result.value.objectValue);
+ browser->releaseobject(result.value.objectValue);
+ return true;
+ }
+
+ return false;
+}
+
+bool testWindowOpen(NPP npp)
+{
+ NPIdentifier openId = browser->getstringidentifier("open");
+
+ NPObject *windowObject = NULL;
+ browser->getvalue(npp, NPNVWindowNPObject, &windowObject);
+ if (!windowObject)
+ return false;
+
+ NPVariant openArgs[2];
+ STRINGZ_TO_NPVARIANT("about:blank", openArgs[0]);
+ STRINGZ_TO_NPVARIANT("_blank", openArgs[1]);
+
+ NPVariant result;
+ browser->invoke(npp, windowObject, openId, openArgs, 2, &result);
+ if (result.type == NPVariantType_Object) {
+ pluginLogWithWindowObjectVariableArgs(windowObject, npp, "WINDOW OPEN SUCCESS");
+ notifyTestCompletion(npp, result.value.objectValue);
+ browser->releaseobject(result.value.objectValue);
+ return true;
+ }
+ return false;
+}
+
static bool pluginInvoke(NPObject* header, NPIdentifier name, const NPVariant* args, uint32_t argCount, NPVariant* result)
{
PluginObject* plugin = reinterpret_cast<PluginObject*>(header);
@@ -691,6 +783,13 @@ static bool pluginInvoke(NPObject* header, NPIdentifier name, const NPVariant* a
browser->invoke(plugin->npp, windowScriptObject, name, args, argCount, result);
} else if (name == pluginMethodIdentifiers[ID_DESTROY_NULL_STREAM])
return destroyNullStream(plugin, args, argCount, result);
+ else if (name == pluginMethodIdentifiers[ID_TEST_RELOAD_PLUGINS_NO_PAGES]) {
+ browser->reloadplugins(false);
+ return true;
+ } else if (name == pluginMethodIdentifiers[ID_TEST_RELOAD_PLUGINS_AND_PAGES]) {
+ browser->reloadplugins(true);
+ return true;
+ }
return false;
}
@@ -721,6 +820,7 @@ static NPObject *pluginAllocate(NPP npp, NPClass *theClass)
newInstance->eventLogging = FALSE;
newInstance->onStreamLoad = 0;
newInstance->onStreamDestroy = 0;
+ newInstance->onDestroy = 0;
newInstance->onURLNotify = 0;
newInstance->logDestroy = FALSE;
newInstance->logSetWindow = FALSE;
@@ -732,6 +832,9 @@ static NPObject *pluginAllocate(NPP npp, NPClass *theClass)
newInstance->lastUrl = NULL;
newInstance->lastHeaders = NULL;
+ newInstance->testDocumentOpenInDestroyStream = FALSE;
+ newInstance->testWindowOpen = FALSE;
+
return (NPObject*)newInstance;
}
diff --git a/WebKitTools/DumpRenderTree/TestNetscapePlugIn.subproj/PluginObject.h b/WebKitTools/DumpRenderTree/TestNetscapePlugIn.subproj/PluginObject.h
index 7437d04..157a1d2 100644
--- a/WebKitTools/DumpRenderTree/TestNetscapePlugIn.subproj/PluginObject.h
+++ b/WebKitTools/DumpRenderTree/TestNetscapePlugIn.subproj/PluginObject.h
@@ -38,8 +38,11 @@ typedef struct {
NPBool cachedPrivateBrowsingMode;
NPObject* testObject;
NPStream* stream;
+ NPBool testDocumentOpenInDestroyStream;
+ NPBool testWindowOpen;
char* onStreamLoad;
char* onStreamDestroy;
+ char* onDestroy;
char* onURLNotify;
char* firstUrl;
char* firstHeaders;
@@ -55,3 +58,5 @@ extern void handleCallback(PluginObject* object, const char *url, NPReason reaso
extern void notifyStream(PluginObject* object, const char *url, const char *headers);
extern void testNPRuntime(NPP npp);
extern void pluginLog(NPP instance, const char* format, ...);
+extern bool testDocumentOpen(NPP npp);
+extern bool testWindowOpen(NPP npp);
diff --git a/WebKitTools/DumpRenderTree/TestNetscapePlugIn.subproj/main.cpp b/WebKitTools/DumpRenderTree/TestNetscapePlugIn.subproj/main.cpp
index 125d2e8..5883ffb 100644
--- a/WebKitTools/DumpRenderTree/TestNetscapePlugIn.subproj/main.cpp
+++ b/WebKitTools/DumpRenderTree/TestNetscapePlugIn.subproj/main.cpp
@@ -105,6 +105,12 @@ NPError NPP_New(NPMIMEType pluginType, NPP instance, uint16 mode, int16 argc, ch
pluginLog(instance, "src: %s", argv[i]);
} else if (strcasecmp(argn[i], "cleardocumentduringnew") == 0)
executeScript(obj, "document.body.innerHTML = ''");
+ else if (!strcasecmp(argn[i], "ondestroy"))
+ obj->onDestroy = strdup(argv[i]);
+ else if (strcasecmp(argn[i], "testdocumentopenindestroystream") == 0)
+ obj->testDocumentOpenInDestroyStream = TRUE;
+ else if (strcasecmp(argn[i], "testwindowopen") == 0)
+ obj->testWindowOpen = TRUE;
}
#ifndef NP_NO_CARBON
@@ -140,6 +146,11 @@ NPError NPP_Destroy(NPP instance, NPSavedData **save)
{
PluginObject* obj = static_cast<PluginObject*>(instance->pdata);
if (obj) {
+ if (obj->onDestroy) {
+ executeScript(obj, obj->onDestroy);
+ free(obj->onDestroy);
+ }
+
if (obj->onStreamLoad)
free(obj->onStreamLoad);
@@ -166,6 +177,11 @@ NPError NPP_SetWindow(NPP instance, NPWindow *window)
pluginLog(instance, "NPP_SetWindow: %d %d", (int)window->width, (int)window->height);
obj->logSetWindow = false;
}
+
+ if (obj->testWindowOpen) {
+ testWindowOpen(instance);
+ obj->testWindowOpen = FALSE;
+ }
}
return NPERR_NO_ERROR;
@@ -210,6 +226,11 @@ NPError NPP_DestroyStream(NPP instance, NPStream *stream, NPReason reason)
if (obj->onStreamDestroy)
executeScript(obj, obj->onStreamDestroy);
+ if (obj->testDocumentOpenInDestroyStream) {
+ testDocumentOpen(instance);
+ obj->testDocumentOpenInDestroyStream = FALSE;
+ }
+
return NPERR_NO_ERROR;
}
diff --git a/WebKitTools/DumpRenderTree/gtk/AccessibilityControllerGtk.cpp b/WebKitTools/DumpRenderTree/gtk/AccessibilityControllerGtk.cpp
index 593f2eb..df06cea 100644
--- a/WebKitTools/DumpRenderTree/gtk/AccessibilityControllerGtk.cpp
+++ b/WebKitTools/DumpRenderTree/gtk/AccessibilityControllerGtk.cpp
@@ -58,7 +58,11 @@ AccessibilityUIElement AccessibilityController::focusedElement()
AccessibilityUIElement AccessibilityController::rootElement()
{
WebKitWebView* view = webkit_web_frame_get_web_view(mainFrame);
- AtkObject* axObject = gtk_widget_get_accessible(GTK_WIDGET(view));
+
+ // The presumed, desired rootElement is the parent of the web view.
+ GtkWidget* webViewParent = gtk_widget_get_parent(GTK_WIDGET(view));
+ AtkObject* axObject = gtk_widget_get_accessible(webViewParent);
+
return AccessibilityUIElement(axObject);
}
diff --git a/WebKitTools/DumpRenderTree/gtk/AccessibilityUIElementGtk.cpp b/WebKitTools/DumpRenderTree/gtk/AccessibilityUIElementGtk.cpp
index 9aa31a8..13d313d 100644
--- a/WebKitTools/DumpRenderTree/gtk/AccessibilityUIElementGtk.cpp
+++ b/WebKitTools/DumpRenderTree/gtk/AccessibilityUIElementGtk.cpp
@@ -161,6 +161,11 @@ JSStringRef AccessibilityUIElement::subrole()
return 0;
}
+JSStringRef AccessibilityUIElement::roleDescription()
+{
+ return 0;
+}
+
JSStringRef AccessibilityUIElement::title()
{
const gchar* name = atk_object_get_name(ATK_OBJECT(m_element));
@@ -181,6 +186,12 @@ JSStringRef AccessibilityUIElement::description()
return JSStringCreateWithUTF8CString(description);
}
+JSStringRef AccessibilityUIElement::stringValue()
+{
+ // FIXME: implement
+ return JSStringCreateWithCharacters(0, 0);
+}
+
JSStringRef AccessibilityUIElement::language()
{
// FIXME: implement
@@ -233,6 +244,10 @@ double AccessibilityUIElement::clickPointY()
return 0.f;
}
+JSStringRef AccessibilityUIElement::orientation() const
+{
+ return 0;
+}
double AccessibilityUIElement::intValue()
{
@@ -316,6 +331,34 @@ bool AccessibilityUIElement::isRequired() const
return false;
}
+bool AccessibilityUIElement::isSelected() const
+{
+ // FIXME: implement
+ return false;
+}
+
+int AccessibilityUIElement::hierarchicalLevel() const
+{
+ // FIXME: implement
+ return 0;
+}
+
+bool AccessibilityUIElement::ariaIsGrabbed() const
+{
+ return false;
+}
+
+JSStringRef AccessibilityUIElement::ariaDropEffects() const
+{
+ return 0;
+}
+
+bool AccessibilityUIElement::isExpanded() const
+{
+ // FIXME: implement
+ return false;
+}
+
JSStringRef AccessibilityUIElement::attributesOfColumnHeaders()
{
// FIXME: implement
@@ -417,6 +460,11 @@ bool AccessibilityUIElement::isAttributeSettable(JSStringRef attribute)
return false;
}
+bool AccessibilityUIElement::isAttributeSupported(JSStringRef attribute)
+{
+ return false;
+}
+
void AccessibilityUIElement::increment()
{
// FIXME: implement
@@ -426,3 +474,57 @@ void AccessibilityUIElement::decrement()
{
// FIXME: implement
}
+
+void AccessibilityUIElement::showMenu()
+{
+ // FIXME: implement
+}
+
+AccessibilityUIElement AccessibilityUIElement::disclosedRowAtIndex(unsigned index)
+{
+ return 0;
+}
+
+AccessibilityUIElement AccessibilityUIElement::ariaOwnsElementAtIndex(unsigned index)
+{
+ return 0;
+}
+
+AccessibilityUIElement AccessibilityUIElement::ariaFlowToElementAtIndex(unsigned index)
+{
+ return 0;
+}
+
+AccessibilityUIElement AccessibilityUIElement::selectedRowAtIndex(unsigned index)
+{
+ return 0;
+}
+
+AccessibilityUIElement AccessibilityUIElement::disclosedByRow()
+{
+ return 0;
+}
+
+JSStringRef AccessibilityUIElement::accessibilityValue() const
+{
+ // FIXME: implement
+ return JSStringCreateWithCharacters(0, 0);
+}
+
+JSStringRef AccessibilityUIElement::documentEncoding()
+{
+ AtkRole role = atk_object_get_role(ATK_OBJECT(m_element));
+ if (role != ATK_ROLE_DOCUMENT_FRAME)
+ return JSStringCreateWithCharacters(0, 0);
+
+ return JSStringCreateWithUTF8CString(atk_document_get_attribute_value(ATK_DOCUMENT(m_element), "Encoding"));
+}
+
+JSStringRef AccessibilityUIElement::documentURI()
+{
+ AtkRole role = atk_object_get_role(ATK_OBJECT(m_element));
+ if (role != ATK_ROLE_DOCUMENT_FRAME)
+ return JSStringCreateWithCharacters(0, 0);
+
+ return JSStringCreateWithUTF8CString(atk_document_get_attribute_value(ATK_DOCUMENT(m_element), "URI"));
+}
diff --git a/WebKitTools/DumpRenderTree/gtk/DumpRenderTree.cpp b/WebKitTools/DumpRenderTree/gtk/DumpRenderTree.cpp
index 4ed6e36..fd1e3c6 100644
--- a/WebKitTools/DumpRenderTree/gtk/DumpRenderTree.cpp
+++ b/WebKitTools/DumpRenderTree/gtk/DumpRenderTree.cpp
@@ -82,6 +82,7 @@ static GCController* gcController = 0;
static WebKitWebView* webView;
static GtkWidget* window;
static GtkWidget* container;
+static GtkWidget* webInspectorWindow;
WebKitWebFrame* mainFrame = 0;
WebKitWebFrame* topLoadingFrame = 0;
guint waitToDumpWatchdog = 0;
@@ -113,6 +114,11 @@ static bool shouldLogFrameLoadDelegates(const char* pathOrURL)
return strstr(pathOrURL, "loading/");
}
+static bool shouldOpenWebInspector(const char* pathOrURL)
+{
+ return strstr(pathOrURL, "inspector/");
+}
+
void dumpFrameScrollPosition(WebKitWebFrame* frame)
{
@@ -120,7 +126,7 @@ void dumpFrameScrollPosition(WebKitWebFrame* frame)
void displayWebView()
{
-
+ gtk_widget_queue_draw(GTK_WIDGET(webView));
}
static void appendString(gchar*& target, gchar* string)
@@ -319,7 +325,6 @@ static void resetDefaultsToConsistentValues()
"enable-offline-web-application-cache", TRUE,
"enable-universal-access-from-file-uris", TRUE,
"enable-scripts", TRUE,
- "enable-web-sockets", TRUE,
"enable-dom-paste", TRUE,
"default-font-family", "Times",
"monospace-font-family", "Courier",
@@ -400,12 +405,8 @@ void dump()
// FIXME: call displayWebView here when we support --paint
- puts("#EOF"); // terminate the (possibly empty) pixels block
-
- fflush(stdout);
- fflush(stderr);
-
done = true;
+ gtk_main_quit();
}
static void setDefaultsToConsistentStateValuesForTesting()
@@ -427,6 +428,14 @@ static void setDefaultsToConsistentStateValuesForTesting()
g_free(databaseDirectory);
}
+static void sendPixelResultsEOF()
+{
+ puts("#EOF");
+
+ fflush(stdout);
+ fflush(stderr);
+}
+
static void runTest(const string& testPathOrURL)
{
ASSERT(!testPathOrURL.empty());
@@ -455,6 +464,9 @@ static void runTest(const string& testPathOrURL)
if (shouldLogFrameLoadDelegates(pathOrURL.c_str()))
gLayoutTestController->setDumpFrameLoadCallbacks(true);
+ if (shouldOpenWebInspector(pathOrURL.c_str()))
+ gLayoutTestController->showWebInspector();
+
WorkQueue::shared()->clear();
WorkQueue::shared()->setFrozen(false);
@@ -484,9 +496,10 @@ static void runTest(const string& testPathOrURL)
g_free(url);
url = NULL;
- while (!done)
- g_main_context_iteration(NULL, TRUE);
+ gtk_main();
+ if (shouldOpenWebInspector(pathOrURL.c_str()))
+ gLayoutTestController->closeWebInspector();
// Also check if we still have opened webViews and free them.
if (gLayoutTestController->closeRemainingWindowsWhenComplete() || webViewList) {
@@ -503,6 +516,9 @@ static void runTest(const string& testPathOrURL)
gLayoutTestController->deref();
gLayoutTestController = 0;
+
+ // terminate the (possibly empty) pixels block after all the state reset
+ sendPixelResultsEOF();
}
void webViewLoadStarted(WebKitWebView* view, WebKitWebFrame* frame, void*)
@@ -565,7 +581,7 @@ static void webViewLoadFinished(WebKitWebView* view, WebKitWebFrame* frame, void
if (WorkQueue::shared()->count())
g_timeout_add(0, processWork, 0);
- else
+ else
dump();
}
@@ -708,9 +724,29 @@ static void databaseQuotaExceeded(WebKitWebView* view, WebKitWebFrame* frame, We
static WebKitWebView* webViewCreate(WebKitWebView*, WebKitWebFrame*);
+static gboolean webInspectorShowWindow(WebKitWebInspector*, gpointer data)
+{
+ gtk_window_set_default_size(GTK_WINDOW(webInspectorWindow), 800, 600);
+ gtk_widget_show_all(webInspectorWindow);
+ return TRUE;
+}
+
+static gboolean webInspectorCloseWindow(WebKitWebInspector*, gpointer data)
+{
+ gtk_widget_destroy(webInspectorWindow);
+ webInspectorWindow = 0;
+ return TRUE;
+}
+
static WebKitWebView* webInspectorInspectWebView(WebKitWebInspector*, gpointer data)
{
- return WEBKIT_WEB_VIEW(webkit_web_view_new());
+ webInspectorWindow = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+
+ GtkWidget* webView = webkit_web_view_new();
+ gtk_container_add(GTK_CONTAINER(webInspectorWindow),
+ webView);
+
+ return WEBKIT_WEB_VIEW(webView);
}
static WebKitWebView* createWebView()
@@ -738,7 +774,11 @@ static WebKitWebView* createWebView()
NULL);
WebKitWebInspector* inspector = webkit_web_view_get_inspector(view);
- g_signal_connect(inspector, "inspect-web-view", G_CALLBACK(webInspectorInspectWebView), 0);
+ g_object_connect(G_OBJECT(inspector),
+ "signal::inspect-web-view", webInspectorInspectWebView, 0,
+ "signal::show-window", webInspectorShowWindow, 0,
+ "signal::close-window", webInspectorCloseWindow, 0,
+ NULL);
return view;
}
@@ -793,6 +833,7 @@ int main(int argc, char* argv[])
gtk_container_add(GTK_CONTAINER(container), GTK_WIDGET(webView));
gtk_widget_realize(GTK_WIDGET(webView));
gtk_widget_show_all(container);
+ gtk_widget_grab_focus(GTK_WIDGET(webView));
mainFrame = webkit_web_view_get_main_frame(webView);
setDefaultsToConsistentStateValuesForTesting();
diff --git a/WebKitTools/DumpRenderTree/gtk/EventSender.cpp b/WebKitTools/DumpRenderTree/gtk/EventSender.cpp
index f42928c..6268b5b 100644
--- a/WebKitTools/DumpRenderTree/gtk/EventSender.cpp
+++ b/WebKitTools/DumpRenderTree/gtk/EventSender.cpp
@@ -200,6 +200,23 @@ static JSValueRef mouseDownCallback(JSContextRef context, JSObjectRef function,
return JSValueMakeUndefined(context);
}
+static guint getStateFlags()
+{
+ guint state = 0;
+
+ if (down) {
+ if (currentEventButton == 1)
+ state = GDK_BUTTON1_MASK;
+ else if (currentEventButton == 2)
+ state = GDK_BUTTON2_MASK;
+ else if (currentEventButton == 3)
+ state = GDK_BUTTON3_MASK;
+ } else
+ state = 0;
+
+ return state;
+}
+
static JSValueRef mouseUpCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
{
@@ -207,8 +224,6 @@ static JSValueRef mouseUpCallback(JSContextRef context, JSObjectRef function, JS
if (!view)
return JSValueMakeUndefined(context);
- down = false;
-
GdkEvent event;
memset(&event, 0, sizeof(event));
event.type = GDK_BUTTON_RELEASE;
@@ -226,6 +241,9 @@ static JSValueRef mouseUpCallback(JSContextRef context, JSObjectRef function, JS
event.button.window = GTK_WIDGET(view)->window;
event.button.time = GDK_CURRENT_TIME;
event.button.device = gdk_device_get_core_pointer();
+ event.button.state = getStateFlags();
+
+ down = false;
int x_root, y_root;
#if GTK_CHECK_VERSION(2,17,3)
@@ -286,16 +304,8 @@ static JSValueRef mouseMoveToCallback(JSContextRef context, JSObjectRef function
event.motion.x_root = x_root;
event.motion.y_root = y_root;
-
- if (down) {
- if (currentEventButton == 1)
- event.motion.state = GDK_BUTTON1_MASK;
- else if (currentEventButton == 2)
- event.motion.state = GDK_BUTTON2_MASK;
- else if (currentEventButton == 3)
- event.motion.state = GDK_BUTTON3_MASK;
- } else
- event.motion.state = 0;
+
+ event.motion.state = getStateFlags();
if (dragMode && down && !replayingSavedEvents) {
msgQueue[endOfQueue].event = event;
diff --git a/WebKitTools/DumpRenderTree/gtk/LayoutTestControllerGtk.cpp b/WebKitTools/DumpRenderTree/gtk/LayoutTestControllerGtk.cpp
index 631fc31..6e94c1c 100644
--- a/WebKitTools/DumpRenderTree/gtk/LayoutTestControllerGtk.cpp
+++ b/WebKitTools/DumpRenderTree/gtk/LayoutTestControllerGtk.cpp
@@ -49,6 +49,7 @@
extern "C" {
bool webkit_web_frame_pause_animation(WebKitWebFrame* frame, const gchar* name, double time, const gchar* element);
bool webkit_web_frame_pause_transition(WebKitWebFrame* frame, const gchar* name, double time, const gchar* element);
+bool webkit_web_frame_pause_svg_animation(WebKitWebFrame* frame, const gchar* name, double time, const gchar* element);
unsigned int webkit_web_frame_number_of_active_animations(WebKitWebFrame* frame);
void webkit_application_cache_set_maximum_size(unsigned long long size);
unsigned int webkit_worker_thread_count(void);
@@ -224,7 +225,18 @@ void LayoutTestController::setMainFrameIsFirstResponder(bool flag)
void LayoutTestController::setTabKeyCyclesThroughElements(bool cycles)
{
- // FIXME: implement
+ WebKitWebView* webView = webkit_web_frame_get_web_view(mainFrame);
+ WebKitWebSettings* settings = webkit_web_view_get_settings(webView);
+ g_object_set(G_OBJECT(settings), "tab-key-cycles-through-elements", cycles, NULL);
+}
+
+void LayoutTestController::setTimelineProfilingEnabled(bool flag)
+{
+ WebKitWebView* view = webkit_web_frame_get_web_view(mainFrame);
+ ASSERT(view);
+
+ WebKitWebInspector* inspector = webkit_web_view_get_inspector(view);
+ g_object_set(G_OBJECT(inspector), "timeline-profiling-enabled", flag, NULL);
}
void LayoutTestController::setUseDashboardCompatibilityMode(bool flag)
@@ -305,6 +317,15 @@ void LayoutTestController::setXSSAuditorEnabled(bool flag)
g_object_set(G_OBJECT(settings), "enable-xss-auditor", flag, NULL);
}
+void LayoutTestController::setAllowUniversalAccessFromFileURLs(bool flag)
+{
+ WebKitWebView* view = webkit_web_frame_get_web_view(mainFrame);
+ ASSERT(view);
+
+ WebKitWebSettings* settings = webkit_web_view_get_settings(view);
+ g_object_set(G_OBJECT(settings), "enable-universal-access-from-file-uris", flag, NULL);
+}
+
void LayoutTestController::setAuthorAndUserStylesEnabled(bool flag)
{
// FIXME: implement
@@ -428,6 +449,16 @@ bool LayoutTestController::pauseTransitionAtTimeOnElementWithId(JSStringRef prop
return returnValue;
}
+bool LayoutTestController::sampleSVGAnimationForElementAtTime(JSStringRef animationId, double time, JSStringRef elementId)
+{
+ gchar* name = JSStringCopyUTF8CString(animationId);
+ gchar* element = JSStringCopyUTF8CString(elementId);
+ bool returnValue = webkit_web_frame_pause_svg_animation(mainFrame, name, time, element);
+ g_free(name);
+ g_free(element);
+ return returnValue;
+}
+
unsigned LayoutTestController::numberOfActiveAnimations() const
{
return webkit_web_frame_number_of_active_animations(mainFrame);
@@ -493,7 +524,7 @@ void LayoutTestController::showWebInspector()
WebKitWebInspector* inspector = webkit_web_view_get_inspector(webView);
g_object_set(webSettings, "enable-developer-extras", TRUE, NULL);
- webkit_web_inspector_inspect_coordinates(inspector, 0, 0);
+ webkit_web_inspector_show(inspector);
}
void LayoutTestController::closeWebInspector()
diff --git a/WebKitTools/DumpRenderTree/mac/AccessibilityUIElementMac.mm b/WebKitTools/DumpRenderTree/mac/AccessibilityUIElementMac.mm
index 375dbad..948f379 100644
--- a/WebKitTools/DumpRenderTree/mac/AccessibilityUIElementMac.mm
+++ b/WebKitTools/DumpRenderTree/mac/AccessibilityUIElementMac.mm
@@ -40,6 +40,18 @@
#define NSAccessibilityValueDescriptionAttribute @"AXValueDescription"
#endif
+#ifndef NSAccessibilityOwnsAttribute
+#define NSAccessibilityOwnsAttribute @"AXOwns"
+#endif
+
+#ifndef NSAccessibilityGrabbedAttribute
+#define NSAccessibilityGrabbedAttribute @"AXGrabbed"
+#endif
+
+#ifndef NSAccessibilityDropEffectsAttribute
+#define NSAccessibilityDropEffectsAttribute @"AXDropEffects"
+#endif
+
@interface NSObject (WebKitAccessibilityArrayCategory)
- (NSArray *)accessibilityArrayAttributeValues:(NSString *)attribute index:(NSUInteger)index maxCount:(NSUInteger)maxCount;
@end
@@ -232,7 +244,43 @@ AccessibilityUIElement AccessibilityUIElement::getChildAtIndex(unsigned index)
if (children.size() == 1)
return children[0];
- return nil;
+ return 0;
+}
+
+AccessibilityUIElement AccessibilityUIElement::ariaOwnsElementAtIndex(unsigned index)
+{
+ NSArray* objects = [m_element accessibilityAttributeValue:NSAccessibilityOwnsAttribute];
+ if (index < [objects count])
+ return [objects objectAtIndex:index];
+
+ return 0;
+}
+
+AccessibilityUIElement AccessibilityUIElement::ariaFlowToElementAtIndex(unsigned index)
+{
+ NSArray* objects = [m_element accessibilityAttributeValue:NSAccessibilityLinkedUIElementsAttribute];
+ if (index < [objects count])
+ return [objects objectAtIndex:index];
+
+ return 0;
+}
+
+AccessibilityUIElement AccessibilityUIElement::disclosedRowAtIndex(unsigned index)
+{
+ NSArray* rows = [m_element accessibilityAttributeValue:NSAccessibilityDisclosedRowsAttribute];
+ if (index < [rows count])
+ return [rows objectAtIndex:index];
+
+ return 0;
+}
+
+AccessibilityUIElement AccessibilityUIElement::selectedRowAtIndex(unsigned index)
+{
+ NSArray* rows = [m_element accessibilityAttributeValue:NSAccessibilitySelectedRowsAttribute];
+ if (index < [rows count])
+ return [rows objectAtIndex:index];
+
+ return 0;
}
AccessibilityUIElement AccessibilityUIElement::titleUIElement()
@@ -241,7 +289,7 @@ AccessibilityUIElement AccessibilityUIElement::titleUIElement()
if (accessibilityObject)
return AccessibilityUIElement(accessibilityObject);
- return nil;
+ return 0;
}
AccessibilityUIElement AccessibilityUIElement::parentElement()
@@ -250,7 +298,16 @@ AccessibilityUIElement AccessibilityUIElement::parentElement()
if (accessibilityObject)
return AccessibilityUIElement(accessibilityObject);
- return nil;
+ return 0;
+}
+
+AccessibilityUIElement AccessibilityUIElement::disclosedByRow()
+{
+ id accessibilityObject = [m_element accessibilityAttributeValue:NSAccessibilityDisclosedByRowAttribute];
+ if (accessibilityObject)
+ return AccessibilityUIElement(accessibilityObject);
+
+ return 0;
}
JSStringRef AccessibilityUIElement::attributesOfLinkedUIElements()
@@ -293,6 +350,11 @@ bool AccessibilityUIElement::isAttributeSettable(JSStringRef attribute)
return [m_element accessibilityIsAttributeSettable:[NSString stringWithJSStringRef:attribute]];
}
+bool AccessibilityUIElement::isAttributeSupported(JSStringRef attribute)
+{
+ return [[m_element accessibilityAttributeNames] containsObject:[NSString stringWithJSStringRef:attribute]];
+}
+
JSStringRef AccessibilityUIElement::parameterizedAttributeNames()
{
NSArray* supportedParameterizedAttributes = [m_element accessibilityParameterizedAttributeNames];
@@ -317,6 +379,12 @@ JSStringRef AccessibilityUIElement::subrole()
return concatenateAttributeAndValue(@"AXSubrole", role);
}
+JSStringRef AccessibilityUIElement::roleDescription()
+{
+ NSString* role = descriptionOfValue([m_element accessibilityAttributeValue:NSAccessibilityRoleDescriptionAttribute], m_element);
+ return concatenateAttributeAndValue(@"AXRoleDescription", role);
+}
+
JSStringRef AccessibilityUIElement::title()
{
NSString* title = descriptionOfValue([m_element accessibilityAttributeValue:NSAccessibilityTitleAttribute], m_element);
@@ -329,6 +397,18 @@ JSStringRef AccessibilityUIElement::description()
return concatenateAttributeAndValue(@"AXDescription", description);
}
+JSStringRef AccessibilityUIElement::orientation() const
+{
+ id description = descriptionOfValue([m_element accessibilityAttributeValue:NSAccessibilityOrientationAttribute], m_element);
+ return concatenateAttributeAndValue(@"AXOrientation", description);
+}
+
+JSStringRef AccessibilityUIElement::stringValue()
+{
+ id description = descriptionOfValue([m_element accessibilityAttributeValue:NSAccessibilityValueAttribute], m_element);
+ return concatenateAttributeAndValue(@"AXValue", description);
+}
+
JSStringRef AccessibilityUIElement::language()
{
id description = descriptionOfValue([m_element accessibilityAttributeValue:@"AXLanguage"], m_element);
@@ -433,6 +513,55 @@ bool AccessibilityUIElement::isRequired() const
return false;
}
+bool AccessibilityUIElement::isSelected() const
+{
+ id value = [m_element accessibilityAttributeValue:NSAccessibilitySelectedAttribute];
+ if ([value isKindOfClass:[NSNumber class]])
+ return [value boolValue];
+ return false;
+}
+
+bool AccessibilityUIElement::isExpanded() const
+{
+ id value = [m_element accessibilityAttributeValue:NSAccessibilityExpandedAttribute];
+ if ([value isKindOfClass:[NSNumber class]])
+ return [value boolValue];
+ return false;
+}
+
+int AccessibilityUIElement::hierarchicalLevel() const
+{
+ id value = [m_element accessibilityAttributeValue:NSAccessibilityDisclosureLevelAttribute];
+ if ([value isKindOfClass:[NSNumber class]])
+ return [value intValue];
+ return 0;
+}
+
+bool AccessibilityUIElement::ariaIsGrabbed() const
+{
+ id value = [m_element accessibilityAttributeValue:NSAccessibilityGrabbedAttribute];
+ if ([value isKindOfClass:[NSNumber class]])
+ return [value boolValue];
+ return false;
+}
+
+JSStringRef AccessibilityUIElement::ariaDropEffects() const
+{
+ id value = [m_element accessibilityAttributeValue:NSAccessibilityDropEffectsAttribute];
+ if (![value isKindOfClass:[NSArray class]])
+ return 0;
+
+ NSMutableString* dropEffects = [NSMutableString string];
+ NSInteger length = [value count];
+ for (NSInteger k = 0; k < length; ++k) {
+ [dropEffects appendString:[value objectAtIndex:k]];
+ if (k < length - 1)
+ [dropEffects appendString:@","];
+ }
+
+ return [dropEffects createJSStringRef];
+}
+
// parameterized attributes
int AccessibilityUIElement::lineForIndex(int index)
{
@@ -571,3 +700,24 @@ void AccessibilityUIElement::decrement()
{
[m_element accessibilityPerformAction:NSAccessibilityDecrementAction];
}
+
+void AccessibilityUIElement::showMenu()
+{
+ [m_element accessibilityPerformAction:NSAccessibilityShowMenuAction];
+}
+
+JSStringRef AccessibilityUIElement::accessibilityValue() const
+{
+ // FIXME: implement
+ return JSStringCreateWithCharacters(0, 0);
+}
+
+JSStringRef AccessibilityUIElement::documentEncoding()
+{
+ return JSStringCreateWithCharacters(0, 0);
+}
+
+JSStringRef AccessibilityUIElement::documentURI()
+{
+ return JSStringCreateWithCharacters(0, 0);
+}
diff --git a/WebKitTools/DumpRenderTree/mac/DumpRenderTree.mm b/WebKitTools/DumpRenderTree/mac/DumpRenderTree.mm
index 98f4f9c..4ffeac3 100644
--- a/WebKitTools/DumpRenderTree/mac/DumpRenderTree.mm
+++ b/WebKitTools/DumpRenderTree/mac/DumpRenderTree.mm
@@ -87,6 +87,10 @@ using namespace std;
@interface DumpRenderTreeEvent : NSEvent
@end
+@interface NSURLRequest (PrivateThingsWeShouldntReallyUse)
++(void)setAllowsAnyHTTPSCertificate:(BOOL)allow forHost:(NSString *)host;
+@end
+
static void runTest(const string& testPathOrURL);
// Deciding when it's OK to dump out the state is a bit tricky. All these must be true:
@@ -302,7 +306,7 @@ WebView *createWebViewAndOffscreenWindow()
[window orderBack:nil];
[window setAutodisplay:NO];
- [window startObservingWebView];
+ [window startListeningForAcceleratedCompositingChanges];
// For reasons that are not entirely clear, the following pair of calls makes WebView handle its
// dynamic scrollbars properly. Without it, every frame will always have scrollbars.
@@ -596,9 +600,17 @@ void dumpRenderTree(int argc, const char *argv[])
mainFrame = [webView mainFrame];
[[NSURLCache sharedURLCache] removeAllCachedResponses];
-
[WebCache empty];
-
+
+ // <http://webkit.org/b/31200> In order to prevent extra frame load delegate logging being generated if the first test to use SSL
+ // is set to log frame load delegate calls we ignore SSL certificate errors on localhost and 127.0.0.1.
+#if BUILDING_ON_TIGER
+ // Initialize internal NSURLRequest data for setAllowsAnyHTTPSCertificate:forHost: to work properly.
+ [[[[NSURLRequest alloc] init] autorelease] HTTPMethod];
+#endif
+ [NSURLRequest setAllowsAnyHTTPSCertificate:YES forHost:@"localhost"];
+ [NSURLRequest setAllowsAnyHTTPSCertificate:YES forHost:@"127.0.0.1"];
+
// <rdar://problem/5222911>
testStringByEvaluatingJavaScriptFromString();
@@ -1090,6 +1102,11 @@ static bool shouldLogHistoryDelegates(const char* pathOrURL)
return strstr(pathOrURL, "globalhistory/");
}
+static bool shouldOpenWebInspector(const char* pathOrURL)
+{
+ return strstr(pathOrURL, "inspector/");
+}
+
static void resetWebViewToConsistentStateBeforeTesting()
{
WebView *webView = [mainFrame webView];
@@ -1105,6 +1122,7 @@ static void resetWebViewToConsistentStateBeforeTesting()
[webView _clearMainFrameName];
[[webView undoManager] removeAllActions];
[WebView _removeAllUserContentFromGroup:[webView groupName]];
+ [[webView window] setAutodisplay:NO];
resetDefaultsToConsistentValues();
@@ -1166,7 +1184,10 @@ static void runTest(const string& testPathOrURL)
[[mainFrame webView] setHistoryDelegate:historyDelegate];
else
[[mainFrame webView] setHistoryDelegate:nil];
-
+
+ if (shouldOpenWebInspector(pathOrURL.c_str()))
+ gLayoutTestController->showWebInspector();
+
if ([WebHistory optionalSharedHistory])
[WebHistory setOptionalSharedHistory:nil];
lastMousePosition = NSZeroPoint;
@@ -1190,6 +1211,7 @@ static void runTest(const string& testPathOrURL)
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantPast]];
[pool release];
}
+
pool = [[NSAutoreleasePool alloc] init];
[EventSendingController clearSavedEvents];
[[mainFrame webView] setSelectedDOMRange:nil affinity:NSSelectionAffinityDownstream];
@@ -1214,11 +1236,14 @@ static void runTest(const string& testPathOrURL)
}
}
+ if (shouldOpenWebInspector(pathOrURL.c_str()))
+ gLayoutTestController->closeWebInspector();
+
resetWebViewToConsistentStateBeforeTesting();
[mainFrame loadHTMLString:@"<html></html>" baseURL:[NSURL URLWithString:@"about:blank"]];
[mainFrame stopLoading];
-
+
[pool release];
// We should only have our main window left open when we're done
diff --git a/WebKitTools/DumpRenderTree/mac/DumpRenderTreeMac.h b/WebKitTools/DumpRenderTree/mac/DumpRenderTreeMac.h
index 72d5db1..fe1ac00 100644
--- a/WebKitTools/DumpRenderTree/mac/DumpRenderTreeMac.h
+++ b/WebKitTools/DumpRenderTree/mac/DumpRenderTreeMac.h
@@ -42,6 +42,7 @@
@class NavigationController;
@class PolicyDelegate;
@class WebFrame;
+@class WebScriptWorld;
@class WebView;
typedef const struct __CFString* CFStringRef;
@@ -62,4 +63,6 @@ extern CFRunLoopTimerRef waitToDumpWatchdog;
WebView* createWebViewAndOffscreenWindow();
void setPersistentUserStyleSheetLocation(CFStringRef);
+unsigned worldIDForWorld(WebScriptWorld *);
+
#endif // DumpRenderTreeMac_h
diff --git a/WebKitTools/DumpRenderTree/mac/DumpRenderTreeWindow.h b/WebKitTools/DumpRenderTree/mac/DumpRenderTreeWindow.h
index b6bdcb8..a229d20 100644
--- a/WebKitTools/DumpRenderTree/mac/DumpRenderTreeWindow.h
+++ b/WebKitTools/DumpRenderTree/mac/DumpRenderTreeWindow.h
@@ -34,7 +34,6 @@
@interface DumpRenderTreeWindow : NSWindow
{
- BOOL observingWebView;
}
// I'm not sure why we can't just use [NSApp windows]
@@ -42,7 +41,6 @@
- (WebView *)webView;
-- (void)startObservingWebView;
-- (void)stopObservingWebView;
+- (void)startListeningForAcceleratedCompositingChanges;
@end
diff --git a/WebKitTools/DumpRenderTree/mac/DumpRenderTreeWindow.mm b/WebKitTools/DumpRenderTree/mac/DumpRenderTreeWindow.mm
index aa5b117..8845ef0 100644
--- a/WebKitTools/DumpRenderTree/mac/DumpRenderTreeWindow.mm
+++ b/WebKitTools/DumpRenderTree/mac/DumpRenderTreeWindow.mm
@@ -67,7 +67,7 @@ static CFArrayCallBacks NonRetainingArrayCallbacks = {
- (void)close
{
- [self stopObservingWebView];
+ [[NSNotificationCenter defaultCenter] removeObserver:self];
CFRange arrayRange = CFRangeMake(0, CFArrayGetCount(openWindowsRef));
CFIndex i = CFArrayGetFirstIndexOfValue(openWindowsRef, arrayRange, self);
@@ -99,32 +99,20 @@ static CFArrayCallBacks NonRetainingArrayCallbacks = {
return nil;
}
-- (void)startObservingWebView
+- (void)startListeningForAcceleratedCompositingChanges
{
- [self stopObservingWebView];
- [[self webView] addObserver:self forKeyPath:@"_isUsingAcceleratedCompositing" options:0 context:0];
- observingWebView = YES;
+ [[self webView] _setPostsAcceleratedCompositingNotifications:YES];
+ [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(webViewStartedAcceleratedCompositing:)
+ name:_WebViewDidStartAcceleratedCompositingNotification object:nil];
}
-- (void)stopObservingWebView
+- (void)webViewStartedAcceleratedCompositing:(NSNotification *)notification
{
- if (!observingWebView)
- return;
- [[self webView] removeObserver:self forKeyPath:@"_isUsingAcceleratedCompositing"];
- observingWebView = NO;
-}
-
-- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
-{
- if ([keyPath isEqualToString:@"_isUsingAcceleratedCompositing"]) {
- // When using accelerated compositing, the window needs to be autodisplay for AppKit/CA to
- // start accelerated animations correctly.
- BOOL isAccelerated = [[self webView] _isUsingAcceleratedCompositing];
- [self setAutodisplay:isAccelerated];
- return;
- }
-
- [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
+ // If the WebView has gone into compositing mode, turn on window autodisplay. This is necessary for CA
+ // to update layers and start animations.
+ // We only ever turn autodisplay on here, because we turn it off before every test.
+ if ([[self webView] _isUsingAcceleratedCompositing])
+ [self setAutodisplay:YES];
}
@end
diff --git a/WebKitTools/DumpRenderTree/mac/FrameLoadDelegate.mm b/WebKitTools/DumpRenderTree/mac/FrameLoadDelegate.mm
index 2838d2e..963eae7 100644
--- a/WebKitTools/DumpRenderTree/mac/FrameLoadDelegate.mm
+++ b/WebKitTools/DumpRenderTree/mac/FrameLoadDelegate.mm
@@ -48,13 +48,10 @@
#import <WebKit/WebHTMLViewPrivate.h>
#import <WebKit/WebKit.h>
#import <WebKit/WebNSURLExtras.h>
+#import <WebKit/WebScriptWorld.h>
#import <WebKit/WebSecurityOriginPrivate.h>
#import <wtf/Assertions.h>
-@interface NSURLRequest (PrivateThingsWeShouldntReallyUse)
-+(void)setAllowsAnyHTTPSCertificate:(BOOL)allow forHost:(NSString *)host;
-@end
-
@interface NSURL (DRTExtras)
- (NSString *)_drt_descriptionSuitableForTestResult;
@end
@@ -182,13 +179,15 @@
{
if (!done && gLayoutTestController->dumpFrameLoadCallbacks()) {
NSString *string = [NSString stringWithFormat:@"%@ - didFailProvisionalLoadWithError", [frame _drt_descriptionSuitableForTestResult]];
- printf ("%s\n", [string UTF8String]);
+ printf("%s\n", [string UTF8String]);
}
if ([error domain] == NSURLErrorDomain && ([error code] == NSURLErrorServerCertificateHasUnknownRoot || [error code] == NSURLErrorServerCertificateUntrusted)) {
- NSURL *failedURL = [[error userInfo] objectForKey:@"NSErrorFailingURLKey"];
- [NSURLRequest setAllowsAnyHTTPSCertificate:YES forHost:[failedURL _web_hostString]];
- [frame loadRequest:[[[[frame provisionalDataSource] request] mutableCopy] autorelease]];
+ // <http://webkit.org/b/31200> In order to prevent extra frame load delegate logging being generated if the first test to use SSL
+ // is set to log frame load delegate calls we ignore SSL certificate errors on localhost and 127.0.0.1 from within dumpRenderTree.
+ // Those are the only hosts that we use SSL with at present. If we hit this code path then we've found another host that we need
+ // to apply the workaround to.
+ ASSERT_NOT_REACHED();
return;
}
@@ -238,11 +237,8 @@
ASSERT_NOT_REACHED();
}
-- (void)webView:(WebView *)sender didClearWindowObject:(WebScriptObject *)obj forFrame:(WebFrame *)frame
+- (void)didClearWindowObjectInStandardWorldForFrame:(WebFrame *)frame
{
- ASSERT(obj == [frame windowObject]);
- ASSERT([obj JSObject] == JSContextGetGlobalObject([frame globalContext]));
-
// Make New-Style LayoutTestController
JSContextRef context = [frame globalContext];
JSObjectRef globalObject = JSContextGetGlobalObject(context);
@@ -260,7 +256,9 @@
// Make Old-Style controllers
- AppleScriptController *asc = [[AppleScriptController alloc] initWithWebView:sender];
+ WebView *webView = [frame webView];
+ WebScriptObject *obj = [frame windowObject];
+ AppleScriptController *asc = [[AppleScriptController alloc] initWithWebView:webView];
[obj setValue:asc forKey:@"appleScriptController"];
[asc release];
@@ -284,11 +282,32 @@
[obj setValue:[PlainTextController sharedPlainTextController] forKey:@"plainText"];
- TextInputController *tic = [[TextInputController alloc] initWithWebView:sender];
+ TextInputController *tic = [[TextInputController alloc] initWithWebView:webView];
[obj setValue:tic forKey:@"textInputController"];
[tic release];
}
+- (void)didClearWindowObjectForFrame:(WebFrame *)frame inIsolatedWorld:(WebScriptWorld *)world
+{
+ JSGlobalContextRef ctx = [frame _globalContextForScriptWorld:world];
+ if (!ctx)
+ return;
+
+ JSObjectRef globalObject = JSContextGetGlobalObject(ctx);
+ if (!globalObject)
+ return;
+
+ JSObjectSetProperty(ctx, globalObject, JSRetainPtr<JSStringRef>(Adopt, JSStringCreateWithUTF8CString("__worldID")).get(), JSValueMakeNumber(ctx, worldIDForWorld(world)), kJSPropertyAttributeReadOnly, 0);
+}
+
+- (void)webView:(WebView *)sender didClearWindowObjectForFrame:(WebFrame *)frame inScriptWorld:(WebScriptWorld *)world
+{
+ if (world == [WebScriptWorld standardWorld])
+ [self didClearWindowObjectInStandardWorldForFrame:frame];
+ else
+ [self didClearWindowObjectForFrame:frame inIsolatedWorld:world];
+}
+
- (void)webView:(WebView *)sender didReceiveTitle:(NSString *)title forFrame:(WebFrame *)frame
{
if (!done && gLayoutTestController->dumpFrameLoadCallbacks()) {
diff --git a/WebKitTools/DumpRenderTree/mac/LayoutTestControllerMac.mm b/WebKitTools/DumpRenderTree/mac/LayoutTestControllerMac.mm
index 4d6a609..69fe19f 100644
--- a/WebKitTools/DumpRenderTree/mac/LayoutTestControllerMac.mm
+++ b/WebKitTools/DumpRenderTree/mac/LayoutTestControllerMac.mm
@@ -43,25 +43,27 @@
#import <WebKit/WebApplicationCache.h>
#import <WebKit/WebBackForwardList.h>
#import <WebKit/WebCoreStatistics.h>
-#import <WebKit/WebDatabaseManagerPrivate.h>
#import <WebKit/WebDataSource.h>
+#import <WebKit/WebDatabaseManagerPrivate.h>
#import <WebKit/WebFrame.h>
#import <WebKit/WebFrameViewPrivate.h>
-#import <WebKit/WebIconDatabasePrivate.h>
+#import <WebKit/WebGeolocationMockPrivate.h>
#import <WebKit/WebHTMLRepresentation.h>
#import <WebKit/WebHTMLViewPrivate.h>
#import <WebKit/WebHistory.h>
#import <WebKit/WebHistoryPrivate.h>
+#import <WebKit/WebIconDatabasePrivate.h>
#import <WebKit/WebInspectorPrivate.h>
-#import <WebKit/WebGeolocationMockPrivate.h>
#import <WebKit/WebNSURLExtras.h>
#import <WebKit/WebPreferences.h>
#import <WebKit/WebPreferencesPrivate.h>
+#import <WebKit/WebScriptWorld.h>
#import <WebKit/WebSecurityOriginPrivate.h>
#import <WebKit/WebTypesInternal.h>
#import <WebKit/WebView.h>
#import <WebKit/WebViewPrivate.h>
#import <WebKit/WebWorkersPrivate.h>
+#import <wtf/HashMap.h>
#import <wtf/RetainPtr.h>
@interface CommandValidationTarget : NSObject <NSValidatedUserInterfaceItem>
@@ -299,6 +301,11 @@ void LayoutTestController::setXSSAuditorEnabled(bool enabled)
[[[mainFrame webView] preferences] setXSSAuditorEnabled:enabled];
}
+void LayoutTestController::setAllowUniversalAccessFromFileURLs(bool enabled)
+{
+ [[[mainFrame webView] preferences] setAllowUniversalAccessFromFileURLs:enabled];
+}
+
void LayoutTestController::setPopupBlockingEnabled(bool popupBlockingEnabled)
{
[[[mainFrame webView] preferences] setJavaScriptCanOpenWindowsAutomatically:!popupBlockingEnabled];
@@ -309,6 +316,11 @@ void LayoutTestController::setTabKeyCyclesThroughElements(bool cycles)
[[mainFrame webView] setTabKeyCyclesThroughElements:cycles];
}
+void LayoutTestController::setTimelineProfilingEnabled(bool enabled)
+{
+ [[[mainFrame webView] inspector] setTimelineProfilingEnabled:enabled];
+}
+
void LayoutTestController::setUseDashboardCompatibilityMode(bool flag)
{
[[mainFrame webView] _setDashboardBehavior:WebDashboardBehaviorUseBackwardCompatibilityMode to:flag];
@@ -474,6 +486,16 @@ bool LayoutTestController::pauseTransitionAtTimeOnElementWithId(JSStringRef prop
return [mainFrame _pauseTransitionOfProperty:nameNS onNode:[[mainFrame DOMDocument] getElementById:idNS] atTime:time];
}
+bool LayoutTestController::sampleSVGAnimationForElementAtTime(JSStringRef animationId, double time, JSStringRef elementId)
+{
+ RetainPtr<CFStringRef> animationIDCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, animationId));
+ NSString *animationIDNS = (NSString *)animationIDCF.get();
+ RetainPtr<CFStringRef> elementIDCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, elementId));
+ NSString *elementIDNS = (NSString *)elementIDCF.get();
+
+ return [mainFrame _pauseSVGAnimation:elementIDNS onSMILNode:[[mainFrame DOMDocument] getElementById:animationIDNS] atTime:time];
+}
+
unsigned LayoutTestController::numberOfActiveAnimations() const
{
return [mainFrame _numberOfActiveAnimations];
@@ -501,14 +523,14 @@ void LayoutTestController::addUserScript(JSStringRef source, bool runAtStart)
{
RetainPtr<CFStringRef> sourceCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, source));
NSString *sourceNS = (NSString *)sourceCF.get();
- [WebView _addUserScriptToGroup:@"org.webkit.DumpRenderTree" worldID:1 source:sourceNS url:nil whitelist:nil blacklist:nil injectionTime:(runAtStart ? WebInjectAtDocumentStart : WebInjectAtDocumentEnd)];
+ [WebView _addUserScriptToGroup:@"org.webkit.DumpRenderTree" world:[WebScriptWorld world] source:sourceNS url:nil whitelist:nil blacklist:nil injectionTime:(runAtStart ? WebInjectAtDocumentStart : WebInjectAtDocumentEnd)];
}
void LayoutTestController::addUserStyleSheet(JSStringRef source)
{
RetainPtr<CFStringRef> sourceCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, source));
NSString *sourceNS = (NSString *)sourceCF.get();
- [WebView _addUserStyleSheetToGroup:@"org.webkit.DumpRenderTree" worldID:1 source:sourceNS url:nil whitelist:nil blacklist:nil];
+ [WebView _addUserStyleSheetToGroup:@"org.webkit.DumpRenderTree" world:[WebScriptWorld world] source:sourceNS url:nil whitelist:nil blacklist:nil];
}
void LayoutTestController::showWebInspector()
@@ -530,9 +552,40 @@ void LayoutTestController::evaluateInWebInspector(long callId, JSStringRef scrip
[[[mainFrame webView] inspector] evaluateInFrontend:nil callId:callId script:scriptNS];
}
+typedef HashMap<unsigned, RetainPtr<WebScriptWorld> > WorldMap;
+static WorldMap& worldMap()
+{
+ static WorldMap& map = *new WorldMap;
+ return map;
+}
+
+unsigned worldIDForWorld(WebScriptWorld *world)
+{
+ WorldMap::const_iterator end = worldMap().end();
+ for (WorldMap::const_iterator it = worldMap().begin(); it != end; ++it) {
+ if (it->second == world)
+ return it->first;
+ }
+
+ return 0;
+}
+
void LayoutTestController::evaluateScriptInIsolatedWorld(unsigned worldID, JSObjectRef globalObject, JSStringRef script)
{
RetainPtr<CFStringRef> scriptCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, script));
NSString *scriptNS = (NSString *)scriptCF.get();
- [mainFrame _stringByEvaluatingJavaScriptInIsolatedWorld:worldID WithGlobalObject:globalObject FromString:scriptNS];
+
+ // A worldID of 0 always corresponds to a new world. Any other worldID corresponds to a world
+ // that is created once and cached forever.
+ WebScriptWorld *world;
+ if (!worldID)
+ world = [WebScriptWorld world];
+ else {
+ RetainPtr<WebScriptWorld>& worldSlot = worldMap().add(worldID, 0).first->second;
+ if (!worldSlot)
+ worldSlot.adoptNS([[WebScriptWorld alloc] init]);
+ world = worldSlot.get();
+ }
+
+ [mainFrame _stringByEvaluatingJavaScriptFromString:scriptNS withGlobalObject:globalObject inScriptWorld:world];
}
diff --git a/WebKitTools/DumpRenderTree/mac/UIDelegate.mm b/WebKitTools/DumpRenderTree/mac/UIDelegate.mm
index 393899e..81c03d2 100644
--- a/WebKitTools/DumpRenderTree/mac/UIDelegate.mm
+++ b/WebKitTools/DumpRenderTree/mac/UIDelegate.mm
@@ -34,9 +34,9 @@
#import "EventSendingController.h"
#import "LayoutTestController.h"
#import <WebKit/WebFramePrivate.h>
-#import <WebKit/WebGeolocationPrivate.h>
#import <WebKit/WebHTMLViewPrivate.h>
#import <WebKit/WebSecurityOriginPrivate.h>
+#import <WebKit/WebUIDelegatePrivate.h>
#import <WebKit/WebView.h>
#import <wtf/Assertions.h>
@@ -151,10 +151,14 @@ DumpRenderTreeDraggingInfo *draggingInfo = nil;
printf("UI DELEGATE STATUS CALLBACK: setStatusText:%s\n", [text UTF8String]);
}
-- (void)webView:(WebView *)sender frame:(WebFrame *)frame requestGeolocationPermission:(WebGeolocation *)geolocation securityOrigin:(WebSecurityOrigin *)origin
+- (void)webView:(WebView *)webView decidePolicyForGeolocationRequestFromOrigin:(WebSecurityOrigin *)origin frame:(WebFrame *)frame listener:(id<WebGeolocationPolicyListener>)listener
{
- if (gLayoutTestController->isGeolocationPermissionSet())
- [geolocation setIsAllowed:gLayoutTestController->geolocationPermission()];
+ if (gLayoutTestController->isGeolocationPermissionSet()) {
+ if (gLayoutTestController->geolocationPermission())
+ [listener allow];
+ else
+ [listener deny];
+ }
}
- (BOOL)webView:(WebView *)sender shouldHaltPlugin:(DOMNode *)pluginNode
diff --git a/WebKitTools/DumpRenderTree/pthreads/JavaScriptThreadingPthreads.cpp b/WebKitTools/DumpRenderTree/pthreads/JavaScriptThreadingPthreads.cpp
index 3ac257d..5a48b27 100644
--- a/WebKitTools/DumpRenderTree/pthreads/JavaScriptThreadingPthreads.cpp
+++ b/WebKitTools/DumpRenderTree/pthreads/JavaScriptThreadingPthreads.cpp
@@ -28,6 +28,7 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+#include "config.h"
#include "JavaScriptThreading.h"
#include <CoreFoundation/CoreFoundation.h>
diff --git a/WebKitTools/DumpRenderTree/qt/DumpRenderTree.cpp b/WebKitTools/DumpRenderTree/qt/DumpRenderTree.cpp
index 9faa37f..6d466bf 100644
--- a/WebKitTools/DumpRenderTree/qt/DumpRenderTree.cpp
+++ b/WebKitTools/DumpRenderTree/qt/DumpRenderTree.cpp
@@ -29,6 +29,8 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+#include "config.h"
+
#include "DumpRenderTree.h"
#include "EventSenderQt.h"
#include "LayoutTestControllerQt.h"
@@ -41,25 +43,29 @@
#include <QCryptographicHash>
#include <QDir>
#include <QFile>
-#include <QTimer>
-#include <QBoxLayout>
-#include <QScrollArea>
#include <QApplication>
#include <QUrl>
+#include <QFileInfo>
#include <QFocusEvent>
#include <QFontDatabase>
+#include <QNetworkAccessManager>
+#include <QNetworkReply>
#include <QNetworkRequest>
+#include <QUndoStack>
-#include <qwebpage.h>
-#include <qwebframe.h>
-#include <qwebview.h>
#include <qwebsettings.h>
#include <qwebsecurityorigin.h>
+#ifndef QT_NO_UITOOLS
+#include <QtUiTools/QUiLoader>
+#endif
+
#ifdef Q_WS_X11
#include <fontconfig/fontconfig.h>
#endif
+#include <limits.h>
+
#include <unistd.h>
#include <qdebug.h>
@@ -69,6 +75,7 @@ extern void qt_dump_frame_loader(bool b);
extern void qt_drt_clearFrameName(QWebFrame* qFrame);
extern void qt_drt_overwritePluginDirectories();
extern void qt_drt_resetOriginAccessWhiteLists();
+extern bool qt_drt_hasDocumentElement(QWebFrame* qFrame);
namespace WebCore {
@@ -76,39 +83,39 @@ namespace WebCore {
const unsigned int maxViewWidth = 800;
const unsigned int maxViewHeight = 600;
-class WebPage : public QWebPage {
- Q_OBJECT
-public:
- WebPage(QWidget *parent, DumpRenderTree *drt);
-
- QWebPage *createWindow(QWebPage::WebWindowType);
-
- void javaScriptAlert(QWebFrame *frame, const QString& message);
- void javaScriptConsoleMessage(const QString& message, int lineNumber, const QString& sourceID);
- bool javaScriptConfirm(QWebFrame *frame, const QString& msg);
- bool javaScriptPrompt(QWebFrame *frame, const QString& msg, const QString& defaultValue, QString* result);
-
- void resetSettings();
-
-public slots:
- bool shouldInterruptJavaScript() { return false; }
+NetworkAccessManager::NetworkAccessManager(QObject* parent)
+ : QNetworkAccessManager(parent)
+{
+#ifndef QT_NO_SSL
+ connect(this, SIGNAL(sslErrors(QNetworkReply*, const QList<QSslError>&)),
+ this, SLOT(sslErrorsEncountered(QNetworkReply*, const QList<QSslError>&)));
+#endif
+}
-protected:
- bool acceptNavigationRequest(QWebFrame* frame, const QNetworkRequest& request, NavigationType type);
+#ifndef QT_NO_SSL
+void NetworkAccessManager::sslErrorsEncountered(QNetworkReply* reply, const QList<QSslError>& errors)
+{
+ if (reply->url().host() == "127.0.0.1" || reply->url().host() == "localhost") {
+ bool ignore = true;
+
+ // Accept any HTTPS certificate.
+ foreach (const QSslError& error, errors) {
+ if (error.error() < QSslError::UnableToGetIssuerCertificate || error.error() > QSslError::HostNameMismatch) {
+ ignore = false;
+ break;
+ }
+ }
-private slots:
- void setViewGeometry(const QRect &r)
- {
- QWidget *v = view();
- if (v)
- v->setGeometry(r);
+ if (ignore)
+ reply->ignoreSslErrors();
}
-private:
- DumpRenderTree *m_drt;
-};
+}
+#endif
-WebPage::WebPage(QWidget *parent, DumpRenderTree *drt)
- : QWebPage(parent), m_drt(drt)
+WebPage::WebPage(QObject* parent, DumpRenderTree* drt)
+ : QWebPage(parent)
+ , m_webInspector(0)
+ , m_drt(drt)
{
QWebSettings* globalSettings = QWebSettings::globalSettings();
@@ -129,21 +136,37 @@ WebPage::WebPage(QWidget *parent, DumpRenderTree *drt)
connect(this, SIGNAL(geometryChangeRequested(const QRect &)),
this, SLOT(setViewGeometry(const QRect & )));
+ setNetworkAccessManager(new NetworkAccessManager(this));
setPluginFactory(new TestPlugin(this));
}
+WebPage::~WebPage()
+{
+ delete m_webInspector;
+}
+
+QWebInspector* WebPage::webInspector()
+{
+ if (!m_webInspector) {
+ m_webInspector = new QWebInspector;
+ m_webInspector->setPage(this);
+ }
+ return m_webInspector;
+}
+
void WebPage::resetSettings()
{
// After each layout test, reset the settings that may have been changed by
// layoutTestController.overridePreference() or similar.
settings()->resetFontSize(QWebSettings::DefaultFontSize);
-
settings()->resetAttribute(QWebSettings::JavascriptCanOpenWindows);
settings()->resetAttribute(QWebSettings::JavascriptEnabled);
settings()->resetAttribute(QWebSettings::PrivateBrowsingEnabled);
settings()->resetAttribute(QWebSettings::LinksIncludedInFocusChain);
settings()->resetAttribute(QWebSettings::OfflineWebApplicationCacheEnabled);
+ settings()->resetAttribute(QWebSettings::LocalContentCanAccessRemoteUrls);
+ QWebSettings::setMaximumPagesInCache(0); // reset to default
}
QWebPage *WebPage::createWindow(QWebPage::WebWindowType)
@@ -153,22 +176,52 @@ QWebPage *WebPage::createWindow(QWebPage::WebWindowType)
void WebPage::javaScriptAlert(QWebFrame*, const QString& message)
{
+ if (!isTextOutputEnabled())
+ return;
+
fprintf(stdout, "ALERT: %s\n", message.toUtf8().constData());
}
+static QString urlSuitableForTestResult(const QString& url)
+{
+ if (url.isEmpty() || !url.startsWith(QLatin1String("file://")))
+ return url;
+
+ return QFileInfo(url).fileName();
+}
+
void WebPage::javaScriptConsoleMessage(const QString& message, int lineNumber, const QString&)
{
- fprintf (stdout, "CONSOLE MESSAGE: line %d: %s\n", lineNumber, message.toUtf8().constData());
+ if (!isTextOutputEnabled())
+ return;
+
+ QString newMessage;
+ if (!message.isEmpty()) {
+ newMessage = message;
+
+ size_t fileProtocol = newMessage.indexOf(QLatin1String("file://"));
+ if (fileProtocol != -1) {
+ newMessage = newMessage.left(fileProtocol) + urlSuitableForTestResult(newMessage.mid(fileProtocol));
+ }
+ }
+
+ fprintf (stdout, "CONSOLE MESSAGE: line %d: %s\n", lineNumber, newMessage.toUtf8().constData());
}
bool WebPage::javaScriptConfirm(QWebFrame*, const QString& msg)
{
+ if (!isTextOutputEnabled())
+ return true;
+
fprintf(stdout, "CONFIRM: %s\n", msg.toUtf8().constData());
return true;
}
bool WebPage::javaScriptPrompt(QWebFrame*, const QString& msg, const QString& defaultValue, QString* result)
{
+ if (!isTextOutputEnabled())
+ return true;
+
fprintf(stdout, "PROMPT: %s, default text: %s\n", msg.toUtf8().constData(), defaultValue.toUtf8().constData());
*result = defaultValue;
return true;
@@ -203,35 +256,83 @@ bool WebPage::acceptNavigationRequest(QWebFrame* frame, const QNetworkRequest& r
typeDescription = "illegal value";
}
- fprintf(stdout, "Policy delegate: attempt to load %s with navigation type '%s'\n",
- url.toUtf8().constData(), typeDescription.toUtf8().constData());
+ if (isTextOutputEnabled())
+ fprintf(stdout, "Policy delegate: attempt to load %s with navigation type '%s'\n",
+ url.toUtf8().constData(), typeDescription.toUtf8().constData());
+
m_drt->layoutTestController()->notifyDone();
}
return QWebPage::acceptNavigationRequest(frame, request, type);
}
+bool WebPage::supportsExtension(QWebPage::Extension extension) const
+{
+ if (extension == QWebPage::ErrorPageExtension)
+ return m_drt->layoutTestController()->shouldHandleErrorPages();
+
+ return false;
+}
+
+bool WebPage::extension(Extension extension, const ExtensionOption *option, ExtensionReturn *output)
+{
+ const QWebPage::ErrorPageExtensionOption* info = static_cast<const QWebPage::ErrorPageExtensionOption*>(option);
+
+ // Lets handle error pages for the main frame for now.
+ if (info->frame != mainFrame())
+ return false;
+
+ QWebPage::ErrorPageExtensionReturn* errorPage = static_cast<QWebPage::ErrorPageExtensionReturn*>(output);
+
+ errorPage->content = QString("data:text/html,<body/>").toUtf8();
+
+ return true;
+}
+
+QObject* WebPage::createPlugin(const QString& classId, const QUrl& url, const QStringList& paramNames, const QStringList& paramValues)
+{
+ Q_UNUSED(url);
+ Q_UNUSED(paramNames);
+ Q_UNUSED(paramValues);
+#ifndef QT_NO_UITOOLS
+ QUiLoader loader;
+ return loader.createWidget(classId, view());
+#else
+ Q_UNUSED(classId);
+ return 0;
+#endif
+}
+
DumpRenderTree::DumpRenderTree()
: m_dumpPixels(false)
, m_stdin(0)
, m_notifier(0)
+ , m_enableTextOutput(false)
{
qt_drt_overwritePluginDirectories();
QWebSettings::enablePersistentStorage();
+ // create our primary testing page/view.
+ m_mainView = new QWebView(0);
+ m_mainView->resize(QSize(maxViewWidth, maxViewHeight));
+ m_page = new WebPage(m_mainView, this);
+ m_mainView->setPage(m_page);
+
+ // create out controllers. This has to be done before connectFrame,
+ // as it exports there to the JavaScript DOM window.
m_controller = new LayoutTestController(this);
connect(m_controller, SIGNAL(done()), this, SLOT(dump()));
+ m_eventSender = new EventSender(m_page);
+ m_textInputController = new TextInputController(m_page);
+ m_gcController = new GCController(m_page);
- QWebView *view = new QWebView(0);
- view->resize(QSize(maxViewWidth, maxViewHeight));
- m_page = new WebPage(view, this);
- view->setPage(m_page);
- connect(m_page, SIGNAL(frameCreated(QWebFrame *)), this, SLOT(connectFrame(QWebFrame *)));
+ // now connect our different signals
+ connect(m_page, SIGNAL(frameCreated(QWebFrame *)),
+ this, SLOT(connectFrame(QWebFrame *)));
connectFrame(m_page->mainFrame());
- connect(m_page->mainFrame(), SIGNAL(loadFinished(bool)), m_controller, SLOT(maybeDump(bool)));
+ connect(m_page, SIGNAL(loadFinished(bool)),
+ m_controller, SLOT(maybeDump(bool)));
- m_page->mainFrame()->setScrollBarPolicy(Qt::Horizontal, Qt::ScrollBarAlwaysOff);
- m_page->mainFrame()->setScrollBarPolicy(Qt::Vertical, Qt::ScrollBarAlwaysOff);
connect(m_page->mainFrame(), SIGNAL(titleChanged(const QString&)),
SLOT(titleChanged(const QString&)));
connect(m_page, SIGNAL(databaseQuotaExceeded(QWebFrame*,QString)),
@@ -239,20 +340,15 @@ DumpRenderTree::DumpRenderTree()
connect(m_page, SIGNAL(statusBarMessage(const QString&)),
this, SLOT(statusBarMessage(const QString&)));
- m_eventSender = new EventSender(m_page);
- m_textInputController = new TextInputController(m_page);
- m_gcController = new GCController(m_page);
-
QObject::connect(this, SIGNAL(quit()), qApp, SLOT(quit()), Qt::QueuedConnection);
qt_drt_run(true);
QFocusEvent event(QEvent::FocusIn, Qt::ActiveWindowFocusReason);
- QApplication::sendEvent(view, &event);
+ QApplication::sendEvent(m_mainView, &event);
}
DumpRenderTree::~DumpRenderTree()
{
- delete m_page;
-
+ delete m_mainView;
delete m_stdin;
delete m_notifier;
}
@@ -270,29 +366,48 @@ void DumpRenderTree::open()
}
}
-void DumpRenderTree::resetToConsistentStateBeforeTesting()
+static void clearHistory(QWebPage* page)
{
- closeRemainingWindows();
+ // QWebHistory::clear() leaves current page, so remove it as well by setting
+ // max item count to 0, and then setting it back to it's original value.
+
+ QWebHistory* history = page->history();
+ int itemCount = history->maximumItemCount();
+
+ history->clear();
+ history->setMaximumItemCount(0);
+ history->setMaximumItemCount(itemCount);
+}
- // Reset so that any current loads are stopped
+void DumpRenderTree::resetToConsistentStateBeforeTesting()
+{
+ // reset so that any current loads are stopped
+ // NOTE: that this has to be done before the layoutTestController is
+ // reset or we get timeouts for some tests.
m_page->blockSignals(true);
m_page->triggerAction(QWebPage::Stop);
m_page->blockSignals(false);
- m_page->mainFrame()->setZoomFactor(1.0);
+ // reset the layoutTestController at this point, so that we under no
+ // circumstance dump (stop the waitUntilDone timer) during the reset
+ // of the DRT.
+ m_controller->reset();
+
+ closeRemainingWindows();
- static_cast<WebPage*>(m_page)->resetSettings();
+ m_page->resetSettings();
+ m_page->undoStack()->clear();
+ m_page->mainFrame()->setZoomFactor(1.0);
+ clearHistory(m_page);
qt_drt_clearFrameName(m_page->mainFrame());
WorkQueue::shared()->clear();
- // Causes timeout, why?
- //WorkQueue::shared()->setFrozen(false);
+ WorkQueue::shared()->setFrozen(false);
- m_controller->reset();
qt_drt_resetOriginAccessWhiteLists();
- QLocale qlocale;
- QLocale::setDefault(qlocale);
+ QLocale::setDefault(QLocale::c());
+ setlocale(LC_ALL, "");
}
void DumpRenderTree::open(const QUrl& aurl)
@@ -316,7 +431,7 @@ void DumpRenderTree::open(const QUrl& aurl)
bool isW3CTest = url.toString().contains("svg/W3C-SVG-1.1");
int width = isW3CTest ? 480 : maxViewWidth;
int height = isW3CTest ? 360 : maxViewHeight;
- m_page->view()->resize(QSize(width, height));
+ m_mainView->resize(QSize(width, height));
m_page->setPreferredContentsSize(QSize());
m_page->setViewportSize(QSize(width, height));
@@ -329,6 +444,7 @@ void DumpRenderTree::open(const QUrl& aurl)
#endif
qt_dump_frame_loader(url.toString().contains("loading/"));
+ setTextOutputEnabled(true);
m_page->mainFrame()->load(url);
}
@@ -359,7 +475,7 @@ void DumpRenderTree::setDumpPixels(bool dump)
void DumpRenderTree::closeRemainingWindows()
{
- foreach(QWidget *widget, windows)
+ foreach (QObject* widget, windows)
delete widget;
windows.clear();
}
@@ -377,7 +493,7 @@ void DumpRenderTree::initJSObjects()
QString DumpRenderTree::dumpFramesAsText(QWebFrame* frame)
{
- if (!frame)
+ if (!frame || !qt_drt_hasDocumentElement(frame))
return QString();
QString result;
@@ -388,7 +504,8 @@ QString DumpRenderTree::dumpFramesAsText(QWebFrame* frame)
result.append(QLatin1String("'\n--------\n"));
}
- result.append(frame->toPlainText());
+ QString innerText = frame->toPlainText();
+ result.append(innerText);
result.append(QLatin1String("\n"));
if (m_controller->shouldDumpChildrenAsText()) {
@@ -400,11 +517,69 @@ QString DumpRenderTree::dumpFramesAsText(QWebFrame* frame)
return result;
}
+static QString dumpHistoryItem(const QWebHistoryItem& item, int indent, bool current)
+{
+ QString result;
+
+ int start = 0;
+ if (current) {
+ result.append(QLatin1String("curr->"));
+ start = 6;
+ }
+ for (int i = start; i < indent; i++)
+ result.append(' ');
+
+ QString url = item.url().toString();
+ if (url.contains("file://")) {
+ static QString layoutTestsString("/LayoutTests/");
+ static QString fileTestString("(file test):");
+
+ QString res = url.mid(url.indexOf(layoutTestsString) + layoutTestsString.length());
+ if (res.isEmpty())
+ return result;
+
+ result.append(fileTestString);
+ result.append(res);
+ } else {
+ result.append(url);
+ }
+
+ // FIXME: Wrong, need (private?) API for determining this.
+ result.append(QLatin1String(" **nav target**"));
+ result.append(QLatin1String("\n"));
+
+ return result;
+}
+
QString DumpRenderTree::dumpBackForwardList()
{
+ QWebHistory* history = webPage()->history();
+
QString result;
result.append(QLatin1String("\n============== Back Forward List ==============\n"));
- result.append(QLatin1String("FIXME: Unimplemented!\n"));
+
+ // FORMAT:
+ // " (file test):fast/loader/resources/click-fragment-link.html **nav target**"
+ // "curr-> (file test):fast/loader/resources/click-fragment-link.html#testfragment **nav target**"
+
+ int maxItems = history->maximumItemCount();
+
+ foreach (const QWebHistoryItem item, history->backItems(maxItems)) {
+ if (!item.isValid())
+ continue;
+ result.append(dumpHistoryItem(item, 8, false));
+ }
+
+ QWebHistoryItem item = history->currentItem();
+ if (item.isValid())
+ result.append(dumpHistoryItem(item, 8, true));
+
+ foreach (const QWebHistoryItem item, history->forwardItems(maxItems)) {
+ if (!item.isValid())
+ continue;
+ result.append(dumpHistoryItem(item, 8, false));
+ }
+
result.append(QLatin1String("===============================================\n"));
return result;
}
@@ -551,25 +726,28 @@ QWebPage *DumpRenderTree::createWindow()
{
if (!m_controller->canOpenWindows())
return 0;
- QWidget *container = new QWidget(0);
- container->resize(0, 0);
- container->move(-1, -1);
- container->hide();
- QWebPage *page = new WebPage(container, this);
- connectFrame(page->mainFrame());
- connect(m_page, SIGNAL(frameCreated(QWebFrame *)), this, SLOT(connectFrame(QWebFrame *)));
+
+ // Create a dummy container object to track the page in DRT.
+ // QObject is used instead of QWidget to prevent DRT from
+ // showing the main view when deleting the container.
+
+ QObject* container = new QObject(m_mainView);
+ // create a QWebPage we want to return
+ QWebPage* page = static_cast<QWebPage*>(new WebPage(container, this));
+ // gets cleaned up in closeRemainingWindows()
windows.append(container);
+
+ // connect the needed signals to the page
+ connect(page, SIGNAL(frameCreated(QWebFrame*)), this, SLOT(connectFrame(QWebFrame*)));
+ connectFrame(page->mainFrame());
+ connect(page, SIGNAL(loadFinished(bool)), m_controller, SLOT(maybeDump(bool)));
return page;
}
int DumpRenderTree::windowCount() const
{
- int count = 0;
- foreach(QWidget *w, windows) {
- if (w->children().count())
- ++count;
- }
- return count + 1;
+// include the main view in the count
+ return windows.count() + 1;
}
#if defined(Q_WS_X11)
@@ -613,5 +791,3 @@ void DumpRenderTree::initializeFonts()
#endif
}
-
-#include "DumpRenderTree.moc"
diff --git a/WebKitTools/DumpRenderTree/qt/DumpRenderTree.h b/WebKitTools/DumpRenderTree/qt/DumpRenderTree.h
index c5b4801..ab229fe 100644
--- a/WebKitTools/DumpRenderTree/qt/DumpRenderTree.h
+++ b/WebKitTools/DumpRenderTree/qt/DumpRenderTree.h
@@ -31,15 +31,25 @@
#define DUMPRENDERTREE_H
#include <QList>
+#include <QNetworkAccessManager>
#include <QObject>
#include <QTextStream>
#include <QSocketNotifier>
+#ifndef QT_NO_SSL
+#include <QSslError>
+#endif
+
+#include <qwebframe.h>
+#include <qwebinspector.h>
+#include <qwebpage.h>
+#include <qwebview.h>
+
QT_BEGIN_NAMESPACE
class QUrl;
class QFile;
QT_END_NAMESPACE
-class QWebPage;
+
class QWebFrame;
class LayoutTestController;
@@ -49,6 +59,8 @@ class GCController;
namespace WebCore {
+class WebPage;
+
class DumpRenderTree : public QObject {
Q_OBJECT
@@ -62,6 +74,9 @@ public:
// Initialize in single-file mode.
void open(const QUrl& url);
+ void setTextOutputEnabled(bool enable) { m_enableTextOutput = enable; }
+ bool isTextOutputEnabled() { return m_enableTextOutput; }
+
void setDumpPixels(bool);
void closeRemainingWindows();
@@ -74,7 +89,7 @@ public:
QWebPage *createWindow();
int windowCount() const;
- QWebPage *webPage() const { return m_page; }
+ WebPage *webPage() const { return m_page; }
#if defined(Q_WS_X11)
@@ -101,7 +116,8 @@ private:
bool m_dumpPixels;
QString m_expectedHash;
- QWebPage *m_page;
+ WebPage *m_page;
+ QWebView* m_mainView;
EventSender *m_eventSender;
TextInputController *m_textInputController;
@@ -110,7 +126,59 @@ private:
QFile *m_stdin;
QSocketNotifier* m_notifier;
- QList<QWidget *> windows;
+ QList<QObject*> windows;
+ bool m_enableTextOutput;
+};
+
+class NetworkAccessManager : public QNetworkAccessManager {
+ Q_OBJECT
+public:
+ NetworkAccessManager(QObject* parent);
+
+private slots:
+#ifndef QT_NO_SSL
+ void sslErrorsEncountered(QNetworkReply*, const QList<QSslError>&);
+#endif
+};
+
+class WebPage : public QWebPage {
+ Q_OBJECT
+public:
+ WebPage(QObject* parent, DumpRenderTree*);
+ virtual ~WebPage();
+ QWebInspector* webInspector();
+
+ QWebPage *createWindow(QWebPage::WebWindowType);
+
+ void javaScriptAlert(QWebFrame *frame, const QString& message);
+ void javaScriptConsoleMessage(const QString& message, int lineNumber, const QString& sourceID);
+ bool javaScriptConfirm(QWebFrame *frame, const QString& msg);
+ bool javaScriptPrompt(QWebFrame *frame, const QString& msg, const QString& defaultValue, QString* result);
+
+ void resetSettings();
+
+ virtual bool supportsExtension(QWebPage::Extension extension) const;
+ virtual bool extension(Extension extension, const ExtensionOption *option, ExtensionReturn *output);
+
+ QObject* createPlugin(const QString&, const QUrl&, const QStringList&, const QStringList&);
+
+public slots:
+ bool shouldInterruptJavaScript() { return false; }
+
+protected:
+ bool acceptNavigationRequest(QWebFrame* frame, const QNetworkRequest& request, NavigationType type);
+ bool isTextOutputEnabled() { return m_drt->isTextOutputEnabled(); }
+
+private slots:
+ void setViewGeometry(const QRect &r)
+ {
+ QWidget *v = view();
+ if (v)
+ v->setGeometry(r);
+ }
+private:
+ QWebInspector* m_webInspector;
+ DumpRenderTree *m_drt;
};
}
diff --git a/WebKitTools/DumpRenderTree/qt/DumpRenderTree.pro b/WebKitTools/DumpRenderTree/qt/DumpRenderTree.pro
index 571313c..81e929b 100644
--- a/WebKitTools/DumpRenderTree/qt/DumpRenderTree.pro
+++ b/WebKitTools/DumpRenderTree/qt/DumpRenderTree.pro
@@ -1,9 +1,20 @@
TARGET = DumpRenderTree
CONFIG -= app_bundle
+CONFIG += uitools
+
+mac:!static:contains(QT_CONFIG, qt_framework):!CONFIG(webkit_no_framework) {
+ CONFIG -= debug
+ CONFIG += release
+}
+
+BASEDIR = $$PWD/../
include(../../../WebKit.pri)
INCLUDEPATH += /usr/include/freetype2
+INCLUDEPATH += ../../..
INCLUDEPATH += ../../../JavaScriptCore
+INCLUDEPATH += ../../../JavaScriptCore/ForwardingHeaders
+INCLUDEPATH += $$BASEDIR
DESTDIR = ../../../bin
CONFIG += link_pkgconfig
@@ -12,7 +23,7 @@ PKGCONFIG += fontconfig
QT = core gui network
macx: QT += xml
-HEADERS = WorkQueue.h \
+HEADERS = $$BASEDIR/WorkQueue.h \
WorkQueueItem.h \
DumpRenderTree.h \
EventSenderQt.h \
@@ -20,7 +31,7 @@ HEADERS = WorkQueue.h \
LayoutTestControllerQt.h \
jsobjects.h \
testplugin.h
-SOURCES = WorkQueue.cpp \
+SOURCES = $$BASEDIR/WorkQueue.cpp \
DumpRenderTree.cpp \
EventSenderQt.cpp \
TextInputControllerQt.cpp \
@@ -34,8 +45,4 @@ unix:!mac {
QMAKE_RPATHDIR = $$OUTPUT_DIR/lib $$QMAKE_RPATHDIR
}
-lessThan(QT_MINOR_VERSION, 4) {
- DEFINES += QT_BEGIN_NAMESPACE="" QT_END_NAMESPACE=""
-}
-
DEFINES+=USE_SYSTEM_MALLOC
diff --git a/WebKitTools/DumpRenderTree/qt/EventSenderQt.cpp b/WebKitTools/DumpRenderTree/qt/EventSenderQt.cpp
index bbefed9..a0da273 100644
--- a/WebKitTools/DumpRenderTree/qt/EventSenderQt.cpp
+++ b/WebKitTools/DumpRenderTree/qt/EventSenderQt.cpp
@@ -30,6 +30,15 @@
#include "EventSenderQt.h"
//#include <QtDebug>
+
+#define KEYCODE_DEL 127
+#define KEYCODE_BACKSPACE 8
+#define KEYCODE_LEFTARROW 0xf702
+#define KEYCODE_RIGHTARROW 0xf703
+#define KEYCODE_UPARROW 0xf700
+#define KEYCODE_DOWNARROW 0xf701
+
+
EventSender::EventSender(QWebPage* parent)
: QObject(parent)
{
@@ -129,7 +138,7 @@ void EventSender::keyDown(const QString& string, const QStringList& modifiers)
if (modifs == Qt::ShiftModifier)
code = Qt::Key_Backtab;
s = QString();
- } else if (code == 127) {
+ } else if (code == KEYCODE_DEL || code == KEYCODE_BACKSPACE) {
code = Qt::Key_Backspace;
if (modifs == Qt::AltModifier)
modifs = Qt::ControlModifier;
@@ -148,28 +157,28 @@ void EventSender::keyDown(const QString& string, const QStringList& modifiers)
s = QString();
code = Qt::Key_Home;
modifs = 0;
- } else if (code == 0xf702) {
+ } else if (code == KEYCODE_LEFTARROW) {
s = QString();
code = Qt::Key_Left;
if (modifs & Qt::MetaModifier) {
code = Qt::Key_Home;
modifs &= ~Qt::MetaModifier;
}
- } else if (code == 0xf703) {
+ } else if (code == KEYCODE_RIGHTARROW) {
s = QString();
code = Qt::Key_Right;
if (modifs & Qt::MetaModifier) {
code = Qt::Key_End;
modifs &= ~Qt::MetaModifier;
}
- } else if (code == 0xf700) {
+ } else if (code == KEYCODE_UPARROW) {
s = QString();
code = Qt::Key_Up;
if (modifs & Qt::MetaModifier) {
code = Qt::Key_PageUp;
modifs &= ~Qt::MetaModifier;
}
- } else if (code == 0xf701) {
+ } else if (code == KEYCODE_DOWNARROW) {
s = QString();
code = Qt::Key_Down;
if (modifs & Qt::MetaModifier) {
diff --git a/WebKitTools/DumpRenderTree/qt/ImageDiff.pro b/WebKitTools/DumpRenderTree/qt/ImageDiff.pro
index 11ee1fa..636835a 100644
--- a/WebKitTools/DumpRenderTree/qt/ImageDiff.pro
+++ b/WebKitTools/DumpRenderTree/qt/ImageDiff.pro
@@ -13,6 +13,3 @@ unix:!mac {
QMAKE_RPATHDIR = $$OUTPUT_DIR/lib $$QMAKE_RPATHDIR
}
-lessThan(QT_MINOR_VERSION, 4) {
- DEFINES += QT_BEGIN_NAMESPACE="" QT_END_NAMESPACE=""
-}
diff --git a/WebKitTools/DumpRenderTree/qt/LayoutTestControllerQt.cpp b/WebKitTools/DumpRenderTree/qt/LayoutTestControllerQt.cpp
index b8de6a5..0ea5632 100644
--- a/WebKitTools/DumpRenderTree/qt/LayoutTestControllerQt.cpp
+++ b/WebKitTools/DumpRenderTree/qt/LayoutTestControllerQt.cpp
@@ -32,13 +32,16 @@
#include "DumpRenderTree.h"
#include "WorkQueue.h"
#include "WorkQueueItem.h"
+#include <QDir>
extern void qt_dump_editing_callbacks(bool b);
extern void qt_dump_resource_load_callbacks(bool b);
extern void qt_drt_setJavaScriptProfilingEnabled(QWebFrame*, bool enabled);
extern bool qt_drt_pauseAnimation(QWebFrame*, const QString& name, double time, const QString& elementId);
extern bool qt_drt_pauseTransitionOfProperty(QWebFrame*, const QString& name, double time, const QString& elementId);
+extern bool qt_drt_pauseSVGAnimation(QWebFrame*, const QString& animationId, double time, const QString& elementId);
extern int qt_drt_numberOfActiveAnimations(QWebFrame*);
+
extern void qt_drt_whiteListAccessFromOrigin(const QString& sourceOrigin, const QString& destinationProtocol, const QString& destinationHost, bool allowDestinationSubdomains);
extern QString qt_drt_counterValueForElementById(QWebFrame* qFrame, const QString& id);
@@ -63,6 +66,7 @@ void LayoutTestController::reset()
m_timeoutTimer.stop();
m_topLoadingFrame = 0;
m_waitForPolicy = false;
+ m_handleErrorPages = false;
qt_dump_editing_callbacks(false);
qt_dump_resource_load_callbacks(false);
}
@@ -72,7 +76,7 @@ void LayoutTestController::processWork()
// qDebug() << ">>>processWork";
// if we didn't start a new load, then we finished all the commands, so we're ready to dump state
- if (!WorkQueue::shared()->processWork() && !shouldWaitUntilDone()) {
+ if (WorkQueue::shared()->processWork() && !shouldWaitUntilDone()) {
emit done();
m_isLoading = false;
}
@@ -81,7 +85,7 @@ void LayoutTestController::processWork()
// Called on loadFinished on mainFrame.
void LayoutTestController::maybeDump(bool success)
{
- Q_ASSERT(sender() == m_topLoadingFrame);
+ Q_ASSERT(sender() == m_topLoadingFrame->page());
// as the function is called on loadFinished, the test might
// already have dumped and thus no longer be active, thus
@@ -107,7 +111,7 @@ void LayoutTestController::waitUntilDone()
{
//qDebug() << ">>>>waitForDone";
m_waitForDone = true;
- m_timeoutTimer.start(11000, this);
+ m_timeoutTimer.start(15000, this);
}
QString LayoutTestController::counterValueForElementById(const QString& id)
@@ -123,10 +127,14 @@ void LayoutTestController::keepWebHistory()
void LayoutTestController::notifyDone()
{
qDebug() << ">>>>notifyDone";
+
if (!m_timeoutTimer.isActive())
return;
+
m_timeoutTimer.stop();
emit done();
+
+ // FIXME: investigate why always resetting these result in timeouts
m_isLoading = false;
m_waitForDone = false;
m_waitForPolicy = false;
@@ -142,6 +150,12 @@ void LayoutTestController::clearBackForwardList()
m_drt->webPage()->history()->clear();
}
+QString LayoutTestController::pathToLocalResource(const QString& url)
+{
+ // Function introduced in r28690.
+ return QLatin1String("file://") + QUrl(url).toLocalFile();
+}
+
void LayoutTestController::dumpEditingCallbacks()
{
qDebug() << ">>>dumpEditingCallbacks";
@@ -179,10 +193,16 @@ void LayoutTestController::queueReload()
WorkQueue::shared()->queue(new ReloadItem(m_drt->webPage()));
}
-void LayoutTestController::queueScript(const QString &url)
+void LayoutTestController::queueLoadingScript(const QString& script)
+{
+ //qDebug() << ">>>queueLoadingScript" << script;
+ WorkQueue::shared()->queue(new LoadingScriptItem(script, m_drt->webPage()));
+}
+
+void LayoutTestController::queueNonLoadingScript(const QString& script)
{
- //qDebug() << ">>>queueScript" << url;
- WorkQueue::shared()->queue(new ScriptItem(url, m_drt->webPage()));
+ //qDebug() << ">>>queueNonLoadingScript" << script;
+ WorkQueue::shared()->queue(new NonLoadingScriptItem(script, m_drt->webPage()));
}
void LayoutTestController::provisionalLoad()
@@ -195,7 +215,9 @@ void LayoutTestController::provisionalLoad()
void LayoutTestController::timerEvent(QTimerEvent *ev)
{
if (ev->timerId() == m_timeoutTimer.timerId()) {
- //qDebug() << ">>>>>>>>>>>>> timeout";
+ const char* message = "FAIL: Timed out waiting for notifyDone to be called\n";
+ fprintf(stderr, "%s", message);
+ fprintf(stdout, "%s", message);
notifyDone();
} else
QObject::timerEvent(ev);
@@ -215,6 +237,22 @@ QString LayoutTestController::decodeHostName(const QString& host)
return decoded;
}
+void LayoutTestController::showWebInspector()
+{
+ m_drt->webPage()->settings()->setAttribute(QWebSettings::DeveloperExtrasEnabled, true);
+ m_drt->webPage()->webInspector()->show();
+}
+
+void LayoutTestController::hideWebInspector()
+{
+ m_drt->webPage()->webInspector()->hide();
+}
+
+void LayoutTestController::setAllowUniversalAccessFromFileURLs(bool enabled)
+{
+ m_drt->webPage()->settings()->setAttribute(QWebSettings::LocalContentCanAccessRemoteUrls, enabled);
+}
+
void LayoutTestController::setJavaScriptProfilingEnabled(bool enable)
{
m_topLoadingFrame->page()->settings()->setAttribute(QWebSettings::DeveloperExtrasEnabled, true);
@@ -260,6 +298,15 @@ bool LayoutTestController::pauseTransitionAtTimeOnElementWithId(const QString& p
return qt_drt_pauseTransitionOfProperty(frame, propertyName, time, elementId);
}
+bool LayoutTestController::sampleSVGAnimationForElementAtTime(const QString& animationId,
+ double time,
+ const QString& elementId)
+{
+ QWebFrame* frame = m_drt->webPage()->mainFrame();
+ Q_ASSERT(frame);
+ return qt_drt_pauseSVGAnimation(frame, animationId, time, elementId);
+}
+
unsigned LayoutTestController::numberOfActiveAnimations() const
{
QWebFrame* frame = m_drt->webPage()->mainFrame();
@@ -313,4 +360,6 @@ void LayoutTestController::overridePreference(const QString& name, const QVarian
settings->setAttribute(QWebSettings::OfflineWebApplicationCacheEnabled, value.toBool());
else if (name == "WebKitDefaultFontSize")
settings->setFontSize(QWebSettings::DefaultFontSize, value.toInt());
+ else if (name == "WebKitUsesPageCachePreferenceKey")
+ QWebSettings::setMaximumPagesInCache(value.toInt());
}
diff --git a/WebKitTools/DumpRenderTree/qt/LayoutTestControllerQt.h b/WebKitTools/DumpRenderTree/qt/LayoutTestControllerQt.h
index cab014c..ac8681f 100644
--- a/WebKitTools/DumpRenderTree/qt/LayoutTestControllerQt.h
+++ b/WebKitTools/DumpRenderTree/qt/LayoutTestControllerQt.h
@@ -63,6 +63,7 @@ public:
bool shouldDumpDatabaseCallbacks() const { return m_dumpDatabaseCallbacks; }
bool shouldDumpStatusCallbacks() const { return m_dumpStatusCallbacks; }
bool shouldWaitUntilDone() const { return m_waitForDone; }
+ bool shouldHandleErrorPages() const { return m_handleErrorPages; }
bool canOpenWindows() const { return m_canOpenWindows; }
bool shouldDumpTitleChanges() const { return m_dumpTitleChanges; }
bool waitForPolicy() const { return m_waitForPolicy; }
@@ -87,22 +88,28 @@ public slots:
void keepWebHistory();
void notifyDone();
void dumpBackForwardList() { m_dumpBackForwardList = true; }
+ void handleErrorPages() { m_handleErrorPages = true; }
void dumpEditingCallbacks();
void dumpResourceLoadCallbacks();
void queueBackNavigation(int howFarBackward);
void queueForwardNavigation(int howFarForward);
void queueLoad(const QString& url, const QString& target = QString());
void queueReload();
- void queueScript(const QString& url);
+ void queueLoadingScript(const QString& script);
+ void queueNonLoadingScript(const QString& script);
void provisionalLoad();
void setCloseRemainingWindowsWhenComplete(bool = false) {}
int windowCount();
void display() {}
void clearBackForwardList();
+ QString pathToLocalResource(const QString& url);
void dumpTitleChanges() { m_dumpTitleChanges = true; }
QString encodeHostName(const QString& host);
QString decodeHostName(const QString& host);
void dumpSelectionRect() const {}
+ void showWebInspector();
+ void hideWebInspector();
+ void setAllowUniversalAccessFromFileURLs(bool enable);
void setJavaScriptProfilingEnabled(bool enable);
void setFixedContentsSize(int width, int height);
void setPrivateBrowsingEnabled(bool enable);
@@ -111,6 +118,8 @@ public slots:
bool pauseAnimationAtTimeOnElementWithId(const QString& animationName, double time, const QString& elementId);
bool pauseTransitionAtTimeOnElementWithId(const QString& propertyName, double time, const QString& elementId);
+ bool sampleSVGAnimationForElementAtTime(const QString& animationId, double time, const QString& elementId);
+
unsigned numberOfActiveAnimations() const;
void whiteListAccessFromOrigin(const QString& sourceOrigin, const QString& destinationProtocol, const QString& destinationHost, bool allowDestinationSubdomains);
@@ -138,6 +147,7 @@ private:
bool m_dumpDatabaseCallbacks;
bool m_dumpStatusCallbacks;
bool m_waitForPolicy;
+ bool m_handleErrorPages;
QBasicTimer m_timeoutTimer;
QWebFrame* m_topLoadingFrame;
diff --git a/WebKitTools/DumpRenderTree/qt/TestNetscapePlugin/TestNetscapePlugin.pro b/WebKitTools/DumpRenderTree/qt/TestNetscapePlugin/TestNetscapePlugin.pro
index 7f502f8..7b8162b 100644
--- a/WebKitTools/DumpRenderTree/qt/TestNetscapePlugin/TestNetscapePlugin.pro
+++ b/WebKitTools/DumpRenderTree/qt/TestNetscapePlugin/TestNetscapePlugin.pro
@@ -1,7 +1,7 @@
TEMPLATE = lib
TARGET = TestNetscapePlugIn
-VPATH = ../../gtk/TestNetscapePlugin ../../TestNetscapePlugIn.subproj
+VPATH = ../../unix/TestNetscapePlugin ../../TestNetscapePlugIn.subproj
include(../../../../WebKit.pri)
DESTDIR = $$OUTPUT_DIR/lib/plugins
@@ -18,8 +18,8 @@ mac {
}
INCLUDEPATH += ../../../../JavaScriptCore \
- ../../gtk/TestNetscapePlugin/ForwardingHeaders \
- ../../gtk/TestNetscapePlugin/ForwardingHeaders/WebKit \
+ ../../unix/TestNetscapePlugin/ForwardingHeaders \
+ ../../unix/TestNetscapePlugin/ForwardingHeaders/WebKit \
../../../../WebCore \
../../../../WebCore/bridge \
../../TestNetscapePlugIn.subproj
@@ -31,5 +31,5 @@ mac {
SOURCES += ../../TestNetscapePlugIn.subproj/main.cpp
LIBS += -framework Carbon
} else {
- SOURCES += ../../gtk/TestNetscapePlugin/TestNetscapePlugin.cpp
+ SOURCES += ../../unix/TestNetscapePlugin/TestNetscapePlugin.cpp
}
diff --git a/WebKitTools/DumpRenderTree/qt/WorkQueue.cpp b/WebKitTools/DumpRenderTree/qt/WorkQueue.cpp
deleted file mode 100644
index f8448e4..0000000
--- a/WebKitTools/DumpRenderTree/qt/WorkQueue.cpp
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Copyright (C) 2007 Apple Inc. All rights reserved.
- * Copyright (C) 2009 Torch Mobile Inc. http://www.torchmobile.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.
- */
-
-#include "config.h"
-#include "WorkQueue.h"
-
-static const unsigned queueLength = 1024;
-
-static WorkQueueItem* theQueue[queueLength];
-static unsigned startOfQueue;
-static unsigned endOfQueue;
-
-WorkQueue* WorkQueue::shared()
-{
- static WorkQueue* sharedInstance = new WorkQueue;
- return sharedInstance;
-}
-
-WorkQueue::WorkQueue()
- : m_frozen(false)
-{
-}
-
-void WorkQueue::queue(WorkQueueItem* item)
-{
- Q_ASSERT(endOfQueue < queueLength);
- Q_ASSERT(endOfQueue >= startOfQueue);
-
- if (m_frozen) {
- delete item;
- return;
- }
-
- theQueue[endOfQueue++] = item;
-}
-
-WorkQueueItem* WorkQueue::dequeue()
-{
- Q_ASSERT(endOfQueue >= startOfQueue);
-
- if (startOfQueue == endOfQueue)
- return 0;
-
- return theQueue[startOfQueue++];
-}
-
-unsigned WorkQueue::count()
-{
- return endOfQueue - startOfQueue;
-}
-
-void WorkQueue::clear()
-{
- for (unsigned i = startOfQueue; i < endOfQueue; ++i) {
- delete theQueue[i];
- theQueue[i] = 0;
- }
-
- startOfQueue = 0;
- endOfQueue = 0;
-}
-
-bool WorkQueue::processWork()
-{
- bool startedLoad = false;
-
- while (!startedLoad && count()) {
- WorkQueueItem* item = dequeue();
- Q_ASSERT(item);
- startedLoad = item->invoke();
- delete item;
- }
-
- // If we're done and we didn't start a load, then we're really done, so return true.
- return !startedLoad;
-}
diff --git a/WebKitTools/DumpRenderTree/qt/WorkQueue.h b/WebKitTools/DumpRenderTree/qt/WorkQueue.h
deleted file mode 100644
index 902ba0d..0000000
--- a/WebKitTools/DumpRenderTree/qt/WorkQueue.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright (C) 2007 Apple Inc. All rights reserved.
- * Copyright (C) 2009 Torch Mobile Inc. http://www.torchmobile.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.
- */
-
-#ifndef WorkQueue_h
-#define WorkQueue_h
-
-#include "WorkQueueItem.h"
-
-class WorkQueue {
-public:
- static WorkQueue* shared();
-
- void queue(WorkQueueItem*);
- WorkQueueItem* dequeue();
- void clear();
- unsigned count();
-
- void setFrozen(bool b) { m_frozen = b; }
-
- bool processWork(); // Returns true if all work is done, false if we started a load.
-
-private:
- WorkQueue();
-
- bool m_frozen;
-};
-
-#endif // !defined(WorkQueue_h)
diff --git a/WebKitTools/DumpRenderTree/qt/WorkQueueItem.h b/WebKitTools/DumpRenderTree/qt/WorkQueueItem.h
index 9819ec0..d534493 100644
--- a/WebKitTools/DumpRenderTree/qt/WorkQueueItem.h
+++ b/WebKitTools/DumpRenderTree/qt/WorkQueueItem.h
@@ -89,6 +89,27 @@ private:
QString m_script;
};
+class LoadingScriptItem : public ScriptItem {
+public:
+ LoadingScriptItem(const QString& script, QWebPage* page)
+ : ScriptItem(script, page)
+ {
+ }
+
+ virtual bool invoke() const { return ScriptItem::invoke(); }
+};
+
+class NonLoadingScriptItem : public ScriptItem {
+public:
+ NonLoadingScriptItem(const QString& script, QWebPage* page)
+ : ScriptItem(script, page)
+ {
+ }
+
+ virtual bool invoke() const { ScriptItem::invoke(); return false; }
+};
+
+
class BackForwardItem : public WorkQueueItem {
public:
virtual bool invoke() const;
diff --git a/WebKitTools/DumpRenderTree/qt/jsobjects.cpp b/WebKitTools/DumpRenderTree/qt/jsobjects.cpp
index e747aeb..af331f0 100644
--- a/WebKitTools/DumpRenderTree/qt/jsobjects.cpp
+++ b/WebKitTools/DumpRenderTree/qt/jsobjects.cpp
@@ -26,7 +26,10 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include <jsobjects.h>
+
+#include "config.h"
+#include "jsobjects.h"
+
#include <qwebpage.h>
GCController::GCController(QWebPage* parent)
diff --git a/WebKitTools/DumpRenderTree/qt/main.cpp b/WebKitTools/DumpRenderTree/qt/main.cpp
index ae67a59..719315f 100644
--- a/WebKitTools/DumpRenderTree/qt/main.cpp
+++ b/WebKitTools/DumpRenderTree/qt/main.cpp
@@ -29,6 +29,8 @@
#include "DumpRenderTree.h"
+#include <wtf/AlwaysInline.h>
+
#include <qstringlist.h>
#include <qapplication.h>
#include <qurl.h>
@@ -38,6 +40,7 @@
#include <qwebsettings.h>
#include <qwebdatabase.h>
#include <qdesktopservices.h>
+#include <qwindowsstyle.h>
#ifdef Q_WS_X11
#include <qx11info_x11.h>
@@ -86,7 +89,7 @@ QString get_backtrace() {
return s;
}
-static void crashHandler(int sig)
+static NO_RETURN void crashHandler(int sig)
{
fprintf(stderr, "%s\n", strsignal(sig));
fprintf(stderr, "%s\n", get_backtrace().toLatin1().constData());
@@ -98,23 +101,25 @@ int main(int argc, char* argv[])
#ifdef Q_WS_X11
FcInit();
WebCore::DumpRenderTree::initializeFonts();
+#endif
+
#if QT_VERSION >= 0x040500
QApplication::setGraphicsSystem("raster");
#endif
-#endif
- QApplication app(argc, argv);
-#ifdef Q_WS_X11
- QX11Info::setAppDpiY(0, 96);
- QX11Info::setAppDpiX(0, 96);
-#endif
+
+ QApplication::setStyle(new QWindowsStyle);
QFont f("Sans Serif");
f.setPointSize(9);
f.setWeight(QFont::Normal);
f.setStyle(QFont::StyleNormal);
- app.setFont(f);
- app.setStyle(QLatin1String("Plastique"));
+ QApplication::setFont(f);
+ QApplication app(argc, argv);
+#ifdef Q_WS_X11
+ QX11Info::setAppDpiY(0, 96);
+ QX11Info::setAppDpiX(0, 96);
+#endif
signal(SIGILL, crashHandler); /* 4: illegal instruction (not reset when caught) */
signal(SIGTRAP, crashHandler); /* 5: trace trap (not reset when caught) */
diff --git a/WebKitTools/DumpRenderTree/gtk/TestNetscapePlugin/ForwardingHeaders/WebKit/npapi.h b/WebKitTools/DumpRenderTree/unix/TestNetscapePlugin/ForwardingHeaders/WebKit/npapi.h
index 08706f7..08706f7 100644
--- a/WebKitTools/DumpRenderTree/gtk/TestNetscapePlugin/ForwardingHeaders/WebKit/npapi.h
+++ b/WebKitTools/DumpRenderTree/unix/TestNetscapePlugin/ForwardingHeaders/WebKit/npapi.h
diff --git a/WebKitTools/DumpRenderTree/gtk/TestNetscapePlugin/ForwardingHeaders/WebKit/npfunctions.h b/WebKitTools/DumpRenderTree/unix/TestNetscapePlugin/ForwardingHeaders/WebKit/npfunctions.h
index 54a603d..54a603d 100644
--- a/WebKitTools/DumpRenderTree/gtk/TestNetscapePlugin/ForwardingHeaders/WebKit/npfunctions.h
+++ b/WebKitTools/DumpRenderTree/unix/TestNetscapePlugin/ForwardingHeaders/WebKit/npfunctions.h
diff --git a/WebKitTools/DumpRenderTree/gtk/TestNetscapePlugin/ForwardingHeaders/WebKit/npruntime.h b/WebKitTools/DumpRenderTree/unix/TestNetscapePlugin/ForwardingHeaders/WebKit/npruntime.h
index 00bbc18..00bbc18 100644
--- a/WebKitTools/DumpRenderTree/gtk/TestNetscapePlugin/ForwardingHeaders/WebKit/npruntime.h
+++ b/WebKitTools/DumpRenderTree/unix/TestNetscapePlugin/ForwardingHeaders/WebKit/npruntime.h
diff --git a/WebKitTools/DumpRenderTree/gtk/TestNetscapePlugin/TestNetscapePlugin.cpp b/WebKitTools/DumpRenderTree/unix/TestNetscapePlugin/TestNetscapePlugin.cpp
index 6c62a7c..cb01267 100644
--- a/WebKitTools/DumpRenderTree/gtk/TestNetscapePlugin/TestNetscapePlugin.cpp
+++ b/WebKitTools/DumpRenderTree/unix/TestNetscapePlugin/TestNetscapePlugin.cpp
@@ -45,6 +45,8 @@ extern "C" {
char* NP_GetMIMEDescription(void);
}
+static void executeScript(const PluginObject* obj, const char* script);
+
static NPError
webkit_test_plugin_new_instance(NPMIMEType /*mimetype*/,
NPP instance,
@@ -75,9 +77,15 @@ webkit_test_plugin_new_instance(NPMIMEType /*mimetype*/,
for (int i = 0; i < argc; i++)
if (strcasecmp(argn[i], "src") == 0)
pluginLog(instance, "src: %s", argv[i]);
- }
+ } else if (strcasecmp(argn[i], "cleardocumentduringnew") == 0)
+ executeScript(obj, "document.body.innerHTML = ''");
+ else if (!strcasecmp(argn[i], "ondestroy"))
+ obj->onDestroy = strdup(argv[i]);
+ else if (strcasecmp(argn[i], "testdocumentopenindestroystream") == 0)
+ obj->testDocumentOpenInDestroyStream = TRUE;
+ else if (strcasecmp(argn[i], "testwindowopen") == 0)
+ obj->testWindowOpen = TRUE;
}
-
instance->pdata = obj;
}
@@ -89,6 +97,11 @@ webkit_test_plugin_destroy_instance(NPP instance, NPSavedData** /*save*/)
{
PluginObject* obj = static_cast<PluginObject*>(instance->pdata);
if (obj) {
+ if (obj->onDestroy) {
+ executeScript(obj, obj->onDestroy);
+ free(obj->onDestroy);
+ }
+
if (obj->onStreamLoad)
free(obj->onStreamLoad);
@@ -117,6 +130,12 @@ webkit_test_plugin_set_window(NPP instance, NPWindow *window)
pluginLog(instance, "NPP_SetWindow: %d %d", (int)window->width, (int)window->height);
obj->logSetWindow = false;
}
+
+ if (obj->testWindowOpen) {
+ testWindowOpen(instance);
+ obj->testWindowOpen = FALSE;
+ }
+
}
return NPERR_NO_ERROR;
@@ -167,6 +186,11 @@ webkit_test_plugin_destroy_stream(NPP instance, NPStream* /*stream*/, NPError /*
if (obj->onStreamDestroy)
executeScript(obj, obj->onStreamDestroy);
+ if (obj->testDocumentOpenInDestroyStream) {
+ testDocumentOpen(instance);
+ obj->testDocumentOpenInDestroyStream = FALSE;
+ }
+
return NPERR_NO_ERROR;
}
diff --git a/WebKitTools/DumpRenderTree/win/AccessibilityUIElementWin.cpp b/WebKitTools/DumpRenderTree/win/AccessibilityUIElementWin.cpp
index de3d9ff..163abb1 100644
--- a/WebKitTools/DumpRenderTree/win/AccessibilityUIElementWin.cpp
+++ b/WebKitTools/DumpRenderTree/win/AccessibilityUIElementWin.cpp
@@ -151,10 +151,24 @@ JSStringRef AccessibilityUIElement::role()
VARIANT vRole;
if (FAILED(m_element->get_accRole(self(), &vRole)))
return JSStringCreateWithCharacters(0, 0);
- ASSERT(V_VT(&vRole) == VT_I4);
- TCHAR roleText[64] = {0};
- ::GetRoleText(V_I4(&vRole), roleText, ARRAYSIZE(roleText));
- return JSStringCreateWithCharacters(roleText, _tcslen(roleText));
+
+ ASSERT(V_VT(&vRole) == VT_I4 || V_VT(&vRole) == VT_BSTR);
+
+ wstring result;
+ if (V_VT(&vRole) == VT_I4) {
+ unsigned roleTextLength = ::GetRoleText(V_I4(&vRole), 0, 0) + 1;
+
+ Vector<TCHAR> roleText(roleTextLength);
+
+ ::GetRoleText(V_I4(&vRole), roleText.data(), roleTextLength);
+
+ result = roleText.data();
+ } else if (V_VT(&vRole) == VT_BSTR)
+ result = wstring(V_BSTR(&vRole), ::SysStringLen(V_BSTR(&vRole)));
+
+ ::VariantClear(&vRole);
+
+ return JSStringCreateWithCharacters(result.data(), result.length());
}
JSStringRef AccessibilityUIElement::subrole()
@@ -162,6 +176,11 @@ JSStringRef AccessibilityUIElement::subrole()
return 0;
}
+JSStringRef AccessibilityUIElement::roleDescription()
+{
+ return 0;
+}
+
JSStringRef AccessibilityUIElement::title()
{
BSTR titleBSTR;
@@ -175,13 +194,18 @@ JSStringRef AccessibilityUIElement::title()
JSStringRef AccessibilityUIElement::description()
{
BSTR descriptionBSTR;
- if (FAILED(m_element->get_accName(self(), &descriptionBSTR)) || !descriptionBSTR)
+ if (FAILED(m_element->get_accDescription(self(), &descriptionBSTR)) || !descriptionBSTR)
return JSStringCreateWithCharacters(0, 0);
wstring description(descriptionBSTR, SysStringLen(descriptionBSTR));
::SysFreeString(descriptionBSTR);
return JSStringCreateWithCharacters(description.data(), description.length());
}
+JSStringRef AccessibilityUIElement::stringValue()
+{
+ return JSStringCreateWithCharacters(0, 0);
+}
+
JSStringRef AccessibilityUIElement::language()
{
return JSStringCreateWithCharacters(0, 0);
@@ -233,6 +257,35 @@ JSStringRef AccessibilityUIElement::valueDescription()
{
return 0;
}
+bool AccessibilityUIElement::isSelected() const
+{
+ return false;
+}
+
+int AccessibilityUIElement::hierarchicalLevel() const
+{
+ return 0;
+}
+
+bool AccessibilityUIElement::ariaIsGrabbed() const
+{
+ return false;
+}
+
+JSStringRef AccessibilityUIElement::ariaDropEffects() const
+{
+ return 0;
+}
+
+bool AccessibilityUIElement::isExpanded() const
+{
+ return false;
+}
+
+JSStringRef AccessibilityUIElement::orientation() const
+{
+ return 0;
+}
double AccessibilityUIElement::intValue()
{
@@ -270,6 +323,7 @@ bool AccessibilityUIElement::isRequired() const
return false;
}
+
int AccessibilityUIElement::insertionPointLineNumber()
{
return 0;
@@ -359,6 +413,11 @@ bool AccessibilityUIElement::isAttributeSettable(JSStringRef attribute)
return false;
}
+bool AccessibilityUIElement::isAttributeSupported(JSStringRef attribute)
+{
+ return false;
+}
+
void AccessibilityUIElement::increment()
{
}
@@ -366,3 +425,55 @@ void AccessibilityUIElement::increment()
void AccessibilityUIElement::decrement()
{
}
+
+void AccessibilityUIElement::showMenu()
+{
+}
+
+AccessibilityUIElement AccessibilityUIElement::disclosedRowAtIndex(unsigned index)
+{
+ return 0;
+}
+
+AccessibilityUIElement AccessibilityUIElement::ariaOwnsElementAtIndex(unsigned index)
+{
+ return 0;
+}
+
+AccessibilityUIElement AccessibilityUIElement::ariaFlowToElementAtIndex(unsigned index)
+{
+ return 0;
+}
+
+AccessibilityUIElement AccessibilityUIElement::selectedRowAtIndex(unsigned index)
+{
+ return 0;
+}
+
+AccessibilityUIElement AccessibilityUIElement::disclosedByRow()
+{
+ return 0;
+}
+
+JSStringRef AccessibilityUIElement::accessibilityValue() const
+{
+ BSTR valueBSTR;
+ if (FAILED(m_element->get_accValue(self(), &valueBSTR)) || !valueBSTR)
+ return JSStringCreateWithCharacters(0, 0);
+
+ wstring value(valueBSTR, SysStringLen(valueBSTR));
+ ::SysFreeString(valueBSTR);
+
+ return JSStringCreateWithCharacters(value.data(), value.length());
+}
+
+
+JSStringRef AccessibilityUIElement::documentEncoding()
+{
+ return JSStringCreateWithCharacters(0, 0);
+}
+
+JSStringRef AccessibilityUIElement::documentURI()
+{
+ return JSStringCreateWithCharacters(0, 0);
+}
diff --git a/WebKitTools/DumpRenderTree/win/DRTDesktopNotificationPresenter.cpp b/WebKitTools/DumpRenderTree/win/DRTDesktopNotificationPresenter.cpp
index b18b724..1bc4678 100644
--- a/WebKitTools/DumpRenderTree/win/DRTDesktopNotificationPresenter.cpp
+++ b/WebKitTools/DumpRenderTree/win/DRTDesktopNotificationPresenter.cpp
@@ -28,6 +28,7 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+#include "config.h"
#include "DRTDesktopNotificationPresenter.h"
#include "DumpRenderTree.h"
diff --git a/WebKitTools/DumpRenderTree/win/DumpRenderTree.cpp b/WebKitTools/DumpRenderTree/win/DumpRenderTree.cpp
index d486d06..1315f9e 100644
--- a/WebKitTools/DumpRenderTree/win/DumpRenderTree.cpp
+++ b/WebKitTools/DumpRenderTree/win/DumpRenderTree.cpp
@@ -66,7 +66,7 @@
using namespace std;
-#ifndef NDEBUG
+#if !defined(NDEBUG) && (!defined(DEBUG_INTERNAL) || defined(DEBUG_ALL))
const LPWSTR TestPluginDir = L"TestNetscapePlugin_Debug";
#else
const LPWSTR TestPluginDir = L"TestNetscapePlugin";
@@ -201,6 +201,43 @@ static const wstring& fontsPath()
return path;
}
+static void addQTDirToPATH()
+{
+ static LPCWSTR pathEnvironmentVariable = L"PATH";
+ static LPCWSTR quickTimeKeyName = L"Software\\Apple Computer, Inc.\\QuickTime";
+ static LPCWSTR quickTimeSysDir = L"QTSysDir";
+ static bool initialized;
+
+ if (initialized)
+ return;
+ initialized = true;
+
+ // Get the QuickTime dll directory from the registry. The key can be in either HKLM or HKCU.
+ WCHAR qtPath[MAX_PATH];
+ DWORD qtPathBufferLen = sizeof(qtPath);
+ DWORD keyType;
+ HRESULT result = SHGetValue(HKEY_LOCAL_MACHINE, quickTimeKeyName, quickTimeSysDir, &keyType, (LPVOID)qtPath, &qtPathBufferLen);
+ if (result != ERROR_SUCCESS || !qtPathBufferLen || keyType != REG_SZ) {
+ qtPathBufferLen = sizeof(qtPath);
+ result = SHGetValue(HKEY_CURRENT_USER, quickTimeKeyName, quickTimeSysDir, &keyType, (LPVOID)qtPath, &qtPathBufferLen);
+ if (result != ERROR_SUCCESS || !qtPathBufferLen || keyType != REG_SZ)
+ return;
+ }
+
+ // Read the current PATH.
+ DWORD pathSize = GetEnvironmentVariableW(pathEnvironmentVariable, 0, 0);
+ Vector<WCHAR> oldPath(pathSize);
+ if (!GetEnvironmentVariableW(pathEnvironmentVariable, oldPath.data(), oldPath.size()))
+ return;
+
+ // And add the QuickTime dll.
+ wstring newPath;
+ newPath.append(qtPath);
+ newPath.append(L";");
+ newPath.append(oldPath.data(), oldPath.size());
+ SetEnvironmentVariableW(pathEnvironmentVariable, newPath.data());
+}
+
#ifdef DEBUG_ALL
#define WEBKITDLL TEXT("WebKit_debug.dll")
#else
@@ -263,6 +300,10 @@ static void initialize()
for (int i = 0; i < ARRAYSIZE(fontsToInstall); ++i)
textRenderer->registerPrivateFont(wstring(resourcesPath + fontsToInstall[i]).c_str());
+ // Add the QuickTime dll directory to PATH or QT 7.6 will fail to initialize on systems
+ // linked with older versions of qtmlclientlib.dll.
+ addQTDirToPATH();
+
// Register a host window
WNDCLASSEX wcex;
@@ -286,7 +327,7 @@ static void initialize()
void displayWebView()
{
::InvalidateRect(webViewWindow, 0, TRUE);
- ::UpdateWindow(webViewWindow);
+ ::SendMessage(webViewWindow, WM_PAINT, 0, 0);
}
void dumpFrameScrollPosition(IWebFrame* frame)
@@ -688,6 +729,11 @@ static bool shouldLogHistoryDelegates(const char* pathOrURL)
return strstr(pathOrURL, "/globalhistory/") || strstr(pathOrURL, "\\globalhistory\\");
}
+static bool shouldOpenWebInspector(const char* pathOrURL)
+{
+ return strstr(pathOrURL, "/inspector/") || strstr(pathOrURL, "\\inspector\\");
+}
+
static void resetDefaultsToConsistentValues(IWebPreferences* preferences)
{
#ifdef USE_MAC_FONTS
@@ -793,6 +839,12 @@ static void resetWebViewToConsistentStateBeforeTesting()
webViewPrivate->clearMainFrameName();
webViewPrivate->resetOriginAccessWhiteLists();
+ BSTR groupName;
+ if (SUCCEEDED(webView->groupName(&groupName))) {
+ webViewPrivate->removeAllUserContentFromGroup(groupName);
+ SysFreeString(groupName);
+ }
+
sharedUIDelegate->resetUndoManager();
sharedFrameLoadDelegate->resetToConsistentState();
@@ -859,6 +911,9 @@ static void runTest(const string& testPathOrURL)
resetWebViewToConsistentStateBeforeTesting();
+ if (shouldOpenWebInspector(pathOrURL.c_str()))
+ gLayoutTestController->showWebInspector();
+
prevTestBFItem = 0;
if (webView) {
COMPtr<IWebBackForwardList> bfList;
@@ -893,6 +948,9 @@ static void runTest(const string& testPathOrURL)
DispatchMessage(&msg);
}
+ if (shouldOpenWebInspector(pathOrURL.c_str()))
+ gLayoutTestController->closeWebInspector();
+
resetWebViewToConsistentStateBeforeTesting();
frame->stopLoading();
diff --git a/WebKitTools/DumpRenderTree/win/DumpRenderTree.vcproj b/WebKitTools/DumpRenderTree/win/DumpRenderTree.vcproj
index ba3640c..299c53c 100644
--- a/WebKitTools/DumpRenderTree/win/DumpRenderTree.vcproj
+++ b/WebKitTools/DumpRenderTree/win/DumpRenderTree.vcproj
@@ -84,7 +84,7 @@
/>
<Tool
Name="VCPostBuildEventTool"
- CommandLine="if exist &quot;$(WebKitOutputDir)\buildfailed&quot; del &quot;$(WebKitOutputDir)\buildfailed&quot;&#x0D;&#x0A;&#x0D;&#x0A;if not defined ARCHIVE_BUILD (if defined PRODUCTION exit /b)&#x0D;&#x0A;&#x0D;&#x0A;mkdir 2&gt;NUL &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;&#x0D;&#x0A;if not exist &quot;$(WebKitLibrariesDir)\bin\CoreFoundation$(LibraryConfigSuffix).dll&quot; exit /b&#x0D;&#x0A;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\CoreFoundation$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\CoreFoundation$(LibraryConfigSuffix).pdb&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\CFNetwork$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\CFNetwork$(LibraryConfigSuffix).pdb&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d /e /i &quot;$(WebKitLibrariesDir)\bin\CFNetwork.resources&quot; &quot;$(WebKitOutputDir)\bin\CFNetwork.resources&quot;&#x0D;&#x0A;xcopy /y /d /e /i &quot;$(WebKitLibrariesDir)\bin\CoreFoundation.resources&quot; &quot;$(WebKitOutputDir)\bin\CoreFoundation.resources&quot;&#x0D;&#x0A;xcopy /y /d /e /i &quot;$(WebKitLibrariesDir)\bin\CharacterSets&quot; &quot;$(WebKitOutputDir)\bin\CharacterSets&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\CoreGraphics$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\CoreGraphics$(LibraryConfigSuffix).pdb&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\dnssd.dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\icudt40.dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\icudt40$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\icuin40$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\icuin40$(LibraryConfigSuffix).pdb&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\icuuc40$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\icuuc40$(LibraryConfigSuffix).pdb&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\libxml2$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\libxslt$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\pthreadVC2$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\pthreadVC2$(LibraryConfigSuffix).pdb&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\SQLite3$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\SQLite3$(LibraryConfigSuffix).pdb&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\zlib1$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\zlib1$(LibraryConfigSuffix).pdb&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;"
+ CommandLine="if exist &quot;$(WebKitOutputDir)\buildfailed&quot; del &quot;$(WebKitOutputDir)\buildfailed&quot;&#x0D;&#x0A;&#x0D;&#x0A;if not defined ARCHIVE_BUILD (if defined PRODUCTION exit /b)&#x0D;&#x0A;&#x0D;&#x0A;mkdir 2&gt;NUL &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;&#x0D;&#x0A;if not exist &quot;$(WebKitLibrariesDir)\bin\CoreFoundation$(LibraryConfigSuffix).dll&quot; exit /b&#x0D;&#x0A;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\CoreFoundation$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\CoreFoundation$(LibraryConfigSuffix).pdb&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\CFNetwork$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\CFNetwork$(LibraryConfigSuffix).pdb&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d /e /i &quot;$(WebKitLibrariesDir)\bin\CFNetwork.resources&quot; &quot;$(WebKitOutputDir)\bin\CFNetwork.resources&quot;&#x0D;&#x0A;xcopy /y /d /e /i &quot;$(WebKitLibrariesDir)\bin\CoreFoundation.resources&quot; &quot;$(WebKitOutputDir)\bin\CoreFoundation.resources&quot;&#x0D;&#x0A;xcopy /y /d /e /i &quot;$(WebKitLibrariesDir)\bin\CharacterSets&quot; &quot;$(WebKitOutputDir)\bin\CharacterSets&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\CoreGraphics$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\CoreGraphics$(LibraryConfigSuffix).pdb&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\dnssd.dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;if exist &quot;$(WebKitLibrariesDir)\bin\icudt40.dll&quot; xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\icudt40.dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;if exist &quot;$(WebKitLibrariesDir)\bin\icudt40$(LibraryConfigSuffix).dll&quot;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\icudt40$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;if exist &quot;$(WebKitLibrariesDir)\bin\icuin40$(LibraryConfigSuffix).dll&quot;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\icuin40$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;if exist &quot;$(WebKitLibrariesDir)\bin\icuin40$(LibraryConfigSuffix).pdb&quot;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\icuin40$(LibraryConfigSuffix).pdb&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;if exist &quot;$(WebKitLibrariesDir)\bin\icuuc40$(LibraryConfigSuffix).dll&quot;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\icuuc40$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;if exist &quot;$(WebKitLibrariesDir)\bin\icuuc40$(LibraryConfigSuffix).pdb&quot;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\icuuc40$(LibraryConfigSuffix).pdb&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;if exist &quot;$(WebKitLibrariesDir)\bin\icudt42.dll&quot; xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\icudt42.dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;if exist &quot;$(WebKitLibrariesDir)\bin\icudt42$(LibraryConfigSuffix).dll&quot;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\icudt42$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;if exist &quot;$(WebKitLibrariesDir)\bin\icuin42$(LibraryConfigSuffix).dll&quot;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\icuin42$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;if exist &quot;$(WebKitLibrariesDir)\bin\icuin42$(LibraryConfigSuffix).pdb&quot;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\icuin42$(LibraryConfigSuffix).pdb&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;if exist &quot;$(WebKitLibrariesDir)\bin\icuuc42$(LibraryConfigSuffix).dll&quot;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\icuuc42$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;if exist &quot;$(WebKitLibrariesDir)\bin\icuuc42$(LibraryConfigSuffix).pdb&quot;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\icuuc42$(LibraryConfigSuffix).pdb&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\libxml2$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\libxslt$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\pthreadVC2$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\pthreadVC2$(LibraryConfigSuffix).pdb&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\SQLite3$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\SQLite3$(LibraryConfigSuffix).pdb&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\zlib1$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\zlib1$(LibraryConfigSuffix).pdb&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;"
/>
</Configuration>
<Configuration
@@ -157,7 +157,7 @@
/>
<Tool
Name="VCPostBuildEventTool"
- CommandLine="if exist &quot;$(WebKitOutputDir)\buildfailed&quot; del &quot;$(WebKitOutputDir)\buildfailed&quot;&#x0D;&#x0A;&#x0D;&#x0A;if not defined ARCHIVE_BUILD (if defined PRODUCTION exit /b)&#x0D;&#x0A;&#x0D;&#x0A;mkdir 2&gt;NUL &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;&#x0D;&#x0A;if not exist &quot;$(WebKitLibrariesDir)\bin\CoreFoundation$(LibraryConfigSuffix).dll&quot; exit /b&#x0D;&#x0A;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\CoreFoundation$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\CoreFoundation$(LibraryConfigSuffix).pdb&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\CFNetwork$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\CFNetwork$(LibraryConfigSuffix).pdb&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d /e /i &quot;$(WebKitLibrariesDir)\bin\CFNetwork.resources&quot; &quot;$(WebKitOutputDir)\bin\CFNetwork.resources&quot;&#x0D;&#x0A;xcopy /y /d /e /i &quot;$(WebKitLibrariesDir)\bin\CoreFoundation.resources&quot; &quot;$(WebKitOutputDir)\bin\CoreFoundation.resources&quot;&#x0D;&#x0A;xcopy /y /d /e /i &quot;$(WebKitLibrariesDir)\bin\CharacterSets&quot; &quot;$(WebKitOutputDir)\bin\CharacterSets&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\CoreGraphics$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\CoreGraphics$(LibraryConfigSuffix).pdb&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\dnssd.dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\icudt40.dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\icudt40$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\icuin40$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\icuin40$(LibraryConfigSuffix).pdb&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\icuuc40$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\icuuc40$(LibraryConfigSuffix).pdb&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\libxml2$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\libxslt$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\pthreadVC2$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\pthreadVC2$(LibraryConfigSuffix).pdb&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\SQLite3$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\SQLite3$(LibraryConfigSuffix).pdb&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\zlib1$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\zlib1$(LibraryConfigSuffix).pdb&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;"
+ CommandLine="if exist &quot;$(WebKitOutputDir)\buildfailed&quot; del &quot;$(WebKitOutputDir)\buildfailed&quot;&#x0D;&#x0A;&#x0D;&#x0A;if not defined ARCHIVE_BUILD (if defined PRODUCTION exit /b)&#x0D;&#x0A;&#x0D;&#x0A;mkdir 2&gt;NUL &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;&#x0D;&#x0A;if not exist &quot;$(WebKitLibrariesDir)\bin\CoreFoundation$(LibraryConfigSuffix).dll&quot; exit /b&#x0D;&#x0A;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\CoreFoundation$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\CoreFoundation$(LibraryConfigSuffix).pdb&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\CFNetwork$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\CFNetwork$(LibraryConfigSuffix).pdb&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d /e /i &quot;$(WebKitLibrariesDir)\bin\CFNetwork.resources&quot; &quot;$(WebKitOutputDir)\bin\CFNetwork.resources&quot;&#x0D;&#x0A;xcopy /y /d /e /i &quot;$(WebKitLibrariesDir)\bin\CoreFoundation.resources&quot; &quot;$(WebKitOutputDir)\bin\CoreFoundation.resources&quot;&#x0D;&#x0A;xcopy /y /d /e /i &quot;$(WebKitLibrariesDir)\bin\CharacterSets&quot; &quot;$(WebKitOutputDir)\bin\CharacterSets&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\CoreGraphics$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\CoreGraphics$(LibraryConfigSuffix).pdb&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\dnssd.dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;if exist &quot;$(WebKitLibrariesDir)\bin\icudt40.dll&quot; xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\icudt40.dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;if exist &quot;$(WebKitLibrariesDir)\bin\icudt40$(LibraryConfigSuffix).dll&quot;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\icudt40$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;if exist &quot;$(WebKitLibrariesDir)\bin\icuin40$(LibraryConfigSuffix).dll&quot;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\icuin40$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;if exist &quot;$(WebKitLibrariesDir)\bin\icuin40$(LibraryConfigSuffix).pdb&quot;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\icuin40$(LibraryConfigSuffix).pdb&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;if exist &quot;$(WebKitLibrariesDir)\bin\icuuc40$(LibraryConfigSuffix).dll&quot;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\icuuc40$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;if exist &quot;$(WebKitLibrariesDir)\bin\icuuc40$(LibraryConfigSuffix).pdb&quot;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\icuuc40$(LibraryConfigSuffix).pdb&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;if exist &quot;$(WebKitLibrariesDir)\bin\icudt42.dll&quot; xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\icudt42.dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;if exist &quot;$(WebKitLibrariesDir)\bin\icudt42$(LibraryConfigSuffix).dll&quot;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\icudt42$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;if exist &quot;$(WebKitLibrariesDir)\bin\icuin42$(LibraryConfigSuffix).dll&quot;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\icuin42$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;if exist &quot;$(WebKitLibrariesDir)\bin\icuin42$(LibraryConfigSuffix).pdb&quot;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\icuin42$(LibraryConfigSuffix).pdb&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;if exist &quot;$(WebKitLibrariesDir)\bin\icuuc42$(LibraryConfigSuffix).dll&quot;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\icuuc42$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;if exist &quot;$(WebKitLibrariesDir)\bin\icuuc42$(LibraryConfigSuffix).pdb&quot;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\icuuc42$(LibraryConfigSuffix).pdb&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\libxml2$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\libxslt$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\pthreadVC2$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\pthreadVC2$(LibraryConfigSuffix).pdb&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\SQLite3$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\SQLite3$(LibraryConfigSuffix).pdb&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\zlib1$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\zlib1$(LibraryConfigSuffix).pdb&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;"
/>
</Configuration>
<Configuration
@@ -228,7 +228,7 @@
/>
<Tool
Name="VCPostBuildEventTool"
- CommandLine="if exist &quot;$(WebKitOutputDir)\buildfailed&quot; del &quot;$(WebKitOutputDir)\buildfailed&quot;&#x0D;&#x0A;&#x0D;&#x0A;if not defined ARCHIVE_BUILD (if defined PRODUCTION exit /b)&#x0D;&#x0A;&#x0D;&#x0A;mkdir 2&gt;NUL &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;&#x0D;&#x0A;if not exist &quot;$(WebKitLibrariesDir)\bin\CoreFoundation$(LibraryConfigSuffix).dll&quot; exit /b&#x0D;&#x0A;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\CoreFoundation$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\CoreFoundation$(LibraryConfigSuffix).pdb&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\CFNetwork$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\CFNetwork$(LibraryConfigSuffix).pdb&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d /e /i &quot;$(WebKitLibrariesDir)\bin\CFNetwork.resources&quot; &quot;$(WebKitOutputDir)\bin\CFNetwork.resources&quot;&#x0D;&#x0A;xcopy /y /d /e /i &quot;$(WebKitLibrariesDir)\bin\CoreFoundation.resources&quot; &quot;$(WebKitOutputDir)\bin\CoreFoundation.resources&quot;&#x0D;&#x0A;xcopy /y /d /e /i &quot;$(WebKitLibrariesDir)\bin\CharacterSets&quot; &quot;$(WebKitOutputDir)\bin\CharacterSets&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\CoreGraphics$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\CoreGraphics$(LibraryConfigSuffix).pdb&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\dnssd.dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\icudt40.dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\icudt40$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\icuin40$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\icuin40$(LibraryConfigSuffix).pdb&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\icuuc40$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\icuuc40$(LibraryConfigSuffix).pdb&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\libxml2$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\libxslt$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\pthreadVC2$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\pthreadVC2$(LibraryConfigSuffix).pdb&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\SQLite3$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\SQLite3$(LibraryConfigSuffix).pdb&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\zlib1$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\zlib1$(LibraryConfigSuffix).pdb&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;"
+ CommandLine="if exist &quot;$(WebKitOutputDir)\buildfailed&quot; del &quot;$(WebKitOutputDir)\buildfailed&quot;&#x0D;&#x0A;&#x0D;&#x0A;if not defined ARCHIVE_BUILD (if defined PRODUCTION exit /b)&#x0D;&#x0A;&#x0D;&#x0A;mkdir 2&gt;NUL &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;&#x0D;&#x0A;if not exist &quot;$(WebKitLibrariesDir)\bin\CoreFoundation$(LibraryConfigSuffix).dll&quot; exit /b&#x0D;&#x0A;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\CoreFoundation$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\CoreFoundation$(LibraryConfigSuffix).pdb&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\CFNetwork$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\CFNetwork$(LibraryConfigSuffix).pdb&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d /e /i &quot;$(WebKitLibrariesDir)\bin\CFNetwork.resources&quot; &quot;$(WebKitOutputDir)\bin\CFNetwork.resources&quot;&#x0D;&#x0A;xcopy /y /d /e /i &quot;$(WebKitLibrariesDir)\bin\CoreFoundation.resources&quot; &quot;$(WebKitOutputDir)\bin\CoreFoundation.resources&quot;&#x0D;&#x0A;xcopy /y /d /e /i &quot;$(WebKitLibrariesDir)\bin\CharacterSets&quot; &quot;$(WebKitOutputDir)\bin\CharacterSets&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\CoreGraphics$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\CoreGraphics$(LibraryConfigSuffix).pdb&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\dnssd.dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;if exist &quot;$(WebKitLibrariesDir)\bin\icudt40.dll&quot; xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\icudt40.dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;if exist &quot;$(WebKitLibrariesDir)\bin\icudt40$(LibraryConfigSuffix).dll&quot;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\icudt40$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;if exist &quot;$(WebKitLibrariesDir)\bin\icuin40$(LibraryConfigSuffix).dll&quot;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\icuin40$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;if exist &quot;$(WebKitLibrariesDir)\bin\icuin40$(LibraryConfigSuffix).pdb&quot;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\icuin40$(LibraryConfigSuffix).pdb&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;if exist &quot;$(WebKitLibrariesDir)\bin\icuuc40$(LibraryConfigSuffix).dll&quot;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\icuuc40$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;if exist &quot;$(WebKitLibrariesDir)\bin\icuuc40$(LibraryConfigSuffix).pdb&quot;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\icuuc40$(LibraryConfigSuffix).pdb&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;if exist &quot;$(WebKitLibrariesDir)\bin\icudt42.dll&quot; xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\icudt42.dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;if exist &quot;$(WebKitLibrariesDir)\bin\icudt42$(LibraryConfigSuffix).dll&quot;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\icudt42$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;if exist &quot;$(WebKitLibrariesDir)\bin\icuin42$(LibraryConfigSuffix).dll&quot;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\icuin42$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;if exist &quot;$(WebKitLibrariesDir)\bin\icuin42$(LibraryConfigSuffix).pdb&quot;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\icuin42$(LibraryConfigSuffix).pdb&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;if exist &quot;$(WebKitLibrariesDir)\bin\icuuc42$(LibraryConfigSuffix).dll&quot;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\icuuc42$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;if exist &quot;$(WebKitLibrariesDir)\bin\icuuc42$(LibraryConfigSuffix).pdb&quot;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\icuuc42$(LibraryConfigSuffix).pdb&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\libxml2$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\libxslt$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\pthreadVC2$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\pthreadVC2$(LibraryConfigSuffix).pdb&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\SQLite3$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\SQLite3$(LibraryConfigSuffix).pdb&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\zlib1$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\zlib1$(LibraryConfigSuffix).pdb&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;"
/>
</Configuration>
<Configuration
@@ -300,7 +300,7 @@
/>
<Tool
Name="VCPostBuildEventTool"
- CommandLine="if exist &quot;$(WebKitOutputDir)\buildfailed&quot; del &quot;$(WebKitOutputDir)\buildfailed&quot;&#x0D;&#x0A;&#x0D;&#x0A;if not defined ARCHIVE_BUILD (if defined PRODUCTION exit /b)&#x0D;&#x0A;&#x0D;&#x0A;mkdir 2&gt;NUL &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;&#x0D;&#x0A;if not exist &quot;$(WebKitLibrariesDir)\bin\CoreFoundation$(LibraryConfigSuffix).dll&quot; exit /b&#x0D;&#x0A;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\CoreFoundation$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\CoreFoundation$(LibraryConfigSuffix).pdb&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\CFNetwork$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\CFNetwork$(LibraryConfigSuffix).pdb&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d /e /i &quot;$(WebKitLibrariesDir)\bin\CFNetwork.resources&quot; &quot;$(WebKitOutputDir)\bin\CFNetwork.resources&quot;&#x0D;&#x0A;xcopy /y /d /e /i &quot;$(WebKitLibrariesDir)\bin\CoreFoundation.resources&quot; &quot;$(WebKitOutputDir)\bin\CoreFoundation.resources&quot;&#x0D;&#x0A;xcopy /y /d /e /i &quot;$(WebKitLibrariesDir)\bin\CharacterSets&quot; &quot;$(WebKitOutputDir)\bin\CharacterSets&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\CoreGraphics$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\CoreGraphics$(LibraryConfigSuffix).pdb&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\dnssd.dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\icudt40.dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\icudt40$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\icuin40$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\icuin40$(LibraryConfigSuffix).pdb&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\icuuc40$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\icuuc40$(LibraryConfigSuffix).pdb&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\libxml2$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\libxslt$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\pthreadVC2$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\pthreadVC2$(LibraryConfigSuffix).pdb&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\SQLite3$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\SQLite3$(LibraryConfigSuffix).pdb&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\zlib1$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\zlib1$(LibraryConfigSuffix).pdb&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;"
+ CommandLine="if exist &quot;$(WebKitOutputDir)\buildfailed&quot; del &quot;$(WebKitOutputDir)\buildfailed&quot;&#x0D;&#x0A;&#x0D;&#x0A;if not defined ARCHIVE_BUILD (if defined PRODUCTION exit /b)&#x0D;&#x0A;&#x0D;&#x0A;mkdir 2&gt;NUL &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;&#x0D;&#x0A;if not exist &quot;$(WebKitLibrariesDir)\bin\CoreFoundation$(LibraryConfigSuffix).dll&quot; exit /b&#x0D;&#x0A;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\CoreFoundation$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\CoreFoundation$(LibraryConfigSuffix).pdb&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\CFNetwork$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\CFNetwork$(LibraryConfigSuffix).pdb&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d /e /i &quot;$(WebKitLibrariesDir)\bin\CFNetwork.resources&quot; &quot;$(WebKitOutputDir)\bin\CFNetwork.resources&quot;&#x0D;&#x0A;xcopy /y /d /e /i &quot;$(WebKitLibrariesDir)\bin\CoreFoundation.resources&quot; &quot;$(WebKitOutputDir)\bin\CoreFoundation.resources&quot;&#x0D;&#x0A;xcopy /y /d /e /i &quot;$(WebKitLibrariesDir)\bin\CharacterSets&quot; &quot;$(WebKitOutputDir)\bin\CharacterSets&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\CoreGraphics$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\CoreGraphics$(LibraryConfigSuffix).pdb&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\dnssd.dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;if exist &quot;$(WebKitLibrariesDir)\bin\icudt40.dll&quot; xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\icudt40.dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;if exist &quot;$(WebKitLibrariesDir)\bin\icudt40$(LibraryConfigSuffix).dll&quot;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\icudt40$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;if exist &quot;$(WebKitLibrariesDir)\bin\icuin40$(LibraryConfigSuffix).dll&quot;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\icuin40$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;if exist &quot;$(WebKitLibrariesDir)\bin\icuin40$(LibraryConfigSuffix).pdb&quot;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\icuin40$(LibraryConfigSuffix).pdb&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;if exist &quot;$(WebKitLibrariesDir)\bin\icuuc40$(LibraryConfigSuffix).dll&quot;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\icuuc40$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;if exist &quot;$(WebKitLibrariesDir)\bin\icuuc40$(LibraryConfigSuffix).pdb&quot;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\icuuc40$(LibraryConfigSuffix).pdb&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;if exist &quot;$(WebKitLibrariesDir)\bin\icudt42.dll&quot; xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\icudt42.dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;if exist &quot;$(WebKitLibrariesDir)\bin\icudt42$(LibraryConfigSuffix).dll&quot;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\icudt42$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;if exist &quot;$(WebKitLibrariesDir)\bin\icuin42$(LibraryConfigSuffix).dll&quot;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\icuin42$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;if exist &quot;$(WebKitLibrariesDir)\bin\icuin42$(LibraryConfigSuffix).pdb&quot;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\icuin42$(LibraryConfigSuffix).pdb&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;if exist &quot;$(WebKitLibrariesDir)\bin\icuuc42$(LibraryConfigSuffix).dll&quot;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\icuuc42$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;if exist &quot;$(WebKitLibrariesDir)\bin\icuuc42$(LibraryConfigSuffix).pdb&quot;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\icuuc42$(LibraryConfigSuffix).pdb&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\libxml2$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\libxslt$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\pthreadVC2$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\pthreadVC2$(LibraryConfigSuffix).pdb&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\SQLite3$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\SQLite3$(LibraryConfigSuffix).pdb&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\zlib1$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\zlib1$(LibraryConfigSuffix).pdb&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;"
/>
</Configuration>
<Configuration
@@ -373,7 +373,7 @@
/>
<Tool
Name="VCPostBuildEventTool"
- CommandLine="if exist &quot;$(WebKitOutputDir)\buildfailed&quot; del &quot;$(WebKitOutputDir)\buildfailed&quot;&#x0D;&#x0A;&#x0D;&#x0A;if not defined ARCHIVE_BUILD (if defined PRODUCTION exit /b)&#x0D;&#x0A;&#x0D;&#x0A;mkdir 2&gt;NUL &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;&#x0D;&#x0A;if not exist &quot;$(WebKitLibrariesDir)\bin\CoreFoundation$(LibraryConfigSuffix).dll&quot; exit /b&#x0D;&#x0A;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\CoreFoundation$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\CoreFoundation$(LibraryConfigSuffix).pdb&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\CFNetwork$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\CFNetwork$(LibraryConfigSuffix).pdb&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d /e /i &quot;$(WebKitLibrariesDir)\bin\CFNetwork.resources&quot; &quot;$(WebKitOutputDir)\bin\CFNetwork.resources&quot;&#x0D;&#x0A;xcopy /y /d /e /i &quot;$(WebKitLibrariesDir)\bin\CoreFoundation.resources&quot; &quot;$(WebKitOutputDir)\bin\CoreFoundation.resources&quot;&#x0D;&#x0A;xcopy /y /d /e /i &quot;$(WebKitLibrariesDir)\bin\CharacterSets&quot; &quot;$(WebKitOutputDir)\bin\CharacterSets&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\CoreGraphics$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\CoreGraphics$(LibraryConfigSuffix).pdb&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\dnssd.dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\icudt40.dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\icudt40$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\icuin40$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\icuin40$(LibraryConfigSuffix).pdb&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\icuuc40$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\icuuc40$(LibraryConfigSuffix).pdb&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\libxml2$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\libxslt$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\pthreadVC2$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\pthreadVC2$(LibraryConfigSuffix).pdb&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\SQLite3$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\SQLite3$(LibraryConfigSuffix).pdb&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\zlib1$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\zlib1$(LibraryConfigSuffix).pdb&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;"
+ CommandLine="if exist &quot;$(WebKitOutputDir)\buildfailed&quot; del &quot;$(WebKitOutputDir)\buildfailed&quot;&#x0D;&#x0A;&#x0D;&#x0A;if not defined ARCHIVE_BUILD (if defined PRODUCTION exit /b)&#x0D;&#x0A;&#x0D;&#x0A;mkdir 2&gt;NUL &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;&#x0D;&#x0A;if not exist &quot;$(WebKitLibrariesDir)\bin\CoreFoundation$(LibraryConfigSuffix).dll&quot; exit /b&#x0D;&#x0A;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\CoreFoundation$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\CoreFoundation$(LibraryConfigSuffix).pdb&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\CFNetwork$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\CFNetwork$(LibraryConfigSuffix).pdb&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d /e /i &quot;$(WebKitLibrariesDir)\bin\CFNetwork.resources&quot; &quot;$(WebKitOutputDir)\bin\CFNetwork.resources&quot;&#x0D;&#x0A;xcopy /y /d /e /i &quot;$(WebKitLibrariesDir)\bin\CoreFoundation.resources&quot; &quot;$(WebKitOutputDir)\bin\CoreFoundation.resources&quot;&#x0D;&#x0A;xcopy /y /d /e /i &quot;$(WebKitLibrariesDir)\bin\CharacterSets&quot; &quot;$(WebKitOutputDir)\bin\CharacterSets&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\CoreGraphics$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\CoreGraphics$(LibraryConfigSuffix).pdb&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\dnssd.dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;if exist &quot;$(WebKitLibrariesDir)\bin\icudt40.dll&quot; xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\icudt40.dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;if exist &quot;$(WebKitLibrariesDir)\bin\icudt40$(LibraryConfigSuffix).dll&quot;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\icudt40$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;if exist &quot;$(WebKitLibrariesDir)\bin\icuin40$(LibraryConfigSuffix).dll&quot;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\icuin40$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;if exist &quot;$(WebKitLibrariesDir)\bin\icuin40$(LibraryConfigSuffix).pdb&quot;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\icuin40$(LibraryConfigSuffix).pdb&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;if exist &quot;$(WebKitLibrariesDir)\bin\icuuc40$(LibraryConfigSuffix).dll&quot;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\icuuc40$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;if exist &quot;$(WebKitLibrariesDir)\bin\icuuc40$(LibraryConfigSuffix).pdb&quot;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\icuuc40$(LibraryConfigSuffix).pdb&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;if exist &quot;$(WebKitLibrariesDir)\bin\icudt42.dll&quot; xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\icudt42.dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;if exist &quot;$(WebKitLibrariesDir)\bin\icudt42$(LibraryConfigSuffix).dll&quot;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\icudt42$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;if exist &quot;$(WebKitLibrariesDir)\bin\icuin42$(LibraryConfigSuffix).dll&quot;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\icuin42$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;if exist &quot;$(WebKitLibrariesDir)\bin\icuin42$(LibraryConfigSuffix).pdb&quot;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\icuin42$(LibraryConfigSuffix).pdb&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;if exist &quot;$(WebKitLibrariesDir)\bin\icuuc42$(LibraryConfigSuffix).dll&quot;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\icuuc42$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;if exist &quot;$(WebKitLibrariesDir)\bin\icuuc42$(LibraryConfigSuffix).pdb&quot;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\icuuc42$(LibraryConfigSuffix).pdb&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\libxml2$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\libxslt$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\pthreadVC2$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\pthreadVC2$(LibraryConfigSuffix).pdb&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\SQLite3$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\SQLite3$(LibraryConfigSuffix).pdb&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\zlib1$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\zlib1$(LibraryConfigSuffix).pdb&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;"
/>
</Configuration>
<Configuration
@@ -444,7 +444,7 @@
/>
<Tool
Name="VCPostBuildEventTool"
- CommandLine="if exist &quot;$(WebKitOutputDir)\buildfailed&quot; del &quot;$(WebKitOutputDir)\buildfailed&quot;&#x0D;&#x0A;&#x0D;&#x0A;if not defined ARCHIVE_BUILD (if defined PRODUCTION exit /b)&#x0D;&#x0A;&#x0D;&#x0A;mkdir 2&gt;NUL &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;&#x0D;&#x0A;if not exist &quot;$(WebKitLibrariesDir)\bin\CoreFoundation$(LibraryConfigSuffix).dll&quot; exit /b&#x0D;&#x0A;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\CoreFoundation$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\CoreFoundation$(LibraryConfigSuffix).pdb&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\CFNetwork$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\CFNetwork$(LibraryConfigSuffix).pdb&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d /e /i &quot;$(WebKitLibrariesDir)\bin\CFNetwork.resources&quot; &quot;$(WebKitOutputDir)\bin\CFNetwork.resources&quot;&#x0D;&#x0A;xcopy /y /d /e /i &quot;$(WebKitLibrariesDir)\bin\CoreFoundation.resources&quot; &quot;$(WebKitOutputDir)\bin\CoreFoundation.resources&quot;&#x0D;&#x0A;xcopy /y /d /e /i &quot;$(WebKitLibrariesDir)\bin\CharacterSets&quot; &quot;$(WebKitOutputDir)\bin\CharacterSets&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\CoreGraphics$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\CoreGraphics$(LibraryConfigSuffix).pdb&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\dnssd.dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\icudt40.dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\icudt40$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\icuin40$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\icuin40$(LibraryConfigSuffix).pdb&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\icuuc40$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\icuuc40$(LibraryConfigSuffix).pdb&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\libxml2$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\libxslt$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\pthreadVC2$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\pthreadVC2$(LibraryConfigSuffix).pdb&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\SQLite3$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\SQLite3$(LibraryConfigSuffix).pdb&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\zlib1$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\zlib1$(LibraryConfigSuffix).pdb&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;"
+ CommandLine="if exist &quot;$(WebKitOutputDir)\buildfailed&quot; del &quot;$(WebKitOutputDir)\buildfailed&quot;&#x0D;&#x0A;&#x0D;&#x0A;if not defined ARCHIVE_BUILD (if defined PRODUCTION exit /b)&#x0D;&#x0A;&#x0D;&#x0A;mkdir 2&gt;NUL &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;&#x0D;&#x0A;if not exist &quot;$(WebKitLibrariesDir)\bin\CoreFoundation$(LibraryConfigSuffix).dll&quot; exit /b&#x0D;&#x0A;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\CoreFoundation$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\CoreFoundation$(LibraryConfigSuffix).pdb&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\CFNetwork$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\CFNetwork$(LibraryConfigSuffix).pdb&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d /e /i &quot;$(WebKitLibrariesDir)\bin\CFNetwork.resources&quot; &quot;$(WebKitOutputDir)\bin\CFNetwork.resources&quot;&#x0D;&#x0A;xcopy /y /d /e /i &quot;$(WebKitLibrariesDir)\bin\CoreFoundation.resources&quot; &quot;$(WebKitOutputDir)\bin\CoreFoundation.resources&quot;&#x0D;&#x0A;xcopy /y /d /e /i &quot;$(WebKitLibrariesDir)\bin\CharacterSets&quot; &quot;$(WebKitOutputDir)\bin\CharacterSets&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\CoreGraphics$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\CoreGraphics$(LibraryConfigSuffix).pdb&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\dnssd.dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;if exist &quot;$(WebKitLibrariesDir)\bin\icudt40.dll&quot; xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\icudt40.dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;if exist &quot;$(WebKitLibrariesDir)\bin\icudt40$(LibraryConfigSuffix).dll&quot;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\icudt40$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;if exist &quot;$(WebKitLibrariesDir)\bin\icuin40$(LibraryConfigSuffix).dll&quot;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\icuin40$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;if exist &quot;$(WebKitLibrariesDir)\bin\icuin40$(LibraryConfigSuffix).pdb&quot;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\icuin40$(LibraryConfigSuffix).pdb&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;if exist &quot;$(WebKitLibrariesDir)\bin\icuuc40$(LibraryConfigSuffix).dll&quot;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\icuuc40$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;if exist &quot;$(WebKitLibrariesDir)\bin\icuuc40$(LibraryConfigSuffix).pdb&quot;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\icuuc40$(LibraryConfigSuffix).pdb&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;if exist &quot;$(WebKitLibrariesDir)\bin\icudt42.dll&quot; xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\icudt42.dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;if exist &quot;$(WebKitLibrariesDir)\bin\icudt42$(LibraryConfigSuffix).dll&quot;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\icudt42$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;if exist &quot;$(WebKitLibrariesDir)\bin\icuin42$(LibraryConfigSuffix).dll&quot;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\icuin42$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;if exist &quot;$(WebKitLibrariesDir)\bin\icuin42$(LibraryConfigSuffix).pdb&quot;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\icuin42$(LibraryConfigSuffix).pdb&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;if exist &quot;$(WebKitLibrariesDir)\bin\icuuc42$(LibraryConfigSuffix).dll&quot;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\icuuc42$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;if exist &quot;$(WebKitLibrariesDir)\bin\icuuc42$(LibraryConfigSuffix).pdb&quot;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\icuuc42$(LibraryConfigSuffix).pdb&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\libxml2$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\libxslt$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\pthreadVC2$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\pthreadVC2$(LibraryConfigSuffix).pdb&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\SQLite3$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\SQLite3$(LibraryConfigSuffix).pdb&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\zlib1$(LibraryConfigSuffix).dll&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;xcopy /y /d &quot;$(WebKitLibrariesDir)\bin\zlib1$(LibraryConfigSuffix).pdb&quot; &quot;$(WebKitOutputDir)\bin&quot;&#x0D;&#x0A;"
/>
</Configuration>
</Configurations>
diff --git a/WebKitTools/DumpRenderTree/win/DumpRenderTreeWin.h b/WebKitTools/DumpRenderTree/win/DumpRenderTreeWin.h
index 6eb468d..54ec87b 100644
--- a/WebKitTools/DumpRenderTree/win/DumpRenderTreeWin.h
+++ b/WebKitTools/DumpRenderTree/win/DumpRenderTreeWin.h
@@ -30,6 +30,7 @@
#define DumpRenderTreeWin_h
struct IWebFrame;
+struct IWebScriptWorld;
struct IWebView;
struct PolicyDelegate;
typedef const struct __CFString* CFStringRef;
@@ -55,6 +56,8 @@ WindowToWebViewMap& windowToWebViewMap();
void setPersistentUserStyleSheetLocation(CFStringRef);
bool setAlwaysAcceptCookies(bool alwaysAcceptCookies);
+unsigned worldIDForWorld(IWebScriptWorld*);
+
extern UINT_PTR waitToDumpWatchdog;
#endif // DumpRenderTreeWin_h
diff --git a/WebKitTools/DumpRenderTree/win/FrameLoadDelegate.cpp b/WebKitTools/DumpRenderTree/win/FrameLoadDelegate.cpp
index 939090a..37d5e1c 100644
--- a/WebKitTools/DumpRenderTree/win/FrameLoadDelegate.cpp
+++ b/WebKitTools/DumpRenderTree/win/FrameLoadDelegate.cpp
@@ -289,12 +289,53 @@ HRESULT STDMETHODCALLTYPE FrameLoadDelegate::willCloseFrame(
return E_NOTIMPL;
}
-HRESULT STDMETHODCALLTYPE FrameLoadDelegate::didClearWindowObject(
- /* [in] */ IWebView*webView,
- /* [in] */ JSContextRef context,
- /* [in] */ JSObjectRef windowObject,
- /* [in] */ IWebFrame* frame)
+HRESULT FrameLoadDelegate::didClearWindowObject(IWebView*, JSContextRef, JSObjectRef, IWebFrame*)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT FrameLoadDelegate::didClearWindowObjectForFrameInScriptWorld(IWebView* webView, IWebFrame* frame, IWebScriptWorld* world)
+{
+ ASSERT_ARG(webView, webView);
+ ASSERT_ARG(frame, frame);
+ ASSERT_ARG(world, world);
+ if (!webView || !frame || !world)
+ return E_POINTER;
+
+ COMPtr<IWebScriptWorld> standardWorld;
+ if (FAILED(world->standardWorld(&standardWorld)))
+ return S_OK;
+
+ if (world == standardWorld)
+ didClearWindowObjectForFrameInStandardWorld(frame);
+ else
+ didClearWindowObjectForFrameInIsolatedWorld(frame, world);
+ return S_OK;
+}
+
+void FrameLoadDelegate::didClearWindowObjectForFrameInIsolatedWorld(IWebFrame* frame, IWebScriptWorld* world)
+{
+ COMPtr<IWebFramePrivate> framePrivate(Query, frame);
+ if (!framePrivate)
+ return;
+
+ JSGlobalContextRef ctx = framePrivate->globalContextForScriptWorld(world);
+ if (!ctx)
+ return;
+
+ JSObjectRef globalObject = JSContextGetGlobalObject(ctx);
+ if (!globalObject)
+ return;
+
+ JSObjectSetProperty(ctx, globalObject, JSRetainPtr<JSStringRef>(Adopt, JSStringCreateWithUTF8CString("__worldID")).get(), JSValueMakeNumber(ctx, worldIDForWorld(world)), kJSPropertyAttributeReadOnly, 0);
+ return;
+}
+
+void FrameLoadDelegate::didClearWindowObjectForFrameInStandardWorld(IWebFrame* frame)
{
+ JSGlobalContextRef context = frame->globalContext();
+ JSObjectRef windowObject = JSContextGetGlobalObject(context);
+
JSValueRef exception = 0;
::gLayoutTestController->makeWindowObject(context, windowObject, &exception);
@@ -310,8 +351,6 @@ HRESULT STDMETHODCALLTYPE FrameLoadDelegate::didClearWindowObject(
JSValueRef eventSender = makeEventSender(context);
JSObjectSetProperty(context, windowObject, eventSenderStr, eventSender, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete, 0);
JSStringRelease(eventSenderStr);
-
- return S_OK;
}
HRESULT STDMETHODCALLTYPE FrameLoadDelegate::didFinishDocumentLoadForFrame(
diff --git a/WebKitTools/DumpRenderTree/win/FrameLoadDelegate.h b/WebKitTools/DumpRenderTree/win/FrameLoadDelegate.h
index 56325e2..cc6653b 100644
--- a/WebKitTools/DumpRenderTree/win/FrameLoadDelegate.h
+++ b/WebKitTools/DumpRenderTree/win/FrameLoadDelegate.h
@@ -141,7 +141,24 @@ public:
/* [in] */ IWebView *sender,
/* [in] */ IWebSecurityOrigin *origin);
-protected:
+ virtual HRESULT STDMETHODCALLTYPE didClearWindowObjectForFrameInScriptWorld(IWebView*, IWebFrame*, IWebScriptWorld*);
+
+ virtual HRESULT STDMETHODCALLTYPE didPushStateWithinPageForFrame(
+ /* [in] */ IWebView *sender,
+ /* [in] */ IWebFrame *frame) { return E_NOTIMPL; }
+
+ virtual HRESULT STDMETHODCALLTYPE didReplaceStateWithinPageForFrame(
+ /* [in] */ IWebView *sender,
+ /* [in] */ IWebFrame *frame) { return E_NOTIMPL; }
+
+ virtual HRESULT STDMETHODCALLTYPE didPopStateWithinPageForFrame(
+ /* [in] */ IWebView *sender,
+ /* [in] */ IWebFrame *frame) { return E_NOTIMPL; }
+
+private:
+ void didClearWindowObjectForFrameInIsolatedWorld(IWebFrame*, IWebScriptWorld*);
+ void didClearWindowObjectForFrameInStandardWorld(IWebFrame*);
+
void locationChangeDone(IWebError*, IWebFrame*);
ULONG m_refCount;
diff --git a/WebKitTools/DumpRenderTree/win/LayoutTestControllerWin.cpp b/WebKitTools/DumpRenderTree/win/LayoutTestControllerWin.cpp
index d3cac7a..5debf16 100644
--- a/WebKitTools/DumpRenderTree/win/LayoutTestControllerWin.cpp
+++ b/WebKitTools/DumpRenderTree/win/LayoutTestControllerWin.cpp
@@ -372,6 +372,23 @@ void LayoutTestController::setXSSAuditorEnabled(bool enabled)
prefsPrivate->setXSSAuditorEnabled(enabled);
}
+void LayoutTestController::setAllowUniversalAccessFromFileURLs(bool enabled)
+{
+ COMPtr<IWebView> webView;
+ if (FAILED(frame->webView(&webView)))
+ return;
+
+ COMPtr<IWebPreferences> preferences;
+ if (FAILED(webView->preferences(&preferences)))
+ return;
+
+ COMPtr<IWebPreferencesPrivate> prefsPrivate(Query, preferences);
+ if (!prefsPrivate)
+ return;
+
+ prefsPrivate->setAllowUniversalAccessFromFileURLs(enabled);
+}
+
void LayoutTestController::setPopupBlockingEnabled(bool enabled)
{
COMPtr<IWebView> webView;
@@ -398,6 +415,23 @@ void LayoutTestController::setTabKeyCyclesThroughElements(bool shouldCycle)
viewPrivate->setTabKeyCyclesThroughElements(shouldCycle ? TRUE : FALSE);
}
+void LayoutTestController::setTimelineProfilingEnabled(bool flag)
+{
+ COMPtr<IWebView> webView;
+ if (FAILED(frame->webView(&webView)))
+ return;
+
+ COMPtr<IWebViewPrivate> viewPrivate;
+ if (FAILED(webView->QueryInterface(&viewPrivate)))
+ return;
+
+ COMPtr<IWebInspector> inspector;
+ if (FAILED(viewPrivate->inspector(&inspector)))
+ return;
+
+ inspector->setTimelineProfilingEnabled(flag);
+}
+
void LayoutTestController::setUseDashboardCompatibilityMode(bool flag)
{
// FIXME: Implement!
@@ -827,6 +861,31 @@ bool LayoutTestController::pauseTransitionAtTimeOnElementWithId(JSStringRef prop
return SUCCEEDED(hr) && wasRunning;
}
+bool LayoutTestController::sampleSVGAnimationForElementAtTime(JSStringRef animationId, double time, JSStringRef elementId)
+{
+ COMPtr<IDOMDocument> document;
+ if (FAILED(frame->DOMDocument(&document)))
+ return false;
+
+ BSTR idBSTR = JSStringCopyBSTR(animationId);
+ COMPtr<IDOMElement> element;
+ HRESULT hr = document->getElementById(idBSTR, &element);
+ SysFreeString(idBSTR);
+ if (FAILED(hr))
+ return false;
+
+ COMPtr<IWebFramePrivate> framePrivate(Query, frame);
+ if (!framePrivate)
+ return false;
+
+ BSTR elementIdBSTR = JSStringCopyBSTR(elementId);
+ BOOL wasRunning = FALSE;
+ hr = framePrivate->pauseSVGAnimation(elementIdBSTR, element.get(), time, &wasRunning);
+ SysFreeString(elementIdBSTR);
+
+ return SUCCEEDED(hr) && wasRunning;
+}
+
unsigned LayoutTestController::numberOfActiveAnimations() const
{
COMPtr<IWebFramePrivate> framePrivate(Query, frame);
@@ -861,7 +920,11 @@ void LayoutTestController::addUserScript(JSStringRef source, bool runAtStart)
if (FAILED(WebKitCreateInstance(__uuidof(WebView), 0, __uuidof(webView), reinterpret_cast<void**>(&webView))))
return;
- webView->addUserScriptToGroup(_bstr_t(L"org.webkit.DumpRenderTree").GetBSTR(), 1, bstrT(source).GetBSTR(), 0, 0, 0, 0, 0, runAtStart ? WebInjectAtDocumentStart : WebInjectAtDocumentEnd);
+ COMPtr<IWebScriptWorld> world;
+ if (FAILED(WebKitCreateInstance(__uuidof(WebScriptWorld), 0, __uuidof(world), reinterpret_cast<void**>(&world))))
+ return;
+
+ webView->addUserScriptToGroup(_bstr_t(L"org.webkit.DumpRenderTree").GetBSTR(), world.get(), bstrT(source).GetBSTR(), 0, 0, 0, 0, 0, runAtStart ? WebInjectAtDocumentStart : WebInjectAtDocumentEnd);
}
@@ -871,7 +934,11 @@ void LayoutTestController::addUserStyleSheet(JSStringRef source)
if (FAILED(WebKitCreateInstance(__uuidof(WebView), 0, __uuidof(webView), reinterpret_cast<void**>(&webView))))
return;
- webView->addUserStyleSheetToGroup(_bstr_t(L"org.webkit.DumpRenderTree").GetBSTR(), 1, bstrT(source).GetBSTR(), 0, 0, 0, 0, 0);
+ COMPtr<IWebScriptWorld> world;
+ if (FAILED(WebKitCreateInstance(__uuidof(WebScriptWorld), 0, __uuidof(world), reinterpret_cast<void**>(&world))))
+ return;
+
+ webView->addUserStyleSheetToGroup(_bstr_t(L"org.webkit.DumpRenderTree").GetBSTR(), world.get(), bstrT(source).GetBSTR(), 0, 0, 0, 0, 0);
}
void LayoutTestController::showWebInspector()
@@ -947,14 +1014,45 @@ void LayoutTestController::evaluateInWebInspector(long callId, JSStringRef scrip
inspectorPrivate->evaluateInFrontend(callId, bstrT(script).GetBSTR());
}
-void LayoutTestController::evaluateScriptInIsolatedWorld(unsigned worldId, JSObjectRef globalObject, JSStringRef script)
+typedef HashMap<unsigned, COMPtr<IWebScriptWorld> > WorldMap;
+static WorldMap& worldMap()
+{
+ static WorldMap& map = *new WorldMap;
+ return map;
+}
+
+unsigned worldIDForWorld(IWebScriptWorld* world)
+{
+ WorldMap::const_iterator end = worldMap().end();
+ for (WorldMap::const_iterator it = worldMap().begin(); it != end; ++it) {
+ if (it->second == world)
+ return it->first;
+ }
+
+ return 0;
+}
+
+void LayoutTestController::evaluateScriptInIsolatedWorld(unsigned worldID, JSObjectRef globalObject, JSStringRef script)
{
COMPtr<IWebFramePrivate> framePrivate(Query, frame);
if (!framePrivate)
return;
+ // A worldID of 0 always corresponds to a new world. Any other worldID corresponds to a world
+ // that is created once and cached forever.
+ COMPtr<IWebScriptWorld> world;
+ if (!worldID) {
+ if (FAILED(WebKitCreateInstance(__uuidof(WebScriptWorld), 0, __uuidof(world), reinterpret_cast<void**>(&world))))
+ return;
+ } else {
+ COMPtr<IWebScriptWorld>& worldSlot = worldMap().add(worldID, 0).first->second;
+ if (!worldSlot && FAILED(WebKitCreateInstance(__uuidof(WebScriptWorld), 0, __uuidof(worldSlot), reinterpret_cast<void**>(&worldSlot))))
+ return;
+ world = worldSlot;
+ }
+
BSTR result;
- if (FAILED(framePrivate->stringByEvaluatingJavaScriptInIsolatedWorld(worldId, reinterpret_cast<OLE_HANDLE>(globalObject), bstrT(script).GetBSTR(), &result)))
+ if (FAILED(framePrivate->stringByEvaluatingJavaScriptInScriptWorld(world.get(), globalObject, bstrT(script).GetBSTR(), &result)))
return;
SysFreeString(result);
}
diff --git a/WebKitTools/DumpRenderTree/win/TestNetscapePlugin/main.cpp b/WebKitTools/DumpRenderTree/win/TestNetscapePlugin/main.cpp
index 7175d33..82b1d4d 100644
--- a/WebKitTools/DumpRenderTree/win/TestNetscapePlugin/main.cpp
+++ b/WebKitTools/DumpRenderTree/win/TestNetscapePlugin/main.cpp
@@ -88,12 +88,15 @@ NPError NPP_New(NPMIMEType pluginType, NPP instance, uint16 mode, int16 argc, ch
for (int i = 0; i < argc; i++)
if (_stricmp(argn[i], "src") == 0)
pluginLog(instance, "src: %s", argv[i]);
- }
+ } else if (_stricmp(argn[i], "testdocumentopenindestroystream") == 0)
+ obj->testDocumentOpenInDestroyStream = TRUE;
+ else if (_stricmp(argn[i], "testwindowopen") == 0)
+ obj->testWindowOpen = TRUE;
}
instance->pdata = obj;
}
-
+
return NPERR_NO_ERROR;
}
@@ -120,6 +123,15 @@ NPError NPP_Destroy(NPP instance, NPSavedData **save)
NPError NPP_SetWindow(NPP instance, NPWindow *window)
{
+ PluginObject* obj = static_cast<PluginObject*>(instance->pdata);
+
+ if (obj) {
+ if (obj->testWindowOpen) {
+ testWindowOpen(instance);
+ obj->testWindowOpen = FALSE;
+ }
+ }
+
return NPERR_NO_ERROR;
}
@@ -149,7 +161,7 @@ NPError NPP_NewStream(NPP instance, NPMIMEType type, NPStream *stream, NPBool se
if (obj->onStreamLoad)
executeScript(obj, obj->onStreamLoad);
-
+
return NPERR_NO_ERROR;
}
@@ -160,6 +172,10 @@ NPError NPP_DestroyStream(NPP instance, NPStream *stream, NPReason reason)
if (obj->onStreamDestroy)
executeScript(obj, obj->onStreamDestroy);
+ if (obj->testDocumentOpenInDestroyStream) {
+ testDocumentOpen(instance);
+ }
+
return NPERR_NO_ERROR;
}
diff --git a/WebKitTools/DumpRenderTree/wscript b/WebKitTools/DumpRenderTree/wscript
new file mode 100644
index 0000000..29eca9a
--- /dev/null
+++ b/WebKitTools/DumpRenderTree/wscript
@@ -0,0 +1,64 @@
+#! /usr/bin/env python
+
+# Copyright (C) 2009 Kevin Ollivier 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.
+#
+# 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.
+#
+# wxBrowser sample app build script for the waf build system
+
+import sys
+
+from settings import *
+
+include_paths = [
+ os.path.join(output_dir),
+ os.path.join(wk_root, 'JavaScriptCore'),
+ os.path.join(wk_root, 'WebCore'),
+ os.path.join(wk_root, 'WebKit', 'wx'),
+ '.',
+ 'wx'
+ ]
+sources = [
+ 'LayoutTestController.cpp',
+ 'WorkQueue.cpp',
+ 'wx/DumpRenderTreeWx.cpp',
+ 'wx/LayoutTestControllerWx.cpp',
+ 'wx/WorkQueueItemWx.cpp'
+ ]
+
+def set_options(opt):
+ common_set_options(opt)
+
+def configure(conf):
+ common_configure(conf)
+
+def build(bld):
+ obj = bld.new_task_gen(
+ features = 'cxx cprogram',
+ includes = ' '.join(include_paths),
+ source = sources,
+ target = 'DumpRenderTree',
+ uselib = 'WXWEBKIT WX ' + get_config(),
+ libpath = [output_dir],
+ uselib_local = '',
+ install_path = output_dir)
+
diff --git a/WebKitTools/DumpRenderTree/wx/LayoutTestControllerWx.cpp b/WebKitTools/DumpRenderTree/wx/LayoutTestControllerWx.cpp
index 72f85ae..2c46950 100644
--- a/WebKitTools/DumpRenderTree/wx/LayoutTestControllerWx.cpp
+++ b/WebKitTools/DumpRenderTree/wx/LayoutTestControllerWx.cpp
@@ -170,6 +170,11 @@ void LayoutTestController::setXSSAuditorEnabled(bool enabled)
// FIXME: implement
}
+void LayoutTestController::setAllowUniversalAccessFromFileURLs(bool enabled)
+{
+ // FIXME: implement
+}
+
void LayoutTestController::setAuthorAndUserStylesEnabled(bool flag)
{
// FIXME: implement
@@ -262,6 +267,12 @@ bool LayoutTestController::pauseAnimationAtTimeOnElementWithId(JSStringRef anima
return false;
}
+bool LayoutTestController::sampleSVGAnimationForElementAtTime(JSStringRef animationId, double time, JSStringRef elementId)
+{
+ // FIXME: implement
+ return false;
+}
+
void LayoutTestController::setCacheModel(int)
{
// FIXME: implement
@@ -318,3 +329,28 @@ void LayoutTestController::removeAllVisitedLinks()
{
// FIXME: Implement this.
}
+
+void LayoutTestController::setTimelineProfilingEnabled(bool enabled)
+{
+
+}
+
+void LayoutTestController::evaluateScriptInIsolatedWorld(unsigned worldId, JSObjectRef globalObject, JSStringRef script)
+{
+
+}
+
+void LayoutTestController::disableImageLoading()
+{
+
+}
+
+void LayoutTestController::whiteListAccessFromOrigin(JSStringRef sourceOrigin, JSStringRef destinationProtocol, JSStringRef destinationHost, bool allowDestinationSubdomains)
+{
+
+}
+
+JSRetainPtr<JSStringRef> LayoutTestController::counterValueForElementById(JSStringRef id)
+{
+
+}
diff --git a/WebKitTools/GNUmakefile.am b/WebKitTools/GNUmakefile.am
index c2029f3..4425196 100644
--- a/WebKitTools/GNUmakefile.am
+++ b/WebKitTools/GNUmakefile.am
@@ -113,7 +113,7 @@ dumprendertree_cppflags += \
TestNetscapePlugin_libtestnetscapeplugin_la_CPPFLAGS = \
-I$(srcdir)/WebKitTools/DumpRenderTree \
- -I$(srcdir)/WebKitTools/DumpRenderTree/gtk/TestNetscapePlugin/ForwardingHeaders \
+ -I$(srcdir)/WebKitTools/DumpRenderTree/unix/TestNetscapePlugin/ForwardingHeaders \
-I$(srcdir)/WebCore \
-I$(srcdir)/WebCore/bridge \
-I$(srcdir)/WebCore/plugins \
@@ -122,17 +122,17 @@ TestNetscapePlugin_libtestnetscapeplugin_la_CPPFLAGS = \
$(javascriptcore_cppflags)
TestNetscapePlugin_libtestnetscapeplugin_la_SOURCES = \
- WebKitTools/DumpRenderTree/gtk/TestNetscapePlugin/ForwardingHeaders/WebKit/npapi.h \
- WebKitTools/DumpRenderTree/gtk/TestNetscapePlugin/ForwardingHeaders/WebKit/npfunctions.h \
- WebKitTools/DumpRenderTree/gtk/TestNetscapePlugin/ForwardingHeaders/WebKit/npruntime.h \
- WebKitTools/DumpRenderTree/gtk/TestNetscapePlugin/TestNetscapePlugin.cpp \
+ WebKitTools/DumpRenderTree/unix/TestNetscapePlugin/ForwardingHeaders/WebKit/npapi.h \
+ WebKitTools/DumpRenderTree/unix/TestNetscapePlugin/ForwardingHeaders/WebKit/npfunctions.h \
+ WebKitTools/DumpRenderTree/unix/TestNetscapePlugin/ForwardingHeaders/WebKit/npruntime.h \
+ WebKitTools/DumpRenderTree/unix/TestNetscapePlugin/TestNetscapePlugin.cpp \
WebKitTools/DumpRenderTree/TestNetscapePlugIn.subproj/PluginObject.cpp \
WebKitTools/DumpRenderTree/TestNetscapePlugIn.subproj/PluginObject.h \
WebKitTools/DumpRenderTree/TestNetscapePlugIn.subproj/TestObject.cpp \
WebKitTools/DumpRenderTree/TestNetscapePlugIn.subproj/TestObject.h
TestNetscapePlugin_libtestnetscapeplugin_la_LDFLAGS = \
- -rpath ${shell pwd}/$(top_builddir)/TestNetscapePlugin/.libs \
+ -rpath ${shell pwd}/$(top_builddir)/../unix/TestNetscapePlugin/.libs \
$(no_undefined) \
-avoid-version \
-module
diff --git a/WebKitTools/CommitQueueStatus/app.yaml b/WebKitTools/QueueStatusServer/app.yaml
index 2756112..2756112 100644
--- a/WebKitTools/CommitQueueStatus/app.yaml
+++ b/WebKitTools/QueueStatusServer/app.yaml
diff --git a/WebKitTools/CommitQueueStatus/filters/__init__.py b/WebKitTools/QueueStatusServer/filters/__init__.py
index ef65bee..ef65bee 100644
--- a/WebKitTools/CommitQueueStatus/filters/__init__.py
+++ b/WebKitTools/QueueStatusServer/filters/__init__.py
diff --git a/WebKitTools/CommitQueueStatus/filters/webkit_extras.py b/WebKitTools/QueueStatusServer/filters/webkit_extras.py
index 6a08727..6a08727 100644
--- a/WebKitTools/CommitQueueStatus/filters/webkit_extras.py
+++ b/WebKitTools/QueueStatusServer/filters/webkit_extras.py
diff --git a/WebKitTools/CommitQueueStatus/index.html b/WebKitTools/QueueStatusServer/index.html
index 2b5aced..fbd51fb 100644
--- a/WebKitTools/CommitQueueStatus/index.html
+++ b/WebKitTools/QueueStatusServer/index.html
@@ -1,3 +1,4 @@
+<!DOCTYPE html>
<html>
<head>
<title>WebKit Commit Queue Status</title>
diff --git a/WebKitTools/CommitQueueStatus/index.yaml b/WebKitTools/QueueStatusServer/index.yaml
index a3b9e05..bf11262 100644
--- a/WebKitTools/CommitQueueStatus/index.yaml
+++ b/WebKitTools/QueueStatusServer/index.yaml
@@ -9,3 +9,16 @@ indexes:
# manually, move them above the marker line. The index.yaml file is
# automatically uploaded to the admin console when you next deploy
# your application using appcfg.py.
+
+- kind: QueueStatus
+ properties:
+ - name: active_patch_id
+ - name: queue_name
+ - name: date
+ direction: desc
+
+- kind: QueueStatus
+ properties:
+ - name: queue_name
+ - name: date
+ direction: desc
diff --git a/WebKitTools/CommitQueueStatus/queue_status.py b/WebKitTools/QueueStatusServer/queue_status.py
index 30d2494..65197bb 100644
--- a/WebKitTools/CommitQueueStatus/queue_status.py
+++ b/WebKitTools/QueueStatusServer/queue_status.py
@@ -35,29 +35,91 @@ use_library('django', '1.1')
from google.appengine.ext.webapp import template
from google.appengine.api import users
-from google.appengine.ext import webapp
+from google.appengine.ext import webapp, db
from google.appengine.ext.webapp.util import run_wsgi_app
-from google.appengine.ext import db
webapp.template.register_template_library('filters.webkit_extras')
+
class QueueStatus(db.Model):
author = db.UserProperty()
+ queue_name = db.StringProperty()
active_bug_id = db.IntegerProperty()
active_patch_id = db.IntegerProperty()
message = db.StringProperty(multiline=True)
date = db.DateTimeProperty(auto_now_add=True)
+ results_file = db.BlobProperty()
+
class MainPage(webapp.RequestHandler):
def get(self):
- statuses_query = QueueStatus.all().order('-date')
+ statuses_query = QueueStatus.all().filter('queue_name =', 'commit-queue').order('-date')
statuses = statuses_query.fetch(6)
+ if not statuses:
+ return self.response.out.write("No status to report.")
template_values = {
'last_status' : statuses[0],
'recent_statuses' : statuses[1:],
}
self.response.out.write(template.render('index.html', template_values))
+
+class PatchStatus(webapp.RequestHandler):
+ def get(self, queue_name, attachment_id):
+ statuses = QueueStatus.all().filter('queue_name =', queue_name).filter('active_patch_id =', int(attachment_id)).order('-date').fetch(1)
+ if not statuses:
+ self.error(404)
+ return
+ self.response.out.write(statuses[0].message)
+
+
+class StatusSummary(object):
+ def _status_to_code(self, status):
+ code_names = {
+ "Pass": "pass",
+ "Pending": "pending",
+ "Fail": "fail",
+ "Error": "error",
+ }
+ return code_names.get(status, "none")
+
+ def _queue_name_to_code(self, queue_name):
+ code_names = {
+ "style-queue": "style",
+ }
+ return code_names[queue_name]
+
+ queues = [
+ "style-queue",
+ ]
+
+ def __init__(self):
+ self._summary = {}
+
+ def summarize(self, attachment_id):
+ if self._summary.get(attachment_id):
+ return self._summary.get(attachment_id)
+
+ attachment_summary = {}
+ for queue in self.queues:
+ statuses = QueueStatus.all().filter('queue_name =', queue).filter('active_patch_id =', attachment_id).order('-date').fetch(1)
+ status_code = self._status_to_code(statuses[0].message if statuses else None)
+ queue_code = self._queue_name_to_code(queue)
+ attachment_summary[queue_code] = status_code
+
+ self._summary[attachment_id] = attachment_summary
+ return attachment_summary
+
+
+class StatusBubble(webapp.RequestHandler):
+ def get(self, attachment_id):
+ status_summary = StatusSummary()
+ template_values = {
+ "queue_status" : status_summary.summarize(int(attachment_id)),
+ }
+ self.response.out.write(template.render('status_bubble.html', template_values))
+
+
class UpdateStatus(webapp.RequestHandler):
def get(self):
self.response.out.write(template.render('update_status.html', None))
@@ -66,6 +128,7 @@ class UpdateStatus(webapp.RequestHandler):
string_value = self.request.get(name)
try:
int_value = int(string_value)
+ return int_value
except ValueError, TypeError:
pass
return None
@@ -76,15 +139,33 @@ class UpdateStatus(webapp.RequestHandler):
if users.get_current_user():
queue_status.author = users.get_current_user()
+ queue_name = self.request.get('queue_name')
+ queue_status.queue_name = queue_name
queue_status.active_bug_id = self._int_from_request('bug_id')
queue_status.active_patch_id = self._int_from_request('patch_id')
queue_status.message = self.request.get('status')
+ results_file = self.request.get("results_file")
+ queue_status.results_file = db.Blob(results_file)
queue_status.put()
self.redirect('/')
+
+class ShowResults(webapp.RequestHandler):
+ def get(self, status_id):
+ status = QueueStatus.get_by_id(int(status_id))
+ if not status:
+ self.error(404)
+ return
+ self.response.headers["Content-Type"] = "text/plain"
+ self.response.out.write(status.results_file)
+
+
routes = [
('/', MainPage),
- ('/update_status', UpdateStatus)
+ ('/update-status', UpdateStatus),
+ (r'/patch-status/(.*)/(.*)', PatchStatus),
+ (r'/status-bubble/(.*)', StatusBubble),
+ (r'/results/(.*)', ShowResults)
]
application = webapp.WSGIApplication(routes, debug=True)
diff --git a/WebKitTools/QueueStatusServer/status_bubble.html b/WebKitTools/QueueStatusServer/status_bubble.html
new file mode 100644
index 0000000..f8959d9
--- /dev/null
+++ b/WebKitTools/QueueStatusServer/status_bubble.html
@@ -0,0 +1,36 @@
+<!DOCTYPE html>
+<html>
+<head>
+<style>
+body {
+ font-family: Verdana, sans-serif;
+ margin: 0px;
+ padding: 0px;
+}
+.status {
+ display: block;
+ float: left;
+ margin: 1px;
+ padding: 1px 2px;
+ border-radius: 5px;
+ border: 1px solid #AAA;
+ font-size: 11px;
+}
+.pass {
+ background-color: #8FDF5F;
+ border: 1px solid #4F8530;
+}
+.fail {
+ background-color: #E98080;
+ border: 1px solid #A77272;
+}
+.pending {
+ background-color: #FFFC6C;
+ border: 1px solid #C5C56D;
+}
+</style>
+</head>
+<body>{% for key, value in queue_status.items %}
+<div class="status {{value}}" title="{{key}}: {{value}}">{{key}}</div>{% endfor %}
+</body>
+</html>
diff --git a/WebKitTools/CommitQueueStatus/stylesheets/main.css b/WebKitTools/QueueStatusServer/stylesheets/main.css
index 55d3694..55d3694 100644
--- a/WebKitTools/CommitQueueStatus/stylesheets/main.css
+++ b/WebKitTools/QueueStatusServer/stylesheets/main.css
diff --git a/WebKitTools/CommitQueueStatus/update_status.html b/WebKitTools/QueueStatusServer/update_status.html
index edafba4..9343c60 100644
--- a/WebKitTools/CommitQueueStatus/update_status.html
+++ b/WebKitTools/QueueStatusServer/update_status.html
@@ -1,5 +1,5 @@
-Update the current status of the commit-queue:
-<form name="update_status" method="post">
+<form name="update_status" enctype="multipart/form-data" method="post">
+Update status for a queue: <input name="queue_name">
<div>
Active Bug Id:
<input name="bug_id">
@@ -8,12 +8,10 @@ Update the current status of the commit-queue:
Active Patch Id:
<input name="patch_id">
</div>
- <div>
- Space separated list of other bugs in queue:
- <input name="bugs_in_queue">
- </div>
<div>
+ Status Text:<br>
<textarea name="status" rows="3" cols="60"></textarea>
</div>
+ <div>Results file: <input type="file" name="results_file"></div>
<div><input type="submit" value="Add Status"></div>
</form>
diff --git a/WebKitTools/Scripts/VCSUtils.pm b/WebKitTools/Scripts/VCSUtils.pm
index e1e0bc2..7638102 100644
--- a/WebKitTools/Scripts/VCSUtils.pm
+++ b/WebKitTools/Scripts/VCSUtils.pm
@@ -41,7 +41,10 @@ BEGIN {
@ISA = qw(Exporter);
@EXPORT = qw(
&canonicalizePath
+ &changeLogEmailAddress
+ &changeLogName
&chdirReturningRelativePath
+ &decodeGitBinaryPatch
&determineSVNRoot
&determineVCSRoot
&fixChangeLogPatch
@@ -298,6 +301,14 @@ sub canonicalizePath($)
return ($#dirs >= 0) ? File::Spec->catdir(@dirs) : ".";
}
+sub removeEOL($)
+{
+ my ($line) = @_;
+
+ $line =~ s/[\r\n]+$//g;
+ return $line;
+}
+
sub svnStatus($)
{
my ($fullPath) = @_;
@@ -335,8 +346,6 @@ 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/(.+)#) {
@@ -347,56 +356,215 @@ sub gitdiff2svndiff($)
return $_;
}
+# 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. Alter the 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.
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
+ my $patch = shift; # $patch will only contain patch fragments for ChangeLog.
+
+ $patch =~ /(\r?\n)/;
+ my $lineEnding = $1;
+ my @patchLines = split(/$lineEnding/, $patch);
+
+ # e.g. 2009-06-03 Eric Seidel <eric@webkit.org>
+ my $dateLineRegexpString = '^\+(\d{4}-\d{2}-\d{2})' # Consume the leading '+' and the date.
+ . '\s+(.+)\s+' # Consume the name.
+ . '<([^<>]+)>$'; # And finally the email address.
+
+ # Figure out where the patch contents start and stop.
+ my $patchHeaderIndex;
+ my $firstContentIndex;
+ my $trailingContextIndex;
+ my $dateIndex;
+ my $patchEndIndex = scalar(@patchLines);
+ for (my $index = 0; $index < @patchLines; ++$index) {
+ my $line = $patchLines[$index];
+ if ($line =~ /^\@\@ -\d+,\d+ \+\d+,\d+ \@\@$/) { # e.g. @@ -1,5 +1,18 @@
+ if ($patchHeaderIndex) {
+ $patchEndIndex = $index; # We only bother to fix up the first patch fragment.
+ last;
}
+ $patchHeaderIndex = $index;
}
- $newPatch .= $line . "\n";
+ $firstContentIndex = $index if ($patchHeaderIndex && !$firstContentIndex && $line =~ /^\+[^+]/); # Only match after finding patchHeaderIndex, otherwise we'd match "+++".
+ $dateIndex = $index if ($line =~ /$dateLineRegexpString/);
+ $trailingContextIndex = $index if ($firstContentIndex && !$trailingContextIndex && $line =~ /^ /);
}
+ my $contentLineCount = $trailingContextIndex - $firstContentIndex;
+ my $trailingContextLineCount = $patchEndIndex - $trailingContextIndex;
+
+ # If we didn't find a date line in the content then this is not a patch we should try and fix.
+ return $patch if (!$dateIndex);
+
+ # We only need to do anything if the date line is not the first content line.
+ return $patch if ($dateIndex == $firstContentIndex);
+
+ # Write the new patch.
+ my $totalNewContentLines = $contentLineCount + $trailingContextLineCount;
+ $patchLines[$patchHeaderIndex] = "@@ -1,$trailingContextLineCount +1,$totalNewContentLines @@"; # Write a new header.
+ my @repeatedLines = splice(@patchLines, $dateIndex, $trailingContextIndex - $dateIndex); # The date line and all the content after it that diff saw as repeated.
+ splice(@patchLines, $firstContentIndex, 0, @repeatedLines); # Move the repeated content to the top.
+ foreach my $line (@repeatedLines) {
+ $line =~ s/^\+/ /;
+ }
+ splice(@patchLines, $trailingContextIndex, $patchEndIndex, @repeatedLines); # Replace trailing context with the repeated content.
+ splice(@patchLines, $patchHeaderIndex + 1, $firstContentIndex - $patchHeaderIndex - 1); # Remove any leading context.
+
+ return join($lineEnding, @patchLines) . "\n"; # patch(1) expects an extra trailing newline.
+}
- return $newPatch;
+sub gitConfig($)
+{
+ return unless $isGit;
+
+ my ($config) = @_;
+
+ my $result = `git config $config`;
+ if (($? >> 8)) {
+ $result = `git repo-config $config`;
+ }
+ chomp $result;
+ return $result;
}
+sub changeLogNameError($)
+{
+ my ($message) = @_;
+ print STDERR "$message\nEither:\n";
+ print STDERR " set CHANGE_LOG_NAME in your environment\n";
+ print STDERR " OR pass --name= on the command line\n";
+ print STDERR " OR set REAL_NAME in your environment";
+ print STDERR " OR git users can set 'git config user.name'\n";
+ exit(1);
+}
+
+sub changeLogName()
+{
+ my $name = $ENV{CHANGE_LOG_NAME} || $ENV{REAL_NAME} || gitConfig("user.name") || (split /\s*,\s*/, (getpwuid $<)[6])[0];
+
+ changeLogNameError("Failed to determine ChangeLog name.") unless $name;
+ # getpwuid seems to always succeed on windows, returning the username instead of the full name. This check will catch that case.
+ changeLogNameError("'$name' does not contain a space! ChangeLogs should contain your full name.") unless ($name =~ /\w \w/);
+
+ return $name;
+}
+
+sub changeLogEmailAddressError($)
+{
+ my ($message) = @_;
+ print STDERR "$message\nEither:\n";
+ print STDERR " set CHANGE_LOG_EMAIL_ADDRESS in your environment\n";
+ print STDERR " OR pass --email= on the command line\n";
+ print STDERR " OR set EMAIL_ADDRESS in your environment\n";
+ print STDERR " OR git users can set 'git config user.email'\n";
+ exit(1);
+}
+
+sub changeLogEmailAddress()
+{
+ my $emailAddress = $ENV{CHANGE_LOG_EMAIL_ADDRESS} || $ENV{EMAIL_ADDRESS} || gitConfig("user.email");
+
+ changeLogEmailAddressError("Failed to determine email address for ChangeLog.") unless $emailAddress;
+ changeLogEmailAddressError("Email address '$emailAddress' does not contain '\@' and is likely invalid.") unless ($emailAddress =~ /\@/);
+
+ return $emailAddress;
+}
+
+# http://tools.ietf.org/html/rfc1924
+sub decodeBase85($)
+{
+ my ($encoded) = @_;
+ my %table;
+ my @characters = ('0'..'9', 'A'..'Z', 'a'..'z', '!', '#', '$', '%', '&', '(', ')', '*', '+', '-', ';', '<', '=', '>', '?', '@', '^', '_', '`', '{', '|', '}', '~');
+ for (my $i = 0; $i < 85; $i++) {
+ $table{$characters[$i]} = $i;
+ }
+
+ my $decoded = '';
+ my @encodedChars = $encoded =~ /./g;
+
+ for (my $encodedIter = 0; defined($encodedChars[$encodedIter]);) {
+ my $digit = 0;
+ for (my $i = 0; $i < 5; $i++) {
+ $digit *= 85;
+ my $char = $encodedChars[$encodedIter];
+ $digit += $table{$char};
+ $encodedIter++;
+ }
+
+ for (my $i = 0; $i < 4; $i++) {
+ $decoded .= chr(($digit >> (3 - $i) * 8) & 255);
+ }
+ }
+
+ return $decoded;
+}
+
+sub decodeGitBinaryChunk($$)
+{
+ my ($contents, $fullPath) = @_;
+
+ # Load this module lazily in case the user don't have this module
+ # and won't handle git binary patches.
+ require Compress::Zlib;
+
+ my $encoded = "";
+ my $compressedSize = 0;
+ while ($contents =~ /^([A-Za-z])(.*)$/gm) {
+ my $line = $2;
+ next if $line eq "";
+ die "$fullPath: unexpected size of a line: $&" if length($2) % 5 != 0;
+ my $actualSize = length($2) / 5 * 4;
+ my $encodedExpectedSize = ord($1);
+ my $expectedSize = $encodedExpectedSize <= ord("Z") ? $encodedExpectedSize - ord("A") + 1 : $encodedExpectedSize - ord("a") + 27;
+
+ die "$fullPath: unexpected size of a line: $&" if int(($expectedSize + 3) / 4) * 4 != $actualSize;
+ $compressedSize += $expectedSize;
+ $encoded .= $line;
+ }
+
+ my $compressed = decodeBase85($encoded);
+ $compressed = substr($compressed, 0, $compressedSize);
+ return Compress::Zlib::uncompress($compressed);
+}
+
+sub decodeGitBinaryPatch($$)
+{
+ my ($contents, $fullPath) = @_;
+
+ # Git binary patch has two chunks. One is for the normal patching
+ # and another is for the reverse patching.
+ #
+ # Each chunk a line which starts from either "literal" or "delta",
+ # followed by a number which specifies decoded size of the chunk.
+ # The "delta" type chunks aren't supported by this function yet.
+ #
+ # Then, content of the chunk comes. To decode the content, we
+ # need decode it with base85 first, and then zlib.
+ my $gitPatchRegExp = '(literal|delta) ([0-9]+)\n([A-Za-z0-9!#$%&()*+-;<=>?@^_`{|}~\\n]*?)\n\n';
+ if ($contents !~ m"\nGIT binary patch\n$gitPatchRegExp$gitPatchRegExp\Z") {
+ die "$fullPath: unknown git binary patch format"
+ }
+
+ my $binaryChunkType = $1;
+ my $binaryChunkExpectedSize = $2;
+ my $encodedChunk = $3;
+ my $reverseBinaryChunkType = $4;
+ my $reverseBinaryChunkExpectedSize = $5;
+ my $encodedReverseChunk = $6;
+
+ my $binaryChunk = decodeGitBinaryChunk($encodedChunk, $fullPath);
+ my $binaryChunkActualSize = length($binaryChunk);
+ my $reverseBinaryChunk = decodeGitBinaryChunk($encodedReverseChunk, $fullPath);
+ my $reverseBinaryChunkActualSize = length($reverseBinaryChunk);
+
+ die "$fullPath: unexpected size of the first chunk (expected $binaryChunkExpectedSize but was $binaryChunkActualSize" if ($binaryChunkExpectedSize != $binaryChunkActualSize);
+ die "$fullPath: unexpected size of the second chunk (expected $reverseBinaryChunkExpectedSize but was $reverseBinaryChunkActualSize" if ($reverseBinaryChunkExpectedSize != $reverseBinaryChunkActualSize);
+
+ return ($binaryChunkType, $binaryChunk, $reverseBinaryChunkType, $reverseBinaryChunk);
+}
1;
diff --git a/WebKitTools/Scripts/bisect-builds b/WebKitTools/Scripts/bisect-builds
index 55bf238..063b61e 100755
--- a/WebKitTools/Scripts/bisect-builds
+++ b/WebKitTools/Scripts/bisect-builds
@@ -363,12 +363,13 @@ sub mountAndRunNightly($$$$)
my $mountPath = "/Volumes/WebKit";
my $webkitApp = File::Spec->catfile($mountPath, "WebKit.app");
my $diskImage = File::Spec->catfile($directory, $filename);
+ my $devNull = File::Spec->devnull();
my $i = 0;
while (-e $mountPath) {
$i++;
usleep 100 if $i > 1;
- exec "hdiutil", "detach '$mountPath' 2> " . File::Spec->devnull();
+ `hdiutil detach '$mountPath' 2> $devNull`;
die "Could not unmount $diskImage at $mountPath" if $i > 100;
}
die "Can't mount $diskImage: $mountPath already exists!" if -e $mountPath;
@@ -393,7 +394,7 @@ sub mountAndRunNightly($$$$)
$tempFile ||= "";
`DYLD_FRAMEWORK_PATH=$frameworkPath WEBKIT_UNSET_DYLD_FRAMEWORK_PATH=YES $safari $tempFile`;
- exec "hdiutil", "detach '$mountPath' 2> " . File::Spec->devnull();
+ `hdiutil detach '$mountPath' 2> $devNull`;
}
sub parseRevisions($$;$)
diff --git a/WebKitTools/Scripts/bugzilla-tool b/WebKitTools/Scripts/bugzilla-tool
index 8e899b5..fdbb740 100755
--- a/WebKitTools/Scripts/bugzilla-tool
+++ b/WebKitTools/Scripts/bugzilla-tool
@@ -31,894 +31,74 @@
# A tool for automating dealing with bugzilla, posting patches, committing patches, etc.
import os
-import re
-import StringIO # for add_patch_to_bug file wrappers
-import subprocess
-import sys
-import time
-from datetime import datetime, timedelta
-from optparse import OptionParser, IndentedHelpFormatter, SUPPRESS_USAGE, make_option
-
-# Import WebKit-specific modules.
-from modules.bugzilla import Bugzilla, parse_bug_id
-from modules.changelogs import ChangeLog
-from modules.comments import bug_comment_from_commit_text
-from modules.logging import error, log, tee
-from modules.scm import CommitMessage, detect_scm_system, ScriptError, CheckoutNeedsUpdate
+from modules.bugzilla import Bugzilla
from modules.buildbot import BuildBot
-from modules.statusbot import StatusBot
-
-def plural(noun):
- # This is a dumb plural() implementation which was just enough for our uses.
- if re.search('h$', noun):
- return noun + 'es'
- else:
- return noun + 's'
-
-def pluralize(noun, count):
- if count != 1:
- noun = plural(noun)
- return "%d %s" % (count, noun)
-
-def commit_message_for_this_commit(scm):
- changelog_paths = scm.modified_changelogs()
- if not len(changelog_paths):
- raise ScriptError(message="Found no modified ChangeLogs, cannot create a commit message.\n"
- "All changes require a ChangeLog. See:\n"
- "http://webkit.org/coding/contributing.html")
-
- changelog_messages = []
- for changelog_path in changelog_paths:
- log("Parsing ChangeLog: %s" % changelog_path)
- changelog_entry = ChangeLog(changelog_path).latest_entry()
- if not changelog_entry:
- raise ScriptError(message="Failed to parse ChangeLog: " + os.path.abspath(changelog_path))
- changelog_messages.append(changelog_entry)
-
- # FIXME: We should sort and label the ChangeLog messages like commit-log-editor does.
- return CommitMessage(''.join(changelog_messages).splitlines())
-
-
-class Command:
- def __init__(self, help_text, argument_names="", options=[], requires_local_commits=False):
- self.help_text = help_text
- self.argument_names = argument_names
- self.options = options
- self.option_parser = HelpPrintingOptionParser(usage=SUPPRESS_USAGE, add_help_option=False, option_list=self.options)
- self.requires_local_commits = requires_local_commits
-
- def name_with_arguments(self, command_name):
- usage_string = command_name
- if len(self.options) > 0:
- usage_string += " [options]"
- if self.argument_names:
- usage_string += " " + self.argument_names
- return usage_string
-
- def parse_args(self, args):
- return self.option_parser.parse_args(args)
-
- def execute(self, options, args, tool):
- raise NotImplementedError, "subclasses must implement"
-
-
-class BugsInCommitQueue(Command):
- def __init__(self):
- Command.__init__(self, 'Bugs in the commit queue')
-
- def execute(self, options, args, tool):
- bug_ids = tool.bugs.fetch_bug_ids_from_commit_queue()
- for bug_id in bug_ids:
- print "%s" % bug_id
-
-
-class PatchesInCommitQueue(Command):
- def __init__(self):
- Command.__init__(self, 'Patches in the commit queue')
-
- def execute(self, options, args, tool):
- patches = tool.bugs.fetch_patches_from_commit_queue()
- log("Patches in commit queue:")
- for patch in patches:
- print "%s" % patch['url']
-
-
-class ReviewedPatchesOnBug(Command):
- def __init__(self):
- Command.__init__(self, 'r+\'d patches on a bug', 'BUGID')
-
- def execute(self, options, args, tool):
- bug_id = args[0]
- patches_to_land = tool.bugs.fetch_reviewed_patches_from_bug(bug_id)
- for patch in patches_to_land:
- print "%s" % patch['url']
-
-
-class ApplyPatchesFromBug(Command):
- def __init__(self):
- options = [
- make_option("--no-update", action="store_false", dest="update", default=True, help="Don't update the working directory before applying patches"),
- make_option("--local-commit", action="store_true", dest="local_commit", default=False, help="Make a local commit for each applied patch"),
- ]
- options += WebKitLandingScripts.cleaning_options()
- Command.__init__(self, 'Applies all patches on a bug to the local working directory without committing.', 'BUGID', options=options)
-
- @staticmethod
- def apply_patches(patches, scm, commit_each):
- for patch in patches:
- scm.apply_patch(patch)
- if commit_each:
- commit_message = commit_message_for_this_commit(scm)
- scm.commit_locally_with_message(commit_message.message() or patch['name'])
-
- def execute(self, options, args, tool):
- bug_id = args[0]
- patches = tool.bugs.fetch_reviewed_patches_from_bug(bug_id)
- os.chdir(tool.scm().checkout_root)
- if options.clean:
- tool.scm().ensure_clean_working_directory(options.force_clean)
- if options.update:
- tool.scm().update_webkit()
-
- if options.local_commit and not tool.scm().supports_local_commits():
- error("--local-commit passed, but %s does not support local commits" % tool.scm().display_name())
-
- self.apply_patches(patches, tool.scm(), options.local_commit)
-
-
-class WebKitLandingScripts:
- @staticmethod
- def cleaning_options():
- return [
- make_option("--force-clean", action="store_true", dest="force_clean", default=False, help="Clean working directory before applying patches (removes local changes and commits)"),
- make_option("--no-clean", action="store_false", dest="clean", default=True, help="Don't check if the working directory is clean before applying patches"),
- ]
-
- @staticmethod
- def land_options():
- return [
- make_option("--ignore-builders", action="store_false", dest="check_builders", default=True, help="Don't check to see if the build.webkit.org builders are green before landing."),
- make_option("--no-close", action="store_false", dest="close_bug", default=True, help="Leave bug open after landing."),
- make_option("--no-build", action="store_false", dest="build", default=True, help="Commit without building first, implies --no-test."),
- make_option("--no-test", action="store_false", dest="test", default=True, help="Commit without running run-webkit-tests."),
- make_option("--quiet", action="store_true", dest="quiet", default=False, help="Produce less console output."),
- make_option("--commit-queue", action="store_true", dest="commit_queue", default=False, help="Run in commit queue mode (no user interaction)."),
- ]
-
- @staticmethod
- def run_command_with_teed_output(args, teed_output):
- child_process = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
-
- # Use our own custom wait loop because Popen ignores a tee'd stderr/stdout.
- # FIXME: This could be improved not to flatten output to stdout.
- while True:
- output_line = child_process.stdout.readline()
- if output_line == '' and child_process.poll() != None:
- return child_process.poll()
- teed_output.write(output_line)
-
- @staticmethod
- def run_and_throw_if_fail(args, quiet=False):
- # Cache the child's output locally so it can be used for error reports.
- child_out_file = StringIO.StringIO()
- if quiet:
- dev_null = open(os.devnull, "w")
- child_stdout = tee(child_out_file, dev_null if quiet else sys.stdout)
- exit_code = WebKitLandingScripts.run_command_with_teed_output(args, child_stdout)
- if quiet:
- dev_null.close()
-
- child_output = child_out_file.getvalue()
- child_out_file.close()
-
- if exit_code:
- raise ScriptError(script_args=args, exit_code=exit_code, output=child_output)
-
- # We might need to pass scm into this function for scm.checkout_root
- @staticmethod
- def webkit_script_path(script_name):
- return os.path.join("WebKitTools", "Scripts", script_name)
-
- @classmethod
- def run_webkit_script(cls, script_name, quiet=False):
- log("Running %s" % script_name)
- cls.run_and_throw_if_fail(cls.webkit_script_path(script_name), quiet)
-
- @classmethod
- def build_webkit(cls, quiet=False):
- cls.run_webkit_script("build-webkit", quiet)
-
- @staticmethod
- def ensure_builders_are_green(buildbot, options):
- if not options.check_builders or buildbot.core_builders_are_green():
- return
- error("Builders at %s are red, please do not commit. Pass --ignore-builders to bypass this check." % (buildbot.buildbot_host))
-
- @classmethod
- def run_webkit_tests(cls, launch_safari, fail_fast=False, quiet=False):
- args = [cls.webkit_script_path("run-webkit-tests")]
- if not launch_safari:
- args.append("--no-launch-safari")
- if quiet:
- args.append("--quiet")
- if fail_fast:
- args.append("--exit-after-n-failures=1")
- cls.run_and_throw_if_fail(args)
-
- @staticmethod
- def setup_for_landing(scm, options):
- os.chdir(scm.checkout_root)
- scm.ensure_no_local_commits(options.force_clean)
- if options.clean:
- scm.ensure_clean_working_directory(options.force_clean)
-
- @classmethod
- def build_and_commit(cls, scm, options):
- if options.build:
- cls.build_webkit(quiet=options.quiet)
- if options.test:
- # When running the commit-queue we don't want to launch Safari and we want to exit after the first failure.
- cls.run_webkit_tests(launch_safari=not options.commit_queue, fail_fast=options.commit_queue, quiet=options.quiet)
- commit_message = commit_message_for_this_commit(scm)
- commit_log = scm.commit_with_message(commit_message.message())
- return bug_comment_from_commit_text(scm, commit_log)
-
-
-class LandAndUpdateBug(Command):
- def __init__(self):
- options = [
- make_option("-r", "--reviewer", action="store", type="string", dest="reviewer", help="Update ChangeLogs to say Reviewed by REVIEWER."),
- ]
- options += WebKitLandingScripts.land_options()
- Command.__init__(self, 'Lands the current working directory diff and updates the bug if provided.', '[BUGID]', options=options)
-
- def guess_reviewer_from_bug(self, bugs, bug_id):
- patches = bugs.fetch_reviewed_patches_from_bug(bug_id)
- if len(patches) != 1:
- log("%s on bug %s, cannot infer reviewer." % (pluralize("reviewed patch", len(patches)), bug_id))
- return None
- patch = patches[0]
- reviewer = patch['reviewer']
- log('Guessing "%s" as reviewer from attachment %s on bug %s.' % (reviewer, patch['id'], bug_id))
- return reviewer
-
- def update_changelogs_with_reviewer(self, reviewer, bug_id, tool):
- if not reviewer:
- if not bug_id:
- log("No bug id provided and --reviewer= not provided. Not updating ChangeLogs with reviewer.")
- return
- reviewer = self.guess_reviewer_from_bug(tool.bugs, bug_id)
-
- if not reviewer:
- log("Failed to guess reviewer from bug %s and --reviewer= not provided. Not updating ChangeLogs with reviewer." % bug_id)
- return
-
- for changelog_path in tool.scm().modified_changelogs():
- ChangeLog(changelog_path).set_reviewer(reviewer)
-
- def execute(self, options, args, tool):
- bug_id = args[0] if len(args) else None
- os.chdir(tool.scm().checkout_root)
-
- WebKitLandingScripts.ensure_builders_are_green(tool.buildbot, options)
-
- self.update_changelogs_with_reviewer(options.reviewer, bug_id, tool)
-
- comment_text = WebKitLandingScripts.build_and_commit(tool.scm(), options)
- if bug_id:
- log("Updating bug %s" % bug_id)
- if options.close_bug:
- tool.bugs.close_bug_as_fixed(bug_id, comment_text)
- else:
- # FIXME: We should a smart way to figure out if the patch is attached
- # to the bug, and if so obsolete it.
- tool.bugs.post_comment_to_bug(bug_id, comment_text)
- else:
- log(comment_text)
- log("No bug id provided.")
-
-
-class LandPatchesFromBugs(Command):
- def __init__(self):
- options = WebKitLandingScripts.cleaning_options()
- options += WebKitLandingScripts.land_options()
- Command.__init__(self, 'Lands all patches on a bug optionally testing them first', 'BUGID', options=options)
-
- @staticmethod
- def handled_error(error):
- log(error)
- exit(2) # Exit 2 insted of 1 to indicate to the commit-queue to indicate we handled the error, and that the queue should keep looping.
-
- @classmethod
- def land_patches(cls, bug_id, patches, options, tool):
- try:
- comment_text = ""
- for patch in patches:
- tool.scm().update_webkit() # Update before every patch in case the tree has changed
- log("Applying %s from bug %s." % (patch['id'], bug_id))
- tool.scm().apply_patch(patch, force=options.commit_queue)
- # Make sure the tree is still green after updating, before building this patch.
- # The first patch ends up checking tree status twice, but that's OK.
- WebKitLandingScripts.ensure_builders_are_green(tool.buildbot, options)
- comment_text = WebKitLandingScripts.build_and_commit(tool.scm(), options)
- tool.bugs.clear_attachment_flags(patch['id'], comment_text)
-
- if options.close_bug:
- tool.bugs.close_bug_as_fixed(bug_id, "All reviewed patches have been landed. Closing bug.")
- except CheckoutNeedsUpdate, e:
- log("Commit was rejected because the checkout is out of date. Please update and try again.")
- log("You can pass --no-build to skip building/testing after update if you believe the new commits did not affect the results.")
- cls.handled_error(e)
- except ScriptError, e:
- # Mark the patch as commit-queue- and comment in the bug.
- tool.bugs.reject_patch_from_commit_queue(patch['id'], e.message_with_output())
- cls.handled_error(e)
-
- @staticmethod
- def _fetch_list_of_patches_to_land(options, args, tool):
- bugs_to_patches = {}
- patch_count = 0
- for bug_id in args:
- patches = []
- if options.commit_queue:
- patches = tool.bugs.fetch_commit_queue_patches_from_bug(bug_id, reject_invalid_patches=True)
- else:
- patches = tool.bugs.fetch_reviewed_patches_from_bug(bug_id)
-
- patches_found = len(patches)
- log("%s found on bug %s." % (pluralize("reviewed patch", patches_found), bug_id))
-
- patch_count += patches_found
- if patches_found:
- bugs_to_patches[bug_id] = patches
-
- log("Landing %s from %s." % (pluralize("patch", patch_count), pluralize("bug", len(args))))
- return bugs_to_patches
-
- def execute(self, options, args, tool):
- if not len(args):
- error("bug-id(s) required")
-
- # Check the tree status here so we can fail early
- WebKitLandingScripts.ensure_builders_are_green(tool.buildbot, options)
-
- bugs_to_patches = self._fetch_list_of_patches_to_land(options, args, tool)
-
- WebKitLandingScripts.setup_for_landing(tool.scm(), options)
-
- for bug_id in bugs_to_patches.keys():
- self.land_patches(bug_id, bugs_to_patches[bug_id], options, tool)
-
-
-class CommitMessageForCurrentDiff(Command):
- def __init__(self):
- Command.__init__(self, 'Prints a commit message suitable for the uncommitted changes.')
-
- def execute(self, options, args, tool):
- os.chdir(tool.scm().checkout_root)
- print "%s" % commit_message_for_this_commit(tool.scm()).message()
-
-
-class ObsoleteAttachmentsOnBug(Command):
- def __init__(self):
- Command.__init__(self, 'Marks all attachments on a bug as obsolete.', 'BUGID')
-
- def execute(self, options, args, tool):
- bug_id = args[0]
- attachments = tool.bugs.fetch_attachments_from_bug(bug_id)
- for attachment in attachments:
- if not attachment['is_obsolete']:
- tool.bugs.obsolete_attachment(attachment['id'])
-
+from modules.buildsteps import BuildSteps
+from modules.commands.download import *
+from modules.commands.early_warning_system import *
+from modules.commands.queries import *
+from modules.commands.queues import *
+from modules.commands.upload import *
+from modules.executive import Executive
+from modules.logging import log
+from modules.multicommandtool import MultiCommandTool
+from modules.scm import detect_scm_system
+
+class BugzillaTool(MultiCommandTool):
+ def __init__(self):
+ MultiCommandTool.__init__(self)
+ self.global_option_parser.add_option("--dry-run", action="callback", help="do not touch remote servers", callback=self.dry_run_callback)
-class PostDiffAsPatchToBug(Command):
- def __init__(self):
- options = [
- make_option("-m", "--description", action="store", type="string", dest="description", help="Description string for the attachment (default: 'patch')"),
- ]
- options += self.posting_options()
- Command.__init__(self, 'Attaches the current working directory diff to a bug as a patch file.', '[BUGID]', options=options)
-
- @staticmethod
- def posting_options():
- return [
- make_option("--no-obsolete", action="store_false", dest="obsolete_patches", default=True, help="Do not obsolete old patches before posting this one."),
- make_option("--no-review", action="store_false", dest="review", default=True, help="Do not mark the patch for review."),
- make_option("--request-commit", action="store_true", dest="request_commit", default=False, help="Mark the patch as needing auto-commit after review."),
- ]
-
- @staticmethod
- def obsolete_patches_on_bug(bug_id, bugs):
- patches = bugs.fetch_patches_from_bug(bug_id)
- if len(patches):
- log("Obsoleting %s on bug %s" % (pluralize('old patch', len(patches)), bug_id))
- for patch in patches:
- bugs.obsolete_attachment(patch['id'])
-
- def execute(self, options, args, tool):
- # Perfer a bug id passed as an argument over a bug url in the diff (i.e. ChangeLogs).
- bug_id = (args and args[0]) or parse_bug_id(tool.scm().create_patch())
- if not bug_id:
- error("No bug id passed and no bug url found in diff, can't post.")
-
- if options.obsolete_patches:
- self.obsolete_patches_on_bug(bug_id, tool.bugs)
-
- diff = tool.scm().create_patch()
- diff_file = StringIO.StringIO(diff) # add_patch_to_bug expects a file-like object
-
- description = options.description or "Patch v1"
- tool.bugs.add_patch_to_bug(bug_id, diff_file, description, mark_for_review=options.review, mark_for_commit_queue=options.request_commit)
-
-
-class PostCommitsAsPatchesToBug(Command):
- def __init__(self):
- options = [
- make_option("-b", "--bug-id", action="store", type="string", dest="bug_id", help="Specify bug id if no URL is provided in the commit log."),
- make_option("--add-log-as-comment", action="store_true", dest="add_log_as_comment", default=False, help="Add commit log message as a comment when uploading the patch."),
- make_option("-m", "--description", action="store", type="string", dest="description", help="Description string for the attachment (default: description from commit message)"),
- ]
- options += PostDiffAsPatchToBug.posting_options()
- Command.__init__(self, 'Attaches a range of local commits to bugs as patch files.', 'COMMITISH', options=options, requires_local_commits=True)
-
- def _comment_text_for_commit(self, options, commit_message, tool, commit_id):
- comment_text = None
- if (options.add_log_as_comment):
- comment_text = commit_message.body(lstrip=True)
- comment_text += "---\n"
- comment_text += tool.scm().files_changed_summary_for_commit(commit_id)
- return comment_text
-
- def _diff_file_for_commit(self, tool, commit_id):
- diff = tool.scm().create_patch_from_local_commit(commit_id)
- return StringIO.StringIO(diff) # add_patch_to_bug expects a file-like object
-
- def execute(self, options, args, tool):
- if not args:
- error("%s argument is required" % self.argument_names)
-
- commit_ids = tool.scm().commit_ids_from_commitish_arguments(args)
- if len(commit_ids) > 10: # We could lower this limit, 10 is too many for one bug as-is.
- error("bugzilla-tool does not support attaching %s at once. Are you sure you passed the right commit range?" % (pluralize('patch', len(commit_ids))))
-
- have_obsoleted_patches = set()
- for commit_id in commit_ids:
- commit_message = tool.scm().commit_message_for_local_commit(commit_id)
-
- # Prefer --bug-id=, then a bug url in the commit message, then a bug url in the entire commit diff (i.e. ChangeLogs).
- bug_id = options.bug_id or parse_bug_id(commit_message.message()) or parse_bug_id(tool.scm().create_patch_from_local_commit(commit_id))
- if not bug_id:
- log("Skipping %s: No bug id found in commit or specified with --bug-id." % commit_id)
- continue
-
- if options.obsolete_patches and bug_id not in have_obsoleted_patches:
- PostDiffAsPatchToBug.obsolete_patches_on_bug(bug_id, tool.bugs)
- have_obsoleted_patches.add(bug_id)
-
- diff_file = self._diff_file_for_commit(tool, commit_id)
- description = options.description or commit_message.description(lstrip=True, strip_url=True)
- comment_text = self._comment_text_for_commit(options, commit_message, tool, commit_id)
- tool.bugs.add_patch_to_bug(bug_id, diff_file, description, comment_text, mark_for_review=options.review, mark_for_commit_queue=options.request_commit)
-
-
-class RolloutCommit(Command):
- def __init__(self):
- options = WebKitLandingScripts.land_options()
- options += WebKitLandingScripts.cleaning_options()
- options.append(make_option("--complete-rollout", action="store_true", dest="complete_rollout", help="Experimental support for complete unsupervised rollouts, including re-opening the bug. Not recommended."))
- Command.__init__(self, 'Reverts the given revision and commits the revert and re-opens the original bug.', 'REVISION [BUGID]', options=options)
-
- @staticmethod
- def _create_changelogs_for_revert(scm, revision):
- # First, discard the ChangeLog changes from the rollout.
- changelog_paths = scm.modified_changelogs()
- scm.revert_files(changelog_paths)
-
- # Second, make new ChangeLog entries for this rollout.
- # This could move to prepare-ChangeLog by adding a --revert= option.
- WebKitLandingScripts.run_webkit_script("prepare-ChangeLog")
- for changelog_path in changelog_paths:
- ChangeLog(changelog_path).update_for_revert(revision)
-
- @staticmethod
- def _parse_bug_id_from_revision_diff(tool, revision):
- original_diff = tool.scm().diff_for_revision(revision)
- return parse_bug_id(original_diff)
-
- @staticmethod
- def _reopen_bug_after_rollout(tool, bug_id, comment_text):
- if bug_id:
- tool.bugs.reopen_bug(bug_id, comment_text)
- else:
- log(comment_text)
- log("No bugs were updated or re-opened to reflect this rollout.")
-
- def execute(self, options, args, tool):
- if not args:
- error("REVISION is required, see --help.")
- revision = args[0]
- bug_id = self._parse_bug_id_from_revision_diff(tool, revision)
- if options.complete_rollout:
- if bug_id:
- log("Will re-open bug %s after rollout." % bug_id)
- else:
- log("Failed to parse bug number from diff. No bugs will be updated/reopened after the rollout.")
-
- WebKitLandingScripts.setup_for_landing(tool.scm(), options)
- tool.scm().update_webkit()
- tool.scm().apply_reverse_diff(revision)
- self._create_changelogs_for_revert(tool.scm(), revision)
-
- # FIXME: Fully automated rollout is not 100% idiot-proof yet, so for now just log with instructions on how to complete the rollout.
- # Once we trust rollout we will remove this option.
- if not options.complete_rollout:
- log("\nNOTE: Rollout support is experimental.\nPlease verify the rollout diff and use 'bugzilla-tool land-diff %s' to commit the rollout." % bug_id)
- else:
- comment_text = WebKitLandingScripts.build_and_commit(tool.scm(), options)
- self._reopen_bug_after_rollout(tool, bug_id, comment_text)
-
-
-class CreateBug(Command):
- def __init__(self):
- options = [
- make_option("--cc", action="store", type="string", dest="cc", help="Comma-separated list of email addresses to carbon-copy."),
- make_option("--component", action="store", type="string", dest="component", help="Component for the new bug."),
- make_option("--no-prompt", action="store_false", dest="prompt", default=True, help="Do not prompt for bug title and comment; use commit log instead."),
- make_option("--no-review", action="store_false", dest="review", default=True, help="Do not mark the patch for review."),
- make_option("--request-commit", action="store_true", dest="request_commit", default=False, help="Mark the patch as needing auto-commit after review."),
- ]
- Command.__init__(self, 'Create a bug from local changes or local commits.', '[COMMITISH]', options=options)
-
- def create_bug_from_commit(self, options, args, tool):
- commit_ids = tool.scm().commit_ids_from_commitish_arguments(args)
- if len(commit_ids) > 3:
- error("Are you sure you want to create one bug with %s patches?" % len(commit_ids))
-
- commit_id = commit_ids[0]
-
- bug_title = ""
- comment_text = ""
- if options.prompt:
- (bug_title, comment_text) = self.prompt_for_bug_title_and_comment()
- else:
- commit_message = tool.scm().commit_message_for_local_commit(commit_id)
- bug_title = commit_message.description(lstrip=True, strip_url=True)
- comment_text = commit_message.body(lstrip=True)
- comment_text += "---\n"
- comment_text += tool.scm().files_changed_summary_for_commit(commit_id)
-
- diff = tool.scm().create_patch_from_local_commit(commit_id)
- diff_file = StringIO.StringIO(diff) # create_bug_with_patch expects a file-like object
- bug_id = tool.bugs.create_bug_with_patch(bug_title, comment_text, options.component, diff_file, "Patch v1", cc=options.cc, mark_for_review=options.review, mark_for_commit_queue=options.request_commit)
-
- if bug_id and len(commit_ids) > 1:
- options.bug_id = bug_id
- options.obsolete_patches = False
- # FIXME: We should pass through --no-comment switch as well.
- PostCommitsAsPatchesToBug.execute(self, options, commit_ids[1:], tool)
-
- def create_bug_from_patch(self, options, args, tool):
- bug_title = ""
- comment_text = ""
- if options.prompt:
- (bug_title, comment_text) = self.prompt_for_bug_title_and_comment()
- else:
- commit_message = commit_message_for_this_commit(tool.scm())
- bug_title = commit_message.description(lstrip=True, strip_url=True)
- comment_text = commit_message.body(lstrip=True)
-
- diff = tool.scm().create_patch()
- diff_file = StringIO.StringIO(diff) # create_bug_with_patch expects a file-like object
- bug_id = tool.bugs.create_bug_with_patch(bug_title, comment_text, options.component, diff_file, "Patch v1", cc=options.cc, mark_for_review=options.review, mark_for_commit_queue=options.request_commit)
-
- def prompt_for_bug_title_and_comment(self):
- bug_title = raw_input("Bug title: ")
- print "Bug comment (hit ^D on blank line to end):"
- lines = sys.stdin.readlines()
- try:
- sys.stdin.seek(0, os.SEEK_END)
- except IOError:
- # Cygwin raises an Illegal Seek (errno 29) exception when the above
- # seek() call is made. Ignoring it seems to cause no harm.
- # FIXME: Figure out a way to get avoid the exception in the first
- # place.
- pass
- else:
- raise
- comment_text = ''.join(lines)
- return (bug_title, comment_text)
-
- def execute(self, options, args, tool):
- if len(args):
- if (not tool.scm().supports_local_commits()):
- error("Extra arguments not supported; patch is taken from working directory.")
- self.create_bug_from_commit(options, args, tool)
- else:
- self.create_bug_from_patch(options, args, tool)
-
-
-class CheckTreeStatus(Command):
- def __init__(self):
- Command.__init__(self, 'Print out the status of the webkit builders.')
-
- def execute(self, options, args, tool):
- for builder in tool.buildbot.builder_statuses():
- status_string = "ok" if builder['is_green'] else 'FAIL'
- print "%s : %s" % (status_string.ljust(4), builder['name'])
-
-
-class LandPatchesFromCommitQueue(Command):
- def __init__(self):
- options = [
- make_option("--is-relaunch", action="store_true", dest="is_relaunch", default=False, help="Internal: Used by the queue to indicate that it's relaunching itself."),
- make_option("--no-confirm", action="store_false", dest="confirm", default=True, help="Do not ask the user for confirmation before running the queue. Dangerous!"),
- make_option("--status-host", action="store", type="string", dest="status_host", default=StatusBot.default_host, help="Do not ask the user for confirmation before running the queue. Dangerous!"),
- ]
- Command.__init__(self, 'Run the commit queue.', options=options)
- self._original_stdout = None
- self._original_stderr = None
- self._files_for_output = []
-
- queue_log_path = 'commit_queue.log'
- bug_logs_directory = 'commit_queue_logs'
-
- log_date_format = "%Y-%m-%d %H:%M:%S"
- sleep_duration_text = "5 mins"
- seconds_to_sleep = 300
-
- def _tee_outputs_to_files(self, files):
- if not self._original_stdout:
- self._original_stdout = sys.stdout
- self._original_stderr = sys.stderr
- if files and len(files):
- sys.stdout = tee(self._original_stdout, *files)
- sys.stderr = tee(self._original_stderr, *files)
- else:
- sys.stdout = self._original_stdout
- sys.stderr = self._original_stderr
-
- @classmethod
- def _sleep_message(cls, message):
- wake_time = datetime.now() + timedelta(seconds=cls.seconds_to_sleep)
- return "%s Sleeping until %s (%s)." % (message, wake_time.strftime(cls.log_date_format), cls.sleep_duration_text)
-
- def _sleep(self, message):
- log(self._sleep_message(message))
- time.sleep(self.seconds_to_sleep)
- self._next_patch()
-
- def _update_status_and_sleep(self, message):
- status_message = self._sleep_message(message)
- self.status_bot.update_status(status_message)
- log(status_message)
- time.sleep(self.seconds_to_sleep)
- self._next_patch()
-
- def _next_patch(self):
- # Re-exec this script to catch any updates to the script.
- # Make sure that the re-execed commit-queue does not wait for the user.
- args = sys.argv[:]
- if args.count("--is-relaunch") == 0:
- args.append("--is-relaunch")
- os.execvp(sys.argv[0], args)
-
- @staticmethod
- def _open_log_file(log_path):
- (log_directory, log_name) = os.path.split(log_path)
- if log_directory and not os.path.exists(log_directory):
- os.makedirs(log_directory)
- return open(log_path, 'a+')
-
- def _add_log_to_output_tee(self, path):
- log_file = self._open_log_file(path)
- self._files_for_output.append(log_file)
- self._tee_outputs_to_files(self._files_for_output)
- return log_file
-
- def _remove_log_from_output_tee(self, log_file):
- self._files_for_output.remove(log_file)
- self._tee_outputs_to_files(self._files_for_output)
- log_file.close()
-
- def execute(self, options, args, tool):
- if not options.is_relaunch:
- log("CAUTION: commit-queue will discard all local changes in %s" % tool.scm().checkout_root)
- if options.confirm:
- response = raw_input("Are you sure? Type 'yes' to continue: ")
- if (response != 'yes'):
- error("User declined.")
-
- queue_log = self._add_log_to_output_tee(self.queue_log_path)
- if not options.is_relaunch:
- log("Running WebKit Commit Queue. %s" % datetime.now().strftime(self.log_date_format))
-
- self.status_bot = StatusBot(host=options.status_host)
-
- # Either of these calls could throw URLError which shouldn't stop the queue.
- # We catch all exceptions just in case.
- try:
- # Fetch patches instead of just bug ids to that we validate reviewer/committer flags on every patch.
- patches = tool.bugs.fetch_patches_from_commit_queue(reject_invalid_patches=True)
- if not len(patches):
- self._update_status_and_sleep("Empty queue.")
- patch_ids = map(lambda patch: patch['id'], patches)
- first_bug_id = patches[0]['bug_id']
- log("%s in commit queue [%s]" % (pluralize('patch', len(patches)), ", ".join(patch_ids)))
-
- red_builders_names = tool.buildbot.red_core_builders_names()
- if red_builders_names:
- red_builders_names = map(lambda name: '"%s"' % name, red_builders_names) # Add quotes around the names.
- self._update_status_and_sleep("Builders [%s] are red. See http://build.webkit.org." % ", ".join(red_builders_names))
-
- self.status_bot.update_status("Landing patches from bug %s." % first_bug_id, bug_id=first_bug_id)
- except Exception, e:
- # Don't try tell the status bot, in case telling it causes an exception.
- self._sleep("Exception while checking queue and bots: %s." % e)
-
- # Try to land patches on the first bug in the queue before looping
- bug_log_path = os.path.join(self.bug_logs_directory, "%s.log" % first_bug_id)
- bug_log = self._add_log_to_output_tee(bug_log_path)
- bugzilla_tool_path = __file__ # re-execute this script
- bugzilla_tool_args = [bugzilla_tool_path, 'land-patches', '--force-clean', '--commit-queue', '--quiet', first_bug_id]
- try:
- WebKitLandingScripts.run_and_throw_if_fail(bugzilla_tool_args)
- except ScriptError, e:
- # Unexpected failure! Mark the patch as commit-queue- and comment in the bug.
- # exit(2) is a special exit code we use to indicate that the error was already handled by land-patches and we should keep looping anyway.
- if e.exit_code != 2:
- tool.bugs.reject_patch_from_commit_queue(patch['id'], "Unexpected failure when landing patch! Please file a bug against bugzilla-tool.\n%s" % e.message_with_output())
- self._remove_log_from_output_tee(bug_log)
- # self._remove_log_from_output_tee(queue_log) # implicit in the exec()
- self._next_patch()
-
-
-class NonWrappingEpilogIndentedHelpFormatter(IndentedHelpFormatter):
- def __init__(self):
- IndentedHelpFormatter.__init__(self)
-
- # The standard IndentedHelpFormatter paragraph-wraps the epilog, killing our custom formatting.
- def format_epilog(self, epilog):
- if epilog:
- return "\n" + epilog + "\n"
- return ""
-
-
-class HelpPrintingOptionParser(OptionParser):
- def error(self, msg):
- self.print_usage(sys.stderr)
- error_message = "%s: error: %s\n" % (self.get_prog_name(), msg)
- error_message += "\nType '" + self.get_prog_name() + " --help' to see usage.\n"
- self.exit(2, error_message)
-
-
-class BugzillaTool:
- def __init__(self):
- self.cached_scm = None
self.bugs = Bugzilla()
self.buildbot = BuildBot()
- self.commands = [
- { 'name' : 'bugs-to-commit', 'object' : BugsInCommitQueue() },
- { 'name' : 'patches-to-commit', 'object' : PatchesInCommitQueue() },
- { 'name' : 'reviewed-patches', 'object' : ReviewedPatchesOnBug() },
- { 'name' : 'create-bug', 'object' : CreateBug() },
- { 'name' : 'apply-patches', 'object' : ApplyPatchesFromBug() },
- { 'name' : 'land-diff', 'object' : LandAndUpdateBug() },
- { 'name' : 'land-patches', 'object' : LandPatchesFromBugs() },
- { 'name' : 'commit-message', 'object' : CommitMessageForCurrentDiff() },
- { 'name' : 'obsolete-attachments', 'object' : ObsoleteAttachmentsOnBug() },
- { 'name' : 'post-diff', 'object' : PostDiffAsPatchToBug() },
- { 'name' : 'post-commits', 'object' : PostCommitsAsPatchesToBug() },
- { 'name' : 'tree-status', 'object' : CheckTreeStatus() },
- { 'name' : 'commit-queue', 'object' : LandPatchesFromCommitQueue() },
- { 'name' : 'rollout', 'object' : RolloutCommit() },
- ]
+ self.executive = Executive()
+ self._scm = None
+ self._status = None
+ self.steps = BuildSteps()
- self.global_option_parser = HelpPrintingOptionParser(usage=self.usage_line(), formatter=NonWrappingEpilogIndentedHelpFormatter(), epilog=self.commands_usage())
- self.global_option_parser.add_option("--dry-run", action="store_true", dest="dryrun", help="do not touch remote servers", default=False)
+ def dry_run_callback(self, option, opt, value, parser):
+ self.scm().dryrun = True
+ self.bugs.dryrun = True
def scm(self):
# Lazily initialize SCM to not error-out before command line parsing (or when running non-scm commands).
- original_cwd = os.path.abspath('.')
- if not self.cached_scm:
- self.cached_scm = detect_scm_system(original_cwd)
-
- if not self.cached_scm:
+ original_cwd = os.path.abspath(".")
+ if not self._scm:
+ self._scm = detect_scm_system(original_cwd)
+
+ if not self._scm:
script_directory = os.path.abspath(sys.path[0])
webkit_directory = os.path.abspath(os.path.join(script_directory, "../.."))
- self.cached_scm = detect_scm_system(webkit_directory)
- if self.cached_scm:
+ self._scm = detect_scm_system(webkit_directory)
+ if self._scm:
log("The current directory (%s) is not a WebKit checkout, using %s" % (original_cwd, webkit_directory))
else:
error("FATAL: Failed to determine the SCM system for either %s or %s" % (original_cwd, webkit_directory))
-
- return self.cached_scm
-
- @staticmethod
- def usage_line():
- return "Usage: %prog [options] command [command-options] [command-arguments]"
-
- def commands_usage(self):
- commands_text = "Commands:\n"
- longest_name_length = 0
- command_rows = []
- scm_supports_local_commits = self.scm().supports_local_commits()
- for command in self.commands:
- command_object = command['object']
- if command_object.requires_local_commits and not scm_supports_local_commits:
- continue
- command_name_and_args = command_object.name_with_arguments(command['name'])
- command_rows.append({ 'name-and-args': command_name_and_args, 'object': command_object })
- longest_name_length = max([longest_name_length, len(command_name_and_args)])
-
- # Use our own help formatter so as to indent enough.
- formatter = IndentedHelpFormatter()
- formatter.indent()
- formatter.indent()
-
- for row in command_rows:
- command_object = row['object']
- commands_text += " " + row['name-and-args'].ljust(longest_name_length + 3) + command_object.help_text + "\n"
- commands_text += command_object.option_parser.format_option_help(formatter)
- return commands_text
-
- def handle_global_args(self, args):
- (options, args) = self.global_option_parser.parse_args(args)
- if len(args):
- # We'll never hit this because split_args splits at the first arg without a leading '-'
- self.global_option_parser.error("Extra arguments before command: " + args)
-
- if options.dryrun:
- self.scm().dryrun = True
- self.bugs.dryrun = True
-
- @staticmethod
- def split_args(args):
- # Assume the first argument which doesn't start with '-' is the command name.
- command_index = 0
- for arg in args:
- if arg[0] != '-':
- break
- command_index += 1
- else:
- return (args[:], None, [])
- global_args = args[:command_index]
- command = args[command_index]
- command_args = args[command_index + 1:]
- return (global_args, command, command_args)
-
- def command_by_name(self, command_name):
- for command in self.commands:
- if command_name == command['name']:
- return command
- return None
-
- def main(self):
- (global_args, command_name, args_after_command_name) = self.split_args(sys.argv[1:])
-
- # Handle --help, etc:
- self.handle_global_args(global_args)
-
- if not command_name:
- self.global_option_parser.error("No command specified")
-
- command = self.command_by_name(command_name)
- if not command:
- self.global_option_parser.error(command_name + " is not a recognized command")
+ return self._scm
- command_object = command['object']
+ def status(self):
+ if not self._status:
+ self._status = StatusBot()
+ return self._status
- if command_object.requires_local_commits and not self.scm().supports_local_commits():
- error(command_name + " requires local commits using %s in %s." % (self.scm().display_name(), self.scm().checkout_root))
+ def path(self):
+ return __file__
- (command_options, command_args) = command_object.parse_args(args_after_command_name)
- return command_object.execute(command_options, command_args, self)
+ def should_show_in_main_help(self, command):
+ if not command.show_in_main_help:
+ return False
+ if command.requires_local_commits:
+ return self.scm().supports_local_commits()
+ return True
+ def should_execute_command(self, command):
+ if command.requires_local_commits and not self.scm().supports_local_commits():
+ failure_reason = "%s requires local commits using %s in %s." % (command.name, self.scm().display_name(), self.scm().checkout_root)
+ return (False, failure_reason)
+ return (True, None)
-def main():
- tool = BugzillaTool()
- return tool.main()
if __name__ == "__main__":
- main()
+ BugzillaTool().main()
diff --git a/WebKitTools/Scripts/build-webkit b/WebKitTools/Scripts/build-webkit
index 4f78eef..566965b 100755
--- a/WebKitTools/Scripts/build-webkit
+++ b/WebKitTools/Scripts/build-webkit
@@ -50,9 +50,9 @@ my $minimal = 0;
my $makeArgs;
my $startTime = time();
-my ($threeDCanvasSupport, $threeDRenderingSupport, $channelMessagingSupport, $databaseSupport, $datagridSupport, $domStorageSupport,
- $eventsourceSupport, $filtersSupport, $geolocationSupport, $iconDatabaseSupport,
- $javaScriptDebuggerSupport, $mathmlSupport, $offlineWebApplicationSupport, $rubySupport, $sharedWorkersSupport,
+my ($threeDCanvasSupport, $threeDRenderingSupport, $channelMessagingSupport, $databaseSupport, $datagridSupport, $datalistSupport,
+ $domStorageSupport, $eventsourceSupport, $filtersSupport, $geolocationSupport, $iconDatabaseSupport,
+ $javaScriptDebuggerSupport, $mathmlSupport, $offlineWebApplicationSupport, $sharedWorkersSupport,
$svgSupport, $svgAnimationSupport, $svgAsImageSupport, $svgDOMObjCBindingsSupport, $svgFontsSupport,
$svgForeignObjectSupport, $svgUseSupport, $videoSupport, $webSocketsSupport, $wmlSupport, $wcssSupport, $xhtmlmpSupport, $workersSupport,
$xpathSupport, $xsltSupport, $coverageSupport, $notificationsSupport);
@@ -75,6 +75,9 @@ my @features = (
{ option => "datagrid", desc => "Toggle Datagrid Support",
define => "ENABLE_DATAGRID", default => 1, value => \$datagridSupport },
+
+ { option => "datalist", desc => "Toggle HTML5 datalist support",
+ define => "ENABLE_DATALIST", default => 1, value => \$datalistSupport },
{ option => "dom-storage", desc => "Toggle DOM Storage Support",
define => "ENABLE_DOM_STORAGE", default => 1, value => \$domStorageSupport },
@@ -83,7 +86,7 @@ my @features = (
define => "ENABLE_EVENTSOURCE", default => 1, value => \$eventsourceSupport },
{ option => "filters", desc => "Toggle Filters support",
- define => "ENABLE_FILTERS", default => 0, value => \$filtersSupport },
+ define => "ENABLE_FILTERS", default => (isAppleWebKit() || isGtk() || isQt()), value => \$filtersSupport },
{ option => "geolocation", desc => "Toggle Geolocation support",
define => "ENABLE_GEOLOCATION", default => isGtk(), value => \$geolocationSupport },
@@ -103,9 +106,6 @@ my @features = (
{ option => "offline-web-applications", desc => "Toggle Offline Web Application Support",
define => "ENABLE_OFFLINE_WEB_APPLICATIONS", default => 1, value => \$offlineWebApplicationSupport },
- { option => "ruby", desc => "Toggle HTML5 Ruby support",
- define => "ENABLE_RUBY", default => 1, value => \$rubySupport },
-
{ option => "shared-workers", desc => "Toggle SharedWorkers support",
define => "ENABLE_SHARED_WORKERS", default => (isAppleWebKit() || isGtk()), value => \$sharedWorkersSupport },
@@ -313,6 +313,7 @@ removeLibraryDependingOnSVG("WebCore", $svgSupport);
if (isWx()) {
downloadWafIfNeeded();
+ push @projects, 'WebKitTools/DumpRenderTree';
push @projects, 'WebKitTools/wx/browser';
push @projects, 'WebKit/wx/bindings/python';
}
@@ -321,7 +322,7 @@ if (isChromium()) {
# Chromium doesn't build by project directories.
@projects = ();
my $result = buildChromium($clean, @options);
- exit $result if $result;
+ exit exitStatus($result) if exitStatus($result);
}
# Build, and abort if the build fails.
@@ -361,7 +362,7 @@ for my $dir (@projects) {
if (isAppleWinWebKit()) {
print "\n\n===== BUILD FAILED ======\n\n";
my $scriptDir = relativeScriptsDir();
- print "Please ensure you have run $scriptDir/update-webkit to install depenedencies.\n\n";
+ print "Please ensure you have run $scriptDir/update-webkit to install dependencies.\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";
}
diff --git a/WebKitTools/Scripts/commit-log-editor b/WebKitTools/Scripts/commit-log-editor
index e58b181..75017e3 100755
--- a/WebKitTools/Scripts/commit-log-editor
+++ b/WebKitTools/Scripts/commit-log-editor
@@ -170,7 +170,8 @@ for my $changeLog (@changeLogs) {
# Attempt to insert the "patch by" line, after the first blank line.
if ($previousLineWasBlank && $hasAuthorInfoToWrite && $lineCount > 0) {
- my $authorAndCommitterAreSamePerson = $ENV{EMAIL_ADDRESS} && $email eq $ENV{EMAIL_ADDRESS};
+ my $committerEmail = changeLogEmailAddress();
+ my $authorAndCommitterAreSamePerson = $email eq $committerEmail;
if (!$authorAndCommitterAreSamePerson) {
$contents .= "Patch by $author <$email> on $date\n";
$hasAuthorInfoToWrite = 0;
@@ -229,7 +230,7 @@ if (isGit() && scalar keys %changeLogSort == 0) {
chomp($webkitGenerateCommitMessage = `git config --bool core.webkitGenerateCommitMessage`);
}
if ($webkitGenerateCommitMessage ne "false") {
- open CHANGELOG_ENTRIES, "-|", "prepare-ChangeLog --git-index --no-write" or die "prepare-ChangeLog failed: $!.\n";
+ open CHANGELOG_ENTRIES, "-|", "$FindBin::Bin/prepare-ChangeLog --git-index --no-write" or die "prepare-ChangeLog failed: $!.\n";
while (<CHANGELOG_ENTRIES>) {
print NEWLOG normalizeLineEndings($_, $endl);
}
diff --git a/WebKitTools/Scripts/do-webcore-rename b/WebKitTools/Scripts/do-webcore-rename
index 2d6ca46..a65fa4f 100755
--- a/WebKitTools/Scripts/do-webcore-rename
+++ b/WebKitTools/Scripts/do-webcore-rename
@@ -33,6 +33,7 @@ use FindBin;
use lib $FindBin::Bin;
use webkitdirs;
use File::Find;
+use VCSUtils;
setConfiguration();
chdirWebKit();
@@ -66,9 +67,229 @@ sub wanted
push @paths, $File::Find::name;
}
-
+my $isDOMTypeRename = 1;
my %renames = (
- "parseURL" => "deprecatedParseURL"
+ "CanvasActiveInfo" => "WebGLActiveInfo",
+ "canvasActiveInfo" => "webGLActiveInfo",
+ "CanvasActiveInfoConstructor" => "WebGLActiveInfoConstructor",
+ "CanvasActiveInfoPrototype" => "WebGLActiveInfoPrototype",
+ "toCanvasActiveInfo" => "toWebGLActiveInfo",
+ "JSCanvasActiveInfo" => "JSWebGLActiveInfo",
+ "JSCanvasActiveInfoPrototype" => "JSWebGLActiveInfoPrototype",
+ "JSCanvasActiveInfoConstructor" => "JSWebGLActiveInfoConstructor",
+ "JSCanvasActiveInfoCustom" => "JSWebGLActiveInfoCustom",
+ "V8CanvasActiveInfo" => "V8WebGLActiveInfo",
+ "V8CanvasActiveInfoPrototype" => "V8WebGLActiveInfoPrototype",
+ "V8CanvasActiveInfoConstructor" => "V8WebGLActiveInfoConstructor",
+ "V8CanvasActiveInfoCustom" => "V8WebGLActiveInfoCustom",
+ "CanvasArray" => "WebGLArray",
+ "canvasArray" => "webGLArray",
+ "CanvasArrayConstructor" => "WebGLArrayConstructor",
+ "CanvasArrayPrototype" => "WebGLArrayPrototype",
+ "toCanvasArray" => "toWebGLArray",
+ "JSCanvasArray" => "JSWebGLArray",
+ "JSCanvasArrayPrototype" => "JSWebGLArrayPrototype",
+ "JSCanvasArrayConstructor" => "JSWebGLArrayConstructor",
+ "JSCanvasArrayCustom" => "JSWebGLArrayCustom",
+ "V8CanvasArray" => "V8WebGLArray",
+ "V8CanvasArrayPrototype" => "V8WebGLArrayPrototype",
+ "V8CanvasArrayConstructor" => "V8WebGLArrayConstructor",
+ "V8CanvasArrayCustom" => "V8WebGLArrayCustom",
+ "CanvasArrayBuffer" => "WebGLArrayBuffer",
+ "canvasArrayBuffer" => "webGLArrayBuffer",
+ "CanvasArrayBufferConstructor" => "WebGLArrayBufferConstructor",
+ "CanvasArrayBufferPrototype" => "WebGLArrayBufferPrototype",
+ "toCanvasArrayBuffer" => "toWebGLArrayBuffer",
+ "JSCanvasArrayBuffer" => "JSWebGLArrayBuffer",
+ "JSCanvasArrayBufferPrototype" => "JSWebGLArrayBufferPrototype",
+ "JSCanvasArrayBufferConstructor" => "JSWebGLArrayBufferConstructor",
+ "JSCanvasArrayBufferCustom" => "JSWebGLArrayBufferCustom",
+ "V8CanvasArrayBuffer" => "V8WebGLArrayBuffer",
+ "V8CanvasArrayBufferPrototype" => "V8WebGLArrayBufferPrototype",
+ "V8CanvasArrayBufferConstructor" => "V8WebGLArrayBufferConstructor",
+ "V8CanvasArrayBufferCustom" => "V8WebGLArrayBufferCustom",
+ "CanvasBuffer" => "WebGLBuffer",
+ "canvasBuffer" => "webGLBuffer",
+ "CanvasBufferConstructor" => "WebGLBufferConstructor",
+ "CanvasBufferPrototype" => "WebGLBufferPrototype",
+ "toCanvasBuffer" => "toWebGLBuffer",
+ "JSCanvasBuffer" => "JSWebGLBuffer",
+ "JSCanvasBufferPrototype" => "JSWebGLBufferPrototype",
+ "JSCanvasBufferConstructor" => "JSWebGLBufferConstructor",
+ "JSCanvasBufferCustom" => "JSWebGLBufferCustom",
+ "V8CanvasBuffer" => "V8WebGLBuffer",
+ "V8CanvasBufferPrototype" => "V8WebGLBufferPrototype",
+ "V8CanvasBufferConstructor" => "V8WebGLBufferConstructor",
+ "V8CanvasBufferCustom" => "V8WebGLBufferCustom",
+ "CanvasByteArray" => "WebGLByteArray",
+ "canvasByteArray" => "webGLByteArray",
+ "CanvasByteArrayConstructor" => "WebGLByteArrayConstructor",
+ "CanvasByteArrayPrototype" => "WebGLByteArrayPrototype",
+ "toCanvasByteArray" => "toWebGLByteArray",
+ "JSCanvasByteArray" => "JSWebGLByteArray",
+ "JSCanvasByteArrayPrototype" => "JSWebGLByteArrayPrototype",
+ "JSCanvasByteArrayConstructor" => "JSWebGLByteArrayConstructor",
+ "JSCanvasByteArrayCustom" => "JSWebGLByteArrayCustom",
+ "V8CanvasByteArray" => "V8WebGLByteArray",
+ "V8CanvasByteArrayPrototype" => "V8WebGLByteArrayPrototype",
+ "V8CanvasByteArrayConstructor" => "V8WebGLByteArrayConstructor",
+ "V8CanvasByteArrayCustom" => "V8WebGLByteArrayCustom",
+ "CanvasFloatArray" => "WebGLFloatArray",
+ "canvasFloatArray" => "webGLFloatArray",
+ "CanvasFloatArrayConstructor" => "WebGLFloatArrayConstructor",
+ "CanvasFloatArrayPrototype" => "WebGLFloatArrayPrototype",
+ "toCanvasFloatArray" => "toWebGLFloatArray",
+ "JSCanvasFloatArray" => "JSWebGLFloatArray",
+ "JSCanvasFloatArrayPrototype" => "JSWebGLFloatArrayPrototype",
+ "JSCanvasFloatArrayConstructor" => "JSWebGLFloatArrayConstructor",
+ "JSCanvasFloatArrayCustom" => "JSWebGLFloatArrayCustom",
+ "V8CanvasFloatArray" => "V8WebGLFloatArray",
+ "V8CanvasFloatArrayPrototype" => "V8WebGLFloatArrayPrototype",
+ "V8CanvasFloatArrayConstructor" => "V8WebGLFloatArrayConstructor",
+ "V8CanvasFloatArrayCustom" => "V8WebGLFloatArrayCustom",
+ "CanvasFramebuffer" => "WebGLFramebuffer",
+ "canvasFramebuffer" => "webGLFramebuffer",
+ "CanvasFramebufferConstructor" => "WebGLFramebufferConstructor",
+ "CanvasFramebufferPrototype" => "WebGLFramebufferPrototype",
+ "toCanvasFramebuffer" => "toWebGLFramebuffer",
+ "JSCanvasFramebuffer" => "JSWebGLFramebuffer",
+ "JSCanvasFramebufferPrototype" => "JSWebGLFramebufferPrototype",
+ "JSCanvasFramebufferConstructor" => "JSWebGLFramebufferConstructor",
+ "JSCanvasFramebufferCustom" => "JSWebGLFramebufferCustom",
+ "V8CanvasFramebuffer" => "V8WebGLFramebuffer",
+ "V8CanvasFramebufferPrototype" => "V8WebGLFramebufferPrototype",
+ "V8CanvasFramebufferConstructor" => "V8WebGLFramebufferConstructor",
+ "V8CanvasFramebufferCustom" => "V8WebGLFramebufferCustom",
+ "CanvasIntArray" => "WebGLIntArray",
+ "canvasIntArray" => "webGLIntArray",
+ "CanvasIntArrayConstructor" => "WebGLIntArrayConstructor",
+ "CanvasIntArrayPrototype" => "WebGLIntArrayPrototype",
+ "toCanvasIntArray" => "toWebGLIntArray",
+ "JSCanvasIntArray" => "JSWebGLIntArray",
+ "JSCanvasIntArrayPrototype" => "JSWebGLIntArrayPrototype",
+ "JSCanvasIntArrayConstructor" => "JSWebGLIntArrayConstructor",
+ "JSCanvasIntArrayCustom" => "JSWebGLIntArrayCustom",
+ "V8CanvasIntArray" => "V8WebGLIntArray",
+ "V8CanvasIntArrayPrototype" => "V8WebGLIntArrayPrototype",
+ "V8CanvasIntArrayConstructor" => "V8WebGLIntArrayConstructor",
+ "V8CanvasIntArrayCustom" => "V8WebGLIntArrayCustom",
+ "CanvasProgram" => "WebGLProgram",
+ "canvasProgram" => "webGLProgram",
+ "CanvasProgramConstructor" => "WebGLProgramConstructor",
+ "CanvasProgramPrototype" => "WebGLProgramPrototype",
+ "toCanvasProgram" => "toWebGLProgram",
+ "JSCanvasProgram" => "JSWebGLProgram",
+ "JSCanvasProgramPrototype" => "JSWebGLProgramPrototype",
+ "JSCanvasProgramConstructor" => "JSWebGLProgramConstructor",
+ "JSCanvasProgramCustom" => "JSWebGLProgramCustom",
+ "V8CanvasProgram" => "V8WebGLProgram",
+ "V8CanvasProgramPrototype" => "V8WebGLProgramPrototype",
+ "V8CanvasProgramConstructor" => "V8WebGLProgramConstructor",
+ "V8CanvasProgramCustom" => "V8WebGLProgramCustom",
+ "CanvasRenderbuffer" => "WebGLRenderbuffer",
+ "canvasRenderbuffer" => "webGLRenderbuffer",
+ "CanvasRenderbufferConstructor" => "WebGLRenderbufferConstructor",
+ "CanvasRenderbufferPrototype" => "WebGLRenderbufferPrototype",
+ "toCanvasRenderbuffer" => "toWebGLRenderbuffer",
+ "JSCanvasRenderbuffer" => "JSWebGLRenderbuffer",
+ "JSCanvasRenderbufferPrototype" => "JSWebGLRenderbufferPrototype",
+ "JSCanvasRenderbufferConstructor" => "JSWebGLRenderbufferConstructor",
+ "JSCanvasRenderbufferCustom" => "JSWebGLRenderbufferCustom",
+ "V8CanvasRenderbuffer" => "V8WebGLRenderbuffer",
+ "V8CanvasRenderbufferPrototype" => "V8WebGLRenderbufferPrototype",
+ "V8CanvasRenderbufferConstructor" => "V8WebGLRenderbufferConstructor",
+ "V8CanvasRenderbufferCustom" => "V8WebGLRenderbufferCustom",
+ "CanvasRenderingContext3D" => "WebGLRenderingContext",
+ "canvasRenderingContext3D" => "webGLRenderingContext",
+ "CanvasRenderingContext3DConstructor" => "WebGLRenderingContextConstructor",
+ "CanvasRenderingContext3DPrototype" => "WebGLRenderingContextPrototype",
+ "toCanvasRenderingContext3D" => "toWebGLRenderingContext",
+ "JSCanvasRenderingContext3D" => "JSWebGLRenderingContext",
+ "JSCanvasRenderingContext3DPrototype" => "JSWebGLRenderingContextPrototype",
+ "JSCanvasRenderingContext3DConstructor" => "JSWebGLRenderingContextConstructor",
+ "JSCanvasRenderingContext3DCustom" => "JSWebGLRenderingContextCustom",
+ "V8CanvasRenderingContext3D" => "V8WebGLRenderingContext",
+ "V8CanvasRenderingContext3DPrototype" => "V8WebGLRenderingContextPrototype",
+ "V8CanvasRenderingContext3DConstructor" => "V8WebGLRenderingContextConstructor",
+ "V8CanvasRenderingContext3DCustom" => "V8WebGLRenderingContextCustom",
+ "CanvasShader" => "WebGLShader",
+ "canvasShader" => "webGLShader",
+ "CanvasShaderConstructor" => "WebGLShaderConstructor",
+ "CanvasShaderPrototype" => "WebGLShaderPrototype",
+ "toCanvasShader" => "toWebGLShader",
+ "JSCanvasShader" => "JSWebGLShader",
+ "JSCanvasShaderPrototype" => "JSWebGLShaderPrototype",
+ "JSCanvasShaderConstructor" => "JSWebGLShaderConstructor",
+ "JSCanvasShaderCustom" => "JSWebGLShaderCustom",
+ "V8CanvasShader" => "V8WebGLShader",
+ "V8CanvasShaderPrototype" => "V8WebGLShaderPrototype",
+ "V8CanvasShaderConstructor" => "V8WebGLShaderConstructor",
+ "V8CanvasShaderCustom" => "V8WebGLShaderCustom",
+ "CanvasShortArray" => "WebGLShortArray",
+ "canvasShortArray" => "webGLShortArray",
+ "CanvasShortArrayConstructor" => "WebGLShortArrayConstructor",
+ "CanvasShortArrayPrototype" => "WebGLShortArrayPrototype",
+ "toCanvasShortArray" => "toWebGLShortArray",
+ "JSCanvasShortArray" => "JSWebGLShortArray",
+ "JSCanvasShortArrayPrototype" => "JSWebGLShortArrayPrototype",
+ "JSCanvasShortArrayConstructor" => "JSWebGLShortArrayConstructor",
+ "JSCanvasShortArrayCustom" => "JSWebGLShortArrayCustom",
+ "V8CanvasShortArray" => "V8WebGLShortArray",
+ "V8CanvasShortArrayPrototype" => "V8WebGLShortArrayPrototype",
+ "V8CanvasShortArrayConstructor" => "V8WebGLShortArrayConstructor",
+ "V8CanvasShortArrayCustom" => "V8WebGLShortArrayCustom",
+ "CanvasTexture" => "WebGLTexture",
+ "canvasTexture" => "webGLTexture",
+ "CanvasTextureConstructor" => "WebGLTextureConstructor",
+ "CanvasTexturePrototype" => "WebGLTexturePrototype",
+ "toCanvasTexture" => "toWebGLTexture",
+ "JSCanvasTexture" => "JSWebGLTexture",
+ "JSCanvasTexturePrototype" => "JSWebGLTexturePrototype",
+ "JSCanvasTextureConstructor" => "JSWebGLTextureConstructor",
+ "JSCanvasTextureCustom" => "JSWebGLTextureCustom",
+ "V8CanvasTexture" => "V8WebGLTexture",
+ "V8CanvasTexturePrototype" => "V8WebGLTexturePrototype",
+ "V8CanvasTextureConstructor" => "V8WebGLTextureConstructor",
+ "V8CanvasTextureCustom" => "V8WebGLTextureCustom",
+ "CanvasUnsignedByteArray" => "WebGLUnsignedByteArray",
+ "canvasUnsignedByteArray" => "webGLUnsignedByteArray",
+ "CanvasUnsignedByteArrayConstructor" => "WebGLUnsignedByteArrayConstructor",
+ "CanvasUnsignedByteArrayPrototype" => "WebGLUnsignedByteArrayPrototype",
+ "toCanvasUnsignedByteArray" => "toWebGLUnsignedByteArray",
+ "JSCanvasUnsignedByteArray" => "JSWebGLUnsignedByteArray",
+ "JSCanvasUnsignedByteArrayPrototype" => "JSWebGLUnsignedByteArrayPrototype",
+ "JSCanvasUnsignedByteArrayConstructor" => "JSWebGLUnsignedByteArrayConstructor",
+ "JSCanvasUnsignedByteArrayCustom" => "JSWebGLUnsignedByteArrayCustom",
+ "V8CanvasUnsignedByteArray" => "V8WebGLUnsignedByteArray",
+ "V8CanvasUnsignedByteArrayPrototype" => "V8WebGLUnsignedByteArrayPrototype",
+ "V8CanvasUnsignedByteArrayConstructor" => "V8WebGLUnsignedByteArrayConstructor",
+ "V8CanvasUnsignedByteArrayCustom" => "V8WebGLUnsignedByteArrayCustom",
+ "CanvasUnsignedIntArray" => "WebGLUnsignedIntArray",
+ "canvasUnsignedIntArray" => "webGLUnsignedIntArray",
+ "CanvasUnsignedIntArrayConstructor" => "WebGLUnsignedIntArrayConstructor",
+ "CanvasUnsignedIntArrayPrototype" => "WebGLUnsignedIntArrayPrototype",
+ "toCanvasUnsignedIntArray" => "toWebGLUnsignedIntArray",
+ "JSCanvasUnsignedIntArray" => "JSWebGLUnsignedIntArray",
+ "JSCanvasUnsignedIntArrayPrototype" => "JSWebGLUnsignedIntArrayPrototype",
+ "JSCanvasUnsignedIntArrayConstructor" => "JSWebGLUnsignedIntArrayConstructor",
+ "JSCanvasUnsignedIntArrayCustom" => "JSWebGLUnsignedIntArrayCustom",
+ "V8CanvasUnsignedIntArray" => "V8WebGLUnsignedIntArray",
+ "V8CanvasUnsignedIntArrayPrototype" => "V8WebGLUnsignedIntArrayPrototype",
+ "V8CanvasUnsignedIntArrayConstructor" => "V8WebGLUnsignedIntArrayConstructor",
+ "V8CanvasUnsignedIntArrayCustom" => "V8WebGLUnsignedIntArrayCustom",
+ "CanvasUnsignedShortArray" => "WebGLUnsignedShortArray",
+ "canvasUnsignedShortArray" => "webGLUnsignedShortArray",
+ "CanvasUnsignedShortArrayConstructor" => "WebGLUnsignedShortArrayConstructor",
+ "CanvasUnsignedShortArrayPrototype" => "WebGLUnsignedShortArrayPrototype",
+ "toCanvasUnsignedShortArray" => "toWebGLUnsignedShortArray",
+ "JSCanvasUnsignedShortArray" => "JSWebGLUnsignedShortArray",
+ "JSCanvasUnsignedShortArrayPrototype" => "JSWebGLUnsignedShortArrayPrototype",
+ "JSCanvasUnsignedShortArrayConstructor" => "JSWebGLUnsignedShortArrayConstructor",
+ "JSCanvasUnsignedShortArrayCustom" => "JSWebGLUnsignedShortArrayCustom",
+ "V8CanvasUnsignedShortArray" => "V8WebGLUnsignedShortArray",
+ "V8CanvasUnsignedShortArrayPrototype" => "V8WebGLUnsignedShortArrayPrototype",
+ "V8CanvasUnsignedShortArrayConstructor" => "V8WebGLUnsignedShortArrayConstructor",
+ "V8CanvasUnsignedShortArrayCustom" => "V8WebGLUnsignedShortArrayCustom"
);
my %renamesContemplatedForTheFuture = (
@@ -150,11 +371,18 @@ for my $file (sort @paths) {
}
}
+
+my $isGit = isGit();
+
for my $file (sort @paths) {
if ($newFile{$file}) {
my $newFile = $newFile{$file};
print "Renaming $file to $newFile\n";
- system "svn move $file $newFile";
+ if ($isGit) {
+ system "git mv $file $newFile";
+ } else {
+ system "svn move $file $newFile";
+ }
}
}
@@ -171,8 +399,14 @@ for my $file (sort @paths) {
}
my $newContents = $contents;
- for my $from (keys %renames) {
- $newContents =~ s/\b$from(?!["\w])/$renames{$from}/g; # this " unconfuses Xcode syntax highlighting
+ if ($isDOMTypeRename) {
+ for my $from (keys %renames) {
+ $newContents =~ s/\b$from/$renames{$from}/g;
+ }
+ } else {
+ for my $from (keys %renames) {
+ $newContents =~ s/\b$from(?!["\w])/$renames{$from}/g; # this " unconfuses Xcode syntax highlighting
+ }
}
if ($newContents ne $contents) {
diff --git a/WebKitTools/Scripts/modules/bugzilla.py b/WebKitTools/Scripts/modules/bugzilla.py
index fe81b48..be78544 100644
--- a/WebKitTools/Scripts/modules/bugzilla.py
+++ b/WebKitTools/Scripts/modules/bugzilla.py
@@ -43,7 +43,7 @@ from modules.committers import CommitterList
# WebKit includes a built copy of BeautifulSoup in Scripts/modules
# so this import should always succeed.
-from .BeautifulSoup import BeautifulSoup
+from .BeautifulSoup import BeautifulSoup, SoupStrainer
try:
from mechanize import Browser
@@ -95,10 +95,10 @@ def is_mac_os_x():
def parse_bug_id(message):
match = re.search("http\://webkit\.org/b/(?P<bug_id>\d+)", message)
if match:
- return match.group('bug_id')
+ return int(match.group('bug_id'))
match = re.search(Bugzilla.bug_server_regex + "show_bug\.cgi\?id=(?P<bug_id>\d+)", message)
if match:
- return match.group('bug_id')
+ return int(match.group('bug_id'))
return None
# FIXME: This should not depend on git for config storage
@@ -163,17 +163,20 @@ class Bugzilla:
def _parse_attachment_flag(self, element, flag_name, attachment, result_key):
flag = element.find('flag', attrs={'name' : flag_name})
- if flag and flag['status'] == '+':
- attachment[result_key] = flag['setter']
+ if flag:
+ attachment[flag_name] = flag['status']
+ if flag['status'] == '+':
+ attachment[result_key] = flag['setter']
def _parse_attachment_element(self, element, bug_id):
attachment = {}
attachment['bug_id'] = bug_id
attachment['is_obsolete'] = (element.has_key('isobsolete') and element['isobsolete'] == "1")
attachment['is_patch'] = (element.has_key('ispatch') and element['ispatch'] == "1")
- attachment['id'] = str(element.find('attachid').string)
+ attachment['id'] = int(element.find('attachid').string)
attachment['url'] = self.attachment_url_for_id(attachment['id'])
attachment['name'] = unicode(element.find('desc').string)
+ attachment['attacher_email'] = str(element.find('attacher').string)
attachment['type'] = str(element.find('type').string)
self._parse_attachment_flag(element, 'review', attachment, 'reviewer_email')
self._parse_attachment_flag(element, 'commit-queue', attachment, 'committer_email')
@@ -192,6 +195,36 @@ class Bugzilla:
attachments.append(attachment)
return attachments
+ def _parse_bug_id_from_attachment_page(self, page):
+ up_link = BeautifulSoup(page).find('link', rel='Up') # The "Up" relation happens to point to the bug.
+ if not up_link:
+ return None # This attachment does not exist (or you don't have permissions to view it).
+ match = re.search("show_bug.cgi\?id=(?P<bug_id>\d+)", up_link['href'])
+ return int(match.group('bug_id'))
+
+ def bug_id_for_attachment_id(self, attachment_id):
+ attachment_url = self.attachment_url_for_id(attachment_id, 'edit')
+ log("Fetching: %s" % attachment_url)
+ page = urllib2.urlopen(attachment_url)
+ return self._parse_bug_id_from_attachment_page(page)
+
+ # This should really return an Attachment object
+ # which can lazily fetch any missing data.
+ def fetch_attachment(self, attachment_id):
+ # We could grab all the attachment details off of the attachment edit page
+ # but we already have working code to do so off of the bugs page, so re-use that.
+ bug_id = self.bug_id_for_attachment_id(attachment_id)
+ if not bug_id:
+ return None
+ attachments = self.fetch_attachments_from_bug(bug_id)
+ for attachment in attachments:
+ # FIXME: Once we have a real Attachment class we shouldn't paper over this possible comparison failure
+ # and we should remove the int() == int() hacks and leave it just ==.
+ if int(attachment['id']) == int(attachment_id):
+ self._validate_committer_and_reviewer(attachment)
+ return attachment
+ return None # This should never be hit.
+
def fetch_title_from_bug(self, bug_id):
bug_url = self.bug_url_for_bug_id(bug_id, xml=True)
page = urllib2.urlopen(bug_url)
@@ -209,6 +242,14 @@ class Bugzilla:
def _view_source_link(self, local_path):
return "http://trac.webkit.org/browser/trunk/%s" % local_path
+ def _flag_permission_rejection_message(self, setter_email, flag_name):
+ committer_list = "WebKitTools/Scripts/modules/committers.py"
+ contribution_guidlines_url = "http://webkit.org/coding/contributing.html"
+ rejection_message = "%s does not have %s permissions according to %s." % (setter_email, flag_name, self._view_source_link(committer_list))
+ rejection_message += "\n\n- If you have %s rights please correct the error in %s by adding yourself to the file (no review needed) and then set the %s flag again." % (flag_name, committer_list, flag_name)
+ rejection_message += "\n\n- If you do not have %s rights please read %s for instructions on how to use bugzilla flags." % (flag_name, contribution_guidlines_url)
+ return rejection_message
+
def _validate_setter_email(self, patch, result_key, lookup_function, rejection_function, reject_invalid_patches):
setter_email = patch.get(result_key + '_email')
if not setter_email:
@@ -220,18 +261,30 @@ class Bugzilla:
return patch[result_key]
if reject_invalid_patches:
- committer_list = "WebKitTools/Scripts/modules/committers.py"
- failure_message = "%s does not have %s permissions according to %s." % (setter_email, result_key, self._view_source_link(committer_list))
- rejection_function(patch['id'], failure_message)
+ rejection_function(patch['id'], self._flag_permission_rejection_message(setter_email, result_key))
else:
- log("Warning, attachment %s on bug %s has invalid %s (%s)", (patch['id'], patch['bug_id'], result_key, setter_email))
+ log("Warning, attachment %s on bug %s has invalid %s (%s)" % (patch['id'], patch['bug_id'], result_key, setter_email))
return None
def _validate_reviewer(self, patch, reject_invalid_patches):
- return self._validate_setter_email(patch, 'reviewer', self.committers.reviewer_by_bugzilla_email, self.reject_patch_from_review_queue, reject_invalid_patches)
+ return self._validate_setter_email(patch, 'reviewer', self.committers.reviewer_by_email, self.reject_patch_from_review_queue, reject_invalid_patches)
def _validate_committer(self, patch, reject_invalid_patches):
- return self._validate_setter_email(patch, 'committer', self.committers.committer_by_bugzilla_email, self.reject_patch_from_commit_queue, reject_invalid_patches)
+ return self._validate_setter_email(patch, 'committer', self.committers.committer_by_email, self.reject_patch_from_commit_queue, reject_invalid_patches)
+
+ # FIXME: This is a hack until we have a real Attachment object.
+ # _validate_committer and _validate_reviewer fill in the 'reviewer' and 'committer'
+ # keys which other parts of the code expect to be filled in.
+ def _validate_committer_and_reviewer(self, patch):
+ self._validate_reviewer(patch, reject_invalid_patches=False)
+ self._validate_committer(patch, reject_invalid_patches=False)
+
+ def fetch_unreviewed_patches_from_bug(self, bug_id):
+ unreviewed_patches = []
+ for attachment in self.fetch_attachments_from_bug(bug_id):
+ if attachment.get('review') == '?' and not attachment['is_obsolete']:
+ unreviewed_patches.append(attachment)
+ return unreviewed_patches
def fetch_reviewed_patches_from_bug(self, bug_id, reject_invalid_patches=False):
reviewed_patches = []
@@ -247,20 +300,44 @@ class Bugzilla:
commit_queue_patches.append(attachment)
return commit_queue_patches
- def fetch_bug_ids_from_commit_queue(self):
- commit_queue_url = self.bug_server_url + "buglist.cgi?query_format=advanced&bug_status=UNCONFIRMED&bug_status=NEW&bug_status=ASSIGNED&bug_status=REOPENED&field0-0-0=flagtypes.name&type0-0-0=equals&value0-0-0=commit-queue%2B"
-
- page = urllib2.urlopen(commit_queue_url)
+ def _fetch_bug_ids_advanced_query(self, query):
+ page = urllib2.urlopen(query)
soup = BeautifulSoup(page)
bug_ids = []
# Grab the cells in the first column (which happens to be the bug ids)
for bug_link_cell in soup('td', "first-child"): # tds with the class "first-child"
bug_link = bug_link_cell.find("a")
- bug_ids.append(bug_link.string) # the contents happen to be the bug id
+ bug_ids.append(int(bug_link.string)) # the contents happen to be the bug id
return bug_ids
+ def _parse_attachment_ids_request_query(self, page):
+ digits = re.compile("\d+")
+ attachment_href = re.compile("attachment.cgi\?id=\d+&action=review")
+ attachment_links = SoupStrainer("a", href=attachment_href)
+ return [int(digits.search(tag["href"]).group(0)) for tag in BeautifulSoup(page, parseOnlyThese=attachment_links)]
+
+ def _fetch_attachment_ids_request_query(self, query):
+ return self._parse_attachment_ids_request_query(urllib2.urlopen(query))
+
+ def fetch_bug_ids_from_commit_queue(self):
+ commit_queue_url = self.bug_server_url + "buglist.cgi?query_format=advanced&bug_status=UNCONFIRMED&bug_status=NEW&bug_status=ASSIGNED&bug_status=REOPENED&field0-0-0=flagtypes.name&type0-0-0=equals&value0-0-0=commit-queue%2B"
+ return self._fetch_bug_ids_advanced_query(commit_queue_url)
+
+ # List of all r+'d bugs.
+ def fetch_bug_ids_from_needs_commit_list(self):
+ needs_commit_query_url = self.bug_server_url + "buglist.cgi?query_format=advanced&bug_status=UNCONFIRMED&bug_status=NEW&bug_status=ASSIGNED&bug_status=REOPENED&field0-0-0=flagtypes.name&type0-0-0=equals&value0-0-0=review%2B"
+ return self._fetch_bug_ids_advanced_query(needs_commit_query_url)
+
+ def fetch_bug_ids_from_review_queue(self):
+ review_queue_url = self.bug_server_url + "buglist.cgi?query_format=advanced&bug_status=UNCONFIRMED&bug_status=NEW&bug_status=ASSIGNED&bug_status=REOPENED&field0-0-0=flagtypes.name&type0-0-0=equals&value0-0-0=review?"
+ return self._fetch_bug_ids_advanced_query(review_queue_url)
+
+ def fetch_attachment_ids_from_review_queue(self):
+ review_queue_url = self.bug_server_url + "request.cgi?action=queue&type=review&group=type"
+ return self._fetch_attachment_ids_request_query(review_queue_url)
+
def fetch_patches_from_commit_queue(self, reject_invalid_patches=False):
patches_to_land = []
for bug_id in self.fetch_bug_ids_from_commit_queue():
@@ -268,6 +345,22 @@ class Bugzilla:
patches_to_land += patches
return patches_to_land
+ def fetch_patches_from_pending_commit_list(self):
+ patches_needing_commit = []
+ for bug_id in self.fetch_bug_ids_from_needs_commit_list():
+ patches = self.fetch_reviewed_patches_from_bug(bug_id)
+ patches_needing_commit += patches
+ return patches_needing_commit
+
+ def fetch_patches_from_review_queue(self, limit=None):
+ patches_to_review = []
+ for bug_id in self.fetch_bug_ids_from_review_queue():
+ if limit and len(patches_to_review) >= limit:
+ break
+ patches = self.fetch_unreviewed_patches_from_bug(bug_id)
+ patches_to_review += patches
+ return patches_to_review
+
def authenticate(self):
if self.authenticated:
return
@@ -312,7 +405,7 @@ class Bugzilla:
if self.dryrun:
log(comment_text)
return
-
+
self.browser.open("%sattachment.cgi?action=enter&bugid=%s" % (self.bug_server_url, bug_id))
self.browser.select_form(name="entryform")
self._fill_attachment_form(description, patch_file_object, mark_for_review=mark_for_review, mark_for_commit_queue=mark_for_commit_queue, bug_id=bug_id)
@@ -442,8 +535,20 @@ class Bugzilla:
# Bugzilla has two textareas named 'comment', one is somehow hidden. We want the first.
self.browser.set_value(comment_text, name='comment', nr=0)
self.browser.submit()
-
- def post_comment_to_bug(self, bug_id, comment_text):
+
+ def add_cc_to_bug(self, bug_id, email_address):
+ self.authenticate()
+
+ log("Adding %s to the CC list for bug %s" % (email_address, bug_id))
+ if self.dryrun:
+ return
+
+ self.browser.open(self.bug_url_for_bug_id(bug_id))
+ self.browser.select_form(name="changeform")
+ self.browser["newcc"] = email_address
+ self.browser.submit()
+
+ def post_comment_to_bug(self, bug_id, comment_text, cc=None):
self.authenticate()
log("Adding comment to bug %s" % bug_id)
@@ -453,7 +558,9 @@ class Bugzilla:
self.browser.open(self.bug_url_for_bug_id(bug_id))
self.browser.select_form(name="changeform")
- self.browser['comment'] = comment_text
+ self.browser["comment"] = comment_text
+ if cc:
+ self.browser["newcc"] = cc
self.browser.submit()
def close_bug_as_fixed(self, bug_id, comment_text=None):
diff --git a/WebKitTools/Scripts/modules/bugzilla_unittest.py b/WebKitTools/Scripts/modules/bugzilla_unittest.py
index f08031e..fb7f8c4 100644
--- a/WebKitTools/Scripts/modules/bugzilla_unittest.py
+++ b/WebKitTools/Scripts/modules/bugzilla_unittest.py
@@ -29,7 +29,7 @@
import unittest
from modules.committers import CommitterList, Reviewer, Committer
-from modules.bugzilla import Bugzilla
+from modules.bugzilla import Bugzilla, parse_bug_id
from modules.BeautifulSoup import BeautifulSoup
@@ -61,17 +61,34 @@ class BugzillaTest(unittest.TestCase):
</attachment>
'''
_expected_example_attachment_parsing = {
- 'bug_id' : "100",
+ 'bug_id' : 100,
'is_obsolete' : True,
'is_patch' : True,
- 'id' : "33721",
+ 'id' : 33721,
'url' : "https://bugs.webkit.org/attachment.cgi?id=33721",
'name' : "Fixed whitespace issue",
'type' : "text/plain",
+ 'review' : '+',
'reviewer_email' : 'one@test.com',
- 'committer_email' : 'two@test.com'
+ 'commit-queue' : '+',
+ 'committer_email' : 'two@test.com',
+ 'attacher_email' : 'christian.plesner.hansen@gmail.com',
}
+ def test_parse_bug_id(self):
+ # FIXME: These would be all better as doctests
+ bugs = Bugzilla()
+ self.assertEquals(12345, parse_bug_id("http://webkit.org/b/12345"))
+ self.assertEquals(12345, parse_bug_id("http://bugs.webkit.org/show_bug.cgi?id=12345"))
+ self.assertEquals(12345, parse_bug_id(bugs.short_bug_url_for_bug_id(12345)))
+ self.assertEquals(12345, parse_bug_id(bugs.bug_url_for_bug_id(12345)))
+ self.assertEquals(12345, parse_bug_id(bugs.bug_url_for_bug_id(12345, xml=True)))
+
+ # Our bug parser is super-fragile, but at least we're testing it.
+ self.assertEquals(None, parse_bug_id("http://www.webkit.org/b/12345"))
+ self.assertEquals(None, parse_bug_id("http://bugs.webkit.org/show_bug.cgi?ctype=xml&id=12345"))
+
+
def test_attachment_parsing(self):
bugzilla = Bugzilla()
@@ -86,5 +103,71 @@ class BugzillaTest(unittest.TestCase):
for key, expected_value in self._expected_example_attachment_parsing.items():
self.assertEquals(attachment[key], expected_value, ("Failure for key: %s: Actual='%s' Expected='%s'" % (key, attachment[key], expected_value)))
+ _sample_attachment_detail_page = """
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+ "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <title>
+ Attachment 41073 Details for Bug 27314</title>
+<link rel="Top" href="https://bugs.webkit.org/">
+ <link rel="Up" href="show_bug.cgi?id=27314">
+"""
+
+ def test_attachment_detail_bug_parsing(self):
+ bugzilla = Bugzilla()
+ self.assertEquals(27314, bugzilla._parse_bug_id_from_attachment_page(self._sample_attachment_detail_page))
+
+ _sample_request_page = """
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+ "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <title>Request Queue</title>
+ </head>
+<body>
+
+<h3>Flag: review</h3>
+ <table class="requests" cellspacing="0" cellpadding="4" border="1">
+ <tr>
+ <th>Requester</th>
+ <th>Requestee</th>
+ <th>Bug</th>
+ <th>Attachment</th>
+ <th>Created</th>
+ </tr>
+ <tr>
+ <td>Shinichiro Hamaji &lt;hamaji&#64;chromium.org&gt;</td>
+ <td></td>
+ <td><a href="show_bug.cgi?id=30015">30015: text-transform:capitalize is failing in CSS2.1 test suite</a></td>
+ <td><a href="attachment.cgi?id=40511&amp;action=review">
+40511: Patch v0</a></td>
+ <td>2009-10-02 04:58 PST</td>
+ </tr>
+ <tr>
+ <td>Zan Dobersek &lt;zandobersek&#64;gmail.com&gt;</td>
+ <td></td>
+ <td><a href="show_bug.cgi?id=26304">26304: [GTK] Add controls for playing html5 video.</a></td>
+ <td><a href="attachment.cgi?id=40722&amp;action=review">
+40722: Media controls, the simple approach</a></td>
+ <td>2009-10-06 09:13 PST</td>
+ </tr>
+ <tr>
+ <td>Zan Dobersek &lt;zandobersek&#64;gmail.com&gt;</td>
+ <td></td>
+ <td><a href="show_bug.cgi?id=26304">26304: [GTK] Add controls for playing html5 video.</a></td>
+ <td><a href="attachment.cgi?id=40723&amp;action=review">
+40723: Adjust the media slider thumb size</a></td>
+ <td>2009-10-06 09:15 PST</td>
+ </tr>
+ </table>
+</body>
+</html>
+"""
+
+ def test_request_page_parsing(self):
+ bugzilla = Bugzilla()
+ self.assertEquals([40511, 40722, 40723], bugzilla._parse_attachment_ids_request_query(self._sample_request_page))
+
if __name__ == '__main__':
unittest.main()
diff --git a/WebKitTools/Scripts/modules/buildbot.py b/WebKitTools/Scripts/modules/buildbot.py
index e948d8c..548cad8 100644
--- a/WebKitTools/Scripts/modules/buildbot.py
+++ b/WebKitTools/Scripts/modules/buildbot.py
@@ -39,7 +39,8 @@ from modules.logging import log
from .BeautifulSoup import BeautifulSoup
class BuildBot:
- def __init__(self, host="build.webkit.org"):
+ default_host = "build.webkit.org"
+ def __init__(self, host=default_host):
self.buildbot_host = host
self.buildbot_server_url = "http://%s/" % self.buildbot_host
diff --git a/WebKitTools/Scripts/modules/buildsteps.py b/WebKitTools/Scripts/modules/buildsteps.py
new file mode 100644
index 0000000..425b912
--- /dev/null
+++ b/WebKitTools/Scripts/modules/buildsteps.py
@@ -0,0 +1,254 @@
+# Copyright (C) 2009 Google 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:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * 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.
+# * Neither the name of Google Inc. 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 THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+# OWNER 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.
+
+import os
+
+from optparse import make_option
+
+from modules.comments import bug_comment_from_commit_text
+from modules.logging import log, error
+from modules.webkitport import WebKitPort
+
+
+class CommandOptions(object):
+ force_clean = make_option("--force-clean", action="store_true", dest="force_clean", default=False, help="Clean working directory before applying patches (removes local changes and commits)")
+ clean = make_option("--no-clean", action="store_false", dest="clean", default=True, help="Don't check if the working directory is clean before applying patches")
+ check_builders = make_option("--ignore-builders", action="store_false", dest="check_builders", default=True, help="Don't check to see if the build.webkit.org builders are green before landing.")
+ quiet = make_option("--quiet", action="store_true", dest="quiet", default=False, help="Produce less console output.")
+ non_interactive = make_option("--non-interactive", action="store_true", dest="non_interactive", default=False, help="Never prompt the user, fail as fast as possible.")
+ parent_command = make_option("--parent-command", action="store", dest="parent_command", default=None, help="(Internal) The command that spawned this instance.")
+ update = make_option("--no-update", action="store_false", dest="update", default=True, help="Don't update the working directory.")
+ build = make_option("--no-build", action="store_false", dest="build", default=True, help="Commit without building first, implies --no-test.")
+ test = make_option("--no-test", action="store_false", dest="test", default=True, help="Commit without running run-webkit-tests.")
+ close_bug = make_option("--no-close", action="store_false", dest="close_bug", default=True, help="Leave bug open after landing.")
+ port = make_option("--port", action="store", dest="port", default=None, help="Specify a port (e.g., mac, qt, gtk, ...).")
+
+
+class AbstractStep(object):
+ def __init__(self, tool, options, patch=None):
+ self._tool = tool
+ self._options = options
+ self._patch = patch
+ self._port = None
+
+ def _run_script(self, script_name, quiet=False, port=WebKitPort):
+ log("Running %s" % script_name)
+ self._tool.executive.run_and_throw_if_fail(port.script_path(script_name), quiet)
+
+ # FIXME: The port should live on the tool.
+ def port(self):
+ if self._port:
+ return self._port
+ self._port = WebKitPort.port(self._options.port)
+ return self._port
+
+ @classmethod
+ def options(cls):
+ return []
+
+ def run(self, tool):
+ raise NotImplementedError, "subclasses must implement"
+
+
+class PrepareChangelogStep(AbstractStep):
+ def run(self):
+ self._run_script("prepare-ChangeLog")
+
+
+class CleanWorkingDirectoryStep(AbstractStep):
+ def __init__(self, tool, options, patch=None, allow_local_commits=False):
+ AbstractStep.__init__(self, tool, options, patch)
+ self._allow_local_commits = allow_local_commits
+
+ @classmethod
+ def options(cls):
+ return [
+ CommandOptions.force_clean,
+ CommandOptions.clean,
+ ]
+
+ def run(self):
+ os.chdir(self._tool.scm().checkout_root)
+ if not self._allow_local_commits:
+ self._tool.scm().ensure_no_local_commits(self._options.force_clean)
+ if self._options.clean:
+ self._tool.scm().ensure_clean_working_directory(force_clean=self._options.force_clean)
+
+
+class UpdateStep(AbstractStep):
+ @classmethod
+ def options(cls):
+ return [
+ CommandOptions.update,
+ CommandOptions.port,
+ ]
+
+ def run(self):
+ if not self._options.update:
+ return
+ log("Updating working directory")
+ self._tool.executive.run_and_throw_if_fail(self.port().update_webkit_command())
+
+
+class ApplyPatchStep(AbstractStep):
+ @classmethod
+ def options(cls):
+ return [
+ CommandOptions.non_interactive,
+ ]
+
+ def run(self):
+ log("Processing patch %s from bug %s." % (self._patch["id"], self._patch["bug_id"]))
+ self._tool.scm().apply_patch(self._patch, force=self._options.non_interactive)
+
+
+class EnsureBuildersAreGreenStep(AbstractStep):
+ @classmethod
+ def options(cls):
+ return [
+ CommandOptions.check_builders,
+ ]
+
+ def run(self):
+ if not self._options.check_builders:
+ return
+ red_builders_names = self._tool.buildbot.red_core_builders_names()
+ if not red_builders_names:
+ return
+ red_builders_names = map(lambda name: "\"%s\"" % name, red_builders_names) # Add quotes around the names.
+ error("Builders [%s] are red, please do not commit.\nSee http://%s.\nPass --ignore-builders to bypass this check." % (", ".join(red_builders_names), self._tool.buildbot.buildbot_host))
+
+
+class BuildStep(AbstractStep):
+ @classmethod
+ def options(cls):
+ return [
+ CommandOptions.build,
+ CommandOptions.quiet,
+ ]
+
+ def run(self):
+ if not self._options.build:
+ return
+ log("Building WebKit")
+ self._tool.executive.run_and_throw_if_fail(self.port().build_webkit_command(), self._options.quiet)
+
+
+class CheckStyleStep(AbstractStep):
+ def run(self):
+ self._run_script("check-webkit-style")
+
+
+class RunTestsStep(AbstractStep):
+ @classmethod
+ def options(cls):
+ return [
+ CommandOptions.build,
+ CommandOptions.test,
+ CommandOptions.non_interactive,
+ CommandOptions.quiet,
+ CommandOptions.port,
+ ]
+
+ def run(self):
+ if not self._options.build:
+ return
+ if not self._options.test:
+ return
+ args = self.port().run_webkit_tests_command()
+ if self._options.non_interactive:
+ args.append("--no-launch-safari")
+ args.append("--exit-after-n-failures=1")
+ if self._options.quiet:
+ args.append("--quiet")
+ self._tool.executive.run_and_throw_if_fail(args)
+
+
+class CommitStep(AbstractStep):
+ def run(self):
+ commit_message = self._tool.scm().commit_message_for_this_commit()
+ return self._tool.scm().commit_with_message(commit_message.message())
+
+
+class ClosePatchStep(AbstractStep):
+ def run(self, commit_log):
+ comment_text = bug_comment_from_commit_text(self._tool.scm(), commit_log)
+ self._tool.bugs.clear_attachment_flags(self._patch["id"], comment_text)
+
+
+class CloseBugStep(AbstractStep):
+ @classmethod
+ def options(cls):
+ return [
+ CommandOptions.close_bug,
+ ]
+
+ def run(self):
+ if not self._options.close_bug:
+ return
+ # Check to make sure there are no r? or r+ patches on the bug before closing.
+ # Assume that r- patches are just previous patches someone forgot to obsolete.
+ patches = self._tool.bugs.fetch_patches_from_bug(self._patch["bug_id"])
+ for patch in patches:
+ review_flag = patch.get("review")
+ if review_flag == "?" or review_flag == "+":
+ log("Not closing bug %s as attachment %s has review=%s. Assuming there are more patches to land from this bug." % (patch["bug_id"], patch["id"], review_flag))
+ return
+ self._tool.bugs.close_bug_as_fixed(self._patch["bug_id"], "All reviewed patches have been landed. Closing bug.")
+
+
+# FIXME: This class is a dinosaur and should be extinct soon.
+class BuildSteps:
+ # FIXME: The options should really live on each "Step" object.
+ @staticmethod
+ def cleaning_options():
+ return [
+ CommandOptions.force_clean,
+ CommandOptions.clean,
+ ]
+
+ # FIXME: These distinctions are bogus. We need a better model for handling options.
+ @staticmethod
+ def build_options():
+ return [
+ CommandOptions.check_builders,
+ CommandOptions.quiet,
+ CommandOptions.non_interactive,
+ CommandOptions.parent_command,
+ CommandOptions.port,
+ ]
+
+ @staticmethod
+ def land_options():
+ return [
+ CommandOptions.update,
+ CommandOptions.build,
+ CommandOptions.test,
+ CommandOptions.close_bug,
+ ]
+
diff --git a/WebKitTools/Scripts/modules/commands/__init__.py b/WebKitTools/Scripts/modules/commands/__init__.py
new file mode 100644
index 0000000..ef65bee
--- /dev/null
+++ b/WebKitTools/Scripts/modules/commands/__init__.py
@@ -0,0 +1 @@
+# Required for Python to search this directory for module files
diff --git a/WebKitTools/Scripts/modules/commands/commandtest.py b/WebKitTools/Scripts/modules/commands/commandtest.py
new file mode 100644
index 0000000..618a517
--- /dev/null
+++ b/WebKitTools/Scripts/modules/commands/commandtest.py
@@ -0,0 +1,42 @@
+# Copyright (C) 2009 Google 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:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * 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.
+# * Neither the name of Google Inc. 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 THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+# OWNER 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.
+
+import unittest
+
+from modules.mock import Mock
+from modules.mock_bugzillatool import MockBugzillaTool
+from modules.outputcapture import OutputCapture
+
+class CommandsTest(unittest.TestCase):
+ def assert_execute_outputs(self, command, args, expected_stdout="", expected_stderr="", options=Mock(), tool=MockBugzillaTool()):
+ capture = OutputCapture()
+ capture.capture_output()
+ command.execute(options, args, tool)
+ (stdout_string, stderr_string) = capture.restore_output()
+ self.assertEqual(stdout_string, expected_stdout)
+ self.assertEqual(expected_stderr, expected_stderr)
diff --git a/WebKitTools/Scripts/modules/commands/download.py b/WebKitTools/Scripts/modules/commands/download.py
new file mode 100644
index 0000000..2acd69f
--- /dev/null
+++ b/WebKitTools/Scripts/modules/commands/download.py
@@ -0,0 +1,370 @@
+#!/usr/bin/env python
+# Copyright (c) 2009, Google Inc. All rights reserved.
+# Copyright (c) 2009 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:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * 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.
+# * Neither the name of Google Inc. 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 THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+# OWNER 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.
+
+import os
+
+from optparse import make_option
+
+from modules.bugzilla import parse_bug_id
+from modules.buildsteps import CommandOptions, BuildSteps, EnsureBuildersAreGreenStep, CleanWorkingDirectoryStep, UpdateStep, ApplyPatchStep, BuildStep, CheckStyleStep, PrepareChangelogStep
+from modules.changelogs import ChangeLog
+from modules.comments import bug_comment_from_commit_text
+from modules.executive import ScriptError
+from modules.grammar import pluralize
+from modules.landingsequence import LandingSequence
+from modules.logging import error, log
+from modules.multicommandtool import Command
+from modules.stepsequence import StepSequence
+
+
+class Build(Command):
+ name = "build"
+ show_in_main_help = False
+ def __init__(self):
+ self._sequence = StepSequence([
+ CleanWorkingDirectoryStep,
+ UpdateStep,
+ BuildStep
+ ])
+ Command.__init__(self, "Update working copy and build", "", self._sequence.options())
+
+ def execute(self, options, args, tool):
+ self._sequence.run_and_handle_errors(tool, options)
+
+
+class ApplyAttachment(Command):
+ name = "apply-attachment"
+ show_in_main_help = True
+ def __init__(self):
+ options = WebKitApplyingScripts.apply_options()
+ options += BuildSteps.cleaning_options()
+ Command.__init__(self, "Apply an attachment to the local working directory", "ATTACHMENT_ID", options=options)
+
+ def execute(self, options, args, tool):
+ WebKitApplyingScripts.setup_for_patch_apply(tool, options)
+ attachment_id = args[0]
+ attachment = tool.bugs.fetch_attachment(attachment_id)
+ WebKitApplyingScripts.apply_patches_with_options(tool.scm(), [attachment], options)
+
+
+class ApplyPatches(Command):
+ name = "apply-patches"
+ show_in_main_help = True
+ def __init__(self):
+ options = WebKitApplyingScripts.apply_options()
+ options += BuildSteps.cleaning_options()
+ Command.__init__(self, "Apply reviewed patches from provided bugs to the local working directory", "BUGID", options=options)
+
+ def execute(self, options, args, tool):
+ WebKitApplyingScripts.setup_for_patch_apply(tool, options)
+ bug_id = args[0]
+ patches = tool.bugs.fetch_reviewed_patches_from_bug(bug_id)
+ WebKitApplyingScripts.apply_patches_with_options(tool.scm(), patches, options)
+
+
+class WebKitApplyingScripts:
+ @staticmethod
+ def apply_options():
+ return [
+ make_option("--no-update", action="store_false", dest="update", default=True, help="Don't update the working directory before applying patches"),
+ make_option("--local-commit", action="store_true", dest="local_commit", default=False, help="Make a local commit for each applied patch"),
+ CommandOptions.port,
+ ]
+
+ @staticmethod
+ def setup_for_patch_apply(tool, options):
+ clean_step = CleanWorkingDirectoryStep(tool, options, allow_local_commits=True)
+ clean_step.run()
+ update_step = UpdateStep(tool, options)
+ update_step.run()
+
+ @staticmethod
+ def apply_patches_with_options(scm, patches, options):
+ if options.local_commit and not scm.supports_local_commits():
+ error("--local-commit passed, but %s does not support local commits" % scm.display_name())
+
+ for patch in patches:
+ log("Applying attachment %s from bug %s" % (patch["id"], patch["bug_id"]))
+ scm.apply_patch(patch)
+ if options.local_commit:
+ commit_message = scm.commit_message_for_this_commit()
+ scm.commit_locally_with_message(commit_message.message() or patch["name"])
+
+
+class LandDiffSequence(LandingSequence):
+ def run(self):
+ self.check_builders()
+ self.build()
+ self.test()
+ commit_log = self.commit()
+ self.close_bug(commit_log)
+
+ def close_bug(self, commit_log):
+ comment_test = bug_comment_from_commit_text(self._tool.scm(), commit_log)
+ bug_id = self._patch["bug_id"]
+ if bug_id:
+ log("Updating bug %s" % bug_id)
+ if self._options.close_bug:
+ self._tool.bugs.close_bug_as_fixed(bug_id, comment_test)
+ else:
+ # FIXME: We should a smart way to figure out if the patch is attached
+ # to the bug, and if so obsolete it.
+ self._tool.bugs.post_comment_to_bug(bug_id, comment_test)
+ else:
+ log(comment_test)
+ log("No bug id provided.")
+
+
+class LandDiff(Command):
+ name = "land-diff"
+ show_in_main_help = True
+ def __init__(self):
+ options = [
+ make_option("-r", "--reviewer", action="store", type="string", dest="reviewer", help="Update ChangeLogs to say Reviewed by REVIEWER."),
+ ]
+ options += BuildSteps.build_options()
+ options += BuildSteps.land_options()
+ Command.__init__(self, "Land the current working directory diff and updates the associated bug if any", "[BUGID]", options=options)
+
+ def guess_reviewer_from_bug(self, bugs, bug_id):
+ patches = bugs.fetch_reviewed_patches_from_bug(bug_id)
+ if len(patches) != 1:
+ log("%s on bug %s, cannot infer reviewer." % (pluralize("reviewed patch", len(patches)), bug_id))
+ return None
+ patch = patches[0]
+ reviewer = patch["reviewer"]
+ log("Guessing \"%s\" as reviewer from attachment %s on bug %s." % (reviewer, patch["id"], bug_id))
+ return reviewer
+
+ def update_changelogs_with_reviewer(self, reviewer, bug_id, tool):
+ if not reviewer:
+ if not bug_id:
+ log("No bug id provided and --reviewer= not provided. Not updating ChangeLogs with reviewer.")
+ return
+ reviewer = self.guess_reviewer_from_bug(tool.bugs, bug_id)
+
+ if not reviewer:
+ log("Failed to guess reviewer from bug %s and --reviewer= not provided. Not updating ChangeLogs with reviewer." % bug_id)
+ return
+
+ for changelog_path in tool.scm().modified_changelogs():
+ ChangeLog(changelog_path).set_reviewer(reviewer)
+
+ def execute(self, options, args, tool):
+ bug_id = (args and args[0]) or parse_bug_id(tool.scm().create_patch())
+
+ EnsureBuildersAreGreenStep(tool, options).run()
+
+ os.chdir(tool.scm().checkout_root)
+ self.update_changelogs_with_reviewer(options.reviewer, bug_id, tool)
+
+ fake_patch = {
+ "id": None,
+ "bug_id": bug_id
+ }
+
+ sequence = LandDiffSequence(fake_patch, options, tool)
+ sequence.run()
+
+
+class AbstractPatchProcessingCommand(Command):
+ def __init__(self, help_text, args_description, options):
+ Command.__init__(self, help_text, args_description, options=options)
+
+ def _fetch_list_of_patches_to_process(self, options, args, tool):
+ raise NotImplementedError, "subclasses must implement"
+
+ def _prepare_to_process(self, options, args, tool):
+ raise NotImplementedError, "subclasses must implement"
+
+ @staticmethod
+ def _collect_patches_by_bug(patches):
+ bugs_to_patches = {}
+ for patch in patches:
+ bug_id = patch["bug_id"]
+ bugs_to_patches[bug_id] = bugs_to_patches.get(bug_id, []) + [patch]
+ return bugs_to_patches
+
+ def execute(self, options, args, tool):
+ self._prepare_to_process(options, args, tool)
+ patches = self._fetch_list_of_patches_to_process(options, args, tool)
+
+ # It's nice to print out total statistics.
+ bugs_to_patches = self._collect_patches_by_bug(patches)
+ log("Processing %s from %s." % (pluralize("patch", len(patches)), pluralize("bug", len(bugs_to_patches))))
+
+ for patch in patches:
+ self._process_patch(patch, options, args, tool)
+
+
+class CheckStyle(AbstractPatchProcessingCommand):
+ name = "check-style"
+ show_in_main_help = False
+ def __init__(self):
+ self._sequence = StepSequence([
+ CleanWorkingDirectoryStep,
+ UpdateStep,
+ ApplyPatchStep,
+ CheckStyleStep,
+ ])
+ AbstractPatchProcessingCommand.__init__(self, "Run check-webkit-style on the specified attachments", "ATTACHMENT_ID [ATTACHMENT_IDS]", self._sequence.options())
+
+ def _fetch_list_of_patches_to_process(self, options, args, tool):
+ return map(lambda patch_id: tool.bugs.fetch_attachment(patch_id), args)
+
+ def _prepare_to_process(self, options, args, tool):
+ pass
+
+ def _process_patch(self, patch, options, args, tool):
+ self._sequence.run_and_handle_errors(tool, options, patch)
+
+
+class BuildAttachment(AbstractPatchProcessingCommand):
+ name = "build-attachment"
+ show_in_main_help = False
+ def __init__(self):
+ self._sequence = StepSequence([
+ CleanWorkingDirectoryStep,
+ UpdateStep,
+ ApplyPatchStep,
+ BuildStep,
+ ])
+ AbstractPatchProcessingCommand.__init__(self, "Apply and build patches from bugzilla", "ATTACHMENT_ID [ATTACHMENT_IDS]", self._sequence.options())
+
+ def _fetch_list_of_patches_to_process(self, options, args, tool):
+ return map(lambda patch_id: tool.bugs.fetch_attachment(patch_id), args)
+
+ def _prepare_to_process(self, options, args, tool):
+ pass
+
+ def _process_patch(self, patch, options, args, tool):
+ self._sequence.run_and_handle_errors(tool, options, patch)
+
+
+class AbstractPatchLandingCommand(AbstractPatchProcessingCommand):
+ def __init__(self, help_text, args_description):
+ options = BuildSteps.cleaning_options()
+ options += BuildSteps.build_options()
+ options += BuildSteps.land_options()
+ AbstractPatchProcessingCommand.__init__(self, help_text, args_description, options)
+
+ def _prepare_to_process(self, options, args, tool):
+ # Check the tree status first so we can fail early.
+ EnsureBuildersAreGreenStep(tool, options).run()
+
+ def _process_patch(self, patch, options, args, tool):
+ sequence = LandingSequence(patch, options, tool)
+ sequence.run_and_handle_errors()
+
+
+class LandAttachment(AbstractPatchLandingCommand):
+ name = "land-attachment"
+ show_in_main_help = True
+ def __init__(self):
+ AbstractPatchLandingCommand.__init__(self, "Land patches from bugzilla, optionally building and testing them first", "ATTACHMENT_ID [ATTACHMENT_IDS]")
+
+ def _fetch_list_of_patches_to_process(self, options, args, tool):
+ return map(lambda patch_id: tool.bugs.fetch_attachment(patch_id), args)
+
+
+class LandPatches(AbstractPatchLandingCommand):
+ name = "land-patches"
+ show_in_main_help = True
+ def __init__(self):
+ AbstractPatchLandingCommand.__init__(self, "Land all patches on the given bugs, optionally building and testing them first", "BUGID [BUGIDS]")
+
+ def _fetch_list_of_patches_to_process(self, options, args, tool):
+ all_patches = []
+ for bug_id in args:
+ patches = tool.bugs.fetch_reviewed_patches_from_bug(bug_id)
+ log("%s found on bug %s." % (pluralize("reviewed patch", len(patches)), bug_id))
+ all_patches += patches
+ return all_patches
+
+
+# FIXME: Requires unit test.
+class Rollout(Command):
+ name = "rollout"
+ show_in_main_help = True
+ def __init__(self):
+ options = BuildSteps.cleaning_options()
+ options += BuildSteps.build_options()
+ options += BuildSteps.land_options()
+ options.append(make_option("--complete-rollout", action="store_true", dest="complete_rollout", help="Commit the revert and re-open the original bug."))
+ Command.__init__(self, "Revert the given revision in the working copy and optionally commit the revert and re-open the original bug", "REVISION [BUGID]", options=options)
+
+ @staticmethod
+ def _create_changelogs_for_revert(tool, revision):
+ # First, discard the ChangeLog changes from the rollout.
+ changelog_paths = tool.scm().modified_changelogs()
+ tool.scm().revert_files(changelog_paths)
+
+ # Second, make new ChangeLog entries for this rollout.
+ # This could move to prepare-ChangeLog by adding a --revert= option.
+ PrepareChangelogStep(tool, None).run()
+ for changelog_path in changelog_paths:
+ ChangeLog(changelog_path).update_for_revert(revision)
+
+ @staticmethod
+ def _parse_bug_id_from_revision_diff(tool, revision):
+ original_diff = tool.scm().diff_for_revision(revision)
+ return parse_bug_id(original_diff)
+
+ @staticmethod
+ def _reopen_bug_after_rollout(tool, bug_id, comment_text):
+ if bug_id:
+ tool.bugs.reopen_bug(bug_id, comment_text)
+ else:
+ log(comment_text)
+ log("No bugs were updated or re-opened to reflect this rollout.")
+
+ def execute(self, options, args, tool):
+ revision = args[0]
+ bug_id = self._parse_bug_id_from_revision_diff(tool, revision)
+ if options.complete_rollout:
+ if bug_id:
+ log("Will re-open bug %s after rollout." % bug_id)
+ else:
+ log("Failed to parse bug number from diff. No bugs will be updated/reopened after the rollout.")
+
+ CleanWorkingDirectoryStep(tool, options).run()
+ UpdateStep(tool, options).run()
+ tool.scm().apply_reverse_diff(revision)
+ self._create_changelogs_for_revert(tool, revision)
+
+ # FIXME: Fully automated rollout is not 100% idiot-proof yet, so for now just log with instructions on how to complete the rollout.
+ # Once we trust rollout we will remove this option.
+ if not options.complete_rollout:
+ log("\nNOTE: Rollout support is experimental.\nPlease verify the rollout diff and use \"bugzilla-tool land-diff %s\" to commit the rollout." % bug_id)
+ else:
+ # FIXME: This function does not exist!!
+ # comment_text = WebKitLandingScripts.build_and_commit(tool.scm(), options)
+ raise ScriptError("OOPS! This option is not implemented (yet).")
+ self._reopen_bug_after_rollout(tool, bug_id, comment_text)
diff --git a/WebKitTools/Scripts/modules/commands/download_unittest.py b/WebKitTools/Scripts/modules/commands/download_unittest.py
new file mode 100644
index 0000000..a1ed41a
--- /dev/null
+++ b/WebKitTools/Scripts/modules/commands/download_unittest.py
@@ -0,0 +1,77 @@
+# Copyright (C) 2009 Google 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:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * 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.
+# * Neither the name of Google Inc. 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 THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+# OWNER 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.
+
+import unittest
+
+from modules.commands.commandtest import CommandsTest
+from modules.commands.download import *
+from modules.mock import Mock
+
+class DownloadCommandsTest(CommandsTest):
+ def _default_options(self):
+ options = Mock()
+ options.force_clean = False
+ options.clean = True
+ options.check_builders = True
+ options.quiet = False
+ options.non_interactive = False
+ options.update = True
+ options.build = True
+ options.test = True
+ options.close_bug = True
+ return options
+
+ def test_build(self):
+ self.assert_execute_outputs(Build(), [], options=self._default_options())
+
+ def test_apply_attachment(self):
+ options = self._default_options()
+ options.update = True
+ options.local_commit = True
+ self.assert_execute_outputs(ApplyAttachment(), [197], options=options)
+
+ def test_apply_patches(self):
+ options = self._default_options()
+ options.update = True
+ options.local_commit = True
+ self.assert_execute_outputs(ApplyPatches(), [42], options=options)
+
+ def test_land_diff(self):
+ self.assert_execute_outputs(LandDiff(), [42], options=self._default_options())
+
+ def test_check_style(self):
+ self.assert_execute_outputs(CheckStyle(), [197], options=self._default_options())
+
+ def test_build_attachment(self):
+ self.assert_execute_outputs(BuildAttachment(), [197], options=self._default_options())
+
+ def test_land_attachment(self):
+ self.assert_execute_outputs(LandAttachment(), [197], options=self._default_options())
+
+ def test_land_patches(self):
+ self.assert_execute_outputs(LandPatches(), [42], options=self._default_options())
diff --git a/WebKitTools/Scripts/modules/commands/early_warning_system.py b/WebKitTools/Scripts/modules/commands/early_warning_system.py
new file mode 100644
index 0000000..e8ef408
--- /dev/null
+++ b/WebKitTools/Scripts/modules/commands/early_warning_system.py
@@ -0,0 +1,66 @@
+#!/usr/bin/env python
+# Copyright (c) 2009, Google 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:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * 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.
+# * Neither the name of Google Inc. 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 THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+# OWNER 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.
+
+from modules.commands.queues import AbstractReviewQueue
+from modules.executive import ScriptError
+from modules.webkitport import WebKitPort
+
+class AbstractEarlyWarningSystem(AbstractReviewQueue):
+ def __init__(self):
+ AbstractReviewQueue.__init__(self)
+ self.port = WebKitPort.port(self.port_name)
+
+ def should_proceed_with_work_item(self, patch):
+ try:
+ self.run_bugzilla_tool(["build", self.port.flag(), "--force-clean", "--quiet"])
+ except ScriptError, e:
+ return (False, "Unable to perform a build.", None)
+ return (True, "Building patch %s on bug %s." % (patch["id"], patch["bug_id"]), patch)
+
+ def process_work_item(self, patch):
+ self.run_bugzilla_tool([
+ "build-attachment",
+ self.port.flag(),
+ "--force-clean",
+ "--quiet",
+ "--non-interactive",
+ "--parent-command=%s" % self.name,
+ "--no-update",
+ patch["id"]])
+ self._patches.did_pass(patch)
+
+
+class QtEWS(AbstractEarlyWarningSystem):
+ name = "qt-ews"
+ port_name = "qt"
+
+
+class ChromiumEWS(AbstractEarlyWarningSystem):
+ name = "chromium-ews"
+ port_name = "chromium"
diff --git a/WebKitTools/Scripts/modules/commands/queries.py b/WebKitTools/Scripts/modules/commands/queries.py
new file mode 100644
index 0000000..98310e3
--- /dev/null
+++ b/WebKitTools/Scripts/modules/commands/queries.py
@@ -0,0 +1,135 @@
+#!/usr/bin/env python
+# Copyright (c) 2009, Google Inc. All rights reserved.
+# Copyright (c) 2009 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:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * 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.
+# * Neither the name of Google Inc. 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 THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+# OWNER 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.
+
+
+from optparse import make_option
+
+from modules.buildbot import BuildBot
+from modules.committers import CommitterList
+from modules.logging import log
+from modules.multicommandtool import Command
+
+
+class BugsToCommit(Command):
+ name = "bugs-to-commit"
+ show_in_main_help = False
+ def __init__(self):
+ Command.__init__(self, "List bugs in the commit-queue")
+
+ def execute(self, options, args, tool):
+ bug_ids = tool.bugs.fetch_bug_ids_from_commit_queue()
+ for bug_id in bug_ids:
+ print "%s" % bug_id
+
+
+class PatchesToCommit(Command):
+ name = "patches-to-commit"
+ show_in_main_help = False
+ def __init__(self):
+ Command.__init__(self, "List patches in the commit-queue")
+
+ def execute(self, options, args, tool):
+ patches = tool.bugs.fetch_patches_from_commit_queue()
+ log("Patches in commit queue:")
+ for patch in patches:
+ print "%s" % patch["url"]
+
+
+class PatchesToCommitQueue(Command):
+ name = "patches-to-commit-queue"
+ show_in_main_help = False
+ def __init__(self):
+ options = [
+ make_option("--bugs", action="store_true", dest="bugs", help="Output bug links instead of patch links"),
+ ]
+ Command.__init__(self, "Patches which should be added to the commit queue", options=options)
+
+ @staticmethod
+ def _needs_commit_queue(patch):
+ commit_queue_flag = patch.get("commit-queue")
+ if (commit_queue_flag and commit_queue_flag == '+'): # If it's already cq+, ignore the patch.
+ log("%s already has cq=%s" % (patch["id"], commit_queue_flag))
+ return False
+
+ # We only need to worry about patches from contributers who are not yet committers.
+ committer_record = CommitterList().committer_by_email(patch["attacher_email"])
+ if committer_record:
+ log("%s committer = %s" % (patch["id"], committer_record))
+ return not committer_record
+
+ def execute(self, options, args, tool):
+ patches = tool.bugs.fetch_patches_from_pending_commit_list()
+ patches_needing_cq = filter(self._needs_commit_queue, patches)
+ if options.bugs:
+ bugs_needing_cq = map(lambda patch: patch['bug_id'], patches_needing_cq)
+ bugs_needing_cq = sorted(set(bugs_needing_cq))
+ for bug_id in bugs_needing_cq:
+ print "%s" % tool.bugs.bug_url_for_bug_id(bug_id)
+ else:
+ for patch in patches_needing_cq:
+ print "%s" % tool.bugs.attachment_url_for_id(patch["id"], action="edit")
+
+
+class PatchesToReview(Command):
+ name = "patches-to-review"
+ show_in_main_help = False
+ def __init__(self):
+ Command.__init__(self, "List patches that are pending review")
+
+ def execute(self, options, args, tool):
+ patch_ids = tool.bugs.fetch_attachment_ids_from_review_queue()
+ log("Patches pending review:")
+ for patch_id in patch_ids:
+ print patch_id
+
+
+class ReviewedPatches(Command):
+ name = "reviewed-patches"
+ show_in_main_help = False
+ def __init__(self):
+ Command.__init__(self, "List r+'d patches on a bug", "BUGID")
+
+ def execute(self, options, args, tool):
+ bug_id = args[0]
+ patches_to_land = tool.bugs.fetch_reviewed_patches_from_bug(bug_id)
+ for patch in patches_to_land:
+ print "%s" % patch["url"]
+
+
+class TreeStatus(Command):
+ name = "tree-status"
+ show_in_main_help = True
+ def __init__(self):
+ Command.__init__(self, "Print the status of the %s buildbots" % BuildBot.default_host)
+
+ def execute(self, options, args, tool):
+ for builder in tool.buildbot.builder_statuses():
+ status_string = "ok" if builder["is_green"] else "FAIL"
+ print "%s : %s" % (status_string.ljust(4), builder["name"])
diff --git a/WebKitTools/Scripts/modules/commands/queries_unittest.py b/WebKitTools/Scripts/modules/commands/queries_unittest.py
new file mode 100644
index 0000000..0d1c82a
--- /dev/null
+++ b/WebKitTools/Scripts/modules/commands/queries_unittest.py
@@ -0,0 +1,68 @@
+# Copyright (C) 2009 Google 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:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * 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.
+# * Neither the name of Google Inc. 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 THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+# OWNER 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.
+
+import unittest
+
+from modules.bugzilla import Bugzilla
+from modules.commands.commandtest import CommandsTest
+from modules.commands.queries import *
+from modules.mock import Mock
+from modules.mock_bugzillatool import MockBugzillaTool
+
+class QueryCommandsTest(CommandsTest):
+ def test_bugs_to_commit(self):
+ self.assert_execute_outputs(BugsToCommit(), None, "42\n75\n")
+
+ def test_patches_to_commit(self):
+ expected_stdout = "http://example.com/197\nhttp://example.com/128\n"
+ expected_stderr = "Patches in commit queue:\n"
+ self.assert_execute_outputs(PatchesToCommit(), None, expected_stdout, expected_stderr)
+
+ def test_patches_to_commit_queue(self):
+ expected_stdout = "http://example.com/197&action=edit\nhttp://example.com/128&action=edit\n"
+ expected_stderr = ""
+ options = Mock()
+ options.bugs = False
+ self.assert_execute_outputs(PatchesToCommitQueue(), None, expected_stdout, expected_stderr, options=options)
+
+ expected_stdout = "http://example.com/42\n"
+ options.bugs = True
+ self.assert_execute_outputs(PatchesToCommitQueue(), None, expected_stdout, expected_stderr, options=options)
+
+ def test_patches_to_review(self):
+ expected_stdout = "197\n128\n"
+ expected_stderr = "Patches pending review:\n"
+ self.assert_execute_outputs(PatchesToReview(), None, expected_stdout, expected_stderr)
+
+ def test_reviewed_patches(self):
+ expected_stdout = "http://example.com/197\nhttp://example.com/128\n"
+ self.assert_execute_outputs(ReviewedPatches(), [42], expected_stdout)
+
+ def test_tree_status(self):
+ expected_stdout = "ok : Builder1\nok : Builder2\n"
+ self.assert_execute_outputs(TreeStatus(), None, expected_stdout)
diff --git a/WebKitTools/Scripts/modules/commands/queues.py b/WebKitTools/Scripts/modules/commands/queues.py
new file mode 100644
index 0000000..53b9e48
--- /dev/null
+++ b/WebKitTools/Scripts/modules/commands/queues.py
@@ -0,0 +1,216 @@
+#!/usr/bin/env python
+# Copyright (c) 2009, Google Inc. All rights reserved.
+# Copyright (c) 2009 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:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * 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.
+# * Neither the name of Google Inc. 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 THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+# OWNER 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.
+
+import re
+
+from datetime import datetime
+from optparse import make_option
+
+from modules.executive import ScriptError
+from modules.grammar import pluralize
+from modules.landingsequence import LandingSequence, LandingSequenceErrorHandler
+from modules.logging import error, log
+from modules.multicommandtool import Command
+from modules.patchcollection import PersistentPatchCollection, PersistentPatchCollectionDelegate
+from modules.statusbot import StatusBot
+from modules.workqueue import WorkQueue, WorkQueueDelegate
+
+class AbstractQueue(Command, WorkQueueDelegate):
+ show_in_main_help = False
+ watchers = "webkit-bot-watchers@googlegroups.com"
+ def __init__(self, options=None): # Default values should never be collections (like []) as default values are shared between invocations
+ options_list = (options or []) + [
+ make_option("--no-confirm", action="store_false", dest="confirm", default=True, help="Do not ask the user for confirmation before running the queue. Dangerous!"),
+ make_option("--status-host", action="store", type="string", dest="status_host", default=StatusBot.default_host, help="Hostname (e.g. localhost or commit.webkit.org) where status updates should be posted."),
+ ]
+ Command.__init__(self, "Run the %s" % self.name, options=options_list)
+
+ def _cc_watchers(self, bug_id):
+ try:
+ self.tool.bugs.add_cc_to_bug(bug_id, self.watchers)
+ except Exception, e:
+ log("Failed to CC watchers: %s." % e)
+
+ def queue_log_path(self):
+ return "%s.log" % self.name
+
+ def work_logs_directory(self):
+ return "%s-logs" % self.name
+
+ def status_host(self):
+ return self.options.status_host
+
+ def begin_work_queue(self):
+ log("CAUTION: %s will discard all local changes in %s" % (self.name, self.tool.scm().checkout_root))
+ if self.options.confirm:
+ response = raw_input("Are you sure? Type \"yes\" to continue: ")
+ if (response != "yes"):
+ error("User declined.")
+ log("Running WebKit %s. %s" % (self.name, datetime.now().strftime(WorkQueue.log_date_format)))
+
+ def should_continue_work_queue(self):
+ return True
+
+ def next_work_item(self):
+ raise NotImplementedError, "subclasses must implement"
+
+ def should_proceed_with_work_item(self, work_item):
+ raise NotImplementedError, "subclasses must implement"
+
+ def process_work_item(self, work_item):
+ raise NotImplementedError, "subclasses must implement"
+
+ def handle_unexpected_error(self, work_item, message):
+ raise NotImplementedError, "subclasses must implement"
+
+ def run_bugzilla_tool(self, args):
+ bugzilla_tool_args = [self.tool.path()] + map(str, args)
+ self.tool.executive.run_and_throw_if_fail(bugzilla_tool_args)
+
+ def log_progress(self, patch_ids):
+ log("%s in %s [%s]" % (pluralize("patch", len(patch_ids)), self.name, ", ".join(map(str, patch_ids))))
+
+ def execute(self, options, args, tool):
+ self.options = options
+ self.tool = tool
+ work_queue = WorkQueue(self.name, self)
+ return work_queue.run()
+
+
+class CommitQueue(AbstractQueue, LandingSequenceErrorHandler):
+ name = "commit-queue"
+ def __init__(self):
+ AbstractQueue.__init__(self)
+
+ # AbstractQueue methods
+
+ def begin_work_queue(self):
+ AbstractQueue.begin_work_queue(self)
+
+ def next_work_item(self):
+ patches = self.tool.bugs.fetch_patches_from_commit_queue(reject_invalid_patches=True)
+ if not patches:
+ return None
+ # Only bother logging if we have patches in the queue.
+ self.log_progress([patch['id'] for patch in patches])
+ return patches[0]
+
+ def should_proceed_with_work_item(self, patch):
+ red_builders_names = self.tool.buildbot.red_core_builders_names()
+ if red_builders_names:
+ red_builders_names = map(lambda name: "\"%s\"" % name, red_builders_names) # Add quotes around the names.
+ return (False, "Builders [%s] are red. See http://build.webkit.org." % ", ".join(red_builders_names), None)
+ return (True, "Landing patch %s from bug %s." % (patch["id"], patch["bug_id"]), patch)
+
+ def process_work_item(self, patch):
+ self._cc_watchers(patch["bug_id"])
+ self.run_bugzilla_tool(["land-attachment", "--force-clean", "--non-interactive", "--parent-command=commit-queue", "--quiet", patch["id"]])
+
+ def handle_unexpected_error(self, patch, message):
+ self.tool.bugs.reject_patch_from_commit_queue(patch["id"], message)
+
+ # LandingSequenceErrorHandler methods
+
+ @classmethod
+ def handle_script_error(cls, tool, patch, script_error):
+ tool.bugs.reject_patch_from_commit_queue(patch["id"], script_error.message_with_output())
+
+
+class AbstractReviewQueue(AbstractQueue, PersistentPatchCollectionDelegate, LandingSequenceErrorHandler):
+ def __init__(self, options=None):
+ AbstractQueue.__init__(self, options)
+
+ # PersistentPatchCollectionDelegate methods
+
+ def collection_name(self):
+ return self.name
+
+ def fetch_potential_patch_ids(self):
+ return self.tool.bugs.fetch_attachment_ids_from_review_queue()
+
+ def status_server(self):
+ return self.tool.status()
+
+ # AbstractQueue methods
+
+ def begin_work_queue(self):
+ AbstractQueue.begin_work_queue(self)
+ self.tool.status().set_host(self.options.status_host)
+ self._patches = PersistentPatchCollection(self)
+
+ def next_work_item(self):
+ patch_id = self._patches.next()
+ if patch_id:
+ return self.tool.bugs.fetch_attachment(patch_id)
+
+ def should_proceed_with_work_item(self, patch):
+ raise NotImplementedError, "subclasses must implement"
+
+ def process_work_item(self, patch):
+ raise NotImplementedError, "subclasses must implement"
+
+ def handle_unexpected_error(self, patch, message):
+ log(message)
+
+ # LandingSequenceErrorHandler methods
+
+ @classmethod
+ def handle_script_error(cls, tool, patch, script_error):
+ log(script_error.message_with_output())
+
+
+class StyleQueue(AbstractReviewQueue):
+ name = "style-queue"
+ def __init__(self):
+ AbstractReviewQueue.__init__(self)
+
+ def should_proceed_with_work_item(self, patch):
+ return (True, "Checking style for patch %s on bug %s." % (patch["id"], patch["bug_id"]), patch)
+
+ def process_work_item(self, patch):
+ try:
+ self.run_bugzilla_tool(["check-style", "--force-clean", "--non-interactive", "--parent-command=style-queue", patch["id"]])
+ message = "%s ran check-webkit-style on attachment %s without any errors." % (self.name, patch["id"])
+ self.tool.bugs.post_comment_to_bug(patch["bug_id"], message, cc=self.watchers)
+ self._patches.did_pass(patch)
+ except ScriptError, e:
+ self._patches.did_fail(patch)
+ raise e
+
+ @classmethod
+ def handle_script_error(cls, tool, patch, script_error):
+ command = script_error.script_args
+ if type(command) is list:
+ command = command[0]
+ # FIXME: We shouldn't need to use a regexp here. ScriptError should
+ # have a better API.
+ if re.search("check-webkit-style", command):
+ message = "Attachment %s did not pass %s:\n\n%s" % (patch["id"], cls.name, script_error.message_with_output(output_limit=5*1024))
+ tool.bugs.post_comment_to_bug(patch["bug_id"], message, cc=cls.watchers)
diff --git a/WebKitTools/Scripts/modules/commands/queues_unittest.py b/WebKitTools/Scripts/modules/commands/queues_unittest.py
new file mode 100644
index 0000000..75abbe5
--- /dev/null
+++ b/WebKitTools/Scripts/modules/commands/queues_unittest.py
@@ -0,0 +1,66 @@
+# Copyright (C) 2009 Google 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:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * 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.
+# * Neither the name of Google Inc. 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 THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+# OWNER 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.
+
+import unittest
+
+from modules.commands.commandtest import CommandsTest
+from modules.commands.queues import *
+from modules.mock_bugzillatool import MockBugzillaTool
+from modules.outputcapture import OutputCapture
+
+
+class TestQueue(AbstractQueue):
+ name = "test-queue"
+
+
+class AbstractQueueTest(CommandsTest):
+ def _assert_output(self, function, args, expected_stdout="", expected_stderr=""):
+ capture = OutputCapture()
+ capture.capture_output()
+ function(*args)
+ (stdout_string, stderr_string) = capture.restore_output()
+ self.assertEqual(stdout_string, expected_stdout)
+ self.assertEqual(stderr_string, expected_stderr)
+
+ def _assert_log_progress_output(self, patch_ids, progress_output):
+ self._assert_output(TestQueue().log_progress, [patch_ids], expected_stderr=progress_output)
+
+ def test_log_progress(self):
+ self._assert_log_progress_output([1,2,3], "3 patches in test-queue [1, 2, 3]\n")
+ self._assert_log_progress_output(["1","2","3"], "3 patches in test-queue [1, 2, 3]\n")
+ self._assert_log_progress_output([1], "1 patch in test-queue [1]\n")
+
+ def _assert_run_bugzilla_tool_output(self, run_args, tool_output):
+ queue = TestQueue()
+ queue.bind_to_tool(MockBugzillaTool())
+ # MockBugzillaTool.path() is "echo"
+ self._assert_output(queue.run_bugzilla_tool, [run_args], expected_stdout=tool_output)
+
+ def test_run_bugzilla_tool(self):
+ self._assert_run_bugzilla_tool_output([1], "")
+ self._assert_run_bugzilla_tool_output(["one", 2], "")
diff --git a/WebKitTools/Scripts/modules/commands/upload.py b/WebKitTools/Scripts/modules/commands/upload.py
new file mode 100644
index 0000000..1f892a1
--- /dev/null
+++ b/WebKitTools/Scripts/modules/commands/upload.py
@@ -0,0 +1,246 @@
+#!/usr/bin/env python
+# Copyright (c) 2009, Google Inc. All rights reserved.
+# Copyright (c) 2009 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:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * 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.
+# * Neither the name of Google Inc. 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 THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+# OWNER 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.
+
+import os
+import StringIO
+import sys
+
+from optparse import make_option
+
+from modules.bugzilla import parse_bug_id
+from modules.grammar import pluralize
+from modules.logging import error, log
+from modules.multicommandtool import Command
+
+# FIXME: Requires unit test.
+class CommitMessageForCurrentDiff(Command):
+ name = "commit-message"
+ show_in_main_help = False
+ def __init__(self):
+ Command.__init__(self, "Print a commit message suitable for the uncommitted changes")
+
+ def execute(self, options, args, tool):
+ os.chdir(tool.scm().checkout_root)
+ print "%s" % tool.scm().commit_message_for_this_commit().message()
+
+
+class ObsoleteAttachments(Command):
+ name = "obsolete-attachments"
+ show_in_main_help = False
+ def __init__(self):
+ Command.__init__(self, "Mark all attachments on a bug as obsolete", "BUGID")
+
+ def execute(self, options, args, tool):
+ bug_id = args[0]
+ attachments = tool.bugs.fetch_attachments_from_bug(bug_id)
+ for attachment in attachments:
+ if not attachment["is_obsolete"]:
+ tool.bugs.obsolete_attachment(attachment["id"])
+
+
+class PostDiff(Command):
+ name = "post-diff"
+ show_in_main_help = True
+ def __init__(self):
+ options = [
+ make_option("-m", "--description", action="store", type="string", dest="description", help="Description string for the attachment (default: \"patch\")"),
+ ]
+ options += self.posting_options()
+ Command.__init__(self, "Attach the current working directory diff to a bug as a patch file", "[BUGID]", options=options)
+
+ @staticmethod
+ def posting_options():
+ return [
+ make_option("--no-obsolete", action="store_false", dest="obsolete_patches", default=True, help="Do not obsolete old patches before posting this one."),
+ make_option("--no-review", action="store_false", dest="review", default=True, help="Do not mark the patch for review."),
+ make_option("--request-commit", action="store_true", dest="request_commit", default=False, help="Mark the patch as needing auto-commit after review."),
+ ]
+
+ @staticmethod
+ def obsolete_patches_on_bug(bug_id, bugs):
+ patches = bugs.fetch_patches_from_bug(bug_id)
+ if len(patches):
+ log("Obsoleting %s on bug %s" % (pluralize("old patch", len(patches)), bug_id))
+ for patch in patches:
+ bugs.obsolete_attachment(patch["id"])
+
+ def execute(self, options, args, tool):
+ # Perfer a bug id passed as an argument over a bug url in the diff (i.e. ChangeLogs).
+ bug_id = (args and args[0]) or parse_bug_id(tool.scm().create_patch())
+ if not bug_id:
+ error("No bug id passed and no bug url found in diff, can't post.")
+
+ if options.obsolete_patches:
+ self.obsolete_patches_on_bug(bug_id, tool.bugs)
+
+ diff = tool.scm().create_patch()
+ diff_file = StringIO.StringIO(diff) # add_patch_to_bug expects a file-like object
+
+ description = options.description or "Patch"
+ tool.bugs.add_patch_to_bug(bug_id, diff_file, description, mark_for_review=options.review, mark_for_commit_queue=options.request_commit)
+
+
+class PostCommits(Command):
+ name = "post-commits"
+ show_in_main_help = True
+ def __init__(self):
+ options = [
+ make_option("-b", "--bug-id", action="store", type="string", dest="bug_id", help="Specify bug id if no URL is provided in the commit log."),
+ make_option("--add-log-as-comment", action="store_true", dest="add_log_as_comment", default=False, help="Add commit log message as a comment when uploading the patch."),
+ make_option("-m", "--description", action="store", type="string", dest="description", help="Description string for the attachment (default: description from commit message)"),
+ ]
+ options += PostDiff.posting_options()
+ Command.__init__(self, "Attach a range of local commits to bugs as patch files", "COMMITISH", options=options, requires_local_commits=True)
+
+ def _comment_text_for_commit(self, options, commit_message, tool, commit_id):
+ comment_text = None
+ if (options.add_log_as_comment):
+ comment_text = commit_message.body(lstrip=True)
+ comment_text += "---\n"
+ comment_text += tool.scm().files_changed_summary_for_commit(commit_id)
+ return comment_text
+
+ def _diff_file_for_commit(self, tool, commit_id):
+ diff = tool.scm().create_patch_from_local_commit(commit_id)
+ return StringIO.StringIO(diff) # add_patch_to_bug expects a file-like object
+
+ def execute(self, options, args, tool):
+ commit_ids = tool.scm().commit_ids_from_commitish_arguments(args)
+ if len(commit_ids) > 10: # We could lower this limit, 10 is too many for one bug as-is.
+ error("bugzilla-tool does not support attaching %s at once. Are you sure you passed the right commit range?" % (pluralize("patch", len(commit_ids))))
+
+ have_obsoleted_patches = set()
+ for commit_id in commit_ids:
+ commit_message = tool.scm().commit_message_for_local_commit(commit_id)
+
+ # Prefer --bug-id=, then a bug url in the commit message, then a bug url in the entire commit diff (i.e. ChangeLogs).
+ bug_id = options.bug_id or parse_bug_id(commit_message.message()) or parse_bug_id(tool.scm().create_patch_from_local_commit(commit_id))
+ if not bug_id:
+ log("Skipping %s: No bug id found in commit or specified with --bug-id." % commit_id)
+ continue
+
+ if options.obsolete_patches and bug_id not in have_obsoleted_patches:
+ PostDiff.obsolete_patches_on_bug(bug_id, tool.bugs)
+ have_obsoleted_patches.add(bug_id)
+
+ diff_file = self._diff_file_for_commit(tool, commit_id)
+ description = options.description or commit_message.description(lstrip=True, strip_url=True)
+ comment_text = self._comment_text_for_commit(options, commit_message, tool, commit_id)
+ tool.bugs.add_patch_to_bug(bug_id, diff_file, description, comment_text, mark_for_review=options.review, mark_for_commit_queue=options.request_commit)
+
+
+class MarkFixed(Command):
+ name = "mark-fixed"
+ show_in_main_help = False
+ def __init__(self):
+ Command.__init__(self, "Mark the specified bug as fixed", "BUG_ID REASON")
+
+ def execute(self, options, args, tool):
+ tool.bugs.close_bug_as_fixed(args[0], args[1])
+
+
+# FIXME: Requires unit test. Blocking issue: too complex for now.
+class CreateBug(Command):
+ name = "create-bug"
+ show_in_main_help = True
+ def __init__(self):
+ options = [
+ make_option("--cc", action="store", type="string", dest="cc", help="Comma-separated list of email addresses to carbon-copy."),
+ make_option("--component", action="store", type="string", dest="component", help="Component for the new bug."),
+ make_option("--no-prompt", action="store_false", dest="prompt", default=True, help="Do not prompt for bug title and comment; use commit log instead."),
+ make_option("--no-review", action="store_false", dest="review", default=True, help="Do not mark the patch for review."),
+ make_option("--request-commit", action="store_true", dest="request_commit", default=False, help="Mark the patch as needing auto-commit after review."),
+ ]
+ Command.__init__(self, "Create a bug from local changes or local commits", "[COMMITISH]", options=options)
+
+ def create_bug_from_commit(self, options, args, tool):
+ commit_ids = tool.scm().commit_ids_from_commitish_arguments(args)
+ if len(commit_ids) > 3:
+ error("Are you sure you want to create one bug with %s patches?" % len(commit_ids))
+
+ commit_id = commit_ids[0]
+
+ bug_title = ""
+ comment_text = ""
+ if options.prompt:
+ (bug_title, comment_text) = self.prompt_for_bug_title_and_comment()
+ else:
+ commit_message = tool.scm().commit_message_for_local_commit(commit_id)
+ bug_title = commit_message.description(lstrip=True, strip_url=True)
+ comment_text = commit_message.body(lstrip=True)
+ comment_text += "---\n"
+ comment_text += tool.scm().files_changed_summary_for_commit(commit_id)
+
+ diff = tool.scm().create_patch_from_local_commit(commit_id)
+ diff_file = StringIO.StringIO(diff) # create_bug_with_patch expects a file-like object
+ bug_id = tool.bugs.create_bug_with_patch(bug_title, comment_text, options.component, diff_file, "Patch", cc=options.cc, mark_for_review=options.review, mark_for_commit_queue=options.request_commit)
+
+ if bug_id and len(commit_ids) > 1:
+ options.bug_id = bug_id
+ options.obsolete_patches = False
+ # FIXME: We should pass through --no-comment switch as well.
+ PostCommits.execute(self, options, commit_ids[1:], tool)
+
+ def create_bug_from_patch(self, options, args, tool):
+ bug_title = ""
+ comment_text = ""
+ if options.prompt:
+ (bug_title, comment_text) = self.prompt_for_bug_title_and_comment()
+ else:
+ commit_message = tool.scm().commit_message_for_this_commit()
+ bug_title = commit_message.description(lstrip=True, strip_url=True)
+ comment_text = commit_message.body(lstrip=True)
+
+ diff = tool.scm().create_patch()
+ diff_file = StringIO.StringIO(diff) # create_bug_with_patch expects a file-like object
+ bug_id = tool.bugs.create_bug_with_patch(bug_title, comment_text, options.component, diff_file, "Patch", cc=options.cc, mark_for_review=options.review, mark_for_commit_queue=options.request_commit)
+
+ def prompt_for_bug_title_and_comment(self):
+ bug_title = raw_input("Bug title: ")
+ print "Bug comment (hit ^D on blank line to end):"
+ lines = sys.stdin.readlines()
+ try:
+ sys.stdin.seek(0, os.SEEK_END)
+ except IOError:
+ # Cygwin raises an Illegal Seek (errno 29) exception when the above
+ # seek() call is made. Ignoring it seems to cause no harm.
+ # FIXME: Figure out a way to get avoid the exception in the first
+ # place.
+ pass
+ comment_text = "".join(lines)
+ return (bug_title, comment_text)
+
+ def execute(self, options, args, tool):
+ if len(args):
+ if (not tool.scm().supports_local_commits()):
+ error("Extra arguments not supported; patch is taken from working directory.")
+ self.create_bug_from_commit(options, args, tool)
+ else:
+ self.create_bug_from_patch(options, args, tool)
diff --git a/WebKitTools/Scripts/modules/commands/upload_unittest.py b/WebKitTools/Scripts/modules/commands/upload_unittest.py
new file mode 100644
index 0000000..4d3f85c
--- /dev/null
+++ b/WebKitTools/Scripts/modules/commands/upload_unittest.py
@@ -0,0 +1,42 @@
+# Copyright (C) 2009 Google 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:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * 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.
+# * Neither the name of Google Inc. 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 THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+# OWNER 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.
+
+import unittest
+
+from modules.commands.commandtest import CommandsTest
+from modules.commands.upload import *
+
+class UploadCommandsTest(CommandsTest):
+ def test_mark_fixed(self):
+ self.assert_execute_outputs(MarkFixed(), [43, "Test comment"])
+
+ def test_obsolete_attachments(self):
+ self.assert_execute_outputs(ObsoleteAttachments(), [42])
+
+ def test_post_diff(self):
+ self.assert_execute_outputs(PostDiff(), [42])
diff --git a/WebKitTools/Scripts/modules/committers.py b/WebKitTools/Scripts/modules/committers.py
index fc263eb..d32a536 100644
--- a/WebKitTools/Scripts/modules/committers.py
+++ b/WebKitTools/Scripts/modules/committers.py
@@ -29,128 +29,176 @@
# WebKit's Python module for committer and reviewer validation
class Committer:
- def __init__(self, name, email):
+ def __init__(self, name, email_or_emails):
self.full_name = name
- self.bugzilla_email = email
+ if isinstance(email_or_emails, str):
+ self.emails = [email_or_emails]
+ else:
+ self.emails = email_or_emails
self.can_review = False
def __str__(self):
- return '"%s" <%s>' % (self.full_name, self.bugzilla_email)
+ return '"%s" <%s>' % (self.full_name, self.emails[0])
class Reviewer(Committer):
- def __init__(self, name, email):
- Committer.__init__(self, name, email)
+ def __init__(self, name, email_or_emails):
+ Committer.__init__(self, name, email_or_emails)
self.can_review = True
-# This is intended as a cannonical, machine-readable list of all non-reviewer committers for WebKit.
+# This is intended as a canonical, machine-readable list of all non-reviewer committers for WebKit.
# If your name is missing here and you are a committer, please add it. No review needed.
# All reviewers are committers, so this list is only of committers who are not reviewers.
committers_unable_to_review = [
Committer("Aaron Boodman", "aa@chromium.org"),
Committer("Adam Langley", "agl@chromium.org"),
Committer("Albert J. Wong", "ajwong@chromium.org"),
+ Committer("Alexander Kellett", ["lypanov@mac.com", "a-lists001@lypanov.net", "lypanov@kde.org"]),
+ Committer("Andre Boule", "aboule@apple.com"),
+ Committer("Andrew Wellington", ["andrew@webkit.org", "proton@wiretapped.net"]),
+ Committer("Anthony Ricaud", "rik@webkit.org"),
Committer("Anton Muhin", "antonm@chromium.org"),
Committer("Antonio Gomes", "tonikitoo@webkit.org"),
- Committer("Anthony Ricaud", "rik@webkit.org"),
Committer("Ben Murdoch", "benm@google.com"),
- Committer("Chris Fleizach", "cfleizach@apple.com"),
+ Committer("Benjamin C Meyer", ["ben@meyerhome.net", "ben@webkit.org"]),
Committer("Brent Fulgham", "bfulgham@webkit.org"),
+ Committer("Brett Wilson", "brettw@chromium.org"),
Committer("Brian Weinstein", "bweinstein@apple.com"),
Committer("Cameron McCormack", "cam@webkit.org"),
+ Committer("Chris Fleizach", "cfleizach@apple.com"),
+ Committer("Chris Marrin", "cmarrin@apple.com"),
+ Committer("Chris Petersen", "cpetersen@apple.com"),
+ Committer("Christian Dywan", ["christian@twotoasts.de", "christian@webkit.org"]),
Committer("Collin Jackson", "collinj@webkit.org"),
Committer("Csaba Osztrogonac", "ossy@webkit.org"),
Committer("Daniel Bates", "dbates@webkit.org"),
+ Committer("David Smith", ["catfish.man@gmail.com", "dsmith@webkit.org"]),
+ Committer("Dean Jackson", "dino@apple.com"),
Committer("Drew Wilson", "atwilson@chromium.org"),
- Committer("Dirk Schulze", "krit@webkit.org"),
- Committer("Dmitry Titov", "dimich@chromium.org"),
Committer("Dumitru Daniliuc", "dumi@chromium.org"),
Committer("Eli Fidler", "eli@staikos.net"),
+ Committer("Enrica Casucci", "enrica@apple.com"),
+ Committer("Erik Arvidsson", "arv@chromium.org"),
Committer("Eric Roman", "eroman@chromium.org"),
+ Committer("Feng Qian", "feng@chromium.org"),
Committer("Fumitoshi Ukai", "ukai@chromium.org"),
+ Committer("Girish Ramakrishnan", ["girish@forwardbias.in", "ramakrishnan.girish@gmail.com"]),
+ Committer("Graham Dennis", ["Graham.Dennis@gmail.com", "gdennis@webkit.org"]),
Committer("Greg Bolsinga", "bolsinga@apple.com"),
- Committer("Jeremy Moskovich", "playmobil@google.com"),
+ Committer("Hin-Chung Lam", ["hclam@google.com", "hclam@chromium.org"]),
+ Committer("Jens Alfke", ["snej@chromium.org", "jens@apple.com"]),
+ Committer("Jeremy Moskovich", ["playmobil@google.com", "jeremy@chromium.org"]),
Committer("Jeremy Orlow", "jorlow@chromium.org"),
+ Committer("Jessie Berlin", ["jberlin@webkit.org", "jberlin@apple.com"]),
Committer("Jian Li", "jianli@chromium.org"),
Committer("John Abd-El-Malek", "jam@chromium.org"),
+ Committer("Joost de Valk", ["joost@webkit.org", "webkit-dev@joostdevalk.nl"]),
Committer("Joseph Pecoraro", "joepeck@webkit.org"),
- Committer("Julie Parent", "jparent@google.com"),
- Committer("Kenneth Rohde Christiansen", "kenneth@webkit.org"),
+ Committer("Julie Parent", ["jparent@google.com", "jparent@chromium.org"]),
+ Committer("Julien Chaffraix", ["jchaffraix@webkit.org", "julien.chaffraix@gmail.com"]),
+ Committer("Jungshik Shin", "jshin@chromium.org"),
+ Committer("Keishi Hattori", "keishi@webkit.org"),
+ Committer("Kelly Norton", "knorton@google.com"),
Committer("Kent Tamura", "tkent@chromium.org"),
+ Committer("Krzysztof Kowalczyk", "kkowalczyk@gmail.com"),
Committer("Laszlo Gombos", "laszlo.1.gombos@nokia.com"),
+ Committer("Levi Weintraub", "lweintraub@apple.com"),
Committer("Mads Ager", "ager@chromium.org"),
+ Committer("Matt Lilek", ["webkit@mattlilek.com", "pewtermoose@webkit.org"]),
+ Committer("Matt Perry", "mpcomplete@chromium.org"),
+ Committer("Maxime Britto", ["maxime.britto@gmail.com", "britto@apple.com"]),
+ Committer("Maxime Simon", ["simon.maxime@gmail.com", "maxime.simon@webkit.org"]),
+ Committer("Michelangelo De Simone", "michelangelo@webkit.org"),
Committer("Mike Belshe", "mike@belshe.com"),
+ Committer("Mike Fenton", ["mike.fenton@torchmobile.com", "mifenton@rim.com"]),
+ Committer("Mike Thole", ["mthole@mikethole.com", "mthole@apple.com"]),
Committer("Nate Chapin", "japhet@chromium.org"),
Committer("Ojan Vafai", "ojan@chromium.org"),
Committer("Pam Greene", "pam@chromium.org"),
- Committer("Peter Kasting", "pkasting@google.com"),
- Committer("Pierre d'Herbemont", "pdherbemont@free.fr"),
+ Committer("Peter Kasting", ["pkasting@google.com", "pkasting@chromium.org"]),
+ Committer("Pierre d'Herbemont", ["pdherbemont@free.fr", "pdherbemont@apple.com"]),
+ Committer("Pierre-Olivier Latour", "pol@apple.com"),
Committer("Roland Steiner", "rolandsteiner@chromium.org"),
Committer("Ryosuke Niwa", "rniwa@webkit.org"),
Committer("Scott Violet", "sky@chromium.org"),
Committer("Shinichiro Hamaji", "hamaji@chromium.org"),
+ Committer("Stephen White", "senorblanco@chromium.org"),
Committer("Steve Block", "steveblock@google.com"),
Committer("Tony Chang", "tony@chromium.org"),
+ Committer("Trey Matteson", "trey@usa.net"),
+ Committer("Tristan O'Tierney", ["tristan@otierney.net", "tristan@apple.com"]),
+ Committer("William Siegrist", "wsiegrist@apple.com"),
Committer("Yael Aharon", "yael.aharon@nokia.com"),
- Committer("Yong Li", "yong.li@torchmobile.com"),
+ Committer("Yaar Schnitman", ["yaar@chromium.org", "yaar@google.com"]),
+ Committer("Yong Li", ["yong.li@torchmobile.com", "yong.li.webkit@gmail.com"]),
+ Committer("Yongjun Zhang", "yongjun.zhang@nokia.com"),
Committer("Yury Semikhatsky", "yurys@chromium.org"),
Committer("Zoltan Horvath", "zoltan@webkit.org"),
]
-# This is intended as a cannonical, machine-readable list of all reviewers for WebKit.
+# This is intended as a canonical, machine-readable list of all reviewers for WebKit.
# If your name is missing here and you are a reviewer, please add it. No review needed.
reviewers_list = [
- Reviewer("Adam Barth", "abarth@webkit.org"),
Reviewer("Ada Chan", "adachan@apple.com"),
+ Reviewer("Adam Barth", "abarth@webkit.org"),
Reviewer("Adam Roben", "aroben@apple.com"),
- Reviewer("Adam Treat", "treat@kde.org"),
+ Reviewer("Adam Treat", ["treat@kde.org", "treat@webkit.org"]),
Reviewer("Adele Peterson", "adele@apple.com"),
- Reviewer("Alexey Proskuryakov", "ap@webkit.org"),
+ Reviewer("Alexey Proskuryakov", ["ap@webkit.org", "ap@apple.com"]),
Reviewer("Alice Liu", "alice.liu@apple.com"),
- Reviewer("Alp Toker", "alp@nuanti.com"),
- Reviewer("Anders Carlsson", "andersca@apple.com"),
- Reviewer("Antti Koivisto", "koivisto@iki.fi"),
- Reviewer("Ariya Hidayat", "ariya.hidayat@trolltech.com"),
+ Reviewer("Alp Toker", ["alp@nuanti.com", "alp@atoker.com", "alp@webkit.org"]),
+ Reviewer("Anders Carlsson", ["andersca@apple.com", "acarlsson@apple.com"]),
+ Reviewer("Antti Koivisto", ["koivisto@iki.fi", "antti@apple.com"]),
+ Reviewer("Ariya Hidayat", ["ariya.hidayat@trolltech.com", "ariya.hidayat@gmail.com", "ariya@webkit.org"]),
+ Reviewer("Beth Dakin", "bdakin@apple.com"),
Reviewer("Brady Eidson", "beidson@apple.com"),
- Reviewer("Cameron Zwarich", "zwarich@apple.com"),
- Reviewer("Dan Bernstein", "mitz@webkit.org"),
+ Reviewer("Cameron Zwarich", ["zwarich@apple.com", "cwzwarich@apple.com", "cwzwarich@webkit.org"]),
+ Reviewer("Chris Blumenberg", "cblu@apple.com"),
+ Reviewer("Dan Bernstein", ["mitz@webkit.org", "mitz@apple.com"]),
Reviewer("Darin Adler", "darin@apple.com"),
- Reviewer("Darin Fisher", "fishd@chromium.org"),
+ Reviewer("Darin Fisher", ["fishd@chromium.org", "darin@chromium.org"]),
Reviewer("David Harrison", "harrison@apple.com"),
Reviewer("David Hyatt", "hyatt@apple.com"),
- Reviewer("David Kilzer", "ddkilzer@webkit.org"),
+ Reviewer("David Kilzer", ["ddkilzer@webkit.org", "ddkilzer@apple.com"]),
Reviewer("David Levin", "levin@chromium.org"),
Reviewer("Dimitri Glazkov", "dglazkov@chromium.org"),
+ Reviewer("Dirk Schulze", "krit@webkit.org"),
+ Reviewer("Dmitry Titov", "dimich@chromium.org"),
Reviewer("Don Melton", "gramps@apple.com"),
- Reviewer("Dmitri Titov", "dimich@chromium.org"),
Reviewer("Eric Carlson", "eric.carlson@apple.com"),
Reviewer("Eric Seidel", "eric@webkit.org"),
Reviewer("Gavin Barraclough", "barraclough@apple.com"),
Reviewer("Geoffrey Garen", "ggaren@apple.com"),
- Reviewer("George Staikos", "staikos@kde.org"),
- Reviewer("Gustavo Noronha", "gns@gnome.org"),
- Reviewer("Holger Freyther", "zecke@selfish.org"),
- Reviewer("Jan Alonzo", "jmalonzo@gmail.com"),
+ Reviewer("George Staikos", ["staikos@kde.org", "staikos@webkit.org"]),
+ Reviewer("Gustavo Noronha Silva", ["gns@gnome.org", "kov@webkit.org"]),
+ Reviewer("Holger Freyther", ["zecke@selfish.org", "zecke@webkit.org"]),
+ Reviewer("Jan Alonzo", ["jmalonzo@gmail.com", "jmalonzo@webkit.org"]),
Reviewer("John Sullivan", "sullivan@apple.com"),
Reviewer("Jon Honeycutt", "jhoneycutt@apple.com"),
Reviewer("Justin Garcia", "justin.garcia@apple.com"),
+ Reviewer("Ken Kocienda", "kocienda@apple.com"),
+ Reviewer("Kenneth Rohde Christiansen", ["kenneth@webkit.org", "kenneth.christiansen@openbossa.org"]),
Reviewer("Kevin Decker", "kdecker@apple.com"),
Reviewer("Kevin McCullough", "kmccullough@apple.com"),
- Reviewer("Kevin Ollivier", "kevino@theolliviers.com"),
- Reviewer("Lars Knoll", "lars@trolltech.com"),
+ Reviewer("Kevin Ollivier", ["kevino@theolliviers.com", "kevino@webkit.org"]),
+ Reviewer("Lars Knoll", ["lars@trolltech.com", "lars@kde.org"]),
Reviewer("Maciej Stachowiak", "mjs@apple.com"),
Reviewer("Mark Rowe", "mrowe@apple.com"),
- Reviewer("Nikolas Zimmermann", "zimmermann@kde.org"),
+ Reviewer("Nikolas Zimmermann", ["zimmermann@kde.org", "zimmermann@physik.rwth-aachen.de", "zimmermann@webkit.org"]),
Reviewer("Oliver Hunt", "oliver@apple.com"),
Reviewer("Pavel Feldman", "pfeldman@chromium.org"),
- Reviewer("Rob Buis", "rwlbuis@gmail.com"),
- Reviewer("Sam Weinig", "sam@webkit.org"),
+ Reviewer("Richard Williamson", "rjw@apple.com"),
+ Reviewer("Rob Buis", ["rwlbuis@gmail.com", "rwlbuis@webkit.org"]),
+ Reviewer("Sam Weinig", ["sam@webkit.org", "weinig@apple.com"]),
Reviewer("Simon Fraser", "simon.fraser@apple.com"),
- Reviewer("Simon Hausmann", "hausmann@webkit.org"),
+ Reviewer("Simon Hausmann", ["hausmann@webkit.org", "hausmann@kde.org"]),
Reviewer("Stephanie Lewis", "slewis@apple.com"),
Reviewer("Steve Falkenburg", "sfalken@apple.com"),
- Reviewer("Timothy Hatcher", "timothy@hatcher.name"),
+ Reviewer("Tim Omernick", "timo@apple.com"),
+ Reviewer("Timothy Hatcher", ["timothy@hatcher.name", "timothy@apple.com"]),
Reviewer(u'Tor Arne Vestb\xf8', "vestbo@webkit.org"),
- Reviewer("Xan Lopez", "xan.lopez@gmail.com"),
+ Reviewer("Vicki Murley", "vicki@apple.com"),
+ Reviewer("Xan Lopez", ["xan.lopez@gmail.com", "xan@gnome.org", "xan@webkit.org"]),
+ Reviewer("Zack Rusin", "zack@kde.org"),
]
@@ -164,17 +212,21 @@ class CommitterList:
def committers(self):
return self._committers
+ def reviewers(self):
+ return self._reviewers
+
def _email_to_committer_map(self):
if not len(self._committers_by_email):
for committer in self._committers:
- self._committers_by_email[committer.bugzilla_email] = committer
+ for email in committer.emails:
+ self._committers_by_email[email] = committer
return self._committers_by_email
- def committer_by_bugzilla_email(self, bugzilla_email):
- return self._email_to_committer_map().get(bugzilla_email)
+ def committer_by_email(self, email):
+ return self._email_to_committer_map().get(email)
- def reviewer_by_bugzilla_email(self, bugzilla_email):
- committer = self.committer_by_bugzilla_email(bugzilla_email)
+ def reviewer_by_email(self, email):
+ committer = self.committer_by_email(email)
if committer and not committer.can_review:
return None
return committer
diff --git a/WebKitTools/Scripts/modules/committers_unittest.py b/WebKitTools/Scripts/modules/committers_unittest.py
index 045e20e..cf9f486 100644
--- a/WebKitTools/Scripts/modules/committers_unittest.py
+++ b/WebKitTools/Scripts/modules/committers_unittest.py
@@ -33,20 +33,30 @@ class CommittersTest(unittest.TestCase):
def test_committer_lookup(self):
committer = Committer('Test One', 'one@test.com')
- reviewer = Reviewer('Test Two', 'two@test.com')
+ reviewer = Reviewer('Test Two', ['two@test.com', 'two@rad.com', 'so_two@gmail.com'])
committer_list = CommitterList(committers=[committer], reviewers=[reviewer])
# Test valid committer and reviewer lookup
- self.assertEqual(committer_list.committer_by_bugzilla_email('one@test.com'), committer)
- self.assertEqual(committer_list.reviewer_by_bugzilla_email('two@test.com'), reviewer)
- self.assertEqual(committer_list.committer_by_bugzilla_email('two@test.com'), reviewer)
+ self.assertEqual(committer_list.committer_by_email('one@test.com'), committer)
+ self.assertEqual(committer_list.reviewer_by_email('two@test.com'), reviewer)
+ self.assertEqual(committer_list.committer_by_email('two@test.com'), reviewer)
+ self.assertEqual(committer_list.committer_by_email('two@rad.com'), reviewer)
+ self.assertEqual(committer_list.reviewer_by_email('so_two@gmail.com'), reviewer)
# Test that a known committer is not returned during reviewer lookup
- self.assertEqual(committer_list.reviewer_by_bugzilla_email('one@test.com'), None)
+ self.assertEqual(committer_list.reviewer_by_email('one@test.com'), None)
# Test that unknown email address fail both committer and reviewer lookup
- self.assertEqual(committer_list.committer_by_bugzilla_email('bar@bar.com'), None)
- self.assertEqual(committer_list.reviewer_by_bugzilla_email('bar@bar.com'), None)
+ self.assertEqual(committer_list.committer_by_email('bar@bar.com'), None)
+ self.assertEqual(committer_list.reviewer_by_email('bar@bar.com'), None)
+
+ # Test that emails returns a list.
+ self.assertEqual(committer.emails, ['one@test.com'])
+
+ # Test that committers returns committers and reviewers and reviewers() just reviewers.
+ self.assertEqual(committer_list.committers(), [committer, reviewer])
+ self.assertEqual(committer_list.reviewers(), [reviewer])
+
if __name__ == '__main__':
unittest.main()
diff --git a/WebKitTools/Scripts/modules/cpp_style.py b/WebKitTools/Scripts/modules/cpp_style.py
index 485b07c..d8ca8d1 100644
--- a/WebKitTools/Scripts/modules/cpp_style.py
+++ b/WebKitTools/Scripts/modules/cpp_style.py
@@ -130,6 +130,7 @@ _ERROR_CATEGORIES = '''\
readability/function
readability/multiline_comment
readability/multiline_string
+ readability/naming
readability/null
readability/streams
readability/todo
@@ -243,14 +244,14 @@ _PRIMARY_HEADER = 1
_OTHER_HEADER = 2
+# The regexp compilation caching is inlined in all regexp functions for
+# performance reasons; factoring it out into a separate function turns out
+# to be noticeably expensive.
_regexp_compile_cache = {}
def match(pattern, s):
"""Matches the string with the pattern, caching the compiled regexp."""
- # The regexp compilation caching is inlined in both match and search for
- # performance reasons; factoring it out into a separate function turns out
- # to be noticeably expensive.
if not pattern in _regexp_compile_cache:
_regexp_compile_cache[pattern] = sre_compile.compile(pattern)
return _regexp_compile_cache[pattern].match(s)
@@ -263,6 +264,20 @@ def search(pattern, s):
return _regexp_compile_cache[pattern].search(s)
+def sub(pattern, replacement, s):
+ """Substitutes occurrences of a pattern, caching the compiled regexp."""
+ if not pattern in _regexp_compile_cache:
+ _regexp_compile_cache[pattern] = sre_compile.compile(pattern)
+ return _regexp_compile_cache[pattern].sub(replacement, s)
+
+
+def subn(pattern, replacement, s):
+ """Substitutes occurrences of a pattern, caching the compiled regexp."""
+ if not pattern in _regexp_compile_cache:
+ _regexp_compile_cache[pattern] = sre_compile.compile(pattern)
+ return _regexp_compile_cache[pattern].subn(replacement, s)
+
+
class _IncludeState(dict):
"""Tracks line numbers for includes, and the order in which includes appear.
@@ -868,7 +883,7 @@ def get_header_guard_cpp_variable(filename):
"""
fileinfo = FileInfo(filename)
- return re.sub(r'[-./\s]', '_', fileinfo.repository_name()).upper() + '_'
+ return sub(r'[-./\s]', '_', fileinfo.repository_name()).upper() + '_'
def check_for_header_guard(filename, lines, error):
@@ -1119,6 +1134,16 @@ class _ClassState(object):
self.classinfo_stack[0].name)
+class _FileState(object):
+ def __init__(self):
+ self._did_inside_namespace_indent_warning = False
+
+ def set_did_inside_namespace_indent_warning(self):
+ self._did_inside_namespace_indent_warning = True
+
+ def did_inside_namespace_indent_warning(self):
+ return self._did_inside_namespace_indent_warning
+
def check_for_non_standard_constructs(filename, clean_lines, line_number,
class_state, error):
"""Logs an error if we see certain non-ANSI constructs ignored by gcc-2.
@@ -1532,10 +1557,10 @@ def check_spacing(filename, clean_lines, line_number, error):
line = clean_lines.elided[line_number] # get rid of comments and strings
# Don't try to do spacing checks for operator methods
- line = re.sub(r'operator(==|!=|<|<<|<=|>=|>>|>)\(', 'operator\(', line)
- # Don't try to do spacing checks for #include statements at minimum it
- # messes up checks for spacing around /
- if match(r'\s*#\s*include', line):
+ line = sub(r'operator(==|!=|<|<<|<=|>=|>>|>)\(', 'operator\(', line)
+ # Don't try to do spacing checks for #include or #import statements at
+ # minimum because it messes up checks for spacing around /
+ if match(r'\s*#\s*(?:include|import)', line):
return
if search(r'[\w.]=[\w.]', line):
error(filename, line_number, 'whitespace/operators', 4,
@@ -1675,7 +1700,7 @@ def get_previous_non_blank_line(clean_lines, line_number):
return ('', -1)
-def check_namespace_indentation(filename, clean_lines, line_number, file_extension, error):
+def check_namespace_indentation(filename, clean_lines, line_number, file_extension, file_state, error):
"""Looks for indentation errors inside of namespaces.
Args:
@@ -1683,6 +1708,8 @@ def check_namespace_indentation(filename, clean_lines, line_number, file_extensi
clean_lines: A CleansedLines instance containing the file.
line_number: The number of the line to check.
file_extension: The extension (dot not included) of the file.
+ file_state: A _FileState instance which maintains information about
+ the state of things in the file.
error: The function to call with any errors found.
"""
@@ -1694,8 +1721,10 @@ def check_namespace_indentation(filename, clean_lines, line_number, file_extensi
current_indentation_level = len(namespace_match.group('namespace_indentation'))
if current_indentation_level > 0:
- error(filename, line_number, 'whitespace/indent', 4,
- 'namespace should never be indented.')
+ # Don't warn about an indented namespace if we already warned about indented code.
+ if not file_state.did_inside_namespace_indent_warning():
+ error(filename, line_number, 'whitespace/indent', 4,
+ 'namespace should never be indented.')
return
looking_for_semicolon = False;
line_offset = 0
@@ -1706,7 +1735,8 @@ def check_namespace_indentation(filename, clean_lines, line_number, file_extensi
continue
if not current_indentation_level:
if not (in_preprocessor_directive or looking_for_semicolon):
- if not match(r'\S', current_line):
+ if not match(r'\S', current_line) and not file_state.did_inside_namespace_indent_warning():
+ file_state.set_did_inside_namespace_indent_warning()
error(filename, line_number + line_offset, 'whitespace/indent', 4,
'Code inside a namespace should not be indented.')
if in_preprocessor_directive or (current_line.strip()[0] == '#'): # This takes care of preprocessor directive syntax.
@@ -1871,7 +1901,8 @@ def check_braces(filename, clean_lines, line_number, error):
'This { should be at the end of the previous line')
elif (search(r'\)\s*(const\s*)?{\s*$', line)
and line.count('(') == line.count(')')
- and not search(r'\b(if|for|foreach|while|switch)\b', line)):
+ and not search(r'\b(if|for|foreach|while|switch)\b', line)
+ and not match(r'\s+[A-Z_][A-Z_0-9]+\b', line)):
error(filename, line_number, 'whitespace/braces', 4,
'Place brace on its own line for function definitions.')
@@ -2124,7 +2155,7 @@ def get_line_width(line):
return len(line)
-def check_style(filename, clean_lines, line_number, file_extension, error):
+def check_style(filename, clean_lines, line_number, file_extension, file_state, error):
"""Checks rules from the 'C++ style rules' section of cppguide.html.
Most of these rules are hard to test (naming, comment style), but we
@@ -2136,6 +2167,8 @@ def check_style(filename, clean_lines, line_number, file_extension, error):
clean_lines: A CleansedLines instance containing the file.
line_number: The number of the line to check.
file_extension: The extension (without the dot) of the filename.
+ file_state: A _FileState instance which maintains information about
+ the state of things in the file.
error: The function to call with any errors found.
"""
@@ -2203,7 +2236,7 @@ def check_style(filename, clean_lines, line_number, file_extension, error):
'operators on the left side of the line instead of the right side.')
# Some more style checks
- check_namespace_indentation(filename, clean_lines, line_number, file_extension, error)
+ check_namespace_indentation(filename, clean_lines, line_number, file_extension, file_state, error)
check_using_std(filename, clean_lines, line_number, error)
check_max_min_macros(filename, clean_lines, line_number, error)
check_switch_indentation(filename, clean_lines, line_number, error)
@@ -2309,7 +2342,7 @@ def _classify_include(filename, include, is_system, include_state):
include_base = FileInfo(include).base_name()
# If we haven't encountered a primary header, then be lenient in checking.
- if not include_state.visited_primary_section() and target_base.startswith(include_base):
+ if not include_state.visited_primary_section() and target_base.find(include_base) != -1:
return _PRIMARY_HEADER
# If we already encountered a primary header, perform a strict comparison.
# In case the two filename bases are the same then the above lenient check
@@ -2616,6 +2649,109 @@ def check_language(filename, clean_lines, line_number, file_extension, include_s
'http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml#Namespaces'
' for more information.')
+ check_identifier_name_in_declaration(filename, line_number, line, error)
+
+
+def check_identifier_name_in_declaration(filename, line_number, line, error):
+ """Checks if identifier names contain any underscores.
+
+ As identifiers in libraries we are using have a bunch of
+ underscores, we only warn about the declarations of identifiers
+ and don't check use of identifiers.
+
+ Args:
+ filename: The name of the current file.
+ line_number: The number of the line to check.
+ line: The line of code to check.
+ error: The function to call with any errors found.
+ """
+ # We don't check a return statement.
+ if match(r'\s*return\b', line):
+ return
+
+ # Basically, a declaration is a type name followed by whitespaces
+ # followed by an identifier. The type name can be complicated
+ # due to type adjectives and templates. We remove them first to
+ # simplify the process to find declarations of identifiers.
+
+ # Convert "long long", "long double", and "long long int" to
+ # simple types, but don't remove simple "long".
+ line = sub(r'long (long )?(?=long|double|int)', '', line)
+ line = sub(r'\b(unsigned|signed|inline|using|static|const|volatile|auto|register|extern|typedef|restrict|struct|class|virtual)(?=\W)', '', line)
+
+ # Remove all template parameters by removing matching < and >.
+ # Loop until no templates are removed to remove nested templates.
+ while True:
+ line, number_of_replacements = subn(r'<([\w\s:]|::)+\s*[*&]*\s*>', '', line)
+ if not number_of_replacements:
+ break
+
+ # Declarations of local variables can be in condition expressions
+ # of control flow statements (e.g., "if (RenderObject* p = o->parent())").
+ # We remove the keywords and the first parenthesis.
+ #
+ # Declarations in "while", "if", and "switch" are different from
+ # other declarations in two aspects:
+ #
+ # - There can be only one declaration between the parentheses.
+ # (i.e., you cannot write "if (int i = 0, j = 1) {}")
+ # - The variable must be initialized.
+ # (i.e., you cannot write "if (int i) {}")
+ #
+ # and we will need different treatments for them.
+ line = sub(r'^\s*for\s*\(', '', line)
+ line, control_statement = subn(r'^\s*(while|else if|if|switch)\s*\(', '', line)
+
+ # Detect variable and functions.
+ type_regexp = r'\w([\w]|\s*[*&]\s*|::)+'
+ identifier_regexp = r'(?P<identifier>[\w:]+)'
+ character_after_identifier_regexp = r'(?P<character_after_identifier>[[;()=,])(?!=)'
+ declaration_without_type_regexp = r'\s*' + identifier_regexp + r'\s*' + character_after_identifier_regexp
+ declaration_with_type_regexp = r'\s*' + type_regexp + r'\s' + declaration_without_type_regexp
+ is_function_arguments = False
+ number_of_identifiers = 0
+ while True:
+ # If we are seeing the first identifier or arguments of a
+ # function, there should be a type name before an identifier.
+ if not number_of_identifiers or is_function_arguments:
+ declaration_regexp = declaration_with_type_regexp
+ else:
+ declaration_regexp = declaration_without_type_regexp
+
+ matched = match(declaration_regexp, line)
+ if not matched:
+ return
+ identifier = matched.group('identifier')
+ character_after_identifier = matched.group('character_after_identifier')
+
+ # If we removed a non-for-control statement, the character after
+ # the identifier should be '='. With this rule, we can avoid
+ # warning for cases like "if (val & INT_MAX) {".
+ if control_statement and character_after_identifier != '=':
+ return
+
+ is_function_arguments = is_function_arguments or character_after_identifier == '('
+
+ # Remove "m_" and "s_" to allow them.
+ modified_identifier = sub(r'(^|(?<=::))[ms]_', '', identifier)
+ if modified_identifier.find('_') >= 0:
+ # Various exceptions to the rule: JavaScript op codes functions, const_iterator.
+ if (not (filename.find('JavaScriptCore') >= 0 and modified_identifier.find('_op_') >= 0)
+ and not modified_identifier == "const_iterator"):
+ error(filename, line_number, 'readability/naming', 4, identifier + " is incorrectly named. Don't use underscores in your identifier names.")
+
+ # There can be only one declaration in non-for-control statements.
+ if control_statement:
+ return
+ # We should continue checking if this is a function
+ # declaration because we need to check its arguments.
+ # Also, we need to check multiple declarations.
+ if character_after_identifier != '(' and character_after_identifier != ',':
+ return
+
+ number_of_identifiers += 1
+ line = line[matched.end():]
+
def check_c_style_cast(filename, line_number, line, raw_line, cast_type, pattern,
error):
@@ -2914,7 +3050,7 @@ def check_for_include_what_you_use(filename, clean_lines, include_state, error,
def process_line(filename, file_extension,
clean_lines, line, include_state, function_state,
- class_state, error):
+ class_state, file_state, error):
"""Processes a single line in the file.
Args:
@@ -2927,6 +3063,8 @@ def process_line(filename, file_extension,
function_state: A _FunctionState instance which counts function lines, etc.
class_state: A _ClassState instance which maintains information about
the current stack of nested class declarations being parsed.
+ file_state: A _FileState instance which maintains information about
+ the state of things in the file.
error: A callable to which errors are reported, which takes 4 arguments:
filename, line number, error level, and message
@@ -2936,7 +3074,7 @@ def process_line(filename, file_extension,
if search(r'\bNOLINT\b', raw_lines[line]): # ignore nolint lines
return
check_for_multiline_comments_and_strings(filename, clean_lines, line, error)
- check_style(filename, clean_lines, line, file_extension, error)
+ check_style(filename, clean_lines, line, file_extension, file_state, error)
check_language(filename, clean_lines, line, file_extension, include_state,
error)
check_for_non_standard_constructs(filename, clean_lines, line,
@@ -2961,6 +3099,7 @@ def process_file_data(filename, file_extension, lines, error):
include_state = _IncludeState()
function_state = _FunctionState()
class_state = _ClassState()
+ file_state = _FileState()
check_for_copyright(filename, lines, error)
@@ -2971,7 +3110,7 @@ def process_file_data(filename, file_extension, lines, error):
clean_lines = CleansedLines(lines)
for line in xrange(clean_lines.num_lines()):
process_line(filename, file_extension, clean_lines, line,
- include_state, function_state, class_state, error)
+ include_state, function_state, class_state, file_state, error)
class_state.check_finished(filename, error)
check_for_include_what_you_use(filename, clean_lines, include_state, error)
@@ -3038,8 +3177,6 @@ def process_file(filename, error=error):
'One or more unexpected \\r (^M) found;'
'better to use only a \\n')
- sys.stderr.write('Done processing %s\n' % filename)
-
def print_usage(message):
"""Prints a brief usage string and exits, optionally with an error message.
diff --git a/WebKitTools/Scripts/modules/cpp_style_unittest.py b/WebKitTools/Scripts/modules/cpp_style_unittest.py
index d5637f4..75dd47e 100644
--- a/WebKitTools/Scripts/modules/cpp_style_unittest.py
+++ b/WebKitTools/Scripts/modules/cpp_style_unittest.py
@@ -120,9 +120,10 @@ class CppStyleTestBase(unittest.TestCase):
function_state = cpp_style._FunctionState()
ext = file_name[file_name.rfind('.') + 1:]
class_state = cpp_style._ClassState()
+ file_state = cpp_style._FileState()
cpp_style.process_line(file_name, ext, clean_lines, 0,
include_state, function_state,
- class_state, error_collector)
+ class_state, file_state, error_collector)
# Single-line lint tests are allowed to fail the 'unlintable function'
# check.
error_collector.remove_if_present(
@@ -137,8 +138,9 @@ class CppStyleTestBase(unittest.TestCase):
lines = cpp_style.CleansedLines(lines)
ext = file_name[file_name.rfind('.') + 1:]
class_state = cpp_style._ClassState()
+ file_state = cpp_style._FileState()
for i in xrange(lines.num_lines()):
- cpp_style.check_style(file_name, lines, i, ext, error_collector)
+ cpp_style.check_style(file_name, lines, i, ext, file_state, error_collector)
cpp_style.check_for_non_standard_constructs(file_name, lines, i, class_state,
error_collector)
class_state.check_finished(file_name, error_collector)
@@ -934,15 +936,15 @@ class CppStyleTest(CppStyleTestBase):
self.assert_lint('int doublesize[some_var * 2];', errmsg)
self.assert_lint('int a[afunction()];', errmsg)
self.assert_lint('int a[function(kMaxFooBars)];', errmsg)
- self.assert_lint('bool a_list[items_->size()];', errmsg)
+ self.assert_lint('bool aList[items_->size()];', errmsg)
self.assert_lint('namespace::Type buffer[len+1];', errmsg)
self.assert_lint('int a[64];', '')
self.assert_lint('int a[0xFF];', '')
self.assert_lint('int first[256], second[256];', '')
- self.assert_lint('int array_name[kCompileTimeConstant];', '')
+ self.assert_lint('int arrayName[kCompileTimeConstant];', '')
self.assert_lint('char buf[somenamespace::kBufSize];', '')
- self.assert_lint('int array_name[ALL_CAPS];', '')
+ self.assert_lint('int arrayName[ALL_CAPS];', '')
self.assert_lint('AClass array1[foo::bar::ALL_CAPS];', '')
self.assert_lint('int a[kMaxStrLen + 1];', '')
self.assert_lint('int a[sizeof(foo)];', '')
@@ -1116,6 +1118,12 @@ class CppStyleTest(CppStyleTestBase):
'if (condition) {',
'')
self.assert_multi_line_lint(
+ ' MACRO1(macroArg) {',
+ '')
+ self.assert_multi_line_lint(
+ 'ACCESSOR_GETTER(MessageEventPorts) {',
+ 'Place brace on its own line for function definitions. [whitespace/braces] [4]')
+ self.assert_multi_line_lint(
'int foo() {',
'Place brace on its own line for function definitions. [whitespace/braces] [4]')
self.assert_multi_line_lint(
@@ -1271,6 +1279,8 @@ class CppStyleTest(CppStyleTestBase):
self.assert_lint('a = 1 << 20', '')
self.assert_multi_line_lint('#include "config.h"\n#include <sys/io.h>\n',
'')
+ self.assert_multi_line_lint('#include "config.h"\n#import <foo/bar.h>\n',
+ '')
def test_spacing_before_last_semicolon(self):
self.assert_lint('call_function() ;',
@@ -1520,14 +1530,14 @@ class CppStyleTest(CppStyleTestBase):
def test_indent(self):
self.assert_lint('static int noindent;', '')
- self.assert_lint(' int four_space_indent;', '')
- self.assert_lint(' int one_space_indent;',
+ self.assert_lint(' int fourSpaceIndent;', '')
+ self.assert_lint(' int oneSpaceIndent;',
'Weird number of spaces at line-start. '
'Are you using a 4-space indent? [whitespace/indent] [3]')
- self.assert_lint(' int three_space_indent;',
+ self.assert_lint(' int threeSpaceIndent;',
'Weird number of spaces at line-start. '
'Are you using a 4-space indent? [whitespace/indent] [3]')
- self.assert_lint(' char* one_space_indent = "public:";',
+ self.assert_lint(' char* oneSpaceIndent = "public:";',
'Weird number of spaces at line-start. '
'Are you using a 4-space indent? [whitespace/indent] [3]')
self.assert_lint(' public:', '')
@@ -1960,7 +1970,7 @@ class CppStyleTest(CppStyleTestBase):
self.assert_lint('double const static foo = 2.0;',
build_storage_class_error_message)
- self.assert_lint('uint64 typedef unsigned_long_long;',
+ self.assert_lint('uint64 typedef unsignedLongLong;',
build_storage_class_error_message)
self.assert_lint('int register foo = 0;',
@@ -2044,6 +2054,7 @@ class CppStyleTest(CppStyleTestBase):
'Changing pointer instead of value (or unused value of '
'operator*). [runtime/invalid_increment] [5]')
+
class CleansedLinesTest(unittest.TestCase):
def test_init(self):
lines = ['Line 1',
@@ -2305,6 +2316,10 @@ class OrderOfIncludesTest(CppStyleTestBase):
classify_include('fooCustom.cpp',
'foo.h',
False, include_state))
+ self.assertEqual(cpp_style._PRIMARY_HEADER,
+ classify_include('PrefixFooCustom.cpp',
+ 'Foo.h',
+ False, include_state))
# Tricky example where both includes might be classified as primary.
self.assert_language_rules_check('ScrollbarThemeWince.cpp',
'#include "config.h"\n'
@@ -2828,7 +2843,16 @@ class WebKitStyleTest(CppStyleTestBase):
'};\n'
'};\n'
'}',
- ['Code inside a namespace should not be indented. [whitespace/indent] [4]', 'namespace should never be indented. [whitespace/indent] [4]'],
+ 'Code inside a namespace should not be indented. [whitespace/indent] [4]',
+ 'foo.h')
+ self.assert_multi_line_lint(
+ 'namespace OuterNamespace {\n'
+ ' class Document {\n'
+ ' namespace InnerNamespace {\n'
+ '};\n'
+ '};\n'
+ '}',
+ 'Code inside a namespace should not be indented. [whitespace/indent] [4]',
'foo.h')
self.assert_multi_line_lint(
'namespace WebCore {\n'
@@ -3584,8 +3608,104 @@ class WebKitStyleTest(CppStyleTestBase):
'foo.h')
def test_names(self):
- # FIXME: Implement this.
- pass
+ name_error_message = " is incorrectly named. Don't use underscores in your identifier names. [readability/naming] [4]"
+
+ # Basic cases from WebKit style guide.
+ self.assert_lint('struct Data;', '')
+ self.assert_lint('size_t bufferSize;', '')
+ self.assert_lint('class HTMLDocument;', '')
+ self.assert_lint('String mimeType();', '')
+ self.assert_lint('size_t buffer_size;',
+ 'buffer_size' + name_error_message)
+ self.assert_lint('short m_length;', '')
+ self.assert_lint('short _length;',
+ '_length' + name_error_message)
+ self.assert_lint('short length_;',
+ 'length_' + name_error_message)
+
+ # Pointers, references, functions, templates, and adjectives.
+ self.assert_lint('char* under_score;',
+ 'under_score' + name_error_message)
+ self.assert_lint('const int UNDER_SCORE;',
+ 'UNDER_SCORE' + name_error_message)
+ self.assert_lint('static inline const char const& const under_score;',
+ 'under_score' + name_error_message)
+ self.assert_lint('WebCore::RenderObject* under_score;',
+ 'under_score' + name_error_message)
+ self.assert_lint('int func_name();',
+ 'func_name' + name_error_message)
+ self.assert_lint('RefPtr<RenderObject*> under_score;',
+ 'under_score' + name_error_message)
+ self.assert_lint('WTF::Vector<WTF::RefPtr<const RenderObject* const> > under_score;',
+ 'under_score' + name_error_message)
+ self.assert_lint('int under_score[];',
+ 'under_score' + name_error_message)
+ self.assert_lint('struct dirent* under_score;',
+ 'under_score' + name_error_message)
+ self.assert_lint('long under_score;',
+ 'under_score' + name_error_message)
+ self.assert_lint('long long under_score;',
+ 'under_score' + name_error_message)
+ self.assert_lint('long double under_score;',
+ 'under_score' + name_error_message)
+ self.assert_lint('long long int under_score;',
+ 'under_score' + name_error_message)
+
+ # Declarations in control statement.
+ self.assert_lint('if (int under_score = 42) {',
+ 'under_score' + name_error_message)
+ self.assert_lint('else if (int under_score = 42) {',
+ 'under_score' + name_error_message)
+ self.assert_lint('for (int under_score = 42; cond; i++) {',
+ 'under_score' + name_error_message)
+ self.assert_lint('while (foo & under_score = bar) {',
+ 'under_score' + name_error_message)
+ self.assert_lint('for (foo * under_score = p; cond; i++) {',
+ 'under_score' + name_error_message)
+ self.assert_lint('for (foo * under_score; cond; i++) {',
+ 'under_score' + name_error_message)
+ self.assert_lint('while (foo & value_in_thirdparty_library) {', '')
+ self.assert_lint('while (foo * value_in_thirdparty_library) {', '')
+ self.assert_lint('if (mli && S_OK == mli->foo()) {', '')
+
+ # More member variables and functions.
+ self.assert_lint('int SomeClass::s_validName', '')
+ self.assert_lint('int m_under_score;',
+ 'm_under_score' + name_error_message)
+ self.assert_lint('int SomeClass::s_under_score = 0;',
+ 'SomeClass::s_under_score' + name_error_message)
+ self.assert_lint('int SomeClass::under_score = 0;',
+ 'SomeClass::under_score' + name_error_message)
+
+ # Other statements.
+ self.assert_lint('return INT_MAX;', '')
+ self.assert_lint('return_t under_score;',
+ 'under_score' + name_error_message)
+ self.assert_lint('goto under_score;',
+ 'under_score' + name_error_message)
+
+ # Multiple variables in one line.
+ self.assert_lint('void myFunction(int variable1, int another_variable);',
+ 'another_variable' + name_error_message)
+ self.assert_lint('int variable1, another_variable;',
+ 'another_variable' + name_error_message)
+ self.assert_lint('int first_variable, secondVariable;',
+ 'first_variable' + name_error_message)
+ self.assert_lint('void my_function(int variable_1, int variable_2);',
+ ['my_function' + name_error_message,
+ 'variable_1' + name_error_message,
+ 'variable_2' + name_error_message])
+ self.assert_lint('for (int variable_1, variable_2;;) {',
+ ['variable_1' + name_error_message,
+ 'variable_2' + name_error_message])
+
+ # There is an exception for op code functions but only in the JavaScriptCore directory.
+ self.assert_lint('void this_op_code(int var1, int var2)', '', 'JavaScriptCore/foo.cpp')
+ self.assert_lint('void this_op_code(int var1, int var2)', 'this_op_code' + name_error_message)
+
+ # const_iterator is allowed as well.
+ self.assert_lint('typedef VectorType::const_iterator const_iterator;', '')
+
def test_other(self):
# FIXME: Implement this.
diff --git a/WebKitTools/Scripts/modules/executive.py b/WebKitTools/Scripts/modules/executive.py
new file mode 100644
index 0000000..b73e17d
--- /dev/null
+++ b/WebKitTools/Scripts/modules/executive.py
@@ -0,0 +1,124 @@
+# Copyright (c) 2009, Google Inc. All rights reserved.
+# Copyright (c) 2009 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:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * 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.
+# * Neither the name of Google Inc. 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 THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+# OWNER 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.
+
+import os
+import StringIO
+import subprocess
+import sys
+
+from modules.logging import tee
+
+
+class ScriptError(Exception):
+ def __init__(self, message=None, script_args=None, exit_code=None, output=None, cwd=None):
+ if not message:
+ message = 'Failed to run "%s"' % script_args
+ if exit_code:
+ message += " exit_code: %d" % exit_code
+ if cwd:
+ message += " cwd: %s" % cwd
+
+ Exception.__init__(self, message)
+ self.script_args = script_args # 'args' is already used by Exception
+ self.exit_code = exit_code
+ self.output = output
+ self.cwd = cwd
+
+ def message_with_output(self, output_limit=500):
+ if self.output:
+ if output_limit and len(self.output) > output_limit:
+ return "%s\nLast %s characters of output:\n%s" % (self, output_limit, self.output[-output_limit:])
+ return "%s\n%s" % (self, self.output)
+ return str(self)
+
+
+# FIXME: This should not be a global static.
+# New code should use Executive.run_command directly instead
+def run_command(*args, **kwargs):
+ return Executive().run_command(*args, **kwargs)
+
+
+class Executive(object):
+ def _run_command_with_teed_output(self, args, teed_output):
+ child_process = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
+
+ # Use our own custom wait loop because Popen ignores a tee'd stderr/stdout.
+ # FIXME: This could be improved not to flatten output to stdout.
+ while True:
+ output_line = child_process.stdout.readline()
+ if output_line == "" and child_process.poll() != None:
+ return child_process.poll()
+ teed_output.write(output_line)
+
+ def run_and_throw_if_fail(self, args, quiet=False):
+ # Cache the child's output locally so it can be used for error reports.
+ child_out_file = StringIO.StringIO()
+ if quiet:
+ dev_null = open(os.devnull, "w")
+ child_stdout = tee(child_out_file, dev_null if quiet else sys.stdout)
+ exit_code = self._run_command_with_teed_output(args, child_stdout)
+ if quiet:
+ dev_null.close()
+
+ child_output = child_out_file.getvalue()
+ child_out_file.close()
+
+ if exit_code:
+ raise ScriptError(script_args=args, exit_code=exit_code, output=child_output)
+
+ # Error handlers do not need to be static methods once all callers are updated to use an Executive object.
+ @staticmethod
+ def default_error_handler(error):
+ raise error
+
+ @staticmethod
+ def ignore_error(error):
+ pass
+
+ # FIXME: This should be merged with run_and_throw_if_fail
+ def run_command(self, args, cwd=None, input=None, error_handler=None, return_exit_code=False, return_stderr=True):
+ if hasattr(input, 'read'): # Check if the input is a file.
+ stdin = input
+ string_to_communicate = None
+ else:
+ stdin = subprocess.PIPE if input else None
+ string_to_communicate = input
+ if return_stderr:
+ stderr = subprocess.STDOUT
+ else:
+ stderr = None
+ process = subprocess.Popen(args, stdin=stdin, stdout=subprocess.PIPE, stderr=stderr, cwd=cwd)
+ output = process.communicate(string_to_communicate)[0]
+ exit_code = process.wait()
+ if exit_code:
+ script_error = ScriptError(script_args=args, exit_code=exit_code, output=output, cwd=cwd)
+ (error_handler or self.default_error_handler)(script_error)
+ if return_exit_code:
+ return exit_code
+ return output
diff --git a/WebKitTools/Scripts/modules/grammar.py b/WebKitTools/Scripts/modules/grammar.py
new file mode 100644
index 0000000..dd2967a
--- /dev/null
+++ b/WebKitTools/Scripts/modules/grammar.py
@@ -0,0 +1,43 @@
+#!/usr/bin/env python
+# Copyright (c) 2009, Google Inc. All rights reserved.
+# Copyright (c) 2009 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:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * 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.
+# * Neither the name of Google Inc. 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 THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+# OWNER 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.
+
+import re
+
+def plural(noun):
+ # This is a dumb plural() implementation which was just enough for our uses.
+ if re.search("h$", noun):
+ return noun + "es"
+ else:
+ return noun + "s"
+
+def pluralize(noun, count):
+ if count != 1:
+ noun = plural(noun)
+ return "%d %s" % (count, noun)
diff --git a/WebKitTools/Scripts/modules/landingsequence.py b/WebKitTools/Scripts/modules/landingsequence.py
new file mode 100644
index 0000000..90683f4
--- /dev/null
+++ b/WebKitTools/Scripts/modules/landingsequence.py
@@ -0,0 +1,113 @@
+#!/usr/bin/env python
+# Copyright (c) 2009, Google Inc. All rights reserved.
+# Copyright (c) 2009 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:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * 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.
+# * Neither the name of Google Inc. 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 THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+# OWNER 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.
+
+from modules.comments import bug_comment_from_commit_text
+from modules.executive import ScriptError
+from modules.logging import log
+from modules.scm import CheckoutNeedsUpdate
+from modules.webkitport import WebKitPort
+from modules.workqueue import WorkQueue
+from modules.buildsteps import CleanWorkingDirectoryStep, UpdateStep, ApplyPatchStep, EnsureBuildersAreGreenStep, BuildStep, RunTestsStep, CommitStep, ClosePatchStep, CloseBugStep
+
+
+class LandingSequenceErrorHandler():
+ @classmethod
+ def handle_script_error(cls, tool, patch, script_error):
+ raise NotImplementedError, "subclasses must implement"
+
+# FIXME: This class is slowing being killed and replaced with StepSequence.
+class LandingSequence:
+ def __init__(self, patch, options, tool):
+ self._patch = patch
+ self._options = options
+ self._tool = tool
+ self._port = WebKitPort.port(self._options.port)
+
+ def run(self):
+ self.clean()
+ self.update()
+ self.apply_patch()
+ self.check_builders()
+ self.build()
+ self.test()
+ commit_log = self.commit()
+ self.close_patch(commit_log)
+ self.close_bug()
+
+ def run_and_handle_errors(self):
+ try:
+ self.run()
+ except CheckoutNeedsUpdate, e:
+ log("Commit failed because the checkout is out of date. Please update and try again.")
+ log("You can pass --no-build to skip building/testing after update if you believe the new commits did not affect the results.")
+ WorkQueue.exit_after_handled_error(e)
+ except ScriptError, e:
+ if not self._options.quiet:
+ log(e.message_with_output())
+ if self._options.parent_command:
+ command = self._tool.command_by_name(self._options.parent_command)
+ command.handle_script_error(self._tool, self._patch, e)
+ WorkQueue.exit_after_handled_error(e)
+
+ def clean(self):
+ step = CleanWorkingDirectoryStep(self._tool, self._options)
+ step.run()
+
+ def update(self):
+ step = UpdateStep(self._tool, self._options)
+ step.run()
+
+ def apply_patch(self):
+ step = ApplyPatchStep(self._tool, self._options, self._patch)
+ step.run()
+
+ def check_builders(self):
+ step = EnsureBuildersAreGreenStep(self._tool, self._options)
+ step.run()
+
+ def build(self):
+ step = BuildStep(self._tool, self._options)
+ step.run()
+
+ def test(self):
+ step = RunTestsStep(self._tool, self._options)
+ step.run()
+
+ def commit(self):
+ step = CommitStep(self._tool, self._options)
+ return step.run()
+
+ def close_patch(self, commit_log):
+ step = ClosePatchStep(self._tool, self._options, self._patch)
+ step.run(commit_log)
+
+ def close_bug(self):
+ step = CloseBugStep(self._tool, self._options, self._patch)
+ step.run()
diff --git a/WebKitTools/Scripts/modules/logging.py b/WebKitTools/Scripts/modules/logging.py
index cbccacf..7b7cec5 100644
--- a/WebKitTools/Scripts/modules/logging.py
+++ b/WebKitTools/Scripts/modules/logging.py
@@ -29,6 +29,7 @@
#
# WebKit's Python module for logging
+import os
import sys
def log(string):
@@ -46,3 +47,38 @@ class tee:
def write(self, string):
for file in self.files:
file.write(string)
+
+class OutputTee:
+ def __init__(self):
+ self._original_stdout = None
+ self._original_stderr = None
+ self._files_for_output = []
+
+ def add_log(self, path):
+ log_file = self._open_log_file(path)
+ self._files_for_output.append(log_file)
+ self._tee_outputs_to_files(self._files_for_output)
+ return log_file
+
+ def remove_log(self, log_file):
+ self._files_for_output.remove(log_file)
+ self._tee_outputs_to_files(self._files_for_output)
+ log_file.close()
+
+ @staticmethod
+ def _open_log_file(log_path):
+ (log_directory, log_name) = os.path.split(log_path)
+ if log_directory and not os.path.exists(log_directory):
+ os.makedirs(log_directory)
+ return open(log_path, 'a+')
+
+ def _tee_outputs_to_files(self, files):
+ if not self._original_stdout:
+ self._original_stdout = sys.stdout
+ self._original_stderr = sys.stderr
+ if files and len(files):
+ sys.stdout = tee(self._original_stdout, *files)
+ sys.stderr = tee(self._original_stderr, *files)
+ else:
+ sys.stdout = self._original_stdout
+ sys.stderr = self._original_stderr
diff --git a/WebKitTools/Scripts/modules/logging_unittest.py b/WebKitTools/Scripts/modules/logging_unittest.py
index 7d41e56..b09a563 100644
--- a/WebKitTools/Scripts/modules/logging_unittest.py
+++ b/WebKitTools/Scripts/modules/logging_unittest.py
@@ -32,8 +32,8 @@ import StringIO
import tempfile
import unittest
+from modules.executive import ScriptError
from modules.logging import *
-from modules.scm import ScriptError
class LoggingTest(unittest.TestCase):
diff --git a/WebKitTools/Scripts/modules/mock.py b/WebKitTools/Scripts/modules/mock.py
new file mode 100644
index 0000000..f6f328e
--- /dev/null
+++ b/WebKitTools/Scripts/modules/mock.py
@@ -0,0 +1,309 @@
+# mock.py
+# Test tools for mocking and patching.
+# Copyright (C) 2007-2009 Michael Foord
+# E-mail: fuzzyman AT voidspace DOT org DOT uk
+
+# mock 0.6.0
+# http://www.voidspace.org.uk/python/mock/
+
+# Released subject to the BSD License
+# Please see http://www.voidspace.org.uk/python/license.shtml
+
+# 2009-11-25: Licence downloaded from above URL.
+# BEGIN DOWNLOADED LICENSE
+#
+# Copyright (c) 2003-2009, Michael Foord
+# All rights reserved.
+# E-mail : fuzzyman AT voidspace DOT org DOT uk
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#
+# * 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.
+#
+# * Neither the name of Michael Foord nor the name of Voidspace
+# may be used to endorse or promote products derived from this
+# software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+# OWNER 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.
+#
+# END DOWNLOADED LICENSE
+
+# Scripts maintained at http://www.voidspace.org.uk/python/index.shtml
+# Comments, suggestions and bug reports welcome.
+
+
+__all__ = (
+ 'Mock',
+ 'patch',
+ 'patch_object',
+ 'sentinel',
+ 'DEFAULT'
+)
+
+__version__ = '0.6.0'
+
+class SentinelObject(object):
+ def __init__(self, name):
+ self.name = name
+
+ def __repr__(self):
+ return '<SentinelObject "%s">' % self.name
+
+
+class Sentinel(object):
+ def __init__(self):
+ self._sentinels = {}
+
+ def __getattr__(self, name):
+ return self._sentinels.setdefault(name, SentinelObject(name))
+
+
+sentinel = Sentinel()
+
+DEFAULT = sentinel.DEFAULT
+
+class OldStyleClass:
+ pass
+ClassType = type(OldStyleClass)
+
+def _is_magic(name):
+ return '__%s__' % name[2:-2] == name
+
+def _copy(value):
+ if type(value) in (dict, list, tuple, set):
+ return type(value)(value)
+ return value
+
+
+class Mock(object):
+
+ def __init__(self, spec=None, side_effect=None, return_value=DEFAULT,
+ name=None, parent=None, wraps=None):
+ self._parent = parent
+ self._name = name
+ if spec is not None and not isinstance(spec, list):
+ spec = [member for member in dir(spec) if not _is_magic(member)]
+
+ self._methods = spec
+ self._children = {}
+ self._return_value = return_value
+ self.side_effect = side_effect
+ self._wraps = wraps
+
+ self.reset_mock()
+
+
+ def reset_mock(self):
+ self.called = False
+ self.call_args = None
+ self.call_count = 0
+ self.call_args_list = []
+ self.method_calls = []
+ for child in self._children.itervalues():
+ child.reset_mock()
+ if isinstance(self._return_value, Mock):
+ self._return_value.reset_mock()
+
+
+ def __get_return_value(self):
+ if self._return_value is DEFAULT:
+ self._return_value = Mock()
+ return self._return_value
+
+ def __set_return_value(self, value):
+ self._return_value = value
+
+ return_value = property(__get_return_value, __set_return_value)
+
+
+ def __call__(self, *args, **kwargs):
+ self.called = True
+ self.call_count += 1
+ self.call_args = (args, kwargs)
+ self.call_args_list.append((args, kwargs))
+
+ parent = self._parent
+ name = self._name
+ while parent is not None:
+ parent.method_calls.append((name, args, kwargs))
+ if parent._parent is None:
+ break
+ name = parent._name + '.' + name
+ parent = parent._parent
+
+ ret_val = DEFAULT
+ if self.side_effect is not None:
+ if (isinstance(self.side_effect, Exception) or
+ isinstance(self.side_effect, (type, ClassType)) and
+ issubclass(self.side_effect, Exception)):
+ raise self.side_effect
+
+ ret_val = self.side_effect(*args, **kwargs)
+ if ret_val is DEFAULT:
+ ret_val = self.return_value
+
+ if self._wraps is not None and self._return_value is DEFAULT:
+ return self._wraps(*args, **kwargs)
+ if ret_val is DEFAULT:
+ ret_val = self.return_value
+ return ret_val
+
+
+ def __getattr__(self, name):
+ if self._methods is not None:
+ if name not in self._methods:
+ raise AttributeError("Mock object has no attribute '%s'" % name)
+ elif _is_magic(name):
+ raise AttributeError(name)
+
+ if name not in self._children:
+ wraps = None
+ if self._wraps is not None:
+ wraps = getattr(self._wraps, name)
+ self._children[name] = Mock(parent=self, name=name, wraps=wraps)
+
+ return self._children[name]
+
+
+ def assert_called_with(self, *args, **kwargs):
+ assert self.call_args == (args, kwargs), 'Expected: %s\nCalled with: %s' % ((args, kwargs), self.call_args)
+
+
+def _dot_lookup(thing, comp, import_path):
+ try:
+ return getattr(thing, comp)
+ except AttributeError:
+ __import__(import_path)
+ return getattr(thing, comp)
+
+
+def _importer(target):
+ components = target.split('.')
+ import_path = components.pop(0)
+ thing = __import__(import_path)
+
+ for comp in components:
+ import_path += ".%s" % comp
+ thing = _dot_lookup(thing, comp, import_path)
+ return thing
+
+
+class _patch(object):
+ def __init__(self, target, attribute, new, spec, create):
+ self.target = target
+ self.attribute = attribute
+ self.new = new
+ self.spec = spec
+ self.create = create
+ self.has_local = False
+
+
+ def __call__(self, func):
+ if hasattr(func, 'patchings'):
+ func.patchings.append(self)
+ return func
+
+ def patched(*args, **keywargs):
+ # don't use a with here (backwards compatability with 2.5)
+ extra_args = []
+ for patching in patched.patchings:
+ arg = patching.__enter__()
+ if patching.new is DEFAULT:
+ extra_args.append(arg)
+ args += tuple(extra_args)
+ try:
+ return func(*args, **keywargs)
+ finally:
+ for patching in getattr(patched, 'patchings', []):
+ patching.__exit__()
+
+ patched.patchings = [self]
+ patched.__name__ = func.__name__
+ patched.compat_co_firstlineno = getattr(func, "compat_co_firstlineno",
+ func.func_code.co_firstlineno)
+ return patched
+
+
+ def get_original(self):
+ target = self.target
+ name = self.attribute
+ create = self.create
+
+ original = DEFAULT
+ if _has_local_attr(target, name):
+ try:
+ original = target.__dict__[name]
+ except AttributeError:
+ # for instances of classes with slots, they have no __dict__
+ original = getattr(target, name)
+ elif not create and not hasattr(target, name):
+ raise AttributeError("%s does not have the attribute %r" % (target, name))
+ return original
+
+
+ def __enter__(self):
+ new, spec, = self.new, self.spec
+ original = self.get_original()
+ if new is DEFAULT:
+ # XXXX what if original is DEFAULT - shouldn't use it as a spec
+ inherit = False
+ if spec == True:
+ # set spec to the object we are replacing
+ spec = original
+ if isinstance(spec, (type, ClassType)):
+ inherit = True
+ new = Mock(spec=spec)
+ if inherit:
+ new.return_value = Mock(spec=spec)
+ self.temp_original = original
+ setattr(self.target, self.attribute, new)
+ return new
+
+
+ def __exit__(self, *_):
+ if self.temp_original is not DEFAULT:
+ setattr(self.target, self.attribute, self.temp_original)
+ else:
+ delattr(self.target, self.attribute)
+ del self.temp_original
+
+
+def patch_object(target, attribute, new=DEFAULT, spec=None, create=False):
+ return _patch(target, attribute, new, spec, create)
+
+
+def patch(target, new=DEFAULT, spec=None, create=False):
+ try:
+ target, attribute = target.rsplit('.', 1)
+ except (TypeError, ValueError):
+ raise TypeError("Need a valid target to patch. You supplied: %r" % (target,))
+ target = _importer(target)
+ return _patch(target, attribute, new, spec, create)
+
+
+
+def _has_local_attr(obj, name):
+ try:
+ return name in vars(obj)
+ except TypeError:
+ # objects without a __dict__
+ return hasattr(obj, name)
diff --git a/WebKitTools/Scripts/modules/mock_bugzillatool.py b/WebKitTools/Scripts/modules/mock_bugzillatool.py
new file mode 100644
index 0000000..e600947
--- /dev/null
+++ b/WebKitTools/Scripts/modules/mock_bugzillatool.py
@@ -0,0 +1,153 @@
+# Copyright (C) 2009 Google 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:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * 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.
+# * Neither the name of Google Inc. 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 THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+# OWNER 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.
+
+import os
+
+from modules.mock import Mock
+from modules.scm import CommitMessage
+
+
+class MockBugzilla(Mock):
+ patch1 = {
+ "id" : 197,
+ "bug_id" : 42,
+ "url" : "http://example.com/197",
+ "is_obsolete" : False,
+ "reviewer" : "Reviewer1",
+ "attacher_email" : "Contributer1",
+ }
+ patch2 = {
+ "id" : 128,
+ "bug_id" : 42,
+ "url" : "http://example.com/128",
+ "is_obsolete" : False,
+ "reviewer" : "Reviewer2",
+ "attacher_email" : "Contributer2",
+ }
+ bug_server_url = "http://example.com"
+
+ def fetch_bug_ids_from_commit_queue(self):
+ return [42, 75]
+
+ def fetch_attachment_ids_from_review_queue(self):
+ return [197, 128]
+
+ def fetch_patches_from_commit_queue(self):
+ return [self.patch1, self.patch2]
+
+ def fetch_patches_from_pending_commit_list(self):
+ return [self.patch1, self.patch2]
+
+ def fetch_reviewed_patches_from_bug(self, bug_id):
+ if bug_id == 42:
+ return [self.patch1, self.patch2]
+ return None
+
+ def fetch_attachments_from_bug(self, bug_id):
+ if bug_id == 42:
+ return [self.patch1, self.patch2]
+ return None
+
+ def fetch_patches_from_bug(self, bug_id):
+ if bug_id == 42:
+ return [self.patch1, self.patch2]
+ return None
+
+ def fetch_attachment(self, attachment_id):
+ if attachment_id == 197:
+ return self.patch1
+ if attachment_id == 128:
+ return self.patch2
+ raise Exception("Bogus attachment_id in fetch_attachment.")
+
+ def bug_url_for_bug_id(self, bug_id):
+ return "%s/%s" % (self.bug_server_url, bug_id)
+
+ def attachment_url_for_id(self, attachment_id, action):
+ action_param = ""
+ if action and action != "view":
+ action_param = "&action=%s" % action
+ return "%s/%s%s" % (self.bug_server_url, attachment_id, action_param)
+
+
+class MockBuildBot(Mock):
+ def builder_statuses(self):
+ return [{
+ "name": "Builder1",
+ "is_green": True
+ }, {
+ "name": "Builder2",
+ "is_green": True
+ }]
+
+ def red_core_builders_names(self):
+ return []
+
+class MockSCM(Mock):
+ def __init__(self):
+ Mock.__init__(self)
+ self.checkout_root = os.getcwd()
+
+ def create_patch(self):
+ return "Patch1"
+
+ def commit_ids_from_commitish_arguments(self, args):
+ return ["Commitish1", "Commitish2"]
+
+ def commit_message_for_local_commit(self, commit_id):
+ if commit_id == "Commitish1":
+ return CommitMessage("CommitMessage1\nhttps://bugs.example.org/show_bug.cgi?id=42\n")
+ if commit_id == "Commitish2":
+ return CommitMessage("CommitMessage2\nhttps://bugs.example.org/show_bug.cgi?id=75\n")
+ raise Exception("Bogus commit_id in commit_message_for_local_commit.")
+
+ def create_patch_from_local_commit(self, commit_id):
+ if commit_id == "Commitish1":
+ return "Patch1"
+ if commit_id == "Commitish2":
+ return "Patch2"
+ raise Exception("Bogus commit_id in commit_message_for_local_commit.")
+
+ def modified_changelogs(self):
+ # Ideally we'd return something more interesting here.
+ # The problem is that LandDiff will try to actually read the path from disk!
+ return []
+
+
+class MockBugzillaTool():
+ def __init__(self):
+ self.bugs = MockBugzilla()
+ self.buildbot = MockBuildBot()
+ self.executive = Mock()
+ self._scm = MockSCM()
+
+ def scm(self):
+ return self._scm
+
+ def path(self):
+ return "echo"
diff --git a/WebKitTools/Scripts/modules/multicommandtool.py b/WebKitTools/Scripts/modules/multicommandtool.py
new file mode 100644
index 0000000..0475cf1
--- /dev/null
+++ b/WebKitTools/Scripts/modules/multicommandtool.py
@@ -0,0 +1,253 @@
+# Copyright (c) 2009, Google Inc. All rights reserved.
+# Copyright (c) 2009 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:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * 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.
+# * Neither the name of Google Inc. 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 THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+# OWNER 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.
+#
+# MultiCommandTool provides a framework for writing svn-like/git-like tools
+# which are called with the following format:
+# tool-name [global options] command-name [command options]
+
+import sys
+
+from optparse import OptionParser, IndentedHelpFormatter, SUPPRESS_USAGE, make_option
+
+from modules.grammar import pluralize
+from modules.logging import log
+
+class Command(object):
+ name = None
+ # show_in_main_help = False # Subclasses must define show_in_main_help, we leave it out here to enforce that.
+ def __init__(self, help_text, argument_names=None, options=None, requires_local_commits=False):
+ self.help_text = help_text
+ self.argument_names = argument_names
+ self.required_arguments = self._parse_required_arguments(argument_names)
+ self.options = options
+ self.option_parser = HelpPrintingOptionParser(usage=SUPPRESS_USAGE, add_help_option=False, option_list=self.options)
+ self.requires_local_commits = requires_local_commits
+ self.tool = None
+
+ # The tool calls bind_to_tool on each Command after adding it to its list.
+ def bind_to_tool(self, tool):
+ # Command instances can only be bound to one tool at a time.
+ if self.tool and tool != self.tool:
+ raise Exception("Command already bound to tool!")
+ self.tool = tool
+
+ @staticmethod
+ def _parse_required_arguments(argument_names):
+ required_args = []
+ if not argument_names:
+ return required_args
+ split_args = argument_names.split(" ")
+ for argument in split_args:
+ if argument[0] == '[':
+ # For now our parser is rather dumb. Do some minimal validation that
+ # we haven't confused it.
+ if argument[-1] != ']':
+ raise Exception("Failure to parse argument string %s. Argument %s is missing ending ]" % (argument_names, argument))
+ else:
+ required_args.append(argument)
+ return required_args
+
+ def name_with_arguments(self):
+ usage_string = self.name
+ if self.options:
+ usage_string += " [options]"
+ if self.argument_names:
+ usage_string += " " + self.argument_names
+ return usage_string
+
+ def parse_args(self, args):
+ return self.option_parser.parse_args(args)
+
+ def check_arguments_and_execute(self, args_after_command_name, tool):
+ (command_options, command_args) = self.parse_args(args_after_command_name)
+
+ if len(command_args) < len(self.required_arguments):
+ log("%s required, %s provided. Provided: %s Required: %s\nSee '%s help %s' for usage." % (
+ pluralize("argument", len(self.required_arguments)),
+ pluralize("argument", len(command_args)),
+ "'%s'" % " ".join(command_args),
+ " ".join(self.required_arguments),
+ tool.name(),
+ self.name))
+ return 1
+ return self.execute(command_options, command_args, tool) or 0
+
+ def standalone_help(self):
+ help_text = self.name_with_arguments().ljust(len(self.name_with_arguments()) + 3) + self.help_text + "\n"
+ help_text += self.option_parser.format_option_help(IndentedHelpFormatter())
+ return help_text
+
+ def execute(self, options, args, tool):
+ raise NotImplementedError, "subclasses must implement"
+
+
+class HelpPrintingOptionParser(OptionParser):
+ def __init__(self, epilog_method=None, *args, **kwargs):
+ self.epilog_method = epilog_method
+ OptionParser.__init__(self, *args, **kwargs)
+
+ def error(self, msg):
+ self.print_usage(sys.stderr)
+ error_message = "%s: error: %s\n" % (self.get_prog_name(), msg)
+ error_message += "\nType \"%s --help\" to see usage.\n" % self.get_prog_name()
+ self.exit(1, error_message)
+
+ # We override format_epilog to avoid the default formatting which would paragraph-wrap the epilog
+ # and also to allow us to compute the epilog lazily instead of in the constructor (allowing it to be context sensitive).
+ def format_epilog(self, epilog):
+ if self.epilog_method:
+ return "\n%s\n" % self.epilog_method()
+ return ""
+
+
+class HelpCommand(Command):
+ name = "help"
+ show_in_main_help = False
+
+ def __init__(self):
+ options = [
+ make_option("-a", "--all-commands", action="store_true", dest="show_all_commands", help="Print all available commands"),
+ ]
+ Command.__init__(self, "Display information about this program or its subcommands", "[COMMAND]", options=options)
+ self.show_all_commands = False # A hack used to pass --all-commands to _help_epilog even though it's called by the OptionParser.
+
+ def _help_epilog(self):
+ # Only show commands which are relevant to this checkout's SCM system. Might this be confusing to some users?
+ if self.show_all_commands:
+ epilog = "All %prog commands:\n"
+ relevant_commands = self.tool.commands[:]
+ else:
+ epilog = "Common %prog commands:\n"
+ relevant_commands = filter(self.tool.should_show_in_main_help, self.tool.commands)
+ longest_name_length = max(map(lambda command: len(command.name), relevant_commands))
+ relevant_commands.sort(lambda a, b: cmp(a.name, b.name))
+ command_help_texts = map(lambda command: " %s %s\n" % (command.name.ljust(longest_name_length), command.help_text), relevant_commands)
+ epilog += "%s\n" % "".join(command_help_texts)
+ epilog += "See '%prog help --all-commands' to list all commands.\n"
+ epilog += "See '%prog help COMMAND' for more information on a specific command.\n"
+ return self.tool.global_option_parser.expand_prog_name(epilog)
+
+ def execute(self, options, args, tool):
+ if args:
+ command = self.tool.command_by_name(args[0])
+ if command:
+ print command.standalone_help()
+ return 0
+
+ self.show_all_commands = options.show_all_commands
+ tool.global_option_parser.print_help()
+ return 0
+
+
+class MultiCommandTool(object):
+ def __init__(self, name=None, commands=None):
+ # Allow the unit tests to disable command auto-discovery.
+ self.commands = commands or [cls() for cls in self._find_all_commands() if cls.name]
+ self.help_command = self.command_by_name(HelpCommand.name)
+ # Require a help command, even if the manual test list doesn't include one.
+ if not self.help_command:
+ self.help_command = HelpCommand()
+ self.commands.append(self.help_command)
+ for command in self.commands:
+ command.bind_to_tool(self)
+ self.global_option_parser = HelpPrintingOptionParser(epilog_method=self.help_command._help_epilog, prog=name, usage=self._usage_line())
+
+ @classmethod
+ def _add_all_subclasses(cls, class_to_crawl, seen_classes):
+ for subclass in class_to_crawl.__subclasses__():
+ if subclass not in seen_classes:
+ seen_classes.add(subclass)
+ cls._add_all_subclasses(subclass, seen_classes)
+
+ @classmethod
+ def _find_all_commands(cls):
+ commands = set()
+ cls._add_all_subclasses(Command, commands)
+ return sorted(commands)
+
+ @staticmethod
+ def _usage_line():
+ return "Usage: %prog [options] COMMAND [ARGS]"
+
+ def name(self):
+ return self.global_option_parser.get_prog_name()
+
+ def handle_global_args(self, args):
+ (options, args) = self.global_option_parser.parse_args(args)
+ # We should never hit this because _split_args splits at the first arg without a leading "-".
+ if args:
+ self.global_option_parser.error("Extra arguments before command: %s" % args)
+
+ @staticmethod
+ def _split_args(args):
+ # Assume the first argument which doesn't start with "-" is the command name.
+ command_index = 0
+ for arg in args:
+ if arg[0] != "-":
+ break
+ command_index += 1
+ else:
+ return (args[:], None, [])
+
+ global_args = args[:command_index]
+ command = args[command_index]
+ command_args = args[command_index + 1:]
+ return (global_args, command, command_args)
+
+ def command_by_name(self, command_name):
+ for command in self.commands:
+ if command_name == command.name:
+ return command
+ return None
+
+ def path(self):
+ raise NotImplementedError, "subclasses must implement"
+
+ def should_show_in_main_help(self, command):
+ return command.show_in_main_help
+
+ def should_execute_command(self, command):
+ raise NotImplementedError, "subclasses must implement"
+
+ def main(self, argv=sys.argv):
+ (global_args, command_name, args_after_command_name) = self._split_args(argv[1:])
+
+ # Handle --help, etc:
+ self.handle_global_args(global_args)
+
+ command = self.command_by_name(command_name) or self.help_command
+ if not command:
+ self.global_option_parser.error("%s is not a recognized command" % command_name)
+
+ (should_execute, failure_reason) = self.should_execute_command(command)
+ if not should_execute:
+ log(failure_reason)
+ return 0
+
+ return command.check_arguments_and_execute(args_after_command_name, self)
diff --git a/WebKitTools/Scripts/modules/multicommandtool_unittest.py b/WebKitTools/Scripts/modules/multicommandtool_unittest.py
new file mode 100644
index 0000000..c71cc09
--- /dev/null
+++ b/WebKitTools/Scripts/modules/multicommandtool_unittest.py
@@ -0,0 +1,158 @@
+# Copyright (c) 2009, Google 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:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * 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.
+# * Neither the name of Google Inc. 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 THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+# OWNER 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.
+
+import sys
+import unittest
+from multicommandtool import MultiCommandTool, Command
+from modules.outputcapture import OutputCapture
+
+from optparse import make_option
+
+class TrivialCommand(Command):
+ name = "trivial"
+ show_in_main_help = True
+ def __init__(self, **kwargs):
+ Command.__init__(self, "help text", **kwargs)
+
+ def execute(self, options, args, tool):
+ pass
+
+class UncommonCommand(TrivialCommand):
+ name = "uncommon"
+ show_in_main_help = False
+
+class CommandTest(unittest.TestCase):
+ def test_name_with_arguments(self):
+ command_with_args = TrivialCommand(argument_names="ARG1 ARG2")
+ self.assertEqual(command_with_args.name_with_arguments(), "trivial ARG1 ARG2")
+
+ command_with_args = TrivialCommand(options=[make_option("--my_option")])
+ self.assertEqual(command_with_args.name_with_arguments(), "trivial [options]")
+
+ def test_parse_required_arguments(self):
+ self.assertEqual(Command._parse_required_arguments("ARG1 ARG2"), ["ARG1", "ARG2"])
+ self.assertEqual(Command._parse_required_arguments("[ARG1] [ARG2]"), [])
+ self.assertEqual(Command._parse_required_arguments("[ARG1] ARG2"), ["ARG2"])
+ # Note: We might make our arg parsing smarter in the future and allow this type of arguments string.
+ self.assertRaises(Exception, Command._parse_required_arguments, "[ARG1 ARG2]")
+
+ def test_required_arguments(self):
+ two_required_arguments = TrivialCommand(argument_names="ARG1 ARG2 [ARG3]")
+ capture = OutputCapture()
+ capture.capture_output()
+ exit_code = two_required_arguments.check_arguments_and_execute(["foo"], TrivialTool())
+ (stdout_string, stderr_string) = capture.restore_output()
+ expected_missing_args_error = "2 arguments required, 1 argument provided. Provided: 'foo' Required: ARG1 ARG2\nSee 'trivial-tool help trivial' for usage.\n"
+ self.assertEqual(exit_code, 1)
+ self.assertEqual(stdout_string, "")
+ self.assertEqual(stderr_string, expected_missing_args_error)
+
+
+class TrivialTool(MultiCommandTool):
+ def __init__(self, commands=None):
+ MultiCommandTool.__init__(self, name="trivial-tool", commands=commands)
+
+ def path():
+ return __file__
+
+ def should_execute_command(self, command):
+ return (True, None)
+
+
+class MultiCommandToolTest(unittest.TestCase):
+ def _assert_split(self, args, expected_split):
+ self.assertEqual(MultiCommandTool._split_args(args), expected_split)
+
+ def test_split_args(self):
+ # MultiCommandToolTest._split_args returns: (global_args, command, command_args)
+ full_args = ["--global-option", "command", "--option", "arg"]
+ full_args_expected = (["--global-option"], "command", ["--option", "arg"])
+ self._assert_split(full_args, full_args_expected)
+
+ full_args = []
+ full_args_expected = ([], None, [])
+ self._assert_split(full_args, full_args_expected)
+
+ full_args = ["command", "arg"]
+ full_args_expected = ([], "command", ["arg"])
+ self._assert_split(full_args, full_args_expected)
+
+ def test_command_by_name(self):
+ # This also tests Command auto-discovery.
+ tool = TrivialTool()
+ self.assertEqual(tool.command_by_name("trivial").name, "trivial")
+ self.assertEqual(tool.command_by_name("bar"), None)
+
+ def _assert_tool_main_outputs(self, tool, main_args, expected_stdout, expected_stderr = "", exit_code=0):
+ capture = OutputCapture()
+ capture.capture_output()
+ exit_code = tool.main(main_args)
+ (stdout_string, stderr_string) = capture.restore_output()
+ self.assertEqual(stdout_string, expected_stdout)
+ self.assertEqual(expected_stderr, expected_stderr)
+
+ def test_global_help(self):
+ tool = TrivialTool(commands=[TrivialCommand(), UncommonCommand()])
+ expected_common_commands_help = """Usage: trivial-tool [options] COMMAND [ARGS]
+
+Options:
+ -h, --help show this help message and exit
+
+Common trivial-tool commands:
+ trivial help text
+
+See 'trivial-tool help --all-commands' to list all commands.
+See 'trivial-tool help COMMAND' for more information on a specific command.
+
+"""
+ self._assert_tool_main_outputs(tool, ["tool", "help"], expected_common_commands_help)
+ expected_all_commands_help = """Usage: trivial-tool [options] COMMAND [ARGS]
+
+Options:
+ -h, --help show this help message and exit
+
+All trivial-tool commands:
+ help Display information about this program or its subcommands
+ trivial help text
+ uncommon help text
+
+See 'trivial-tool help --all-commands' to list all commands.
+See 'trivial-tool help COMMAND' for more information on a specific command.
+
+"""
+ self._assert_tool_main_outputs(tool, ["tool", "help", "--all-commands"], expected_all_commands_help)
+
+ def test_command_help(self):
+ command_with_options = TrivialCommand(options=[make_option("--my_option")])
+ tool = TrivialTool(commands=[command_with_options])
+ expected_subcommand_help = "trivial [options] help text\nOptions:\n --my_option=MY_OPTION\n\n"
+ self._assert_tool_main_outputs(tool, ["tool", "help", "trivial"], expected_subcommand_help)
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/WebKitTools/Scripts/modules/outputcapture.py b/WebKitTools/Scripts/modules/outputcapture.py
new file mode 100644
index 0000000..f02fc5d
--- /dev/null
+++ b/WebKitTools/Scripts/modules/outputcapture.py
@@ -0,0 +1,53 @@
+# Copyright (c) 2009, Google 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:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * 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.
+# * Neither the name of Google Inc. 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 THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+# OWNER 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.
+#
+# Class for unittest support. Used for capturing stderr/stdout.
+
+import sys
+from StringIO import StringIO
+
+class OutputCapture(object):
+ def __init__(self):
+ self.saved_outputs = dict()
+
+ def _capture_output_with_name(self, output_name):
+ self.saved_outputs[output_name] = getattr(sys, output_name)
+ setattr(sys, output_name, StringIO())
+
+ def _restore_output_with_name(self, output_name):
+ captured_output = getattr(sys, output_name).getvalue()
+ setattr(sys, output_name, self.saved_outputs[output_name])
+ del self.saved_outputs[output_name]
+ return captured_output
+
+ def capture_output(self):
+ self._capture_output_with_name("stdout")
+ self._capture_output_with_name("stderr")
+
+ def restore_output(self):
+ return (self._restore_output_with_name("stdout"), self._restore_output_with_name("stderr"))
diff --git a/WebKitTools/Scripts/modules/patchcollection.py b/WebKitTools/Scripts/modules/patchcollection.py
new file mode 100644
index 0000000..add8129
--- /dev/null
+++ b/WebKitTools/Scripts/modules/patchcollection.py
@@ -0,0 +1,71 @@
+#!/usr/bin/env python
+# Copyright (c) 2009, Google 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:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * 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.
+# * Neither the name of Google Inc. 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 THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+# OWNER 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.
+
+class PersistentPatchCollectionDelegate:
+ def collection_name(self):
+ raise NotImplementedError, "subclasses must implement"
+
+ def fetch_potential_patch_ids(self):
+ raise NotImplementedError, "subclasses must implement"
+
+ def status_server(self):
+ raise NotImplementedError, "subclasses must implement"
+
+
+class PersistentPatchCollection:
+ _initial_status = "Pending"
+ _pass_status = "Pass"
+ _fail_status = "Fail"
+ def __init__(self, delegate):
+ self._delegate = delegate
+ self._name = self._delegate.collection_name()
+ self._status = self._delegate.status_server()
+ self._status_cache = {}
+
+ def _cached_status(self, patch_id):
+ cached = self._status_cache.get(patch_id)
+ if cached:
+ return cached
+ status = self._status.patch_status(self._name, patch_id)
+ if status:
+ self._status_cache[patch_id] = status
+ return status
+
+ def next(self):
+ patch_ids = self._delegate.fetch_potential_patch_ids()
+ for patch_id in patch_ids:
+ status = self._cached_status(patch_id)
+ if not status:
+ return patch_id
+
+ def did_pass(self, patch):
+ self._status.update_status(self._name, self._pass_status, patch)
+
+ def did_fail(self, patch):
+ self._status.update_status(self._name, self._fail_status, patch)
diff --git a/WebKitTools/Scripts/modules/scm.py b/WebKitTools/Scripts/modules/scm.py
index 3ffa23b..ff26693 100644
--- a/WebKitTools/Scripts/modules/scm.py
+++ b/WebKitTools/Scripts/modules/scm.py
@@ -34,6 +34,8 @@ import re
import subprocess
# Import WebKit-specific modules.
+from modules.changelogs import ChangeLog
+from modules.executive import Executive, run_command, ScriptError
from modules.logging import error, log
def detect_scm_system(path):
@@ -77,44 +79,16 @@ class CommitMessage:
return "\n".join(self.message_lines) + "\n"
-class ScriptError(Exception):
- def __init__(self, message=None, script_args=None, exit_code=None, output=None, cwd=None):
- if not message:
- message = 'Failed to run "%s"' % script_args
- if exit_code:
- message += " exit_code: %d" % exit_code
- if cwd:
- message += " cwd: %s" % cwd
-
- Exception.__init__(self, message)
- self.script_args = script_args # 'args' is already used by Exception
- self.exit_code = exit_code
- self.output = output
- self.cwd = cwd
-
- def message_with_output(self, output_limit=500):
- if self.output:
- if len(self.output) > output_limit:
- return "%s\nLast %s characters of output:\n%s" % (self, output_limit, self.output[-output_limit:])
- return "%s\n%s" % (self, self.output)
- return str(self)
-
-
class CheckoutNeedsUpdate(ScriptError):
def __init__(self, script_args, exit_code, output, cwd):
ScriptError.__init__(self, script_args=script_args, exit_code=exit_code, output=output, cwd=cwd)
-def default_error_handler(error):
- raise error
-
def commit_error_handler(error):
if re.search("resource out of date", error.output):
raise CheckoutNeedsUpdate(script_args=error.script_args, exit_code=error.exit_code, output=error.output, cwd=error.cwd)
- default_error_handler(error)
+ Executive.default_error_handler(error)
-def ignore_error(error):
- pass
class SCM:
def __init__(self, cwd, dryrun=False):
@@ -122,33 +96,15 @@ class SCM:
self.checkout_root = self.find_checkout_root(self.cwd)
self.dryrun = dryrun
- @staticmethod
- def run_command(args, cwd=None, input=None, error_handler=default_error_handler, return_exit_code=False):
- if hasattr(input, 'read'): # Check if the input is a file.
- stdin = input
- string_to_communicate = None
- else:
- stdin = subprocess.PIPE if input else None
- string_to_communicate = input
- process = subprocess.Popen(args, stdin=stdin, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, cwd=cwd)
- output = process.communicate(string_to_communicate)[0].rstrip()
- exit_code = process.wait()
- if exit_code:
- script_error = ScriptError(script_args=args, exit_code=exit_code, output=output, cwd=cwd)
- error_handler(script_error)
- if return_exit_code:
- return exit_code
- return output
-
def scripts_directory(self):
return os.path.join(self.checkout_root, "WebKitTools", "Scripts")
def script_path(self, script_name):
return os.path.join(self.scripts_directory(), script_name)
- def ensure_clean_working_directory(self, force):
- if not force and not self.working_directory_is_clean():
- print self.run_command(self.status_command(), error_handler=ignore_error)
+ def ensure_clean_working_directory(self, force_clean):
+ if not force_clean and not self.working_directory_is_clean():
+ print run_command(self.status_command(), error_handler=Executive.ignore_error)
raise ScriptError(message="Working directory has modifications, pass --force-clean or --no-clean to continue.")
log("Cleaning working directory")
@@ -168,15 +124,17 @@ class SCM:
# It's possible that the patch was not made from the root directory.
# We should detect and handle that case.
curl_process = subprocess.Popen(['curl', '--location', '--silent', '--show-error', patch['url']], stdout=subprocess.PIPE)
- args = [self.script_path('svn-apply'), '--reviewer', patch['reviewer']]
+ args = [self.script_path('svn-apply')]
+ if patch.get('reviewer'):
+ args += ['--reviewer', patch['reviewer']]
if force:
args.append('--force')
- self.run_command(args, input=curl_process.stdout)
+ run_command(args, input=curl_process.stdout)
def run_status_and_extract_filenames(self, status_command, status_regexp):
filenames = []
- for line in self.run_command(status_command).splitlines():
+ for line in run_command(status_command).splitlines():
match = re.search(status_regexp, line)
if not match:
continue
@@ -204,6 +162,28 @@ class SCM:
changelog_paths.append(path)
return changelog_paths
+ # FIXME: Requires unit test
+ # FIXME: commit_message_for_this_commit and modified_changelogs don't
+ # really belong here. We should have a separate module for
+ # handling ChangeLogs.
+ def commit_message_for_this_commit(self):
+ changelog_paths = self.modified_changelogs()
+ if not len(changelog_paths):
+ raise ScriptError(message="Found no modified ChangeLogs, cannot create a commit message.\n"
+ "All changes require a ChangeLog. See:\n"
+ "http://webkit.org/coding/contributing.html")
+
+ changelog_messages = []
+ for changelog_path in changelog_paths:
+ log("Parsing ChangeLog: %s" % changelog_path)
+ changelog_entry = ChangeLog(changelog_path).latest_entry()
+ if not changelog_entry:
+ raise ScriptError(message="Failed to parse ChangeLog: " + os.path.abspath(changelog_path))
+ changelog_messages.append(changelog_entry)
+
+ # FIXME: We should sort and label the ChangeLog messages like commit-log-editor does.
+ return CommitMessage("".join(changelog_messages).splitlines())
+
@staticmethod
def in_working_directory(path):
raise NotImplementedError, "subclasses must implement"
@@ -222,9 +202,6 @@ class SCM:
def clean_working_directory(self):
raise NotImplementedError, "subclasses must implement"
- def update_webkit(self):
- raise NotImplementedError, "subclasses must implement"
-
def status_command(self):
raise NotImplementedError, "subclasses must implement"
@@ -295,7 +272,7 @@ class SVN(SCM):
@classmethod
def value_from_svn_info(cls, path, field_name):
svn_info_args = ['svn', 'info', path]
- info_output = cls.run_command(svn_info_args)
+ info_output = run_command(svn_info_args).rstrip()
match = re.search("^%s: (?P<value>.+)$" % field_name, info_output, re.MULTILINE)
if not match:
raise ScriptError(script_args=svn_info_args, message='svn info did not contain a %s.' % field_name)
@@ -323,18 +300,15 @@ class SVN(SCM):
def svn_version(self):
if not self.cached_version:
- self.cached_version = self.run_command(['svn', '--version', '--quiet'])
+ self.cached_version = run_command(['svn', '--version', '--quiet'])
return self.cached_version
def working_directory_is_clean(self):
- return self.run_command(['svn', 'diff']) == ""
+ return run_command(['svn', 'diff']) == ""
def clean_working_directory(self):
- self.run_command(['svn', 'revert', '-R', '.'])
-
- def update_webkit(self):
- self.run_command(self.script_path("update-webkit"))
+ run_command(['svn', 'revert', '-R', '.'])
def status_command(self):
return ['svn', 'status']
@@ -354,10 +328,10 @@ class SVN(SCM):
return "svn"
def create_patch(self):
- return self.run_command(self.script_path("svn-create-patch"), cwd=self.checkout_root)
+ return run_command(self.script_path("svn-create-patch"), cwd=self.checkout_root, return_stderr=False)
def diff_for_revision(self, revision):
- return self.run_command(['svn', 'diff', '-c', str(revision)])
+ return run_command(['svn', 'diff', '-c', str(revision)])
def _repository_url(self):
return self.value_from_svn_info(self.checkout_root, 'URL')
@@ -367,20 +341,20 @@ class SVN(SCM):
svn_merge_args = ['svn', 'merge', '--non-interactive', '-c', '-%s' % revision, self._repository_url()]
log("WARNING: svn merge has been known to take more than 10 minutes to complete. It is recommended you use git for rollouts.")
log("Running '%s'" % " ".join(svn_merge_args))
- self.run_command(svn_merge_args)
+ run_command(svn_merge_args)
def revert_files(self, file_paths):
- self.run_command(['svn', 'revert'] + file_paths)
+ run_command(['svn', 'revert'] + file_paths)
def commit_with_message(self, message):
if self.dryrun:
# Return a string which looks like a commit so that things which parse this output will succeed.
return "Dry run, no commit.\nCommitted revision 0."
- return self.run_command(['svn', 'commit', '-m', message], error_handler=commit_error_handler)
+ return run_command(['svn', 'commit', '-m', message], error_handler=commit_error_handler)
def svn_commit_log(self, svn_revision):
svn_revision = self.strip_r_from_svn_revision(str(svn_revision))
- return self.run_command(['svn', 'log', '--non-interactive', '--revision', svn_revision]);
+ return run_command(['svn', 'log', '--non-interactive', '--revision', svn_revision]);
def last_svn_commit_log(self):
# BASE is the checkout revision, HEAD is the remote repository revision
@@ -394,12 +368,12 @@ class Git(SCM):
@classmethod
def in_working_directory(cls, path):
- return cls.run_command(['git', 'rev-parse', '--is-inside-work-tree'], cwd=path, error_handler=ignore_error) == "true"
+ return run_command(['git', 'rev-parse', '--is-inside-work-tree'], cwd=path, error_handler=Executive.ignore_error).rstrip() == "true"
@classmethod
def find_checkout_root(cls, path):
# "git rev-parse --show-cdup" would be another way to get to the root
- (checkout_root, dot_git) = os.path.split(cls.run_command(['git', 'rev-parse', '--git-dir'], cwd=path))
+ (checkout_root, dot_git) = os.path.split(run_command(['git', 'rev-parse', '--git-dir'], cwd=path))
# If we were using 2.6 # checkout_root = os.path.relpath(checkout_root, path)
if not os.path.isabs(checkout_root): # Sometimes git returns relative paths
checkout_root = os.path.join(path, checkout_root)
@@ -411,28 +385,23 @@ class Git(SCM):
def discard_local_commits(self):
- self.run_command(['git', 'reset', '--hard', 'trunk'])
+ run_command(['git', 'reset', '--hard', 'trunk'])
def local_commits(self):
- return self.run_command(['git', 'log', '--pretty=oneline', 'HEAD...trunk']).splitlines()
+ return run_command(['git', 'log', '--pretty=oneline', 'HEAD...trunk']).splitlines()
def rebase_in_progress(self):
return os.path.exists(os.path.join(self.checkout_root, '.git/rebase-apply'))
def working_directory_is_clean(self):
- return self.run_command(['git', 'diff-index', 'HEAD']) == ""
+ return run_command(['git', 'diff-index', 'HEAD']) == ""
def clean_working_directory(self):
# Could run git clean here too, but that wouldn't match working_directory_is_clean
- self.run_command(['git', 'reset', '--hard', 'HEAD'])
+ run_command(['git', 'reset', '--hard', 'HEAD'])
# Aborting rebase even though this does not match working_directory_is_clean
if self.rebase_in_progress():
- self.run_command(['git', 'rebase', '--abort'])
-
- def update_webkit(self):
- # FIXME: Call update-webkit once https://bugs.webkit.org/show_bug.cgi?id=27162 is fixed.
- log("Updating working directory")
- self.run_command(['git', 'svn', 'rebase'])
+ run_command(['git', 'rebase', '--abort'])
def status_command(self):
return ['git', 'status']
@@ -450,12 +419,12 @@ class Git(SCM):
return "git"
def create_patch(self):
- return self.run_command(['git', 'diff', 'HEAD'])
+ return run_command(['git', 'diff', '--binary', 'HEAD'])
@classmethod
def git_commit_from_svn_revision(cls, revision):
# git svn find-rev always exits 0, even when the revision is not found.
- return cls.run_command(['git', 'svn', 'find-rev', 'r%s' % revision])
+ return run_command(['git', 'svn', 'find-rev', 'r%s' % revision]).rstrip()
def diff_for_revision(self, revision):
git_commit = self.git_commit_from_svn_revision(revision)
@@ -469,15 +438,15 @@ class Git(SCM):
# I think this will always fail due to ChangeLogs.
# FIXME: We need to detec specific failure conditions and handle them.
- self.run_command(['git', 'revert', '--no-commit', git_commit], error_handler=ignore_error)
+ run_command(['git', 'revert', '--no-commit', git_commit], error_handler=Executive.ignore_error)
# Fix any ChangeLogs if necessary.
changelog_paths = self.modified_changelogs()
if len(changelog_paths):
- self.run_command([self.script_path('resolve-ChangeLogs')] + changelog_paths)
+ run_command([self.script_path('resolve-ChangeLogs')] + changelog_paths)
def revert_files(self, file_paths):
- self.run_command(['git', 'checkout', 'HEAD'] + file_paths)
+ run_command(['git', 'checkout', 'HEAD'] + file_paths)
def commit_with_message(self, message):
self.commit_locally_with_message(message)
@@ -485,27 +454,27 @@ class Git(SCM):
def svn_commit_log(self, svn_revision):
svn_revision = self.strip_r_from_svn_revision(svn_revision)
- return self.run_command(['git', 'svn', 'log', '-r', svn_revision])
+ return run_command(['git', 'svn', 'log', '-r', svn_revision])
def last_svn_commit_log(self):
- return self.run_command(['git', 'svn', 'log', '--limit=1'])
+ return run_command(['git', 'svn', 'log', '--limit=1'])
# Git-specific methods:
def create_patch_from_local_commit(self, commit_id):
- return self.run_command(['git', 'diff', commit_id + "^.." + commit_id])
+ return run_command(['git', 'diff', '--binary', commit_id + "^.." + commit_id])
def create_patch_since_local_commit(self, commit_id):
- return self.run_command(['git', 'diff', commit_id])
+ return run_command(['git', 'diff', '--binary', commit_id])
def commit_locally_with_message(self, message):
- self.run_command(['git', 'commit', '--all', '-F', '-'], input=message)
+ run_command(['git', 'commit', '--all', '-F', '-'], input=message)
def push_local_commits_to_server(self):
if self.dryrun:
# Return a string which looks like a commit so that things which parse this output will succeed.
return "Dry run, no remote commit.\nCommitted r0"
- return self.run_command(['git', 'svn', 'dcommit'], error_handler=commit_error_handler)
+ return run_command(['git', 'svn', 'dcommit'], error_handler=commit_error_handler)
# This function supports the following argument formats:
# no args : rev-list trunk..HEAD
@@ -522,14 +491,14 @@ class Git(SCM):
if '...' in commitish:
raise ScriptError(message="'...' is not supported (found in '%s'). Did you mean '..'?" % commitish)
elif '..' in commitish:
- commit_ids += reversed(self.run_command(['git', 'rev-list', commitish]).splitlines())
+ commit_ids += reversed(run_command(['git', 'rev-list', commitish]).splitlines())
else:
# Turn single commits or branch or tag names into commit ids.
- commit_ids += self.run_command(['git', 'rev-parse', '--revs-only', commitish]).splitlines()
+ commit_ids += run_command(['git', 'rev-parse', '--revs-only', commitish]).splitlines()
return commit_ids
def commit_message_for_local_commit(self, commit_id):
- commit_lines = self.run_command(['git', 'cat-file', 'commit', commit_id]).splitlines()
+ commit_lines = run_command(['git', 'cat-file', 'commit', commit_id]).splitlines()
# Skip the git headers.
first_line_after_headers = 0
@@ -540,4 +509,4 @@ class Git(SCM):
return CommitMessage(commit_lines[first_line_after_headers:])
def files_changed_summary_for_commit(self, commit_id):
- return self.run_command(['git', 'diff-tree', '--shortstat', '--no-commit-id', commit_id])
+ return run_command(['git', 'diff-tree', '--shortstat', '--no-commit-id', commit_id])
diff --git a/WebKitTools/Scripts/modules/scm_unittest.py b/WebKitTools/Scripts/modules/scm_unittest.py
index 784303f..8e82f3c 100644
--- a/WebKitTools/Scripts/modules/scm_unittest.py
+++ b/WebKitTools/Scripts/modules/scm_unittest.py
@@ -29,21 +29,22 @@
import base64
import os
+import os.path
import re
import stat
import subprocess
import tempfile
import unittest
import urllib
-from modules.scm import detect_scm_system, SCM, ScriptError, CheckoutNeedsUpdate, ignore_error, commit_error_handler
+from datetime import date
+from modules.executive import Executive, run_command, ScriptError
+from modules.scm import detect_scm_system, SCM, CheckoutNeedsUpdate, commit_error_handler
# Eventually we will want to write tests which work for both scms. (like update_webkit, changed_files, etc.)
# Perhaps through some SCMTest base-class which both SVNTest and GitTest inherit from.
-def run(args, cwd=None):
- return SCM.run_command(args, cwd=cwd)
-
+# FIXME: This should be unified into one of the executive.py commands!
def run_silent(args, cwd=None):
process = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=cwd)
process.communicate() # ignore output
@@ -72,26 +73,26 @@ class SVNTestRepository:
test_file.write("test1")
test_file.flush()
- run(['svn', 'add', 'test_file'])
- run(['svn', 'commit', '--quiet', '--message', 'initial commit'])
+ run_command(['svn', 'add', 'test_file'])
+ run_command(['svn', 'commit', '--quiet', '--message', 'initial commit'])
test_file.write("test2")
test_file.flush()
- run(['svn', 'commit', '--quiet', '--message', 'second commit'])
+ run_command(['svn', 'commit', '--quiet', '--message', 'second commit'])
test_file.write("test3\n")
test_file.flush()
- run(['svn', 'commit', '--quiet', '--message', 'third commit'])
+ run_command(['svn', 'commit', '--quiet', '--message', 'third commit'])
test_file.write("test4\n")
test_file.close()
- run(['svn', 'commit', '--quiet', '--message', 'fourth commit'])
+ run_command(['svn', 'commit', '--quiet', '--message', 'fourth commit'])
# svn does not seem to update after commit as I would expect.
- run(['svn', 'update'])
+ run_command(['svn', 'update'])
@classmethod
def setup(cls, test_object):
@@ -100,18 +101,18 @@ class SVNTestRepository:
test_object.svn_repo_url = "file://%s" % test_object.svn_repo_path # Not sure this will work on windows
# git svn complains if we don't pass --pre-1.5-compatible, not sure why:
# Expected FS format '2'; found format '3' at /usr/local/libexec/git-core//git-svn line 1477
- run(['svnadmin', 'create', '--pre-1.5-compatible', test_object.svn_repo_path])
+ run_command(['svnadmin', 'create', '--pre-1.5-compatible', test_object.svn_repo_path])
# Create a test svn checkout
test_object.svn_checkout_path = tempfile.mkdtemp(suffix="svn_test_checkout")
- run(['svn', 'checkout', '--quiet', test_object.svn_repo_url, test_object.svn_checkout_path])
+ run_command(['svn', 'checkout', '--quiet', test_object.svn_repo_url, test_object.svn_checkout_path])
cls._setup_test_commits(test_object)
@classmethod
def tear_down(cls, test_object):
- run(['rm', '-rf', test_object.svn_repo_path])
- run(['rm', '-rf', test_object.svn_checkout_path])
+ run_command(['rm', '-rf', test_object.svn_repo_path])
+ run_command(['rm', '-rf', test_object.svn_checkout_path])
# For testing the SCM baseclass directly.
class SCMClassTests(unittest.TestCase):
@@ -122,21 +123,21 @@ class SCMClassTests(unittest.TestCase):
self.dev_null.close()
def test_run_command_with_pipe(self):
- input_process = subprocess.Popen(['/bin/echo', 'foo\nbar'], stdout=subprocess.PIPE, stderr=self.dev_null)
- self.assertEqual(SCM.run_command(['/usr/bin/grep', 'bar'], input=input_process.stdout), "bar")
+ input_process = subprocess.Popen(['echo', 'foo\nbar'], stdout=subprocess.PIPE, stderr=self.dev_null)
+ self.assertEqual(run_command(['grep', 'bar'], input=input_process.stdout), "bar\n")
# Test the non-pipe case too:
- self.assertEqual(SCM.run_command(['/usr/bin/grep', 'bar'], input="foo\nbar"), "bar")
+ self.assertEqual(run_command(['grep', 'bar'], input="foo\nbar"), "bar\n")
command_returns_non_zero = ['/bin/sh', '--invalid-option']
# Test when the input pipe process fails.
input_process = subprocess.Popen(command_returns_non_zero, stdout=subprocess.PIPE, stderr=self.dev_null)
self.assertTrue(input_process.poll() != 0)
- self.assertRaises(ScriptError, SCM.run_command, ['/usr/bin/grep', 'bar'], input=input_process.stdout)
+ self.assertRaises(ScriptError, run_command, ['grep', 'bar'], input=input_process.stdout)
# Test when the run_command process fails.
- input_process = subprocess.Popen(['/bin/echo', 'foo\nbar'], stdout=subprocess.PIPE, stderr=self.dev_null) # grep shows usage and calls exit(2) when called w/o arguments.
- self.assertRaises(ScriptError, SCM.run_command, command_returns_non_zero, input=input_process.stdout)
+ input_process = subprocess.Popen(['echo', 'foo\nbar'], stdout=subprocess.PIPE, stderr=self.dev_null) # grep shows usage and calls exit(2) when called w/o arguments.
+ self.assertRaises(ScriptError, run_command, command_returns_non_zero, input=input_process.stdout)
def test_error_handlers(self):
git_failure_message="Merge conflict during commit: Your file or directory 'WebCore/ChangeLog' is probably out-of-date: resource out of date; try updating at /usr/local/libexec/git-core//git-svn line 469"
@@ -145,12 +146,13 @@ svn: File or directory 'ChangeLog' is out of date; try updating
svn: resource out of date; try updating
"""
command_does_not_exist = ['does_not_exist', 'invalid_option']
- self.assertRaises(OSError, SCM.run_command, command_does_not_exist)
- self.assertRaises(OSError, SCM.run_command, command_does_not_exist, error_handler=ignore_error)
+ self.assertRaises(OSError, run_command, command_does_not_exist)
+ self.assertRaises(OSError, run_command, command_does_not_exist, error_handler=Executive.ignore_error)
command_returns_non_zero = ['/bin/sh', '--invalid-option']
- self.assertRaises(ScriptError, SCM.run_command, command_returns_non_zero)
- self.assertTrue(SCM.run_command(command_returns_non_zero, error_handler=ignore_error))
+ self.assertRaises(ScriptError, run_command, command_returns_non_zero)
+ # Check if returns error text:
+ self.assertTrue(run_command(command_returns_non_zero, error_handler=Executive.ignore_error))
self.assertRaises(CheckoutNeedsUpdate, commit_error_handler, ScriptError(output=git_failure_message))
self.assertRaises(CheckoutNeedsUpdate, commit_error_handler, ScriptError(output=svn_failure_message))
@@ -201,9 +203,185 @@ class SCMTest(unittest.TestCase):
self.assertTrue(re.search('test2', r3_patch))
self.assertTrue(re.search('test2', self.scm.diff_for_revision(2)))
+ def _shared_test_svn_apply_git_patch(self):
+ self._setup_webkittools_scripts_symlink(self.scm)
+ git_binary_addition = """diff --git a/fizzbuzz7.gif b/fizzbuzz7.gif
+new file mode 100644
+index 0000000000000000000000000000000000000000..64a9532e7794fcd791f6f12157406d90
+60151690
+GIT binary patch
+literal 512
+zcmZ?wbhEHbRAx|MU|?iW{Kxc~?KofD;ckY;H+&5HnHl!!GQMD7h+sU{_)e9f^V3c?
+zhJP##HdZC#4K}7F68@!1jfWQg2daCm-gs#3|JREDT>c+pG4L<_2;w##WMO#ysPPap
+zLqpAf1OE938xAsSp4!5f-o><?VKe(#0jEcwfHGF4%M1^kRs14oVBp2ZEL{E1N<-zJ
+zsfLmOtKta;2_;2c#^S1-8cf<nb!QnGl>c!Xe6RXvrEtAWBvSDTgTO1j3vA31Puw!A
+zs(87q)j_mVDTqBo-P+03-P5mHCEnJ+x}YdCuS7#bCCyePUe(ynK+|4b-3qK)T?Z&)
+zYG+`tl4h?GZv_$t82}X4*DTE|$;{DEiPyF@)U-1+FaX++T9H{&%cag`W1|zVP@`%b
+zqiSkp6{BTpWTkCr!=<C6Q=?#~R8^JfrliAF6Q^gV9Iup8RqCXqqhqC`qsyhk<-nlB
+z00f{QZvfK&|Nm#oZ0TQl`Yr$BIa6A@16O26ud7H<QM=xl`toLKnz-3h@9c9q&wm|X
+z{89I|WPyD!*M?gv?q`;L=2YFeXrJQNti4?}s!zFo=5CzeBxC69xA<zrjP<wUcCRh4
+ptUl-ZG<%a~#LwkIWv&q!KSCH7tQ8cJDiw+|GV?MN)RjY50RTb-xvT&H
+
+literal 0
+HcmV?d00001
+
+"""
+ self.scm.apply_patch(self._create_patch(git_binary_addition))
+ added = read_from_path('fizzbuzz7.gif')
+ self.assertEqual(512, len(added))
+ self.assertTrue(added.startswith('GIF89a'))
+ self.assertTrue('fizzbuzz7.gif' in self.scm.changed_files())
+
+ # The file already exists.
+ self.assertRaises(ScriptError, self.scm.apply_patch, self._create_patch(git_binary_addition))
+
+ git_binary_modification = """diff --git a/fizzbuzz7.gif b/fizzbuzz7.gif
+index 64a9532e7794fcd791f6f12157406d9060151690..323fae03f4606ea9991df8befbb2fca7
+GIT binary patch
+literal 7
+OcmYex&reD$;sO8*F9L)B
+
+literal 512
+zcmZ?wbhEHbRAx|MU|?iW{Kxc~?KofD;ckY;H+&5HnHl!!GQMD7h+sU{_)e9f^V3c?
+zhJP##HdZC#4K}7F68@!1jfWQg2daCm-gs#3|JREDT>c+pG4L<_2;w##WMO#ysPPap
+zLqpAf1OE938xAsSp4!5f-o><?VKe(#0jEcwfHGF4%M1^kRs14oVBp2ZEL{E1N<-zJ
+zsfLmOtKta;2_;2c#^S1-8cf<nb!QnGl>c!Xe6RXvrEtAWBvSDTgTO1j3vA31Puw!A
+zs(87q)j_mVDTqBo-P+03-P5mHCEnJ+x}YdCuS7#bCCyePUe(ynK+|4b-3qK)T?Z&)
+zYG+`tl4h?GZv_$t82}X4*DTE|$;{DEiPyF@)U-1+FaX++T9H{&%cag`W1|zVP@`%b
+zqiSkp6{BTpWTkCr!=<C6Q=?#~R8^JfrliAF6Q^gV9Iup8RqCXqqhqC`qsyhk<-nlB
+z00f{QZvfK&|Nm#oZ0TQl`Yr$BIa6A@16O26ud7H<QM=xl`toLKnz-3h@9c9q&wm|X
+z{89I|WPyD!*M?gv?q`;L=2YFeXrJQNti4?}s!zFo=5CzeBxC69xA<zrjP<wUcCRh4
+ptUl-ZG<%a~#LwkIWv&q!KSCH7tQ8cJDiw+|GV?MN)RjY50RTb-xvT&H
+
+"""
+ self.scm.apply_patch(self._create_patch(git_binary_modification))
+ modified = read_from_path('fizzbuzz7.gif')
+ self.assertEqual('foobar\n', modified)
+ self.assertTrue('fizzbuzz7.gif' in self.scm.changed_files())
+
+ # Applying the same modification should fail.
+ self.assertRaises(ScriptError, self.scm.apply_patch, self._create_patch(git_binary_modification))
+
+ git_binary_deletion = """diff --git a/fizzbuzz7.gif b/fizzbuzz7.gif
+deleted file mode 100644
+index 323fae0..0000000
+GIT binary patch
+literal 0
+HcmV?d00001
+
+literal 7
+OcmYex&reD$;sO8*F9L)B
+
+"""
+ self.scm.apply_patch(self._create_patch(git_binary_deletion))
+ self.assertFalse(os.path.exists('fizzbuzz7.gif'))
+ self.assertFalse('fizzbuzz7.gif' in self.scm.changed_files())
+
+ # Cannot delete again.
+ self.assertRaises(ScriptError, self.scm.apply_patch, self._create_patch(git_binary_deletion))
+
class SVNTest(SCMTest):
+ @staticmethod
+ def _set_date_and_reviewer(changelog_entry):
+ # Joe Cool matches the reviewer set in SCMTest._create_patch
+ changelog_entry = changelog_entry.replace('REVIEWER_HERE', 'Joe Cool')
+ # svn-apply will update ChangeLog entries with today's date.
+ return changelog_entry.replace('DATE_HERE', date.today().isoformat())
+
+ def test_svn_apply(self):
+ first_entry = """2009-10-26 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Foo Bar.
+
+ Most awesome change ever.
+
+ * scm_unittest.py:
+"""
+ intermediate_entry = """2009-10-27 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Baz Bar.
+
+ A more awesomer change yet!
+
+ * scm_unittest.py:
+"""
+ one_line_overlap_patch = """Index: ChangeLog
+===================================================================
+--- ChangeLog (revision 5)
++++ ChangeLog (working copy)
+@@ -1,5 +1,13 @@
+ 2009-10-26 Eric Seidel <eric@webkit.org>
+
++ Reviewed by NOBODY (OOPS!).
++
++ Second most awsome change ever.
++
++ * scm_unittest.py:
++
++2009-10-26 Eric Seidel <eric@webkit.org>
++
+ Reviewed by Foo Bar.
+
+ Most awesome change ever.
+"""
+ one_line_overlap_entry = """DATE_HERE Eric Seidel <eric@webkit.org>
+
+ Reviewed by REVIEWER_HERE.
+
+ Second most awsome change ever.
+
+ * scm_unittest.py:
+"""
+ two_line_overlap_patch = """Index: ChangeLog
+===================================================================
+--- ChangeLog (revision 5)
++++ ChangeLog (working copy)
+@@ -2,6 +2,14 @@
+
+ Reviewed by Foo Bar.
+
++ Second most awsome change ever.
++
++ * scm_unittest.py:
++
++2009-10-26 Eric Seidel <eric@webkit.org>
++
++ Reviewed by Foo Bar.
++
+ Most awesome change ever.
+
+ * scm_unittest.py:
+"""
+ two_line_overlap_entry = """DATE_HERE Eric Seidel <eric@webkit.org>
+
+ Reviewed by Foo Bar.
+
+ Second most awsome change ever.
+
+ * scm_unittest.py:
+"""
+ write_into_file_at_path('ChangeLog', first_entry)
+ run_command(['svn', 'add', 'ChangeLog'])
+ run_command(['svn', 'commit', '--quiet', '--message', 'ChangeLog commit'])
+
+ # Patch files were created against just 'first_entry'.
+ # Add a second commit to make svn-apply have to apply the patches with fuzz.
+ changelog_contents = "%s\n%s" % (intermediate_entry, first_entry)
+ write_into_file_at_path('ChangeLog', changelog_contents)
+ run_command(['svn', 'commit', '--quiet', '--message', 'Intermediate commit'])
+
+ self._setup_webkittools_scripts_symlink(self.scm)
+ self.scm.apply_patch(self._create_patch(one_line_overlap_patch))
+ expected_changelog_contents = "%s\n%s" % (self._set_date_and_reviewer(one_line_overlap_entry), changelog_contents)
+ self.assertEquals(read_from_path('ChangeLog'), expected_changelog_contents)
+
+ self.scm.revert_files(['ChangeLog'])
+ self.scm.apply_patch(self._create_patch(two_line_overlap_patch))
+ expected_changelog_contents = "%s\n%s" % (self._set_date_and_reviewer(two_line_overlap_entry), changelog_contents)
+ self.assertEquals(read_from_path('ChangeLog'), expected_changelog_contents)
+
def setUp(self):
SVNTestRepository.setup(self)
os.chdir(self.svn_checkout_path)
@@ -217,13 +395,13 @@ class SVNTest(SCMTest):
os.mkdir(test_dir_path)
test_file_path = os.path.join(test_dir_path, 'test_file2')
write_into_file_at_path(test_file_path, 'test content')
- run(['svn', 'add', 'test_dir'])
+ run_command(['svn', 'add', 'test_dir'])
# create_patch depends on 'svn-create-patch', so make a dummy version.
scripts_path = os.path.join(self.svn_checkout_path, 'WebKitTools', 'Scripts')
os.makedirs(scripts_path)
create_patch_path = os.path.join(scripts_path, 'svn-create-patch')
- write_into_file_at_path(create_patch_path, '#!/bin/sh\necho $PWD')
+ write_into_file_at_path(create_patch_path, '#!/bin/sh\necho $PWD') # We could pass -n to prevent the \n, but not all echo accept -n.
os.chmod(create_patch_path, stat.S_IXUSR | stat.S_IRUSR)
# Change into our test directory and run the create_patch command.
@@ -232,7 +410,7 @@ class SVNTest(SCMTest):
self.assertEqual(scm.checkout_root, self.svn_checkout_path) # Sanity check that detection worked right.
patch_contents = scm.create_patch()
# Our fake 'svn-create-patch' returns $PWD instead of a patch, check that it was executed from the root of the repo.
- self.assertEqual(os.path.realpath(scm.checkout_root), patch_contents)
+ self.assertEqual("%s\n" % os.path.realpath(scm.checkout_root), patch_contents) # Add a \n because echo adds a \n.
def test_detection(self):
scm = detect_scm_system(self.svn_checkout_path)
@@ -262,13 +440,13 @@ Q1dTBx0AAAB42itg4GlgYJjGwMDDyODMxMDw34GBgQEAJPQDJA==
def test_apply_svn_patch(self):
scm = detect_scm_system(self.svn_checkout_path)
- patch = self._create_patch(run(['svn', 'diff', '-r4:3']))
+ patch = self._create_patch(run_command(['svn', 'diff', '-r4:3']))
self._setup_webkittools_scripts_symlink(scm)
scm.apply_patch(patch)
def test_apply_svn_patch_force(self):
scm = detect_scm_system(self.svn_checkout_path)
- patch = self._create_patch(run(['svn', 'diff', '-r2:4']))
+ patch = self._create_patch(run_command(['svn', 'diff', '-r2:4']))
self._setup_webkittools_scripts_symlink(scm)
self.assertRaises(ScriptError, scm.apply_patch, patch, force=True)
@@ -286,6 +464,8 @@ Q1dTBx0AAAB42itg4GlgYJjGwMDDyODMxMDw34GBgQEAJPQDJA==
def test_diff_for_revision(self):
self._shared_test_diff_for_revision()
+ def test_svn_apply_git_patch(self):
+ self._shared_test_svn_apply_git_patch()
class GitTest(SCMTest):
@@ -295,7 +475,7 @@ class GitTest(SCMTest):
run_silent(['git', 'svn', '--quiet', 'clone', self.svn_repo_url, self.git_checkout_path])
def _tear_down_git_clone_of_svn_repository(self):
- run(['rm', '-rf', self.git_checkout_path])
+ run_command(['rm', '-rf', self.git_checkout_path])
def setUp(self):
SVNTestRepository.setup(self)
@@ -315,11 +495,11 @@ class GitTest(SCMTest):
def test_rebase_in_progress(self):
svn_test_file = os.path.join(self.svn_checkout_path, 'test_file')
write_into_file_at_path(svn_test_file, "svn_checkout")
- run(['svn', 'commit', '--message', 'commit to conflict with git commit'], cwd=self.svn_checkout_path)
+ run_command(['svn', 'commit', '--message', 'commit to conflict with git commit'], cwd=self.svn_checkout_path)
git_test_file = os.path.join(self.git_checkout_path, 'test_file')
write_into_file_at_path(git_test_file, "git_checkout")
- run(['git', 'commit', '-a', '-m', 'commit to be thrown away by rebase abort'])
+ run_command(['git', 'commit', '-a', '-m', 'commit to be thrown away by rebase abort'])
# --quiet doesn't make git svn silent, so use run_silent to redirect output
self.assertRaises(ScriptError, run_silent, ['git', 'svn', '--quiet', 'rebase']) # Will fail due to a conflict leaving us mid-rebase.
@@ -351,19 +531,19 @@ class GitTest(SCMTest):
actual_commits = scm.commit_ids_from_commitish_arguments([commit_range])
expected_commits = []
- expected_commits += reversed(run(['git', 'rev-list', commit_range]).splitlines())
+ expected_commits += reversed(run_command(['git', 'rev-list', commit_range]).splitlines())
self.assertEqual(actual_commits, expected_commits)
def test_apply_git_patch(self):
scm = detect_scm_system(self.git_checkout_path)
- patch = self._create_patch(run(['git', 'diff', 'HEAD..HEAD^']))
+ patch = self._create_patch(run_command(['git', 'diff', 'HEAD..HEAD^']))
self._setup_webkittools_scripts_symlink(scm)
scm.apply_patch(patch)
def test_apply_git_patch_force(self):
scm = detect_scm_system(self.git_checkout_path)
- patch = self._create_patch(run(['git', 'diff', 'HEAD~2..HEAD']))
+ patch = self._create_patch(run_command(['git', 'diff', 'HEAD~2..HEAD']))
self._setup_webkittools_scripts_symlink(scm)
self.assertRaises(ScriptError, scm.apply_patch, patch, force=True)
@@ -376,5 +556,39 @@ class GitTest(SCMTest):
def test_diff_for_revision(self):
self._shared_test_diff_for_revision()
+ def test_svn_apply_git_patch(self):
+ self._shared_test_svn_apply_git_patch()
+
+ def test_create_binary_patch(self):
+ # Create a git binary patch and check the contents.
+ scm = detect_scm_system(self.git_checkout_path)
+ test_file_name = 'binary_file'
+ test_file_path = os.path.join(self.git_checkout_path, test_file_name)
+ file_contents = ''.join(map(chr, range(256)))
+ write_into_file_at_path(test_file_path, file_contents)
+ run_command(['git', 'add', test_file_name])
+ patch = scm.create_patch()
+ self.assertTrue(re.search(r'\nliteral 0\n', patch))
+ self.assertTrue(re.search(r'\nliteral 256\n', patch))
+
+ # Check if we can apply the created patch.
+ run_command(['git', 'rm', '-f', test_file_name])
+ self._setup_webkittools_scripts_symlink(scm)
+ self.scm.apply_patch(self._create_patch(patch))
+ self.assertEqual(file_contents, read_from_path(test_file_path))
+
+ # Check if we can create a patch from a local commit.
+ write_into_file_at_path(test_file_path, file_contents)
+ run_command(['git', 'add', test_file_name])
+ run_command(['git', 'commit', '-m', 'binary diff'])
+ patch_from_local_commit = scm.create_patch_from_local_commit('HEAD')
+ self.assertTrue(re.search(r'\nliteral 0\n', patch_from_local_commit))
+ self.assertTrue(re.search(r'\nliteral 256\n', patch_from_local_commit))
+ patch_since_local_commit = scm.create_patch_since_local_commit('HEAD^1')
+ self.assertTrue(re.search(r'\nliteral 0\n', patch_since_local_commit))
+ self.assertTrue(re.search(r'\nliteral 256\n', patch_since_local_commit))
+ self.assertEqual(patch_from_local_commit, patch_since_local_commit)
+
+
if __name__ == '__main__':
unittest.main()
diff --git a/WebKitTools/Scripts/modules/statusbot.py b/WebKitTools/Scripts/modules/statusbot.py
index 9c9ba04..350aebf 100644
--- a/WebKitTools/Scripts/modules/statusbot.py
+++ b/WebKitTools/Scripts/modules/statusbot.py
@@ -46,21 +46,44 @@ http://wwwsearch.sourceforge.net/mechanize/
"""
exit(1)
+import urllib2
+
+
class StatusBot:
default_host = "webkit-commit-queue.appspot.com"
def __init__(self, host=default_host):
+ self.set_host(host)
+ self.browser = Browser()
+
+ def set_host(self, host):
self.statusbot_host = host
self.statusbot_server_url = "http://%s" % self.statusbot_host
- self.update_status_url = "%s/update_status" % self.statusbot_server_url
- self.browser = Browser()
- def update_status(self, status, bug_id=None, patch_id=None):
- self.browser.open(self.update_status_url)
+ def update_status(self, queue_name, status, patch=None, results_file=None):
+ # During unit testing, statusbot_host is None
+ if not self.statusbot_host:
+ return
+
+ update_status_url = "%s/update-status" % self.statusbot_server_url
+ self.browser.open(update_status_url)
self.browser.select_form(name="update_status")
- if bug_id:
- self.browser['bug_id'] = str(bug_id)
- if patch_id:
- self.browser['patch_id'] = str(patch_id)
+ self.browser['queue_name'] = queue_name
+ if patch:
+ if patch.get('bug_id'):
+ self.browser['bug_id'] = str(patch['bug_id'])
+ if patch.get('id'):
+ self.browser['patch_id'] = str(patch['id'])
self.browser['status'] = status
+ if results_file:
+ self.browser.add_file(results_file, "text/plain", "results.txt", 'results_file')
self.browser.submit()
+
+ def patch_status(self, queue_name, patch_id):
+ update_status_url = "%s/patch-status/%s/%s" % (self.statusbot_server_url, queue_name, patch_id)
+ try:
+ return urllib2.urlopen(update_status_url).read()
+ except urllib2.HTTPError, e:
+ if e.code == 404:
+ return None
+ raise e
diff --git a/WebKitTools/Scripts/modules/stepsequence.py b/WebKitTools/Scripts/modules/stepsequence.py
new file mode 100644
index 0000000..6f085c9
--- /dev/null
+++ b/WebKitTools/Scripts/modules/stepsequence.py
@@ -0,0 +1,68 @@
+# Copyright (C) 2009 Google 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:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * 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.
+# * Neither the name of Google Inc. 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 THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+# OWNER 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.
+
+from modules.buildsteps import CommandOptions
+from modules.executive import ScriptError
+from modules.logging import log
+from modules.scm import CheckoutNeedsUpdate
+from modules.workqueue import WorkQueue
+
+
+class StepSequence(object):
+ def __init__(self, steps):
+ self._steps = steps
+
+ def options(self):
+ collected_options = [
+ CommandOptions.parent_command,
+ CommandOptions.quiet,
+ ]
+ for step in self._steps:
+ collected_options = collected_options + step.options()
+ # Remove duplicates.
+ collected_options = sorted(set(collected_options))
+ return collected_options
+
+ def _run(self, tool, options, patch):
+ for step in self._steps:
+ step(tool, options, patch).run()
+
+ def run_and_handle_errors(self, tool, options, patch=None):
+ try:
+ self._run(tool, options, patch)
+ except CheckoutNeedsUpdate, e:
+ log("Commit failed because the checkout is out of date. Please update and try again.")
+ log("You can pass --no-build to skip building/testing after update if you believe the new commits did not affect the results.")
+ WorkQueue.exit_after_handled_error(e)
+ except ScriptError, e:
+ if not options.quiet:
+ log(e.message_with_output())
+ if options.parent_command:
+ command = tool.command_by_name(options.parent_command)
+ command.handle_script_error(tool, patch, e)
+ WorkQueue.exit_after_handled_error(e)
diff --git a/WebKitTools/Scripts/modules/webkitport.py b/WebKitTools/Scripts/modules/webkitport.py
new file mode 100644
index 0000000..849ac4b
--- /dev/null
+++ b/WebKitTools/Scripts/modules/webkitport.py
@@ -0,0 +1,118 @@
+# Copyright (C) 2009, Google 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:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * 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.
+# * Neither the name of Google Inc. 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 THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+# OWNER 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.
+#
+# WebKit's Python module for understanding the various ports
+
+import os
+
+from optparse import make_option
+
+class WebKitPort():
+ # We might need to pass scm into this function for scm.checkout_root
+ @classmethod
+ def script_path(cls, script_name):
+ return os.path.join("WebKitTools", "Scripts", script_name)
+
+ @staticmethod
+ def port(port_name):
+ if port_name == "mac":
+ return MacPort
+ if port_name == "qt":
+ return QtPort
+ if port_name == "chromium":
+ return ChromiumPort
+ # FIXME: We should default to WinPort on Windows.
+ return MacPort
+
+ @classmethod
+ def name(cls):
+ raise NotImplementedError, "subclasses must implement"
+
+ @classmethod
+ def flag(cls):
+ raise NotImplementedError, "subclasses must implement"
+
+ @classmethod
+ def update_webkit_command(cls):
+ return [cls.script_path("update-webkit")]
+
+ @classmethod
+ def build_webkit_command(cls):
+ return [cls.script_path("build-webkit")]
+
+ @classmethod
+ def run_webkit_tests_command(cls):
+ return [cls.script_path("run-webkit-tests")]
+
+
+class MacPort(WebKitPort):
+ @classmethod
+ def name(cls):
+ return "Mac"
+
+ @classmethod
+ def flag(cls):
+ return "--port=mac"
+
+
+class QtPort(WebKitPort):
+ @classmethod
+ def name(cls):
+ return "Qt"
+
+ @classmethod
+ def flag(cls):
+ return "--port=qt"
+
+ @classmethod
+ def build_webkit_command(cls):
+ command = WebKitPort.build_webkit_command()
+ command.append("--qt")
+ return command
+
+
+class ChromiumPort(WebKitPort):
+ @classmethod
+ def name(cls):
+ return "Chromium"
+
+ @classmethod
+ def flag(cls):
+ return "--port=chromium"
+
+ @classmethod
+ def update_webkit_command(cls):
+ command = WebKitPort.update_webkit_command()
+ command.append("--chromium")
+ return command
+
+ @classmethod
+ def build_webkit_command(cls):
+ command = WebKitPort.build_webkit_command()
+ command.append("--chromium")
+ return command
diff --git a/WebKitTools/Scripts/modules/webkitport_unittest.py b/WebKitTools/Scripts/modules/webkitport_unittest.py
new file mode 100644
index 0000000..c713e83
--- /dev/null
+++ b/WebKitTools/Scripts/modules/webkitport_unittest.py
@@ -0,0 +1,56 @@
+#!/usr/bin/env python
+# Copyright (c) 2009, Google 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:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * 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.
+# * Neither the name of Google Inc. 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 THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+# OWNER 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.
+
+import unittest
+
+from modules.webkitport import WebKitPort, MacPort, QtPort, ChromiumPort
+
+class WebKitPortTest(unittest.TestCase):
+ def test_mac_port(self):
+ self.assertEquals(MacPort.name(), "Mac")
+ self.assertEquals(MacPort.flag(), "--port=mac")
+ self.assertEquals(MacPort.run_webkit_tests_command(), [WebKitPort.script_path("run-webkit-tests")])
+ self.assertEquals(MacPort.build_webkit_command(), [WebKitPort.script_path("build-webkit")])
+
+ def test_qt_port(self):
+ self.assertEquals(QtPort.name(), "Qt")
+ self.assertEquals(QtPort.flag(), "--port=qt")
+ self.assertEquals(QtPort.run_webkit_tests_command(), [WebKitPort.script_path("run-webkit-tests")])
+ self.assertEquals(QtPort.build_webkit_command(), [WebKitPort.script_path("build-webkit"), "--qt"])
+
+ def test_chromium_port(self):
+ self.assertEquals(ChromiumPort.name(), "Chromium")
+ self.assertEquals(ChromiumPort.flag(), "--port=chromium")
+ self.assertEquals(ChromiumPort.run_webkit_tests_command(), [WebKitPort.script_path("run-webkit-tests")])
+ self.assertEquals(ChromiumPort.build_webkit_command(), [WebKitPort.script_path("build-webkit"), "--chromium"])
+ self.assertEquals(ChromiumPort.update_webkit_command(), [WebKitPort.script_path("update-webkit"), "--chromium"])
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/WebKitTools/Scripts/modules/workqueue.py b/WebKitTools/Scripts/modules/workqueue.py
new file mode 100644
index 0000000..f8cbba8
--- /dev/null
+++ b/WebKitTools/Scripts/modules/workqueue.py
@@ -0,0 +1,159 @@
+#!/usr/bin/env python
+# Copyright (c) 2009, Google Inc. All rights reserved.
+# Copyright (c) 2009 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:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * 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.
+# * Neither the name of Google Inc. 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 THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+# OWNER 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.
+
+import os
+import time
+import traceback
+
+from datetime import datetime, timedelta
+
+from modules.executive import ScriptError
+from modules.logging import log, OutputTee
+from modules.statusbot import StatusBot
+
+class WorkQueueDelegate:
+ def queue_name(self):
+ raise NotImplementedError, "subclasses must implement"
+
+ def queue_log_path(self):
+ raise NotImplementedError, "subclasses must implement"
+
+ def work_logs_directory(self):
+ raise NotImplementedError, "subclasses must implement"
+
+ def status_host(self):
+ raise NotImplementedError, "subclasses must implement"
+
+ def begin_work_queue(self):
+ raise NotImplementedError, "subclasses must implement"
+
+ def should_continue_work_queue(self):
+ raise NotImplementedError, "subclasses must implement"
+
+ def next_work_item(self):
+ raise NotImplementedError, "subclasses must implement"
+
+ def should_proceed_with_work_item(self, work_item):
+ # returns (safe_to_proceed, waiting_message, patch)
+ raise NotImplementedError, "subclasses must implement"
+
+ def process_work_item(self, work_item):
+ raise NotImplementedError, "subclasses must implement"
+
+ def handle_unexpected_error(self, work_item, message):
+ raise NotImplementedError, "subclasses must implement"
+
+
+class WorkQueue:
+ def __init__(self, name, delegate):
+ self._name = name
+ self._delegate = delegate
+ self._output_tee = OutputTee()
+
+ log_date_format = "%Y-%m-%d %H:%M:%S"
+ sleep_duration_text = "5 mins"
+ seconds_to_sleep = 300
+ handled_error_code = 2
+
+ # Child processes exit with a special code to the parent queue process can detect the error was handled.
+ @classmethod
+ def exit_after_handled_error(cls, error):
+ log(error)
+ exit(cls.handled_error_code)
+
+ def run(self):
+ self._begin_logging()
+ self.status_bot = StatusBot(host=self._delegate.status_host())
+
+ self._delegate.begin_work_queue()
+ while (self._delegate.should_continue_work_queue()):
+ self._ensure_work_log_closed()
+ try:
+ work_item = self._delegate.next_work_item()
+ if not work_item:
+ self._update_status_and_sleep("Empty queue.")
+ continue
+ (safe_to_proceed, waiting_message, patch) = self._delegate.should_proceed_with_work_item(work_item)
+ if not safe_to_proceed:
+ self._update_status_and_sleep(waiting_message)
+ continue
+ self.status_bot.update_status(self._name, waiting_message, patch)
+ except KeyboardInterrupt, e:
+ log("\nUser terminated queue.")
+ return 1
+ except Exception, e:
+ traceback.print_exc()
+ # Don't try tell the status bot, in case telling it causes an exception.
+ self._sleep("Exception while preparing queue: %s." % e)
+ continue
+
+ # FIXME: Work logs should not depend on bug_id specificaly.
+ self._open_work_log(patch["bug_id"])
+ try:
+ self._delegate.process_work_item(work_item)
+ except ScriptError, e:
+ # Use a special exit code to indicate that the error was already
+ # handled in the child process and we should just keep looping.
+ if e.exit_code == self.handled_error_code:
+ continue
+ message = "Unexpected failure when landing patch! Please file a bug against bugzilla-tool.\n%s" % e.message_with_output()
+ self._delegate.handle_unexpected_error(work_item, message)
+ # Never reached.
+ self._ensure_work_log_closed()
+
+ def _begin_logging(self):
+ self._queue_log = self._output_tee.add_log(self._delegate.queue_log_path())
+ self._work_log = None
+
+ def _open_work_log(self, bug_id):
+ work_log_path = os.path.join(self._delegate.work_logs_directory(), "%s.log" % bug_id)
+ self._work_log = self._output_tee.add_log(work_log_path)
+
+ def _ensure_work_log_closed(self):
+ # If we still have a bug log open, close it.
+ if self._work_log:
+ self._output_tee.remove_log(self._work_log)
+ self._work_log = None
+
+ @classmethod
+ def _sleep_message(cls, message):
+ wake_time = datetime.now() + timedelta(seconds=cls.seconds_to_sleep)
+ return "%s Sleeping until %s (%s)." % (message, wake_time.strftime(cls.log_date_format), cls.sleep_duration_text)
+
+ @classmethod
+ def _sleep(cls, message):
+ log(cls._sleep_message(message))
+ time.sleep(cls.seconds_to_sleep)
+
+ def _update_status_and_sleep(self, message):
+ status_message = self._sleep_message(message)
+ self.status_bot.update_status(self._name, status_message)
+ log(status_message)
+ time.sleep(self.seconds_to_sleep)
diff --git a/WebKitTools/Scripts/modules/workqueue_unittest.py b/WebKitTools/Scripts/modules/workqueue_unittest.py
new file mode 100644
index 0000000..ed77b5f
--- /dev/null
+++ b/WebKitTools/Scripts/modules/workqueue_unittest.py
@@ -0,0 +1,176 @@
+#!/usr/bin/env python
+# Copyright (c) 2009, Google 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:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * 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.
+# * Neither the name of Google Inc. 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 THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+# OWNER 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.
+
+import os
+import shutil
+import tempfile
+import unittest
+
+from modules.executive import ScriptError
+from modules.workqueue import WorkQueue, WorkQueueDelegate
+
+class LoggingDelegate(WorkQueueDelegate):
+ def __init__(self, test):
+ self._test = test
+ self._callbacks = []
+ self._run_before = False
+
+ expected_callbacks = [
+ 'queue_log_path',
+ 'status_host',
+ 'begin_work_queue',
+ 'should_continue_work_queue',
+ 'next_work_item',
+ 'should_proceed_with_work_item',
+ 'work_logs_directory',
+ 'process_work_item',
+ 'should_continue_work_queue'
+ ]
+
+ def record(self, method_name):
+ self._callbacks.append(method_name)
+
+ def queue_log_path(self):
+ self.record("queue_log_path")
+ return os.path.join(self._test.temp_dir, "queue_log_path")
+
+ def work_logs_directory(self):
+ self.record("work_logs_directory")
+ return os.path.join(self._test.temp_dir, "work_log_path")
+
+ def status_host(self):
+ self.record("status_host")
+ return None
+
+ def begin_work_queue(self):
+ self.record("begin_work_queue")
+
+ def should_continue_work_queue(self):
+ self.record("should_continue_work_queue")
+ if not self._run_before:
+ self._run_before = True
+ return True
+ return False
+
+ def next_work_item(self):
+ self.record("next_work_item")
+ return "work_item"
+
+ def should_proceed_with_work_item(self, work_item):
+ self.record("should_proceed_with_work_item")
+ self._test.assertEquals(work_item, "work_item")
+ fake_patch = { 'bug_id' : 42 }
+ return (True, "waiting_message", fake_patch)
+
+ def process_work_item(self, work_item):
+ self.record("process_work_item")
+ self._test.assertEquals(work_item, "work_item")
+
+ def handle_unexpected_error(self, work_item, message):
+ self.record("handle_unexpected_error")
+ self._test.assertEquals(work_item, "work_item")
+
+
+class ThrowErrorDelegate(LoggingDelegate):
+ def __init__(self, test, error_code):
+ LoggingDelegate.__init__(self, test)
+ self.error_code = error_code
+
+ def process_work_item(self, work_item):
+ self.record("process_work_item")
+ raise ScriptError(exit_code=self.error_code)
+
+
+class NotSafeToProceedDelegate(LoggingDelegate):
+ def should_proceed_with_work_item(self, work_item):
+ self.record("should_proceed_with_work_item")
+ self._test.assertEquals(work_item, "work_item")
+ fake_patch = { 'bug_id' : 42 }
+ return (False, "waiting_message", fake_patch)
+
+
+class FastWorkQueue(WorkQueue):
+ def __init__(self, delegate):
+ WorkQueue.__init__(self, "fast-queue", delegate)
+
+ # No sleep for the wicked.
+ seconds_to_sleep = 0
+
+ def _update_status_and_sleep(self, message):
+ pass
+
+
+class WorkQueueTest(unittest.TestCase):
+ def test_trivial(self):
+ delegate = LoggingDelegate(self)
+ work_queue = WorkQueue("trivial-queue", delegate)
+ work_queue.run()
+ self.assertEquals(delegate._callbacks, LoggingDelegate.expected_callbacks)
+ self.assertTrue(os.path.exists(delegate.queue_log_path()))
+ self.assertTrue(os.path.exists(os.path.join(delegate.work_logs_directory(), "42.log")))
+
+ def test_unexpected_error(self):
+ delegate = ThrowErrorDelegate(self, 3)
+ work_queue = WorkQueue("error-queue", delegate)
+ work_queue.run()
+ expected_callbacks = LoggingDelegate.expected_callbacks[:]
+ work_item_index = expected_callbacks.index('process_work_item')
+ # The unexpected error should be handled right after process_work_item starts
+ # but before any other callback. Otherwise callbacks should be normal.
+ expected_callbacks.insert(work_item_index + 1, 'handle_unexpected_error')
+ self.assertEquals(delegate._callbacks, expected_callbacks)
+
+ def test_handled_error(self):
+ delegate = ThrowErrorDelegate(self, WorkQueue.handled_error_code)
+ work_queue = WorkQueue("handled-error-queue", delegate)
+ work_queue.run()
+ self.assertEquals(delegate._callbacks, LoggingDelegate.expected_callbacks)
+
+ def test_not_safe_to_proceed(self):
+ delegate = NotSafeToProceedDelegate(self)
+ work_queue = FastWorkQueue(delegate)
+ work_queue.run()
+ expected_callbacks = LoggingDelegate.expected_callbacks[:]
+ next_work_item_index = expected_callbacks.index('next_work_item')
+ # We slice out the common part of the expected callbacks.
+ # We add 2 here to include should_proceed_with_work_item, which is
+ # a pain to search for directly because it occurs twice.
+ expected_callbacks = expected_callbacks[:next_work_item_index + 2]
+ expected_callbacks.append('should_continue_work_queue')
+ self.assertEquals(delegate._callbacks, expected_callbacks)
+
+ def setUp(self):
+ self.temp_dir = tempfile.mkdtemp(suffix="work_queue_test_logs")
+
+ def tearDown(self):
+ shutil.rmtree(self.temp_dir)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/WebKitTools/Scripts/prepare-ChangeLog b/WebKitTools/Scripts/prepare-ChangeLog
index dd864df..4c59af9 100755
--- a/WebKitTools/Scripts/prepare-ChangeLog
+++ b/WebKitTools/Scripts/prepare-ChangeLog
@@ -65,8 +65,8 @@ use POSIX qw(strftime);
use VCSUtils;
sub changeLogDate($);
-sub changeLogEmailAddress($);
-sub changeLogName($);
+sub changeLogEmailAddressFromArgs($);
+sub changeLogNameFromArgs($);
sub firstDirectoryOrCwd();
sub diffFromToString();
sub diffCommand(@);
@@ -77,7 +77,6 @@ sub findOriginalFileFromSvn($);
sub determinePropertyChanges($$$);
sub pluralizeAndList($$@);
sub generateFileList(\@\@\%);
-sub gitConfig($);
sub isUnmodifiedStatus($);
sub isModifiedStatus($);
sub isAddedStatus($);
@@ -246,8 +245,8 @@ if (%changed_line_ranges) {
# Get some parameters for the ChangeLog we are about to write.
my $date = changeLogDate($changeLogTimeZone);
-$name = changeLogName($name);
-$emailAddress = changeLogEmailAddress($emailAddress);
+$name = changeLogNameFromArgs($name);
+$emailAddress = changeLogEmailAddressFromArgs($emailAddress);
print STDERR " Change author: $name <$emailAddress>.\n";
@@ -443,62 +442,22 @@ sub changeLogDate($)
return $date;
}
-sub changeLogNameError($)
-{
- my ($message) = @_;
- print STDERR "$message\nEither:\n";
- print STDERR " set CHANGE_LOG_NAME in your environment\n";
- print STDERR " OR pass --name= on the command line\n";
- print STDERR " OR set REAL_NAME in your environment";
- print STDERR " OR git users can set 'git config user.name'\n";
- exit(1);
-}
-
-sub changeLogName($)
+sub changeLogNameFromArgs($)
{
my ($nameFromArgs) = @_;
- # Silently allow --git-commit to win, we could warn if $emailAddressFromArgs is defined.
+ # Silently allow --git-commit to win, we could warn if $nameFromArgs is defined.
return `$GIT log --max-count=1 --pretty=\"format:%an\" \"$gitCommit\"` if $gitCommit;
- my $name = $nameFromArgs
- || $ENV{CHANGE_LOG_NAME}
- || $ENV{REAL_NAME}
- || gitConfig("user.name")
- || (split /\s*,\s*/, (getpwuid $<)[6])[0];
-
- changeLogNameError("Failed to determine ChangeLog name.") unless $name;
- # getpwuid seems to always succeed on windows, returning the username instead of the full name. This check will catch that case.
- changeLogNameError("'$name' does not contain a space! ChangeLogs should contain your full name.") unless ($name =~ /\w \w/);
-
- return $name;
-}
-
-sub changeLogEmailAddressError($)
-{
- my ($message) = @_;
- print STDERR "$message\nEither:\n";
- print STDERR " set CHANGE_LOG_EMAIL_ADDRESS in your environment\n";
- print STDERR " OR pass --email= on the command line\n";
- print STDERR " OR set EMAIL_ADDRESS in your environment\n";
- print STDERR " OR git users can set 'git config user.email'\n";
- exit(1);
+ return $nameFromArgs || changeLogName();
}
-sub changeLogEmailAddress($)
+sub changeLogEmailAddressFromArgs($)
{
my ($emailAddressFromArgs) = @_;
# Silently allow --git-commit to win, we could warn if $emailAddressFromArgs is defined.
return `$GIT log --max-count=1 --pretty=\"format:%ae\" \"$gitCommit\"` if $gitCommit;
- my $emailAddress = $emailAddressFromArgs
- || $ENV{CHANGE_LOG_EMAIL_ADDRESS}
- || $ENV{EMAIL_ADDRESS}
- || gitConfig("user.email");
-
- changeLogEmailAddressError("Failed to determine email address for ChangeLog.") unless $emailAddress;
- changeLogEmailAddressError("Email address '$emailAddress' does not contain '\@' and is likely invalid.") unless ($emailAddress =~ /\@/);
-
- return $emailAddress;
+ return $emailAddressFromArgs || changeLogEmailAddress();
}
sub get_function_line_ranges($$)
@@ -1477,20 +1436,6 @@ sub generateFileList(\@\@\%)
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 isUnmodifiedStatus($)
{
my ($status) = @_;
diff --git a/WebKitTools/Scripts/run-webkit-tests b/WebKitTools/Scripts/run-webkit-tests
index 6056035..6dd8339 100755
--- a/WebKitTools/Scripts/run-webkit-tests
+++ b/WebKitTools/Scripts/run-webkit-tests
@@ -76,6 +76,7 @@ sub buildPlatformTestHierarchy(@);
sub closeCygpaths();
sub closeDumpTool();
sub closeHTTPD();
+sub closeWebSocketServer();
sub countAndPrintLeaks($$$);
sub countFinishedTest($$$$);
sub deleteExpectedAndActualResults($);
@@ -86,15 +87,18 @@ sub fileNameWithNumber($$);
sub htmlForResultsSection(\@$&);
sub isTextOnlyTest($);
sub launchWithCurrentEnv(@);
+sub resolveAndMakeTestResultsDirectory();
sub numericcmp($$);
sub openDiffTool();
sub openDumpTool();
sub openHTTPDIfNeeded();
sub parseLeaksandPrintUniqueLeaks();
+sub openWebSocketServerIfNeeded();
sub pathcmp($$);
sub printFailureMessageForTest($$);
sub processIgnoreTests($$);
sub readFromDumpToolWithTimer(**);
+sub readSkippedFiles($);
sub recordActualResultsAndDiff($$);
sub sampleDumpTool();
sub setFileHandleNonBlocking(*$);
@@ -117,6 +121,9 @@ my $guardMalloc = '';
my $httpdPort = 8000;
my $httpdSSLPort = 8443;
my $ignoreMetrics = 0;
+my $webSocketPort = 8880;
+# wss is disabled until all platforms support pyOpenSSL.
+# my $webSocketSecurePort = 9323;
my $ignoreTests = '';
my $iterations = 1;
my $launchSafari = 1;
@@ -185,6 +192,12 @@ if (isAppleMacWebKit()) {
}
} elsif (isGtk()) {
$platform = "gtk";
+ if (!$ENV{"WEBKIT_TESTFONTS"}) {
+ print "The WEBKIT_TESTFONTS environment variable is not defined.\n";
+ print "You must set it before running the tests.\n";
+ print "Use git to grab the actual fonts from http://gitorious.org/qtwebkit/testfonts\n";
+ exit 1;
+ }
} elsif (isWx()) {
$platform = "wx";
} elsif (isCygwin()) {
@@ -292,8 +305,6 @@ if (!$getOptionsResult || $showHelp) {
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.";
-
my $configuration = configuration();
$verbose = 1 if $testsPerDumpTool == 1;
@@ -347,12 +358,12 @@ if (!defined($root)) {
}
my $dumpToolName = "DumpRenderTree";
-$dumpToolName .= "_debug" if isCygwin() && $configuration ne "Release";
+$dumpToolName .= "_debug" if isCygwin() && configurationForVisualStudio() !~ /^Release|Debug_Internal$/;
my $dumpTool = "$productDir/$dumpToolName";
die "can't find executable $dumpToolName (looked in $productDir)\n" unless -x $dumpTool;
my $imageDiffTool = "$productDir/ImageDiff";
-$imageDiffTool .= "_debug" if isCygwin() && $configuration ne "Release";
+$imageDiffTool .= "_debug" if isCygwin() && configurationForVisualStudio() !~ /^Release|Debug_Internal$/;
die "can't find executable $imageDiffTool (looked in $productDir)\n" if $pixelTests && !-x $imageDiffTool;
checkFrameworks() unless isCygwin();
@@ -412,6 +423,7 @@ if (checkWebCoreSVGSupport(0)) {
if (!$testHTTP) {
$ignoredDirectories{'http'} = 1;
+ $ignoredDirectories{'websocket'} = 1;
}
if (!$testMedia) {
@@ -449,7 +461,17 @@ if (!checkWebCoreWCSSSupport(0)) {
}
processIgnoreTests($ignoreTests, "ignore-tests") if $ignoreTests;
-readSkippedFiles() unless $ignoreSkipped;
+if (!$ignoreSkipped) {
+ if (!$skippedOnly || @ARGV == 0) {
+ readSkippedFiles("");
+ } else {
+ # Since readSkippedFiles() appends to @ARGV, we must use a foreach
+ # loop so that we only iterate over the original argument list.
+ foreach my $argnum (0 .. $#ARGV) {
+ readSkippedFiles(shift @ARGV);
+ }
+ }
+}
my @tests = findTestsToRun();
@@ -485,6 +507,11 @@ my $atLineStart = 1;
my $lastDirectory = "";
my $isHttpdOpen = 0;
+my $isWebSocketServerOpen = 0;
+my $webSocketServerPID = 0;
+my $failedToStartWebSocketServer = 0;
+# wss is disabled until all platforms support pyOpenSSL.
+# my $webSocketSecureServerPID = 0;
sub catch_pipe { $dumpToolCrashed = 1; }
$SIG{"PIPE"} = "catch_pipe";
@@ -577,15 +604,7 @@ for my $test (@tests) {
}
}
- if ($test !~ /^http\//) {
- my $testPath = "$testDirectory/$test";
- if (isCygwin()) {
- $testPath = toWindowsPath($testPath);
- } else {
- $testPath = canonpath($testPath);
- }
- print OUT "$testPath$suffixExpectedHash\n";
- } else {
+ if ($test =~ /^http\//) {
openHTTPDIfNeeded();
if ($test !~ /^http\/tests\/local\// && $test !~ /^http\/tests\/ssl\// && $test !~ /^http\/tests\/wml\// && $test !~ /^http\/tests\/media\//) {
my $path = canonpath($test);
@@ -604,6 +623,41 @@ for my $test (@tests) {
}
print OUT "$testPath$suffixExpectedHash\n";
}
+ } elsif ($test =~ /^websocket\//) {
+ if ($test =~ /^websocket\/tests\/local\//) {
+ my $testPath = "$testDirectory/$test";
+ if (isCygwin()) {
+ $testPath = toWindowsPath($testPath);
+ } else {
+ $testPath = canonpath($testPath);
+ }
+ print OUT "$testPath\n";
+ } else {
+ if (openWebSocketServerIfNeeded()) {
+ my $path = canonpath($test);
+ if ($test =~ /^websocket\/tests\/ssl\//) {
+ # wss is disabled until all platforms support pyOpenSSL.
+ print STDERR "Error: wss is disabled until all platforms support pyOpenSSL.";
+ # print OUT "https://127.0.0.1:$webSocketSecurePort/$path\n";
+ } else {
+ print OUT "http://127.0.0.1:$webSocketPort/$path\n";
+ }
+ } else {
+ # We failed to launch the WebSocket server. Display a useful error message rather than attempting
+ # to run tests that expect the server to be available.
+ my $errorMessagePath = "$testDirectory/websocket/resources/server-failed-to-start.html";
+ $errorMessagePath = isCygwin() ? toWindowsPath($errorMessagePath) : canonpath($errorMessagePath);
+ print OUT "$errorMessagePath\n";
+ }
+ }
+ } else {
+ my $testPath = "$testDirectory/$test";
+ if (isCygwin()) {
+ $testPath = toWindowsPath($testPath);
+ } else {
+ $testPath = canonpath($testPath);
+ }
+ print OUT "$testPath$suffixExpectedHash\n";
}
# DumpRenderTree is expected to dump two "blocks" to stdout for each test.
@@ -892,6 +946,7 @@ printf "\n%0.2fs total testing time\n", (time - $overallStartTime) . "";
!$isDumpToolOpen || die "Failed to close $dumpToolName.\n";
closeHTTPD();
+closeWebSocketServer();
# Because multiple instances of this script are running concurrently we cannot
# safely delete this symlink.
@@ -966,7 +1021,10 @@ close HTML;
my @configurationArgs = argumentsForConfiguration();
-if (isQt() || isGtk()) {
+if (isGtk()) {
+ system "WebKitTools/Scripts/run-launcher", @configurationArgs, "file://".$testResults if $launchSafari;
+} elsif (isQt()) {
+ unshift @configurationArgs, qw(-graphicssystem raster -style windows);
system "WebKitTools/Scripts/run-launcher", @configurationArgs, "file://".$testResults if $launchSafari;
} elsif (isCygwin()) {
system "cygstart", $testResults if $launchSafari;
@@ -1166,6 +1224,13 @@ sub launchWithCurrentEnv(@)
return @args;
}
+sub resolveAndMakeTestResultsDirectory()
+{
+ my $absTestResultsDirectory = File::Spec->rel2abs(glob $testResultsDirectory);
+ mkpath $absTestResultsDirectory;
+ return $absTestResultsDirectory;
+}
+
sub openDiffTool()
{
return if $isDiffToolOpen;
@@ -1238,7 +1303,7 @@ sub openDumpTool()
}
if ($useValgrind) {
- unshift @args, "valgrind";
+ unshift @args, "valgrind", "--suppressions=$platformBaseDirectory/qt/SuppressedValgrindErrors";
}
$ENV{MallocStackLogging} = 1 if $shouldCheckLeaks;
@@ -1326,11 +1391,9 @@ sub openHTTPDIfNeeded()
my $jsTestResourcesDirectory = $testDirectory . "/fast/js/resources";
my $typesConfig = "$testDirectory/http/conf/mime.types";
my $listen = "127.0.0.1:$httpdPort";
- my $absTestResultsDirectory = File::Spec->rel2abs(glob $testResultsDirectory);
+ my $absTestResultsDirectory = resolveAndMakeTestResultsDirectory();
my $sslCertificate = "$testDirectory/http/conf/webkit-httpd.pem";
- mkpath $absTestResultsDirectory;
-
my @args = (
"-f", "$httpdConfig",
"-C", "DocumentRoot \"$documentRoot\"",
@@ -1373,6 +1436,77 @@ sub closeHTTPD()
$isHttpdOpen = 0;
}
+sub openWebSocketServerIfNeeded()
+{
+ return 1 if $isWebSocketServerOpen;
+ return 0 if $failedToStartWebSocketServer;
+
+ my $webSocketServerPath = "/usr/bin/python";
+ my $webSocketPythonPath = "WebKitTools/pywebsocket";
+ my $webSocketHandlerDir = "$testDirectory";
+ my $webSocketHandlerScanDir = "$testDirectory/websocket/tests";
+ my $sslCertificate = "$testDirectory/http/conf/webkit-httpd.pem";
+ my $absTestResultsDirectory = resolveAndMakeTestResultsDirectory();
+ my $logFile = "$absTestResultsDirectory/pywebsocket_log.txt";
+
+ my @args = (
+ "WebKitTools/pywebsocket/mod_pywebsocket/standalone.py",
+ "-p", "$webSocketPort",
+ "-d", "$webSocketHandlerDir",
+ "-s", "$webSocketHandlerScanDir",
+ "-l", "$logFile",
+ );
+ # wss is disabled until all platforms support pyOpenSSL.
+ # my @argsSecure = (
+ # "WebKitTools/pywebsocket/mod_pywebsocket/standalone.py",
+ # "-p", "$webSocketSecurePort",
+ # "-d", "$webSocketHandlerDir",
+ # "-t",
+ # "-k", "$sslCertificate",
+ # "-c", "$sslCertificate",
+ # );
+
+ $ENV{"PYTHONPATH"} = $webSocketPythonPath;
+ $webSocketServerPID = open3(\*WEBSOCKETSERVER_IN, \*WEBSOCKETSERVER_OUT, \*WEBSOCKETSERVER_ERR, $webSocketServerPath, @args);
+ # wss is disabled until all platforms support pyOpenSSL.
+ # $webSocketSecureServerPID = open3(\*WEBSOCKETSECURESERVER_IN, \*WEBSOCKETSECURESERVER_OUT, \*WEBSOCKETSECURESERVER_ERR, $webSocketServerPath, @argsSecure);
+ # my @listen = ("http://127.0.0.1:$webSocketPort", "https://127.0.0.1:$webSocketSecurePort");
+ my @listen = ("http://127.0.0.1:$webSocketPort");
+ for (my $i = 0; $i < @listen; $i++) {
+ my $retryCount = 10;
+ while (system("/usr/bin/curl -k -q --silent --stderr - --output /dev/null $listen[$i]") && $retryCount) {
+ sleep 1;
+ --$retryCount;
+ }
+ unless ($retryCount) {
+ print STDERR "Timed out waiting for WebSocketServer to start.\n";
+ $failedToStartWebSocketServer = 1;
+ return 0;
+ }
+ }
+
+ $isWebSocketServerOpen = 1;
+ return 1;
+}
+
+sub closeWebSocketServer()
+{
+ return if !$isWebSocketServerOpen;
+
+ close WEBSOCKETSERVER_IN;
+ close WEBSOCKETSERVER_OUT;
+ close WEBSOCKETSERVER_ERR;
+ kill 15, $webSocketServerPID;
+
+ # wss is disabled until all platforms support pyOpenSSL.
+ # close WEBSOCKETSECURESERVER_IN;
+ # close WEBSOCKETSECURESERVER_OUT;
+ # close WEBSOCKETSECURESERVER_ERR;
+ # kill 15, $webSocketSecureServerPID;
+
+ $isWebSocketServerOpen = 0;
+}
+
sub fileNameWithNumber($$)
{
my ($base, $number) = @_;
@@ -1980,8 +2114,10 @@ sub fileShouldBeIgnored
return 0;
}
-sub readSkippedFiles
+sub readSkippedFiles($)
{
+ my ($constraintPath) = @_;
+
foreach my $level (@platformTestHierarchy) {
if (open SKIPPED, "<", "$level/Skipped") {
if ($verbose) {
@@ -1996,8 +2132,19 @@ sub readSkippedFiles
$skipped =~ s/[ \n\r]+$//;
if ($skipped && $skipped !~ /^#/) {
if ($skippedOnly) {
- if (!&fileShouldBeIgnored($skipped)) {
- push(@ARGV, $skipped);
+ if (!fileShouldBeIgnored($skipped)) {
+ if (!$constraintPath) {
+ # Always add $skipped since no constraint path was specified on the command line.
+ push(@ARGV, $skipped);
+ } elsif ($skipped =~ /^($constraintPath)/) {
+ # Add $skipped only if it matches the current path constraint, e.g.,
+ # "--skipped=only dir1" with "dir1/file1.html" on the skipped list.
+ push(@ARGV, $skipped);
+ } elsif ($constraintPath =~ /^($skipped)/) {
+ # Add current path constraint if it is more specific than the skip list entry,
+ # e.g., "--skipped=only dir1/dir2/dir3" with "dir1" on the skipped list.
+ push(@ARGV, $constraintPath);
+ }
} elsif ($verbose) {
print " $skipped\n";
}
@@ -2068,6 +2215,9 @@ sub findTestsToRun
}
}
+ # Remove duplicate tests
+ @testsToRun = keys %{{ map { $_ => 1 } @testsToRun }};
+
@testsToRun = sort pathcmp @testsToRun;
# Reverse the tests
diff --git a/WebKitTools/Scripts/run-webkit-unittests b/WebKitTools/Scripts/run-webkit-unittests
index 8d0ef1d..3487299 100755
--- a/WebKitTools/Scripts/run-webkit-unittests
+++ b/WebKitTools/Scripts/run-webkit-unittests
@@ -32,11 +32,18 @@ import unittest
from modules.bugzilla_unittest import *
from modules.buildbot_unittest import *
from modules.changelogs_unittest import *
+from modules.commands.download_unittest import *
+from modules.commands.upload_unittest import *
+from modules.commands.queries_unittest import *
+from modules.commands.queues_unittest import *
from modules.committers_unittest import *
from modules.cpp_style_unittest import *
from modules.diff_parser_unittest import *
from modules.logging_unittest import *
+from modules.multicommandtool_unittest import *
from modules.scm_unittest import *
+from modules.webkitport_unittest import *
+from modules.workqueue_unittest import *
if __name__ == "__main__":
unittest.main()
diff --git a/WebKitTools/Scripts/run-webkit-websocketserver b/WebKitTools/Scripts/run-webkit-websocketserver
new file mode 100755
index 0000000..e05303a
--- /dev/null
+++ b/WebKitTools/Scripts/run-webkit-websocketserver
@@ -0,0 +1,96 @@
+#!/usr/bin/perl
+# Copyright (C) 2009 Google 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:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * 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.
+# * Neither the name of Google Inc. 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 THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+# OWNER 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.
+
+# Script to run Web Socket server.
+
+use strict;
+use warnings;
+
+use File::Spec;
+use FindBin;
+use IPC::Open2;
+
+use lib $FindBin::Bin;
+use webkitdirs;
+
+sub closeWebSocketServer();
+sub openWebSocketServer();
+
+my $webSocketPort = 8880;
+
+my $srcDir = sourceDir();
+my $layoutTestsName = "$srcDir/LayoutTests";
+my $testDirectory = File::Spec->rel2abs($layoutTestsName);
+my $webSocketServerPID = 0;
+
+
+print "Starting Web Socket server...\n";
+openWebSocketServer();
+print "Started.\n";
+print "Hit [ENTER] to stop it.";
+<STDIN>;
+print "Stopping Web Socket server...\n";
+closeWebSocketServer();
+print "Stopped.\n";
+exit 0;
+
+
+sub openWebSocketServer()
+{
+ my $webSocketServerPath = "/usr/bin/python";
+ my $webSocketPythonPath = "$srcDir/WebKitTools/pywebsocket";
+ my $webSocketHandlerDir = "$testDirectory";
+ my $webSocketHandlerScanDir = "$testDirectory/websocket/tests";
+
+ my @args = (
+ "$srcDir/WebKitTools/pywebsocket/mod_pywebsocket/standalone.py",
+ "-p", "$webSocketPort",
+ "-d", "$webSocketHandlerDir",
+ "-s", "$webSocketHandlerScanDir",
+ );
+
+ $ENV{"PYTHONPATH"} = $webSocketPythonPath;
+ $webSocketServerPID = open2(\*WEBSOCKETSERVER_IN, \*WEBSOCKETSERVER_OUT, $webSocketServerPath, @args);
+
+ my $listen = "http://127.0.0.1:$webSocketPort";
+ my $retryCount = 10;
+ while (system("/usr/bin/curl -k -q --silent --stderr - --output /dev/null $listen") && $retryCount) {
+ sleep 1;
+ --$retryCount;
+ }
+ die "Timed out waiting for WebSocketServer to start" unless $retryCount;
+}
+
+sub closeWebSocketServer()
+{
+ close WEBSOCKETSERVER_IN;
+ close WEBSOCKETSERVER_OUT;
+ kill 15, $webSocketServerPID;
+}
+
diff --git a/WebKitTools/Scripts/svn-apply b/WebKitTools/Scripts/svn-apply
index 7d14e3a..0373aa5 100755
--- a/WebKitTools/Scripts/svn-apply
+++ b/WebKitTools/Scripts/svn-apply
@@ -55,7 +55,7 @@
# 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
+# Handle git-diff patches with binary delta
use strict;
use warnings;
@@ -75,11 +75,11 @@ sub addDirectoriesIfNeeded($);
sub applyPatch($$;$);
sub checksum($);
sub handleBinaryChange($$);
+sub handleGitBinaryChange($$);
sub isDirectoryEmptyForRemoval($);
sub patch($);
sub removeDirectoriesIfNeeded();
sub setChangeLogDateAndReviewer($$);
-sub removeEOL($);
# These should be replaced by an scm class/module:
sub scmKnowsOfFile($);
@@ -277,6 +277,39 @@ sub handleBinaryChange($$)
}
}
+sub handleGitBinaryChange($$)
+{
+ my ($fullPath, $contents) = @_;
+
+ my ($binaryChunkType, $binaryChunk, $reverseBinaryChunkType, $reverseBinaryChunk) = decodeGitBinaryPatch($contents, $fullPath);
+ # FIXME: support "delta" type.
+ die "only literal type is supported now" if ($binaryChunkType ne "literal" || $reverseBinaryChunkType ne "literal");
+
+ my $isFileAddition = $contents =~ /\nnew file mode \d+\n/;
+ my $isFileDeletion = $contents =~ /\ndeleted file mode \d+\n/;
+
+ my $originalContents = "";
+ if (open FILE, $fullPath) {
+ die "$fullPath already exists" if $isFileAddition;
+
+ $originalContents = join("", <FILE>);
+ close FILE;
+ }
+ die "Original content of $fullPath mismatches" if $originalContents ne $reverseBinaryChunk;
+
+ if ($isFileDeletion) {
+ scmRemove($fullPath);
+ } else {
+ # Addition or Modification
+ open FILE, ">", $fullPath or die "Failed to open $fullPath.";
+ print FILE $binaryChunk;
+ close FILE;
+ if ($isFileAddition) {
+ scmAdd($fullPath);
+ }
+ }
+}
+
sub isDirectoryEmptyForRemoval($)
{
my ($dir) = @_;
@@ -311,12 +344,14 @@ sub patch($)
my $deletion = 0;
my $addition = 0;
my $isBinary = 0;
+ my $isGitBinary = 0;
$addition = 1 if ($patch =~ /\n--- .+\(revision 0\)\r?\n/ || $patch =~ /\n@@ -0,0 .* @@/) && !exists($copiedFiles{$fullPath});
$deletion = 1 if $patch =~ /\n@@ .* \+0,0 @@/;
$isBinary = 1 if $patch =~ /\nCannot display: file marked as a binary type\./;
+ $isGitBinary = 1 if $patch =~ /\nGIT binary patch\n/;
- if (!$addition && !$deletion && !$isBinary) {
+ if (!$addition && !$deletion && !$isBinary && !$isGitBinary) {
# Standard patch, patch tool can handle this.
if (basename($fullPath) eq "ChangeLog") {
my $changeLogDotOrigExisted = -f "${fullPath}.orig";
@@ -333,6 +368,9 @@ sub patch($)
if ($isBinary) {
# Binary change
handleBinaryChange($fullPath, $patch);
+ } elsif ($isGitBinary) {
+ # Git binary change
+ handleGitBinaryChange($fullPath, $patch);
} elsif ($deletion) {
# Deletion
applyPatch($patch, $fullPath, ["--force"]);
@@ -378,14 +416,6 @@ sub setChangeLogDateAndReviewer($$)
return $patch;
}
-sub removeEOL($)
-{
- my ($line) = @_;
-
- $line =~ s/[\r\n]+$//g;
- return $line;
-}
-
# This could be made into a more general "status" call, except svn and git
# have different ideas about "moving" files which might get confusing.
sub scmWillDeleteFile($)
diff --git a/WebKitTools/Scripts/svn-unapply b/WebKitTools/Scripts/svn-unapply
index 94bb1ce..c277a3e 100755
--- a/WebKitTools/Scripts/svn-unapply
+++ b/WebKitTools/Scripts/svn-unapply
@@ -73,7 +73,6 @@ use VCSUtils;
sub checksum($);
sub patch($);
sub revertDirectories();
-sub removeEOL($);
sub unapplyPatch($$;$);
sub unsetChangeLogDate($$);
@@ -259,14 +258,6 @@ sub revertDirectories()
}
}
-sub removeEOL($)
-{
- my ($line) = @_;
-
- $line =~ s/[\r\n]+$//g;
- return $line;
-}
-
sub unapplyPatch($$;$)
{
my ($patch, $fullPath, $options) = @_;
diff --git a/WebKitTools/Scripts/update-webkit b/WebKitTools/Scripts/update-webkit
index b503004..7602c41 100755
--- a/WebKitTools/Scripts/update-webkit
+++ b/WebKitTools/Scripts/update-webkit
@@ -39,6 +39,7 @@ use VCSUtils;
use webkitdirs;
sub runSvnUpdate();
+sub runGitUpdate();
# Handle options
my $quiet = '';
@@ -46,6 +47,11 @@ my $showHelp;
determineIsChromium();
+chdirWebKit();
+
+my $isGit = isGit();
+my $isSVN = isSVN();
+
my $getOptionsResult = GetOptions(
'h|help' => \$showHelp,
'q|quiet' => \$quiet,
@@ -67,20 +73,23 @@ push @svnOptions, '-q' if $quiet;
# Don't prompt when using svn-1.6 or newer.
push @svnOptions, qw(--accept postpone) if isSVNVersion16OrNewer();
-chdirWebKit();
print "Updating OpenSource\n" unless $quiet;
-runSvnUpdate();
+runSvnUpdate() if $isSVN;
+runGitUpdate() if $isGit;
if (-d "../Internal") {
chdir("../Internal");
print "Updating Internal\n" unless $quiet;
- runSvnUpdate();
+ runSvnUpdate() if $isSVN;
+ runGitUpdate() if $isGit;
} elsif (isChromium()) {
system("perl", "WebKitTools/Scripts/update-webkit-chromium") == 0 or die $!;
} elsif (isAppleWinWebKit()) {
system("perl", "WebKitTools/Scripts/update-webkit-auxiliary-libs") == 0 or die;
}
+setupAppleWinEnv() if isAppleWinWebKit();
+
exit 0;
sub runSvnUpdate()
@@ -104,3 +113,8 @@ sub runSvnUpdate()
or die "Could not open resolve-ChangeLogs script: $!.\n";
}
}
+
+sub runGitUpdate()
+{
+ system("git", "svn", "rebase") == 0 or die;
+}
diff --git a/WebKitTools/Scripts/update-webkit-chromium b/WebKitTools/Scripts/update-webkit-chromium
index a0cc19a..779b9a6 100644..100755
--- a/WebKitTools/Scripts/update-webkit-chromium
+++ b/WebKitTools/Scripts/update-webkit-chromium
@@ -48,4 +48,4 @@ if (! -e ".gclient") {
# Execute gclient sync.
print "Updating chromium port dependencies using gclient...\n";
-system("gclient", "sync") == 0 or die $!;
+system("gclient", "sync", "--force") == 0 or die $!;
diff --git a/WebKitTools/Scripts/validate-committer-lists b/WebKitTools/Scripts/validate-committer-lists
new file mode 100755
index 0000000..05f2b36
--- /dev/null
+++ b/WebKitTools/Scripts/validate-committer-lists
@@ -0,0 +1,252 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2009, Google 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:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * 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.
+# * Neither the name of Google Inc. 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 THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+# OWNER 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.
+#
+# Checks Python's known list of committers against lists.webkit.org and SVN history.
+
+
+import os
+import subprocess
+import re
+import urllib2
+from datetime import date, datetime, timedelta
+from modules.committers import CommitterList
+from modules.logging import log, error
+
+# WebKit includes a built copy of BeautifulSoup in Scripts/modules
+# so this import should always succeed.
+from modules.BeautifulSoup import BeautifulSoup
+
+def print_list_if_non_empty(title, list_to_print):
+ if not list_to_print:
+ return
+ print # Newline before the list
+ print title
+ for item in list_to_print:
+ print item
+
+class CommitterListFromMailingList:
+ committers_list_url = "http://lists.webkit.org/mailman/roster.cgi/webkit-committers"
+ reviewers_list_url = "http://lists.webkit.org/mailman/roster.cgi/webkit-reviewers"
+
+ def _fetch_emails_from_page(self, url):
+ page = urllib2.urlopen(url)
+ soup = BeautifulSoup(page)
+
+ emails = []
+ # Grab the cells in the first column (which happens to be the bug ids).
+ for email_item in soup('li'):
+ email_link = email_item.find("a")
+ email = email_link.string.replace(" at ", "@") # The email is obfuscated using " at " instead of "@".
+ emails.append(email)
+ return emails
+
+ @staticmethod
+ def _commiters_not_found_in_email_list(committers, emails):
+ missing_from_mailing_list = []
+ for committer in committers:
+ for email in committer.emails:
+ if email in emails:
+ break
+ else:
+ missing_from_mailing_list.append(committer)
+ return missing_from_mailing_list
+
+ @staticmethod
+ def _emails_not_found_in_committer_list(committers, emails):
+ email_to_committer_map = {}
+ for committer in committers:
+ for email in committer.emails:
+ email_to_committer_map[email] = committer
+
+ return filter(lambda email: not email_to_committer_map.get(email), emails)
+
+ def check_for_emails_missing_from_list(self, committer_list):
+ committer_emails = self._fetch_emails_from_page(self.committers_list_url)
+ list_name = "webkit-committers@lists.webkit.org"
+
+ missing_from_mailing_list = self._commiters_not_found_in_email_list(committer_list.committers(), committer_emails)
+ print_list_if_non_empty("Committers missing from %s:" % list_name, missing_from_mailing_list)
+
+ users_missing_from_committers = self._emails_not_found_in_committer_list(committer_list.committers(), committer_emails)
+ print_list_if_non_empty("Subcribers to %s missing from committer.py:" % list_name, users_missing_from_committers)
+
+
+ reviewer_emails = self._fetch_emails_from_page(self.reviewers_list_url)
+ list_name = "webkit-reviewers@lists.webkit.org"
+
+ missing_from_mailing_list = self._commiters_not_found_in_email_list(committer_list.reviewers(), reviewer_emails)
+ print_list_if_non_empty("Reviewers missing from %s:" % list_name, missing_from_mailing_list)
+
+ missing_from_reviewers = self._emails_not_found_in_committer_list(committer_list.reviewers(), reviewer_emails)
+ print_list_if_non_empty("Subcribers to %s missing from reviewers in committer.py:" % list_name, missing_from_reviewers)
+
+ missing_from_committers = self._emails_not_found_in_committer_list(committer_list.committers(), reviewer_emails)
+ print_list_if_non_empty("Subcribers to %s completely missing from committers.py" % list_name, missing_from_committers)
+
+
+class CommitterListFromGit:
+ login_to_email_address = {
+ 'aliceli1' : 'alice.liu@apple.com',
+ 'bdash' : 'mrowe@apple.com',
+ 'bdibello' : 'bdibello@apple.com', # Bruce DiBello, only 4 commits: r10023, r9548, r9538, r9535
+ 'cblu' : 'cblu@apple.com',
+ 'cpeterse' : 'cpetersen@apple.com',
+ 'eseidel' : 'eric@webkit.org',
+ 'gdennis' : 'gdennis@webkit.org',
+ 'goldsmit' : 'goldsmit@apple.com', # Debbie Goldsmith, only one commit r8839
+ 'gramps' : 'gramps@apple.com',
+ 'honeycutt' : 'jhoneycutt@apple.com',
+ 'jdevalk' : 'joost@webkit.org',
+ 'jens' : 'jens@apple.com',
+ 'justing' : 'justin.garcia@apple.com',
+ 'kali' : 'kali@apple.com', # Christy Warren, did BIDI work, 5 commits: r8815, r8802, r8801, r8791, r8773, r8603
+ 'kjk' : 'kkowalczyk@gmail.com',
+ 'kmccullo' : 'kmccullough@apple.com',
+ 'kocienda' : 'kocienda@apple.com',
+ 'lamadio' : 'lamadio@apple.com', # Lou Amadio, only 2 commits: r17949 and r17783
+ 'lars' : 'lars@kde.org',
+ 'lweintraub' : 'lweintraub@apple.com',
+ 'lypanov' : 'lypanov@kde.org',
+ 'mhay' : 'mhay@apple.com', # Mike Hay, 3 commits: r3813, r2552, r2548
+ 'ouch' : 'ouch@apple.com', # John Louch
+ 'pyeh' : 'patti@apple.com', # Patti Yeh, did VoiceOver work in WebKit
+ 'rjw' : 'rjw@apple.com',
+ 'seangies' : 'seangies@apple.com', # Sean Gies?, only 5 commits: r16600, r16592, r16511, r16489, r16484
+ 'sheridan' : 'sheridan@apple.com', # Shelly Sheridan
+ 'thatcher' : 'timothy@apple.com',
+ 'tomernic' : 'timo@apple.com',
+ 'trey' : 'trey@usa.net',
+ 'tristan' : 'tristan@apple.com',
+ 'vicki' : 'vicki@apple.com',
+ 'voas' : 'voas@apple.com', # Ed Voas, did some Carbon work in WebKit
+ 'zack' : 'zack@kde.org',
+ 'zimmermann' : 'zimmermann@webkit.org',
+ }
+
+ def __init__(self):
+ self._last_commit_time_by_author_cache = {}
+
+ def _fetch_authors_and_last_commit_time_from_git_log(self):
+ last_commit_dates = {}
+ git_log_args = ['git', 'log', '--reverse', '--pretty=format:%ae %at']
+ process = subprocess.Popen(git_log_args, stdout=subprocess.PIPE)
+
+ # eric@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc 1257090899
+ line_regexp = re.compile("^(?P<author>.+)@\S+ (?P<timestamp>\d+)$")
+ while True:
+ output_line = process.stdout.readline()
+ if output_line == '' and process.poll() != None:
+ return last_commit_dates
+
+ match_result = line_regexp.match(output_line)
+ if not match_result:
+ error("Failed to match line: %s" % output_line)
+ last_commit_dates[match_result.group('author')] = float(match_result.group('timestamp'))
+
+ def _fill_in_emails_for_old_logins(self):
+ authors_missing_email = filter(lambda author: author.find('@') == -1, self._last_commit_time_by_author_cache)
+ authors_with_email = filter(lambda author: author.find('@') != -1, self._last_commit_time_by_author_cache)
+ prefixes_of_authors_with_email = map(lambda author: author.split('@')[0], authors_with_email)
+
+ for author in authors_missing_email:
+ # First check to see if we have a manual mapping from login to email.
+ author_email = self.login_to_email_address.get(author)
+
+ # Most old logins like 'darin' are now just 'darin@apple.com', so check for a prefix match if a manual mapping was not found.
+ if not author_email and author in prefixes_of_authors_with_email:
+ author_email_index = prefixes_of_authors_with_email.index(author)
+ author_email = authors_with_email[author_email_index]
+
+ if not author_email:
+ # No known email mapping, likely not an active committer. We could log here.
+ continue
+
+ # log("%s -> %s" % (author, author_email)) # For sanity checking.
+ no_email_commit_time = self._last_commit_time_by_author_cache.get(author)
+ email_commit_time = self._last_commit_time_by_author_cache.get(author_email)
+ # We compare the timestamps for extra sanity even though we could assume commits before email address were used for login are always going to be older.
+ if not email_commit_time or email_commit_time < no_email_commit_time:
+ self._last_commit_time_by_author_cache[author_email] = no_email_commit_time
+ del self._last_commit_time_by_author_cache[author]
+
+ def _last_commit_by_author(self):
+ if not self._last_commit_time_by_author_cache:
+ self._last_commit_time_by_author_cache = self._fetch_authors_and_last_commit_time_from_git_log()
+ self._fill_in_emails_for_old_logins()
+ del self._last_commit_time_by_author_cache['(no author)'] # The initial svn import isn't very useful.
+ return self._last_commit_time_by_author_cache
+
+ @staticmethod
+ def _print_three_column_row(widths, values):
+ print "%s%s%s" % (values[0].ljust(widths[0]), values[1].ljust(widths[1]), values[2])
+
+ def print_possibly_expired_committers(self, committer_list):
+ authors_and_last_commits = self._last_commit_by_author().items()
+ authors_and_last_commits.sort(lambda a,b: cmp(a[1], b[1]), reverse=True)
+ committer_cuttof = date.today() - timedelta(days=365)
+ column_widths = [13, 25]
+ print
+ print "Committers who have not committed within one year:"
+ self._print_three_column_row(column_widths, ("Last Commit", "Committer Email", "Committer Record"))
+ for (author, last_commit) in authors_and_last_commits:
+ last_commit_date = date.fromtimestamp(last_commit)
+ if committer_cuttof > last_commit_date:
+ committer_record = committer_list.committer_by_email(author)
+ self._print_three_column_row(column_widths, (str(last_commit_date), author, committer_record))
+
+ def print_committers_missing_from_committer_list(self, committer_list):
+ missing_from_committers_py = []
+ last_commit_time_by_author = self._last_commit_by_author()
+ for author in last_commit_time_by_author:
+ if not committer_list.committer_by_email(author):
+ missing_from_committers_py.append(author)
+
+ never_committed = []
+ for committer in committer_list.committers():
+ for email in committer.emails:
+ if last_commit_time_by_author.get(email):
+ break
+ else:
+ never_committed.append(committer)
+
+ print_list_if_non_empty("Historical committers missing from committer.py:", missing_from_committers_py)
+ print_list_if_non_empty("Committers in committer.py who have never committed:", never_committed)
+
+
+def main():
+ committer_list = CommitterList()
+ CommitterListFromMailingList().check_for_emails_missing_from_list(committer_list)
+
+ svn_committer_list = CommitterListFromGit()
+ svn_committer_list.print_possibly_expired_committers(committer_list)
+ svn_committer_list.print_committers_missing_from_committer_list(committer_list)
+
+if __name__ == "__main__":
+ main()
diff --git a/WebKitTools/Scripts/webkitdirs.pm b/WebKitTools/Scripts/webkitdirs.pm
index 16f9c26..64e5dc4 100644
--- a/WebKitTools/Scripts/webkitdirs.pm
+++ b/WebKitTools/Scripts/webkitdirs.pm
@@ -67,6 +67,7 @@ my $isChromium;
# Variables for Win32 support
my $vcBuildPath;
my $windowsTmpPath;
+my $windowsSourceDir;
sub determineSourceDir
{
@@ -521,9 +522,19 @@ sub builtDylibPathForName
{
my $libraryName = shift;
determineConfigurationProductDir();
- if (isQt() or isChromium()) {
+ if (isChromium()) {
return "$configurationProductDir/$libraryName";
}
+ if (isQt()) {
+ $libraryName = "QtWebKit";
+ if (isDarwin() and -d "$configurationProductDir/lib/$libraryName.framework") {
+ return "$configurationProductDir/lib/$libraryName.framework/$libraryName";
+ } elsif (isWindows() or isCygwin()) {
+ return "$configurationProductDir/lib/$libraryName.dll";
+ } else {
+ return "$configurationProductDir/lib/lib$libraryName.so";
+ }
+ }
if (isWx()) {
return "$configurationProductDir/libwxwebkit.dylib";
}
@@ -561,7 +572,7 @@ sub libraryContainsSymbol
my $path = shift;
my $symbol = shift;
- if (isCygwin()) {
+ if (isCygwin() or isWindows()) {
# FIXME: Implement this for Windows.
return 0;
}
@@ -637,7 +648,8 @@ sub checkWebCoreSVGSupport
sub hasAcceleratedCompositingSupport
{
- return 0 if isCygwin() || isQt();
+ # On platforms other than Mac the Skipped files are used to skip compositing tests
+ return 1 if !isAppleMacWebKit();
my $path = shift;
return libraryContainsSymbol($path, "GraphicsLayer");
@@ -657,7 +669,8 @@ sub checkWebCoreAcceleratedCompositingSupport
sub has3DRenderingSupport
{
- return 0 if isQt();
+ # On platforms other than Mac the Skipped files are used to skip 3D tests
+ return 1 if !isAppleMacWebKit();
my $path = shift;
return libraryContainsSymbol($path, "WebCoreHas3DRendering");
@@ -680,7 +693,7 @@ sub has3DCanvasSupport
return 0 if isQt();
my $path = shift;
- return libraryContainsSymbol($path, "CanvasShader");
+ return libraryContainsSymbol($path, "WebGLShader");
}
sub checkWebCore3DCanvasSupport
@@ -974,6 +987,11 @@ sub isSnowLeopard()
return isDarwin() && osXVersion()->{"minor"} == 6;
}
+sub isWindowsNT()
+{
+ return $ENV{'OS'} eq 'Windows_NT';
+}
+
sub relativeScriptsDir()
{
my $scriptDir = File::Spec->catpath("", File::Spec->abs2rel(dirname($0), getcwd()), "");
@@ -1025,7 +1043,7 @@ sub checkRequiredSystemConfig
print "http://developer.apple.com/tools/xcode\n";
print "*************************************************************\n";
}
- } elsif (isGtk() or isQt() or isWx() or isChromium()) {
+ } elsif (isGtk() or isQt() or isWx()) {
my @cmds = qw(flex bison gperf);
my @missing = ();
foreach my $cmd (@cmds) {
@@ -1041,6 +1059,68 @@ sub checkRequiredSystemConfig
# Win32 and other platforms may want to check for minimum config
}
+sub determineWindowsSourceDir()
+{
+ return if $windowsSourceDir;
+ my $sourceDir = sourceDir();
+ chomp($windowsSourceDir = `cygpath -w $sourceDir`);
+}
+
+sub windowsSourceDir()
+{
+ determineWindowsSourceDir();
+ return $windowsSourceDir;
+}
+
+sub windowsLibrariesDir()
+{
+ return windowsSourceDir() . "\\WebKitLibraries\\win";
+}
+
+sub windowsOutputDir()
+{
+ return windowsSourceDir() . "\\WebKitBuild";
+}
+
+sub setupAppleWinEnv()
+{
+ return unless isAppleWinWebKit();
+
+ if (isWindowsNT()) {
+ my $restartNeeded = 0;
+ my %variablesToSet = ();
+
+ # Setting the environment variable 'CYGWIN' to 'tty' makes cygwin enable extra support (i.e., termios)
+ # for UNIX-like ttys in the Windows console
+ $variablesToSet{CYGWIN} = "tty" unless $ENV{CYGWIN};
+
+ # Those environment variables must be set to be able to build inside Visual Studio.
+ $variablesToSet{WEBKITLIBRARIESDIR} = windowsLibrariesDir() unless $ENV{WEBKITLIBRARIESDIR};
+ $variablesToSet{WEBKITOUTPUTDIR} = windowsOutputDir() unless $ENV{WEBKITOUTPUTDIR};
+
+ foreach my $variable (keys %variablesToSet) {
+ print "Setting the Environment Variable '" . $variable . "' to '" . $variablesToSet{$variable} . "'\n\n";
+ system qw(regtool -s set), '\\HKEY_CURRENT_USER\\Environment\\' . $variable, $variablesToSet{$variable};
+ $restartNeeded ||= $variable eq "WEBKITLIBRARIESDIR" || $variable eq "WEBKITOUTPUTDIR";
+ }
+
+ if ($restartNeeded) {
+ print "Please restart your computer before attempting to build inside Visual Studio.\n\n";
+ }
+ } else {
+ if (!$ENV{'WEBKITLIBRARIESDIR'}) {
+ print "Warning: You must set the 'WebKitLibrariesDir' environment variable\n";
+ print " to be able build WebKit from within Visual Studio.\n";
+ print " Make sure that 'WebKitLibrariesDir' points to the\n";
+ print " 'WebKitLibraries/win' directory, not the 'WebKitLibraries/' directory.\n\n";
+ }
+ if (!$ENV{'WEBKITOUTPUTDIR'}) {
+ print "Warning: You must set the 'WebKitOutputDir' environment variable\n";
+ print " to be able build WebKit from within Visual Studio.\n\n";
+ }
+ }
+}
+
sub setupCygwinEnv()
{
return if !isCygwin();
@@ -1119,9 +1199,6 @@ sub buildVisualStudioProject
}
my $useenv = "/useenv";
- if (isChromium()) {
- $useenv = "";
- }
my @command = ($vcBuildPath, $useenv, $winProjectPath, $action, $config);
@@ -1393,6 +1470,46 @@ sub buildGtkProject($$@)
return buildAutotoolsProject($clean, @buildArgs);
}
+sub buildChromiumMakefile($$$)
+{
+ my ($dir, $target, $clean) = @_;
+ chdir $dir;
+ if ($clean) {
+ return system qw(rm -rf out);
+ }
+ my $config = configuration();
+ my @command = ("make", "-j4", "BUILDTYPE=$config", $target);
+ print join(" ", @command) . "\n";
+ return system @command;
+}
+
+sub buildChromiumVisualStudioProject($$)
+{
+ my ($projectPath, $clean) = @_;
+
+ my $config = configuration();
+ my $action = "/build";
+ $action = "/clean" if $clean;
+
+ # Find Visual Studio installation.
+ my $vsInstallDir;
+ my $programFilesPath = $ENV{'PROGRAMFILES'} || "C:\\Program Files";
+ if ($ENV{'VSINSTALLDIR'}) {
+ $vsInstallDir = $ENV{'VSINSTALLDIR'};
+ } else {
+ $vsInstallDir = "$programFilesPath/Microsoft Visual Studio 8";
+ }
+ $vsInstallDir = `cygpath "$vsInstallDir"` if isCygwin();
+ chomp $vsInstallDir;
+ $vcBuildPath = "$vsInstallDir/Common7/IDE/devenv.com";
+
+ # Create command line and execute it.
+ my @command = ($vcBuildPath, $projectPath, $action, $config);
+ print "Building results into: ", baseProductDir(), "\n";
+ print join(" ", @command), "\n";
+ return system @command;
+}
+
sub buildChromium($@)
{
my ($clean, @options) = @_;
@@ -1400,30 +1517,38 @@ sub buildChromium($@)
my $result = 1;
if (isDarwin()) {
# Mac build - builds the root xcode project.
- $result = buildXCodeProject("WebKit/chromium/webkit",
- $clean,
- (@options));
- } elsif (isCygwin()) {
+ $result = buildXCodeProject("WebKit/chromium/WebKit", $clean, (@options));
+ } elsif (isCygwin() || isWindows()) {
# Windows build - builds the root visual studio solution.
- $result = buildVisualStudioProject("WebKit/chromium/webkit.sln",
- $clean);
+ $result = buildChromiumVisualStudioProject("WebKit/chromium/WebKit.sln", $clean);
} elsif (isLinux()) {
- # Linux build
- # FIXME support linux.
- print STDERR "Linux build is not supported. Yet.";
+ # Linux build - build using make.
+ $ result = buildChromiumMakefile("WebKit/chromium/", "webkit", $clean);
} else {
- print STDERR "This platform is not supported by chromium.";
+ print STDERR "This platform is not supported by chromium.\n";
}
return $result;
}
+sub appleApplicationSupportPath
+{
+ open INSTALL_DIR, "</proc/registry/HKEY_LOCAL_MACHINE/SOFTWARE/Apple\ Inc./Apple\ Application\ Support/InstallDir";
+ my $path = <INSTALL_DIR>;
+ $path =~ s/[\r\n\x00].*//;
+ close INSTALL_DIR;
+
+ my $unixPath = `cygpath -u '$path'`;
+ chomp $unixPath;
+ return $unixPath;
+}
+
sub setPathForRunningWebKitApp
{
my ($env) = @_;
return unless isAppleWinWebKit();
- $env->{PATH} = join(':', productDir(), dirname(installedSafariPath()), $env->{PATH} || "");
+ $env->{PATH} = join(':', productDir(), dirname(installedSafariPath()), appleApplicationSupportPath(), $env->{PATH} || "");
}
sub exitStatus($)
diff --git a/WebKitTools/pywebsocket/example/echo_client.py b/WebKitTools/pywebsocket/example/echo_client.py
index 61b129c..3262a6d 100644
--- a/WebKitTools/pywebsocket/example/echo_client.py
+++ b/WebKitTools/pywebsocket/example/echo_client.py
@@ -46,6 +46,8 @@ import socket
import sys
+_TIMEOUT_SEC = 10
+
_DEFAULT_PORT = 80
_DEFAULT_SECURE_PORT = 443
_UNDEFINED_PORT = -1
@@ -57,6 +59,8 @@ _EXPECTED_RESPONSE = (
_UPGRADE_HEADER +
_CONNECTION_HEADER)
+_GOODBYE_MESSAGE = 'Goodbye'
+
def _method_line(resource):
return 'GET %s HTTP/1.1\r\n' % resource
@@ -96,13 +100,14 @@ class EchoClient(object):
Shake hands and then repeat sending message and receiving its echo.
"""
self._socket = socket.socket()
+ self._socket.settimeout(self._options.socket_timeout)
try:
self._socket.connect((self._options.server_host,
self._options.server_port))
if self._options.use_tls:
self._socket = _TLSSocket(self._socket)
self._handshake()
- for line in self._options.message.split(','):
+ for line in self._options.message.split(',') + [_GOODBYE_MESSAGE]:
frame = '\x00' + line.encode('utf-8') + '\xff'
self._socket.send(frame)
if self._options.verbose:
@@ -111,7 +116,8 @@ class EchoClient(object):
if received != frame:
raise Exception('Incorrect echo: %r' % received)
if self._options.verbose:
- print 'Recv: %s' % received[1:-1].decode('utf-8')
+ print 'Recv: %s' % received[1:-1].decode('utf-8',
+ 'replace')
finally:
self._socket.close()
@@ -166,11 +172,17 @@ def main():
parser.add_option('-r', '--resource', dest='resource', type='string',
default='/echo', help='resource path')
parser.add_option('-m', '--message', dest='message', type='string',
- help='comma-separated messages to send')
+ help=('comma-separated messages to send excluding "%s" '
+ 'that is always sent at the end' %
+ _GOODBYE_MESSAGE))
parser.add_option('-q', '--quiet', dest='verbose', action='store_false',
default=True, help='suppress messages')
parser.add_option('-t', '--tls', dest='use_tls', action='store_true',
default=False, help='use TLS (wss://)')
+ parser.add_option('-k', '--socket_timeout', dest='socket_timeout',
+ type='int', default=_TIMEOUT_SEC,
+ help='Timeout(sec) for sockets')
+
(options, unused_args) = parser.parse_args()
# Default port number depends on whether TLS is used.
diff --git a/WebKitTools/pywebsocket/example/echo_wsh.py b/WebKitTools/pywebsocket/example/echo_wsh.py
index f680fa5..50cad31 100644
--- a/WebKitTools/pywebsocket/example/echo_wsh.py
+++ b/WebKitTools/pywebsocket/example/echo_wsh.py
@@ -31,6 +31,9 @@
from mod_pywebsocket import msgutil
+_GOODBYE_MESSAGE = 'Goodbye'
+
+
def web_socket_do_extra_handshake(request):
pass # Always accept.
@@ -39,6 +42,8 @@ def web_socket_transfer_data(request):
while True:
line = msgutil.receive_message(request)
msgutil.send_message(request, line)
+ if line == _GOODBYE_MESSAGE:
+ return
# vi:sts=4 sw=4 et
diff --git a/WebKitTools/pywebsocket/mod_pywebsocket/__init__.py b/WebKitTools/pywebsocket/mod_pywebsocket/__init__.py
index beacc9e..05e80e8 100644
--- a/WebKitTools/pywebsocket/mod_pywebsocket/__init__.py
+++ b/WebKitTools/pywebsocket/mod_pywebsocket/__init__.py
@@ -96,6 +96,9 @@ web_socket_transfer_data is called after the handshake completed
successfully. A handler can receive/send messages from/to the client
using request. mod_pywebsocket.msgutil module provides utilities
for data transfer.
+
+A Web Socket handler must be thread-safe if the server (Apache or
+standalone.py) is configured to use threads.
"""
diff --git a/WebKitTools/pywebsocket/mod_pywebsocket/dispatch.py b/WebKitTools/pywebsocket/mod_pywebsocket/dispatch.py
index 84422eb..bf9a856 100644
--- a/WebKitTools/pywebsocket/mod_pywebsocket/dispatch.py
+++ b/WebKitTools/pywebsocket/mod_pywebsocket/dispatch.py
@@ -62,7 +62,7 @@ def _normalize_path(path):
"""
path = path.replace('\\', os.path.sep)
- path = os.path.abspath(path)
+ path = os.path.realpath(path)
path = path.replace('\\', '/')
return path
@@ -136,7 +136,8 @@ class Dispatcher(object):
self._source_warnings = []
if scan_dir is None:
scan_dir = root_dir
- if not os.path.abspath(scan_dir).startswith(os.path.abspath(root_dir)):
+ if not os.path.realpath(scan_dir).startswith(
+ os.path.realpath(root_dir)):
raise DispatchError('scan_dir:%s must be a directory under '
'root_dir:%s.' % (scan_dir, root_dir))
self._source_files_in_dir(root_dir, scan_dir)
@@ -159,9 +160,13 @@ class Dispatcher(object):
do_extra_handshake_, unused_transfer_data = self._handler(request)
try:
do_extra_handshake_(request)
- except Exception:
- raise DispatchError('%s raised exception: %s' %
- (_DO_EXTRA_HANDSHAKE_HANDLER_NAME, util.get_stack_trace()))
+ except Exception, e:
+ util.prepend_message_to_exception(
+ '%s raised exception for %s: ' % (
+ _DO_EXTRA_HANDSHAKE_HANDLER_NAME,
+ request.ws_resource),
+ e)
+ raise
def transfer_data(self, request):
"""Let a handler transfer_data with a Web Socket client.
@@ -176,19 +181,23 @@ class Dispatcher(object):
unused_do_extra_handshake, transfer_data_ = self._handler(request)
try:
transfer_data_(request)
- except Exception:
- raise DispatchError('%s raised exception: %s' %
- (_TRANSFER_DATA_HANDLER_NAME, util.get_stack_trace()))
+ except Exception, e:
+ util.prepend_message_to_exception(
+ '%s raised exception for %s: ' % (
+ _TRANSFER_DATA_HANDLER_NAME, request.ws_resource),
+ e)
+ raise
def _handler(self, request):
try:
- return self._handlers[request.ws_resource]
+ ws_resource_path = request.ws_resource.split('?', 1)[0]
+ return self._handlers[ws_resource_path]
except KeyError:
raise DispatchError('No handler for: %r' % request.ws_resource)
def _source_files_in_dir(self, root_dir, scan_dir):
"""Source all the handler source files in the scan_dir directory.
-
+
The resource path is determined relative to root_dir.
"""
diff --git a/WebKitTools/pywebsocket/mod_pywebsocket/msgutil.py b/WebKitTools/pywebsocket/mod_pywebsocket/msgutil.py
index bdb554d..90ae715 100644
--- a/WebKitTools/pywebsocket/mod_pywebsocket/msgutil.py
+++ b/WebKitTools/pywebsocket/mod_pywebsocket/msgutil.py
@@ -39,6 +39,31 @@ not suitable because they don't allow direct raw bytes writing/reading.
import Queue
import threading
+import util
+
+
+class MsgUtilException(Exception):
+ pass
+
+
+def _read(request, length):
+ bytes = request.connection.read(length)
+ if not bytes:
+ raise MsgUtilException(
+ 'Failed to receive message from %r' %
+ (request.connection.remote_addr,))
+ return bytes
+
+
+def _write(request, bytes):
+ try:
+ request.connection.write(bytes)
+ except Exception, e:
+ util.prepend_message_to_exception(
+ 'Failed to send message to %r: ' %
+ (request.connection.remote_addr,),
+ e)
+ raise
def send_message(request, message):
@@ -49,7 +74,7 @@ def send_message(request, message):
message: unicode string to send.
"""
- request.connection.write('\x00' + message.encode('utf-8') + '\xff')
+ _write(request, '\x00' + message.encode('utf-8') + '\xff')
def receive_message(request):
@@ -63,7 +88,7 @@ def receive_message(request):
# Read 1 byte.
# mp_conn.read will block if no bytes are available.
# Timeout is controlled by TimeOut directive of Apache.
- frame_type_str = request.connection.read(1)
+ frame_type_str = _read(request, 1)
frame_type = ord(frame_type_str[0])
if (frame_type & 0x80) == 0x80:
# The payload length is specified in the frame.
@@ -73,7 +98,9 @@ def receive_message(request):
else:
# The payload is delimited with \xff.
bytes = _read_until(request, '\xff')
- message = bytes.decode('utf-8')
+ # The Web Socket protocol section 4.4 specifies that invalid
+ # characters must be replaced with U+fffd REPLACEMENT CHARACTER.
+ message = bytes.decode('utf-8', 'replace')
if frame_type == 0x00:
return message
# Discard data of other types.
@@ -82,7 +109,7 @@ def receive_message(request):
def _payload_length(request):
length = 0
while True:
- b_str = request.connection.read(1)
+ b_str = _read(request, 1)
b = ord(b_str[0])
length = length * 128 + (b & 0x7f)
if (b & 0x80) == 0:
@@ -93,7 +120,7 @@ def _payload_length(request):
def _receive_bytes(request, length):
bytes = []
while length > 0:
- new_bytes = request.connection.read(length)
+ new_bytes = _read(request, length)
bytes.append(new_bytes)
length -= len(new_bytes)
return ''.join(bytes)
@@ -102,7 +129,7 @@ def _receive_bytes(request, length):
def _read_until(request, delim_char):
bytes = []
while True:
- ch = request.connection.read(1)
+ ch = _read(request, 1)
if ch == delim_char:
break
bytes.append(ch)
diff --git a/WebKitTools/pywebsocket/mod_pywebsocket/standalone.py b/WebKitTools/pywebsocket/mod_pywebsocket/standalone.py
index a4c142b..6217585 100644
--- a/WebKitTools/pywebsocket/mod_pywebsocket/standalone.py
+++ b/WebKitTools/pywebsocket/mod_pywebsocket/standalone.py
@@ -38,6 +38,7 @@ Usage:
python standalone.py [-p <ws_port>] [-w <websock_handlers>]
[-s <scan_dir>]
[-d <document_root>]
+ ... for other options, see _main below ...
<ws_port> is the port number to use for ws:// connection.
@@ -59,6 +60,7 @@ import BaseHTTPServer
import SimpleHTTPServer
import SocketServer
import logging
+import logging.handlers
import optparse
import os
import socket
@@ -73,6 +75,25 @@ except ImportError:
import dispatch
import handshake
+import util
+
+
+_LOG_LEVELS = {
+ 'debug': logging.DEBUG,
+ 'info': logging.INFO,
+ 'warn': logging.WARN,
+ 'error': logging.ERROR,
+ 'critical': logging.CRITICAL};
+
+_DEFAULT_LOG_MAX_BYTES = 1024 * 256
+_DEFAULT_LOG_BACKUP_COUNT = 5
+
+
+def _print_warnings_if_any(dispatcher):
+ warnings = dispatcher.source_warnings()
+ if warnings:
+ for warning in warnings:
+ logging.warning('mod_pywebsocket: %s' % warning)
class _StandaloneConnection(object):
@@ -92,6 +113,14 @@ class _StandaloneConnection(object):
self._request_handler.server.server_port)
local_addr = property(get_local_addr)
+ def get_remote_addr(self):
+ """Getter to mimic mp_conn.remote_addr.
+
+ Setting the property in __init__ won't work because the request
+ handler is not initialized yet there."""
+ return self._request_handler.client_address
+ remote_addr = property(get_remote_addr)
+
def write(self, data):
"""Mimic mp_conn.write()."""
return self._request_handler.wfile.write(data)
@@ -152,6 +181,16 @@ class WebSocketServer(SocketServer.ThreadingMixIn, BaseHTTPServer.HTTPServer):
socket_ = OpenSSL.SSL.Connection(ctx, socket_)
return socket_
+ def handle_error(self, rquest, client_address):
+ """Override SocketServer.handle_error."""
+
+ logging.error(
+ ('Exception in processing request from: %r' % (client_address,)) +
+ '\n' + util.get_stack_trace())
+ # Note: client_address is a tuple. To match it against %r, we need the
+ # trailing comma.
+
+
class WebSocketRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
"""SimpleHTTPRequestHandler specialized for Web Socket."""
@@ -159,15 +198,13 @@ class WebSocketRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
"""Override SocketServer.StreamRequestHandler.setup."""
self.connection = self.request
- self.rfile = socket._fileobject(self.request, "rb", self.rbufsize)
- self.wfile = socket._fileobject(self.request, "wb", self.wbufsize)
+ self.rfile = socket._fileobject(self.request, 'rb', self.rbufsize)
+ self.wfile = socket._fileobject(self.request, 'wb', self.wbufsize)
def __init__(self, *args, **keywords):
self._request = _StandaloneRequest(
self, WebSocketRequestHandler.options.use_tls)
- self._dispatcher = dispatch.Dispatcher(
- WebSocketRequestHandler.options.websock_handlers,
- WebSocketRequestHandler.options.scan_dir)
+ self._dispatcher = WebSocketRequestHandler.options.dispatcher
self._print_warnings_if_any()
self._handshaker = handshake.Handshaker(self._request,
self._dispatcher)
@@ -198,12 +235,41 @@ class WebSocketRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
except dispatch.DispatchError, e:
logging.warning('mod_pywebsocket: %s' % e)
return False
+ except Exception, e:
+ logging.warning('mod_pywebsocket: %s' % e)
+ logging.info('mod_pywebsocket: %s' % util.get_stack_trace())
+ return False
return result
+ def log_request(self, code='-', size='-'):
+ """Override BaseHTTPServer.log_request."""
-def _main():
- logging.basicConfig()
+ logging.info('"%s" %s %s',
+ self.requestline, str(code), str(size))
+ def log_error(self, *args):
+ """Override BaseHTTPServer.log_error."""
+
+ # Despite the name, this method is for warnings than for errors.
+ # For example, HTTP status code is logged by this method.
+ logging.warn('%s - %s' % (self.address_string(), (args[0] % args[1:])))
+
+
+def _configure_logging(options):
+ logger = logging.getLogger()
+ logger.setLevel(_LOG_LEVELS[options.log_level])
+ if options.log_file:
+ handler = logging.handlers.RotatingFileHandler(
+ options.log_file, 'a', options.log_max, options.log_count)
+ else:
+ handler = logging.StreamHandler()
+ formatter = logging.Formatter(
+ "[%(asctime)s] [%(levelname)s] %(name)s: %(message)s")
+ handler.setFormatter(formatter)
+ logger.addHandler(handler)
+
+
+def _main():
parser = optparse.OptionParser()
parser.add_option('-p', '--port', dest='port', type='int',
default=handshake._DEFAULT_WEB_SOCKET_PORT,
@@ -224,27 +290,51 @@ def _main():
default='', help='TLS private key file.')
parser.add_option('-c', '--certificate', dest='certificate',
default='', help='TLS certificate file.')
+ parser.add_option('-l', '--log_file', dest='log_file',
+ default='', help='Log file.')
+ parser.add_option('--log_level', type='choice', dest='log_level',
+ default='warn',
+ choices=['debug', 'info', 'warn', 'error', 'critical'],
+ help='Log level.')
+ parser.add_option('--log_max', dest='log_max', type='int',
+ default=_DEFAULT_LOG_MAX_BYTES,
+ help='Log maximum bytes')
+ parser.add_option('--log_count', dest='log_count', type='int',
+ default=_DEFAULT_LOG_BACKUP_COUNT,
+ help='Log backup count')
options = parser.parse_args()[0]
+ os.chdir(options.document_root)
+
+ _configure_logging(options)
+
if options.use_tls:
if not _HAS_OPEN_SSL:
- print >>sys.stderr, 'To use TLS, install pyOpenSSL.'
+ logging.critical('To use TLS, install pyOpenSSL.')
sys.exit(1)
if not options.private_key or not options.certificate:
- print >>sys.stderr, ('To use TLS, specify private_key and '
- 'certificate.')
+ logging.critical(
+ 'To use TLS, specify private_key and certificate.')
sys.exit(1)
if not options.scan_dir:
options.scan_dir = options.websock_handlers
- WebSocketRequestHandler.options = options
- WebSocketServer.options = options
-
- os.chdir(options.document_root)
-
- server = WebSocketServer(('', options.port), WebSocketRequestHandler)
- server.serve_forever()
+ try:
+ # Share a Dispatcher among request handlers to save time for
+ # instantiation. Dispatcher can be shared because it is thread-safe.
+ options.dispatcher = dispatch.Dispatcher(options.websock_handlers,
+ options.scan_dir)
+ _print_warnings_if_any(options.dispatcher)
+
+ WebSocketRequestHandler.options = options
+ WebSocketServer.options = options
+
+ server = WebSocketServer(('', options.port), WebSocketRequestHandler)
+ server.serve_forever()
+ except Exception, e:
+ logging.critical(str(e))
+ sys.exit(1)
if __name__ == '__main__':
diff --git a/WebKitTools/pywebsocket/mod_pywebsocket/util.py b/WebKitTools/pywebsocket/mod_pywebsocket/util.py
index 4835298..0ea8053 100644
--- a/WebKitTools/pywebsocket/mod_pywebsocket/util.py
+++ b/WebKitTools/pywebsocket/mod_pywebsocket/util.py
@@ -49,4 +49,11 @@ def get_stack_trace():
return out.getvalue()
+def prepend_message_to_exception(message, exc):
+ """Prepend message to the exception."""
+
+ exc.args = (message + str(exc),)
+ return
+
+
# vi:sts=4 sw=4 et
diff --git a/WebKitTools/pywebsocket/setup.py b/WebKitTools/pywebsocket/setup.py
index 1810a6d..df05fef 100644
--- a/WebKitTools/pywebsocket/setup.py
+++ b/WebKitTools/pywebsocket/setup.py
@@ -56,7 +56,7 @@ setup(author='Yuzo Fujishima',
name=_PACKAGE_NAME,
packages=[_PACKAGE_NAME],
url='http://code.google.com/p/pywebsocket/',
- version='0.4.1',
+ version='0.4.3',
)
diff --git a/WebKitTools/pywebsocket/test/test_dispatch.py b/WebKitTools/pywebsocket/test/test_dispatch.py
index d617205..b19d706 100644
--- a/WebKitTools/pywebsocket/test/test_dispatch.py
+++ b/WebKitTools/pywebsocket/test/test_dispatch.py
@@ -136,8 +136,7 @@ class DispatcherTest(unittest.TestCase):
dispatcher.do_extra_handshake(request) # Must not raise exception.
request.ws_origin = 'http://bad.example.com'
- self.assertRaises(dispatch.DispatchError,
- dispatcher.do_extra_handshake, request)
+ self.assertRaises(Exception, dispatcher.do_extra_handshake, request)
def test_transfer_data(self):
dispatcher = dispatch.Dispatcher(_TEST_HANDLERS_DIR, None)
@@ -156,6 +155,20 @@ class DispatcherTest(unittest.TestCase):
self.assertEqual('sub/plain_wsh.py is called for /sub/plain, None',
request.connection.written_data())
+ request = mock.MockRequest(connection=mock.MockConn(''))
+ request.ws_resource = '/sub/plain?'
+ request.ws_protocol = None
+ dispatcher.transfer_data(request)
+ self.assertEqual('sub/plain_wsh.py is called for /sub/plain?, None',
+ request.connection.written_data())
+
+ request = mock.MockRequest(connection=mock.MockConn(''))
+ request.ws_resource = '/sub/plain?q=v'
+ request.ws_protocol = None
+ dispatcher.transfer_data(request)
+ self.assertEqual('sub/plain_wsh.py is called for /sub/plain?q=v, None',
+ request.connection.written_data())
+
def test_transfer_data_no_handler(self):
dispatcher = dispatch.Dispatcher(_TEST_HANDLERS_DIR, None)
for resource in ['/blank', '/sub/non_callable',
@@ -179,10 +192,8 @@ class DispatcherTest(unittest.TestCase):
try:
dispatcher.transfer_data(request)
self.fail()
- except dispatch.DispatchError, e:
+ except Exception, e:
self.failUnless(str(e).find('Intentional') != -1)
- except Exception:
- self.fail()
def test_scan_dir(self):
disp = dispatch.Dispatcher(_TEST_HANDLERS_DIR, None)
diff --git a/WebKitTools/pywebsocket/test/test_msgutil.py b/WebKitTools/pywebsocket/test/test_msgutil.py
index b3ba539..16b88e0 100644
--- a/WebKitTools/pywebsocket/test/test_msgutil.py
+++ b/WebKitTools/pywebsocket/test/test_msgutil.py
@@ -71,6 +71,13 @@ class MessageTest(unittest.TestCase):
# U+672c is encoded as e6,9c,ac in UTF-8
self.assertEqual(u'\u672c', msgutil.receive_message(request))
+ def test_receive_message_erroneous_unicode(self):
+ # \x80 and \x81 are invalid as UTF-8.
+ request = _create_request('\x00\x80\x81\xff')
+ # Invalid characters should be replaced with
+ # U+fffd REPLACEMENT CHARACTER
+ self.assertEqual(u'\ufffd\ufffd', msgutil.receive_message(request))
+
def test_receive_message_discard(self):
request = _create_request('\x80\x06IGNORE\x00Hello\xff'
'\x01DISREGARD\xff\x00World!\xff')
diff --git a/WebKitTools/pywebsocket/test/test_util.py b/WebKitTools/pywebsocket/test/test_util.py
index 8058b6d..83e2635 100644
--- a/WebKitTools/pywebsocket/test/test_util.py
+++ b/WebKitTools/pywebsocket/test/test_util.py
@@ -49,6 +49,12 @@ class UtilTest(unittest.TestCase):
self.failUnless(trace.startswith('Traceback'))
self.failUnless(trace.find('ZeroDivisionError') != -1)
+ def test_prepend_message_to_exception(self):
+ exc = Exception('World')
+ self.assertEqual('World', str(exc))
+ util.prepend_message_to_exception('Hello ', exc)
+ self.assertEqual('Hello World', str(exc))
+
if __name__ == '__main__':
unittest.main()
diff --git a/WebKitTools/wx/browser/wscript b/WebKitTools/wx/browser/wscript
index d5246c1..a2a24e0 100644
--- a/WebKitTools/wx/browser/wscript
+++ b/WebKitTools/wx/browser/wscript
@@ -45,7 +45,7 @@ def build(bld):
includes = ' '.join(include_paths),
source = 'browser.cpp',
target = 'wxBrowser',
- uselib = 'WXWEBKIT WX ' + get_config(),
+ uselib = 'WX CURL ICU XSLT XML WXWEBKIT ' + get_config(),
libpath = [output_dir],
uselib_local = '',
install_path = output_dir)
diff --git a/WebKitTools/wx/build/build_utils.py b/WebKitTools/wx/build/build_utils.py
index b767d9f..a6962e2 100644
--- a/WebKitTools/wx/build/build_utils.py
+++ b/WebKitTools/wx/build/build_utils.py
@@ -176,7 +176,7 @@ def get_config(wk_root):
return config
def svn_revision():
- if os.system("git info") == 0:
+ if os.system("git-svn info") == 0:
info = commands.getoutput("git-svn info ../..")
else:
info = commands.getoutput("svn info")
diff --git a/WebKitTools/wx/build/settings.py b/WebKitTools/wx/build/settings.py
index 652a880..f7f75b6 100644
--- a/WebKitTools/wx/build/settings.py
+++ b/WebKitTools/wx/build/settings.py
@@ -337,7 +337,7 @@ def common_configure(conf):
# common win libs
conf.env.append_value('LIB', [
'kernel32', 'user32','gdi32','comdlg32','winspool','winmm',
- 'shell32', 'comctl32', 'ole32', 'oleaut32', 'uuid', 'advapi32',
+ 'shell32', 'shlwapi', 'comctl32', 'ole32', 'oleaut32', 'uuid', 'advapi32',
'wsock32', 'gdiplus', 'version'])
conf.env['LIB_ICU'] = ['icudt', 'icule', 'iculx', 'icuuc', 'icuin', 'icuio', 'icutu']
diff --git a/WebKitTools/wx/packaging/build-debian-installer.py b/WebKitTools/wx/packaging/build-debian-installer.py
new file mode 100644
index 0000000..5c6795d
--- /dev/null
+++ b/WebKitTools/wx/packaging/build-debian-installer.py
@@ -0,0 +1,36 @@
+#!/usr/bin/env python
+
+import os
+import shutil
+import sys
+
+sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "build")))
+
+import build_utils
+
+script_dir = os.path.abspath(os.path.dirname(__file__))
+wxwebkit_dir = os.path.abspath(os.path.join(script_dir, "..", "..", "..", "WebKitBuild", "Debug" + build_utils.git_branch_name()))
+wxwk_root = os.path.abspath(os.path.join(script_dir, "..", "..", ".."))
+
+try:
+ os.chdir(wxwk_root)
+ deb_dir = os.path.join(wxwk_root, 'wxwebkit')
+ if os.path.exists(deb_dir):
+ shutil.rmtree(deb_dir)
+ os.makedirs(deb_dir)
+ print "Archiving git tree..."
+ os.system('git archive --format=tar HEAD | gzip > %s/webkitwx_0.1.orig.tar.gz' % deb_dir)
+ src_root = os.path.join(deb_dir, 'webkitwx-0.1')
+ print "Extracting tree..."
+ os.makedirs(src_root)
+ os.chdir(src_root)
+ os.system('tar xzvf ../webkitwx_0.1.orig.tar.gz')
+
+ shutil.copytree(os.path.join(script_dir, 'debian'), os.path.join(src_root, 'debian'))
+
+ print "Building package..."
+ os.system('fakeroot debian/rules clean')
+ os.system('fakeroot debian/rules build')
+ os.system('debuild -i -rfakeroot -us -uc')
+finally:
+ shutil.rmtree(os.path.join(src_root, 'debian'))
diff --git a/WebKitTools/wx/packaging/debian/changelog b/WebKitTools/wx/packaging/debian/changelog
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/WebKitTools/wx/packaging/debian/changelog
@@ -0,0 +1 @@
+
diff --git a/WebKitTools/wx/packaging/debian/compat b/WebKitTools/wx/packaging/debian/compat
new file mode 100644
index 0000000..7ed6ff8
--- /dev/null
+++ b/WebKitTools/wx/packaging/debian/compat
@@ -0,0 +1 @@
+5
diff --git a/WebKitTools/wx/packaging/debian/control b/WebKitTools/wx/packaging/debian/control
new file mode 100644
index 0000000..57d8407
--- /dev/null
+++ b/WebKitTools/wx/packaging/debian/control
@@ -0,0 +1,29 @@
+Source: webkitwx
+Section: Python
+Priority: extra
+Maintainer: Kevin Ollivier <kevino@theolliviers.com>
+Build-Depends: debhelper (>= 5.0.38), python-central (>= 0.6), python-all-dev,
+ libwxgtk2.8-dev (>= 2.8.9.2-1), python-wxgtk2.8, python-wxtools (>= 2.8.9.2-1),
+ wx2.8-headers (>= 2.8.9.2-1), wx2.8-i18n (>= 2.8.9.2-1),
+ flex, bison, gperf, automake, autoconf, libtool, dpatch,
+ libxslt1-dev, libcurl4-openssl-dev,
+ libicu-dev, libjpeg62-dev, libpng12-dev, libsqlite3-dev, libgtk2.0-dev
+Build-Conflicts: python-setuptools
+XS-Python-Version: all
+Standards-Version: 3.7.3
+
+Package: python-webkitwx
+Section: python
+Architecture: any
+Depends: ${python:Depends}, ${shlibs:Depends}
+Provides: ${python:Provides}, webkitwx
+XB-Python-Version: ${python:Versions}
+Description: Python binding of wxwebkit
+ This is an experimental packaged release of webkit for wxpython
+
+Package: webkitwx-headers
+Architecture: all
+Description: Python binding of wxwebkit
+ This is an experimental packaged release of webkit for wxpython
+ These are the header files
+
diff --git a/WebKitTools/wx/packaging/debian/copyright b/WebKitTools/wx/packaging/debian/copyright
new file mode 100644
index 0000000..c2244ec
--- /dev/null
+++ b/WebKitTools/wx/packaging/debian/copyright
@@ -0,0 +1,18 @@
+This package was debianized by Chris Willing c.willing@uq.edu.au on
+Thu, Sat, 11 Apr 2009 12:54:52 +1000
+
+Upstream Author: Kevin Ollivier kevino@theolliviers.com and others
+
+Copyright: 2009 Kevin Ollivier, Apple Inc., and others
+
+License:
+ LGPL
+
+
+The Debian packaging is (C) 2009, Chris Willing <c.willing@uq.edu.au> and
+is licensed under the GPL, see `/usr/share/common-licenses/GPL'.
+
+
+# Please also look if there are files or directories which have a
+# different copyright/license attached and list them here.
+
diff --git a/WebKitTools/wx/packaging/debian/python-webkitwx.install b/WebKitTools/wx/packaging/debian/python-webkitwx.install
new file mode 100644
index 0000000..dff51ce
--- /dev/null
+++ b/WebKitTools/wx/packaging/debian/python-webkitwx.install
@@ -0,0 +1 @@
+WebKitBuild/Debug.master/libwxwebkit.so usr/lib/
diff --git a/WebKitTools/wx/packaging/debian/rules b/WebKitTools/wx/packaging/debian/rules
new file mode 100644
index 0000000..6840731
--- /dev/null
+++ b/WebKitTools/wx/packaging/debian/rules
@@ -0,0 +1,75 @@
+#! /usr/bin/make -f
+
+SHELL = /bin/bash
+
+PYVERS := $(shell /usr/bin/python -c 'import sys; print sys.version[:3]')
+VER := $(shell /usr/bin/python -c 'import sys; print sys.version[:3]')
+BIULD_DIR := WebKitBuild/Debug.master
+build: build-stamp
+build-stamp: $(PYVERS:%=build-python%)
+ touch $@
+build-python%:
+ touch $@
+
+clean:
+ rm -rf *-stamp build-python* build
+ rm -rf $(addprefix debian/,$(packages)) debian/files debian/substvars
+ rm -rf _trial_temp test.log
+ find . -name "*.pyc" |xargs -r rm
+ dh_clean
+
+install: build-stamp install-prereq $(PYVERS:%=install-python%) install-libs install-nover
+
+install-prereq: build-stamp
+ dh_testdir
+ dh_testroot
+ dh_clean -k
+
+install-python%: install-prereq
+ dh_install -ppython-webkitwx \
+ $(BUILD_DIR)/webview.py \
+ $(BUILD_DIR)/Debug.master/_webview.so \
+ usr/lib/python$*/site-packages/wx-2.8-gtk2-unicode/wx/
+
+install-nover: install-prereq
+ dh_install -pwebkitwx-headers \
+ $(BUILD_DIR)/JavaScriptCore \
+ usr/include/wxwebkit-1.0/
+
+install-libs: install-prereq
+ dh_install
+
+
+binary-indep:
+ (cd WebKitTools/Scripts && ./build-webkit --wx --makeargs="--wxpython")
+ dh_testdir
+ dh_testroot
+ dh_installchangelogs -i
+ dh_installdocs -i
+ dh_strip -i
+ dh_compress -i
+ dh_fixperms -i
+ dh_installdeb -i
+ dh_gencontrol -i
+ dh_md5sums -i
+ dh_builddeb -i
+
+binary-arch:
+ dh_testdir
+ dh_testroot
+ echo $(shell pwd)
+ echo $(shell ls -l)
+ dh_installchangelogs -a
+ dh_installdocs -a WebKit/wx/bindings/python/samples/simple.py
+ dh_strip -a
+ dh_compress -a -Xsimple.py
+ dh_fixperms -a
+ dh_pycentral -a
+ dh_installdeb -a
+ dh_shlibdeps -a
+ dh_gencontrol -a
+ dh_md5sums -a
+ dh_builddeb -a
+
+binary: binary-indep binary-arch
+.PHONY: build clean binary-indep binary-arch binary install install-nover install-prereq install-libs