172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#!/usr/bin/env python
2c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott# Copyright (C) 2010 Google Inc. All rights reserved.
3c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#
4c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott# Redistribution and use in source and binary forms, with or without
5c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott# modification, are permitted provided that the following conditions are
6c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott# met:
7c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#
8c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#     * Redistributions of source code must retain the above copyright
9c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott# notice, this list of conditions and the following disclaimer.
10c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#     * Redistributions in binary form must reproduce the above
11ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen# copyright notice, this list of conditions and the following disclaimer
123345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick# in the documentation and/or other materials provided with the
13ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen# distribution.
14c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#     * Neither the name of Google Inc. nor the names of its
15c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott# contributors may be used to endorse or promote products derived from
16c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott# this software without specific prior written permission.
17c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#
18c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
30c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott"""Chromium Mac implementation of the Port interface."""
31c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
32c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottimport logging
33c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottimport os
34c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottimport signal
35c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
36c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottfrom webkitpy.layout_tests.port import mac
37c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottfrom webkitpy.layout_tests.port import chromium
38c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
39c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottfrom webkitpy.common.system.executive import Executive
40c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
41c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott_log = logging.getLogger("webkitpy.layout_tests.port.chromium_mac")
42c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
43c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
44c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottclass ChromiumMacPort(chromium.ChromiumPort):
45c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    """Chromium Mac implementation of the Port class."""
46c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    SUPPORTED_OS_VERSIONS = ('leopard', 'snowleopard', 'future')
47c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
48c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    FALLBACK_PATHS = {
49c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        'leopard': [
50c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott            'chromium-mac-leopard',
51c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott            'chromium-mac',
52c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott            'chromium',
53c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott            'mac-leopard',
54c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott            'mac-snowleopard',
55c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott            'mac',
56ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        ],
57ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        'snowleopard': [
58ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen            'chromium-mac',
59ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen            'chromium',
60ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen            'mac-snowleopard',
61ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen            'mac',
62ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        ],
63ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        'future': [
64ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen            'chromium-mac',
65ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen            'chromium',
66ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen            'mac',
67c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        ],
68c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    }
69c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
7072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    def __init__(self, port_name=None, os_version_string=None, **kwargs):
7172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        # We're a little generic here because this code is reused by the
72c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        # 'google-chrome' port as well as the 'mock-' and 'dryrun-' ports.
73c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        port_name = port_name or 'chromium-mac'
74c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        chromium.ChromiumPort.__init__(self, port_name=port_name, **kwargs)
75c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        if port_name.endswith('-mac'):
76c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott            self._version = mac.os_version(os_version_string, self.SUPPORTED_OS_VERSIONS)
77c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott            self._name = port_name + '-' + self._version
78c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        else:
79c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott            self._version = port_name[port_name.index('-mac-') + 5:]
80c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott            assert self._version in self.SUPPORTED_OS_VERSIONS
81c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        self._operating_system = 'mac'
82c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
83c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    def baseline_path(self):
84c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        if self.version() in ('snowleopard', 'future'):
85c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott            # We treat Snow Leopard as the newest version of mac,
86c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott            # so it gets the base dir.
87c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott            return self._webkit_baseline_path('chromium-mac')
88c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        return self._webkit_baseline_path(self.name())
89c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
90c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    def baseline_search_path(self):
91c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        return map(self._webkit_baseline_path, self.FALLBACK_PATHS[self._version])
92c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
93c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    def check_build(self, needs_http):
94c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        result = chromium.ChromiumPort.check_build(self, needs_http)
95ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        result = self._check_wdiff_install() and result
96c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        if not result:
97c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott            _log.error('For complete Mac build requirements, please see:')
98c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott            _log.error('')
99ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen            _log.error('    http://code.google.com/p/chromium/wiki/'
100ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                       'MacBuildInstructions')
101ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        return result
102ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
103ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    def default_child_processes(self):
104ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        if not self._multiprocessing_is_available:
105c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott            # Running multiple threads in Mac Python is unstable (See
106c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott            # https://bugs.webkit.org/show_bug.cgi?id=38553 for more info).
107c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott            return 1
108c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        return chromium.ChromiumPort.default_child_processes(self)
109
110    def driver_name(self):
111        return "DumpRenderTree"
112
113    #
114    # PROTECTED METHODS
115    #
116
117    def _build_path(self, *comps):
118        if self.get_option('build_directory'):
119            return self._filesystem.join(self.get_option('build_directory'),
120                                         *comps)
121
122        path = self.path_from_chromium_base('xcodebuild', *comps)
123        if self._filesystem.exists(path):
124            return path
125        return self.path_from_webkit_base(
126            'Source', 'WebKit', 'chromium', 'xcodebuild', *comps)
127
128    def _check_wdiff_install(self):
129        try:
130            # We're ignoring the return and always returning True
131            self._executive.run_command([self._path_to_wdiff()], error_handler=Executive.ignore_error)
132        except OSError:
133            _log.warning('wdiff not found. Install using MacPorts or some '
134                         'other means')
135        return True
136
137    def _lighttpd_path(self, *comps):
138        return self.path_from_chromium_base('third_party', 'lighttpd',
139                                            'mac', *comps)
140
141    def _path_to_apache(self):
142        return '/usr/sbin/httpd'
143
144    def _path_to_apache_config_file(self):
145        return self._filesystem.join(self.layout_tests_dir(), 'http', 'conf',
146                                     'apache2-httpd.conf')
147
148    def _path_to_lighttpd(self):
149        return self._lighttpd_path('bin', 'lighttpd')
150
151    def _path_to_lighttpd_modules(self):
152        return self._lighttpd_path('lib')
153
154    def _path_to_lighttpd_php(self):
155        return self._lighttpd_path('bin', 'php-cgi')
156
157    def _path_to_driver(self, configuration=None):
158        # FIXME: make |configuration| happy with case-sensitive file
159        # systems.
160        if not configuration:
161            configuration = self.get_option('configuration')
162        return self._build_path(configuration, self.driver_name() + '.app',
163            'Contents', 'MacOS', self.driver_name())
164
165    def _path_to_helper(self):
166        binary_name = 'LayoutTestHelper'
167        return self._build_path(self.get_option('configuration'), binary_name)
168
169    def _path_to_wdiff(self):
170        return 'wdiff'
171
172    def _shut_down_http_server(self, server_pid):
173        """Shut down the lighttpd web server. Blocks until it's fully
174        shut down.
175
176        Args:
177            server_pid: The process ID of the running server.
178        """
179        # server_pid is not set when "http_server.py stop" is run manually.
180        if server_pid is None:
181            # TODO(mmoss) This isn't ideal, since it could conflict with
182            # lighttpd processes not started by http_server.py,
183            # but good enough for now.
184            self._executive.kill_all('lighttpd')
185            self._executive.kill_all('httpd')
186        else:
187            try:
188                os.kill(server_pid, signal.SIGTERM)
189                # TODO(mmoss) Maybe throw in a SIGKILL just to be sure?
190            except OSError:
191                # Sometimes we get a bad PID (e.g. from a stale httpd.pid
192                # file), so if kill fails on the given PID, just try to
193                # 'killall' web servers.
194                self._shut_down_http_server(None)
195