| # Copyright 2018 The Fuchsia Authors. All rights reserved. |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| from recipe_engine import recipe_api |
| |
| NINJA_CIPD_PATH = "infra/ninja/${platform}" |
| NINJA_CIPD_VERSION = "version:1.9.0" |
| |
| |
| class NinjaApi(recipe_api.RecipeApi): |
| """APIs for interacting with Ninja. |
| |
| NOTE: Recipes that use the Fuchsia build system should use the |
| `build` recipe module, which uses `fint` instead of running GN and |
| Ninja directly. Only recipes that build code outside of a Fuchsia |
| checkout should use this `ninja` module. |
| """ |
| |
| def build(self, build_dir, targets=(), step_name="ninja", job_count=None, **kwargs): |
| """Does a build using Ninja. |
| |
| Args: |
| build_dir (Path): CD into this directory before executing. |
| targets (seq(str)): List of targets to build. |
| step_name (string): Step name (default: 'ninja'). |
| job_count (int): No. parallel jobs (Ninja default is to guess |
| from available CPUs). |
| **kwargs (dict): Passed through to `api.step()`. |
| """ |
| # Construct command for ninja |
| ninja_command = [ |
| self._ninja_path(), |
| "-C", |
| build_dir, |
| ] |
| |
| if job_count: |
| ninja_command.extend(["-j", job_count]) |
| # Sort the targets for a deterministic ordering. This will ease reviews, |
| # as a re-ordering of build logic will yield the same ninja invocation. |
| ninja_command.extend(sorted(targets)) |
| |
| # Use ninja_wrapper to run ninja build |
| ninja_wrapper_args = ["--failure_output", self.m.raw_io.output()] |
| ninja_wrapper_args.append("--") |
| ninja_wrapper_args.extend(ninja_command) |
| |
| step_test_data = lambda: self.m.raw_io.test_api.output( |
| "[1/1] CXX a.o\nerror info\n" |
| ) |
| |
| ninja_step_result = self.m.python( |
| step_name, |
| script=self.resource("ninja_wrapper.py"), |
| args=ninja_wrapper_args, |
| step_test_data=step_test_data, |
| ok_ret="any", |
| **kwargs |
| ) |
| # Handle failure ourselves so we can include the failure summary. |
| if ninja_step_result.exc_result.had_timeout: |
| raise self.m.step.InfraFailure(step_name, result=ninja_step_result) |
| if ninja_step_result.exc_result.retcode: |
| ninja_step_result.presentation.status = self.m.step.FAILURE |
| |
| failure_summary_link = "failure summary" |
| failure_summary = ninja_step_result.raw_io.output |
| ninja_step_result.presentation.logs[failure_summary_link] = failure_summary |
| # Trailing newlines take up extra space in the build summary and |
| # are almost certainly safe to remove without affecting the meaning |
| # of the failure message. |
| failure_summary = failure_summary.rstrip() |
| |
| truncation_message = ( |
| "(failure summary truncated, see the %s step's %r link for full " |
| "failure details)" |
| ) % (step_name, failure_summary_link) |
| |
| raise self.m.step.StepFailure( |
| self.m.buildbucket_util.summary_message( |
| failure_summary, truncation_message |
| ) |
| ) |
| |
| return ninja_step_result |
| |
| def _ninja_path(self): |
| return self.m.cipd.ensure_tool(NINJA_CIPD_PATH, NINJA_CIPD_VERSION) |