| OLD | NEW |
| (Empty) |
| 1 # Copyright (C) 2010 Google Inc. All rights reserved. | |
| 2 # | |
| 3 # Redistribution and use in source and binary forms, with or without | |
| 4 # modification, are permitted provided that the following conditions are | |
| 5 # met: | |
| 6 # | |
| 7 # * Redistributions of source code must retain the above copyright | |
| 8 # notice, this list of conditions and the following disclaimer. | |
| 9 # * Redistributions in binary form must reproduce the above | |
| 10 # copyright notice, this list of conditions and the following disclaimer | |
| 11 # in the documentation and/or other materials provided with the | |
| 12 # distribution. | |
| 13 # * Neither the name of Google Inc. nor the names of its | |
| 14 # contributors may be used to endorse or promote products derived from | |
| 15 # this software without specific prior written permission. | |
| 16 # | |
| 17 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
| 18 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| 19 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
| 20 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
| 21 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
| 22 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
| 23 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
| 24 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
| 25 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
| 26 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
| 27 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
| 28 | |
| 29 """Windows implementation of the Port interface.""" | |
| 30 | |
| 31 import errno | |
| 32 import os | |
| 33 import logging | |
| 34 | |
| 35 try: | |
| 36 import _winreg | |
| 37 except ImportError as e: | |
| 38 _winreg = None | |
| 39 WindowsError = Exception # this shuts up pylint. | |
| 40 | |
| 41 from webkitpy.layout_tests.breakpad.dump_reader_win import DumpReaderWin | |
| 42 from webkitpy.layout_tests.models import test_run_results | |
| 43 from webkitpy.layout_tests.port import base | |
| 44 from webkitpy.layout_tests.servers import crash_service | |
| 45 | |
| 46 | |
| 47 _log = logging.getLogger(__name__) | |
| 48 | |
| 49 | |
| 50 class WinPort(base.Port): | |
| 51 port_name = 'win' | |
| 52 | |
| 53 # FIXME: Figure out how to unify this with base.TestConfiguration.all_system
s()? | |
| 54 SUPPORTED_VERSIONS = ('xp', 'win7') | |
| 55 | |
| 56 FALLBACK_PATHS = { 'win7': [ 'win' ]} | |
| 57 FALLBACK_PATHS['xp'] = ['win-xp'] + FALLBACK_PATHS['win7'] | |
| 58 | |
| 59 DEFAULT_BUILD_DIRECTORIES = ('build', 'out') | |
| 60 | |
| 61 BUILD_REQUIREMENTS_URL = 'http://www.chromium.org/developers/how-tos/build-i
nstructions-windows' | |
| 62 | |
| 63 @classmethod | |
| 64 def determine_full_port_name(cls, host, options, port_name): | |
| 65 if port_name.endswith('win'): | |
| 66 assert host.platform.is_win() | |
| 67 # We don't maintain separate baselines for vista, so we pretend it i
s win7. | |
| 68 if host.platform.os_version in ('vista', '7sp0', '7sp1', 'future'): | |
| 69 version = 'win7' | |
| 70 else: | |
| 71 version = host.platform.os_version | |
| 72 port_name = port_name + '-' + version | |
| 73 return port_name | |
| 74 | |
| 75 def __init__(self, host, port_name, **kwargs): | |
| 76 super(WinPort, self).__init__(host, port_name, **kwargs) | |
| 77 self._version = port_name[port_name.index('win-') + len('win-'):] | |
| 78 assert self._version in self.SUPPORTED_VERSIONS, "%s is not in %s" % (se
lf._version, self.SUPPORTED_VERSIONS) | |
| 79 if not self.get_option('disable_breakpad'): | |
| 80 self._dump_reader = DumpReaderWin(host, self._build_path()) | |
| 81 self._crash_service = None | |
| 82 self._crash_service_available = None | |
| 83 | |
| 84 def additional_drt_flag(self): | |
| 85 flags = super(WinPort, self).additional_drt_flag() | |
| 86 flags += ['--enable-direct-write'] | |
| 87 if not self.get_option('disable_breakpad'): | |
| 88 flags += ['--enable-crash-reporter', '--crash-dumps-dir=%s' % self._
dump_reader.crash_dumps_directory()] | |
| 89 return flags | |
| 90 | |
| 91 def check_httpd(self): | |
| 92 res = super(WinPort, self).check_httpd() | |
| 93 if self.uses_apache(): | |
| 94 # In order to run CGI scripts on Win32 that use unix shebang lines,
we need to | |
| 95 # create entries in the registry that remap the extensions (.pl and
.cgi) to the | |
| 96 # appropriate Win32 paths. The command line arguments must match the
command | |
| 97 # line arguments in the shebang line exactly. | |
| 98 if _winreg: | |
| 99 res = self._check_reg(r'.cgi\Shell\ExecCGI\Command') and res | |
| 100 res = self._check_reg(r'.pl\Shell\ExecCGI\Command') and res | |
| 101 else: | |
| 102 _log.warning("Could not check the registry; http may not work co
rrectly.") | |
| 103 | |
| 104 return res | |
| 105 | |
| 106 def _check_reg(self, sub_key): | |
| 107 # see comments in check_httpd(), above, for why this routine exists and
what it's doing. | |
| 108 try: | |
| 109 # Note that we HKCR is a union of HKLM and HKCR (with the latter | |
| 110 # overridding the former), so reading from HKCR ensures that we get | |
| 111 # the value if it is set in either place. See als comments below. | |
| 112 hkey = _winreg.OpenKey(_winreg.HKEY_CLASSES_ROOT, sub_key) | |
| 113 args = _winreg.QueryValue(hkey, '').split() | |
| 114 _winreg.CloseKey(hkey) | |
| 115 | |
| 116 # In order to keep multiple checkouts from stepping on each other, w
e simply check that an | |
| 117 # existing entry points to a valid path and has the right command li
ne. | |
| 118 if len(args) == 2 and self._filesystem.exists(args[0]) and args[0].e
ndswith('perl.exe') and args[1] == '-wT': | |
| 119 return True | |
| 120 except WindowsError, e: | |
| 121 if e.errno != errno.ENOENT: | |
| 122 raise e | |
| 123 # The key simply probably doesn't exist. | |
| 124 pass | |
| 125 | |
| 126 # Note that we write to HKCU so that we don't need privileged access | |
| 127 # to the registry, and that will get reflected in HKCR when it is read,
above. | |
| 128 cmdline = self.path_from_chromium_base('third_party', 'perl', 'perl', 'b
in', 'perl.exe') + ' -wT' | |
| 129 hkey = _winreg.CreateKeyEx(_winreg.HKEY_CURRENT_USER, 'Software\\Classes
\\' + sub_key, 0, _winreg.KEY_WRITE) | |
| 130 _winreg.SetValue(hkey, '', _winreg.REG_SZ, cmdline) | |
| 131 _winreg.CloseKey(hkey) | |
| 132 return True | |
| 133 | |
| 134 def setup_test_run(self): | |
| 135 super(WinPort, self).setup_test_run() | |
| 136 | |
| 137 if not self.get_option('disable_breakpad'): | |
| 138 assert not self._crash_service, 'Already running a crash service' | |
| 139 if self._crash_service_available == None: | |
| 140 self._crash_service_available = self._check_crash_service_availa
ble() | |
| 141 if not self._crash_service_available: | |
| 142 return | |
| 143 service = crash_service.CrashService(self, self._dump_reader.crash_d
umps_directory()) | |
| 144 service.start() | |
| 145 self._crash_service = service | |
| 146 | |
| 147 def clean_up_test_run(self): | |
| 148 super(WinPort, self).clean_up_test_run() | |
| 149 | |
| 150 if self._crash_service: | |
| 151 self._crash_service.stop() | |
| 152 self._crash_service = None | |
| 153 | |
| 154 def setup_environ_for_server(self, server_name=None): | |
| 155 env = super(WinPort, self).setup_environ_for_server(server_name) | |
| 156 | |
| 157 # FIXME: This is a temporary hack to get the cr-win bot online until | |
| 158 # someone from the cr-win port can take a look. | |
| 159 apache_envvars = ['SYSTEMDRIVE', 'SYSTEMROOT', 'TEMP', 'TMP'] | |
| 160 for key, value in os.environ.items(): | |
| 161 if key not in env and key in apache_envvars: | |
| 162 env[key] = value | |
| 163 | |
| 164 # Put the cygwin directory first in the path to find cygwin1.dll. | |
| 165 env["PATH"] = "%s;%s" % (self.path_from_chromium_base("third_party", "cy
gwin", "bin"), env["PATH"]) | |
| 166 # Configure the cygwin directory so that pywebsocket finds proper | |
| 167 # python executable to run cgi program. | |
| 168 env["CYGWIN_PATH"] = self.path_from_chromium_base("third_party", "cygwin
", "bin") | |
| 169 if self.get_option('register_cygwin'): | |
| 170 setup_mount = self.path_from_chromium_base("third_party", "cygwin",
"setup_mount.bat") | |
| 171 self._executive.run_command([setup_mount]) # Paths are all absolute
, so this does not require a cwd. | |
| 172 return env | |
| 173 | |
| 174 def _modules_to_search_for_symbols(self): | |
| 175 # FIXME: we should return the path to the ffmpeg equivalents to detect i
f we have the mp3 and aac codecs installed. | |
| 176 # See https://bugs.webkit.org/show_bug.cgi?id=89706. | |
| 177 return [] | |
| 178 | |
| 179 def check_build(self, needs_http, printer): | |
| 180 result = super(WinPort, self).check_build(needs_http, printer) | |
| 181 | |
| 182 self._crash_service_available = self._check_crash_service_available() | |
| 183 if not self._crash_service_available: | |
| 184 result = test_run_results.UNEXPECTED_ERROR_EXIT_STATUS | |
| 185 | |
| 186 if result: | |
| 187 _log.error('For complete Windows build requirements, please see:') | |
| 188 _log.error('') | |
| 189 _log.error(' http://dev.chromium.org/developers/how-tos/build-ins
tructions-windows') | |
| 190 return result | |
| 191 | |
| 192 def operating_system(self): | |
| 193 return 'win' | |
| 194 | |
| 195 def relative_test_filename(self, filename): | |
| 196 path = filename[len(self.layout_tests_dir()) + 1:] | |
| 197 return path.replace('\\', '/') | |
| 198 | |
| 199 def uses_apache(self): | |
| 200 val = self.get_option('use_apache') | |
| 201 if val is None: | |
| 202 return True | |
| 203 return val | |
| 204 | |
| 205 def path_to_apache(self): | |
| 206 return self.path_from_chromium_base('third_party', 'apache-win32', 'bin'
, 'httpd.exe') | |
| 207 | |
| 208 def path_to_apache_config_file(self): | |
| 209 return self._filesystem.join(self.layout_tests_dir(), 'http', 'conf', 'w
in-httpd.conf') | |
| 210 | |
| 211 # | |
| 212 # PROTECTED ROUTINES | |
| 213 # | |
| 214 | |
| 215 def _path_to_driver(self, configuration=None): | |
| 216 binary_name = '%s.exe' % self.driver_name() | |
| 217 return self._build_path_with_configuration(configuration, binary_name) | |
| 218 | |
| 219 def _path_to_crash_service(self): | |
| 220 binary_name = 'content_shell_crash_service.exe' | |
| 221 return self._build_path(binary_name) | |
| 222 | |
| 223 def _path_to_image_diff(self): | |
| 224 binary_name = 'image_diff.exe' | |
| 225 return self._build_path(binary_name) | |
| 226 | |
| 227 def _path_to_wdiff(self): | |
| 228 return self.path_from_chromium_base('third_party', 'cygwin', 'bin', 'wdi
ff.exe') | |
| 229 | |
| 230 def _check_crash_service_available(self): | |
| 231 """Checks whether the crash service binary is present.""" | |
| 232 result = self._check_file_exists(self._path_to_crash_service(), "content
_shell_crash_service.exe") | |
| 233 if not result: | |
| 234 _log.error(" Could not find crash service, unexpected crashes won
't be symbolized.") | |
| 235 _log.error(' Did you build the target blink_tests?') | |
| 236 _log.error('') | |
| 237 return result | |
| 238 | |
| 239 def look_for_new_crash_logs(self, crashed_processes, start_time): | |
| 240 if self.get_option('disable_breakpad'): | |
| 241 return None | |
| 242 return self._dump_reader.look_for_new_crash_logs(crashed_processes, star
t_time) | |
| 243 | |
| 244 def clobber_old_port_specific_results(self): | |
| 245 if not self.get_option('disable_breakpad'): | |
| 246 self._dump_reader.clobber_old_results() | |
| OLD | NEW |