blob: 260bb45971e11736d83681d00defa3fa49e496cb [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
10import os
11import subprocess
12import sys
13
14import ninja
15import gclient_paths
16
17
18def find_reclient_bin_dir():
19 tools_path = gclient_paths.GetBuildtoolsPath()
20 if not tools_path:
21 return None
22
23 reclient_bin_dir = os.path.join(tools_path, 'reclient')
24 if os.path.isdir(reclient_bin_dir):
25 return reclient_bin_dir
26 return None
27
28
29def find_reclient_cfg():
30 tools_path = gclient_paths.GetBuildtoolsPath()
31 if not tools_path:
32 return None
33
34 reclient_cfg = os.path.join(tools_path, 'reclient_cfgs', 'reproxy.cfg')
35 if os.path.isfile(reclient_cfg):
36 return reclient_cfg
37 return None
38
39
40def run(cmd_args):
41 if os.environ.get('NINJA_SUMMARIZE_BUILD') == '1':
42 print(' '.join(cmd_args))
43 return subprocess.call(cmd_args)
44
45
46def start_reproxy(reclient_cfg, reclient_bin_dir):
47 return run([
48 os.path.join(reclient_bin_dir, 'bootstrap'),
49 '--re_proxy=' + os.path.join(reclient_bin_dir, 'reproxy'),
50 '--cfg=' + reclient_cfg
51 ])
52
53
54def stop_reproxy(reclient_cfg, reclient_bin_dir):
55 return run([
56 os.path.join(reclient_bin_dir, 'bootstrap'), '--shutdown',
57 '--cfg=' + reclient_cfg
58 ])
59
60
Ben Segallc4efd8a2023-02-13 17:17:33 +000061def find_rel_ninja_out_dir(args):
62 # Ninja uses getopt_long, which allow to intermix non-option arguments.
63 # To leave non supported parameters untouched, we do not use getopt.
64 for index, arg in enumerate(args[1:]):
65 if arg == '-C':
66 # + 1 to get the next argument and +1 because we trimmed off args[0]
67 return args[index + 2]
68 if arg.startswith('-C'):
69 # Support -Cout/Default
70 return arg[2:]
71 return '.'
72
73
74def set_reproxy_path_flags(out_dir):
75 """Helper to setup the logs and cache directories for reclient
76
77 Creates the following directory structure:
78 out_dir/
79 .reproxy_tmp/
80 logs/
81 cache/
82
83 The following env vars are set if not already set:
84 RBE_output_dir=out_dir/.reproxy_tmp/logs
85 RBE_proxy_log_dir=out_dir/.reproxy_tmp/logs
86 RBE_log_dir=out_dir/.reproxy_tmp/logs
87 RBE_cache_dir=out_dir/.reproxy_tmp/cache
88 *Nix Only:
89 RBE_server_address=unix://out_dir/.reproxy_tmp/reproxy.sock
90 Windows Only:
91 RBE_server_address=pipe://out_dir/.reproxy_tmp/reproxy.pipe
92 """
93 tmp_dir = os.path.abspath(os.path.join(out_dir, '.reproxy_tmp'))
94 os.makedirs(tmp_dir, exist_ok=True)
95 log_dir = os.path.join(tmp_dir, 'logs')
96 os.makedirs(log_dir, exist_ok=True)
97 os.environ.setdefault("RBE_output_dir", log_dir)
98 os.environ.setdefault("RBE_proxy_log_dir", log_dir)
99 os.environ.setdefault("RBE_log_dir", log_dir)
100 cache_dir = os.path.join(tmp_dir, 'cache')
101 os.makedirs(cache_dir, exist_ok=True)
102 os.environ.setdefault("RBE_cache_dir", cache_dir)
103 if sys.platform.startswith('win'):
104 os.environ.setdefault("RBE_server_address",
105 "pipe://%s/reproxy.pipe" % tmp_dir)
106 else:
107 os.environ.setdefault("RBE_server_address",
108 "unix://%s/reproxy.sock" % tmp_dir)
109
110
Ben Segalleb2866e2023-01-20 20:14:44 +0000111def main(argv):
112 # If use_remoteexec is set, but the reclient binaries or configs don't
113 # exist, display an error message and stop. Otherwise, the build will
114 # attempt to run with rewrapper wrapping actions, but will fail with
115 # possible non-obvious problems.
116 # As of January 2023, dev builds with reclient are not supported, so
117 # indicate that use_goma should be swapped for use_remoteexec. This
118 # message will be changed when dev builds are fully supported.
119 reclient_bin_dir = find_reclient_bin_dir()
120 reclient_cfg = find_reclient_cfg()
121 if reclient_bin_dir is None or reclient_cfg is None:
122 print(("Build is configured to use reclient but necessary binaries "
123 "or config files can't be found. Developer builds with "
124 "reclient are not yet supported. Try regenerating your "
125 "build with use_goma in place of use_remoteexec for now."),
126 file=sys.stderr)
127 return 1
Ben Segallc4efd8a2023-02-13 17:17:33 +0000128 try:
129 set_reproxy_path_flags(find_rel_ninja_out_dir(argv))
130 except OSError:
131 print("Error creating reproxy_tmp in output dir", file=sys.stderr)
132 return 1
Ben Segalleb2866e2023-01-20 20:14:44 +0000133 reproxy_ret_code = start_reproxy(reclient_cfg, reclient_bin_dir)
134 if reproxy_ret_code != 0:
135 return reproxy_ret_code
136 try:
137 return ninja.main(argv)
138 except KeyboardInterrupt:
Ben Segall6a710522023-02-24 04:52:05 +0000139 print("Caught User Interrupt", file=sys.stderr)
Ben Segalleb2866e2023-01-20 20:14:44 +0000140 # Suppress python stack trace if ninja is interrupted
141 return 1
142 finally:
Ben Segall6a710522023-02-24 04:52:05 +0000143 print("Shutting down reproxy...", file=sys.stderr)
Ben Segalleb2866e2023-01-20 20:14:44 +0000144 stop_reproxy(reclient_cfg, reclient_bin_dir)
145
146
147if __name__ == '__main__':
148 sys.exit(main(sys.argv))