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