blob: 7977dca62b2324feaf945e60c320b9c5dee5ad8e [file] [log] [blame]
Rob Mohr3b7da062020-04-30 14:30:57 -07001# Copyright 2020 The Pigweed Authors
Rob Mohrb671bc72019-12-13 08:36:15 -08002#
3# Licensed under the Apache License, Version 2.0 (the "License"); you may not
4# use this file except in compliance with the License. You may obtain a copy of
5# the License at
6#
7# https://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12# License for the specific language governing permissions and limitations under
13# the License.
14"""Environment utility functions.
15
16Usage:
Rob Mohr500364a2023-02-01 15:05:30 +000017env = api.environment.initialize(checkout, env_options)
Rob Mohrfaa377f2022-01-19 14:38:36 -080018with env():
Rob Mohrb671bc72019-12-13 08:36:15 -080019 ...
20"""
21
Rob Mohr758a4722024-05-08 22:03:16 +000022from __future__ import annotations
23
Rob Mohr21f15eb2020-09-09 10:10:39 -070024import contextlib
Rob Mohr465feb32023-07-27 01:15:24 +000025import dataclasses
Rob Mohr59a9b1a2020-11-10 14:49:43 -080026import pprint
Rob Mohr758a4722024-05-08 22:03:16 +000027from typing import TYPE_CHECKING
Rob Mohr21f15eb2020-09-09 10:10:39 -070028
Rob Mohrfaa377f2022-01-19 14:38:36 -080029from PB.recipe_modules.pigweed.environment.options import Options
Rob Mohr758a4722024-05-08 22:03:16 +000030from recipe_engine import recipe_api
Rob Mohrfaa377f2022-01-19 14:38:36 -080031
Rob Mohr758a4722024-05-08 22:03:16 +000032if TYPE_CHECKING: # pragma: no cover
33 from recipe_engine import config_types, engine_types
34 from RECIPE_MODULES.pigweed.checkout import api as checkout_api
Rob Mohrb671bc72019-12-13 08:36:15 -080035
36
Rob Mohr465feb32023-07-27 01:15:24 +000037@dataclasses.dataclass
Rob Mohr82c0e352022-07-27 20:57:40 +000038class Environment:
Rob Mohrc16bf4b2024-03-06 19:59:03 +000039 api: recipe_api.RecipeApi
Rob Mohr465feb32023-07-27 01:15:24 +000040 dir: config_types.Path
Rob Mohrc16bf4b2024-03-06 19:59:03 +000041 checkout: checkout_api.CheckoutContext
42 prefixes: dict[str, list[str]] = dataclasses.field(default_factory=dict)
43 suffixes: dict[str, list[str]] = dataclasses.field(default_factory=dict)
44 env: dict[str, str] = dataclasses.field(default_factory=dict)
45 override_gn_args: dict = dataclasses.field(default_factory=dict)
Rob Mohrfaa377f2022-01-19 14:38:36 -080046
47 @contextlib.contextmanager
48 def __call__(self):
Rob Mohr18d0ae92023-11-17 19:37:44 +000049 with self.api.macos_sdk():
50 # Using reversed() because things that are added later in
51 # environment setup need to override things that came earlier.
52 with self.api.context(
53 env_prefixes={k: reversed(v) for k, v in self.prefixes.items()},
54 env_suffixes=self.suffixes,
55 env=self.env,
56 ):
Rob Mohrfaa377f2022-01-19 14:38:36 -080057 yield self
58
Rob Mohrc16bf4b2024-03-06 19:59:03 +000059 def __getattr__(self, name) -> str:
Rob Mohrfaa377f2022-01-19 14:38:36 -080060 if name not in self.env:
61 raise AttributeError(name)
62
63 return self.env.get(name)
Rob Mohrb671bc72019-12-13 08:36:15 -080064
65
Rob Mohrc16bf4b2024-03-06 19:59:03 +000066def path(
67 relative_path: config_types.Path,
68 checkout: checkout_api.CheckoutContext,
69) -> config_types.Path:
Rob Mohr0567a302023-09-19 16:19:42 +000070 parts = [x for x in relative_path.split('/') if x not in ('.', u'.')]
71 if parts:
Rob Mohr90fe7d82024-04-16 18:01:15 +000072 return checkout.root.joinpath(*parts)
Rob Mohr0567a302023-09-19 16:19:42 +000073 else:
74 return checkout.root # pragma: no cover
75
76
Rob Mohrb671bc72019-12-13 08:36:15 -080077class EnvironmentApi(recipe_api.RecipeApi):
Rob Mohr57204602020-09-23 08:41:18 -070078 """Environment utility functions."""
Rob Mohrb671bc72019-12-13 08:36:15 -080079
Rob Mohrd260a4e2023-11-13 19:00:16 +000080 Environment = Environment
81
Rob Mohrc16bf4b2024-03-06 19:59:03 +000082 def _init_platform(self, env: Environment) -> None:
Rob Mohr57204602020-09-23 08:41:18 -070083 if self.m.platform.is_mac:
84 with self.m.step.nest('setup platform'):
85 with self.m.macos_sdk():
86 pass
Rob Mohr21f15eb2020-09-09 10:10:39 -070087
Rob Mohrc16bf4b2024-03-06 19:59:03 +000088 def _init_misc_vars(
89 self,
90 env: Environment,
91 additional_variables: dict[str, str] | None = None,
92 ) -> None:
Rob Mohrfaa377f2022-01-19 14:38:36 -080093 env.env['PW_ENVIRONMENT_NO_ERROR_ON_UNRECOGNIZED'] = '1'
94 env.env['PW_ENVSETUP_DISABLE_SPINNER'] = '1'
95 env.env['PW_PRESUBMIT_DISABLE_SUBPROCESS_CAPTURE'] = '1'
Rob Mohr33bf5df2023-03-27 22:24:15 +000096 env.env['PW_USE_COLOR'] = ''
Rob Mohrc00a2622023-10-18 23:49:02 +000097 env.env['CLICOLOR'] = '0' # Formerly on https://bixense.com/clicolors/.
98 env.env['NO_COLOR'] = '1' # See https://no-color.org.
Rob Mohrd62d6a12023-09-26 18:42:22 +000099 # This should tell ninja to disable colors based on implementation at
100 # https://github.com/ninja-build/ninja/blob/master/src/line_printer.cc#L60.
101 env.env['CLICOLOR_FORCE'] = '0'
Rob Mohr31ed9ee2024-01-25 22:54:57 +0000102 env.env['GCC_COLORS'] = ''
Rob Mohr8360e162021-01-13 08:46:28 -0800103
Rob Mohr9a397182022-07-12 02:00:24 +0000104 env.env.update(additional_variables or {})
105
Rob Mohrecd37e42023-11-30 16:09:48 +0000106 if self.m.led.launched_by_led and not self.m.led.led_build:
Rob Mohre181c022022-09-16 18:11:17 +0000107 # Not using self.m.buildbucket_util.id because some downstream
108 # projects need this id to never be longer than a typical
109 # buildbucket id. Shorter is fine.
110 env.env['BUILDBUCKET_ID'] = '0'
Rob Mohrfaa377f2022-01-19 14:38:36 -0800111 env.env['BUILD_NUMBER'] = str(self.m.buildbucket.build.number)
Rob Mohr6042b342020-10-22 16:33:40 -0700112
Rob Mohra89b6ae2020-10-08 13:42:56 -0700113 else:
Rob Mohrfaa377f2022-01-19 14:38:36 -0800114 env.env['BUILDBUCKET_ID'] = str(self.m.buildbucket.build.id)
115 env.env['BUILD_NUMBER'] = str(self.m.buildbucket.build.number)
Rob Mohra89b6ae2020-10-08 13:42:56 -0700116
Rob Mohrfaa377f2022-01-19 14:38:36 -0800117 env.env['BUILDBUCKET_NAME'] = ':'.join(
Rob Mohr7ab2baf2020-10-16 11:48:29 -0700118 (
119 self.m.buildbucket.build.builder.project,
120 self.m.buildbucket.build.builder.bucket,
121 self.m.buildbucket.build.builder.builder,
122 )
123 )
Rob Mohra89b6ae2020-10-08 13:42:56 -0700124
Rob Mohrfaa377f2022-01-19 14:38:36 -0800125 if env.env['BUILDBUCKET_NAME'] == '::':
126 env.env['BUILDBUCKET_NAME'] = 'project:bucket:builder'
Rob Mohra89b6ae2020-10-08 13:42:56 -0700127
Rob Mohrd1e0dd22024-04-11 19:38:20 +0000128 env.env['CCACHE_DIR'] = self.m.path.cache_dir / 'ccache'
129 env.env['CTCACHE_DIR'] = self.m.path.cache_dir / 'clang_tidy'
130 env.env['GOCACHE'] = self.m.path.cache_dir / 'go'
131 env.env['PIP_CACHE_DIR'] = self.m.path.cache_dir / 'pip'
132 env.env['TEST_TMPDIR'] = self.m.path.cache_dir / 'bazel'
Rob Mohr59a9b1a2020-11-10 14:49:43 -0800133
Rob Mohrb2d926c2023-02-01 15:07:42 +0000134 env.env['TRIGGERING_CHANGES_JSON'] = env.checkout.changes_json
135
Rob Mohrfaa377f2022-01-19 14:38:36 -0800136 def _init_pigweed(
137 self,
Rob Mohrc16bf4b2024-03-06 19:59:03 +0000138 checkout: checkout_api.CheckoutContext,
139 top_presentation: engine_types.StepPresentation,
140 use_constraint_file: bool,
141 pigweed_root: config_types.Path,
142 options: Options,
143 env: Environment,
144 ) -> None:
Rob Mohr59a9b1a2020-11-10 14:49:43 -0800145 """Run pw_env_setup."""
146
Rob Mohrfabf49c2023-04-11 20:08:52 +0000147 json_file = env.dir / 'vars.json'
148 shell_file = env.dir / 'setup.sh'
149 venv_dir = env.dir / 'venv'
Rob Mohr59a9b1a2020-11-10 14:49:43 -0800150
Rob Mohr8afb1b42021-02-26 13:56:08 -0800151 self.m.file.ensure_directory(
Rob Mohr336d3352024-02-14 19:27:51 +0000152 f'mkdir {self.m.path.basename(env.dir)}',
153 env.dir,
Rob Mohr8afb1b42021-02-26 13:56:08 -0800154 )
Rob Mohr59a9b1a2020-11-10 14:49:43 -0800155
Rob Mohr8afb1b42021-02-26 13:56:08 -0800156 self.m.file.ensure_directory(
Rob Mohr336d3352024-02-14 19:27:51 +0000157 f'mkdir {self.m.path.basename(venv_dir)}',
158 venv_dir,
Rob Mohr8afb1b42021-02-26 13:56:08 -0800159 )
Rob Mohr59a9b1a2020-11-10 14:49:43 -0800160
Rob Mohrc16bf4b2024-03-06 19:59:03 +0000161 cmd: list[str | config_types.Path] = [
Rob Mohrc7e06392021-04-15 14:10:28 -0700162 'python3',
Rob Mohrfabf49c2023-04-11 20:08:52 +0000163 (
164 pigweed_root
165 / 'pw_env_setup'
166 / 'py'
167 / 'pw_env_setup'
168 / 'env_setup.py'
Rob Mohrfaa377f2022-01-19 14:38:36 -0800169 ),
Rob Mohr8afb1b42021-02-26 13:56:08 -0800170 '--pw-root',
Rob Mohrfaa377f2022-01-19 14:38:36 -0800171 pigweed_root,
Rob Mohr8afb1b42021-02-26 13:56:08 -0800172 '--install-dir',
Rob Mohrdcc61c82022-08-16 18:01:54 +0000173 env.dir,
Rob Mohr8afb1b42021-02-26 13:56:08 -0800174 '--json-file',
175 json_file,
176 '--shell-file',
177 shell_file,
Rob Mohr21e3da82021-05-27 13:21:41 -0700178 '--virtualenv-gn-out-dir',
Rob Mohrfabf49c2023-04-11 20:08:52 +0000179 env.dir / 'out',
Rob Mohr47d3d5c2021-05-13 06:59:23 -0700180 '--use-existing-cipd',
Rob Mohr95ab0342021-05-27 10:38:22 -0700181 '--strict',
Rob Mohre60c7722023-12-13 16:45:35 +0000182 '--disable-rosetta',
Rob Mohr8afb1b42021-02-26 13:56:08 -0800183 ]
Rob Mohr59a9b1a2020-11-10 14:49:43 -0800184
Rob Mohr9794dc82023-07-22 00:19:43 +0000185 if options.skip_submodule_check:
Rob Mohr5b95c712022-06-13 13:22:21 -0700186 cmd.append('--skip-submodule-check')
187
Rob Mohr80408192021-09-23 07:59:12 -0700188 if not use_constraint_file:
189 cmd.append('--unpin-pip-packages')
190
Rob Mohr3534bfe2023-07-24 19:02:55 +0000191 for f in options.additional_cipd_files:
Rob Mohre4031732023-09-18 22:53:36 +0000192 f = f.replace('$PW_ROOT', str(pigweed_root))
Rob Mohr3534bfe2023-07-24 19:02:55 +0000193 cmd.extend(('--additional-cipd-file', f))
194
Rob Mohr0567a302023-09-19 16:19:42 +0000195 cmd.append('--config-file')
196 cmd.append(path(options.config_file or 'pigweed.json', checkout))
Rob Mohr8afb1b42021-02-26 13:56:08 -0800197
Rob Mohr2e6a9d02023-10-27 14:29:33 +0000198 with self.m.step.nest('run pw_env_setup') as pres:
Rob Mohr84f58bb2023-11-08 22:06:57 +0000199 with self.m.defer.context() as defer:
200 with env(), self.m.default_timeout():
Rob Mohrb08e1ed2023-12-13 20:57:16 +0000201 result = defer(self.m.step, 'pw_env_setup', cmd)
Rob Mohr8afb1b42021-02-26 13:56:08 -0800202
Rob Mohr84f58bb2023-11-08 22:06:57 +0000203 defer(self.m.file.listdir, 'ls', env.dir, recursive=True)
Rob Mohr9a0d6af2023-04-28 20:30:45 +0000204
Rob Mohrb08e1ed2023-12-13 20:57:16 +0000205 defer(
206 self.m.save_logs,
207 dirs=(env.dir,),
208 pres=pres,
209 step_passed=result.is_ok(),
Rob Mohr8df8f902024-01-09 18:40:01 +0000210 step_name='environment-setup',
Rob Mohrb08e1ed2023-12-13 20:57:16 +0000211 )
Rob Mohr59a9b1a2020-11-10 14:49:43 -0800212
Rob Mohr8afb1b42021-02-26 13:56:08 -0800213 json_data = self.m.file.read_json(
214 'read json file',
215 json_file,
216 test_data={
217 'set': {'VIRTUAL_ENV': '/environment/virtualenv'},
218 'modify': {
219 'PATH': {'append': ['/environment/bin']},
220 'LD_LIBRARY_PATH': {'prepend': ['/environment/lib']},
Rob Mohr59a9b1a2020-11-10 14:49:43 -0800221 },
Rob Mohr8afb1b42021-02-26 13:56:08 -0800222 },
223 )
Rob Mohrb1eff262022-09-07 16:58:47 +0000224 top_presentation.logs['vars.json'] = pprint.pformat(json_data)
Rob Mohr59a9b1a2020-11-10 14:49:43 -0800225
Rob Mohrfabf49c2023-04-11 20:08:52 +0000226 env_gni_path = (
227 checkout.root / 'build_overrides' / 'pigweed_environment.gni'
Rob Mohr07314452022-08-16 18:22:52 +0000228 )
Rob Mohr07314452022-08-16 18:22:52 +0000229
Rob Mohrb1eff262022-09-07 16:58:47 +0000230 self.m.path.mock_add_file(env_gni_path)
231 if self.m.path.isfile(env_gni_path):
232 environment_gni = self.m.file.read_text(
233 'read gni file', env_gni_path
234 )
235 top_presentation.logs['pigweed_environment.gni'] = environment_gni
Rob Mohr59a9b1a2020-11-10 14:49:43 -0800236
Rob Mohre3be66a2021-08-27 12:38:18 -0700237 for var, value in json_data['set'].items():
Rob Mohrfaa377f2022-01-19 14:38:36 -0800238 env.env[var] = value
Rob Mohr59a9b1a2020-11-10 14:49:43 -0800239
Rob Mohre3be66a2021-08-27 12:38:18 -0700240 for var, actions in json_data['modify'].items():
Rob Mohr8afb1b42021-02-26 13:56:08 -0800241 for value in actions.get('prepend', ()):
Rob Mohrfaa377f2022-01-19 14:38:36 -0800242 env.prefixes.setdefault(var, [])
243 env.prefixes[var].append(value)
Rob Mohr8afb1b42021-02-26 13:56:08 -0800244 for value in actions.get('append', ()):
Rob Mohrfaa377f2022-01-19 14:38:36 -0800245 env.suffixes.setdefault(var, [])
246 env.suffixes[var].append(value)
Rob Mohr59a9b1a2020-11-10 14:49:43 -0800247
Rob Mohrc16bf4b2024-03-06 19:59:03 +0000248 def _toolchain_override(self, env: Environment) -> None:
Rob Mohrdc93dd92022-08-13 00:15:04 +0000249 """Checks for a toolchain override and applies it."""
250
Oliver Newman630409a2023-09-27 17:33:25 +0000251 # Using '$fuchsia/checkout' properties to simplify interface with the
Rob Mohrdc93dd92022-08-13 00:15:04 +0000252 # Fuchsia Toolchain team.
Rob Mohr336d3352024-02-14 19:27:51 +0000253 fuchsia_build_props = self.m.properties.thaw().get(
254 '$fuchsia/checkout', {}
255 )
Rob Mohrdc93dd92022-08-13 00:15:04 +0000256 toolchain_props = fuchsia_build_props.get('clang_toolchain', {})
257 if not toolchain_props:
258 return
259
260 with self.m.step.nest('toolchain override'):
261 with self.m.context(infra_steps=True):
Rob Mohrfabf49c2023-04-11 20:08:52 +0000262 toolchain_dir = env.dir / 'override' / 'clang_toolchain'
Rob Mohrdc93dd92022-08-13 00:15:04 +0000263
Oliver Newman630409a2023-09-27 17:33:25 +0000264 if cipd_version := toolchain_props.get('cipd_version'):
Rob Mohrdc93dd92022-08-13 00:15:04 +0000265 pkgs = self.m.cipd.EnsureFile()
266 pkgs.add_package(
267 'fuchsia/third_party/clang/${platform}',
Oliver Newman630409a2023-09-27 17:33:25 +0000268 cipd_version,
Rob Mohrdc93dd92022-08-13 00:15:04 +0000269 )
Rob Mohrbf732212022-09-12 18:11:22 +0000270 self.m.cipd.ensure(toolchain_dir, pkgs)
Rob Mohrdc93dd92022-08-13 00:15:04 +0000271
Oliver Newman630409a2023-09-27 17:33:25 +0000272 elif cas_digest := toolchain_props.get('cas_digest'):
Rob Mohr6da5ed82022-09-12 18:20:29 +0000273 with self.m.cas.with_instance(
274 'projects/chromium-swarm/instances/default_instance'
275 ):
276 self.m.cas.download(
277 'download',
Oliver Newman630409a2023-09-27 17:33:25 +0000278 digest=cas_digest,
Rob Mohr6da5ed82022-09-12 18:20:29 +0000279 output_dir=toolchain_dir,
280 )
Rob Mohrdc93dd92022-08-13 00:15:04 +0000281
282 else: # pragma: no cover
283 raise KeyError(
Oliver Newman630409a2023-09-27 17:33:25 +0000284 f'invalid clang toolchain properties: {toolchain_props!r}'
Rob Mohrdc93dd92022-08-13 00:15:04 +0000285 )
286
287 env.prefixes.setdefault('PATH', [])
Rob Mohrbf732212022-09-12 18:11:22 +0000288 env.prefixes['PATH'].append(toolchain_dir)
Rob Mohrfabf49c2023-04-11 20:08:52 +0000289 env.prefixes['PATH'].append(toolchain_dir / 'bin')
Rob Mohrbf732212022-09-12 18:11:22 +0000290
Rob Mohrfabf49c2023-04-11 20:08:52 +0000291 clang_prefix = toolchain_dir / 'bin'
Rob Mohr336d3352024-02-14 19:27:51 +0000292 env.override_gn_args['pw_toolchain_CLANG_PREFIX'] = (
293 f'{clang_prefix}/'
294 )
Rob Mohrdc93dd92022-08-13 00:15:04 +0000295
Rob Mohr3effd0c2024-03-27 18:05:05 +0000296 @recipe_api.ignore_warnings('recipe_engine/PYTHON2_DEPRECATED')
Rob Mohrfaa377f2022-01-19 14:38:36 -0800297 def init(
Rob Mohr336d3352024-02-14 19:27:51 +0000298 self,
Rob Mohrc16bf4b2024-03-06 19:59:03 +0000299 checkout: checkout_api.CheckoutContext,
300 options: Options | None = None,
301 use_constraint_file: bool = True,
302 ) -> Environment:
Rob Mohr500364a2023-02-01 15:05:30 +0000303 pigweed_root = checkout.root
Rob Mohrbf732212022-09-12 18:11:22 +0000304 env = Environment(
Rob Mohr336d3352024-02-14 19:27:51 +0000305 api=self.m,
306 dir=checkout.root / 'environment',
307 checkout=checkout,
Rob Mohrbf732212022-09-12 18:11:22 +0000308 )
Rob Mohre47c6582022-07-14 16:33:10 +0000309
Rob Mohre4475152022-11-16 20:04:36 +0000310 # If in recipe tests always add at least one variable to make it easier
311 # to test use of variables in recipes.
312 if self._test_data.enabled:
313 env.env['PW_TEST_VAR'] = 'test_value'
314
Rob Mohr2cb42052023-09-26 18:40:07 +0000315 if not options:
316 options = Options()
317
Rob Mohrfaa377f2022-01-19 14:38:36 -0800318 if not options.config_file:
Rob Mohr2cb42052023-09-26 18:40:07 +0000319 # Always set certain variables even without an environment config.
320 self._init_misc_vars(env, options.additional_variables)
Rob Mohrfaa377f2022-01-19 14:38:36 -0800321 return env
Rob Mohr3b7da062020-04-30 14:30:57 -0700322
Rob Mohrfaa377f2022-01-19 14:38:36 -0800323 if options.relative_pigweed_root not in (None, '', '.'):
Rob Mohrfabf49c2023-04-11 20:08:52 +0000324 pigweed_root = checkout.root / options.relative_pigweed_root
Rob Mohrfaa377f2022-01-19 14:38:36 -0800325
Rob Mohrfaa377f2022-01-19 14:38:36 -0800326 with self.m.step.nest('environment') as pres:
Rob Mohrd5764982023-11-16 18:59:44 +0000327 with self.m.step.nest('options') as options_pres:
328 options_pres.step_summary_text = repr(options)
329
Rob Mohr0567a302023-09-19 16:19:42 +0000330 cfg_json = self.m.file.read_json(
331 'read config',
332 path(options.config_file, checkout),
333 test_data={
334 'pw': {
Rob Mohr336d3352024-02-14 19:27:51 +0000335 'pw_env_setup': {
336 'relative_pigweed_root': 'pigweed',
337 },
Rob Mohr0567a302023-09-19 16:19:42 +0000338 },
339 },
340 )
341 pres.logs['config.json'] = pprint.pformat(cfg_json)
342
343 cfg_json = cfg_json.get('pw', cfg_json)
344 cfg_json = cfg_json.get('pw_env_setup', cfg_json)
345 if 'relative_pigweed_root' in cfg_json:
346 pigweed_root = checkout.root / cfg_json['relative_pigweed_root']
347
Rob Mohr500364a2023-02-01 15:05:30 +0000348 env.env['PW_PROJECT_ROOT'] = checkout.root
Rob Mohr0567a302023-09-19 16:19:42 +0000349 env.env['PW_ROOT'] = pigweed_root
Rob Mohrfaa377f2022-01-19 14:38:36 -0800350
351 self._init_platform(env)
Rob Mohr9a397182022-07-12 02:00:24 +0000352 self._init_misc_vars(env, options.additional_variables)
Rob Mohrfaa377f2022-01-19 14:38:36 -0800353 self._init_pigweed(
Rob Mohr500364a2023-02-01 15:05:30 +0000354 checkout=checkout,
Rob Mohrfaa377f2022-01-19 14:38:36 -0800355 top_presentation=pres,
356 use_constraint_file=use_constraint_file,
357 pigweed_root=pigweed_root,
Rob Mohr9794dc82023-07-22 00:19:43 +0000358 options=options,
Rob Mohrfaa377f2022-01-19 14:38:36 -0800359 env=env,
360 )
Rob Mohrdc93dd92022-08-13 00:15:04 +0000361 self._toolchain_override(env)
Rob Mohrfaa377f2022-01-19 14:38:36 -0800362
Rob Mohr322b7aa2022-09-07 19:45:05 +0000363 with env():
Rob Mohr322b7aa2022-09-07 19:45:05 +0000364 try:
365 self.m.step('doctor', ['python', '-m', 'pw_cli', 'doctor'])
366 except self.m.step.StepFailure:
Rob Mohrcfe746b2024-06-24 18:38:18 +0000367 if not options.allow_doctor_to_fail:
368 raise
Rob Mohr322b7aa2022-09-07 19:45:05 +0000369
Rob Mohrfaa377f2022-01-19 14:38:36 -0800370 return env