blob: 75d1c0423fc60246d01bc3ece4d590423e07dad6 [file] [log] [blame]
Jett Rink17ed0f52020-09-25 17:14:31 -06001# -*- coding: utf-8 -*-
2# Copyright 2020 The Chromium OS Authors. All rights reserved.
3# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
LaMont Jonesed9a5de2021-02-03 11:06:12 -07005
Jett Rink17ed0f52020-09-25 17:14:31 -06006"""Firmware builder controller.
7
LaMont Jonesdec69ad2021-01-27 13:02:00 -07008Handle all firmware builder related functionality. Currently no service module
9exists: all of the work is done here.
Jett Rink17ed0f52020-09-25 17:14:31 -060010"""
11
12import os
13import tempfile
14
15from google.protobuf import json_format
16
17from chromite.api import controller
18from chromite.api import faux
19from chromite.api import validate
20from chromite.api.gen.chromite.api import firmware_pb2
LaMont Jonesdec69ad2021-01-27 13:02:00 -070021from chromite.api.gen.chromiumos import common_pb2
Jett Rink17ed0f52020-09-25 17:14:31 -060022from chromite.lib import constants
23from chromite.lib import cros_build_lib
LaMont Jonesed9a5de2021-02-03 11:06:12 -070024from chromite.lib import osutils
25
Jett Rink17ed0f52020-09-25 17:14:31 -060026
LaMont Jonesb7be76b2021-02-16 16:22:14 -070027def _call_entry(fw_loc, metric_proto, subcmd, *args, **kwargs):
Jett Rink17ed0f52020-09-25 17:14:31 -060028 """Calls into firmware_builder.py with the specified subcmd."""
29
LaMont Jonesdec69ad2021-01-27 13:02:00 -070030 if fw_loc == common_pb2.PLATFORM_EC:
Jett Rink17ed0f52020-09-25 17:14:31 -060031 fw_path = 'src/platform/ec/'
LaMont Jonesdec69ad2021-01-27 13:02:00 -070032 elif fw_loc == common_pb2.PLATFORM_ZEPHYR:
Jett Rink17ed0f52020-09-25 17:14:31 -060033 fw_path = 'src/platform/zephyr-chrome/'
LaMont Jonesdec69ad2021-01-27 13:02:00 -070034 elif fw_loc == common_pb2.PLATFORM_TI50:
Andrew Luo60439f32021-01-26 15:19:28 -080035 fw_path = 'src/platform/ti50/common/'
Jett Rink17ed0f52020-09-25 17:14:31 -060036 else:
LaMont Jonesdec69ad2021-01-27 13:02:00 -070037 cros_build_lib.Die(f'Unknown firmware location {fw_loc}.')
Jett Rink17ed0f52020-09-25 17:14:31 -060038
LaMont Jonesed9a5de2021-02-03 11:06:12 -070039 entry_point = os.path.join(constants.SOURCE_ROOT, fw_path,
40 'firmware_builder.py')
Jett Rink17ed0f52020-09-25 17:14:31 -060041
LaMont Jonesdec69ad2021-01-27 13:02:00 -070042 with tempfile.NamedTemporaryFile() as tmpfile:
LaMont Jonesb7be76b2021-02-16 16:22:14 -070043 cmd = [entry_point, '--metrics', tmpfile.name] + list(args)
LaMont Jonesdec69ad2021-01-27 13:02:00 -070044 for key, value in kwargs.items():
45 cmd += [f'--{key.replace("_", "-")}', value]
LaMont Jonesed9a5de2021-02-03 11:06:12 -070046 cmd += [subcmd]
LaMont Jonesdec69ad2021-01-27 13:02:00 -070047
48 result = cros_build_lib.run(cmd, check=False)
49 with open(tmpfile.name, 'r') as f:
Jett Rink17ed0f52020-09-25 17:14:31 -060050 response = f.read()
51
LaMont Jonesed9a5de2021-02-03 11:06:12 -070052 if metric_proto:
53 # Parse the entire metric file as our metric proto (as a passthru).
54 # TODO(b/177907747): BundleFirmwareArtifacts doesn't use this (yet?), but
55 # firmware_builder.py requires it.
56 json_format.Parse(response, metric_proto)
Jett Rink17ed0f52020-09-25 17:14:31 -060057
58 if result.returncode == 0:
59 return controller.RETURN_CODE_SUCCESS
60 else:
61 return controller.RETURN_CODE_COMPLETED_UNSUCCESSFULLY
62
63
64def _BuildAllTotFirmwareResponse(_input_proto, output_proto, _config):
LaMont Jonesdec69ad2021-01-27 13:02:00 -070065 """Add a fw region metric to a successful response."""
Jett Rink17ed0f52020-09-25 17:14:31 -060066
67 metric = output_proto.success.value.add()
68 metric.target_name = 'foo'
69 metric.platform_name = 'bar'
70 fw_section = metric.fw_section.add()
71 fw_section.region = firmware_pb2.FwBuildMetric.FwSection.EC_RO
72 fw_section.used = 100
73 fw_section.total = 150
74
LaMont Jonesed9a5de2021-02-03 11:06:12 -070075
Jett Rink17ed0f52020-09-25 17:14:31 -060076@faux.success(_BuildAllTotFirmwareResponse)
77@faux.empty_completed_unsuccessfully_error
78@validate.require('firmware_location')
79@validate.validation_complete
80def BuildAllTotFirmware(input_proto, output_proto, _config):
81 """Build all of the firmware targets at the specified location."""
82
LaMont Jonesb7be76b2021-02-16 16:22:14 -070083 args = ['--code-coverage'] if input_proto.code_coverage else []
Jett Rink17ed0f52020-09-25 17:14:31 -060084 return _call_entry(input_proto.firmware_location, output_proto.metrics,
LaMont Jonesb7be76b2021-02-16 16:22:14 -070085 'build', *args)
Jett Rink17ed0f52020-09-25 17:14:31 -060086
87
88def _TestAllTotFirmwareResponse(_input_proto, output_proto, _config):
LaMont Jonesdec69ad2021-01-27 13:02:00 -070089 """Add a fw region metric to a successful response."""
Jett Rink17ed0f52020-09-25 17:14:31 -060090
91 metric = output_proto.success.value.add()
92 metric.name = 'foo-test'
93
LaMont Jonesed9a5de2021-02-03 11:06:12 -070094
Jett Rink17ed0f52020-09-25 17:14:31 -060095@faux.success(_TestAllTotFirmwareResponse)
96@faux.empty_completed_unsuccessfully_error
97@validate.require('firmware_location')
98@validate.validation_complete
99def TestAllTotFirmware(input_proto, output_proto, _config):
100 """Runs all of the firmware tests at the specified location."""
101
LaMont Jonesb7be76b2021-02-16 16:22:14 -0700102 args = ['--code-coverage'] if input_proto.code_coverage else []
Jett Rink17ed0f52020-09-25 17:14:31 -0600103 return _call_entry(input_proto.firmware_location, output_proto.metrics,
LaMont Jonesb7be76b2021-02-16 16:22:14 -0700104 'test', *args)
LaMont Jonesdec69ad2021-01-27 13:02:00 -0700105
106
107def _BuildAllFirmwareResponse(_input_proto, output_proto, _config):
108 """Add a fw region metric to a successful response."""
109
Michael Mortensen515c8892021-02-26 15:37:59 -0700110 metric = output_proto.metrics.value.add()
LaMont Jonesdec69ad2021-01-27 13:02:00 -0700111 metric.target_name = 'foo'
112 metric.platform_name = 'bar'
113 fw_section = metric.fw_section.add()
114 fw_section.region = firmware_pb2.FwBuildMetric.FwSection.EC_RO
115 fw_section.used = 100
116 fw_section.total = 150
117
LaMont Jonesed9a5de2021-02-03 11:06:12 -0700118
LaMont Jonesdec69ad2021-01-27 13:02:00 -0700119@faux.success(_BuildAllFirmwareResponse)
120@faux.empty_completed_unsuccessfully_error
121@validate.require('firmware_location')
122@validate.validation_complete
123def BuildAllFirmware(input_proto, output_proto, _config):
124 """Build all of the firmware targets at the specified location."""
125
LaMont Jonesb7be76b2021-02-16 16:22:14 -0700126 args = ['--code-coverage'] if input_proto.code_coverage else []
LaMont Jonesdec69ad2021-01-27 13:02:00 -0700127 return _call_entry(input_proto.firmware_location, output_proto.metrics,
LaMont Jonesb7be76b2021-02-16 16:22:14 -0700128 'build', *args)
LaMont Jonesdec69ad2021-01-27 13:02:00 -0700129
130
131def _TestAllFirmwareResponse(_input_proto, output_proto, _config):
132 """Add a fw region metric to a successful response."""
133
134 metric = output_proto.success.value.add()
135 metric.name = 'foo-test'
136
LaMont Jonesed9a5de2021-02-03 11:06:12 -0700137
LaMont Jonesdec69ad2021-01-27 13:02:00 -0700138@faux.success(_TestAllFirmwareResponse)
139@faux.empty_completed_unsuccessfully_error
140@validate.require('firmware_location')
141@validate.validation_complete
142def TestAllFirmware(input_proto, output_proto, _config):
143 """Runs all of the firmware tests at the specified location."""
144
LaMont Jonesb7be76b2021-02-16 16:22:14 -0700145 args = ['--code-coverage'] if input_proto.code_coverage else []
LaMont Jonesdec69ad2021-01-27 13:02:00 -0700146 return _call_entry(input_proto.firmware_location, output_proto.metrics,
LaMont Jonesb7be76b2021-02-16 16:22:14 -0700147 'test', *args)
LaMont Jonesdec69ad2021-01-27 13:02:00 -0700148
149
150def _BundleFirmwareArtifactsResponse(_input_proto, output_proto, _config):
151 """Add a fw region metric to a successful response."""
152
153 metric = output_proto.success.value.add()
154 metric.name = 'foo-test'
155
LaMont Jonesed9a5de2021-02-03 11:06:12 -0700156
LaMont Jonesdec69ad2021-01-27 13:02:00 -0700157@faux.success(_BundleFirmwareArtifactsResponse)
158@faux.empty_completed_unsuccessfully_error
LaMont Jonesdec69ad2021-01-27 13:02:00 -0700159@validate.validation_complete
160def BundleFirmwareArtifacts(input_proto, output_proto, _config):
161 """Runs all of the firmware tests at the specified location."""
162
LaMont Jonesed9a5de2021-02-03 11:06:12 -0700163 if len(input_proto.artifacts.output_artifacts) > 1:
LaMont Jones9a0594d2021-03-17 15:51:20 -0600164 raise ValueError('Must have exactly one output_artifact entry')
LaMont Jonesdec69ad2021-01-27 13:02:00 -0700165
LaMont Jonesed9a5de2021-02-03 11:06:12 -0700166 with osutils.TempDir(delete=False) as tmpdir:
167 info = input_proto.artifacts.output_artifacts[0]
168 metadata_path = os.path.join(tmpdir, 'firmware_metadata.jsonpb')
LaMont Jonesb7be76b2021-02-16 16:22:14 -0700169 args = []
170 if input_proto.artifacts.FIRMWARE_LCOV in info.artifact_types:
171 args += ['--code-coverage']
LaMont Jonesdec69ad2021-01-27 13:02:00 -0700172 resp = _call_entry(
LaMont Jonesed9a5de2021-02-03 11:06:12 -0700173 info.location,
174 None,
175 'bundle',
LaMont Jonesb7be76b2021-02-16 16:22:14 -0700176 *args,
LaMont Jonesed9a5de2021-02-03 11:06:12 -0700177 output_dir=tmpdir,
178 metadata=metadata_path)
LaMont Jones9a0594d2021-03-17 15:51:20 -0600179 file_paths = []
180 if os.path.exists(metadata_path):
LaMont Jones80dc8bc2021-02-09 16:29:30 -0700181 with open(metadata_path, 'r') as f:
182 metadata = json_format.Parse(f.read(),
183 firmware_pb2.FirmwareArtifactInfo())
LaMont Jones9a0594d2021-03-17 15:51:20 -0600184 else:
185 metadata = firmware_pb2.FirmwareArtifactInfo()
186 if input_proto.artifacts.FIRMWARE_TARBALL_INFO in info.artifact_types:
187 output_proto.artifacts.artifacts.add(
LaMont Jonesed9a5de2021-02-03 11:06:12 -0700188 artifact_type=input_proto.artifacts.FIRMWARE_TARBALL_INFO,
LaMont Jones9a0594d2021-03-17 15:51:20 -0600189 location=info.location, paths=[
LaMont Jonesed9a5de2021-02-03 11:06:12 -0700190 common_pb2.Path(
191 path=metadata_path, location=common_pb2.Path.INSIDE)
192 ])
LaMont Jones9a0594d2021-03-17 15:51:20 -0600193
194 full_path = lambda x: common_pb2.Path(
195 path=os.path.join(tmpdir, x.file_name),
196 location=common_pb2.Path.INSIDE)
197
198 for typ, name in (
199 (input_proto.artifacts.FIRMWARE_TARBALL, 'tarball_info'),
200 (input_proto.artifacts.FIRMWARE_LCOV, 'lcov_info')):
201 file_paths = [
202 full_path(x) for x in metadata.objects
203 if x.WhichOneof('firmware_object_info') == name
LaMont Jones80dc8bc2021-02-09 16:29:30 -0700204 ]
LaMont Jones9a0594d2021-03-17 15:51:20 -0600205 if (file_paths and typ in info.artifact_types):
206 output_proto.artifacts.artifacts.add(
207 artifact_type=typ, paths=file_paths, location=info.location)
208
LaMont Jonesdec69ad2021-01-27 13:02:00 -0700209 return resp