1#!/usr/bin/env python 2# Copyright (C) 2010 Google Inc. All rights reserved. 3# 4# Redistribution and use in source and binary forms, with or without 5# modification, are permitted provided that the following conditions are 6# met: 7# 8# * Redistributions of source code must retain the above copyright 9# notice, this list of conditions and the following disclaimer. 10# * Redistributions in binary form must reproduce the above 11# copyright notice, this list of conditions and the following disclaimer 12# in the documentation and/or other materials provided with the 13# distribution. 14# * Neither the name of Google Inc. nor the names of its 15# contributors may be used to endorse or promote products derived from 16# this software without specific prior written permission. 17# 18# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 30"""Chromium Linux implementation of the Port interface.""" 31 32import logging 33import os 34import signal 35 36import chromium 37 38_log = logging.getLogger("webkitpy.layout_tests.port.chromium_linux") 39 40 41class ChromiumLinuxPort(chromium.ChromiumPort): 42 """Chromium Linux implementation of the Port class.""" 43 SUPPORTED_ARCHITECTURES = ('x86', 'x86_64') 44 45 FALLBACK_PATHS = { 46 'x86_64': ['chromium-linux-x86_64', 'chromium-linux', 'chromium-win', 'chromium', 'win', 'mac'], 47 'x86': ['chromium-linux', 'chromium-win', 'chromium', 'win', 'mac'], 48 } 49 50 def __init__(self, port_name=None, **kwargs): 51 port_name = port_name or 'chromium-linux' 52 chromium.ChromiumPort.__init__(self, port_name=port_name, **kwargs) 53 54 # We re-set the port name once the base object is fully initialized 55 # in order to be able to find the DRT binary properly. 56 if port_name.endswith('-linux'): 57 self._architecture = self._determine_architecture() 58 # FIXME: this is an ugly hack to avoid renaming the GPU port. 59 if port_name == 'chromium-linux': 60 port_name = port_name + '-' + self._architecture 61 else: 62 base, arch = port_name.rsplit('-', 1) 63 assert base in ('chromium-linux', 'chromium-gpu-linux') 64 self._architecture = arch 65 assert self._architecture in self.SUPPORTED_ARCHITECTURES 66 assert port_name in ('chromium-linux', 'chromium-gpu-linux', 67 'chromium-linux-x86', 'chromium-linux-x86_64', 68 'chromium-gpu-linux-x86_64') 69 self._name = port_name 70 self._operating_system = 'linux' 71 # FIXME: add support for 'lucid' 72 self._version = 'hardy' 73 74 def _determine_architecture(self): 75 driver_path = self._path_to_driver() 76 file_output = '' 77 if self._filesystem.exists(driver_path): 78 file_output = self._executive.run_command(['file', driver_path], 79 return_stderr=True) 80 81 if 'ELF 32-bit LSB executable' in file_output: 82 return 'x86' 83 if 'ELF 64-bit LSB executable' in file_output: 84 return 'x86_64' 85 if file_output: 86 _log.warning('Could not determine architecture from "file" output: %s' % file_output) 87 88 # We don't know what the architecture is; default to 'x86' because 89 # maybe we're rebaselining and the binary doesn't actually exist, 90 # or something else weird is going on. It's okay to do this because 91 # if we actually try to use the binary, check_build() should fail. 92 return 'x86' 93 94 def baseline_path(self): 95 if self._architecture == 'x86_64': 96 return self._webkit_baseline_path(self._name) 97 return self._webkit_baseline_path('chromium-linux') 98 99 def baseline_search_path(self): 100 port_names = self.FALLBACK_PATHS[self._architecture] 101 return map(self._webkit_baseline_path, port_names) 102 103 def check_build(self, needs_http): 104 result = chromium.ChromiumPort.check_build(self, needs_http) 105 if needs_http: 106 if self.get_option('use_apache'): 107 result = self._check_apache_install() and result 108 else: 109 result = self._check_lighttpd_install() and result 110 result = self._check_wdiff_install() and result 111 112 if not result: 113 _log.error('For complete Linux build requirements, please see:') 114 _log.error('') 115 _log.error(' http://code.google.com/p/chromium/wiki/' 116 'LinuxBuildInstructions') 117 return result 118 119 # 120 # PROTECTED METHODS 121 # 122 123 def _build_path(self, *comps): 124 if self.get_option('build_directory'): 125 return self._filesystem.join(self.get_option('build_directory'), 126 *comps) 127 128 base = self.path_from_chromium_base() 129 if self._filesystem.exists(self._filesystem.join(base, 'sconsbuild')): 130 return self._filesystem.join(base, 'sconsbuild', *comps) 131 if self._filesystem.exists(self._filesystem.join(base, 'out', *comps)): 132 return self._filesystem.join(base, 'out', *comps) 133 base = self.path_from_webkit_base() 134 if self._filesystem.exists(self._filesystem.join(base, 'sconsbuild')): 135 return self._filesystem.join(base, 'sconsbuild', *comps) 136 return self._filesystem.join(base, 'out', *comps) 137 138 def _check_apache_install(self): 139 result = self._check_file_exists(self._path_to_apache(), 140 "apache2") 141 result = self._check_file_exists(self._path_to_apache_config_file(), 142 "apache2 config file") and result 143 if not result: 144 _log.error(' Please install using: "sudo apt-get install ' 145 'apache2 libapache2-mod-php5"') 146 _log.error('') 147 return result 148 149 def _check_lighttpd_install(self): 150 result = self._check_file_exists( 151 self._path_to_lighttpd(), "LigHTTPd executable") 152 result = self._check_file_exists(self._path_to_lighttpd_php(), 153 "PHP CGI executable") and result 154 result = self._check_file_exists(self._path_to_lighttpd_modules(), 155 "LigHTTPd modules") and result 156 if not result: 157 _log.error(' Please install using: "sudo apt-get install ' 158 'lighttpd php5-cgi"') 159 _log.error('') 160 return result 161 162 def _check_wdiff_install(self): 163 result = self._check_file_exists(self._path_to_wdiff(), 'wdiff') 164 if not result: 165 _log.error(' Please install using: "sudo apt-get install ' 166 'wdiff"') 167 _log.error('') 168 # FIXME: The ChromiumMac port always returns True. 169 return result 170 171 def _path_to_apache(self): 172 if self._is_redhat_based(): 173 return '/usr/sbin/httpd' 174 else: 175 return '/usr/sbin/apache2' 176 177 def _path_to_apache_config_file(self): 178 if self._is_redhat_based(): 179 config_name = 'fedora-httpd.conf' 180 else: 181 config_name = 'apache2-debian-httpd.conf' 182 183 return self._filesystem.join(self.layout_tests_dir(), 'http', 'conf', 184 config_name) 185 186 def _path_to_lighttpd(self): 187 return "/usr/sbin/lighttpd" 188 189 def _path_to_lighttpd_modules(self): 190 return "/usr/lib/lighttpd" 191 192 def _path_to_lighttpd_php(self): 193 return "/usr/bin/php-cgi" 194 195 def _path_to_driver(self, configuration=None): 196 if not configuration: 197 configuration = self.get_option('configuration') 198 binary_name = 'DumpRenderTree' 199 return self._build_path(configuration, binary_name) 200 201 def _path_to_helper(self): 202 return None 203 204 def _path_to_wdiff(self): 205 if self._is_redhat_based(): 206 return '/usr/bin/dwdiff' 207 else: 208 return '/usr/bin/wdiff' 209 210 def _is_redhat_based(self): 211 return self._filesystem.exists(self._filesystem.join('/etc', 'redhat-release')) 212 213 def _shut_down_http_server(self, server_pid): 214 """Shut down the lighttpd web server. Blocks until it's fully 215 shut down. 216 217 Args: 218 server_pid: The process ID of the running server. 219 """ 220 # server_pid is not set when "http_server.py stop" is run manually. 221 if server_pid is None: 222 # TODO(mmoss) This isn't ideal, since it could conflict with 223 # lighttpd processes not started by http_server.py, 224 # but good enough for now. 225 self._executive.kill_all("lighttpd") 226 self._executive.kill_all("apache2") 227 else: 228 try: 229 os.kill(server_pid, signal.SIGTERM) 230 # TODO(mmoss) Maybe throw in a SIGKILL just to be sure? 231 except OSError: 232 # Sometimes we get a bad PID (e.g. from a stale httpd.pid 233 # file), so if kill fails on the given PID, just try to 234 # 'killall' web servers. 235 self._shut_down_http_server(None) 236