build: Support installing packages
Reordering the options protobuf because the numbers don't matter in this
context and logically packages come before other options.
Adding a test to handle default (empty) values for packages, gn args,
and targets.
Bug: b/285350808
Change-Id: Ia82b8a7b1bdda8c336b2c755e452082292b3b52e
Reviewed-on: https://pigweed-review.googlesource.com/c/infra/recipes/+/149990
Reviewed-by: Anthony DiGirolamo <tonymd@google.com>
Pigweed-Auto-Submit: Rob Mohr <mohrr@google.com>
Commit-Queue: Auto-Submit <auto-submit@pigweed.google.com.iam.gserviceaccount.com>
diff --git a/recipe_modules/build/api.py b/recipe_modules/build/api.py
index 0dd116b..9af00b2 100644
--- a/recipe_modules/build/api.py
+++ b/recipe_modules/build/api.py
@@ -36,9 +36,19 @@
return Context(self.m, checkout_root, root, options)
def __call__(self, ctx):
+ self.install_packages(ctx)
self.gn_gen(ctx)
self.ninja(ctx)
+ def install_packages(self, ctx):
+ if not ctx.options.packages:
+ return
+
+ with self.m.step.nest('install packages'):
+ cmd = ['python', '-m', 'pw_cli', 'package', 'install']
+ for package in ctx.options.packages:
+ self.m.step(package, cmd + [package])
+
def gn_gen(self, ctx):
cmd = ['gn', 'gen']
diff --git a/recipe_modules/build/options.proto b/recipe_modules/build/options.proto
index b122ad8..c180cbe 100644
--- a/recipe_modules/build/options.proto
+++ b/recipe_modules/build/options.proto
@@ -16,9 +16,12 @@
package recipe_modules.pigweed.build;
message Options {
+ // List of names of pw_package packages to install.
+ repeated string packages = 1;
+
// List of gn args ("var=value", ...). Default: empty.
- repeated string gn_args = 1;
+ repeated string gn_args = 2;
// List of targets to build. Default: empty (build default target).
- repeated string ninja_targets = 2;
+ repeated string ninja_targets = 3;
}
diff --git a/recipe_modules/build/test_api.py b/recipe_modules/build/test_api.py
index d6f67b9..0e59e2f 100644
--- a/recipe_modules/build/test_api.py
+++ b/recipe_modules/build/test_api.py
@@ -20,11 +20,13 @@
class BuildTestApi(recipe_test_api.RecipeTestApi):
"""Test API for build."""
- def options(self, *, gn_args=(), ninja_targets=()):
+ def options(self, *, packages=(), gn_args=(), ninja_targets=()):
+ assert isinstance(packages, (list, tuple))
assert isinstance(gn_args, (list, tuple))
assert isinstance(ninja_targets, (list, tuple))
opts = options.Options()
+ opts.packages.extend(packages)
opts.gn_args.extend(gn_args)
opts.ninja_targets.extend(ninja_targets)
return opts
diff --git a/recipe_modules/build/tests/full.expected/default.json b/recipe_modules/build/tests/full.expected/default.json
new file mode 100644
index 0000000..4ac4eac
--- /dev/null
+++ b/recipe_modules/build/tests/full.expected/default.json
@@ -0,0 +1,486 @@
+[
+ {
+ "cmd": [
+ "gn",
+ "gen",
+ "--export-compile-commands",
+ "[START_DIR]/checkout/out"
+ ],
+ "cwd": "[START_DIR]/checkout",
+ "name": "gn gen"
+ },
+ {
+ "cmd": [],
+ "name": "timeout 11h 4m 38s"
+ },
+ {
+ "cmd": [
+ "ninja",
+ "-C",
+ "[START_DIR]/checkout/out"
+ ],
+ "luci_context": {
+ "deadline": {
+ "grace_period": 30.0,
+ "soft_deadline": -120.0
+ }
+ },
+ "name": "ninja"
+ },
+ {
+ "cmd": [],
+ "name": "save logs",
+ "~followup_annotations": [
+ "@@@STEP_LINK@description@https://url@@@",
+ "@@@STEP_FAILURE@@@"
+ ]
+ },
+ {
+ "cmd": [],
+ "name": "save logs.logs",
+ "~followup_annotations": [
+ "@@@STEP_NEST_LEVEL@1@@@"
+ ]
+ },
+ {
+ "cmd": [],
+ "name": "save logs.logs.glob",
+ "~followup_annotations": [
+ "@@@STEP_NEST_LEVEL@2@@@"
+ ]
+ },
+ {
+ "cmd": [
+ "vpython3",
+ "-u",
+ "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+ "--json-output",
+ "/path/to/tmp/json",
+ "glob",
+ "[START_DIR]/checkout/out",
+ "*.gn",
+ "--hidden"
+ ],
+ "infra_step": true,
+ "name": "save logs.logs.glob.*.gn",
+ "~followup_annotations": [
+ "@@@STEP_NEST_LEVEL@3@@@",
+ "@@@STEP_LOG_END@glob@@@"
+ ]
+ },
+ {
+ "cmd": [
+ "vpython3",
+ "-u",
+ "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+ "--json-output",
+ "/path/to/tmp/json",
+ "glob",
+ "[START_DIR]/checkout/out",
+ "*.log",
+ "--hidden"
+ ],
+ "infra_step": true,
+ "name": "save logs.logs.glob.*.log",
+ "~followup_annotations": [
+ "@@@STEP_NEST_LEVEL@3@@@",
+ "@@@STEP_LOG_LINE@glob@[START_DIR]/checkout/out/.ninja_log@@@",
+ "@@@STEP_LOG_LINE@glob@[START_DIR]/checkout/out/failure-summary.log@@@",
+ "@@@STEP_LOG_LINE@glob@[START_DIR]/checkout/out/links.json@@@",
+ "@@@STEP_LOG_END@glob@@@"
+ ]
+ },
+ {
+ "cmd": [
+ "vpython3",
+ "-u",
+ "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+ "--json-output",
+ "/path/to/tmp/json",
+ "glob",
+ "[START_DIR]/checkout/out",
+ "*.json",
+ "--hidden"
+ ],
+ "infra_step": true,
+ "name": "save logs.logs.glob.*.json",
+ "~followup_annotations": [
+ "@@@STEP_NEST_LEVEL@3@@@",
+ "@@@STEP_LOG_END@glob@@@"
+ ]
+ },
+ {
+ "cmd": [
+ "vpython3",
+ "-u",
+ "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+ "--json-output",
+ "/path/to/tmp/json",
+ "glob",
+ "[START_DIR]/checkout/out",
+ "*.compdb",
+ "--hidden"
+ ],
+ "infra_step": true,
+ "name": "save logs.logs.glob.*.compdb",
+ "~followup_annotations": [
+ "@@@STEP_NEST_LEVEL@3@@@",
+ "@@@STEP_LOG_END@glob@@@"
+ ]
+ },
+ {
+ "cmd": [
+ "vpython3",
+ "-u",
+ "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+ "--json-output",
+ "/path/to/tmp/json",
+ "glob",
+ "[START_DIR]/checkout/out",
+ "*.graph",
+ "--hidden"
+ ],
+ "infra_step": true,
+ "name": "save logs.logs.glob.*.graph",
+ "~followup_annotations": [
+ "@@@STEP_NEST_LEVEL@3@@@",
+ "@@@STEP_LOG_END@glob@@@"
+ ]
+ },
+ {
+ "cmd": [
+ "vpython3",
+ "-u",
+ "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+ "--json-output",
+ "/path/to/tmp/json",
+ "glob",
+ "[START_DIR]/checkout/out",
+ "*_log",
+ "--hidden"
+ ],
+ "infra_step": true,
+ "name": "save logs.logs.glob.*_log",
+ "~followup_annotations": [
+ "@@@STEP_NEST_LEVEL@3@@@",
+ "@@@STEP_LOG_END@glob@@@"
+ ]
+ },
+ {
+ "cmd": [
+ "vpython3",
+ "-u",
+ "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+ "--json-output",
+ "/path/to/tmp/json",
+ "copy",
+ "[START_DIR]/checkout/out/.ninja_log",
+ "/path/to/tmp/"
+ ],
+ "infra_step": true,
+ "name": "save logs.logs..ninja_log",
+ "~followup_annotations": [
+ "@@@STEP_NEST_LEVEL@2@@@",
+ "@@@STEP_LOG_LINE@.ninja_log@2000 5000 0 medium 0@@@",
+ "@@@STEP_LOG_LINE@.ninja_log@3000 8000 0 long 0@@@",
+ "@@@STEP_LOG_LINE@.ninja_log@malformed line@@@",
+ "@@@STEP_LOG_LINE@.ninja_log@4000 5000 0 short 0@@@",
+ "@@@STEP_LOG_LINE@.ninja_log@5000 x 0 malformed-end-time 0@@@",
+ "@@@STEP_LOG_END@.ninja_log@@@"
+ ]
+ },
+ {
+ "cmd": [
+ "vpython3",
+ "-u",
+ "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+ "--json-output",
+ "/path/to/tmp/json",
+ "copy",
+ "[START_DIR]/checkout/out/failure-summary.log",
+ "/path/to/tmp/"
+ ],
+ "infra_step": true,
+ "name": "save logs.logs.failure-summary.log",
+ "~followup_annotations": [
+ "@@@STEP_NEST_LEVEL@2@@@",
+ "@@@STEP_LOG_LINE@failure-summary.log@[5/10] foo.c@@@",
+ "@@@STEP_LOG_LINE@failure-summary.log@error: ???@@@",
+ "@@@STEP_LOG_END@failure-summary.log@@@"
+ ]
+ },
+ {
+ "cmd": [
+ "vpython3",
+ "-u",
+ "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+ "--json-output",
+ "/path/to/tmp/json",
+ "copy",
+ "[START_DIR]/checkout/out/links.json",
+ "/path/to/tmp/"
+ ],
+ "infra_step": true,
+ "name": "save logs.logs.links.json",
+ "~followup_annotations": [
+ "@@@STEP_NEST_LEVEL@2@@@",
+ "@@@STEP_LOG_LINE@links.json@[@@@",
+ "@@@STEP_LOG_LINE@links.json@ {@@@",
+ "@@@STEP_LOG_LINE@links.json@ \"description\": \"description\",@@@",
+ "@@@STEP_LOG_LINE@links.json@ \"url\": \"https://url\"@@@",
+ "@@@STEP_LOG_LINE@links.json@ }@@@",
+ "@@@STEP_LOG_LINE@links.json@]@@@",
+ "@@@STEP_LOG_END@links.json@@@"
+ ]
+ },
+ {
+ "cmd": [],
+ "name": "save logs.failure summary",
+ "~followup_annotations": [
+ "@@@STEP_NEST_LEVEL@1@@@",
+ "@@@STEP_SUMMARY_TEXT@```\n[5/10] foo.c\nerror: ???\n```@@@",
+ "@@@STEP_LOG_LINE@full contents@[5/10] foo.c@@@",
+ "@@@STEP_LOG_LINE@full contents@error: ???@@@",
+ "@@@STEP_LOG_END@full contents@@@",
+ "@@@STEP_FAILURE@@@"
+ ]
+ },
+ {
+ "cmd": [],
+ "name": "save logs.longest build steps",
+ "~followup_annotations": [
+ "@@@STEP_NEST_LEVEL@1@@@"
+ ]
+ },
+ {
+ "cmd": [],
+ "name": "save logs.longest build steps.long",
+ "~followup_annotations": [
+ "@@@STEP_NEST_LEVEL@2@@@",
+ "@@@STEP_SUMMARY_TEXT@5.0s@@@"
+ ]
+ },
+ {
+ "cmd": [],
+ "name": "save logs.longest build steps.medium",
+ "~followup_annotations": [
+ "@@@STEP_NEST_LEVEL@2@@@",
+ "@@@STEP_SUMMARY_TEXT@3.0s@@@"
+ ]
+ },
+ {
+ "cmd": [],
+ "name": "save logs.longest build steps.short",
+ "~followup_annotations": [
+ "@@@STEP_NEST_LEVEL@2@@@",
+ "@@@STEP_SUMMARY_TEXT@1.0s@@@"
+ ]
+ },
+ {
+ "cmd": [
+ "vpython3",
+ "-u",
+ "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+ "--json-output",
+ "/path/to/tmp/json",
+ "ensure-directory",
+ "--mode",
+ "0777",
+ "[START_DIR]/checkout/out/export/build_logs"
+ ],
+ "infra_step": true,
+ "name": "save logs.mkdir build_logs",
+ "~followup_annotations": [
+ "@@@STEP_NEST_LEVEL@1@@@"
+ ]
+ },
+ {
+ "cmd": [],
+ "name": "save logs.copy",
+ "~followup_annotations": [
+ "@@@STEP_NEST_LEVEL@1@@@"
+ ]
+ },
+ {
+ "cmd": [
+ "vpython3",
+ "-u",
+ "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+ "--json-output",
+ "/path/to/tmp/json",
+ "copy",
+ "[START_DIR]/checkout/out/.ninja_log",
+ "[START_DIR]/checkout/out/export/build_logs/.ninja_log"
+ ],
+ "infra_step": true,
+ "name": "save logs.copy..ninja_log",
+ "~followup_annotations": [
+ "@@@STEP_NEST_LEVEL@2@@@"
+ ]
+ },
+ {
+ "cmd": [
+ "vpython3",
+ "-u",
+ "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+ "--json-output",
+ "/path/to/tmp/json",
+ "copy",
+ "[START_DIR]/checkout/out/failure-summary.log",
+ "[START_DIR]/checkout/out/export/build_logs/failure-summary.log"
+ ],
+ "infra_step": true,
+ "name": "save logs.copy.failure-summary.log",
+ "~followup_annotations": [
+ "@@@STEP_NEST_LEVEL@2@@@"
+ ]
+ },
+ {
+ "cmd": [
+ "vpython3",
+ "-u",
+ "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+ "--json-output",
+ "/path/to/tmp/json",
+ "copy",
+ "[START_DIR]/checkout/out/links.json",
+ "[START_DIR]/checkout/out/export/build_logs/links.json"
+ ],
+ "infra_step": true,
+ "name": "save logs.copy.links.json",
+ "~followup_annotations": [
+ "@@@STEP_NEST_LEVEL@2@@@"
+ ]
+ },
+ {
+ "cmd": [
+ "gn",
+ "args",
+ "[START_DIR]/checkout/out",
+ "--list",
+ "--json"
+ ],
+ "cwd": "[START_DIR]/checkout",
+ "name": "all gn args",
+ "~followup_annotations": [
+ "@@@STEP_LOG_LINE@json.output@[]@@@",
+ "@@@STEP_LOG_END@json.output@@@"
+ ]
+ },
+ {
+ "cmd": [],
+ "name": "archive to cas",
+ "~followup_annotations": [
+ "@@@SET_BUILD_PROPERTY@cas_build_digest@\"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855/0\"@@@"
+ ]
+ },
+ {
+ "cmd": [
+ "vpython3",
+ "-u",
+ "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+ "--json-output",
+ "/path/to/tmp/json",
+ "copy",
+ "RECIPE_MODULE[recipe_engine::cas]/resources/infra.sha1",
+ "/path/to/tmp/"
+ ],
+ "infra_step": true,
+ "name": "archive to cas.read infra revision",
+ "~followup_annotations": [
+ "@@@STEP_NEST_LEVEL@1@@@",
+ "@@@STEP_LOG_LINE@infra.sha1@git_revision:mock_infra_git_revision@@@",
+ "@@@STEP_LOG_END@infra.sha1@@@"
+ ]
+ },
+ {
+ "cmd": [],
+ "name": "archive to cas.install infra/tools/luci/cas",
+ "~followup_annotations": [
+ "@@@STEP_NEST_LEVEL@1@@@"
+ ]
+ },
+ {
+ "cmd": [
+ "vpython3",
+ "-u",
+ "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+ "--json-output",
+ "/path/to/tmp/json",
+ "ensure-directory",
+ "--mode",
+ "0777",
+ "[START_DIR]/cipd_tool/infra/tools/luci/cas/git_revision%3Amock_infra_git_revision"
+ ],
+ "infra_step": true,
+ "name": "archive to cas.install infra/tools/luci/cas.ensure package directory",
+ "~followup_annotations": [
+ "@@@STEP_NEST_LEVEL@2@@@"
+ ]
+ },
+ {
+ "cmd": [
+ "cipd",
+ "ensure",
+ "-root",
+ "[START_DIR]/cipd_tool/infra/tools/luci/cas/git_revision%3Amock_infra_git_revision",
+ "-ensure-file",
+ "infra/tools/luci/cas/${platform} git_revision:mock_infra_git_revision",
+ "-max-threads",
+ "0",
+ "-json-output",
+ "/path/to/tmp/json"
+ ],
+ "infra_step": true,
+ "name": "archive to cas.install infra/tools/luci/cas.ensure_installed",
+ "~followup_annotations": [
+ "@@@STEP_NEST_LEVEL@2@@@",
+ "@@@STEP_LOG_LINE@json.output@{@@@",
+ "@@@STEP_LOG_LINE@json.output@ \"result\": {@@@",
+ "@@@STEP_LOG_LINE@json.output@ \"\": [@@@",
+ "@@@STEP_LOG_LINE@json.output@ {@@@",
+ "@@@STEP_LOG_LINE@json.output@ \"instance_id\": \"resolved-instance_id-of-git_revision:moc\", @@@",
+ "@@@STEP_LOG_LINE@json.output@ \"package\": \"infra/tools/luci/cas/resolved-platform\"@@@",
+ "@@@STEP_LOG_LINE@json.output@ }@@@",
+ "@@@STEP_LOG_LINE@json.output@ ]@@@",
+ "@@@STEP_LOG_LINE@json.output@ }@@@",
+ "@@@STEP_LOG_LINE@json.output@}@@@",
+ "@@@STEP_LOG_END@json.output@@@"
+ ]
+ },
+ {
+ "cmd": [
+ "[START_DIR]/cipd_tool/infra/tools/luci/cas/git_revision%3Amock_infra_git_revision/cas",
+ "archive",
+ "-cas-instance",
+ "projects/example-cas-server/instances/default_instance",
+ "-dump-digest",
+ "/path/to/tmp/",
+ "-paths-json",
+ "[[\"[START_DIR]/checkout/out\", \".\"]]"
+ ],
+ "infra_step": true,
+ "name": "archive to cas.archive",
+ "~followup_annotations": [
+ "@@@STEP_NEST_LEVEL@1@@@",
+ "@@@STEP_LINK@CAS UI@https://cas-viewer.appspot.com/projects/example-cas-server/instances/default_instance/blobs/e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855/0/tree@@@"
+ ]
+ },
+ {
+ "cmd": [
+ "[START_DIR]/cipd_tool/infra/tools/luci/cas/git_revision%3Amock_infra_git_revision/cas",
+ "download",
+ "-cas-instance",
+ "projects/example-cas-server/instances/default_instance",
+ "-digest",
+ "digest",
+ "-dir",
+ "[START_DIR]/checkout/out"
+ ],
+ "infra_step": true,
+ "name": "download from cas"
+ },
+ {
+ "name": "$result"
+ }
+]
\ No newline at end of file
diff --git a/recipe_modules/build/tests/full.expected/full.json b/recipe_modules/build/tests/full.expected/full.json
index 23d731e..5116ffd 100644
--- a/recipe_modules/build/tests/full.expected/full.json
+++ b/recipe_modules/build/tests/full.expected/full.json
@@ -1,5 +1,23 @@
[
{
+ "cmd": [],
+ "name": "install packages"
+ },
+ {
+ "cmd": [
+ "python",
+ "-m",
+ "pw_cli",
+ "package",
+ "install",
+ "pkg"
+ ],
+ "name": "install packages.pkg",
+ "~followup_annotations": [
+ "@@@STEP_NEST_LEVEL@1@@@"
+ ]
+ },
+ {
"cmd": [
"gn",
"gen",
diff --git a/recipe_modules/build/tests/full.py b/recipe_modules/build/tests/full.py
index f885415..b5cfbe7 100644
--- a/recipe_modules/build/tests/full.py
+++ b/recipe_modules/build/tests/full.py
@@ -44,7 +44,13 @@
api.test('full')
+ api.properties(
build_options=api.build.options(
- gn_args=['foo=true'], ninja_targets=['target'],
+ packages=['pkg'],
+ gn_args=['foo=true'],
+ ninja_targets=['target'],
)
)
)
+
+ yield (
+ api.test('default') + api.properties(build_options=api.build.options())
+ )