android_build_server_helper.py 2.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879
  1. # Copyright 2024 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. import contextlib
  5. import os
  6. import sys
  7. import signal
  8. import subprocess
  9. import gclient_paths
  10. # Keeps track of whether our SIGINT handler was called.
  11. _is_canceled = False
  12. def _register_build_id(local_dev_server_path, build_id, out_dir):
  13. subprocess.run([
  14. local_dev_server_path, '--register-build-id', build_id, '--builder-pid',
  15. str(os.getpid()), '--output-directory',
  16. os.path.abspath(out_dir)
  17. ])
  18. def _print_status(local_dev_server_path, build_id):
  19. subprocess.run([local_dev_server_path, '--print-status', build_id])
  20. def _get_server_path():
  21. src_dir = gclient_paths.GetPrimarySolutionPath()
  22. return os.path.join(src_dir, 'build/android/fast_local_dev_server.py')
  23. def _set_signal_handler(local_dev_server_path, build_id):
  24. original_sigint_handler = signal.getsignal(signal.SIGINT)
  25. def _kill_handler(signum, frame):
  26. global _is_canceled
  27. _is_canceled = True
  28. # Cancel the pending build tasks if user CTRL+c early.
  29. print('🛑 Canceling pending build_server tasks', file=sys.stderr)
  30. subprocess.run([local_dev_server_path, '--cancel-build', build_id])
  31. original_sigint_handler(signum, frame)
  32. signal.signal(signal.SIGINT, _kill_handler)
  33. def _start_server(local_dev_server_path):
  34. subprocess.Popen([local_dev_server_path, '--exit-on-idle', '--quiet'],
  35. start_new_session=True)
  36. def _set_tty_env():
  37. # If the caller explicitly set this environment variable, just use it
  38. # instead of failing.
  39. if "AUTONINJA_STDOUT_NAME" in os.environ:
  40. return True
  41. stdout_name = os.readlink('/proc/self/fd/1')
  42. # Anonymous pipes can't be opened. These look like "pipe:[394765110]".
  43. ret = os.path.exists(stdout_name)
  44. if ret:
  45. os.environ.setdefault("AUTONINJA_STDOUT_NAME", stdout_name)
  46. return ret
  47. @contextlib.contextmanager
  48. def build_server_context(build_id, out_dir, use_android_build_server=False):
  49. if not use_android_build_server or not _set_tty_env():
  50. yield
  51. return
  52. server_path = _get_server_path()
  53. _start_server(server_path)
  54. # Tell the build server about us.
  55. _register_build_id(server_path, build_id, out_dir)
  56. _set_signal_handler(server_path, build_id)
  57. yield
  58. # No need to print status if we CTRL+Ced out.
  59. if (not _is_canceled):
  60. _print_status(server_path, build_id)