blob: 93fa6e519fd4a03e39403e2d4b75408c7508ec39 [file] [log] [blame]
Jett Rink17ed0f52020-09-25 17:14:31 -06001# Copyright 2020 The Chromium OS Authors. All rights reserved.
2# 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"""
10
11import 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:
Azizur Rahmanc6cf6e92021-10-21 18:58:19 +000027 """Get firmware_builder.py location.
28
29 Args:
Jeremy Bettise87bbaf2022-07-07 11:57:16 -060030 fw_loc: FwLocation enum.
Azizur Rahmanc6cf6e92021-10-21 18:58:19 +000031
32 Returns:
Jeremy Bettise87bbaf2022-07-07 11:57:16 -060033 path to firmware_builder.py for valid fw_loc.
Azizur Rahmanc6cf6e92021-10-21 18:58:19 +000034 """
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, '')
41
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):
Jett Rink17ed0f52020-09-25 17:14:31 -060044 """Calls into firmware_builder.py with the specified subcmd."""
45
Azizur Rahmanc6cf6e92021-10-21 18:58:19 +000046 fw_path = get_fw_loc(fw_loc)
47 if not fw_path:
LaMont Jonesdec69ad2021-01-27 13:02:00 -070048 cros_build_lib.Die(f'Unknown firmware location {fw_loc}.')
Jett Rink17ed0f52020-09-25 17:14:31 -060049
LaMont Jonesed9a5de2021-02-03 11:06:12 -070050 entry_point = os.path.join(constants.SOURCE_ROOT, fw_path,
51 'firmware_builder.py')
Jett Rink17ed0f52020-09-25 17:14:31 -060052
LaMont Jonesdec69ad2021-01-27 13:02:00 -070053 with tempfile.NamedTemporaryFile() as tmpfile:
LaMont Jonesb7be76b2021-02-16 16:22:14 -070054 cmd = [entry_point, '--metrics', tmpfile.name] + list(args)
LaMont Jonesdec69ad2021-01-27 13:02:00 -070055 for key, value in kwargs.items():
56 cmd += [f'--{key.replace("_", "-")}', value]
LaMont Jonesed9a5de2021-02-03 11:06:12 -070057 cmd += [subcmd]
LaMont Jonesdec69ad2021-01-27 13:02:00 -070058
59 result = cros_build_lib.run(cmd, check=False)
60 with open(tmpfile.name, 'r') as f:
Jett Rink17ed0f52020-09-25 17:14:31 -060061 response = f.read()
62
LaMont Jonesed9a5de2021-02-03 11:06:12 -070063 if metric_proto:
64 # Parse the entire metric file as our metric proto (as a passthru).
65 # TODO(b/177907747): BundleFirmwareArtifacts doesn't use this (yet?), but
66 # firmware_builder.py requires it.
67 json_format.Parse(response, metric_proto)
Jett Rink17ed0f52020-09-25 17:14:31 -060068
69 if result.returncode == 0:
70 return controller.RETURN_CODE_SUCCESS
71 else:
72 return controller.RETURN_CODE_COMPLETED_UNSUCCESSFULLY
73
74
75def _BuildAllTotFirmwareResponse(_input_proto, output_proto, _config):
LaMont Jonesdec69ad2021-01-27 13:02:00 -070076 """Add a fw region metric to a successful response."""
Jett Rink17ed0f52020-09-25 17:14:31 -060077
78 metric = output_proto.success.value.add()
79 metric.target_name = 'foo'
80 metric.platform_name = 'bar'
81 fw_section = metric.fw_section.add()
Andrew Luod08045d2021-06-17 12:06:44 -070082 fw_section.region = 'EC_RO'
Jett Rink17ed0f52020-09-25 17:14:31 -060083 fw_section.used = 100
84 fw_section.total = 150
85
LaMont Jonesed9a5de2021-02-03 11:06:12 -070086
Jett Rink17ed0f52020-09-25 17:14:31 -060087@faux.success(_BuildAllTotFirmwareResponse)
88@faux.empty_completed_unsuccessfully_error
89@validate.require('firmware_location')
90@validate.validation_complete
91def BuildAllTotFirmware(input_proto, output_proto, _config):
92 """Build all of the firmware targets at the specified location."""
93
LaMont Jonesb7be76b2021-02-16 16:22:14 -070094 args = ['--code-coverage'] if input_proto.code_coverage else []
Jett Rink17ed0f52020-09-25 17:14:31 -060095 return _call_entry(input_proto.firmware_location, output_proto.metrics,
LaMont Jonesb7be76b2021-02-16 16:22:14 -070096 'build', *args)
Jett Rink17ed0f52020-09-25 17:14:31 -060097
98
99def _TestAllTotFirmwareResponse(_input_proto, output_proto, _config):
LaMont Jonesdec69ad2021-01-27 13:02:00 -0700100 """Add a fw region metric to a successful response."""
Jett Rink17ed0f52020-09-25 17:14:31 -0600101
102 metric = output_proto.success.value.add()
103 metric.name = 'foo-test'
104
LaMont Jonesed9a5de2021-02-03 11:06:12 -0700105
Jett Rink17ed0f52020-09-25 17:14:31 -0600106@faux.success(_TestAllTotFirmwareResponse)
107@faux.empty_completed_unsuccessfully_error
108@validate.require('firmware_location')
109@validate.validation_complete
110def TestAllTotFirmware(input_proto, output_proto, _config):
111 """Runs all of the firmware tests at the specified location."""
112
LaMont Jonesb7be76b2021-02-16 16:22:14 -0700113 args = ['--code-coverage'] if input_proto.code_coverage else []
Jett Rink17ed0f52020-09-25 17:14:31 -0600114 return _call_entry(input_proto.firmware_location, output_proto.metrics,
LaMont Jonesb7be76b2021-02-16 16:22:14 -0700115 'test', *args)
LaMont Jonesdec69ad2021-01-27 13:02:00 -0700116
117
118def _BuildAllFirmwareResponse(_input_proto, output_proto, _config):
119 """Add a fw region metric to a successful response."""
120
Michael Mortensen515c8892021-02-26 15:37:59 -0700121 metric = output_proto.metrics.value.add()
LaMont Jonesdec69ad2021-01-27 13:02:00 -0700122 metric.target_name = 'foo'
123 metric.platform_name = 'bar'
124 fw_section = metric.fw_section.add()
Andrew Luod08045d2021-06-17 12:06:44 -0700125 fw_section.region = 'EC_RO'
LaMont Jonesdec69ad2021-01-27 13:02:00 -0700126 fw_section.used = 100
127 fw_section.total = 150
128
LaMont Jonesed9a5de2021-02-03 11:06:12 -0700129
LaMont Jonesdec69ad2021-01-27 13:02:00 -0700130@faux.success(_BuildAllFirmwareResponse)
131@faux.empty_completed_unsuccessfully_error
132@validate.require('firmware_location')
133@validate.validation_complete
134def BuildAllFirmware(input_proto, output_proto, _config):
135 """Build all of the firmware targets at the specified location."""
136
LaMont Jonesb7be76b2021-02-16 16:22:14 -0700137 args = ['--code-coverage'] if input_proto.code_coverage else []
LaMont Jonesdec69ad2021-01-27 13:02:00 -0700138 return _call_entry(input_proto.firmware_location, output_proto.metrics,
LaMont Jonesb7be76b2021-02-16 16:22:14 -0700139 'build', *args)
LaMont Jonesdec69ad2021-01-27 13:02:00 -0700140
141
142def _TestAllFirmwareResponse(_input_proto, output_proto, _config):
143 """Add a fw region metric to a successful response."""
144
145 metric = output_proto.success.value.add()
146 metric.name = 'foo-test'
147
LaMont Jonesed9a5de2021-02-03 11:06:12 -0700148
LaMont Jonesdec69ad2021-01-27 13:02:00 -0700149@faux.success(_TestAllFirmwareResponse)
150@faux.empty_completed_unsuccessfully_error
151@validate.require('firmware_location')
152@validate.validation_complete
153def TestAllFirmware(input_proto, output_proto, _config):
154 """Runs all of the firmware tests at the specified location."""
155
LaMont Jonesb7be76b2021-02-16 16:22:14 -0700156 args = ['--code-coverage'] if input_proto.code_coverage else []
LaMont Jonesdec69ad2021-01-27 13:02:00 -0700157 return _call_entry(input_proto.firmware_location, output_proto.metrics,
LaMont Jonesb7be76b2021-02-16 16:22:14 -0700158 'test', *args)
LaMont Jonesdec69ad2021-01-27 13:02:00 -0700159
160
161def _BundleFirmwareArtifactsResponse(_input_proto, output_proto, _config):
162 """Add a fw region metric to a successful response."""
163
164 metric = output_proto.success.value.add()
165 metric.name = 'foo-test'
166
LaMont Jonesed9a5de2021-02-03 11:06:12 -0700167
LaMont Jonesdec69ad2021-01-27 13:02:00 -0700168@faux.success(_BundleFirmwareArtifactsResponse)
169@faux.empty_completed_unsuccessfully_error
LaMont Jonesdec69ad2021-01-27 13:02:00 -0700170@validate.validation_complete
171def BundleFirmwareArtifacts(input_proto, output_proto, _config):
172 """Runs all of the firmware tests at the specified location."""
173
LaMont Jonesed9a5de2021-02-03 11:06:12 -0700174 if len(input_proto.artifacts.output_artifacts) > 1:
LaMont Jones9a0594d2021-03-17 15:51:20 -0600175 raise ValueError('Must have exactly one output_artifact entry')
LaMont Jonesdec69ad2021-01-27 13:02:00 -0700176
LaMont Jonesed9a5de2021-02-03 11:06:12 -0700177 with osutils.TempDir(delete=False) as tmpdir:
178 info = input_proto.artifacts.output_artifacts[0]
179 metadata_path = os.path.join(tmpdir, 'firmware_metadata.jsonpb')
LaMont Jonesb7be76b2021-02-16 16:22:14 -0700180 args = []
181 if input_proto.artifacts.FIRMWARE_LCOV in info.artifact_types:
182 args += ['--code-coverage']
LaMont Jonesdec69ad2021-01-27 13:02:00 -0700183 resp = _call_entry(
LaMont Jonesed9a5de2021-02-03 11:06:12 -0700184 info.location,
185 None,
186 'bundle',
LaMont Jonesb7be76b2021-02-16 16:22:14 -0700187 *args,
LaMont Jonesed9a5de2021-02-03 11:06:12 -0700188 output_dir=tmpdir,
189 metadata=metadata_path)
LaMont Jones9a0594d2021-03-17 15:51:20 -0600190 file_paths = []
191 if os.path.exists(metadata_path):
LaMont Jones80dc8bc2021-02-09 16:29:30 -0700192 with open(metadata_path, 'r') as f:
193 metadata = json_format.Parse(f.read(),
194 firmware_pb2.FirmwareArtifactInfo())
LaMont Jones9a0594d2021-03-17 15:51:20 -0600195 else:
196 metadata = firmware_pb2.FirmwareArtifactInfo()
197 if input_proto.artifacts.FIRMWARE_TARBALL_INFO in info.artifact_types:
198 output_proto.artifacts.artifacts.add(
LaMont Jonesed9a5de2021-02-03 11:06:12 -0700199 artifact_type=input_proto.artifacts.FIRMWARE_TARBALL_INFO,
LaMont Jones9a0594d2021-03-17 15:51:20 -0600200 location=info.location, paths=[
LaMont Jonesed9a5de2021-02-03 11:06:12 -0700201 common_pb2.Path(
202 path=metadata_path, location=common_pb2.Path.INSIDE)
203 ])
LaMont Jones9a0594d2021-03-17 15:51:20 -0600204
205 full_path = lambda x: common_pb2.Path(
206 path=os.path.join(tmpdir, x.file_name),
207 location=common_pb2.Path.INSIDE)
208
209 for typ, name in (
210 (input_proto.artifacts.FIRMWARE_TARBALL, 'tarball_info'),
Jeremy Bettise87bbaf2022-07-07 11:57:16 -0600211 (input_proto.artifacts.FIRMWARE_LCOV, 'lcov_info'),
212 (input_proto.artifacts.CODE_COVERAGE_HTML, 'coverage_html')):
LaMont Jones9a0594d2021-03-17 15:51:20 -0600213 file_paths = [
214 full_path(x) for x in metadata.objects
215 if x.WhichOneof('firmware_object_info') == name
LaMont Jones80dc8bc2021-02-09 16:29:30 -0700216 ]
LaMont Jones9a0594d2021-03-17 15:51:20 -0600217 if (file_paths and typ in info.artifact_types):
218 output_proto.artifacts.artifacts.add(
219 artifact_type=typ, paths=file_paths, location=info.location)
220
LaMont Jonesdec69ad2021-01-27 13:02:00 -0700221 return resp