Added: trunk/Tools/Scripts/webkitpy/common/system/abstractexecutive.py (0 => 217801)
--- trunk/Tools/Scripts/webkitpy/common/system/abstractexecutive.py (rev 0)
+++ trunk/Tools/Scripts/webkitpy/common/system/abstractexecutive.py 2017-06-05 23:01:21 UTC (rev 217801)
@@ -0,0 +1,127 @@
+# 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 sys
+import time
+
+from webkitpy.common.system.filesystem import FileSystem
+
+
+class AbstractExecutive(object):
+
+ def run_and_throw_if_fail(self, args, quiet=False, decode_output=True, **kwargs):
+ raise NotImplementedError('subclasses must implement')
+
+ def cpu_count(self):
+ raise NotImplementedError('subclasses must implement')
+
+ @staticmethod
+ def interpreter_for_script(script_path, fs=None):
+ fs = fs or FileSystem()
+ lines = fs.read_text_file(script_path).splitlines()
+ if not len(lines):
+ return None
+ first_line = lines[0]
+ if not first_line.startswith('#!'):
+ return None
+ if first_line.find('python') > -1:
+ return sys.executable
+ if first_line.find('perl') > -1:
+ return 'perl'
+ if first_line.find('ruby') > -1:
+ return 'ruby'
+ return None
+
+ @staticmethod
+ def shell_command_for_script(script_path, fs=None):
+ fs = fs or FileSystem()
+ # Win32 does not support shebang. We need to detect the interpreter ourself.
+ if sys.platform.startswith('win'):
+ interpreter = AbstractExecutive.interpreter_for_script(script_path, fs)
+ if interpreter:
+ return [interpreter, script_path]
+ return [script_path]
+
+ def kill_process(self, pid):
+ raise NotImplementedError('subclasses must implement')
+
+ def check_running_pid(self, pid):
+ raise NotImplementedError('subclasses must implement')
+
+ def running_pids(self, process_name_filter=None):
+ raise NotImplementedError('subclasses must implement')
+
+ def wait_newest(self, process_name_filter=None):
+ if not process_name_filter:
+ process_name_filter = lambda process_name: True
+
+ running_pids = self.running_pids(process_name_filter)
+ if not running_pids:
+ return
+ pid = running_pids[-1]
+
+ while self.check_running_pid(pid):
+ time.sleep(0.25)
+
+ def wait_limited(self, pid, limit_in_seconds=None, check_frequency_in_seconds=None):
+ seconds_left = limit_in_seconds or 10
+ sleep_length = check_frequency_in_seconds or 1
+ while seconds_left > 0 and self.check_running_pid(pid):
+ seconds_left -= sleep_length
+ time.sleep(sleep_length)
+
+ def interrupt(self, pid):
+ raise NotImplementedError('subclasses must implement')
+
+ @staticmethod
+ def default_error_handler(error):
+ raise error
+
+ @staticmethod
+ def ignore_error(error):
+ pass
+
+ def _stringify_args(self, args):
+ return map(unicode, args)
+
+ def command_for_printing(self, args):
+ """Returns a print-ready string representing command args.
+ The string should be copy/paste ready for execution in a shell."""
+ args = self._stringify_args(args)
+ escaped_args = []
+ for arg in args:
+ if isinstance(arg, unicode):
+ # Escape any non-ascii characters for easy copy/paste
+ arg = arg.encode("unicode_escape")
+ # FIXME: Do we need to fix quotes here?
+ escaped_args.append(arg)
+ return " ".join(escaped_args)
+
+ def run_command(self, args, cwd=None, env=None, input=None, error_handler=None,
+ return_exit_code=False, return_stderr=True, decode_output=True):
+ raise NotImplementedError('subclasses must implement')
+
+ def popen(self, args, **kwargs):
+ raise NotImplementedError('subclasses must implement')
+
+ def run_in_parallel(self, command_lines_and_cwds, processes=None):
+ raise NotImplementedError('subclasses must implement')
Modified: trunk/Tools/Scripts/webkitpy/common/system/executive.py (217800 => 217801)
--- trunk/Tools/Scripts/webkitpy/common/system/executive.py 2017-06-05 22:41:42 UTC (rev 217800)
+++ trunk/Tools/Scripts/webkitpy/common/system/executive.py 2017-06-05 23:01:21 UTC (rev 217801)
@@ -37,8 +37,8 @@
import sys
import time
+from webkitpy.common.system.abstractexecutive import AbstractExecutive
from webkitpy.common.system.outputtee import Tee
-from webkitpy.common.system.filesystem import FileSystem
_log = logging.getLogger(__name__)
@@ -80,7 +80,7 @@
return os.path.basename(command_path)
-class Executive(object):
+class Executive(AbstractExecutive):
PIPE = subprocess.PIPE
STDOUT = subprocess.STDOUT
@@ -157,33 +157,6 @@
pass
return multiprocessing.cpu_count()
- @staticmethod
- def interpreter_for_script(script_path, fs=None):
- fs = fs or FileSystem()
- lines = fs.read_text_file(script_path).splitlines()
- if not len(lines):
- return None
- first_line = lines[0]
- if not first_line.startswith('#!'):
- return None
- if first_line.find('python') > -1:
- return sys.executable
- if first_line.find('perl') > -1:
- return 'perl'
- if first_line.find('ruby') > -1:
- return 'ruby'
- return None
-
- @staticmethod
- def shell_command_for_script(script_path, fs=None):
- fs = fs or FileSystem()
- # Win32 does not support shebang. We need to detect the interpreter ourself.
- if sys.platform.startswith('win'):
- interpreter = Executive.interpreter_for_script(script_path, fs)
- if interpreter:
- return [interpreter, script_path]
- return [script_path]
-
def kill_process(self, pid):
# Killing a process with a pid of 0 or a negative pid is a valid command, but
# will kill all processes in this process' group (if 0) or all non-system processes
@@ -323,25 +296,6 @@
return sorted(running_pids)
- def wait_newest(self, process_name_filter=None):
- if not process_name_filter:
- process_name_filter = lambda process_name: True
-
- running_pids = self.running_pids(process_name_filter)
- if not running_pids:
- return
- pid = running_pids[-1]
-
- while self.check_running_pid(pid):
- time.sleep(0.25)
-
- def wait_limited(self, pid, limit_in_seconds=None, check_frequency_in_seconds=None):
- seconds_left = limit_in_seconds or 10
- sleep_length = check_frequency_in_seconds or 1
- while seconds_left > 0 and self.check_running_pid(pid):
- seconds_left -= sleep_length
- time.sleep(sleep_length)
-
def _windows_image_name(self, process_name):
name, extension = os.path.splitext(process_name)
if not extension:
@@ -384,17 +338,6 @@
# We should log in exit_code == 1
self.run_command(command, error_handler=self.ignore_error)
- # 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
-
def _compute_stdin(self, input):
"""Returns (stdin, string_to_communicate)"""
# FIXME: We should be returning /dev/null for stdin
@@ -414,19 +357,6 @@
input = input.encode(self._child_process_encoding())
return (self.PIPE, input)
- def command_for_printing(self, args):
- """Returns a print-ready string representing command args.
- The string should be copy/paste ready for execution in a shell."""
- args = self._stringify_args(args)
- escaped_args = []
- for arg in args:
- if isinstance(arg, unicode):
- # Escape any non-ascii characters for easy copy/paste
- arg = arg.encode("unicode_escape")
- # FIXME: Do we need to fix quotes here?
- escaped_args.append(arg)
- return " ".join(escaped_args)
-
# FIXME: run_and_throw_if_fail should be merged into this method.
def run_command(self,
args,