| # Copyright (C) 2010 Google Inc. All rights reserved. |
| # Copyright (C) 2013, 2015 Apple Inc. All rights reserved. |
| # |
| # Redistribution and use in source and binary forms, with or without |
| # modification, are permitted provided that the following conditions are |
| # met: |
| # |
| # * Redistributions of source code must retain the above copyright |
| # notice, this list of conditions and the following disclaimer. |
| # * Redistributions in binary form must reproduce the above |
| # copyright notice, this list of conditions and the following disclaimer |
| # in the documentation and/or other materials provided with the |
| # distribution. |
| # * Neither the Google name nor the names of its |
| # contributors may be used to endorse or promote products derived from |
| # this software without specific prior written permission. |
| # |
| # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| |
| import atexit |
| import os |
| import logging |
| import re |
| import sys |
| import time |
| |
| from webkitpy.common.system.crashlogs import CrashLogs |
| from webkitpy.common.system.systemhost import SystemHost |
| from webkitpy.common.system.executive import ScriptError, Executive |
| from webkitpy.common.system.path import abspath_to_uri, cygpath |
| from webkitpy.port.apple import ApplePort |
| |
| |
| _log = logging.getLogger(__name__) |
| |
| |
| try: |
| import _winreg |
| import win32com.client |
| except ImportError: |
| _log.warn("Not running on native Windows.") |
| |
| |
| class WinPort(ApplePort): |
| port_name = "win" |
| |
| VERSION_FALLBACK_ORDER = ["win-xp", "win-vista", "win-7sp0", "win-win10", "win"] |
| |
| ARCHITECTURES = ['x86', 'x86_64'] |
| |
| CRASH_LOG_PREFIX = "CrashLog" |
| |
| if sys.platform.startswith('win'): |
| POST_MORTEM_DEBUGGER_KEY = r'SOFTWARE\Microsoft\Windows NT\CurrentVersion\AeDebug' |
| WOW64_POST_MORTEM_DEBUGGER_KEY = r'SOFTWARE\Wow6432Node\Microsoft\Windows NT\CurrentVersion\AeDebug' |
| WINDOWS_ERROR_REPORTING_KEY = r'SOFTWARE\Microsoft\Windows\Windows Error Reporting' |
| WOW64_WINDOWS_ERROR_REPORTING_KEY = r'SOFTWARE\Wow6432Node\Microsoft\Windows\Windows Error Reporting' |
| _HKLM = _winreg.HKEY_LOCAL_MACHINE |
| _HKCU = _winreg.HKEY_CURRENT_USER |
| _REG_DWORD = _winreg.REG_DWORD |
| _REG_SZ = _winreg.REG_SZ |
| else: |
| POST_MORTEM_DEBUGGER_KEY = "/%s/SOFTWARE/Microsoft/Windows NT/CurrentVersion/AeDebug/%s" |
| WOW64_POST_MORTEM_DEBUGGER_KEY = "/%s/SOFTWARE/Wow6432Node/Microsoft/Windows NT/CurrentVersion/AeDebug/%s" |
| WINDOWS_ERROR_REPORTING_KEY = "/%s/SOFTWARE/Microsoft/Windows/Windows Error Reporting/%s" |
| WOW64_WINDOWS_ERROR_REPORTING_KEY = "/%s/SOFTWARE/Wow6432Node/Microsoft/Windows/Windows Error Reporting/%s" |
| _HKLM = "HKLM" |
| _HKCU = "HKCU" |
| _REG_DWORD = "-d" |
| _REG_SZ = "-s" |
| |
| previous_debugger_values = {} |
| previous_wow64_debugger_values = {} |
| |
| previous_error_reporting_values = {} |
| previous_wow64_error_reporting_values = {} |
| |
| def do_text_results_differ(self, expected_text, actual_text): |
| # Sanity was restored in WK2, so we don't need this hack there. |
| if self.get_option('webkit_test_runner'): |
| return ApplePort.do_text_results_differ(self, expected_text, actual_text) |
| |
| # This is a hack (which dates back to ORWT). |
| # Windows does not have an EDITING DELEGATE, so we strip any EDITING DELEGATE |
| # messages to make more of the tests pass. |
| # It's possible more of the ports might want this and this could move down into WebKitPort. |
| delegate_regexp = re.compile("^EDITING DELEGATE: .*?\n", re.MULTILINE) |
| expected_text = delegate_regexp.sub("", expected_text) |
| actual_text = delegate_regexp.sub("", actual_text) |
| return expected_text != actual_text |
| |
| def default_baseline_search_path(self): |
| name = self._name.replace('-wk2', '') |
| if name.endswith(self.FUTURE_VERSION): |
| fallback_names = [self.port_name] |
| else: |
| fallback_names = self.VERSION_FALLBACK_ORDER[self.VERSION_FALLBACK_ORDER.index(name):-1] + [self.port_name] |
| # FIXME: The AppleWin port falls back to AppleMac for some results. Eventually we'll have a shared 'apple' port. |
| if self.get_option('webkit_test_runner'): |
| fallback_names.insert(0, 'win-wk2') |
| fallback_names.append('mac-wk2') |
| # Note we do not add 'wk2' here, even though it's included in _skipped_search_paths(). |
| # FIXME: Perhaps we should get this list from MacPort? |
| fallback_names.append('mac') |
| return map(self._webkit_baseline_path, fallback_names) |
| |
| def setup_environ_for_server(self, server_name=None): |
| env = super(WinPort, self).setup_environ_for_server(server_name) |
| env['XML_CATALOG_FILES'] = '' # work around missing /etc/catalog <rdar://problem/4292995> |
| return env |
| |
| def operating_system(self): |
| return 'win' |
| |
| def _port_flag_for_scripts(self): |
| if self.get_option('architecture') == 'x86_64': |
| return '--64-bit' |
| return None |
| |
| def show_results_html_file(self, results_filename): |
| self._run_script('run-safari', [abspath_to_uri(SystemHost().platform, results_filename)]) |
| |
| def _runtime_feature_list(self): |
| supported_features_command = [self._path_to_driver(), '--print-supported-features'] |
| try: |
| output = self._executive.run_command(supported_features_command, error_handler=Executive.ignore_error) |
| except OSError, e: |
| _log.warn("Exception running driver: %s, %s. Driver must be built before calling WebKitPort.test_expectations()." % (supported_features_command, e)) |
| return None |
| |
| # Note: win/DumpRenderTree.cpp does not print a leading space before the features_string. |
| match_object = re.match("SupportedFeatures:\s*(?P<features_string>.*)\s*", output) |
| if not match_object: |
| return None |
| return match_object.group('features_string').split(' ') |
| |
| def _build_path(self, *comps): |
| """Returns the full path to the test driver (DumpRenderTree).""" |
| root_directory = self.get_option('_cached_root') or self.get_option('root') |
| if not root_directory: |
| ApplePort._build_path(self, *comps) # Sets option _cached_root |
| binary_directory = 'bin32' |
| if self.get_option('architecture') == 'x86_64': |
| binary_directory = 'bin64' |
| root_directory = self._filesystem.join(self.get_option('_cached_root'), binary_directory) |
| self.set_option('_cached_root', root_directory) |
| |
| return self._filesystem.join(root_directory, *comps) |
| |
| # Note: These are based on the stock XAMPP locations for these files. |
| def _uses_apache(self): |
| return True |
| |
| def _path_to_apache(self): |
| httpdPath = os.path.join('C:', 'xampp', 'apache', 'bin', 'httpd.exe') |
| if self._filesystem.exists(httpdPath): |
| return httpdPath |
| _log.error("Could not find apache. Not installed or unknown path.") |
| return None |
| |
| def _path_to_lighttpd(self): |
| return "/usr/sbin/lighttpd" |
| |
| def _path_to_lighttpd_modules(self): |
| return "/usr/lib/lighttpd" |
| |
| def _path_to_lighttpd_php(self): |
| return "/usr/bin/php-cgi" |
| |
| def test_search_path(self): |
| test_fallback_names = [path for path in self.baseline_search_path() if not path.startswith(self._webkit_baseline_path('mac'))] |
| return map(self._webkit_baseline_path, test_fallback_names) |
| |
| def _ntsd_location(self): |
| if 'PROGRAMFILES' not in os.environ: |
| return None |
| possible_paths = [self._filesystem.join(os.environ['PROGRAMFILES'], "Windows Kits", "10", "Debuggers", "x64", "ntsd.exe"), |
| self._filesystem.join(os.environ['PROGRAMFILES'], "Windows Kits", "8.1", "Debuggers", "x64", "ntsd.exe"), |
| self._filesystem.join(os.environ['PROGRAMFILES'], "Windows Kits", "8.0", "Debuggers", "x64", "ntsd.exe")] |
| if self.get_option('architecture') == 'x86_64': |
| possible_paths.append(self._filesystem.join("{0} (x86)".format(os.environ['PROGRAMFILES']), "Windows Kits", "10", "Debuggers", "x64", "ntsd.exe")) |
| possible_paths.append(self._filesystem.join("{0} (x86)".format(os.environ['PROGRAMFILES']), "Windows Kits", "8.1", "Debuggers", "x64", "ntsd.exe")) |
| possible_paths.append(self._filesystem.join("{0} (x86)".format(os.environ['PROGRAMFILES']), "Windows Kits", "8.0", "Debuggers", "x64", "ntsd.exe")) |
| possible_paths.append(self._filesystem.join("{0} (x86)".format(os.environ['PROGRAMFILES']), "Debugging Tools for Windows (x64)", "ntsd.exe")) |
| else: |
| possible_paths.append(self._filesystem.join(os.environ['PROGRAMFILES'], "Debugging Tools for Windows (x86)", "ntsd.exe")) |
| possible_paths.append(self._filesystem.join(os.environ['SYSTEMROOT'], "system32", "ntsd.exe")) |
| if 'ProgramW6432' in os.environ: |
| possible_paths.append(self._filesystem.join(os.environ['ProgramW6432'], "Windows Kits", "10", "Debuggers", "x64", "ntsd.exe")) |
| possible_paths.append(self._filesystem.join(os.environ['ProgramW6432'], "Windows Kits", "8.1", "Debuggers", "x64", "ntsd.exe")) |
| possible_paths.append(self._filesystem.join(os.environ['ProgramW6432'], "Windows Kits", "8.0", "Debuggers", "x64", "ntsd.exe")) |
| possible_paths.append(self._filesystem.join(os.environ['ProgramW6432'], "Debugging Tools for Windows (x64)", "ntsd.exe")) |
| for path in possible_paths: |
| expanded_path = self._filesystem.expanduser(path) |
| _log.debug("Considering '%s'" % expanded_path) |
| if self._filesystem.exists(expanded_path): |
| _log.debug("Using ntsd located in '%s'" % path) |
| return expanded_path |
| return None |
| |
| def create_debugger_command_file(self): |
| debugger_temp_directory = str(self._filesystem.mkdtemp()) |
| command_file = self._filesystem.join(debugger_temp_directory, "debugger-commands.txt") |
| commands = ''.join(['.logopen /t "%s\\%s.txt"\n' % (cygpath(self.results_directory()), self.CRASH_LOG_PREFIX), |
| '.srcpath "%s"\n' % cygpath(self._webkit_finder.webkit_base()), |
| '!analyze -vv\n', |
| '~*kpn\n', |
| 'q\n']) |
| self._filesystem.write_text_file(command_file, commands) |
| return command_file |
| |
| def read_registry_value(self, reg_path, arch, root, key): |
| if sys.platform.startswith('win'): |
| _log.debug("Trying to read %s\\%s" % (reg_path, key)) |
| try: |
| registry_key = _winreg.OpenKey(root, reg_path) |
| value = _winreg.QueryValueEx(registry_key, key) |
| _winreg.CloseKey(registry_key) |
| except WindowsError as ex: |
| _log.debug("Unable to read %s\\%s: %s" % (reg_path, key, str(ex))) |
| return ['', self._REG_SZ] |
| else: |
| registry_key = reg_path % (root, key) |
| _log.debug("Reading %s" % (registry_key)) |
| read_registry_command = ["regtool", arch, "get", registry_key] |
| int_value = self._executive.run_command(read_registry_command, error_handler=Executive.ignore_error) |
| # regtool doesn't return the type of the entry, so need this ugly hack: |
| if reg_path in (self.WINDOWS_ERROR_REPORTING_KEY, self.WOW64_WINDOWS_ERROR_REPORTING_KEY): |
| _log.debug("I got {0}".format(int_value)) |
| try: |
| value = [int(int_value), self._REG_DWORD] |
| except: |
| value = [0, self._REG_DWORD] |
| else: |
| value = [int_value.rstrip(), self._REG_SZ] |
| |
| _log.debug("I got back ({0}) of type ({1})".format(value[0], value[1])) |
| return value |
| |
| def write_registry_value(self, reg_path, arch, root, key, regType, value): |
| if sys.platform.startswith('win'): |
| _log.debug("Trying to write %s\\%s = %s" % (reg_path, key, value)) |
| try: |
| registry_key = _winreg.OpenKey(root, reg_path, 0, _winreg.KEY_WRITE) |
| except WindowsError: |
| try: |
| _log.debug("Key doesn't exist -- must create it.") |
| registry_key = _winreg.CreateKeyEx(root, reg_path, 0, _winreg.KEY_WRITE) |
| except WindowsError as ex: |
| _log.error("Error setting (%s) %s\key: %s to value: %s. Error=%s." % (arch, root, key, value, str(ex))) |
| _log.error("You many need to adjust permissions on the %s\\%s key." % (reg_path, key)) |
| return False |
| |
| _log.debug("Writing {0} of type {1} to {2}\\{3}".format(value, regType, registry_key, key)) |
| _winreg.SetValueEx(registry_key, key, 0, regType, value) |
| _winreg.CloseKey(registry_key) |
| else: |
| registry_key = reg_path % (root, key) |
| _log.debug("Writing to %s" % registry_key) |
| |
| set_reg_value_command = ["regtool", arch, "set", regType, str(registry_key), str(value)] |
| rc = self._executive.run_command(set_reg_value_command, return_exit_code=True) |
| if rc == 2: |
| add_reg_value_command = ["regtool", arch, "add", regType, str(registry_key)] |
| rc = self._executive.run_command(add_reg_value_command, return_exit_code=True) |
| if rc == 0: |
| rc = self._executive.run_command(set_reg_value_command, return_exit_code=True) |
| if rc: |
| _log.warn("Error setting (%s) %s\key: %s to value: %s. Error=%s." % (arch, root, key, value, str(rc))) |
| _log.warn("You many need to adjust permissions on the %s key." % registry_key) |
| return False |
| |
| # On Windows Vista/7 with UAC enabled, regtool will fail to modify the registry, but will still |
| # return a successful exit code. So we double-check here that the value we tried to write to the |
| # registry was really written. |
| check_value = self.read_registry_value(reg_path, arch, root, key) |
| if check_value[0] != value or check_value[1] != regType: |
| _log.warn("Reg update reported success, but value of key %s did not change." % key) |
| _log.warn("Wanted to set it to ({0}, {1}), but got {2})".format(value, regType, check_value)) |
| _log.warn("You many need to adjust permissions on the %s\\%s key." % (reg_path, key)) |
| return False |
| |
| return True |
| |
| def setup_crash_log_saving(self): |
| if '_NT_SYMBOL_PATH' not in os.environ: |
| _log.warning("The _NT_SYMBOL_PATH environment variable is not set. Using Microsoft Symbol Server.") |
| os.environ['_NT_SYMBOL_PATH'] = 'SRV*http://msdl.microsoft.com/download/symbols' |
| |
| # Add build path to symbol path |
| os.environ['_NT_SYMBOL_PATH'] += ";" + self._build_path() |
| |
| ntsd_path = self._ntsd_location() |
| if not ntsd_path: |
| _log.warning("Can't find ntsd.exe. Crash logs will not be saved.") |
| return None |
| # If we used -c (instead of -cf) we could pass the commands directly on the command line. But |
| # when the commands include multiple quoted paths (e.g., for .logopen and .srcpath), Windows |
| # fails to invoke the post-mortem debugger at all (perhaps due to a bug in Windows's command |
| # line parsing). So we save the commands to a file instead and tell the debugger to execute them |
| # using -cf. |
| command_file = self.create_debugger_command_file() |
| if not command_file: |
| return None |
| debugger_options = '"{0}" -p %ld -e %ld -g -noio -lines -cf "{1}"'.format(cygpath(ntsd_path), cygpath(command_file)) |
| registry_settings = {'Debugger': [debugger_options, self._REG_SZ], 'Auto': ["1", self._REG_SZ]} |
| for key, value in registry_settings.iteritems(): |
| for arch in ["--wow32", "--wow64"]: |
| self.previous_debugger_values[(arch, self._HKLM, key)] = self.read_registry_value(self.POST_MORTEM_DEBUGGER_KEY, arch, self._HKLM, key) |
| self.previous_wow64_debugger_values[(arch, self._HKLM, key)] = self.read_registry_value(self.WOW64_POST_MORTEM_DEBUGGER_KEY, arch, self._HKLM, key) |
| self.write_registry_value(self.POST_MORTEM_DEBUGGER_KEY, arch, self._HKLM, key, value[1], value[0]) |
| self.write_registry_value(self.WOW64_POST_MORTEM_DEBUGGER_KEY, arch, self._HKLM, key, value[1], value[0]) |
| |
| def restore_crash_log_saving(self): |
| for key, value in self.previous_debugger_values.iteritems(): |
| self.write_registry_value(self.POST_MORTEM_DEBUGGER_KEY, key[0], key[1], key[2], value[1], value[0]) |
| for key, value in self.previous_wow64_debugger_values.iteritems(): |
| self.write_registry_value(self.WOW64_POST_MORTEM_DEBUGGER_KEY, key[0], key[1], key[2], value[1], value[0]) |
| |
| def prevent_error_dialogs(self): |
| registry_settings = {'DontShowUI': [1, self._REG_DWORD], 'Disabled': [1, self._REG_DWORD]} |
| for key, value in registry_settings.iteritems(): |
| for root in [self._HKLM, self._HKCU]: |
| for arch in ["--wow32", "--wow64"]: |
| self.previous_error_reporting_values[(arch, root, key)] = self.read_registry_value(self.WINDOWS_ERROR_REPORTING_KEY, arch, root, key) |
| self.previous_wow64_error_reporting_values[(arch, root, key)] = self.read_registry_value(self.WOW64_WINDOWS_ERROR_REPORTING_KEY, arch, root, key) |
| self.write_registry_value(self.WINDOWS_ERROR_REPORTING_KEY, arch, root, key, value[1], value[0]) |
| self.write_registry_value(self.WOW64_WINDOWS_ERROR_REPORTING_KEY, arch, root, key, value[1], value[0]) |
| |
| def allow_error_dialogs(self): |
| for key, value in self.previous_error_reporting_values.iteritems(): |
| self.write_registry_value(self.WINDOWS_ERROR_REPORTING_KEY, key[0], key[1], key[2], value[1], value[0]) |
| for key, value in self.previous_wow64_error_reporting_values.iteritems(): |
| self.write_registry_value(self.WOW64_WINDOWS_ERROR_REPORTING_KEY, key[0], key[1], key[2], value[1], value[0]) |
| |
| def delete_sem_locks(self): |
| os.system("rm -rf /dev/shm/sem.*") |
| |
| def setup_test_run(self, device_class=None): |
| atexit.register(self.restore_crash_log_saving) |
| self.setup_crash_log_saving() |
| self.prevent_error_dialogs() |
| self.delete_sem_locks() |
| super(WinPort, self).setup_test_run(device_class) |
| |
| def clean_up_test_run(self): |
| self.allow_error_dialogs() |
| self.restore_crash_log_saving() |
| super(WinPort, self).clean_up_test_run() |
| |
| def _get_crash_log(self, name, pid, stdout, stderr, newer_than, time_fn=None, sleep_fn=None, wait_for_log=True): |
| # Note that we do slow-spin here and wait, since it appears the time |
| # ReportCrash takes to actually write and flush the file varies when there are |
| # lots of simultaneous crashes going on. |
| # FIXME: Should most of this be moved into CrashLogs()? |
| time_fn = time_fn or time.time |
| sleep_fn = sleep_fn or time.sleep |
| crash_log = '' |
| crash_logs = CrashLogs(self.host, self.results_directory()) |
| now = time_fn() |
| # FIXME: delete this after we're sure this code is working ... |
| _log.debug('looking for crash log for %s:%s' % (name, str(pid))) |
| deadline = now + 5 * int(self.get_option('child_processes', 1)) |
| while not crash_log and now <= deadline: |
| # If the system_pid hasn't been determined yet, just try with the passed in pid. We'll be checking again later |
| system_pid = self._executive.pid_to_system_pid.get(pid) |
| if system_pid == None: |
| break # We haven't mapped cygwin pid->win pid yet |
| crash_log = crash_logs.find_newest_log(name, system_pid, include_errors=True, newer_than=newer_than) |
| if not wait_for_log: |
| break |
| if not crash_log or not [line for line in crash_log.splitlines() if line.startswith('quit:')]: |
| sleep_fn(0.1) |
| now = time_fn() |
| |
| if not crash_log: |
| return (stderr, None) |
| return (stderr, crash_log) |
| |
| def look_for_new_crash_logs(self, crashed_processes, start_time): |
| """Since crash logs can take a long time to be written out if the system is |
| under stress do a second pass at the end of the test run. |
| |
| crashes: test_name -> pid, process_name tuple of crashed process |
| start_time: time the tests started at. We're looking for crash |
| logs after that time. |
| """ |
| crash_logs = {} |
| for (test_name, process_name, pid) in crashed_processes: |
| # Passing None for output. This is a second pass after the test finished so |
| # if the output had any logging we would have already collected it. |
| crash_log = self._get_crash_log(process_name, pid, None, None, start_time, wait_for_log=False)[1] |
| if crash_log: |
| crash_logs[test_name] = crash_log |
| return crash_logs |
| |
| def look_for_new_samples(self, unresponsive_processes, start_time): |
| # No sampling on Windows. |
| pass |
| |
| def sample_process(self, name, pid): |
| # No sampling on Windows. |
| pass |
| |
| def _make_leak_detector(self): |
| return None |
| |
| def check_for_leaks(self, process_name, process_pid): |
| # No leak checking on Windows. |
| pass |
| |
| def print_leaks_summary(self): |
| # No leak checking on Windows. |
| pass |
| |
| def _path_to_webcore_library(self): |
| return None |
| |
| def find_system_pid(self, name, pid): |
| system_pid = int(pid) |
| |
| if sys.platform == "cygwin": |
| # Windows and Cygwin PIDs are not the same. We need to find the Windows |
| # PID for our Cygwin process so we can match it later to any crash |
| # files we end up creating (which will be tagged with the Windows PID) |
| ps_process = self._executive.run_command(['ps', '-e'], error_handler=Executive.ignore_error) |
| for line in ps_process.splitlines(): |
| tokens = line.strip().split() |
| try: |
| cpid, ppid, pgid, winpid, tty, uid, stime, process_name = tokens |
| if process_name.endswith(name): |
| self._executive.pid_to_system_pid[int(cpid)] = int(winpid) |
| if int(pid) == int(cpid): |
| system_pid = int(winpid) |
| break |
| except ValueError, e: |
| pass |
| else: |
| wmi = win32com.client.GetObject('winmgmts:') |
| _log.debug('Querying WMI with "%{0}%"'.format(name)) |
| procs = wmi.ExecQuery('Select * from win32_process where name like "%{0}%"'.format(name)) |
| for proc in procs: |
| self._executive.pid_to_system_pid[int(proc.ProcessId)] = int(proc.ProcessId) |
| _log.debug("I see {0}: {1}".format(proc.Name, proc.ProcessId)) |
| if int(pid) == int(proc.ProcessId): |
| system_pid = int(proc.ProcessId) |
| break |
| |
| return system_pid |
| |
| |
| class WinCairoPort(WinPort): |
| port_name = "wincairo" |
| |
| VERSION_FALLBACK_ORDER = ["wincairo-xp", "wincairo-vista", "wincairo-7sp0", "wincairo-win10", "wincairo"] |
| |
| def default_baseline_search_path(self): |
| name = self._name.replace('-wk2', '') |
| fallback_names = self.VERSION_FALLBACK_ORDER[self.VERSION_FALLBACK_ORDER.index(name):-1] + [self.port_name] |
| fallback_names.append('win') |
| fallback_names.append('mac') |
| return map(self._webkit_baseline_path, fallback_names) |