blob: d529fe7297be6450faacafd765f3c49a30d69f8f [file] [log] [blame]
# 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)