blob: 7347836a4ddf1060180e7eaf4814f476d76e8cb8 [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
Jett Rink17ed0f52020-09-25 17:14:31 -060025
LaMont Jonesb7be76b2021-02-16 16:22:14 -070026def _call_entry(fw_loc, metric_proto, subcmd, *args, **kwargs):
Jett Rink17ed0f52020-09-25 17:14:31 -060027 """Calls into firmware_builder.py with the specified subcmd."""
28
LaMont Jonesdec69ad2021-01-27 13:02:00 -070029 if fw_loc == common_pb2.PLATFORM_EC:
Jett Rink17ed0f52020-09-25 17:14:31 -060030 fw_path = 'src/platform/ec/'
LaMont Jonesdec69ad2021-01-27 13:02:00 -070031 elif fw_loc == common_pb2.PLATFORM_ZEPHYR:
Jack Rosenthald56a9b22021-03-25 15:36:42 -060032 fw_path = 'src/platform/ec/zephyr/'
LaMont Jonesdec69ad2021-01-27 13:02:00 -070033 elif fw_loc == common_pb2.PLATFORM_TI50:
Andrew Luo60439f32021-01-26 15:19:28 -080034 fw_path = 'src/platform/ti50/common/'
Azizur Rahman6a063292021-10-18 18:35:46 +000035 elif fw_loc == common_pb2.PLATFORM_CR50:
36 fw_path = 'src/platform/cr50/'
Jett Rink17ed0f52020-09-25 17:14:31 -060037 else:
LaMont Jonesdec69ad2021-01-27 13:02:00 -070038 cros_build_lib.Die(f'Unknown firmware location {fw_loc}.')
Jett Rink17ed0f52020-09-25 17:14:31 -060039
LaMont Jonesed9a5de2021-02-03 11:06:12 -070040 entry_point = os.path.join(constants.SOURCE_ROOT, fw_path,
41 'firmware_builder.py')
Jett Rink17ed0f52020-09-25 17:14:31 -060042
LaMont Jonesdec69ad2021-01-27 13:02:00 -070043 with tempfile.NamedTemporaryFile() as tmpfile:
LaMont Jonesb7be76b2021-02-16 16:22:14 -070044 cmd = [entry_point, '--metrics', tmpfile.name] + list(args)
LaMont Jonesdec69ad2021-01-27 13:02:00 -070045 for key, value in kwargs.items():
46 cmd += [f'--{key.replace("_", "-")}', value]
LaMont Jonesed9a5de2021-02-03 11:06:12 -070047 cmd += [subcmd]
LaMont Jonesdec69ad2021-01-27 13:02:00 -070048
49 result = cros_build_lib.run(cmd, check=False)
50 with open(tmpfile.name, 'r') as f:
Jett Rink17ed0f52020-09-25 17:14:31 -060051 response = f.read()
52
LaMont Jonesed9a5de2021-02-03 11:06:12 -070053 if metric_proto:
54 # Parse the entire metric file as our metric proto (as a passthru).
55 # TODO(b/177907747): BundleFirmwareArtifacts doesn't use this (yet?), but
56 # firmware_builder.py requires it.
57 json_format.Parse(response, metric_proto)
Jett Rink17ed0f52020-09-25 17:14:31 -060058
59 if result.returncode == 0:
60 return controller.RETURN_CODE_SUCCESS
61 else:
62 return controller.RETURN_CODE_COMPLETED_UNSUCCESSFULLY
63
64
65def _BuildAllTotFirmwareResponse(_input_proto, output_proto, _config):
LaMont Jonesdec69ad2021-01-27 13:02:00 -070066 """Add a fw region metric to a successful response."""
Jett Rink17ed0f52020-09-25 17:14:31 -060067
68 metric = output_proto.success.value.add()
69 metric.target_name = 'foo'
70 metric.platform_name = 'bar'
71 fw_section = metric.fw_section.add()
Andrew Luod08045d2021-06-17 12:06:44 -070072 fw_section.region = 'EC_RO'
Jett Rink17ed0f52020-09-25 17:14:31 -060073 fw_section.used = 100
74 fw_section.total = 150
75
LaMont Jonesed9a5de2021-02-03 11:06:12 -070076
Jett Rink17ed0f52020-09-25 17:14:31 -060077@faux.success(_BuildAllTotFirmwareResponse)
78@faux.empty_completed_unsuccessfully_error
79@validate.require('firmware_location')
80@validate.validation_complete
81def BuildAllTotFirmware(input_proto, output_proto, _config):
82 """Build all of the firmware targets at the specified location."""
83
LaMont Jonesb7be76b2021-02-16 16:22:14 -070084 args = ['--code-coverage'] if input_proto.code_coverage else []
Jett Rink17ed0f52020-09-25 17:14:31 -060085 return _call_entry(input_proto.firmware_location, output_proto.metrics,
LaMont Jonesb7be76b2021-02-16 16:22:14 -070086 'build', *args)
Jett Rink17ed0f52020-09-25 17:14:31 -060087
88
89def _TestAllTotFirmwareResponse(_input_proto, output_proto, _config):
LaMont Jonesdec69ad2021-01-27 13:02:00 -070090 """Add a fw region metric to a successful response."""
Jett Rink17ed0f52020-09-25 17:14:31 -060091
92 metric = output_proto.success.value.add()
93 metric.name = 'foo-test'
94
LaMont Jonesed9a5de2021-02-03 11:06:12 -070095
Jett Rink17ed0f52020-09-25 17:14:31 -060096@faux.success(_TestAllTotFirmwareResponse)
97@faux.empty_completed_unsuccessfully_error
98@validate.require('firmware_location')
99@validate.validation_complete
100def TestAllTotFirmware(input_proto, output_proto, _config):
101 """Runs all of the firmware tests at the specified location."""
102
LaMont Jonesb7be76b2021-02-16 16:22:14 -0700103 args = ['--code-coverage'] if input_proto.code_coverage else []
Jett Rink17ed0f52020-09-25 17:14:31 -0600104 return _call_entry(input_proto.firmware_location, output_proto.metrics,
LaMont Jonesb7be76b2021-02-16 16:22:14 -0700105 'test', *args)
LaMont Jonesdec69ad2021-01-27 13:02:00 -0700106
107
108def _BuildAllFirmwareResponse(_input_proto, output_proto, _config):
109 """Add a fw region metric to a successful response."""
110
Michael Mortensen515c8892021-02-26 15:37:59 -0700111 metric = output_proto.metrics.value.add()
LaMont Jonesdec69ad2021-01-27 13:02:00 -0700112 metric.target_name = 'foo'
113 metric.platform_name = 'bar'
114 fw_section = metric.fw_section.add()
Andrew Luod08045d2021-06-17 12:06:44 -0700115 fw_section.region = 'EC_RO'
LaMont Jonesdec69ad2021-01-27 13:02:00 -0700116 fw_section.used = 100
117 fw_section.total = 150
118
LaMont Jonesed9a5de2021-02-03 11:06:12 -0700119
LaMont Jonesdec69ad2021-01-27 13:02:00 -0700120@faux.success(_BuildAllFirmwareResponse)
121@faux.empty_completed_unsuccessfully_error
122@validate.require('firmware_location')
123@validate.validation_complete
124def BuildAllFirmware(input_proto, output_proto, _config):
125 """Build all of the firmware targets at the specified location."""
126
LaMont Jonesb7be76b2021-02-16 16:22:14 -0700127 args = ['--code-coverage'] if input_proto.code_coverage else []
LaMont Jonesdec69ad2021-01-27 13:02:00 -0700128 return _call_entry(input_proto.firmware_location, output_proto.metrics,
LaMont Jonesb7be76b2021-02-16 16:22:14 -0700129 'build', *args)
LaMont Jonesdec69ad2021-01-27 13:02:00 -0700130
131
132def _TestAllFirmwareResponse(_input_proto, output_proto, _config):
133 """Add a fw region metric to a successful response."""
134
135 metric = output_proto.success.value.add()
136 metric.name = 'foo-test'
137
LaMont Jonesed9a5de2021-02-03 11:06:12 -0700138
LaMont Jonesdec69ad2021-01-27 13:02:00 -0700139@faux.success(_TestAllFirmwareResponse)
140@faux.empty_completed_unsuccessfully_error
141@validate.require('firmware_location')
142@validate.validation_complete
143def TestAllFirmware(input_proto, output_proto, _config):
144 """Runs all of the firmware tests at the specified location."""
145
LaMont Jonesb7be76b2021-02-16 16:22:14 -0700146 args = ['--code-coverage'] if input_proto.code_coverage else []
LaMont Jonesdec69ad2021-01-27 13:02:00 -0700147 return _call_entry(input_proto.firmware_location, output_proto.metrics,
LaMont Jonesb7be76b2021-02-16 16:22:14 -0700148 'test', *args)
LaMont Jonesdec69ad2021-01-27 13:02:00 -0700149
150
151def _BundleFirmwareArtifactsResponse(_input_proto, output_proto, _config):
152 """Add a fw region metric to a successful response."""
153
154 metric = output_proto.success.value.add()
155 metric.name = 'foo-test'
156
LaMont Jonesed9a5de2021-02-03 11:06:12 -0700157
LaMont Jonesdec69ad2021-01-27 13:02:00 -0700158@faux.success(_BundleFirmwareArtifactsResponse)
159@faux.empty_completed_unsuccessfully_error
LaMont Jonesdec69ad2021-01-27 13:02:00 -0700160@validate.validation_complete
161def BundleFirmwareArtifacts(input_proto, output_proto, _config):
162 """Runs all of the firmware tests at the specified location."""
163
LaMont Jonesed9a5de2021-02-03 11:06:12 -0700164 if len(input_proto.artifacts.output_artifacts) > 1:
LaMont Jones9a0594d2021-03-17 15:51:20 -0600165 raise ValueError('Must have exactly one output_artifact entry')
LaMont Jonesdec69ad2021-01-27 13:02:00 -0700166
LaMont Jonesed9a5de2021-02-03 11:06:12 -0700167 with osutils.TempDir(delete=False) as tmpdir:
168 info = input_proto.artifacts.output_artifacts[0]
169 metadata_path = os.path.join(tmpdir, 'firmware_metadata.jsonpb')
LaMont Jonesb7be76b2021-02-16 16:22:14 -0700170 args = []
171 if input_proto.artifacts.FIRMWARE_LCOV in info.artifact_types:
172 args += ['--code-coverage']
LaMont Jonesdec69ad2021-01-27 13:02:00 -0700173 resp = _call_entry(
LaMont Jonesed9a5de2021-02-03 11:06:12 -0700174 info.location,
175 None,
176 'bundle',
LaMont Jonesb7be76b2021-02-16 16:22:14 -0700177 *args,
LaMont Jonesed9a5de2021-02-03 11:06:12 -0700178 output_dir=tmpdir,
179 metadata=metadata_path)
LaMont Jones9a0594d2021-03-17 15:51:20 -0600180 file_paths = []
181 if os.path.exists(metadata_path):
LaMont Jones80dc8bc2021-02-09 16:29:30 -0700182 with open(metadata_path, 'r') as f:
183 metadata = json_format.Parse(f.read(),
184 firmware_pb2.FirmwareArtifactInfo())
LaMont Jones9a0594d2021-03-17 15:51:20 -0600185 else:
186 metadata = firmware_pb2.FirmwareArtifactInfo()
187 if input_proto.artifacts.FIRMWARE_TARBALL_INFO in info.artifact_types:
188 output_proto.artifacts.artifacts.add(
LaMont Jonesed9a5de2021-02-03 11:06:12 -0700189 artifact_type=input_proto.artifacts.FIRMWARE_TARBALL_INFO,
LaMont Jones9a0594d2021-03-17 15:51:20 -0600190 location=info.location, paths=[
LaMont Jonesed9a5de2021-02-03 11:06:12 -0700191 common_pb2.Path(
192 path=metadata_path, location=common_pb2.Path.INSIDE)
193 ])
LaMont Jones9a0594d2021-03-17 15:51:20 -0600194
195 full_path = lambda x: common_pb2.Path(
196 path=os.path.join(tmpdir, x.file_name),
197 location=common_pb2.Path.INSIDE)
198
199 for typ, name in (
200 (input_proto.artifacts.FIRMWARE_TARBALL, 'tarball_info'),
201 (input_proto.artifacts.FIRMWARE_LCOV, 'lcov_info')):
202 file_paths = [
203 full_path(x) for x in metadata.objects
204 if x.WhichOneof('firmware_object_info') == name
LaMont Jones80dc8bc2021-02-09 16:29:30 -0700205 ]
LaMont Jones9a0594d2021-03-17 15:51:20 -0600206 if (file_paths and typ in info.artifact_types):
207 output_proto.artifacts.artifacts.add(
208 artifact_type=typ, paths=file_paths, location=info.location)
209
LaMont Jonesdec69ad2021-01-27 13:02:00 -0700210 return resp