runner_exceptions.py 2.6 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182
  1. # Copyright 2020 The Chromium Authors. All rights reserved.
  2. # Use of this source code is governed by a BSD-style license that can be
  3. # found in the LICENSE file.
  4. """Converts exceptions to return codes and prints error messages.
  5. This makes it easier to query build tables for particular error types as
  6. exit codes are visible to queries while exception stack traces are not."""
  7. import errno
  8. import fcntl
  9. import logging
  10. import os
  11. import subprocess
  12. import sys
  13. import traceback
  14. from device_target import ProvisionDeviceException
  15. from target import FuchsiaTargetException
  16. def _PrintException(value, trace):
  17. """Prints stack trace and error message for the current exception."""
  18. traceback.print_tb(trace)
  19. print(str(value))
  20. def IsStdoutBlocking():
  21. """Returns True if sys.stdout is blocking or False if non-blocking.
  22. sys.stdout should always be blocking. Non-blocking is associated with
  23. intermittent IOErrors (crbug.com/1080858).
  24. """
  25. nonblocking = fcntl.fcntl(sys.stdout, fcntl.F_GETFL) & os.O_NONBLOCK
  26. return not nonblocking
  27. def HandleExceptionAndReturnExitCode():
  28. """Maps the current exception to a return code and prints error messages.
  29. Mapped exception types are assigned blocks of 8 return codes starting at 64.
  30. The choice of 64 as the starting code is based on the Advanced Bash-Scripting
  31. Guide (http://tldp.org/LDP/abs/html/exitcodes.html).
  32. A generic exception is mapped to the start of the block. More specific
  33. exceptions are mapped to numbers inside the block. For example, a
  34. FuchsiaTargetException is mapped to return code 64, unless it involves SSH
  35. in which case it is mapped to return code 65.
  36. Exceptions not specifically mapped go to return code 1.
  37. Returns the mapped return code."""
  38. (type, value, trace) = sys.exc_info()
  39. _PrintException(value, trace)
  40. if type is FuchsiaTargetException:
  41. if 'ssh' in str(value).lower():
  42. print('Error: FuchsiaTargetException: SSH to Fuchsia target failed.')
  43. return 65
  44. return 64
  45. elif type is IOError:
  46. if value.errno == errno.EAGAIN:
  47. logging.info('Python print to sys.stdout probably failed')
  48. if not IsStdoutBlocking():
  49. logging.warn('sys.stdout is non-blocking')
  50. return 73
  51. return 72
  52. elif type is subprocess.CalledProcessError:
  53. if os.path.basename(value.cmd[0]) == 'scp':
  54. print('Error: scp operation failed - %s' % str(value))
  55. return 81
  56. if os.path.basename(value.cmd[0]) == 'qemu-img':
  57. print('Error: qemu-img fuchsia image generation failed.')
  58. return 82
  59. return 80
  60. elif type is ProvisionDeviceException:
  61. print('Error: Failed to pave device')
  62. return 90
  63. else:
  64. return 1