summaryrefslogtreecommitdiff
path: root/zephyr/firmware_builder.py
diff options
context:
space:
mode:
authorKevin Shelton <kmshelton@chromium.org>2021-03-30 15:11:37 -0700
committerCommit Bot <commit-bot@chromium.org>2021-04-05 22:55:46 +0000
commit0e85e435cfdc234b5b6b7df1c88e63ee1cb8752e (patch)
tree9934205701978c5f3a69ea88b000b4c85ac97f0c /zephyr/firmware_builder.py
parent362e02845295c56a3c1fbb4c5fd39b318a45253c (diff)
downloadchrome-ec-0e85e435cfdc234b5b6b7df1c88e63ee1cb8752e.tar.gz
zephyr: firmware_builder bundle functionality
Ports bundle functionality (excluding LCOV info bundling) from platform/ec/firmware_builder.py. BUG=b:176926834 BRANCH=None TEST=./firmware_builder.py --metrics=/tmp/metrics build, ./firmware_builder.py --metrics=/tmp/metrics bundle, ./firmware_builder.py --output-dir=/tmp/testbundle --metrics=/tmp/metrics --metadata=/tmp/testmetadata bundle, ./firmware_builder.py --metrics=/tmp/metrics --code-coverage bundle, bundle with code-coverage option raises an exception as expected, build included some errors that are unrelated to this change, e.g.: "Zmake/ERROR: Including boilerplate (Zephyr base): Signed-off-by: Kevin Shelton <kmshelton@chromium.org> Change-Id: I3b7a5a0d2ec8415320bdf289b1d64210feeb39c3 Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/2797541 Reviewed-by: Jack Rosenthal <jrosenth@chromium.org>
Diffstat (limited to 'zephyr/firmware_builder.py')
-rwxr-xr-xzephyr/firmware_builder.py116
1 files changed, 106 insertions, 10 deletions
diff --git a/zephyr/firmware_builder.py b/zephyr/firmware_builder.py
index 7a32c45a81..540274105b 100755
--- a/zephyr/firmware_builder.py
+++ b/zephyr/firmware_builder.py
@@ -10,16 +10,19 @@ This is the entry point for the custom firmware builder workflow recipe.
import argparse
import multiprocessing
-import os
-import shutil
+import pathlib
import subprocess
import sys
+import zmake.project
# TODO(crbug/1181505): Code outside of chromite should not be importing from
# chromite.api.gen. Import json_format after that so we get the matching one.
from chromite.api.gen.chromite.api import firmware_pb2
from google.protobuf import json_format
+DEFAULT_BUNDLE_DIRECTORY = '/tmp/artifact_bundles'
+DEFAULT_BUNDLE_METADATA_FILE = '/tmp/artifact_bundle_metadata'
+
def build(opts):
"""Builds all Zephyr firmware targets"""
@@ -28,26 +31,84 @@ def build(opts):
with open(opts.metrics, 'w') as f:
f.write(json_format.MessageToJson(metrics))
- temp_build_dir = os.path.join('/tmp', 'zbuild')
-
targets = [
'projects/kohaku',
'projects/posix-ec',
'projects/volteer/volteer',
]
for target in targets:
- if os.path.exists(temp_build_dir):
- shutil.rmtree(temp_build_dir)
-
print('Building {}'.format(target))
- rv = subprocess.run(
- ['zmake', '-D', 'configure', '-b', '-B', temp_build_dir, target],
- cwd=os.path.dirname(__file__)).returncode
+ cmd = ['zmake', '-D', 'configure', '-b', target]
+ rv = subprocess.run(cmd, cwd=pathlib.Path(__file__).parent).returncode
if rv != 0:
return rv
return 0
+def bundle(opts):
+ if opts.code_coverage:
+ bundle_coverage(opts)
+ else:
+ bundle_firmware(opts)
+
+
+def get_bundle_dir(opts):
+ """Get the directory for the bundle from opts or use the default.
+
+ Also create the directory if it doesn't exist."""
+ bundle_dir = (opts.output_dir
+ if opts.output_dir else DEFAULT_BUNDLE_DIRECTORY)
+ bundle_dir = pathlib.Path(bundle_dir)
+ if not bundle_dir.is_dir():
+ bundle_dir.mkdir()
+ return bundle_dir
+
+
+def write_metadata(opts, info):
+ """Write the metadata about the bundle."""
+ bundle_metadata_file = (opts.metadata
+ if opts.metadata else DEFAULT_BUNDLE_METADATA_FILE)
+ with open(bundle_metadata_file, 'w') as f:
+ f.write(json_format.MessageToJson(info))
+
+
+def bundle_coverage(opts):
+ """Bundles the artifacts from code coverage into its own tarball."""
+ raise NotImplementedError
+
+
+def bundle_firmware(opts):
+ """Bundles the artifacts from each target into its own tarball."""
+ info = firmware_pb2.FirmwareArtifactInfo()
+ info.bcs_version_info.version_string = opts.bcs_version
+ bundle_dir = get_bundle_dir(opts)
+ zephyr_dir = pathlib.Path(__file__).parent
+ platform_ec = zephyr_dir.resolve().parent
+ for project in zmake.project.find_projects(zephyr_dir):
+ build_dir = zmake.util.resolve_build_dir(platform_ec,
+ project.project_dir, None)
+ artifacts_dir = build_dir / 'output'
+ # TODO(kmshelton): Remove once the build command does not rely
+ # on a pre-defined list of targets.
+ if not artifacts_dir.is_dir():
+ continue
+ project_identifier = '_'.join(
+ project.project_dir.
+ parts[project.project_dir.parts.index('projects') + 1:])
+ tarball_name = '{}.firmware.tbz2'.format(project_identifier)
+ tarball_path = bundle_dir.joinpath(tarball_name)
+ cmd = ['tar', 'cvfj', tarball_path, '.']
+ subprocess.run(cmd, cwd=artifacts_dir, check=True)
+ meta = info.objects.add()
+ meta.file_name = tarball_name
+ meta.tarball_info.type = (
+ firmware_pb2.FirmwareArtifactInfo.TarballInfo.FirmwareType.EC)
+ # TODO(kmshelton): Populate the rest of metadata contents as it
+ # gets defined in infra/proto/src/chromite/api/firmware.proto.
+
+ write_metadata(opts, info)
+
+
def test(opts):
"""Runs all of the unit tests for Zephyr firmware"""
# TODO(b/169178847): Add appropriate metric information
@@ -86,6 +147,36 @@ def parse_args(args):
help='File to write the json-encoded MetricsList proto message.',
)
+ parser.add_argument(
+ '--metadata',
+ required=False,
+ help=('Full pathname for the file in which to write build artifact '
+ 'metadata.'),
+ )
+
+ parser.add_argument(
+ '--output-dir',
+ required=False,
+ help=
+ 'Full pathanme for the directory in which to bundle build artifacts.',
+ )
+
+ parser.add_argument(
+ '--code-coverage',
+ required=False,
+ action='store_true',
+ help='Build host-based unit tests for code coverage.',
+ )
+
+ parser.add_argument(
+ '--bcs-version',
+ dest='bcs_version',
+ default='',
+ required=False,
+ # TODO(b/180008931): make this required=True.
+ help='BCS version to include in metadata.',
+ )
+
# Would make this required=True, but not available until 3.7
sub_cmds = parser.add_subparsers()
@@ -93,6 +184,11 @@ def parse_args(args):
help='Builds all firmware targets')
build_cmd.set_defaults(func=build)
+ build_cmd = sub_cmds.add_parser('bundle',
+ help='Creates a tarball containing build '
+ 'artifacts from all firmware targets')
+ build_cmd.set_defaults(func=bundle)
+
test_cmd = sub_cmds.add_parser('test', help='Runs all firmware unit tests')
test_cmd.set_defaults(func=test)