<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[211370] trunk/Tools</title>
</head>
<body>
<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; }
#msg dl a { font-weight: bold}
#msg dl a:link { color:#fc3; }
#msg dl a:active { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/211370">211370</a></dd>
<dt>Author</dt> <dd>jbedard@apple.com</dd>
<dt>Date</dt> <dd>2017-01-30 09:31:47 -0800 (Mon, 30 Jan 2017)</dd>
</dl>
<h3>Log Message</h3>
<pre>Use simctl instead of LayoutTestRelay
https://bugs.webkit.org/show_bug.cgi?id=165927
Reviewed by Daniel Bates.
Part 1
LayoutTestRelay uses SPI, since recent versions of the iOS SDK allow for installing apps on
simulators through simctl (iOS 10 and later), use this functionality instead.
* Scripts/webkitpy/port/base.py:
(Port.__init__): Added _test_runner_process_constructor.
* Scripts/webkitpy/port/darwin.py:
(DarwinPort.app_identifier_from_bundle): Added function to extract bundle ID from plist.
* Scripts/webkitpy/port/driver.py:
(Driver._start): Pass worker_number to server_process so we can look up the correct simulator device to use.
(IOSSimulatorDriver): Deleted.
* Scripts/webkitpy/port/driver_unittest.py:
(DriverTest.test_stop_cleans_up_properly): Set _test_runner_process_constructor for testing.
(DriverTest.test_two_starts_cleans_up_properly): Ditto.
(DriverTest.test_start_actually_starts): Ditto.
* Scripts/webkitpy/port/ios.py:
(IOSSimulatorPort): Remove relay_name.
(IOSSimulatorPort.__init__): Set _test_runner_process_constructor to SimulatorProcess for IOSSimulatorPort.
(IOSSimulatorPort._create_simulators): Formatting change.
(IOSSimulatorPort.relay_path): Deleted.
(IOSSimulatorPort._check_relay): Deleted.
(IOSSimulatorPort._check_port_build): Deleted. Use base class implementation
(IOSSimulatorPort._build_relay): Deleted.
(IOSSimulatorPort._build_driver): Deleted. Use base class implementation
(IOSSimulatorPort._driver_class): Deleted. Use base class implementation
* Scripts/webkitpy/port/ios_unittest.py:
(iosTest.test_32bit): Update test.
(iosTest.test_64bit): Update test.
* Scripts/webkitpy/port/server_process.py:
(ServerProcess.__init__): Added argument worker_number. This class does not make use of it. We will make use of this argument in SimulatorProcess to lookup the associated simulator device.
(ServerProcess._set_file_nonblocking): Added to share common code.
* Scripts/webkitpy/port/server_process_mock.py:
(MockServerProcess.__init__): Added argument worker_number.
* Scripts/webkitpy/port/simulator_process.py: Added.
(SimulatorProcess): Added.
(SimulatorProcess.Popen): Added.
(SimulatorProcess.Popen.__init__): Added. Initialize Popen structure with stdin, stdout, stderr and pid.
(SimulatorProcess.Popen.poll): Added. Check if the process is running.
(SimulatorProcess.Popen.wait): Added. Wait for process to close.
(SimulatorProcess.__init__): Added. Install app to device specified through port and worker_number.
(SimulatorProcess._reset): Added. Unlink fifos.
(SimulatorProcess._start): Added. Launch app on simulator, link fifos.
(SimulatorProcess._kill): Added. Shutdown app on simulator.
* Scripts/webkitpy/xcode/simulator.py:
(Device.__init__): Accept host to run install/launch/terminate.
(Device.install_app): Install app to target Device.
(Device.launch_app): Launch app on target Device.
(Device.terminate_app): Shutdown app on target Device.
(Simulator._parse_devices): Pass host to Device.</pre>
<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkToolsChangeLog">trunk/Tools/ChangeLog</a></li>
<li><a href="#trunkToolsScriptswebkitpyportbasepy">trunk/Tools/Scripts/webkitpy/port/base.py</a></li>
<li><a href="#trunkToolsScriptswebkitpyportdarwinpy">trunk/Tools/Scripts/webkitpy/port/darwin.py</a></li>
<li><a href="#trunkToolsScriptswebkitpyportdriverpy">trunk/Tools/Scripts/webkitpy/port/driver.py</a></li>
<li><a href="#trunkToolsScriptswebkitpyportdriver_unittestpy">trunk/Tools/Scripts/webkitpy/port/driver_unittest.py</a></li>
<li><a href="#trunkToolsScriptswebkitpyportiospy">trunk/Tools/Scripts/webkitpy/port/ios.py</a></li>
<li><a href="#trunkToolsScriptswebkitpyportios_unittestpy">trunk/Tools/Scripts/webkitpy/port/ios_unittest.py</a></li>
<li><a href="#trunkToolsScriptswebkitpyportserver_processpy">trunk/Tools/Scripts/webkitpy/port/server_process.py</a></li>
<li><a href="#trunkToolsScriptswebkitpyportserver_process_mockpy">trunk/Tools/Scripts/webkitpy/port/server_process_mock.py</a></li>
<li><a href="#trunkToolsScriptswebkitpyxcodesimulatorpy">trunk/Tools/Scripts/webkitpy/xcode/simulator.py</a></li>
</ul>
<h3>Added Paths</h3>
<ul>
<li><a href="#trunkToolsScriptswebkitpyportsimulator_processpy">trunk/Tools/Scripts/webkitpy/port/simulator_process.py</a></li>
</ul>
</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkToolsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Tools/ChangeLog (211369 => 211370)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/ChangeLog        2017-01-30 17:09:06 UTC (rev 211369)
+++ trunk/Tools/ChangeLog        2017-01-30 17:31:47 UTC (rev 211370)
</span><span class="lines">@@ -1,3 +1,61 @@
</span><ins>+2017-01-30 Jonathan Bedard <jbedard@apple.com>
+
+ Use simctl instead of LayoutTestRelay
+ https://bugs.webkit.org/show_bug.cgi?id=165927
+
+ Reviewed by Daniel Bates.
+
+ Part 1
+
+ LayoutTestRelay uses SPI, since recent versions of the iOS SDK allow for installing apps on
+ simulators through simctl (iOS 10 and later), use this functionality instead.
+
+ * Scripts/webkitpy/port/base.py:
+ (Port.__init__): Added _test_runner_process_constructor.
+ * Scripts/webkitpy/port/darwin.py:
+ (DarwinPort.app_identifier_from_bundle): Added function to extract bundle ID from plist.
+ * Scripts/webkitpy/port/driver.py:
+ (Driver._start): Pass worker_number to server_process so we can look up the correct simulator device to use.
+ (IOSSimulatorDriver): Deleted.
+ * Scripts/webkitpy/port/driver_unittest.py:
+ (DriverTest.test_stop_cleans_up_properly): Set _test_runner_process_constructor for testing.
+ (DriverTest.test_two_starts_cleans_up_properly): Ditto.
+ (DriverTest.test_start_actually_starts): Ditto.
+ * Scripts/webkitpy/port/ios.py:
+ (IOSSimulatorPort): Remove relay_name.
+ (IOSSimulatorPort.__init__): Set _test_runner_process_constructor to SimulatorProcess for IOSSimulatorPort.
+ (IOSSimulatorPort._create_simulators): Formatting change.
+ (IOSSimulatorPort.relay_path): Deleted.
+ (IOSSimulatorPort._check_relay): Deleted.
+ (IOSSimulatorPort._check_port_build): Deleted. Use base class implementation
+ (IOSSimulatorPort._build_relay): Deleted.
+ (IOSSimulatorPort._build_driver): Deleted. Use base class implementation
+ (IOSSimulatorPort._driver_class): Deleted. Use base class implementation
+ * Scripts/webkitpy/port/ios_unittest.py:
+ (iosTest.test_32bit): Update test.
+ (iosTest.test_64bit): Update test.
+ * Scripts/webkitpy/port/server_process.py:
+ (ServerProcess.__init__): Added argument worker_number. This class does not make use of it. We will make use of this argument in SimulatorProcess to lookup the associated simulator device.
+ (ServerProcess._set_file_nonblocking): Added to share common code.
+ * Scripts/webkitpy/port/server_process_mock.py:
+ (MockServerProcess.__init__): Added argument worker_number.
+ * Scripts/webkitpy/port/simulator_process.py: Added.
+ (SimulatorProcess): Added.
+ (SimulatorProcess.Popen): Added.
+ (SimulatorProcess.Popen.__init__): Added. Initialize Popen structure with stdin, stdout, stderr and pid.
+ (SimulatorProcess.Popen.poll): Added. Check if the process is running.
+ (SimulatorProcess.Popen.wait): Added. Wait for process to close.
+ (SimulatorProcess.__init__): Added. Install app to device specified through port and worker_number.
+ (SimulatorProcess._reset): Added. Unlink fifos.
+ (SimulatorProcess._start): Added. Launch app on simulator, link fifos.
+ (SimulatorProcess._kill): Added. Shutdown app on simulator.
+ * Scripts/webkitpy/xcode/simulator.py:
+ (Device.__init__): Accept host to run install/launch/terminate.
+ (Device.install_app): Install app to target Device.
+ (Device.launch_app): Launch app on target Device.
+ (Device.terminate_app): Shutdown app on target Device.
+ (Simulator._parse_devices): Pass host to Device.
+
</ins><span class="cx"> 2017-01-30 Carlos Alberto Lopez Perez <clopez@igalia.com>
</span><span class="cx">
</span><span class="cx"> [GTK] pixman fails to compile on Raspberry Pi (GCC crash)
</span></span></pre></div>
<a id="trunkToolsScriptswebkitpyportbasepy"></a>
<div class="modfile"><h4>Modified: trunk/Tools/Scripts/webkitpy/port/base.py (211369 => 211370)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/Scripts/webkitpy/port/base.py        2017-01-30 17:09:06 UTC (rev 211369)
+++ trunk/Tools/Scripts/webkitpy/port/base.py        2017-01-30 17:31:47 UTC (rev 211370)
</span><span class="lines">@@ -131,6 +131,7 @@
</span><span class="cx"> self._web_platform_test_server = None
</span><span class="cx"> self._image_differ = None
</span><span class="cx"> self._server_process_constructor = server_process.ServerProcess # overridable for testing
</span><ins>+ self._test_runner_process_constructor = server_process.ServerProcess
</ins><span class="cx">
</span><span class="cx"> if not hasattr(options, 'configuration') or not options.configuration:
</span><span class="cx"> self.set_option_default('configuration', self.default_configuration())
</span></span></pre></div>
<a id="trunkToolsScriptswebkitpyportdarwinpy"></a>
<div class="modfile"><h4>Modified: trunk/Tools/Scripts/webkitpy/port/darwin.py (211369 => 211370)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/Scripts/webkitpy/port/darwin.py        2017-01-30 17:09:06 UTC (rev 211369)
+++ trunk/Tools/Scripts/webkitpy/port/darwin.py        2017-01-30 17:31:47 UTC (rev 211370)
</span><span class="lines">@@ -174,3 +174,11 @@
</span><span class="cx"> except ScriptError:
</span><span class="cx"> _log.warn("xcrun failed; falling back to '%s'." % fallback)
</span><span class="cx"> return fallback
</span><ins>+
+ def app_identifier_from_bundle(self, app_bundle):
+ plist_path = self._filesystem.join(app_bundle, 'Info.plist')
+ if not self._filesystem.exists(plist_path):
+ plist_path = self._filesystem.join(app_bundle, 'Contents', 'Info.plist')
+ if not self._filesystem.exists(plist_path):
+ return None
+ return self._executive.run_command(['/usr/libexec/PlistBuddy', '-c', 'Print CFBundleIdentifier', plist_path]).rstrip()
</ins></span></pre></div>
<a id="trunkToolsScriptswebkitpyportdriverpy"></a>
<div class="modfile"><h4>Modified: trunk/Tools/Scripts/webkitpy/port/driver.py (211369 => 211370)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/Scripts/webkitpy/port/driver.py        2017-01-30 17:09:06 UTC (rev 211369)
+++ trunk/Tools/Scripts/webkitpy/port/driver.py        2017-01-30 17:31:47 UTC (rev 211370)
</span><span class="lines">@@ -138,7 +138,7 @@
</span><span class="cx"> self._driver_user_directory_suffix = None
</span><span class="cx"> self._driver_user_cache_directory = None
</span><span class="cx">
</span><del>- # WebKitTestRunner/LayoutTestRelay can report back subprocess crashes by printing
</del><ins>+ # WebKitTestRunner can report back subprocess crashes by printing
</ins><span class="cx"> # "#CRASHED - PROCESSNAME". Since those can happen at any time and ServerProcess
</span><span class="cx"> # won't be aware of them (since the actual tool didn't crash, just a subprocess)
</span><span class="cx"> # we record the crashed subprocess name here.
</span><span class="lines">@@ -327,7 +327,6 @@
</span><span class="cx">
</span><span class="cx"> def _setup_environ_for_driver(self, environment):
</span><span class="cx"> build_root_path = str(self._port._build_path())
</span><del>- # FIXME: DYLD_* variables should be Mac-only. Even iOS Simulator doesn't need them, as LayoutTestRelay is a host binary.
</del><span class="cx"> self._append_environment_variable_path(environment, 'DYLD_LIBRARY_PATH', build_root_path)
</span><span class="cx"> self._append_environment_variable_path(environment, '__XPC_DYLD_LIBRARY_PATH', build_root_path)
</span><span class="cx"> self._append_environment_variable_path(environment, 'DYLD_FRAMEWORK_PATH', build_root_path)
</span><span class="lines">@@ -369,7 +368,7 @@
</span><span class="cx"> environment = self._setup_environ_for_test()
</span><span class="cx"> self._crashed_process_name = None
</span><span class="cx"> self._crashed_pid = None
</span><del>- self._server_process = self._port._server_process_constructor(self._port, self._server_name, self.cmd_line(pixel_tests, per_test_args), environment)
</del><ins>+ self._server_process = self._port._test_runner_process_constructor(self._port, self._server_name, self.cmd_line(pixel_tests, per_test_args), environment, worker_number=self._worker_number)
</ins><span class="cx"> self._server_process.start()
</span><span class="cx">
</span><span class="cx"> def _run_post_start_tasks(self):
</span><span class="lines">@@ -611,27 +610,6 @@
</span><span class="cx"> return True
</span><span class="cx">
</span><span class="cx">
</span><del>-# FIXME: this should be abstracted out via the Port subclass somehow.
-class IOSSimulatorDriver(Driver):
- def cmd_line(self, pixel_tests, per_test_args):
- cmd = super(IOSSimulatorDriver, self).cmd_line(pixel_tests, per_test_args)
- relay_tool = self._port.relay_path
- dump_tool = cmd[0]
- dump_tool_args = cmd[1:]
- product_dir = self._port._build_path()
- relay_args = [
- '-developerDir', self._port.developer_dir,
- '-udid', self._port.device_id_for_worker_number(self._worker_number),
- '-productDir', product_dir,
- '-app', dump_tool,
- ]
- return [relay_tool] + relay_args + ['--'] + dump_tool_args
-
- def _setup_environ_for_driver(self, environment):
- environment['DEVELOPER_DIR'] = self._port.developer_dir
- return super(IOSSimulatorDriver, self)._setup_environ_for_driver(environment)
-
-
</del><span class="cx"> class ContentBlock(object):
</span><span class="cx"> def __init__(self):
</span><span class="cx"> self.content_type = None
</span></span></pre></div>
<a id="trunkToolsScriptswebkitpyportdriver_unittestpy"></a>
<div class="modfile"><h4>Modified: trunk/Tools/Scripts/webkitpy/port/driver_unittest.py (211369 => 211370)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/Scripts/webkitpy/port/driver_unittest.py        2017-01-30 17:09:06 UTC (rev 211369)
+++ trunk/Tools/Scripts/webkitpy/port/driver_unittest.py        2017-01-30 17:31:47 UTC (rev 211370)
</span><span class="lines">@@ -264,7 +264,7 @@
</span><span class="cx">
</span><span class="cx"> def test_stop_cleans_up_properly(self):
</span><span class="cx"> port = TestWebKitPort()
</span><del>- port._server_process_constructor = MockServerProcess
</del><ins>+ port._test_runner_process_constructor = MockServerProcess
</ins><span class="cx"> driver = Driver(port, 0, pixel_tests=True)
</span><span class="cx"> driver.start(True, [])
</span><span class="cx"> last_tmpdir = port._filesystem.last_tmpdir
</span><span class="lines">@@ -274,7 +274,7 @@
</span><span class="cx">
</span><span class="cx"> def test_two_starts_cleans_up_properly(self):
</span><span class="cx"> port = TestWebKitPort()
</span><del>- port._server_process_constructor = MockServerProcess
</del><ins>+ port._test_runner_process_constructor = MockServerProcess
</ins><span class="cx"> driver = Driver(port, 0, pixel_tests=True)
</span><span class="cx"> driver.start(True, [])
</span><span class="cx"> last_tmpdir = port._filesystem.last_tmpdir
</span><span class="lines">@@ -283,7 +283,7 @@
</span><span class="cx">
</span><span class="cx"> def test_start_actually_starts(self):
</span><span class="cx"> port = TestWebKitPort()
</span><del>- port._server_process_constructor = MockServerProcess
</del><ins>+ port._test_runner_process_constructor = MockServerProcess
</ins><span class="cx"> driver = Driver(port, 0, pixel_tests=True)
</span><span class="cx"> driver.start(True, [])
</span><span class="cx"> self.assertTrue(driver._server_process.started)
</span></span></pre></div>
<a id="trunkToolsScriptswebkitpyportiospy"></a>
<div class="modfile"><h4>Modified: trunk/Tools/Scripts/webkitpy/port/ios.py (211369 => 211370)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/Scripts/webkitpy/port/ios.py        2017-01-30 17:09:06 UTC (rev 211369)
+++ trunk/Tools/Scripts/webkitpy/port/ios.py        2017-01-30 17:31:47 UTC (rev 211370)
</span><span class="lines">@@ -34,6 +34,7 @@
</span><span class="cx"> from webkitpy.port import config as port_config
</span><span class="cx"> from webkitpy.port import driver, image_diff
</span><span class="cx"> from webkitpy.port.darwin import DarwinPort
</span><ins>+from webkitpy.port.simulator_process import SimulatorProcess
</ins><span class="cx"> from webkitpy.xcode.simulator import Simulator, Runtime, DeviceType
</span><span class="cx"> from webkitpy.common.system.crashlogs import CrashLogs
</span><span class="cx">
</span><span class="lines">@@ -78,7 +79,6 @@
</span><span class="cx"> SDK = 'iphonesimulator'
</span><span class="cx">
</span><span class="cx"> SIMULATOR_BUNDLE_ID = 'com.apple.iphonesimulator'
</span><del>- relay_name = 'LayoutTestRelay'
</del><span class="cx"> SIMULATOR_DIRECTORY = "/tmp/WebKitTestingSimulators/"
</span><span class="cx"> LSREGISTER_PATH = "/System/Library/Frameworks/CoreServices.framework/Frameworks/LaunchServices.framework/Versions/Current/Support/lsregister"
</span><span class="cx"> PROCESS_COUNT_ESTIMATE_PER_SIMULATOR_INSTANCE = 100
</span><span class="lines">@@ -97,6 +97,7 @@
</span><span class="cx">
</span><span class="cx"> def __init__(self, host, port_name, **kwargs):
</span><span class="cx"> DarwinPort.__init__(self, host, port_name, **kwargs)
</span><ins>+ self._test_runner_process_constructor = SimulatorProcess
</ins><span class="cx">
</span><span class="cx"> optional_device_class = self.get_option('device_class')
</span><span class="cx"> self._printing_cmd_line = False
</span><span class="lines">@@ -148,17 +149,7 @@
</span><span class="cx"> device_type = DeviceType.from_name(device_name)
</span><span class="cx"> return device_type
</span><span class="cx">
</span><del>- @property
</del><span class="cx"> @memoized
</span><del>- def relay_path(self):
- if self._root_was_set:
- path = self._filesystem.abspath(self.get_option('root'))
- else:
- mac_config = port_config.Config(self._executive, self._filesystem, 'mac')
- path = mac_config.build_directory(self.get_option('configuration'))
- return self._filesystem.join(path, self.relay_name)
-
- @memoized
</del><span class="cx"> def child_processes(self):
</span><span class="cx"> return int(self.get_option('child_processes'))
</span><span class="cx">
</span><span class="lines">@@ -182,19 +173,6 @@
</span><span class="cx">
</span><span class="cx"> return min(maximum_simulator_count_on_this_system, best_child_process_count_for_cpu)
</span><span class="cx">
</span><del>- def _check_relay(self):
- if not self._filesystem.exists(self.relay_path):
- _log.error("%s was not found at %s" % (self.relay_name, self.relay_path))
- return False
- return True
-
- def _check_port_build(self):
- if not self._root_was_set and self.get_option('build') and not self._build_relay():
- return False
- if not self._check_relay():
- return False
- return True
-
</del><span class="cx"> def _get_crash_log(self, name, pid, stdout, stderr, newer_than, time_fn=time.time, sleep_fn=time.sleep, wait_for_log=True):
</span><span class="cx"> time_fn = time_fn or time.time
</span><span class="cx"> sleep_fn = sleep_fn or time.sleep
</span><span class="lines">@@ -215,7 +193,7 @@
</span><span class="cx"> return self._get_crash_log(crashed_subprocess_name_and_pid[0], crashed_subprocess_name_and_pid[1], stdout,
</span><span class="cx"> '\n'.join(stderr_lines), newer_than, time_fn, sleep_fn, wait_for_log)
</span><span class="cx">
</span><del>- # LayoutTestRelay crashed
</del><ins>+ # App crashed
</ins><span class="cx"> _log.debug('looking for crash log for %s:%s' % (name, str(pid)))
</span><span class="cx"> crash_log = ''
</span><span class="cx"> crash_logs = CrashLogs(self.host)
</span><span class="lines">@@ -233,25 +211,6 @@
</span><span class="cx"> return stderr, None
</span><span class="cx"> return stderr, crash_log
</span><span class="cx">
</span><del>- def _build_relay(self):
- environment = self.host.copy_current_environment()
- environment.disable_gcc_smartquotes()
- env = environment.to_dictionary()
-
- try:
- # FIXME: We should be passing _arguments_for_configuration(), which respects build configuration and port,
- # instead of hardcoding --ios-simulator.
- self._run_script("build-layouttestrelay", args=["--ios-simulator"], env=env)
- except ScriptError, e:
- _log.error(e.message_with_output(output_limit=None))
- return False
- return True
-
- def _build_driver(self):
- built_tool = super(IOSSimulatorPort, self)._build_driver()
- built_relay = self._build_relay()
- return built_tool and built_relay
-
</del><span class="cx"> def _build_driver_flags(self):
</span><span class="cx"> archs = ['ARCHS=i386'] if self.architecture() == 'x86' else []
</span><span class="cx"> sdk = ['--sdk', 'iphonesimulator']
</span><span class="lines">@@ -264,9 +223,6 @@
</span><span class="cx"> configurations.append(TestConfiguration(version=self._version, architecture=architecture, build_type=build_type))
</span><span class="cx"> return configurations
</span><span class="cx">
</span><del>- def _driver_class(self):
- return driver.IOSSimulatorDriver
-
</del><span class="cx"> def default_baseline_search_path(self):
</span><span class="cx"> if self.get_option('webkit_test_runner'):
</span><span class="cx"> fallback_names = [self._wk2_port_name()] + [self.port_name] + ['wk2']
</span><span class="lines">@@ -280,9 +236,9 @@
</span><span class="cx">
</span><span class="cx"> def _create_simulators(self):
</span><span class="cx"> if (self.default_child_processes() < self.child_processes()):
</span><del>- _log.warn("You have specified very high value({0}) for --child-processes".format(self.child_processes()))
- _log.warn("maximum child-processes which can be supported on this system are: {0}".format(self.default_child_processes()))
- _log.warn("This is very likely to fail.")
</del><ins>+ _log.warn('You have specified very high value({0}) for --child-processes'.format(self.child_processes()))
+ _log.warn('maximum child-processes which can be supported on this system are: {0}'.format(self.default_child_processes()))
+ _log.warn('This is very likely to fail.')
</ins><span class="cx">
</span><span class="cx"> if self._using_dedicated_simulators():
</span><span class="cx"> self._createSimulatorApps()
</span><span class="lines">@@ -413,7 +369,7 @@
</span><span class="cx"> def _testing_device(self, number):
</span><span class="cx"> return Simulator.device_number(number)
</span><span class="cx">
</span><del>- # This is only exposed so that IOSSimulatorDriver can use it.
</del><ins>+ # FIXME: This is only exposed so that SimulatorProcess can use it.
</ins><span class="cx"> def device_id_for_worker_number(self, number):
</span><span class="cx"> if self._printing_cmd_line:
</span><span class="cx"> return '<dummy id>'
</span></span></pre></div>
<a id="trunkToolsScriptswebkitpyportios_unittestpy"></a>
<div class="modfile"><h4>Modified: trunk/Tools/Scripts/webkitpy/port/ios_unittest.py (211369 => 211370)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/Scripts/webkitpy/port/ios_unittest.py        2017-01-30 17:09:06 UTC (rev 211369)
+++ trunk/Tools/Scripts/webkitpy/port/ios_unittest.py        2017-01-30 17:31:47 UTC (rev 211370)
</span><span class="lines">@@ -70,7 +70,7 @@
</span><span class="cx"> port._run_script = run_script
</span><span class="cx"> self.assertEqual(port.architecture(), 'x86')
</span><span class="cx"> port._build_driver()
</span><del>- self.assertEqual(self.args, ['--ios-simulator'])
</del><ins>+ self.assertEqual(self.args, ['ARCHS=i386', '--sdk', 'iphonesimulator'])
</ins><span class="cx">
</span><span class="cx"> def test_64bit(self):
</span><span class="cx"> # Apple Mac port is 64-bit by default
</span><span class="lines">@@ -82,7 +82,7 @@
</span><span class="cx">
</span><span class="cx"> port._run_script = run_script
</span><span class="cx"> port._build_driver()
</span><del>- self.assertEqual(self.args, ['--ios-simulator'])
</del><ins>+ self.assertEqual(self.args, ['--sdk', 'iphonesimulator'])
</ins><span class="cx">
</span><span class="cx"> def test_sdk_name(self):
</span><span class="cx"> port = self.make_port()
</span></span></pre></div>
<a id="trunkToolsScriptswebkitpyportserver_processpy"></a>
<div class="modfile"><h4>Modified: trunk/Tools/Scripts/webkitpy/port/server_process.py (211369 => 211370)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/Scripts/webkitpy/port/server_process.py        2017-01-30 17:09:06 UTC (rev 211369)
+++ trunk/Tools/Scripts/webkitpy/port/server_process.py        2017-01-30 17:31:47 UTC (rev 211370)
</span><span class="lines">@@ -1,3 +1,4 @@
</span><ins>+# Copyright (C) 2017 Apple Inc. All rights reserved.
</ins><span class="cx"> # Copyright (C) 2010 Google Inc. All rights reserved.
</span><span class="cx"> #
</span><span class="cx"> # Redistribution and use in source and binary forms, with or without
</span><span class="lines">@@ -59,7 +60,7 @@
</span><span class="cx"> indefinitely. The class also handles transparently restarting processes
</span><span class="cx"> as necessary to keep issuing commands."""
</span><span class="cx">
</span><del>- def __init__(self, port_obj, name, cmd, env=None, universal_newlines=False, treat_no_data_as_crash=False):
</del><ins>+ def __init__(self, port_obj, name, cmd, env=None, universal_newlines=False, treat_no_data_as_crash=False, worker_number=None):
</ins><span class="cx"> self._port = port_obj
</span><span class="cx"> self._name = name # Should be the command name (e.g. DumpRenderTree, ImageDiff)
</span><span class="cx"> self._cmd = cmd
</span><span class="lines">@@ -103,6 +104,11 @@
</span><span class="cx"> def process_name(self):
</span><span class="cx"> return self._name
</span><span class="cx">
</span><ins>+ @staticmethod
+ def _set_file_nonblocking(file):
+ flags = fcntl.fcntl(file.fileno(), fcntl.F_GETFL)
+ fcntl.fcntl(file.fileno(), fcntl.F_SETFL, flags | os.O_NONBLOCK)
+
</ins><span class="cx"> def _start(self):
</span><span class="cx"> if self._proc:
</span><span class="cx"> raise ValueError("%s already running" % self._name)
</span><span class="lines">@@ -117,13 +123,9 @@
</span><span class="cx"> universal_newlines=self._universal_newlines)
</span><span class="cx"> self._pid = self._proc.pid
</span><span class="cx"> self._port.find_system_pid(self.name(), self._pid)
</span><del>- fd = self._proc.stdout.fileno()
</del><span class="cx"> if not self._use_win32_apis:
</span><del>- fl = fcntl.fcntl(fd, fcntl.F_GETFL)
- fcntl.fcntl(fd, fcntl.F_SETFL, fl | os.O_NONBLOCK)
- fd = self._proc.stderr.fileno()
- fl = fcntl.fcntl(fd, fcntl.F_GETFL)
- fcntl.fcntl(fd, fcntl.F_SETFL, fl | os.O_NONBLOCK)
</del><ins>+ self._set_file_nonblocking(self._proc.stdout)
+ self._set_file_nonblocking(self._proc.stderr)
</ins><span class="cx">
</span><span class="cx"> def _handle_possible_interrupt(self):
</span><span class="cx"> """This routine checks to see if the process crashed or exited
</span></span></pre></div>
<a id="trunkToolsScriptswebkitpyportserver_process_mockpy"></a>
<div class="modfile"><h4>Modified: trunk/Tools/Scripts/webkitpy/port/server_process_mock.py (211369 => 211370)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/Scripts/webkitpy/port/server_process_mock.py        2017-01-30 17:09:06 UTC (rev 211369)
+++ trunk/Tools/Scripts/webkitpy/port/server_process_mock.py        2017-01-30 17:31:47 UTC (rev 211370)
</span><span class="lines">@@ -28,7 +28,7 @@
</span><span class="cx">
</span><span class="cx">
</span><span class="cx"> class MockServerProcess(object):
</span><del>- def __init__(self, port_obj=None, name=None, cmd=None, env=None, universal_newlines=False, lines=None, crashed=False):
</del><ins>+ def __init__(self, port_obj=None, name=None, cmd=None, env=None, universal_newlines=False, lines=None, crashed=False, worker_number=None):
</ins><span class="cx"> self.timed_out = False
</span><span class="cx"> self.lines = lines or []
</span><span class="cx"> self.crashed = crashed
</span></span></pre></div>
<a id="trunkToolsScriptswebkitpyportsimulator_processpy"></a>
<div class="addfile"><h4>Added: trunk/Tools/Scripts/webkitpy/port/simulator_process.py (0 => 211370)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/Scripts/webkitpy/port/simulator_process.py         (rev 0)
+++ trunk/Tools/Scripts/webkitpy/port/simulator_process.py        2017-01-30 17:31:47 UTC (rev 211370)
</span><span class="lines">@@ -0,0 +1,134 @@
</span><ins>+# Copyright (C) 2017 Apple Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY APPLE INC. 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 INC. 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.
+
+
+import errno
+import os
+import signal
+import time
+
+from webkitpy.port.server_process import ServerProcess
+from webkitpy.xcode.simulator import Simulator
+
+
+class SimulatorProcess(ServerProcess):
+
+ class Popen(object):
+
+ def __init__(self, pid, stdin, stdout, stderr):
+ self.stdin = stdin
+ self.stdout = stdout
+ self.stderr = stderr
+ self.pid = pid
+ self.returncode = None
+
+ def poll(self):
+ if self.returncode:
+ return self.returncode
+ try:
+ os.kill(self.pid, 0)
+ except OSError, err:
+ assert err.errno == errno.ESRCH
+ self.returncode = 1
+ return self.returncode
+
+ def wait(self):
+ while not self.poll():
+ time.sleep(0.01) # In seconds
+ return self.returncode
+
+ def __init__(self, port_obj, name, cmd, env=None, universal_newlines=False, treat_no_data_as_crash=False, worker_number=None):
+ self._bundle_id = port_obj.app_identifier_from_bundle(cmd[0])
+ self._device = Simulator(port_obj.host).find_device_by_udid(port_obj.device_id_for_worker_number(worker_number))
+ if not self._device.install_app(cmd[0]):
+ raise RuntimeError('Failed to install app {} on simulator device {}'.format(cmd[0], self._device.udid))
+ env['IPC_IDENTIFIER'] = self._bundle_id + '-' + self._device.udid
+
+ # This location matches the location used by WebKitTestRunner and DumpRenderTree
+ # for the other side of these fifos.
+ file_location = '/tmp/' + env['IPC_IDENTIFIER']
+ self._in_path = file_location + '_IN'
+ self._out_path = file_location + '_OUT'
+ self._error_path = file_location + '_ERROR'
+
+ super(SimulatorProcess, self).__init__(port_obj, name, cmd, env, universal_newlines, treat_no_data_as_crash)
+
+ def _reset(self):
+ super(SimulatorProcess, self)._reset()
+
+ # Unlinks are needed on reset in the event that the Python code unexpectedly
+ # fails between _start() and kill(). This can be caused by a SIGKILL or a crash.
+ # This ensures that os.mkfifo() will not be obstructed by previous fifos.
+ # Other files will still cause os.mkfifo() to fail.
+ try:
+ os.unlink(self._in_path)
+ except:
+ pass
+ try:
+ os.unlink(self._out_path)
+ except:
+ pass
+ try:
+ os.unlink(self._error_path)
+ except:
+ pass
+
+ def _start(self):
+ if self._proc:
+ raise ValueError('{} already running'.format(self._name))
+ self._reset()
+
+ FIFO_PERMISSION_FLAGS = 0600 # Only owner can read and write
+ os.mkfifo(self._in_path, FIFO_PERMISSION_FLAGS)
+ os.mkfifo(self._out_path, FIFO_PERMISSION_FLAGS)
+ os.mkfifo(self._error_path, FIFO_PERMISSION_FLAGS)
+
+ stdout = os.fdopen(os.open(self._out_path, os.O_RDONLY | os.O_NONBLOCK), 'rb')
+ stderr = os.fdopen(os.open(self._error_path, os.O_RDONLY | os.O_NONBLOCK), 'rb')
+
+ self._pid = self._device.launch_app(self._bundle_id, self._cmd[1:], env=self._env)
+
+ def handler(signum, frame):
+ assert signum == signal.SIGALRM
+ raise Exception('Timed out waiting for process to open {}'.format(self._in_path))
+ signal.signal(signal.SIGALRM, handler)
+ signal.alarm(3) # In seconds
+
+ stdin = None
+ try:
+ stdin = open(self._in_path, 'w', 0) # Opening with no buffering, like popen
+ except:
+ # We set self._proc as _reset() and _kill() depend on it.
+ self._proc = SimulatorProcess.Popen(self._pid, stdin, stdout, stderr)
+ if self._proc.poll() is not None:
+ self._reset()
+ raise Exception('App {} crashed before stdin could be attached'.format(os.path.basename(self._cmd[0])))
+ self._kill()
+ self._reset()
+ raise
+ signal.alarm(0) # Cancel alarm
+
+ self._proc = SimulatorProcess.Popen(self._pid, stdin, stdout, stderr)
+
+ def _kill(self):
+ self._device.terminate_app(self._bundle_id)
+ super(SimulatorProcess, self)._kill()
</ins></span></pre></div>
<a id="trunkToolsScriptswebkitpyxcodesimulatorpy"></a>
<div class="modfile"><h4>Modified: trunk/Tools/Scripts/webkitpy/xcode/simulator.py (211369 => 211370)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/Scripts/webkitpy/xcode/simulator.py        2017-01-30 17:09:06 UTC (rev 211369)
+++ trunk/Tools/Scripts/webkitpy/xcode/simulator.py        2017-01-30 17:31:47 UTC (rev 211370)
</span><span class="lines">@@ -167,7 +167,7 @@
</span><span class="cx"> Represents a CoreSimulator device underneath a runtime
</span><span class="cx"> """
</span><span class="cx">
</span><del>- def __init__(self, name, udid, available, runtime):
</del><ins>+ def __init__(self, name, udid, available, runtime, host):
</ins><span class="cx"> """
</span><span class="cx"> :param name: The device name
</span><span class="cx"> :type name: str
</span><span class="lines">@@ -177,7 +177,10 @@
</span><span class="cx"> :type available: bool
</span><span class="cx"> :param runtime: The iOS Simulator runtime that hosts this device
</span><span class="cx"> :type runtime: Runtime
</span><ins>+ :param host: The host which can run command line commands
+ :type host: Host
</ins><span class="cx"> """
</span><ins>+ self._host = host
</ins><span class="cx"> self.name = name
</span><span class="cx"> self.udid = udid
</span><span class="cx"> self.available = available
</span><span class="lines">@@ -260,6 +263,31 @@
</span><span class="cx"> except subprocess.CalledProcessError:
</span><span class="cx"> raise RuntimeError('"xcrun simctl erase" failed: device state is {}'.format(Simulator.device_state(udid)))
</span><span class="cx">
</span><ins>+ def install_app(self, app_path):
+ return not self._host.executive.run_command(['xcrun', 'simctl', 'install', self.udid, app_path], return_exit_code=True)
+
+ def launch_app(self, bundle_id, args, env=None):
+ environment_to_use = {}
+ SIMCTL_ENV_PREFIX = 'SIMCTL_CHILD_'
+ for value in (env or {}):
+ if not value.startswith(SIMCTL_ENV_PREFIX):
+ environment_to_use[SIMCTL_ENV_PREFIX + value] = env[value]
+ else:
+ environment_to_use[value] = env[value]
+
+ output = self._host.executive.run_command(
+ ['xcrun', 'simctl', 'launch', self.udid, bundle_id] + args,
+ env=environment_to_use,
+ )
+
+ match = re.match(r'(?P<bundle>[^:]+): (?P<pid>\d+)\n', output)
+ if not match or match.group('bundle') != bundle_id:
+ raise RuntimeError('Failed to find process id for {}: {}'.format(bundle_id, output))
+ return int(match.group('pid'))
+
+ def terminate_app(self, bundle_id):
+ return not self._host.executive.run_command(['xcrun', 'simctl', 'terminate', self.udid, bundle_id], return_exit_code=True)
+
</ins><span class="cx"> def __eq__(self, other):
</span><span class="cx"> return self.udid == other.udid
</span><span class="cx">
</span><span class="lines">@@ -477,7 +505,8 @@
</span><span class="cx"> device = Device(name=device_match.group('name').rstrip(),
</span><span class="cx"> udid=device_match.group('udid'),
</span><span class="cx"> available=device_match.group('availability') is None,
</span><del>- runtime=current_runtime)
</del><ins>+ runtime=current_runtime,
+ host=self._host)
</ins><span class="cx"> current_runtime.devices.append(device)
</span><span class="cx">
</span><span class="cx"> def device_type(self, name=None, identifier=None):
</span></span></pre>
</div>
</div>
</body>
</html>