1*4f2df630SAndroid Build Coastguard Worker#!/usr/bin/env python3 2*4f2df630SAndroid Build Coastguard Worker# Copyright 2023 The ChromiumOS Authors 3*4f2df630SAndroid Build Coastguard Worker# Use of this source code is governed by a BSD-style license that can be 4*4f2df630SAndroid Build Coastguard Worker# found in the LICENSE file. 5*4f2df630SAndroid Build Coastguard Worker 6*4f2df630SAndroid Build Coastguard Worker"""Build, bundle, or test all of the EC boards. 7*4f2df630SAndroid Build Coastguard Worker 8*4f2df630SAndroid Build Coastguard WorkerThis is the entry point for the custom firmware builder workflow recipe. It 9*4f2df630SAndroid Build Coastguard Workergets invoked by chromite/api/controller/firmware.py. 10*4f2df630SAndroid Build Coastguard Worker""" 11*4f2df630SAndroid Build Coastguard Worker 12*4f2df630SAndroid Build Coastguard Workerimport argparse 13*4f2df630SAndroid Build Coastguard Workerimport multiprocessing 14*4f2df630SAndroid Build Coastguard Workerimport os 15*4f2df630SAndroid Build Coastguard Workerimport subprocess 16*4f2df630SAndroid Build Coastguard Workerimport sys 17*4f2df630SAndroid Build Coastguard Worker 18*4f2df630SAndroid Build Coastguard Worker# pylint: disable=import-error 19*4f2df630SAndroid Build Coastguard Workerfrom google.protobuf import json_format 20*4f2df630SAndroid Build Coastguard Worker 21*4f2df630SAndroid Build Coastguard Worker# TODO(crbug/1181505): Code outside of chromite should not be importing from 22*4f2df630SAndroid Build Coastguard Worker# chromite.api.gen. Import json_format after that so we get the matching one. 23*4f2df630SAndroid Build Coastguard Workerfrom chromite.api.gen.chromite.api import firmware_pb2 24*4f2df630SAndroid Build Coastguard Worker 25*4f2df630SAndroid Build Coastguard Worker 26*4f2df630SAndroid Build Coastguard Workerdef build(opts): 27*4f2df630SAndroid Build Coastguard Worker """Builds all targets in extra/usb_updater 28*4f2df630SAndroid Build Coastguard Worker 29*4f2df630SAndroid Build Coastguard Worker Note that when we are building unit tests for code coverage, we don't 30*4f2df630SAndroid Build Coastguard Worker need this step. It builds EC **firmware** targets, but unit tests with 31*4f2df630SAndroid Build Coastguard Worker code coverage are all host-based. So if the --code-coverage flag is set, 32*4f2df630SAndroid Build Coastguard Worker we don't need to build the firmware targets and we can return without 33*4f2df630SAndroid Build Coastguard Worker doing anything but creating the metrics file and giving an informational 34*4f2df630SAndroid Build Coastguard Worker message. 35*4f2df630SAndroid Build Coastguard Worker """ 36*4f2df630SAndroid Build Coastguard Worker # Write empty metrics file as there is nothing to report but recipe needs 37*4f2df630SAndroid Build Coastguard Worker # the file to exist. 38*4f2df630SAndroid Build Coastguard Worker metrics = firmware_pb2.FwBuildMetricList() # pylint: disable=no-member 39*4f2df630SAndroid Build Coastguard Worker with open(opts.metrics, "w", encoding="utf-8") as f: 40*4f2df630SAndroid Build Coastguard Worker f.write(json_format.MessageToJson(metrics)) 41*4f2df630SAndroid Build Coastguard Worker 42*4f2df630SAndroid Build Coastguard Worker cmd = [ 43*4f2df630SAndroid Build Coastguard Worker "make", 44*4f2df630SAndroid Build Coastguard Worker "BOARD=cr50", 45*4f2df630SAndroid Build Coastguard Worker f"-j{opts.cpus}", 46*4f2df630SAndroid Build Coastguard Worker "-C", 47*4f2df630SAndroid Build Coastguard Worker "extra/usb_updater", 48*4f2df630SAndroid Build Coastguard Worker ] 49*4f2df630SAndroid Build Coastguard Worker print(f'# Running {" ".join(cmd)}.') 50*4f2df630SAndroid Build Coastguard Worker subprocess.run(cmd, cwd=os.path.dirname(__file__), check=True) 51*4f2df630SAndroid Build Coastguard Worker 52*4f2df630SAndroid Build Coastguard Worker 53*4f2df630SAndroid Build Coastguard Workerdef bundle(opts): 54*4f2df630SAndroid Build Coastguard Worker """Bundles all of the EC targets.""" 55*4f2df630SAndroid Build Coastguard Worker # Provide an empty metadata file since the file is required, but we 56*4f2df630SAndroid Build Coastguard Worker # don't have any artifacts that needs to be uploadeddd 57*4f2df630SAndroid Build Coastguard Worker if opts.metadata: 58*4f2df630SAndroid Build Coastguard Worker metadata = ( 59*4f2df630SAndroid Build Coastguard Worker firmware_pb2.FirmwareArtifactInfo() # pylint: disable=no-member 60*4f2df630SAndroid Build Coastguard Worker ) 61*4f2df630SAndroid Build Coastguard Worker with open(opts.metadata, "w", encoding="utf-8") as f: 62*4f2df630SAndroid Build Coastguard Worker f.write(json_format.MessageToJson(metadata)) 63*4f2df630SAndroid Build Coastguard Worker 64*4f2df630SAndroid Build Coastguard Worker 65*4f2df630SAndroid Build Coastguard Workerdef test(opts): 66*4f2df630SAndroid Build Coastguard Worker """Tests all of the EC targets.""" 67*4f2df630SAndroid Build Coastguard Worker del opts # Unused. 68*4f2df630SAndroid Build Coastguard Worker 69*4f2df630SAndroid Build Coastguard Worker 70*4f2df630SAndroid Build Coastguard Workerdef main(args): 71*4f2df630SAndroid Build Coastguard Worker """Builds, bundles, or tests all of the EC targets. 72*4f2df630SAndroid Build Coastguard Worker 73*4f2df630SAndroid Build Coastguard Worker Additionally, the tool reports build metrics. 74*4f2df630SAndroid Build Coastguard Worker """ 75*4f2df630SAndroid Build Coastguard Worker opts = parse_args(args) 76*4f2df630SAndroid Build Coastguard Worker 77*4f2df630SAndroid Build Coastguard Worker if not hasattr(opts, "func"): 78*4f2df630SAndroid Build Coastguard Worker print("Must select a valid sub command!") 79*4f2df630SAndroid Build Coastguard Worker return -1 80*4f2df630SAndroid Build Coastguard Worker 81*4f2df630SAndroid Build Coastguard Worker # Run selected sub command function 82*4f2df630SAndroid Build Coastguard Worker try: 83*4f2df630SAndroid Build Coastguard Worker opts.func(opts) 84*4f2df630SAndroid Build Coastguard Worker except subprocess.CalledProcessError: 85*4f2df630SAndroid Build Coastguard Worker return 1 86*4f2df630SAndroid Build Coastguard Worker else: 87*4f2df630SAndroid Build Coastguard Worker return 0 88*4f2df630SAndroid Build Coastguard Worker 89*4f2df630SAndroid Build Coastguard Worker 90*4f2df630SAndroid Build Coastguard Workerdef parse_args(args): 91*4f2df630SAndroid Build Coastguard Worker """Parses command-line arguments.""" 92*4f2df630SAndroid Build Coastguard Worker parser = argparse.ArgumentParser(description=__doc__) 93*4f2df630SAndroid Build Coastguard Worker 94*4f2df630SAndroid Build Coastguard Worker parser.add_argument( 95*4f2df630SAndroid Build Coastguard Worker "--cpus", 96*4f2df630SAndroid Build Coastguard Worker default=multiprocessing.cpu_count(), 97*4f2df630SAndroid Build Coastguard Worker help="The number of cores to use.", 98*4f2df630SAndroid Build Coastguard Worker ) 99*4f2df630SAndroid Build Coastguard Worker 100*4f2df630SAndroid Build Coastguard Worker parser.add_argument( 101*4f2df630SAndroid Build Coastguard Worker "--metrics", 102*4f2df630SAndroid Build Coastguard Worker dest="metrics", 103*4f2df630SAndroid Build Coastguard Worker required=True, 104*4f2df630SAndroid Build Coastguard Worker help="File to write the json-encoded MetricsList proto message.", 105*4f2df630SAndroid Build Coastguard Worker ) 106*4f2df630SAndroid Build Coastguard Worker 107*4f2df630SAndroid Build Coastguard Worker parser.add_argument( 108*4f2df630SAndroid Build Coastguard Worker "--metadata", 109*4f2df630SAndroid Build Coastguard Worker required=False, 110*4f2df630SAndroid Build Coastguard Worker help="Full pathname for the file in which to write build artifact " 111*4f2df630SAndroid Build Coastguard Worker "metadata.", 112*4f2df630SAndroid Build Coastguard Worker ) 113*4f2df630SAndroid Build Coastguard Worker 114*4f2df630SAndroid Build Coastguard Worker parser.add_argument( 115*4f2df630SAndroid Build Coastguard Worker "--output-dir", 116*4f2df630SAndroid Build Coastguard Worker required=False, 117*4f2df630SAndroid Build Coastguard Worker help="Full pathanme for the directory in which to bundle build " 118*4f2df630SAndroid Build Coastguard Worker "artifacts.", 119*4f2df630SAndroid Build Coastguard Worker ) 120*4f2df630SAndroid Build Coastguard Worker 121*4f2df630SAndroid Build Coastguard Worker parser.add_argument( 122*4f2df630SAndroid Build Coastguard Worker "--code-coverage", 123*4f2df630SAndroid Build Coastguard Worker required=False, 124*4f2df630SAndroid Build Coastguard Worker action="store_true", 125*4f2df630SAndroid Build Coastguard Worker help="Build host-based unit tests for code coverage.", 126*4f2df630SAndroid Build Coastguard Worker ) 127*4f2df630SAndroid Build Coastguard Worker 128*4f2df630SAndroid Build Coastguard Worker parser.add_argument( 129*4f2df630SAndroid Build Coastguard Worker "--bcs-version", 130*4f2df630SAndroid Build Coastguard Worker dest="bcs_version", 131*4f2df630SAndroid Build Coastguard Worker default="", 132*4f2df630SAndroid Build Coastguard Worker required=False, 133*4f2df630SAndroid Build Coastguard Worker # TODO(b/180008931): make this required=True. 134*4f2df630SAndroid Build Coastguard Worker help="BCS version to include in metadata.", 135*4f2df630SAndroid Build Coastguard Worker ) 136*4f2df630SAndroid Build Coastguard Worker 137*4f2df630SAndroid Build Coastguard Worker # Would make this required=True, but not available until 3.7 138*4f2df630SAndroid Build Coastguard Worker sub_cmds = parser.add_subparsers() 139*4f2df630SAndroid Build Coastguard Worker 140*4f2df630SAndroid Build Coastguard Worker build_cmd = sub_cmds.add_parser("build", help="Builds all firmware targets") 141*4f2df630SAndroid Build Coastguard Worker build_cmd.set_defaults(func=build) 142*4f2df630SAndroid Build Coastguard Worker 143*4f2df630SAndroid Build Coastguard Worker build_cmd = sub_cmds.add_parser( 144*4f2df630SAndroid Build Coastguard Worker "bundle", help="Does nothing, kept for compatibility" 145*4f2df630SAndroid Build Coastguard Worker ) 146*4f2df630SAndroid Build Coastguard Worker build_cmd.set_defaults(func=bundle) 147*4f2df630SAndroid Build Coastguard Worker 148*4f2df630SAndroid Build Coastguard Worker test_cmd = sub_cmds.add_parser( 149*4f2df630SAndroid Build Coastguard Worker "test", help="Does nothing, kept for compatibility" 150*4f2df630SAndroid Build Coastguard Worker ) 151*4f2df630SAndroid Build Coastguard Worker test_cmd.set_defaults(func=test) 152*4f2df630SAndroid Build Coastguard Worker 153*4f2df630SAndroid Build Coastguard Worker return parser.parse_args(args) 154*4f2df630SAndroid Build Coastguard Worker 155*4f2df630SAndroid Build Coastguard Worker 156*4f2df630SAndroid Build Coastguard Workerif __name__ == "__main__": 157*4f2df630SAndroid Build Coastguard Worker sys.exit(main(sys.argv[1:])) 158