| OLD | NEW |
| 1 # Copyright (C) 2012 Google Inc. All rights reserved. | 1 # Copyright (C) 2012 Google Inc. All rights reserved. |
| 2 # | 2 # |
| 3 # Redistribution and use in source and binary forms, with or without | 3 # Redistribution and use in source and binary forms, with or without |
| 4 # modification, are permitted provided that the following conditions are | 4 # modification, are permitted provided that the following conditions are |
| 5 # met: | 5 # met: |
| 6 # | 6 # |
| 7 # * Redistributions of source code must retain the above copyright | 7 # * Redistributions of source code must retain the above copyright |
| 8 # notice, this list of conditions and the following disclaimer. | 8 # notice, this list of conditions and the following disclaimer. |
| 9 # * Redistributions in binary form must reproduce the above | 9 # * Redistributions in binary form must reproduce the above |
| 10 # copyright notice, this list of conditions and the following disclaimer | 10 # copyright notice, this list of conditions and the following disclaimer |
| (...skipping 284 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 295 command_version = path_version | 295 command_version = path_version |
| 296 | 296 |
| 297 assert command_path, 'Unable to locate the "adb" command. Are you using
an Android checkout of Chromium?' | 297 assert command_path, 'Unable to locate the "adb" command. Are you using
an Android checkout of Chromium?' |
| 298 | 298 |
| 299 AndroidCommands._adb_command_path = command_path | 299 AndroidCommands._adb_command_path = command_path |
| 300 return command_path | 300 return command_path |
| 301 | 301 |
| 302 # Local private methods. | 302 # Local private methods. |
| 303 | 303 |
| 304 def _log_error(self, message): | 304 def _log_error(self, message): |
| 305 _log.error('[%s] %s' % (self._device_serial, message)) | 305 _log.error('[%s] %s', self._device_serial, message) |
| 306 | 306 |
| 307 def _log_info(self, message): | 307 def _log_info(self, message): |
| 308 _log.info('[%s] %s' % (self._device_serial, message)) | 308 _log.info('[%s] %s', self._device_serial, message) |
| 309 | 309 |
| 310 def _log_debug(self, message): | 310 def _log_debug(self, message): |
| 311 if self._debug_logging: | 311 if self._debug_logging: |
| 312 _log.debug('[%s] %s' % (self._device_serial, message)) | 312 _log.debug('[%s] %s', self._device_serial, message) |
| 313 | 313 |
| 314 @staticmethod | 314 @staticmethod |
| 315 def _determine_adb_version(adb_command_path, executive, debug_logging): | 315 def _determine_adb_version(adb_command_path, executive, debug_logging): |
| 316 re_version = re.compile('^.*version ([\d\.]+)') | 316 re_version = re.compile('^.*version ([\d\.]+)') |
| 317 try: | 317 try: |
| 318 output = executive.run_command([adb_command_path, 'version'], error_
handler=executive.ignore_error, | 318 output = executive.run_command([adb_command_path, 'version'], error_
handler=executive.ignore_error, |
| 319 debug_logging=debug_logging) | 319 debug_logging=debug_logging) |
| 320 except OSError: | 320 except OSError: |
| 321 return None | 321 return None |
| 322 | 322 |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 360 | 360 |
| 361 result = executive.run_command([AndroidCommands.adb_command_path(executi
ve, debug_logging=self._debug_logging), 'devices'], | 361 result = executive.run_command([AndroidCommands.adb_command_path(executi
ve, debug_logging=self._debug_logging), 'devices'], |
| 362 error_handler=executive.ignore_error, deb
ug_logging=self._debug_logging) | 362 error_handler=executive.ignore_error, deb
ug_logging=self._debug_logging) |
| 363 devices = re_device.findall(result) | 363 devices = re_device.findall(result) |
| 364 if not devices: | 364 if not devices: |
| 365 return [] | 365 return [] |
| 366 | 366 |
| 367 for device_serial in sorted(devices): | 367 for device_serial in sorted(devices): |
| 368 commands = AndroidCommands(executive, device_serial, self._debug_log
ging) | 368 commands = AndroidCommands(executive, device_serial, self._debug_log
ging) |
| 369 if self._battery_level_for_device(commands) < AndroidDevices.MINIMUM
_BATTERY_PERCENTAGE: | 369 if self._battery_level_for_device(commands) < AndroidDevices.MINIMUM
_BATTERY_PERCENTAGE: |
| 370 _log.warning('Device with serial "%s" skipped because it has les
s than %d percent battery.' | 370 _log.warning('Device with serial "%s" skipped because it has les
s than %d percent battery.', |
| 371 % (commands.get_serial(), AndroidDevices.MINIMUM_BA
TTERY_PERCENTAGE)) | 371 commands.get_serial(), AndroidDevices.MINIMUM_BATTE
RY_PERCENTAGE) |
| 372 continue | 372 continue |
| 373 | 373 |
| 374 if not self._is_device_screen_on(commands): | 374 if not self._is_device_screen_on(commands): |
| 375 _log.warning('Device with serial "%s" skipped because the screen
must be on.' % commands.get_serial()) | 375 _log.warning('Device with serial "%s" skipped because the screen
must be on.', commands.get_serial()) |
| 376 continue | 376 continue |
| 377 | 377 |
| 378 self._usable_devices.append(commands) | 378 self._usable_devices.append(commands) |
| 379 | 379 |
| 380 return self._usable_devices | 380 return self._usable_devices |
| 381 | 381 |
| 382 def get_device(self, executive, device_index): | 382 def get_device(self, executive, device_index): |
| 383 devices = self.usable_devices(executive) | 383 devices = self.usable_devices(executive) |
| 384 if device_index >= len(devices): | 384 if device_index >= len(devices): |
| 385 raise AssertionError('Device index exceeds number of usable devices.
') | 385 raise AssertionError('Device index exceeds number of usable devices.
') |
| 386 | 386 |
| 387 return devices[device_index] | 387 return devices[device_index] |
| 388 | 388 |
| 389 def is_device_prepared(self, device_serial): | 389 def is_device_prepared(self, device_serial): |
| 390 return device_serial in self._prepared_devices | 390 return device_serial in self._prepared_devices |
| 391 | 391 |
| 392 def set_device_prepared(self, device_serial): | 392 def set_device_prepared(self, device_serial): |
| 393 self._prepared_devices.append(device_serial) | 393 self._prepared_devices.append(device_serial) |
| 394 | 394 |
| 395 # Private methods | 395 # Private methods |
| 396 def _battery_level_for_device(self, commands): | 396 def _battery_level_for_device(self, commands): |
| 397 battery_status = commands.run(['shell', 'dumpsys', 'battery']) | 397 battery_status = commands.run(['shell', 'dumpsys', 'battery']) |
| 398 if 'Error' in battery_status or "Can't find service: battery" in battery
_status: | 398 if 'Error' in battery_status or "Can't find service: battery" in battery
_status: |
| 399 _log.warning('Unable to read the battery level from device with seri
al "%s".' % commands.get_serial()) | 399 _log.warning('Unable to read the battery level from device with seri
al "%s".', commands.get_serial()) |
| 400 return 0 | 400 return 0 |
| 401 | 401 |
| 402 return int(re.findall('level: (\d+)', battery_status)[0]) | 402 return int(re.findall('level: (\d+)', battery_status)[0]) |
| 403 | 403 |
| 404 def _is_device_screen_on(self, commands): | 404 def _is_device_screen_on(self, commands): |
| 405 power_status = commands.run(['shell', 'dumpsys', 'power']) | 405 power_status = commands.run(['shell', 'dumpsys', 'power']) |
| 406 return 'mScreenOn=true' in power_status or 'mScreenOn=SCREEN_ON_BIT' in
power_status or 'Display Power: state=ON' in power_status | 406 return 'mScreenOn=true' in power_status or 'mScreenOn=SCREEN_ON_BIT' in
power_status or 'Display Power: state=ON' in power_status |
| 407 | 407 |
| 408 | 408 |
| 409 class AndroidPort(base.Port): | 409 class AndroidPort(base.Port): |
| (...skipping 142 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 552 callback("[%s] %s" % (serial, msg)) | 552 callback("[%s] %s" % (serial, msg)) |
| 553 finally: | 553 finally: |
| 554 lock.release() | 554 lock.release() |
| 555 | 555 |
| 556 log_safely("preparing device", throttled=False) | 556 log_safely("preparing device", throttled=False) |
| 557 try: | 557 try: |
| 558 d._setup_test(log_safely) | 558 d._setup_test(log_safely) |
| 559 log_safely("device prepared", throttled=False) | 559 log_safely("device prepared", throttled=False) |
| 560 except (ScriptError, driver.DeviceFailure) as e: | 560 except (ScriptError, driver.DeviceFailure) as e: |
| 561 lock.acquire() | 561 lock.acquire() |
| 562 _log.warning("[%s] failed to prepare_device: %s" % (serial, str(
e))) | 562 _log.warning("[%s] failed to prepare_device: %s", serial, str(e)
) |
| 563 lock.release() | 563 lock.release() |
| 564 except KeyboardInterrupt: | 564 except KeyboardInterrupt: |
| 565 if pool: | 565 if pool: |
| 566 pool.terminate() | 566 pool.terminate() |
| 567 | 567 |
| 568 # FIXME: It would be nice if we knew how many workers we needed. | 568 # FIXME: It would be nice if we knew how many workers we needed. |
| 569 num_workers = self.default_child_processes() | 569 num_workers = self.default_child_processes() |
| 570 num_child_processes = int(self.get_option('child_processes')) | 570 num_child_processes = int(self.get_option('child_processes')) |
| 571 if num_child_processes: | 571 if num_child_processes: |
| 572 num_workers = min(num_workers, num_child_processes) | 572 num_workers = min(num_workers, num_child_processes) |
| (...skipping 28 matching lines...) Expand all Loading... |
| 601 | 601 |
| 602 def check_sys_deps(self, needs_http): | 602 def check_sys_deps(self, needs_http): |
| 603 for (font_dirs, font_file, package) in HOST_FONT_FILES: | 603 for (font_dirs, font_file, package) in HOST_FONT_FILES: |
| 604 exists = False | 604 exists = False |
| 605 for font_dir in font_dirs: | 605 for font_dir in font_dirs: |
| 606 font_path = font_dir + font_file | 606 font_path = font_dir + font_file |
| 607 if self._check_file_exists(font_path, '', more_logging=False): | 607 if self._check_file_exists(font_path, '', more_logging=False): |
| 608 exists = True | 608 exists = True |
| 609 break | 609 break |
| 610 if not exists: | 610 if not exists: |
| 611 _log.error('You are missing %s under %s. Try installing %s. See
build instructions.' % | 611 _log.error('You are missing %s under %s. Try installing %s. See
build instructions.', |
| 612 (font_file, font_dirs, package)) | 612 font_file, font_dirs, package) |
| 613 return test_run_results.SYS_DEPS_EXIT_STATUS | 613 return test_run_results.SYS_DEPS_EXIT_STATUS |
| 614 return test_run_results.OK_EXIT_STATUS | 614 return test_run_results.OK_EXIT_STATUS |
| 615 | 615 |
| 616 def requires_http_server(self): | 616 def requires_http_server(self): |
| 617 """Chromium Android runs tests on devices, and uses the HTTP server to | 617 """Chromium Android runs tests on devices, and uses the HTTP server to |
| 618 serve the actual layout tests to the test driver.""" | 618 serve the actual layout tests to the test driver.""" |
| 619 return True | 619 return True |
| 620 | 620 |
| 621 def start_http_server(self, additional_dirs, number_of_drivers): | 621 def start_http_server(self, additional_dirs, number_of_drivers): |
| 622 additional_dirs[PERF_TEST_PATH_PREFIX] = self.perf_tests_dir() | 622 additional_dirs[PERF_TEST_PATH_PREFIX] = self.perf_tests_dir() |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 691 def __init__(self, host, executable_path, output_dir, android_commands, symf
s_path, kallsyms_path, identifier=None): | 691 def __init__(self, host, executable_path, output_dir, android_commands, symf
s_path, kallsyms_path, identifier=None): |
| 692 super(AndroidPerf, self).__init__(host, executable_path, output_dir, "da
ta", identifier) | 692 super(AndroidPerf, self).__init__(host, executable_path, output_dir, "da
ta", identifier) |
| 693 self._android_commands = android_commands | 693 self._android_commands = android_commands |
| 694 self._perf_process = None | 694 self._perf_process = None |
| 695 self._symfs_path = symfs_path | 695 self._symfs_path = symfs_path |
| 696 self._kallsyms_path = kallsyms_path | 696 self._kallsyms_path = kallsyms_path |
| 697 | 697 |
| 698 def check_configuration(self): | 698 def check_configuration(self): |
| 699 # Check that perf is installed | 699 # Check that perf is installed |
| 700 if not self._android_commands.file_exists('/system/bin/perf'): | 700 if not self._android_commands.file_exists('/system/bin/perf'): |
| 701 _log.error("Cannot find /system/bin/perf on device %s" % self._andro
id_commands.get_serial()) | 701 _log.error("Cannot find /system/bin/perf on device %s", self._androi
d_commands.get_serial()) |
| 702 return False | 702 return False |
| 703 | 703 |
| 704 # Check that the device is a userdebug build (or at least has the necess
ary libraries). | 704 # Check that the device is a userdebug build (or at least has the necess
ary libraries). |
| 705 if self._android_commands.run(['shell', 'getprop', 'ro.build.type']).str
ip() != 'userdebug': | 705 if self._android_commands.run(['shell', 'getprop', 'ro.build.type']).str
ip() != 'userdebug': |
| 706 _log.error("Device %s is not flashed with a userdebug build of Andro
id" % self._android_commands.get_serial()) | 706 _log.error("Device %s is not flashed with a userdebug build of Andro
id", self._android_commands.get_serial()) |
| 707 return False | 707 return False |
| 708 | 708 |
| 709 # FIXME: Check that the binary actually is perf-able (has stackframe poi
nters)? | 709 # FIXME: Check that the binary actually is perf-able (has stackframe poi
nters)? |
| 710 # objdump -s a function and make sure it modifies the fp? | 710 # objdump -s a function and make sure it modifies the fp? |
| 711 # Instruct users to rebuild after export GYP_DEFINES="profiling=1 $GYP_D
EFINES" | 711 # Instruct users to rebuild after export GYP_DEFINES="profiling=1 $GYP_D
EFINES" |
| 712 return True | 712 return True |
| 713 | 713 |
| 714 def print_setup_instructions(self): | 714 def print_setup_instructions(self): |
| 715 _log.error(""" | 715 _log.error(""" |
| 716 perf on android requires a 'userdebug' build of Android, see: | 716 perf on android requires a 'userdebug' build of Android, see: |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 759 self._cached_perf_host_path = self._find_perfhost_binary() | 759 self._cached_perf_host_path = self._find_perfhost_binary() |
| 760 return self._cached_perf_host_path | 760 return self._cached_perf_host_path |
| 761 | 761 |
| 762 def _first_ten_lines_of_profile(self, perf_output): | 762 def _first_ten_lines_of_profile(self, perf_output): |
| 763 match = re.search("^#[^\n]*\n((?: [^\n]*\n){1,10})", perf_output, re.MUL
TILINE) | 763 match = re.search("^#[^\n]*\n((?: [^\n]*\n){1,10})", perf_output, re.MUL
TILINE) |
| 764 return match.group(1) if match else None | 764 return match.group(1) if match else None |
| 765 | 765 |
| 766 def profile_after_exit(self): | 766 def profile_after_exit(self): |
| 767 perf_exitcode = self._perf_process.wait() | 767 perf_exitcode = self._perf_process.wait() |
| 768 if perf_exitcode != 0: | 768 if perf_exitcode != 0: |
| 769 _log.debug("Perf failed (exit code: %i), can't process results." % p
erf_exitcode) | 769 _log.debug("Perf failed (exit code: %i), can't process results.", pe
rf_exitcode) |
| 770 return | 770 return |
| 771 | 771 |
| 772 self._android_commands.pull('/data/perf.data', self._output_path) | 772 self._android_commands.pull('/data/perf.data', self._output_path) |
| 773 | 773 |
| 774 perfhost_path = self._perfhost_path() | 774 perfhost_path = self._perfhost_path() |
| 775 perfhost_report_command = [ | 775 perfhost_report_command = [ |
| 776 'report', | 776 'report', |
| 777 '--input', self._output_path, | 777 '--input', self._output_path, |
| 778 '--symfs', self._symfs_path, | 778 '--symfs', self._symfs_path, |
| 779 '--kallsyms', self._kallsyms_path, | 779 '--kallsyms', self._kallsyms_path, |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 848 | 848 |
| 849 def _update_kallsyms_cache(self, output_dir): | 849 def _update_kallsyms_cache(self, output_dir): |
| 850 kallsyms_name = "%s-kallsyms" % self._android_commands.get_serial() | 850 kallsyms_name = "%s-kallsyms" % self._android_commands.get_serial() |
| 851 kallsyms_cache_path = self._port.host.filesystem.join(output_dir, kallsy
ms_name) | 851 kallsyms_cache_path = self._port.host.filesystem.join(output_dir, kallsy
ms_name) |
| 852 | 852 |
| 853 self._android_commands.restart_as_root() | 853 self._android_commands.restart_as_root() |
| 854 | 854 |
| 855 saved_kptr_restrict = self._android_commands.run(['shell', 'cat', KPTR_R
ESTRICT_PATH]).strip() | 855 saved_kptr_restrict = self._android_commands.run(['shell', 'cat', KPTR_R
ESTRICT_PATH]).strip() |
| 856 self._android_commands.run(['shell', 'echo', '0', '>', KPTR_RESTRICT_PAT
H]) | 856 self._android_commands.run(['shell', 'echo', '0', '>', KPTR_RESTRICT_PAT
H]) |
| 857 | 857 |
| 858 _log.debug("Updating kallsyms file (%s) from device" % kallsyms_cache_pa
th) | 858 _log.debug("Updating kallsyms file (%s) from device", kallsyms_cache_pat
h) |
| 859 self._android_commands.pull("/proc/kallsyms", kallsyms_cache_path) | 859 self._android_commands.pull("/proc/kallsyms", kallsyms_cache_path) |
| 860 | 860 |
| 861 self._android_commands.run(['shell', 'echo', saved_kptr_restrict, '>', K
PTR_RESTRICT_PATH]) | 861 self._android_commands.run(['shell', 'echo', saved_kptr_restrict, '>', K
PTR_RESTRICT_PATH]) |
| 862 | 862 |
| 863 return kallsyms_cache_path | 863 return kallsyms_cache_path |
| 864 | 864 |
| 865 def _find_or_create_symfs(self): | 865 def _find_or_create_symfs(self): |
| 866 env = self._port.host.environ.copy() | 866 env = self._port.host.environ.copy() |
| 867 fs = self._port.host.filesystem | 867 fs = self._port.host.filesystem |
| 868 | 868 |
| 869 if 'ANDROID_SYMFS' in env: | 869 if 'ANDROID_SYMFS' in env: |
| 870 symfs_path = env['ANDROID_SYMFS'] | 870 symfs_path = env['ANDROID_SYMFS'] |
| 871 else: | 871 else: |
| 872 symfs_path = fs.join(self._port.results_directory(), 'symfs') | 872 symfs_path = fs.join(self._port.results_directory(), 'symfs') |
| 873 _log.debug("ANDROID_SYMFS not set, using %s" % symfs_path) | 873 _log.debug("ANDROID_SYMFS not set, using %s", symfs_path) |
| 874 | 874 |
| 875 # find the installed path, and the path of the symboled built library | 875 # find the installed path, and the path of the symboled built library |
| 876 # FIXME: We should get the install path from the device! | 876 # FIXME: We should get the install path from the device! |
| 877 symfs_library_path = fs.join(symfs_path, "data/app-lib/%s-1/%s" % | 877 symfs_library_path = fs.join(symfs_path, "data/app-lib/%s-1/%s" % |
| 878 (self._driver_details.package_name(), self.
_driver_details.library_name())) | 878 (self._driver_details.package_name(), self.
_driver_details.library_name())) |
| 879 built_library_path = self._port._build_path('lib', self._driver_details.
library_name()) | 879 built_library_path = self._port._build_path('lib', self._driver_details.
library_name()) |
| 880 assert fs.exists(built_library_path) | 880 assert fs.exists(built_library_path) |
| 881 | 881 |
| 882 # FIXME: Ideally we'd check the sha1's first and make a soft-link instea
d | 882 # FIXME: Ideally we'd check the sha1's first and make a soft-link instea
d |
| 883 # of copying (since we probably never care about windows). | 883 # of copying (since we probably never care about windows). |
| 884 _log.debug("Updating symfs library (%s) from built copy (%s)" % (symfs_l
ibrary_path, built_library_path)) | 884 _log.debug("Updating symfs library (%s) from built copy (%s)", symfs_lib
rary_path, built_library_path) |
| 885 fs.maybe_make_directory(fs.dirname(symfs_library_path)) | 885 fs.maybe_make_directory(fs.dirname(symfs_library_path)) |
| 886 fs.copyfile(built_library_path, symfs_library_path) | 886 fs.copyfile(built_library_path, symfs_library_path) |
| 887 | 887 |
| 888 return symfs_path | 888 return symfs_path |
| 889 | 889 |
| 890 def _setup_md5sum_and_push_data_if_needed(self, log_callback): | 890 def _setup_md5sum_and_push_data_if_needed(self, log_callback): |
| 891 self._md5sum_path = self._port.path_to_md5sum() | 891 self._md5sum_path = self._port.path_to_md5sum() |
| 892 if not self._android_commands.file_exists(MD5SUM_DEVICE_PATH): | 892 if not self._android_commands.file_exists(MD5SUM_DEVICE_PATH): |
| 893 if not self._android_commands.push(self._md5sum_path, MD5SUM_DEVICE_
PATH): | 893 if not self._android_commands.push(self._md5sum_path, MD5SUM_DEVICE_
PATH): |
| 894 self._abort('Could not push md5sum to device') | 894 self._abort('Could not push md5sum to device') |
| (...skipping 24 matching lines...) Expand all Loading... |
| 919 self._android_commands.mkdir(self._driver_details.device_directory(), ch
mod='777') | 919 self._android_commands.mkdir(self._driver_details.device_directory(), ch
mod='777') |
| 920 self._android_commands.mkdir(self._driver_details.device_fifo_directory(
), chmod='777') | 920 self._android_commands.mkdir(self._driver_details.device_fifo_directory(
), chmod='777') |
| 921 | 921 |
| 922 # Make sure that the disk cache on the device resets to a clean state. | 922 # Make sure that the disk cache on the device resets to a clean state. |
| 923 self._android_commands.run(['shell', 'rm', '-r', self._driver_details.de
vice_cache_directory()]) | 923 self._android_commands.run(['shell', 'rm', '-r', self._driver_details.de
vice_cache_directory()]) |
| 924 | 924 |
| 925 # Mark this device as having been set up. | 925 # Mark this device as having been set up. |
| 926 self._android_devices.set_device_prepared(self._android_commands.get_ser
ial()) | 926 self._android_devices.set_device_prepared(self._android_commands.get_ser
ial()) |
| 927 | 927 |
| 928 def _log_error(self, message): | 928 def _log_error(self, message): |
| 929 _log.error('[%s] %s' % (self._android_commands.get_serial(), message)) | 929 _log.error('[%s] %s', self._android_commands.get_serial(), message) |
| 930 | 930 |
| 931 def _log_warning(self, message): | 931 def _log_warning(self, message): |
| 932 _log.warning('[%s] %s' % (self._android_commands.get_serial(), message)) | 932 _log.warning('[%s] %s', self._android_commands.get_serial(), message) |
| 933 | 933 |
| 934 def _log_debug(self, message): | 934 def _log_debug(self, message): |
| 935 if self._debug_logging: | 935 if self._debug_logging: |
| 936 _log.debug('[%s] %s' % (self._android_commands.get_serial(), message
)) | 936 _log.debug('[%s] %s', self._android_commands.get_serial(), message) |
| 937 | 937 |
| 938 def _abort(self, message): | 938 def _abort(self, message): |
| 939 self._device_failed = True | 939 self._device_failed = True |
| 940 raise driver.DeviceFailure('[%s] %s' % (self._android_commands.get_seria
l(), message)) | 940 raise driver.DeviceFailure('[%s] %s' % (self._android_commands.get_seria
l(), message)) |
| 941 | 941 |
| 942 @staticmethod | 942 @staticmethod |
| 943 def _extract_hashes_from_md5sum_output(md5sum_output): | 943 def _extract_hashes_from_md5sum_output(md5sum_output): |
| 944 assert md5sum_output | 944 assert md5sum_output |
| 945 return [line.split(' ')[0] for line in md5sum_output] | 945 return [line.split(' ')[0] for line in md5sum_output] |
| 946 | 946 |
| (...skipping 360 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1307 return command | 1307 return command |
| 1308 | 1308 |
| 1309 def _read_prompt(self, deadline): | 1309 def _read_prompt(self, deadline): |
| 1310 last_char = '' | 1310 last_char = '' |
| 1311 while True: | 1311 while True: |
| 1312 current_char = self._server_process.read_stdout(deadline, 1) | 1312 current_char = self._server_process.read_stdout(deadline, 1) |
| 1313 if current_char == ' ': | 1313 if current_char == ' ': |
| 1314 if last_char in ('#', '$'): | 1314 if last_char in ('#', '$'): |
| 1315 return | 1315 return |
| 1316 last_char = current_char | 1316 last_char = current_char |
| OLD | NEW |