1643ca7872b450ea4efacab6188849e5aac2ba161Steve Block# Copyright (c) 2009, Google Inc. All rights reserved. 2643ca7872b450ea4efacab6188849e5aac2ba161Steve Block# Copyright (c) 2009 Apple Inc. All rights reserved. 3d0825bca7fe65beaee391d30da42e937db621564Steve Block# 4643ca7872b450ea4efacab6188849e5aac2ba161Steve Block# Redistribution and use in source and binary forms, with or without 5643ca7872b450ea4efacab6188849e5aac2ba161Steve Block# modification, are permitted provided that the following conditions are 6643ca7872b450ea4efacab6188849e5aac2ba161Steve Block# met: 7d0825bca7fe65beaee391d30da42e937db621564Steve Block# 8643ca7872b450ea4efacab6188849e5aac2ba161Steve Block# * Redistributions of source code must retain the above copyright 9643ca7872b450ea4efacab6188849e5aac2ba161Steve Block# notice, this list of conditions and the following disclaimer. 10643ca7872b450ea4efacab6188849e5aac2ba161Steve Block# * Redistributions in binary form must reproduce the above 11643ca7872b450ea4efacab6188849e5aac2ba161Steve Block# copyright notice, this list of conditions and the following disclaimer 12643ca7872b450ea4efacab6188849e5aac2ba161Steve Block# in the documentation and/or other materials provided with the 13643ca7872b450ea4efacab6188849e5aac2ba161Steve Block# distribution. 14643ca7872b450ea4efacab6188849e5aac2ba161Steve Block# * Neither the name of Google Inc. nor the names of its 15643ca7872b450ea4efacab6188849e5aac2ba161Steve Block# contributors may be used to endorse or promote products derived from 16643ca7872b450ea4efacab6188849e5aac2ba161Steve Block# this software without specific prior written permission. 17d0825bca7fe65beaee391d30da42e937db621564Steve Block# 18643ca7872b450ea4efacab6188849e5aac2ba161Steve Block# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19643ca7872b450ea4efacab6188849e5aac2ba161Steve Block# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20643ca7872b450ea4efacab6188849e5aac2ba161Steve Block# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21643ca7872b450ea4efacab6188849e5aac2ba161Steve Block# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22643ca7872b450ea4efacab6188849e5aac2ba161Steve Block# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23643ca7872b450ea4efacab6188849e5aac2ba161Steve Block# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24643ca7872b450ea4efacab6188849e5aac2ba161Steve Block# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25643ca7872b450ea4efacab6188849e5aac2ba161Steve Block# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26643ca7872b450ea4efacab6188849e5aac2ba161Steve Block# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27643ca7872b450ea4efacab6188849e5aac2ba161Steve Block# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28643ca7872b450ea4efacab6188849e5aac2ba161Steve Block# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29643ca7872b450ea4efacab6188849e5aac2ba161Steve Block 30dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Blocktry: 31dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block # This API exists only in Python 2.6 and higher. :( 32dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block import multiprocessing 33dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Blockexcept ImportError: 34dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block multiprocessing = None 35dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 3628040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhuimport ctypes 376c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsenimport errno 386c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsenimport logging 39643ca7872b450ea4efacab6188849e5aac2ba161Steve Blockimport os 40dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Blockimport platform 41643ca7872b450ea4efacab6188849e5aac2ba161Steve Blockimport StringIO 42dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Blockimport signal 43643ca7872b450ea4efacab6188849e5aac2ba161Steve Blockimport subprocess 44643ca7872b450ea4efacab6188849e5aac2ba161Steve Blockimport sys 45e78cbe89e6f337f2f1fe40315be88f742b547151Steve Blockimport time 46643ca7872b450ea4efacab6188849e5aac2ba161Steve Block 47dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Blockfrom webkitpy.common.system.deprecated_logging import tee 482daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdochfrom webkitpy.common.system.filesystem import FileSystem 4928040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhufrom webkitpy.python24 import versioning 50643ca7872b450ea4efacab6188849e5aac2ba161Steve Block 51643ca7872b450ea4efacab6188849e5aac2ba161Steve Block 526c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen_log = logging.getLogger("webkitpy.common.system") 536c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen 546c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen 55643ca7872b450ea4efacab6188849e5aac2ba161Steve Blockclass ScriptError(Exception): 56d0825bca7fe65beaee391d30da42e937db621564Steve Block 5765f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch # This is a custom List.__str__ implementation to allow size limiting. 5865f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch def _string_from_args(self, args, limit=100): 5965f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch args_string = unicode(args) 6065f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch # We could make this much fancier, but for now this is OK. 6165f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch if len(args_string) > limit: 6265f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch return args_string[:limit - 3] + "..." 6365f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch return args_string 6465f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch 65d0825bca7fe65beaee391d30da42e937db621564Steve Block def __init__(self, 66d0825bca7fe65beaee391d30da42e937db621564Steve Block message=None, 67d0825bca7fe65beaee391d30da42e937db621564Steve Block script_args=None, 68d0825bca7fe65beaee391d30da42e937db621564Steve Block exit_code=None, 69d0825bca7fe65beaee391d30da42e937db621564Steve Block output=None, 70d0825bca7fe65beaee391d30da42e937db621564Steve Block cwd=None): 71643ca7872b450ea4efacab6188849e5aac2ba161Steve Block if not message: 7265f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch message = 'Failed to run "%s"' % self._string_from_args(script_args) 73643ca7872b450ea4efacab6188849e5aac2ba161Steve Block if exit_code: 74643ca7872b450ea4efacab6188849e5aac2ba161Steve Block message += " exit_code: %d" % exit_code 75643ca7872b450ea4efacab6188849e5aac2ba161Steve Block if cwd: 76643ca7872b450ea4efacab6188849e5aac2ba161Steve Block message += " cwd: %s" % cwd 77643ca7872b450ea4efacab6188849e5aac2ba161Steve Block 78643ca7872b450ea4efacab6188849e5aac2ba161Steve Block Exception.__init__(self, message) 79643ca7872b450ea4efacab6188849e5aac2ba161Steve Block self.script_args = script_args # 'args' is already used by Exception 80643ca7872b450ea4efacab6188849e5aac2ba161Steve Block self.exit_code = exit_code 81643ca7872b450ea4efacab6188849e5aac2ba161Steve Block self.output = output 82643ca7872b450ea4efacab6188849e5aac2ba161Steve Block self.cwd = cwd 83643ca7872b450ea4efacab6188849e5aac2ba161Steve Block 84643ca7872b450ea4efacab6188849e5aac2ba161Steve Block def message_with_output(self, output_limit=500): 85643ca7872b450ea4efacab6188849e5aac2ba161Steve Block if self.output: 86643ca7872b450ea4efacab6188849e5aac2ba161Steve Block if output_limit and len(self.output) > output_limit: 8765f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch return u"%s\n\nLast %s characters of output:\n%s" % \ 88d0825bca7fe65beaee391d30da42e937db621564Steve Block (self, output_limit, self.output[-output_limit:]) 8965f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch return u"%s\n\n%s" % (self, self.output) 90e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block return unicode(self) 91643ca7872b450ea4efacab6188849e5aac2ba161Steve Block 92d0825bca7fe65beaee391d30da42e937db621564Steve Block def command_name(self): 93d0825bca7fe65beaee391d30da42e937db621564Steve Block command_path = self.script_args 94d0825bca7fe65beaee391d30da42e937db621564Steve Block if type(command_path) is list: 95d0825bca7fe65beaee391d30da42e937db621564Steve Block command_path = command_path[0] 96d0825bca7fe65beaee391d30da42e937db621564Steve Block return os.path.basename(command_path) 97d0825bca7fe65beaee391d30da42e937db621564Steve Block 98643ca7872b450ea4efacab6188849e5aac2ba161Steve Block 99643ca7872b450ea4efacab6188849e5aac2ba161Steve Blockdef run_command(*args, **kwargs): 100d0825bca7fe65beaee391d30da42e937db621564Steve Block # FIXME: This should not be a global static. 101d0825bca7fe65beaee391d30da42e937db621564Steve Block # New code should use Executive.run_command directly instead 102643ca7872b450ea4efacab6188849e5aac2ba161Steve Block return Executive().run_command(*args, **kwargs) 103643ca7872b450ea4efacab6188849e5aac2ba161Steve Block 104643ca7872b450ea4efacab6188849e5aac2ba161Steve Block 105643ca7872b450ea4efacab6188849e5aac2ba161Steve Blockclass Executive(object): 106d0825bca7fe65beaee391d30da42e937db621564Steve Block 10721939df44de1705786c545cd1bf519d47250322dBen Murdoch def _should_close_fds(self): 10821939df44de1705786c545cd1bf519d47250322dBen Murdoch # We need to pass close_fds=True to work around Python bug #2320 10921939df44de1705786c545cd1bf519d47250322dBen Murdoch # (otherwise we can hang when we kill DumpRenderTree when we are running 11021939df44de1705786c545cd1bf519d47250322dBen Murdoch # multiple threads). See http://bugs.python.org/issue2320 . 11121939df44de1705786c545cd1bf519d47250322dBen Murdoch # Note that close_fds isn't supported on Windows, but this bug only 11221939df44de1705786c545cd1bf519d47250322dBen Murdoch # shows up on Mac and Linux. 11321939df44de1705786c545cd1bf519d47250322dBen Murdoch return sys.platform not in ('win32', 'cygwin') 11421939df44de1705786c545cd1bf519d47250322dBen Murdoch 115643ca7872b450ea4efacab6188849e5aac2ba161Steve Block def _run_command_with_teed_output(self, args, teed_output): 11621939df44de1705786c545cd1bf519d47250322dBen Murdoch args = map(unicode, args) # Popen will throw an exception if args are non-strings (like int()) 11728040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu args = map(self._encode_argument_if_needed, args) 11828040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu 119d0825bca7fe65beaee391d30da42e937db621564Steve Block child_process = subprocess.Popen(args, 120d0825bca7fe65beaee391d30da42e937db621564Steve Block stdout=subprocess.PIPE, 12121939df44de1705786c545cd1bf519d47250322dBen Murdoch stderr=subprocess.STDOUT, 12221939df44de1705786c545cd1bf519d47250322dBen Murdoch close_fds=self._should_close_fds()) 123643ca7872b450ea4efacab6188849e5aac2ba161Steve Block 124d0825bca7fe65beaee391d30da42e937db621564Steve Block # Use our own custom wait loop because Popen ignores a tee'd 125d0825bca7fe65beaee391d30da42e937db621564Steve Block # stderr/stdout. 126643ca7872b450ea4efacab6188849e5aac2ba161Steve Block # FIXME: This could be improved not to flatten output to stdout. 127643ca7872b450ea4efacab6188849e5aac2ba161Steve Block while True: 128643ca7872b450ea4efacab6188849e5aac2ba161Steve Block output_line = child_process.stdout.readline() 129643ca7872b450ea4efacab6188849e5aac2ba161Steve Block if output_line == "" and child_process.poll() != None: 13021939df44de1705786c545cd1bf519d47250322dBen Murdoch # poll() is not threadsafe and can throw OSError due to: 13121939df44de1705786c545cd1bf519d47250322dBen Murdoch # http://bugs.python.org/issue1731717 132643ca7872b450ea4efacab6188849e5aac2ba161Steve Block return child_process.poll() 13321939df44de1705786c545cd1bf519d47250322dBen Murdoch # We assume that the child process wrote to us in utf-8, 13421939df44de1705786c545cd1bf519d47250322dBen Murdoch # so no re-encoding is necessary before writing here. 135643ca7872b450ea4efacab6188849e5aac2ba161Steve Block teed_output.write(output_line) 136643ca7872b450ea4efacab6188849e5aac2ba161Steve Block 13721939df44de1705786c545cd1bf519d47250322dBen Murdoch # FIXME: Remove this deprecated method and move callers to run_command. 13821939df44de1705786c545cd1bf519d47250322dBen Murdoch # FIXME: This method is a hack to allow running command which both 13921939df44de1705786c545cd1bf519d47250322dBen Murdoch # capture their output and print out to stdin. Useful for things 14021939df44de1705786c545cd1bf519d47250322dBen Murdoch # like "build-webkit" where we want to display to the user that we're building 14121939df44de1705786c545cd1bf519d47250322dBen Murdoch # but still have the output to stuff into a log file. 14221939df44de1705786c545cd1bf519d47250322dBen Murdoch def run_and_throw_if_fail(self, args, quiet=False, decode_output=True): 143643ca7872b450ea4efacab6188849e5aac2ba161Steve Block # Cache the child's output locally so it can be used for error reports. 144643ca7872b450ea4efacab6188849e5aac2ba161Steve Block child_out_file = StringIO.StringIO() 145dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block tee_stdout = sys.stdout 146643ca7872b450ea4efacab6188849e5aac2ba161Steve Block if quiet: 14721939df44de1705786c545cd1bf519d47250322dBen Murdoch dev_null = open(os.devnull, "w") # FIXME: Does this need an encoding? 148dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block tee_stdout = dev_null 149dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block child_stdout = tee(child_out_file, tee_stdout) 150643ca7872b450ea4efacab6188849e5aac2ba161Steve Block exit_code = self._run_command_with_teed_output(args, child_stdout) 151643ca7872b450ea4efacab6188849e5aac2ba161Steve Block if quiet: 152643ca7872b450ea4efacab6188849e5aac2ba161Steve Block dev_null.close() 153643ca7872b450ea4efacab6188849e5aac2ba161Steve Block 154643ca7872b450ea4efacab6188849e5aac2ba161Steve Block child_output = child_out_file.getvalue() 155643ca7872b450ea4efacab6188849e5aac2ba161Steve Block child_out_file.close() 156643ca7872b450ea4efacab6188849e5aac2ba161Steve Block 15721939df44de1705786c545cd1bf519d47250322dBen Murdoch if decode_output: 15828040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu child_output = child_output.decode(self._child_process_encoding()) 15921939df44de1705786c545cd1bf519d47250322dBen Murdoch 160643ca7872b450ea4efacab6188849e5aac2ba161Steve Block if exit_code: 161d0825bca7fe65beaee391d30da42e937db621564Steve Block raise ScriptError(script_args=args, 162d0825bca7fe65beaee391d30da42e937db621564Steve Block exit_code=exit_code, 163d0825bca7fe65beaee391d30da42e937db621564Steve Block output=child_output) 164dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block return child_output 165d0825bca7fe65beaee391d30da42e937db621564Steve Block 166dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block def cpu_count(self): 167dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block if multiprocessing: 168d0825bca7fe65beaee391d30da42e937db621564Steve Block return multiprocessing.cpu_count() 169dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block # Darn. We don't have the multiprocessing package. 170dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block system_name = platform.system() 171dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block if system_name == "Darwin": 172dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block return int(self.run_command(["sysctl", "-n", "hw.ncpu"])) 173dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block elif system_name == "Windows": 174dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block return int(os.environ.get('NUMBER_OF_PROCESSORS', 1)) 175dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block elif system_name == "Linux": 176dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block num_cores = os.sysconf("SC_NPROCESSORS_ONLN") 177dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block if isinstance(num_cores, int) and num_cores > 0: 178dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block return num_cores 179dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block # This quantity is a lie but probably a reasonable guess for modern 180dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block # machines. 181dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block return 2 182dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 1832daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch @staticmethod 1842daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch def interpreter_for_script(script_path, fs=FileSystem()): 1852daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch lines = fs.read_text_file(script_path).splitlines() 1862daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch if not len(lines): 1872daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch return None 1882daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch first_line = lines[0] 1892daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch if not first_line.startswith('#!'): 1902daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch return None 1912daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch if first_line.find('python') > -1: 1922daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch return sys.executable 1932daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch if first_line.find('perl') > -1: 1942daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch return 'perl' 1952daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch if first_line.find('ruby') > -1: 1962daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch return 'ruby' 1972daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch return None 1982daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch 199dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block def kill_process(self, pid): 20021939df44de1705786c545cd1bf519d47250322dBen Murdoch """Attempts to kill the given pid. 20121939df44de1705786c545cd1bf519d47250322dBen Murdoch Will fail silently if pid does not exist or insufficient permisssions.""" 2026c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen if sys.platform == "win32": 2036c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen # We only use taskkill.exe on windows (not cygwin) because subprocess.pid 2046c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen # is a CYGWIN pid and taskkill.exe expects a windows pid. 2056c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen # Thankfully os.kill on CYGWIN handles either pid type. 2066c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen command = ["taskkill.exe", "/f", "/pid", pid] 2076c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen # taskkill will exit 128 if the process is not found. We should log. 20821939df44de1705786c545cd1bf519d47250322dBen Murdoch self.run_command(command, error_handler=self.ignore_error) 209dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block return 2106c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen 2116c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen # According to http://docs.python.org/library/os.html 2126c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen # os.kill isn't available on Windows. python 2.5.5 os.kill appears 2136c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen # to work in cygwin, however it occasionally raises EAGAIN. 214e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke retries_left = 10 if sys.platform == "cygwin" else 1 2156c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen while retries_left > 0: 2166c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen try: 2176c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen retries_left -= 1 2186c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen os.kill(pid, signal.SIGKILL) 2196c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen except OSError, e: 2206c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen if e.errno == errno.EAGAIN: 2216c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen if retries_left <= 0: 2226c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen _log.warn("Failed to kill pid %s. Too many EAGAIN errors." % pid) 2236c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen continue 2246c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen if e.errno == errno.ESRCH: # The process does not exist. 2256c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen _log.warn("Called kill_process with a non-existant pid %s" % pid) 2266c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen return 2276c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen raise 2286c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen 2296b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner def _win32_check_running_pid(self, pid): 23028040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu 23128040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu class PROCESSENTRY32(ctypes.Structure): 23228040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu _fields_ = [("dwSize", ctypes.c_ulong), 23328040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu ("cntUsage", ctypes.c_ulong), 23428040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu ("th32ProcessID", ctypes.c_ulong), 23528040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu ("th32DefaultHeapID", ctypes.c_ulong), 23628040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu ("th32ModuleID", ctypes.c_ulong), 23728040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu ("cntThreads", ctypes.c_ulong), 23828040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu ("th32ParentProcessID", ctypes.c_ulong), 23928040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu ("pcPriClassBase", ctypes.c_ulong), 24028040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu ("dwFlags", ctypes.c_ulong), 24128040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu ("szExeFile", ctypes.c_char * 260)] 24228040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu 24328040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu CreateToolhelp32Snapshot = ctypes.windll.kernel32.CreateToolhelp32Snapshot 24428040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu Process32First = ctypes.windll.kernel32.Process32First 24528040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu Process32Next = ctypes.windll.kernel32.Process32Next 24628040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu CloseHandle = ctypes.windll.kernel32.CloseHandle 24728040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu TH32CS_SNAPPROCESS = 0x00000002 # win32 magic number 24828040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0) 24928040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu pe32 = PROCESSENTRY32() 25028040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu pe32.dwSize = ctypes.sizeof(PROCESSENTRY32) 25128040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu result = False 25228040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu if not Process32First(hProcessSnap, ctypes.byref(pe32)): 25328040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu _log.debug("Failed getting first process.") 25428040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu CloseHandle(hProcessSnap) 25528040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu return result 25628040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu while True: 25728040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu if pe32.th32ProcessID == pid: 25828040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu result = True 25928040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu break 26028040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu if not Process32Next(hProcessSnap, ctypes.byref(pe32)): 26128040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu break 26228040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu CloseHandle(hProcessSnap) 26328040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu return result 26428040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu 26528040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu def check_running_pid(self, pid): 26628040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu """Return True if pid is alive, otherwise return False.""" 26728040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu if sys.platform in ('darwin', 'linux2', 'cygwin'): 26828040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu try: 26928040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu os.kill(pid, 0) 27028040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu return True 27128040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu except OSError: 27228040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu return False 27328040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu elif sys.platform == 'win32': 2746b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner return self._win32_check_running_pid(pid) 27528040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu 27628040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu assert(False) 27728040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu 2786c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen def _windows_image_name(self, process_name): 2796c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen name, extension = os.path.splitext(process_name) 2806c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen if not extension: 2816c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen # taskkill expects processes to end in .exe 2826c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen # If necessary we could add a flag to disable appending .exe. 2836c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen process_name = "%s.exe" % name 2846c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen return process_name 28521939df44de1705786c545cd1bf519d47250322dBen Murdoch 28621939df44de1705786c545cd1bf519d47250322dBen Murdoch def kill_all(self, process_name): 28721939df44de1705786c545cd1bf519d47250322dBen Murdoch """Attempts to kill processes matching process_name. 28821939df44de1705786c545cd1bf519d47250322dBen Murdoch Will fail silently if no process are found.""" 2896c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen if sys.platform in ("win32", "cygwin"): 2906c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen image_name = self._windows_image_name(process_name) 2916c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen command = ["taskkill.exe", "/f", "/im", image_name] 2926c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen # taskkill will exit 128 if the process is not found. We should log. 29321939df44de1705786c545cd1bf519d47250322dBen Murdoch self.run_command(command, error_handler=self.ignore_error) 29421939df44de1705786c545cd1bf519d47250322dBen Murdoch return 29521939df44de1705786c545cd1bf519d47250322dBen Murdoch 29621939df44de1705786c545cd1bf519d47250322dBen Murdoch # FIXME: This is inconsistent that kill_all uses TERM and kill_process 29721939df44de1705786c545cd1bf519d47250322dBen Murdoch # uses KILL. Windows is always using /f (which seems like -KILL). 29821939df44de1705786c545cd1bf519d47250322dBen Murdoch # We should pick one mode, or add support for switching between them. 29921939df44de1705786c545cd1bf519d47250322dBen Murdoch # Note: Mac OS X 10.6 requires -SIGNALNAME before -u USER 30021939df44de1705786c545cd1bf519d47250322dBen Murdoch command = ["killall", "-TERM", "-u", os.getenv("USER"), process_name] 3016c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen # killall returns 1 if no process can be found and 2 on command error. 3026c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen # FIXME: We should pass a custom error_handler to allow only exit_code 1. 3036c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen # We should log in exit_code == 1 30421939df44de1705786c545cd1bf519d47250322dBen Murdoch self.run_command(command, error_handler=self.ignore_error) 305d0825bca7fe65beaee391d30da42e937db621564Steve Block 306d0825bca7fe65beaee391d30da42e937db621564Steve Block # Error handlers do not need to be static methods once all callers are 307d0825bca7fe65beaee391d30da42e937db621564Steve Block # updated to use an Executive object. 308643ca7872b450ea4efacab6188849e5aac2ba161Steve Block 309643ca7872b450ea4efacab6188849e5aac2ba161Steve Block @staticmethod 310643ca7872b450ea4efacab6188849e5aac2ba161Steve Block def default_error_handler(error): 311643ca7872b450ea4efacab6188849e5aac2ba161Steve Block raise error 312643ca7872b450ea4efacab6188849e5aac2ba161Steve Block 313643ca7872b450ea4efacab6188849e5aac2ba161Steve Block @staticmethod 314643ca7872b450ea4efacab6188849e5aac2ba161Steve Block def ignore_error(error): 315643ca7872b450ea4efacab6188849e5aac2ba161Steve Block pass 316643ca7872b450ea4efacab6188849e5aac2ba161Steve Block 31721939df44de1705786c545cd1bf519d47250322dBen Murdoch def _compute_stdin(self, input): 31821939df44de1705786c545cd1bf519d47250322dBen Murdoch """Returns (stdin, string_to_communicate)""" 31921939df44de1705786c545cd1bf519d47250322dBen Murdoch # FIXME: We should be returning /dev/null for stdin 32021939df44de1705786c545cd1bf519d47250322dBen Murdoch # or closing stdin after process creation to prevent 32121939df44de1705786c545cd1bf519d47250322dBen Murdoch # child processes from getting input from the user. 32221939df44de1705786c545cd1bf519d47250322dBen Murdoch if not input: 32321939df44de1705786c545cd1bf519d47250322dBen Murdoch return (None, None) 32421939df44de1705786c545cd1bf519d47250322dBen Murdoch if hasattr(input, "read"): # Check if the input is a file. 32521939df44de1705786c545cd1bf519d47250322dBen Murdoch return (input, None) # Assume the file is in the right encoding. 32621939df44de1705786c545cd1bf519d47250322dBen Murdoch 32721939df44de1705786c545cd1bf519d47250322dBen Murdoch # Popen in Python 2.5 and before does not automatically encode unicode objects. 32821939df44de1705786c545cd1bf519d47250322dBen Murdoch # http://bugs.python.org/issue5290 32921939df44de1705786c545cd1bf519d47250322dBen Murdoch # See https://bugs.webkit.org/show_bug.cgi?id=37528 33021939df44de1705786c545cd1bf519d47250322dBen Murdoch # for an example of a regresion caused by passing a unicode string directly. 33121939df44de1705786c545cd1bf519d47250322dBen Murdoch # FIXME: We may need to encode differently on different platforms. 33221939df44de1705786c545cd1bf519d47250322dBen Murdoch if isinstance(input, unicode): 33328040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu input = input.encode(self._child_process_encoding()) 33421939df44de1705786c545cd1bf519d47250322dBen Murdoch return (subprocess.PIPE, input) 335d0825bca7fe65beaee391d30da42e937db621564Steve Block 336e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block def _command_for_printing(self, args): 337e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block """Returns a print-ready string representing command args. 338e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block The string should be copy/paste ready for execution in a shell.""" 339e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block escaped_args = [] 340e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block for arg in args: 341e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block if isinstance(arg, unicode): 342e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block # Escape any non-ascii characters for easy copy/paste 343e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block arg = arg.encode("unicode_escape") 344e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block # FIXME: Do we need to fix quotes here? 345e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block escaped_args.append(arg) 346e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block return " ".join(escaped_args) 347e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block 34821939df44de1705786c545cd1bf519d47250322dBen Murdoch # FIXME: run_and_throw_if_fail should be merged into this method. 349d0825bca7fe65beaee391d30da42e937db621564Steve Block def run_command(self, 350d0825bca7fe65beaee391d30da42e937db621564Steve Block args, 351d0825bca7fe65beaee391d30da42e937db621564Steve Block cwd=None, 352d0825bca7fe65beaee391d30da42e937db621564Steve Block input=None, 353d0825bca7fe65beaee391d30da42e937db621564Steve Block error_handler=None, 354d0825bca7fe65beaee391d30da42e937db621564Steve Block return_exit_code=False, 35521939df44de1705786c545cd1bf519d47250322dBen Murdoch return_stderr=True, 35621939df44de1705786c545cd1bf519d47250322dBen Murdoch decode_output=True): 35721939df44de1705786c545cd1bf519d47250322dBen Murdoch """Popen wrapper for convenience and to work around python bugs.""" 358e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block assert(isinstance(args, list) or isinstance(args, tuple)) 359e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block start_time = time.time() 36021939df44de1705786c545cd1bf519d47250322dBen Murdoch args = map(unicode, args) # Popen will throw an exception if args are non-strings (like int()) 36128040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu args = map(self._encode_argument_if_needed, args) 36228040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu 36321939df44de1705786c545cd1bf519d47250322dBen Murdoch stdin, string_to_communicate = self._compute_stdin(input) 36421939df44de1705786c545cd1bf519d47250322dBen Murdoch stderr = subprocess.STDOUT if return_stderr else None 365d0825bca7fe65beaee391d30da42e937db621564Steve Block 366d0825bca7fe65beaee391d30da42e937db621564Steve Block process = subprocess.Popen(args, 367d0825bca7fe65beaee391d30da42e937db621564Steve Block stdin=stdin, 368d0825bca7fe65beaee391d30da42e937db621564Steve Block stdout=subprocess.PIPE, 369d0825bca7fe65beaee391d30da42e937db621564Steve Block stderr=stderr, 37021939df44de1705786c545cd1bf519d47250322dBen Murdoch cwd=cwd, 37121939df44de1705786c545cd1bf519d47250322dBen Murdoch close_fds=self._should_close_fds()) 372643ca7872b450ea4efacab6188849e5aac2ba161Steve Block output = process.communicate(string_to_communicate)[0] 37328040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu 37421939df44de1705786c545cd1bf519d47250322dBen Murdoch # run_command automatically decodes to unicode() unless explicitly told not to. 37521939df44de1705786c545cd1bf519d47250322dBen Murdoch if decode_output: 37628040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu output = output.decode(self._child_process_encoding()) 37728040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu 37821939df44de1705786c545cd1bf519d47250322dBen Murdoch # wait() is not threadsafe and can throw OSError due to: 37921939df44de1705786c545cd1bf519d47250322dBen Murdoch # http://bugs.python.org/issue1731717 380643ca7872b450ea4efacab6188849e5aac2ba161Steve Block exit_code = process.wait() 381dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 382e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block _log.debug('"%s" took %.2fs' % (self._command_for_printing(args), time.time() - start_time)) 383e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block 384dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block if return_exit_code: 385dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block return exit_code 386dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 387643ca7872b450ea4efacab6188849e5aac2ba161Steve Block if exit_code: 388d0825bca7fe65beaee391d30da42e937db621564Steve Block script_error = ScriptError(script_args=args, 389d0825bca7fe65beaee391d30da42e937db621564Steve Block exit_code=exit_code, 390d0825bca7fe65beaee391d30da42e937db621564Steve Block output=output, 391d0825bca7fe65beaee391d30da42e937db621564Steve Block cwd=cwd) 392643ca7872b450ea4efacab6188849e5aac2ba161Steve Block (error_handler or self.default_error_handler)(script_error) 393643ca7872b450ea4efacab6188849e5aac2ba161Steve Block return output 39428040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu 39528040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu def _child_process_encoding(self): 39628040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu # Win32 Python 2.x uses CreateProcessA rather than CreateProcessW 39728040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu # to launch subprocesses, so we have to encode arguments using the 39828040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu # current code page. 39928040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu if sys.platform == 'win32' and versioning.compare_version(sys, '3.0')[0] < 0: 40028040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu return 'mbcs' 40128040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu # All other platforms use UTF-8. 40228040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu # FIXME: Using UTF-8 on Cygwin will confuse Windows-native commands 40328040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu # which will expect arguments to be encoded using the current code 40428040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu # page. 40528040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu return 'utf-8' 40628040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu 40728040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu def _should_encode_child_process_arguments(self): 40828040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu # Cygwin's Python's os.execv doesn't support unicode command 40928040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu # arguments, and neither does Cygwin's execv itself. 41028040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu if sys.platform == 'cygwin': 41128040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu return True 41228040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu 41328040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu # Win32 Python 2.x uses CreateProcessA rather than CreateProcessW 41428040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu # to launch subprocesses, so we have to encode arguments using the 41528040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu # current code page. 41628040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu if sys.platform == 'win32' and versioning.compare_version(sys, '3.0')[0] < 0: 41728040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu return True 41828040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu 41928040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu return False 42028040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu 42128040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu def _encode_argument_if_needed(self, argument): 42228040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu if not self._should_encode_child_process_arguments(): 42328040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu return argument 42428040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu return argument.encode(self._child_process_encoding()) 425