Home | History | Annotate | Download | only in port
      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 
     32 import logging
     33 import os
     34 import signal
     35 
     36 import chromium
     37 
     38 _log = logging.getLogger("webkitpy.layout_tests.port.chromium_linux")
     39 
     40 
     41 class 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