blob: 1ed00d83af72bf8ceaae358d2f6edc71141079e6 [file] [log] [blame]
Ben Segalleb2866e2023-01-20 20:14:44 +00001#!/usr/bin/env python3
2# Copyright 2023 The Chromium Authors. All rights reserved.
3# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
5"""This script is a wrapper around the ninja.py script that also
6handles the client lifecycle safely. It will automatically start
7reproxy before running ninja and stop reproxy when ninja stops
8for any reason eg. build completes, keyboard interupt etc."""
9
Ben Segall87fa6102023-03-02 01:53:58 +000010import hashlib
Ben Segalleb2866e2023-01-20 20:14:44 +000011import os
12import subprocess
13import sys
14
15import ninja
16import gclient_paths
17
18
19def find_reclient_bin_dir():
20 tools_path = gclient_paths.GetBuildtoolsPath()
21 if not tools_path:
22 return None
23
24 reclient_bin_dir = os.path.join(tools_path, 'reclient')
25 if os.path.isdir(reclient_bin_dir):
26 return reclient_bin_dir
27 return None
28
29
30def find_reclient_cfg():
31 tools_path = gclient_paths.GetBuildtoolsPath()
32 if not tools_path:
33 return None
34
35 reclient_cfg = os.path.join(tools_path, 'reclient_cfgs', 'reproxy.cfg')
36 if os.path.isfile(reclient_cfg):
37 return reclient_cfg
38 return None
39
40
41def run(cmd_args):
42 if os.environ.get('NINJA_SUMMARIZE_BUILD') == '1':
43 print(' '.join(cmd_args))
44 return subprocess.call(cmd_args)
45
46
47def start_reproxy(reclient_cfg, reclient_bin_dir):
48 return run([
49 os.path.join(reclient_bin_dir, 'bootstrap'),
50 '--re_proxy=' + os.path.join(reclient_bin_dir, 'reproxy'),
51 '--cfg=' + reclient_cfg
52 ])
53
54
55def stop_reproxy(reclient_cfg, reclient_bin_dir):
56 return run([
57 os.path.join(reclient_bin_dir, 'bootstrap'), '--shutdown',
58 '--cfg=' + reclient_cfg
59 ])
60
61
Ben Segallc4efd8a2023-02-13 17:17:33 +000062def find_rel_ninja_out_dir(args):
63 # Ninja uses getopt_long, which allow to intermix non-option arguments.
64 # To leave non supported parameters untouched, we do not use getopt.
65 for index, arg in enumerate(args[1:]):
66 if arg == '-C':
67 # + 1 to get the next argument and +1 because we trimmed off args[0]
68 return args[index + 2]
69 if arg.startswith('-C'):
70 # Support -Cout/Default
71 return arg[2:]
72 return '.'
73
74
Ben Segall9e36ef62023-04-18 22:09:28 +000075def set_reproxy_path_flags(out_dir, make_dirs=True):
Ben Segallc4efd8a2023-02-13 17:17:33 +000076 """Helper to setup the logs and cache directories for reclient
77
Ben Segall9e36ef62023-04-18 22:09:28 +000078 Creates the following directory structure if make_dirs is true:
Ben Segallc4efd8a2023-02-13 17:17:33 +000079 out_dir/
80 .reproxy_tmp/
81 logs/
82 cache/
83
84 The following env vars are set if not already set:
85 RBE_output_dir=out_dir/.reproxy_tmp/logs
86 RBE_proxy_log_dir=out_dir/.reproxy_tmp/logs
87 RBE_log_dir=out_dir/.reproxy_tmp/logs
88 RBE_cache_dir=out_dir/.reproxy_tmp/cache
89 *Nix Only:
90 RBE_server_address=unix://out_dir/.reproxy_tmp/reproxy.sock
91 Windows Only:
Ben Segall87fa6102023-03-02 01:53:58 +000092 RBE_server_address=pipe://md5(out_dir/.reproxy_tmp)/reproxy.pipe
Ben Segallc4efd8a2023-02-13 17:17:33 +000093 """
94 tmp_dir = os.path.abspath(os.path.join(out_dir, '.reproxy_tmp'))
Ben Segallc4efd8a2023-02-13 17:17:33 +000095 log_dir = os.path.join(tmp_dir, 'logs')
Ben Segall9e36ef62023-04-18 22:09:28 +000096 cache_dir = os.path.join(tmp_dir, 'cache')
97 if make_dirs:
98 os.makedirs(tmp_dir, exist_ok=True)
99 os.makedirs(log_dir, exist_ok=True)
100 os.makedirs(cache_dir, exist_ok=True)
Ben Segallc4efd8a2023-02-13 17:17:33 +0000101 os.environ.setdefault("RBE_output_dir", log_dir)
102 os.environ.setdefault("RBE_proxy_log_dir", log_dir)
103 os.environ.setdefault("RBE_log_dir", log_dir)
Ben Segallc4efd8a2023-02-13 17:17:33 +0000104 os.environ.setdefault("RBE_cache_dir", cache_dir)
105 if sys.platform.startswith('win'):
Ben Segall87fa6102023-03-02 01:53:58 +0000106 pipe_dir = hashlib.md5(tmp_dir.encode()).hexdigest()
Ben Segallc4efd8a2023-02-13 17:17:33 +0000107 os.environ.setdefault("RBE_server_address",
Ben Segall87fa6102023-03-02 01:53:58 +0000108 "pipe://%s/reproxy.pipe" % pipe_dir)
Ben Segallc4efd8a2023-02-13 17:17:33 +0000109 else:
110 os.environ.setdefault("RBE_server_address",
111 "unix://%s/reproxy.sock" % tmp_dir)
112
113
Ben Segalleb2866e2023-01-20 20:14:44 +0000114def main(argv):
115 # If use_remoteexec is set, but the reclient binaries or configs don't
116 # exist, display an error message and stop. Otherwise, the build will
117 # attempt to run with rewrapper wrapping actions, but will fail with
118 # possible non-obvious problems.
119 # As of January 2023, dev builds with reclient are not supported, so
120 # indicate that use_goma should be swapped for use_remoteexec. This
121 # message will be changed when dev builds are fully supported.
122 reclient_bin_dir = find_reclient_bin_dir()
123 reclient_cfg = find_reclient_cfg()
124 if reclient_bin_dir is None or reclient_cfg is None:
125 print(("Build is configured to use reclient but necessary binaries "
126 "or config files can't be found. Developer builds with "
127 "reclient are not yet supported. Try regenerating your "
128 "build with use_goma in place of use_remoteexec for now."),
129 file=sys.stderr)
130 return 1
Ben Segallc4efd8a2023-02-13 17:17:33 +0000131 try:
132 set_reproxy_path_flags(find_rel_ninja_out_dir(argv))
133 except OSError:
134 print("Error creating reproxy_tmp in output dir", file=sys.stderr)
135 return 1
Ben Segalleb2866e2023-01-20 20:14:44 +0000136 reproxy_ret_code = start_reproxy(reclient_cfg, reclient_bin_dir)
137 if reproxy_ret_code != 0:
138 return reproxy_ret_code
139 try:
140 return ninja.main(argv)
141 except KeyboardInterrupt:
Ben Segall6a710522023-02-24 04:52:05 +0000142 print("Caught User Interrupt", file=sys.stderr)
Ben Segalleb2866e2023-01-20 20:14:44 +0000143 # Suppress python stack trace if ninja is interrupted
144 return 1
145 finally:
Ben Segall6a710522023-02-24 04:52:05 +0000146 print("Shutting down reproxy...", file=sys.stderr)
Ben Segalleb2866e2023-01-20 20:14:44 +0000147 stop_reproxy(reclient_cfg, reclient_bin_dir)
148
149
150if __name__ == '__main__':
151 sys.exit(main(sys.argv))