blob: 122e5f7bed4382f36d951ce91262f9a8bfa2f41c [file] [log] [blame]
Mike Frysingerf1ba7ad2022-09-12 05:42:57 -04001# Copyright 2020 The ChromiumOS Authors
Jett Rink17ed0f52020-09-25 17:14:31 -06002# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
LaMont Jonesed9a5de2021-02-03 11:06:12 -07004
Jett Rink17ed0f52020-09-25 17:14:31 -06005"""Firmware builder controller.
6
LaMont Jonesdec69ad2021-01-27 13:02:00 -07007Handle all firmware builder related functionality. Currently no service module
8exists: all of the work is done here.
Jett Rink17ed0f52020-09-25 17:14:31 -06009"""
Alex Kleineec90f72023-02-03 10:53:12 -070010import logging
Jett Rink17ed0f52020-09-25 17:14:31 -060011import os
12import tempfile
13
Mike Frysinger2c024062021-05-22 15:43:22 -040014from chromite.third_party.google.protobuf import json_format
Jett Rink17ed0f52020-09-25 17:14:31 -060015
16from chromite.api import controller
17from chromite.api import faux
18from chromite.api import validate
19from chromite.api.gen.chromite.api import firmware_pb2
LaMont Jonesdec69ad2021-01-27 13:02:00 -070020from chromite.api.gen.chromiumos import common_pb2
Jett Rink17ed0f52020-09-25 17:14:31 -060021from chromite.lib import constants
22from chromite.lib import cros_build_lib
LaMont Jonesed9a5de2021-02-03 11:06:12 -070023from chromite.lib import osutils
24
Mike Frysinger1cc8f1f2022-04-28 22:40:40 -040025
Jeremy Bettise87bbaf2022-07-07 11:57:16 -060026def get_fw_loc(fw_loc: int) -> str:
Alex Klein1699fab2022-09-08 08:46:06 -060027 """Get firmware_builder.py location.
Azizur Rahmanc6cf6e92021-10-21 18:58:19 +000028
Alex Klein1699fab2022-09-08 08:46:06 -060029 Args:
Alex Klein611dddd2022-10-11 17:02:01 -060030 fw_loc: FwLocation enum.
Azizur Rahmanc6cf6e92021-10-21 18:58:19 +000031
Alex Klein1699fab2022-09-08 08:46:06 -060032 Returns:
Alex Klein611dddd2022-10-11 17:02:01 -060033 path to firmware_builder.py for valid fw_loc.
Alex Klein1699fab2022-09-08 08:46:06 -060034 """
35 return {
36 common_pb2.PLATFORM_EC: "src/platform/ec/",
37 common_pb2.PLATFORM_ZEPHYR: "src/platform/ec/zephyr/",
38 common_pb2.PLATFORM_TI50: "src/platform/ti50/common/",
39 common_pb2.PLATFORM_CR50: "src/platform/cr50/",
40 }.get(fw_loc, "")
Azizur Rahmanc6cf6e92021-10-21 18:58:19 +000041
Jett Rink17ed0f52020-09-25 17:14:31 -060042
LaMont Jonesb7be76b2021-02-16 16:22:14 -070043def _call_entry(fw_loc, metric_proto, subcmd, *args, **kwargs):
Alex Klein1699fab2022-09-08 08:46:06 -060044 """Calls into firmware_builder.py with the specified subcmd."""
Jett Rink17ed0f52020-09-25 17:14:31 -060045
Alex Klein1699fab2022-09-08 08:46:06 -060046 fw_path = get_fw_loc(fw_loc)
47 if not fw_path:
48 cros_build_lib.Die(f"Unknown firmware location {fw_loc}.")
Jett Rink17ed0f52020-09-25 17:14:31 -060049
Alex Klein1699fab2022-09-08 08:46:06 -060050 entry_point = os.path.join(
51 constants.SOURCE_ROOT, fw_path, "firmware_builder.py"
52 )
Jett Rink17ed0f52020-09-25 17:14:31 -060053
Alex Klein1699fab2022-09-08 08:46:06 -060054 with tempfile.NamedTemporaryFile() as tmpfile:
55 cmd = [entry_point, "--metrics", tmpfile.name] + list(args)
56 for key, value in kwargs.items():
57 cmd += [f'--{key.replace("_", "-")}', value]
58 cmd += [subcmd]
LaMont Jonesdec69ad2021-01-27 13:02:00 -070059
Alex Klein1699fab2022-09-08 08:46:06 -060060 result = cros_build_lib.run(cmd, check=False)
Mike Frysingerd97829b2023-02-24 16:09:20 -050061 with open(tmpfile.name, "r", encoding="utf-8") as f:
Alex Klein1699fab2022-09-08 08:46:06 -060062 response = f.read()
Jett Rink17ed0f52020-09-25 17:14:31 -060063
Alex Klein1699fab2022-09-08 08:46:06 -060064 if metric_proto:
Alex Kleineec90f72023-02-03 10:53:12 -070065 if not response:
66 logging.warning("Metrics data empty.")
67 else:
68 # Parse the entire metric file as our metric proto (as a passthru).
69 # TODO(b/177907747): BundleFirmwareArtifacts doesn't use this
70 # (yet?), but firmware_builder.py requires it.
71 json_format.Parse(response, metric_proto)
Jett Rink17ed0f52020-09-25 17:14:31 -060072
Alex Klein1699fab2022-09-08 08:46:06 -060073 if result.returncode == 0:
74 return controller.RETURN_CODE_SUCCESS
75 else:
76 return controller.RETURN_CODE_COMPLETED_UNSUCCESSFULLY
Jett Rink17ed0f52020-09-25 17:14:31 -060077
78
79def _BuildAllTotFirmwareResponse(_input_proto, output_proto, _config):
Alex Klein1699fab2022-09-08 08:46:06 -060080 """Add a fw region metric to a successful response."""
Jett Rink17ed0f52020-09-25 17:14:31 -060081
Alex Klein1699fab2022-09-08 08:46:06 -060082 metric = output_proto.success.value.add()
83 metric.target_name = "foo"
84 metric.platform_name = "bar"
85 fw_section = metric.fw_section.add()
86 fw_section.region = "EC_RO"
87 fw_section.used = 100
88 fw_section.total = 150
Jett Rink17ed0f52020-09-25 17:14:31 -060089
LaMont Jonesed9a5de2021-02-03 11:06:12 -070090
Jett Rink17ed0f52020-09-25 17:14:31 -060091@faux.success(_BuildAllTotFirmwareResponse)
92@faux.empty_completed_unsuccessfully_error
Alex Klein1699fab2022-09-08 08:46:06 -060093@validate.require("firmware_location")
Jett Rink17ed0f52020-09-25 17:14:31 -060094@validate.validation_complete
95def BuildAllTotFirmware(input_proto, output_proto, _config):
Alex Klein1699fab2022-09-08 08:46:06 -060096 """Build all of the firmware targets at the specified location."""
Jett Rink17ed0f52020-09-25 17:14:31 -060097
Alex Klein1699fab2022-09-08 08:46:06 -060098 args = ["--code-coverage"] if input_proto.code_coverage else []
99 return _call_entry(
100 input_proto.firmware_location, output_proto.metrics, "build", *args
101 )
Jett Rink17ed0f52020-09-25 17:14:31 -0600102
103
104def _TestAllTotFirmwareResponse(_input_proto, output_proto, _config):
Alex Klein1699fab2022-09-08 08:46:06 -0600105 """Add a fw region metric to a successful response."""
Jett Rink17ed0f52020-09-25 17:14:31 -0600106
Alex Klein1699fab2022-09-08 08:46:06 -0600107 metric = output_proto.success.value.add()
108 metric.name = "foo-test"
Jett Rink17ed0f52020-09-25 17:14:31 -0600109
LaMont Jonesed9a5de2021-02-03 11:06:12 -0700110
Jett Rink17ed0f52020-09-25 17:14:31 -0600111@faux.success(_TestAllTotFirmwareResponse)
112@faux.empty_completed_unsuccessfully_error
Alex Klein1699fab2022-09-08 08:46:06 -0600113@validate.require("firmware_location")
Jett Rink17ed0f52020-09-25 17:14:31 -0600114@validate.validation_complete
115def TestAllTotFirmware(input_proto, output_proto, _config):
Alex Klein1699fab2022-09-08 08:46:06 -0600116 """Runs all of the firmware tests at the specified location."""
Jett Rink17ed0f52020-09-25 17:14:31 -0600117
Alex Klein1699fab2022-09-08 08:46:06 -0600118 args = ["--code-coverage"] if input_proto.code_coverage else []
119 return _call_entry(
120 input_proto.firmware_location, output_proto.metrics, "test", *args
121 )
LaMont Jonesdec69ad2021-01-27 13:02:00 -0700122
123
124def _BuildAllFirmwareResponse(_input_proto, output_proto, _config):
Alex Klein1699fab2022-09-08 08:46:06 -0600125 """Add a fw region metric to a successful response."""
LaMont Jonesdec69ad2021-01-27 13:02:00 -0700126
Alex Klein1699fab2022-09-08 08:46:06 -0600127 metric = output_proto.metrics.value.add()
128 metric.target_name = "foo"
129 metric.platform_name = "bar"
130 fw_section = metric.fw_section.add()
131 fw_section.region = "EC_RO"
132 fw_section.used = 100
133 fw_section.total = 150
LaMont Jonesdec69ad2021-01-27 13:02:00 -0700134
LaMont Jonesed9a5de2021-02-03 11:06:12 -0700135
LaMont Jonesdec69ad2021-01-27 13:02:00 -0700136@faux.success(_BuildAllFirmwareResponse)
137@faux.empty_completed_unsuccessfully_error
Alex Klein1699fab2022-09-08 08:46:06 -0600138@validate.require("firmware_location")
LaMont Jonesdec69ad2021-01-27 13:02:00 -0700139@validate.validation_complete
140def BuildAllFirmware(input_proto, output_proto, _config):
Alex Klein1699fab2022-09-08 08:46:06 -0600141 """Build all of the firmware targets at the specified location."""
LaMont Jonesdec69ad2021-01-27 13:02:00 -0700142
Alex Klein1699fab2022-09-08 08:46:06 -0600143 args = ["--code-coverage"] if input_proto.code_coverage else []
144 return _call_entry(
145 input_proto.firmware_location, output_proto.metrics, "build", *args
146 )
LaMont Jonesdec69ad2021-01-27 13:02:00 -0700147
148
149def _TestAllFirmwareResponse(_input_proto, output_proto, _config):
Alex Klein1699fab2022-09-08 08:46:06 -0600150 """Add a fw region metric to a successful response."""
LaMont Jonesdec69ad2021-01-27 13:02:00 -0700151
Alex Klein1699fab2022-09-08 08:46:06 -0600152 metric = output_proto.success.value.add()
153 metric.name = "foo-test"
LaMont Jonesdec69ad2021-01-27 13:02:00 -0700154
LaMont Jonesed9a5de2021-02-03 11:06:12 -0700155
LaMont Jonesdec69ad2021-01-27 13:02:00 -0700156@faux.success(_TestAllFirmwareResponse)
157@faux.empty_completed_unsuccessfully_error
Alex Klein1699fab2022-09-08 08:46:06 -0600158@validate.require("firmware_location")
LaMont Jonesdec69ad2021-01-27 13:02:00 -0700159@validate.validation_complete
160def TestAllFirmware(input_proto, output_proto, _config):
Alex Klein1699fab2022-09-08 08:46:06 -0600161 """Runs all of the firmware tests at the specified location."""
LaMont Jonesdec69ad2021-01-27 13:02:00 -0700162
Alex Klein1699fab2022-09-08 08:46:06 -0600163 args = ["--code-coverage"] if input_proto.code_coverage else []
164 return _call_entry(
165 input_proto.firmware_location, output_proto.metrics, "test", *args
166 )
LaMont Jonesdec69ad2021-01-27 13:02:00 -0700167
168
169def _BundleFirmwareArtifactsResponse(_input_proto, output_proto, _config):
Alex Klein1699fab2022-09-08 08:46:06 -0600170 """Add a fw region metric to a successful response."""
LaMont Jonesdec69ad2021-01-27 13:02:00 -0700171
Alex Klein1699fab2022-09-08 08:46:06 -0600172 metric = output_proto.success.value.add()
173 metric.name = "foo-test"
LaMont Jonesdec69ad2021-01-27 13:02:00 -0700174
LaMont Jonesed9a5de2021-02-03 11:06:12 -0700175
LaMont Jonesdec69ad2021-01-27 13:02:00 -0700176@faux.success(_BundleFirmwareArtifactsResponse)
177@faux.empty_completed_unsuccessfully_error
LaMont Jonesdec69ad2021-01-27 13:02:00 -0700178@validate.validation_complete
179def BundleFirmwareArtifacts(input_proto, output_proto, _config):
Alex Klein1699fab2022-09-08 08:46:06 -0600180 """Runs all of the firmware tests at the specified location."""
LaMont Jonesdec69ad2021-01-27 13:02:00 -0700181
Alex Klein1699fab2022-09-08 08:46:06 -0600182 if len(input_proto.artifacts.output_artifacts) > 1:
183 raise ValueError("Must have exactly one output_artifact entry")
LaMont Jonesdec69ad2021-01-27 13:02:00 -0700184
Alex Klein1699fab2022-09-08 08:46:06 -0600185 with osutils.TempDir(delete=False) as tmpdir:
186 info = input_proto.artifacts.output_artifacts[0]
187 metadata_path = os.path.join(tmpdir, "firmware_metadata.jsonpb")
188 args = []
189 if input_proto.artifacts.FIRMWARE_LCOV in info.artifact_types:
190 args += ["--code-coverage"]
191 resp = _call_entry(
192 info.location,
193 None,
194 "bundle",
195 *args,
196 output_dir=tmpdir,
197 metadata=metadata_path,
198 )
199 file_paths = []
200 if os.path.exists(metadata_path):
Mike Frysingerd97829b2023-02-24 16:09:20 -0500201 with open(metadata_path, "r", encoding="utf-8") as f:
Alex Klein1699fab2022-09-08 08:46:06 -0600202 metadata = json_format.Parse(
203 f.read(), firmware_pb2.FirmwareArtifactInfo()
204 )
205 else:
206 metadata = firmware_pb2.FirmwareArtifactInfo()
207 if input_proto.artifacts.FIRMWARE_TARBALL_INFO in info.artifact_types:
208 output_proto.artifacts.artifacts.add(
209 artifact_type=input_proto.artifacts.FIRMWARE_TARBALL_INFO,
210 location=info.location,
211 paths=[
212 common_pb2.Path(
213 path=metadata_path, location=common_pb2.Path.INSIDE
214 )
215 ],
216 )
LaMont Jones9a0594d2021-03-17 15:51:20 -0600217
Alex Klein1699fab2022-09-08 08:46:06 -0600218 full_path = lambda x: common_pb2.Path(
219 path=os.path.join(tmpdir, x.file_name),
220 location=common_pb2.Path.INSIDE,
221 )
LaMont Jones9a0594d2021-03-17 15:51:20 -0600222
Alex Klein1699fab2022-09-08 08:46:06 -0600223 for typ, name in (
224 (input_proto.artifacts.FIRMWARE_TARBALL, "tarball_info"),
225 (input_proto.artifacts.FIRMWARE_LCOV, "lcov_info"),
226 (input_proto.artifacts.CODE_COVERAGE_HTML, "coverage_html"),
227 ):
228 file_paths = [
229 full_path(x)
230 for x in metadata.objects
231 if x.WhichOneof("firmware_object_info") == name
232 ]
233 if file_paths and typ in info.artifact_types:
234 output_proto.artifacts.artifacts.add(
235 artifact_type=typ, paths=file_paths, location=info.location
236 )
LaMont Jones9a0594d2021-03-17 15:51:20 -0600237
Alex Klein1699fab2022-09-08 08:46:06 -0600238 return resp