| # Copyright 2021 The Pigweed Authors |
| # |
| # Licensed under the Apache License, Version 2.0 (the "License"); you may not |
| # use this file except in compliance with the License. You may obtain a copy of |
| # the License at |
| # |
| # https://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, software |
| # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
| # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
| # License for the specific language governing permissions and limitations under |
| # the License. |
| """Calls to build code.""" |
| |
| import dataclasses |
| from typing import Any, Optional |
| |
| from PB.recipe_modules.pigweed.build import options as options_pb2 |
| from recipe_engine import config_types, recipe_api, step_data |
| |
| |
| @dataclasses.dataclass |
| class BuildContext: |
| _api: recipe_api.RecipeApi |
| checkout_root: config_types.Path |
| root: config_types.Path |
| options: options_pb2.Options |
| |
| |
| _Command = list[str | config_types.Path] |
| |
| |
| class BuildApi(recipe_api.RecipeApi): |
| """Calls to build code.""" |
| |
| BuildContext = BuildContext |
| |
| CAS_DIGEST_PROPERTY_NAME: str = 'cas_build_digest' |
| |
| def create( |
| self, |
| checkout_root: config_types.Path, |
| options: options_pb2.Options, |
| root: Optional[config_types.Path] = None, |
| ) -> BuildContext: |
| if not root: |
| root = checkout_root / 'out' |
| return BuildContext(self.m, checkout_root, root, options) |
| |
| def __call__(self, ctx: BuildContext) -> None: |
| self.install_packages(ctx) |
| self.gn_gen(ctx) |
| self.ninja(ctx) |
| |
| def install_packages(self, ctx: BuildContext) -> None: |
| if not ctx.options.packages: |
| return |
| |
| with self.m.step.nest('install packages'): |
| cmd: _Command = ['python', '-m', 'pw_cli', 'package', 'install'] |
| for package in ctx.options.packages: |
| self.m.step(package, cmd + [package]) |
| |
| def gn_gen(self, ctx: BuildContext) -> None: |
| cmd: _Command = ['gn', 'gen'] |
| |
| for gn_arg in ctx.options.gn_args: |
| cmd.append(f'--args={gn_arg}') |
| |
| # Infrequently needed but harmless to always add this. |
| cmd.append('--export-compile-commands') |
| |
| cmd.append(ctx.root) |
| |
| with self.m.context(cwd=ctx.checkout_root): |
| self.m.step('gn gen', cmd) |
| |
| def get_gn_args( |
| self, ctx: BuildContext, test_data=None, |
| ) -> dict[str, int | str]: |
| context_kwargs = {'cwd': ctx.checkout_root} if ctx.checkout_root else {} |
| with self.m.context(**context_kwargs): |
| cmd: _Command = ['gn', 'args', ctx.root, '--list', '--json'] |
| args = self.m.step( |
| 'all gn args', |
| cmd, |
| stdout=self.m.json.output(), |
| step_test_data=lambda: self.m.json.test_api.output_stream( |
| test_data or [] |
| ), |
| ).stdout |
| return {x['name']: x for x in args or ()} |
| |
| def ninja(self, ctx: BuildContext) -> None: |
| cmd: _Command = ['ninja', '-C', ctx.root] |
| cmd.extend(ctx.options.ninja_targets) |
| with self.m.default_timeout(): |
| self.m.step('ninja', cmd) |
| |
| def archive_to_cas(self, ctx: BuildContext) -> str: |
| # TODO: b/234879756 - Only archive necessary files. |
| with self.m.step.nest('archive to cas') as pres: |
| digest: str = self.m.cas.archive('archive', ctx.root, ctx.root) |
| pres.properties[self.CAS_DIGEST_PROPERTY_NAME] = digest |
| return digest |
| |
| def download_from_cas( |
| self, ctx: BuildContext, digest: str |
| ) -> step_data.StepData: |
| return self.m.cas.download('download from cas', digest, ctx.root) |