blob: d88f4b2eb545e910ddea0b262914d52cb759f42a [file] [log] [blame]
Paul Fagerburg3b534f92019-11-07 15:05:22 -07001#!/usr/bin/env python3
2# -*- coding: utf-8 -*-
Paul Fagerburg92fcb4b2020-02-19 21:21:43 -07003#
4# Copyright 2020 The Chromium OS Authors. All rights reserved.
5# Use of this source code is governed by a BSD-style license that can be
6# found in the LICENSE file.
7#
Paul Fagerburge868e832020-01-22 17:14:04 -07008"""Create a new variant of an existing reference board
Paul Fagerburg3b534f92019-11-07 15:05:22 -07009
10This program will call all of the scripts that create the various pieces
11of a new variant. For example to create a new variant of the hatch base
12board, the following scripts are called:
13
Paul Fagerburg5f794bf2020-02-12 13:01:36 -070014* platform/dev/contrib/variant/create_coreboot_variant.sh
Paul Fagerburg3b534f92019-11-07 15:05:22 -070015* platform/dev/contrib/variant/create_coreboot_config.sh
16* private-overlays/baseboard-hatch-private/sys-boot/
17 * coreboot-private-files-hatch/files/add_fitimage.sh
18 * coreboot-private-files-hatch/asset_generation/gen_fit_image.sh
19 * Outside the chroot, because it uses WINE to run the FIT tools
20* platform/dev/contrib/variant/create_initial_ec_image.sh
21* platform/dev/contrib/variant/add_variant_to_yaml.sh
22* private-overlays/overlay-hatch-private/chromeos-base/
23 * chromeos-config-bsp-hatch-private/add_variant.sh
24
25Once the scripts are done, the following repos have changes
26
27* third_party/coreboot
28* third_party/chromiumos-overlay
29* private-overlays/baseboard-hatch-private
30* platform/ec
31* private-overlays/overlay-hatch-private
32* overlays
33
Paul Fagerburge868e832020-01-22 17:14:04 -070034The program has support for multiple reference boards, so the repos, directories,
35and scripts above can change depending on what the reference board is.
Paul Fagerburg3b534f92019-11-07 15:05:22 -070036"""
37
38from __future__ import print_function
39import argparse
Paul Fagerburgbab5dde2020-01-10 15:10:29 -070040import importlib
Paul Fagerburg8d850932020-02-25 14:13:32 -070041import json
Paul Fagerburg3b534f92019-11-07 15:05:22 -070042import logging
43import os
44import re
45import shutil
46import subprocess
47import sys
Paul Fagerburg1d043c32020-02-03 08:57:08 -070048from chromite.lib import git
Paul Fagerburga8c7e342020-02-25 13:30:49 -070049from chromite.lib import gerrit
Paul Fagerburg8d850932020-02-25 14:13:32 -070050import requests
Paul Fagerburgbab5dde2020-01-10 15:10:29 -070051import step_names
Paul Fagerburg3b534f92019-11-07 15:05:22 -070052import variant_status
53
54
55def main():
Paul Fagerburge868e832020-01-22 17:14:04 -070056 """Create a new variant of an existing reference board
Paul Fagerburg3b534f92019-11-07 15:05:22 -070057
58 This program automates the creation of a new variant of an existing
Paul Fagerburge868e832020-01-22 17:14:04 -070059 reference board by calling various scripts that copy the reference board,
60 modify files for the new variant, stage commits, and upload to gerrit.
Paul Fagerburg3b534f92019-11-07 15:05:22 -070061
62 Note that one of the following is required:
63 * --continue
64 * --board=BOARD --variant=VARIANT [--bug=BUG]
65 """
66 board, variant, bug, continue_flag = get_args()
67
68 if not check_flags(board, variant, bug, continue_flag):
69 return False
70
71 status = get_status(board, variant, bug, continue_flag)
72 if status is None:
73 return False
74
75 status.load()
76
Paul Fagerburg5f794bf2020-02-12 13:01:36 -070077 # Where is new_variant.py located?
78 status.my_loc = os.path.dirname(os.path.abspath(__file__))
79
Paul Fagerburgbab5dde2020-01-10 15:10:29 -070080 while status.step is not None:
Paul Fagerburg3b534f92019-11-07 15:05:22 -070081 status.save()
Paul Fagerburgbab5dde2020-01-10 15:10:29 -070082 if not perform_step(status):
83 logging.debug('perform_step returned False; exiting ...')
Paul Fagerburg3b534f92019-11-07 15:05:22 -070084 return False
85
Paul Fagerburgbab5dde2020-01-10 15:10:29 -070086 move_to_next_step(status)
Paul Fagerburg3b534f92019-11-07 15:05:22 -070087
88 return True
89
90
91def get_args():
92 """Parse the command-line arguments
93
94 There doesn't appear to be a way to specify that --continue is
95 mutually exclusive with --board, --variant, and --bug. As a result,
96 all arguments are optional, and another function will apply the logic
97 to check if there is an illegal combination of arguments.
98
99 Returns a list of:
Paul Fagerburge868e832020-01-22 17:14:04 -0700100 board Name of the reference board
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700101 variant Name of the variant being created
102 bug Text for bug number, if any ('None' otherwise)
103 continue_flag Flag if --continue was specified
104 """
105 parser = argparse.ArgumentParser(
106 description=main.__doc__,
107 formatter_class=argparse.RawTextHelpFormatter)
Paul Fagerburge868e832020-01-22 17:14:04 -0700108 parser.add_argument('--board', type=str, help='Name of the reference board')
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700109 parser.add_argument(
110 '--variant', type=str, help='Name of the new variant to create')
111 parser.add_argument(
112 '--bug', type=str, help='Bug number to reference in commits')
113 parser.add_argument(
114 '--continue', action='store_true',
115 dest='continue_flag', help='Continue the process from where it paused')
116 parser.add_argument(
117 '--verbose', action='store_true',
118 dest='verbose_flag', help='Enable verbose output of progress')
119 args = parser.parse_args()
120
121 if args.verbose_flag:
122 logging.basicConfig(level=logging.DEBUG)
123 else:
124 logging.basicConfig(level=logging.INFO)
125
126 board = args.board
127 if board is not None:
128 board = board.lower()
129
130 variant = args.variant
131 if variant is not None:
132 variant = variant.lower()
133
134 bug = args.bug or 'None'
135
136 return (board, variant, bug, args.continue_flag)
137
138
139def check_flags(board, variant, bug, continue_flag):
140 """Check the flags to ensure no invalid combinations
141
142 We allow any of the following:
143 --continue
144 --board=board_name --variant=variant_name
145 --board=board_name --variant=variant_name --bug=bug_text
146
147 The argument parser does have the functionality to represent the
148 combination of --board and --variant as a single mutually-exclusive
149 argument, so we have to use this function to do the checking.
150
Paul Fagerburg92fcb4b2020-02-19 21:21:43 -0700151 Args:
152 board: Name of the reference board
153 variant: Name of the variant being created
154 bug: Text for bug number, if any ('None' otherwise)
155 continue_flag: Flag if --continue was specified
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700156
157 Returns:
158 True if the arguments are acceptable, False otherwise
159 """
160 if continue_flag:
161 if board is not None or variant is not None:
162 logging.error('--continue cannot have other options')
163 return False
164
165 if bug != 'None':
166 logging.error('--continue cannot have other options')
167 return False
168 else:
169 if board is None:
170 logging.error('--board must be specified')
171 return False
172
173 if variant is None:
174 logging.error('--variant must be specified')
175 return False
176
177 return True
178
179
180def file_exists(filepath, filename):
181 """Determine if a path and file exists
182
Paul Fagerburg92fcb4b2020-02-19 21:21:43 -0700183 Args:
184 filepath: Path where build outputs should be found, e.g.
185 /build/hatch/firmware
186 filename: File that should exist in that path, e.g. image-sushi.bin
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700187
188 Returns:
189 True if file exists in that path, False otherwise
190 """
191 fullname = os.path.join(filepath, filename)
192 return os.path.exists(fullname) and os.path.isfile(fullname)
193
194
195def get_status(board, variant, bug, continue_flag):
196 """Create the status file or get the previous status
197
198 This program can stop at several places as we have to wait for CLs
199 to work through CQ or be upstreamed into the chromiumos tree, so just
200 like a git cherry-pick, there is a --continue option to pick up where
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700201 you left off by reading a specially-named status file.
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700202
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700203 If --continue is specified, the status file must exist.
204 If the status file exists, then --continue must be specified.
205 When --continue is specified, we read the status file and return
206 with the contents.
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700207
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700208 If the status file does not exist, we will create the state file with
209 the board, variant, and (optional) bug details.
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700210
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700211 To decouple the list of boards supported from this main program, we
Paul Fagerburge868e832020-01-22 17:14:04 -0700212 try to import a module with the same name as the reference board,
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700213 so --board=hatch means that we import hatch.py. If we can't import
Paul Fagerburge868e832020-01-22 17:14:04 -0700214 the file, then we don't support that reference board.
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700215
216 The board-specific module will set several variables, which we will
217 copy into the object that we return.
218
Paul Fagerburge868e832020-01-22 17:14:04 -0700219 * base - the name of the base board, such as Hatch, Volteer, or Zork.
220 This can be different from the reference board, e.g. the Trembyle
221 reference board in the Zork project.
Paul Fagerburg4d343452020-01-24 15:23:53 -0700222 * coreboot_dir - base directory for coreboot, usually third_party/coreboot
223 but could differ for processors that use a private repo
224 * cb_config_dir - base directory for coreboot configs, usually
225 third_party/chromiumos-overlay/sys-boot/coreboot/files/configs but
226 could differ for processors that use a private repo
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700227 * step_list - list of steps (named in step_names.py) to run in sequence
Paul Fagerburge868e832020-01-22 17:14:04 -0700228 to create the new variant of the reference board
229 * fsp - package name for FSP. This may be None, depending on the
230 processor on the reference board
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700231 * fitimage_pkg - package name for the fitimage
Paul Fagerburg5f794bf2020-02-12 13:01:36 -0700232 * fitimage_dir - directory for fitimage; prepend '/mnt/host/source/src/'
233 in chroot, prepend '~/chromiumos/src' outside the chroot
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700234 * workon_pkgs - list of packages to cros_workon
235 * emerge_cmd - the emerge command, e.g. 'emerge-hatch'
236 * emerge_pkgs - list of packages to emerge
237 * yaml_emerge_pkgs - list of packages to emerge just to build the yaml
238 * private_yaml_dir - directory for the private yaml file
Paul Fagerburga8c7e342020-02-25 13:30:49 -0700239 * commits - map of commits for the various steps. Indexed by step name,
240 and the step names used are the same ones in step_names.py
241 * repo_upload_list - list of commits to upload using `repo upload`
242 * coreboot_push_list - list of commits to upload using `git push` to
243 coreboot
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700244
245 Additionally, the following fields will be set:
246
Paul Fagerburge868e832020-01-22 17:14:04 -0700247 * board - the name of the reference board, e.g. 'hatch'
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700248 * variant - the name of the variant, e.g. 'sushi'
249 * bug - optional text for a bug ID, used in the git commit messages.
250 Could be 'None' (as text, not the python None), or something like
251 'b:12345' for buganizer, or 'chromium:12345'
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700252 * step - internal state tracking, what step of the variant creation
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700253 we are at.
254 * yaml_file - internal, just the name of the file where all this data
255 gets saved.
256
257 These data might come from the status file (because we read it), or
258 they might be the initial values after we created the file (because
259 it did not already exist).
260
Paul Fagerburg92fcb4b2020-02-19 21:21:43 -0700261 Args:
262 board: Name of the reference board
263 variant: Name of the variant being created
264 bug: Text for bug number, if any ('None' otherwise)
265 continue_flag: Flag if --continue was specified
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700266
267 Returns:
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700268 variant_status object with all the data mentioned above
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700269 """
270 status = variant_status.variant_status()
271 if continue_flag:
272 if not status.yaml_file_exists():
273 logging.error(
274 'new_variant is not in progress; nothing to --continue')
275 return None
276 else:
277 if status.yaml_file_exists():
278 logging.error(
279 'new_variant already in progress; did you forget --continue?')
280 return None
281
282 status.board = board
283 status.variant = variant
284 status.bug = bug
Paul Fagerburgdd3e9c32020-01-07 14:00:35 -0700285
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700286 # We're just starting out, so load the appropriate module and copy
287 # all the data from it.
288 try:
289 module = importlib.import_module(board)
290 except ImportError:
Paul Fagerburge868e832020-01-22 17:14:04 -0700291 print('Unsupported board "' + board + '"')
Paul Fagerburgdd3e9c32020-01-07 14:00:35 -0700292 sys.exit(1)
293
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700294 # pylint: disable=bad-whitespace
295 # Allow extra spaces around = so that we can line things up nicely
Paul Fagerburge868e832020-01-22 17:14:04 -0700296 status.base = module.base
Paul Fagerburg4d343452020-01-24 15:23:53 -0700297 status.coreboot_dir = module.coreboot_dir
298 status.cb_config_dir = module.cb_config_dir
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700299 status.emerge_cmd = module.emerge_cmd
300 status.emerge_pkgs = module.emerge_pkgs
301 status.fitimage_dir = module.fitimage_dir
302 status.fitimage_pkg = module.fitimage_pkg
Paul Fagerburg55dabf42020-01-27 15:30:09 -0700303 status.fitimage_cmd = module.fitimage_cmd
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700304 status.fsp = module.fsp
305 status.private_yaml_dir = module.private_yaml_dir
306 status.step_list = module.step_list
307 status.workon_pkgs = module.workon_pkgs
308 status.yaml_emerge_pkgs = module.yaml_emerge_pkgs
Paul Fagerburga8c7e342020-02-25 13:30:49 -0700309 status.coreboot_push_list = module.coreboot_push_list
310 status.repo_upload_list = module.repo_upload_list
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700311 # pylint: enable=bad-whitespace
Paul Fagerburgdd3e9c32020-01-07 14:00:35 -0700312
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700313 # Start at the first entry in the step list
314 status.step = status.step_list[0]
Paul Fagerburgdd3e9c32020-01-07 14:00:35 -0700315
Paul Fagerburg1d043c32020-02-03 08:57:08 -0700316 # Start a blank map for tracking CL data
317 status.commits = {}
318
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700319 status.save()
320
321 return status
322
323
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700324def perform_step(status):
325 """Call the appropriate function for the current step
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700326
Paul Fagerburg92fcb4b2020-02-19 21:21:43 -0700327 Args:
328 status: variant_status object tracking our board, variant, etc.
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700329
330 Returns:
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700331 True if the step succeeded, False if it failed
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700332 """
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700333 # Function to call based on the step
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700334 dispatch = {
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700335 step_names.CB_VARIANT: create_coreboot_variant,
336 step_names.CB_CONFIG: create_coreboot_config,
Paul Fagerburg2fd23f42020-02-07 14:04:48 -0700337 step_names.CRAS_CONFIG: copy_cras_config,
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700338 step_names.ADD_FIT: add_fitimage,
339 step_names.GEN_FIT: gen_fit_image_outside_chroot,
340 step_names.COMMIT_FIT: commit_fitimage,
341 step_names.EC_IMAGE: create_initial_ec_image,
342 step_names.EC_BUILDALL: ec_buildall,
Paul Fagerburg1d043c32020-02-03 08:57:08 -0700343 step_names.ADD_PUB_YAML: add_variant_to_public_yaml,
344 step_names.ADD_PRIV_YAML: add_variant_to_private_yaml,
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700345 step_names.BUILD_YAML: build_yaml,
346 step_names.EMERGE: emerge_all,
347 step_names.PUSH: push_coreboot,
348 step_names.UPLOAD: upload_CLs,
349 step_names.FIND: find_coreboot_upstream,
350 step_names.CQ_DEPEND: add_cq_depends,
351 step_names.CLEAN_UP: clean_up,
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700352 }
353
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700354 if status.step not in dispatch:
355 logging.error('Unknown step "%s", aborting...', status.step)
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700356 sys.exit(1)
357
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700358 return dispatch[status.step](status)
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700359
360
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700361def move_to_next_step(status):
362 """Move to the next step in the list
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700363
Paul Fagerburg92fcb4b2020-02-19 21:21:43 -0700364 Args:
365 status: variant_status object tracking our board, variant, etc.
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700366 """
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700367 if status.step not in status.step_list:
368 logging.error('Unknown step "%s", aborting...', status.step)
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700369 sys.exit(1)
370
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700371 idx = status.step_list.index(status.step)
372 if idx == len(status.step_list)-1:
373 status.step = None
Paul Fagerburgdd3e9c32020-01-07 14:00:35 -0700374 else:
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700375 status.step = status.step_list[idx+1]
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700376
377
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700378def run_process(args, cwd=None, env=None, capture_output=False):
379 """Run a process, log debug messages, return text output of process
380
381 The capture_output parameter allows us to capture the output when we
382 care about it (and not sending it to the screen), or ignoring it when
383 we don't care, and letting the user see the output so they know that
384 the build is still running, etc.
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700385
Paul Fagerburg92fcb4b2020-02-19 21:21:43 -0700386 Args:
387 args: List of the command and its params
388 cwd: If not None, cd to this directory before running
389 env: Environment to use for execution; if needed, get os.environ.copy()
390 and add variables. If None, just use the current environment
391 capture_output: True if we should capture the stdout, false if we
392 just care about success or not.
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700393
394 Returns:
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700395 If capture_output == True, we return the text output from running
396 the subprocess as a list of lines, or None if the process failed.
397 If capture_output == False, we return a True if it successed, or
398 None if the process failed.
399
400 The caller can evaluate as a bool, because bool(None) == False, and
401 bool() of a non-empty list is True, or the caller can use the returned
402 text for further processing.
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700403 """
404 logging.debug('Run %s', str(args))
Paul Fagerburga8c7e342020-02-25 13:30:49 -0700405 if cwd is not None:
406 logging.debug('cwd = %s', cwd)
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700407 try:
408 if capture_output:
Paul Fagerburga8c7e342020-02-25 13:30:49 -0700409 output = subprocess.run(args, cwd=cwd, env=env, check=True,
410 stderr=subprocess.STDOUT, stdout=subprocess.PIPE).stdout
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700411 else:
412 subprocess.run(args, cwd=cwd, env=env, check=True)
413 # Just something to decode so we don't get an empty list
414 output = b'True'
415
416 logging.debug('process returns 0')
417 # Convert from byte string to ASCII
418 decoded = output.decode('utf-8')
419 # Split into array of individual lines
420 lines = decoded.split('\n')
421 return lines
422 except subprocess.CalledProcessError as err:
423 logging.debug('process returns %s', str(err.returncode))
424 return None
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700425
426
Paul Fagerburg1d043c32020-02-03 08:57:08 -0700427def get_git_commit_data(cwd):
428 """Get the branch name and change id of the current commit
429
Paul Fagerburg92fcb4b2020-02-19 21:21:43 -0700430 Args:
431 cwd: The current working directory, where we want to get the branch
432 name and change id
Paul Fagerburg1d043c32020-02-03 08:57:08 -0700433
434 Returns:
435 Map with 'dir', 'branch_name' and 'change_id' keys. The 'dir'
436 key maps to the value of os.path.expanduser(cwd)
437 """
Paul Fagerburga8c7e342020-02-25 13:30:49 -0700438 cwd = git.FindGitTopLevel(os.path.expanduser(cwd))
Paul Fagerburg1d043c32020-02-03 08:57:08 -0700439 logging.debug('get_git_commit_data(%s)', cwd)
440
441 branch_name = git.GetCurrentBranch(cwd)
442 if branch_name is None:
443 logging.error('Cannot determine git branch name in %s; exiting', cwd)
444 sys.exit(1)
445 logging.debug('git current branch is %s', branch_name)
446
447 change_id = git.GetChangeId(cwd)
448 if change_id is None:
449 logging.error('Cannot determine Change-Id in %s; exiting', cwd)
450 sys.exit(1)
451 logging.debug('git Change-Id is %s', change_id)
452
453 return {
454 'dir': cwd,
455 'branch_name': branch_name,
456 'change_id': change_id
457 }
458
459
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700460def cros_workon(status, action):
461 """Call cros_workon for all the 9999 ebuilds we'll be touching
462
Paul Fagerburg92fcb4b2020-02-19 21:21:43 -0700463 Args:
464 status: variant_status object tracking our board, variant, etc.
465 action: 'start' or 'stop'
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700466
467 Returns:
468 True if the call to cros_workon was successful, False if failed
469 """
470
471 # Build up the command from all the packages in the list
Paul Fagerburge868e832020-01-22 17:14:04 -0700472 workon_cmd = ['cros_workon', '--board=' + status.base, action] + status.workon_pkgs
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700473 return bool(run_process(workon_cmd))
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700474
475
476def create_coreboot_variant(status):
Paul Fagerburge868e832020-01-22 17:14:04 -0700477 """Create source files for a new variant of the reference board in coreboot
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700478
479 This function calls create_coreboot_variant.sh to set up a new variant
Paul Fagerburge868e832020-01-22 17:14:04 -0700480 of the reference board.
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700481
Paul Fagerburg92fcb4b2020-02-19 21:21:43 -0700482 Args:
483 status: variant_status object tracking our board, variant, etc.
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700484
485 Returns:
486 True if everything succeeded, False if something failed
487 """
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700488 logging.info('Running step create_coreboot_variant')
Paul Fagerburg5f794bf2020-02-12 13:01:36 -0700489 cb_src_dir = os.path.join('/mnt/host/source/src/', status.coreboot_dir)
490 environ = os.environ.copy()
491 environ['CB_SRC_DIR'] = cb_src_dir
492 create_coreboot_variant_sh = os.path.join(status.my_loc,
493 'create_coreboot_variant.sh')
Paul Fagerburg1d043c32020-02-03 08:57:08 -0700494 rc = bool(run_process(
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700495 [create_coreboot_variant_sh,
Paul Fagerburge868e832020-01-22 17:14:04 -0700496 status.base,
Paul Fagerburgabb15622020-02-07 15:41:29 -0700497 status.board,
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700498 status.variant,
Paul Fagerburg5f794bf2020-02-12 13:01:36 -0700499 status.bug], env=environ))
Paul Fagerburg1d043c32020-02-03 08:57:08 -0700500 if rc:
Paul Fagerburga8c7e342020-02-25 13:30:49 -0700501 status.commits[step_names.CB_VARIANT] = get_git_commit_data(cb_src_dir)
Paul Fagerburg1d043c32020-02-03 08:57:08 -0700502 return rc
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700503
504
505def create_coreboot_config(status):
506 """Create a coreboot configuration for a new variant
507
508 This function calls create_coreboot_config.sh, which will make a copy
509 of coreboot.${BOARD} into coreboot.${VARIANT}.
510
Paul Fagerburg92fcb4b2020-02-19 21:21:43 -0700511 Args:
512 status: variant_status object tracking our board, variant, etc.
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700513
514 Returns:
515 True if the script and test build succeeded, False if something failed
516 """
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700517 logging.info('Running step create_coreboot_config')
Paul Fagerburg4d343452020-01-24 15:23:53 -0700518 environ = os.environ.copy()
519 if status.cb_config_dir is not None:
520 environ['CB_CONFIG_DIR'] = status.cb_config_dir
Paul Fagerburg5f794bf2020-02-12 13:01:36 -0700521 create_coreboot_config_sh = os.path.join(status.my_loc,
522 'create_coreboot_config.sh')
Paul Fagerburg1d043c32020-02-03 08:57:08 -0700523 rc = bool(run_process(
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700524 [create_coreboot_config_sh,
Paul Fagerburge868e832020-01-22 17:14:04 -0700525 status.base,
526 status.board,
527 status.variant,
Paul Fagerburg4d343452020-01-24 15:23:53 -0700528 status.bug], env=environ))
Paul Fagerburg1d043c32020-02-03 08:57:08 -0700529 if rc:
530 # Use status.cb_config_dir if defined, or if not, use
Paul Fagerburg5f794bf2020-02-12 13:01:36 -0700531 # '/mnt/host/source/src/third_party/chromiumos-overlay'
Paul Fagerburg1d043c32020-02-03 08:57:08 -0700532 if status.cb_config_dir is not None:
Paul Fagerburg5f794bf2020-02-12 13:01:36 -0700533 cb_config_dir = os.path.join('/mnt/host/source/src/', status.cb_config_dir)
Paul Fagerburg1d043c32020-02-03 08:57:08 -0700534 else:
Paul Fagerburg5f794bf2020-02-12 13:01:36 -0700535 cb_config_dir = '/mnt/host/source/src/third_party/chromiumos-overlay'
Paul Fagerburga8c7e342020-02-25 13:30:49 -0700536 status.commits[step_names.CB_CONFIG] = get_git_commit_data(cb_config_dir)
Paul Fagerburg1d043c32020-02-03 08:57:08 -0700537 return rc
Paul Fagerburge868e832020-01-22 17:14:04 -0700538
539
Paul Fagerburg2fd23f42020-02-07 14:04:48 -0700540def copy_cras_config(status):
541 """Copy the cras config for a new variant
542
543 This is only necessary for the Zork baseboard right now.
544 This function calls copy_cras_config.sh, which will copy the
545 cras config in
546 overlays/overlay-${BASE}/chromeos-base/chromeos-bsp-${BASE}/files/cras-config/${BASE}
547 to .../${VARIANT}
548
Paul Fagerburg92fcb4b2020-02-19 21:21:43 -0700549 Args:
550 status: variant_status object tracking our board, variant, etc.
Paul Fagerburg2fd23f42020-02-07 14:04:48 -0700551
552 Returns:
553 True if the script and test build succeeded, False if something failed
554 """
555 logging.info('Running step copy_cras_config')
Paul Fagerburg5f794bf2020-02-12 13:01:36 -0700556 copy_cras_config_sh = os.path.join(status.my_loc, 'copy_cras_config.sh')
Paul Fagerburg1d043c32020-02-03 08:57:08 -0700557 rc = bool(run_process(
Paul Fagerburg2fd23f42020-02-07 14:04:48 -0700558 [copy_cras_config_sh,
559 status.base,
560 status.board,
561 status.variant,
562 status.bug]))
Paul Fagerburg1d043c32020-02-03 08:57:08 -0700563 if rc:
Paul Fagerburga8c7e342020-02-25 13:30:49 -0700564 status.commits[step_names.CRAS_CONFIG] = get_git_commit_data(
Paul Fagerburg5f794bf2020-02-12 13:01:36 -0700565 '/mnt/host/source/src/overlays')
Paul Fagerburg1d043c32020-02-03 08:57:08 -0700566 return rc
Paul Fagerburg2fd23f42020-02-07 14:04:48 -0700567
568
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700569def add_fitimage(status):
570 """Add the source files for a fitimage for the new variant
571
572 This function calls add_fitimage.sh to create a new XSL file for the
Paul Fagerburge868e832020-01-22 17:14:04 -0700573 variant's fitimage, which can override settings from the reference board's
574 XSL. When this is done, the user will have to build the fitimage by running
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700575 gen_fit_image.sh outside of the chroot (and outside of this program's
576 control) because gen_fit_image.sh uses WINE, which is not installed in
577 the chroot. (There is a linux version of FIT, but it requires Open GL,
578 which is also not installed in the chroot.)
579
Paul Fagerburg92fcb4b2020-02-19 21:21:43 -0700580 Args:
581 status: variant_status object tracking our board, variant, etc.
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700582
583 Returns:
584 True if the script succeeded, False otherwise
585 """
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700586 logging.info('Running step add_fitimage')
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700587 add_fitimage_sh = os.path.expanduser(os.path.join(
Paul Fagerburg5f794bf2020-02-12 13:01:36 -0700588 '/mnt/host/source/src', status.fitimage_dir, 'files/add_fitimage.sh'))
Paul Fagerburg1d043c32020-02-03 08:57:08 -0700589 rc = bool(run_process(
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700590 [add_fitimage_sh,
591 status.variant,
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700592 status.bug]))
Paul Fagerburg1d043c32020-02-03 08:57:08 -0700593 if rc:
Paul Fagerburg5f794bf2020-02-12 13:01:36 -0700594 fitimage_dir = os.path.join('/mnt/host/source/src', status.fitimage_dir)
Paul Fagerburga8c7e342020-02-25 13:30:49 -0700595 status.commits[step_names.COMMIT_FIT] = get_git_commit_data(fitimage_dir)
Paul Fagerburg1d043c32020-02-03 08:57:08 -0700596 return rc
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700597
598
599def gen_fit_image_outside_chroot(status):
600 """Tell the user to run gen_fit_image.sh outside the chroot
601
602 As noted for add_Fitimage(), gen_fit_image.sh cannot run inside the
603 chroot. This function tells the user to run gen_fit_image.sh in
604 their normal environment, and then come back (--continue) when that
605 is done.
606
Paul Fagerburg92fcb4b2020-02-19 21:21:43 -0700607 Args:
608 status: variant_status object tracking our board, variant, etc.
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700609
610 Returns:
611 True
612 """
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700613 logging.info('Running step gen_fit_image_outside_chroot')
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700614 fit_image_files = check_fit_image_files(status)
615 # If the list is empty, then `not` of the list is True, so the files
616 # we need are all present and we can continue.
617 if not fit_image_files:
618 return True
619
620 logging.info('The following files need to be generated:')
621 for filename in fit_image_files:
622 logging.info('* %s', filename)
623 logging.info('The fitimage sources are ready for gen_fit_image.sh to process.')
624 logging.info('gen_fit_image.sh cannot run inside the chroot. Please open a new terminal')
625 logging.info('window, change to the directory where gen_fit_image.sh is located, and run')
Paul Fagerburg55dabf42020-01-27 15:30:09 -0700626 logging.info(status.fitimage_cmd, status.variant)
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700627 logging.info('Then re-start this program with --continue.')
628 logging.info('If your chroot is based in ~/chromiumos, then the folder you want is')
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700629 logging.info('~/chromiumos/src/%s/asset_generation', status.fitimage_dir)
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700630 return False
631
632
633def check_fit_image_files(status):
634 """Check if the fitimage has been generated
635
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700636 This function is not called directly as a step, and so it doesn't need
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700637 to produce any error messages to the user (except with --verbose).
638 gen_fit_image_outside_chroot will call this function to see if the
639 fitimage files exist, and if not, then that function will print the
640 message about how the user needs to run gen_fit_image.sh outside the
641 chroot.
642
Paul Fagerburg92fcb4b2020-02-19 21:21:43 -0700643 Args:
644 status: variant_status object tracking our board, variant, etc.
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700645
646 Returns:
647 List of files that *DO NOT* exist and need to be created, [] if
648 all files are present.
649 """
Paul Fagerburg5f794bf2020-02-12 13:01:36 -0700650 outputs_dir = os.path.join('/mnt/host/source/src', status.fitimage_dir,
651 'asset_generation/outputs')
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700652 logging.debug('outputs_dir = "%s"', outputs_dir)
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700653
654 files = []
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700655 if not file_exists(outputs_dir, 'fitimage-' + status.variant + '.bin'):
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700656 files.append('fitimage-' + status.variant + '.bin')
657
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700658 if not file_exists(outputs_dir,
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700659 'fitimage-' + status.variant + '-versions.txt'):
660 files.append('fitimage-' + status.variant + '-versions.txt')
661
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700662 if not file_exists(outputs_dir, 'fit.log'):
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700663 files.append('fit.log')
664
665 return files
666
667
668def move_fitimage_file(fitimage_dir, filename):
669 """Move fitimage files from create-place to commit-place
670
671 commit_fitimage needs to move the fitimage files from the place where
672 they were created to a different directory in the tree. This utility
673 function handles joining paths and calling a file move function.
674
Paul Fagerburg92fcb4b2020-02-19 21:21:43 -0700675 Args:
676 fitimage_dir: Directory where the fitimage files are
677 filename: Name of the file being moved
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700678
679 Returns:
680 True if the move succeeded, False if it failed
681 """
682 src_dir = os.path.join(fitimage_dir, 'asset_generation/outputs')
683 src = os.path.join(src_dir, filename)
684 dest_dir = os.path.join(fitimage_dir, 'files')
685 dest = os.path.join(dest_dir, filename)
686 # If src does not exist and dest does, the move is already done => success!
687 if not file_exists(src_dir, filename) and file_exists(dest_dir, filename):
688 logging.debug('move "%s", "%s" unnecessary because dest exists and'
689 ' src does not exist', src, dest)
690 return True
691
692 logging.debug('move "%s", "%s"', src, dest)
693 return shutil.move(src, dest)
694
695
696def commit_fitimage(status):
697 """Move the fitimage files and add them to a git commit
698
699 This function moves the fitimage binary and -versions files from
700 asset_generation/outputs to files/ and then adds those files and
701 fit.log to the existing git commit.
702
Paul Fagerburg92fcb4b2020-02-19 21:21:43 -0700703 Args:
704 status: variant_status object tracking our board, variant, etc.
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700705
706 Returns:
707 True if the copy, git add, and git commit --amend all succeeded.
708 False if something failed.
709 """
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700710 logging.info('Running step commit_fitimage')
Paul Fagerburg5f794bf2020-02-12 13:01:36 -0700711 fitimage_dir = os.path.join('/mnt/host/source/src', status.fitimage_dir)
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700712 logging.debug('fitimage_dir = "%s"', fitimage_dir)
713
714 # The copy operation will check that the source file exists, so no
715 # need to check separately.
716 if not move_fitimage_file(fitimage_dir,
717 'fitimage-' + status.variant + '.bin'):
718 logging.error('Moving fitimage binary failed')
719 return False
720
721 if not move_fitimage_file(fitimage_dir,
722 'fitimage-' + status.variant + '-versions.txt'):
723 logging.error('Moving fitimage versions.txt failed')
724 return False
725
Paul Fagerburg1d043c32020-02-03 08:57:08 -0700726 # TODO(pfagerburg) volteer also needs files/blobs/descriptor-${VARIANT}.bin
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700727 if not bool(run_process(
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700728 ['git', 'add',
729 'asset_generation/outputs/fit.log',
730 'files/fitimage-' + status.variant + '.bin',
731 'files/fitimage-' + status.variant + '-versions.txt'
732 ],
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700733 cwd=fitimage_dir)):
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700734 return False
735
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700736 return bool(run_process(['git', 'commit', '--amend', '--no-edit'],
737 cwd=fitimage_dir))
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700738
739
740def create_initial_ec_image(status):
Paul Fagerburge868e832020-01-22 17:14:04 -0700741 """Create an EC image for the variant as a clone of the reference board
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700742
743 This function calls create_initial_ec_image.sh, which will clone the
Paul Fagerburge868e832020-01-22 17:14:04 -0700744 reference board to create the variant. The shell script will build the
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700745 EC code for the variant, but the repo upload hook insists that we
746 have done a `make buildall` before it will allow an upload, so this
747 function does the buildall.
748
Paul Fagerburg92fcb4b2020-02-19 21:21:43 -0700749 Args:
750 status: variant_status object tracking our board, variant, etc.
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700751
752 Returns:
753 True if the script and test build succeeded, False if something failed
754 """
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700755 logging.info('Running step create_initial_ec_image')
Paul Fagerburg5f794bf2020-02-12 13:01:36 -0700756 create_initial_ec_image_sh = os.path.join(status.my_loc,
757 'create_initial_ec_image.sh')
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700758 if not bool(run_process(
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700759 [create_initial_ec_image_sh,
760 status.board,
761 status.variant,
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700762 status.bug])):
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700763 return False
764
Paul Fagerburg1d043c32020-02-03 08:57:08 -0700765 # No need to `if rc:` because we already tested the run_process result above
Paul Fagerburga8c7e342020-02-25 13:30:49 -0700766 status.commits[step_names.EC_IMAGE] = get_git_commit_data(
Paul Fagerburg5f794bf2020-02-12 13:01:36 -0700767 '/mnt/host/source/src/platform/ec/board')
Paul Fagerburg1d043c32020-02-03 08:57:08 -0700768
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700769 # create_initial_ec_image.sh will build the ec.bin for this variant
770 # if successful.
Paul Fagerburg5f794bf2020-02-12 13:01:36 -0700771 ec = '/mnt/host/source/src/platform/ec'
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700772 logging.debug('ec = "%s"', ec)
Paul Fagerburga8c7e342020-02-25 13:30:49 -0700773 ec_bin = os.path.join('/build', status.base, 'firmware', status.variant,
774 'ec.bin')
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700775 logging.debug('ec.bin = "%s"', ec_bin)
776
Paul Fagerburga8c7e342020-02-25 13:30:49 -0700777 if not file_exists(ec, ec_bin):
778 logging.error('EC binary %s not found', ec_bin)
779 return False
780 return True
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700781
782
783def ec_buildall(status):
784 """Do a make buildall -j for the EC, which is required for repo upload
785
786 The upload hook checks to ensure that the entire EC codebase builds
787 without error, so we have to run make buildall -j before uploading.
788
Paul Fagerburg92fcb4b2020-02-19 21:21:43 -0700789 Args:
790 status: variant_status object tracking our board, variant, etc.
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700791
792 Returns:
793 True if the script and test build succeeded, False if something failed
794 """
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700795 logging.info('Running step ec_buildall')
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700796 del status # unused parameter
Paul Fagerburg5f794bf2020-02-12 13:01:36 -0700797 ec = '/mnt/host/source/src/platform/ec'
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700798 logging.debug('ec = "%s"', ec)
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700799 return bool(run_process(['make', 'buildall', '-j'], cwd=ec))
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700800
801
Paul Fagerburg1d043c32020-02-03 08:57:08 -0700802def add_variant_to_public_yaml(status):
803 """Add the new variant to the public model.yaml file
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700804
Paul Fagerburg1d043c32020-02-03 08:57:08 -0700805 This function calls add_variant_to_yaml.sh to add the new variant to
806 the public model.yaml file.
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700807
Paul Fagerburg92fcb4b2020-02-19 21:21:43 -0700808 Args:
809 status: variant_status object tracking our board, variant, etc.
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700810
811 Returns:
Paul Fagerburg1d043c32020-02-03 08:57:08 -0700812 True if the script succeeded, False is something failed
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700813 """
Paul Fagerburg1d043c32020-02-03 08:57:08 -0700814 logging.info('Running step add_variant_to_public_yaml')
Paul Fagerburg5f794bf2020-02-12 13:01:36 -0700815 add_variant_to_yaml_sh = os.path.join(status.my_loc,
816 'add_variant_to_yaml.sh')
Paul Fagerburg1d043c32020-02-03 08:57:08 -0700817 rc = bool(run_process(
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700818 [add_variant_to_yaml_sh,
Paul Fagerburge868e832020-01-22 17:14:04 -0700819 status.base,
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700820 status.variant,
Paul Fagerburg1d043c32020-02-03 08:57:08 -0700821 status.bug]))
822 if rc:
Paul Fagerburga8c7e342020-02-25 13:30:49 -0700823 status.commits[step_names.ADD_PUB_YAML] = get_git_commit_data(
Paul Fagerburg5f794bf2020-02-12 13:01:36 -0700824 '/mnt/host/source/src/overlays')
Paul Fagerburg1d043c32020-02-03 08:57:08 -0700825 return rc
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700826
Paul Fagerburg1d043c32020-02-03 08:57:08 -0700827
828def add_variant_to_private_yaml(status):
829 """Add the new variant to the private model.yaml file
830
831 This function calls add_variant.sh to add the new variant to
832 the private model.yaml file.
833
Paul Fagerburg92fcb4b2020-02-19 21:21:43 -0700834 Args:
835 status: variant_status object tracking our board, variant, etc.
Paul Fagerburg1d043c32020-02-03 08:57:08 -0700836
837 Returns:
838 True if the script succeeded, False is something failed
839 """
840 logging.info('Running step add_variant_to_private_yaml')
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700841 add_variant_sh = os.path.expanduser(os.path.join(status.private_yaml_dir, 'add_variant.sh'))
Paul Fagerburg1d043c32020-02-03 08:57:08 -0700842 rc = bool(run_process(
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700843 [add_variant_sh,
844 status.variant,
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700845 status.bug]))
Paul Fagerburg1d043c32020-02-03 08:57:08 -0700846 if rc:
Paul Fagerburga8c7e342020-02-25 13:30:49 -0700847 status.commits[step_names.ADD_PRIV_YAML] = get_git_commit_data(status.private_yaml_dir)
Paul Fagerburg1d043c32020-02-03 08:57:08 -0700848 return rc
849
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700850
851
852def build_yaml(status):
853 """Build config files from the yaml files
854
855 This function builds the yaml files into the JSON and C code that
856 mosys and other tools use, then verifies that the new variant's name
857 shows up in all of the output files.
858
Paul Fagerburg92fcb4b2020-02-19 21:21:43 -0700859 Args:
860 status: variant_status object tracking our board, variant, etc.
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700861
862 Returns:
863 True if the scripts and build succeeded, False is something failed
864 """
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700865 logging.info('Running step build_yaml')
866 if not bool(run_process([status.emerge_cmd] + status.yaml_emerge_pkgs)):
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700867 return False
868
869 # Check generated files for occurences of the variant name.
870 # Each file should have at least one occurence, so use `grep -c` to
871 # count the occurrences of the variant name in each file.
872 # The results will be something like this:
873 # config.json:10
874 # yaml/config.c:6
875 # yaml/config.yaml:27
876 # yaml/model.yaml:6
877 # yaml/private-model.yaml:10
878 # If the variant name doesn't show up in the file, then the count
879 # will be 0, so we would see, e.g.
880 # config.json:0
Paul Fagerburge868e832020-01-22 17:14:04 -0700881 # Note that we leave out yaml/model.yaml (the public one) because for
882 # some boards, there is nothing in the public yaml file.
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700883 # We gather the output from grep, then look for any of the strings
884 # ending in :0. If none of them match, then we're good, but if even
885 # one of them ends with :0 then there was a problem with generating
886 # the files from the yaml.
Paul Fagerburge868e832020-01-22 17:14:04 -0700887 chromeos_config = '/build/' + status.base + '/usr/share/chromeos-config'
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700888 logging.debug('chromeos_config = "%s"', chromeos_config)
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700889 grep = run_process(
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700890 ['grep',
Paul Fagerburge868e832020-01-22 17:14:04 -0700891 '-ci',
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700892 status.variant,
893 'config.json',
894 'yaml/config.c',
895 'yaml/config.yaml',
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700896 'yaml/private-model.yaml'], cwd=chromeos_config, capture_output=True)
897
898 if grep is None:
899 return False
900
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700901 return not bool([s for s in grep if re.search(r':0$', s)])
902
903
904def emerge_all(status):
905 """Build the coreboot BIOS and EC code for the new variant
906
Paul Fagerburg92fcb4b2020-02-19 21:21:43 -0700907 Args:
908 status: variant_status object tracking our board, variant, etc.
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700909
910 Returns:
911 True if the build succeeded, False if something failed
912 """
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700913 logging.info('Running step emerge_all')
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700914 cros_workon(status, 'start')
915 environ = os.environ.copy()
916 environ['FW_NAME'] = status.variant
917 # Build up the command for emerge from all the packages in the list
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700918 emerge_cmd_and_params = [status.emerge_cmd] + status.emerge_pkgs
919 if not bool(run_process(emerge_cmd_and_params, env=environ)):
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700920 return False
921
922 cros_workon(status, 'stop')
Paul Fagerburge868e832020-01-22 17:14:04 -0700923 build_path = '/build/' + status.base + '/firmware'
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700924 logging.debug('build_path = "%s"', build_path)
925 if not file_exists(build_path, 'image-' + status.variant + '.bin'):
926 logging.error('emerge failed because image-%s.bin does not exist',
927 status.variant)
928 return False
929
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700930 if not file_exists(build_path, 'image-' + status.variant + '.serial.bin'):
931 logging.error('emerge failed because image-%s.serial.bin does not exist',
932 status.variant)
933 return False
934
935 return True
936
937
938def push_coreboot(status):
939 """Push the coreboot CL to coreboot.org
940
Paul Fagerburg92fcb4b2020-02-19 21:21:43 -0700941 Args:
942 status: variant_status object tracking our board, variant, etc.
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700943
944 Returns:
945 True if the build succeeded, False if something failed
946 """
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700947 logging.info('Running step push_coreboot')
Paul Fagerburg8d850932020-02-25 14:13:32 -0700948
949 # Set up a return code that may change to False if we find that a
950 # coreboot CL has not been uploaded.
951 rc = True
952
953 for commit_key in status.coreboot_push_list:
954 logging.debug(f'Processing key {commit_key}')
955 commit = status.commits[commit_key]
956 if 'gerrit' not in commit or 'cl_number' not in commit:
957 change_id = commit['change_id']
958 cl = find_change_id(change_id)
959 if cl is not None:
960 save_cl_data(status, commit_key, cl)
961 else:
962 logging.debug(f'Not found {change_id}, need to upload')
963 logging.info('The following commit needs to be pushed to coreboot.org:')
964 logging.info(' Branch "%s"', commit['branch_name'])
965 logging.info(' in directory "%s"', commit['dir'])
966 logging.info(' with change-id "%s"', commit['change_id'])
967 logging.info('Please push the branch to review.coreboot.org, '\
968 'and then re-start this program with --continue')
969 # Since this commit needs to be uploaded, do not continue after
970 # this step returns.
971 rc = False
972 else:
973 instance_name = commit['gerrit']
974 cl_number = commit['cl_number']
975 logging.debug(f'Already uploaded ({instance_name}, {cl_number})')
976
977 return rc
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700978
979
Paul Fagerburga8c7e342020-02-25 13:30:49 -0700980def query_gerrit(instance, change_id):
981 """Search a gerrit instance for a specific change_id
982
983 Args:
984 instance: gerrit instance to query. Suitable values come from
985 gerrit.GetCrosInternal() and gerrit.GetCrosExternal()
986 change_id: The change_id to search for
987
988 Returns:
989 CL number if found, None if not
990 """
991 raw = instance.Query(change=change_id, raw=True)
992 if raw:
993 # If the CL was found by change_id, there will be only one,
994 # because the change_id is used to recognize a new patchset
995 # on an existing CL.
996 return raw[0]['number']
997
998 return None
999
1000
Paul Fagerburg8d850932020-02-25 14:13:32 -07001001def query_coreboot_gerrit(change_id):
1002 """Search the coreboot gerrit for a specific change_id
1003
1004 Use the REST API to look for the change_id. See
1005 https://gerrit-review.googlesource.com/Documentation/rest-api-changes.html
1006 for details on the REST API to search for a change-id.
1007
1008 We can't use query_gerrit with a manually constructed GerritHelper
1009 because we need the user's private SSH key to access review.coreboot.org,
1010 but these are not available inside the chroot.
1011
1012 Args:
1013 change_id: The change_id to search for
1014
1015 Returns:
1016 CL number if found, None if not
1017 """
1018 r = requests.get('https://review.coreboot.org/changes/' + change_id)
1019 response = r.content.decode('utf-8')
1020 # Check if the response starts with 'Not found', in which case return None
1021 if response.startswith('Not found:'):
1022 return None
1023 # Strip off the initial )]}'\n that is used as XSS protections, see
1024 # https://gerrit-review.googlesource.com/Documentation/rest-api.html#output
1025 # and decode as JSON.
1026 data = json.loads(response[5:])
1027 if '_number' in data:
1028 return data['_number']
1029 return None
1030
1031
Paul Fagerburga8c7e342020-02-25 13:30:49 -07001032def find_change_id(change_id):
1033 """Search the public and private ChromeOS gerrit instances for a change-id
1034
1035 Args:
1036 change_id: Change-Id to search for in both gerrit instances
1037
1038 Returns:
1039 Tuple of the gerrit instance ('chromium' or 'chrome-internal') and
1040 the CL number if the Change-Id is found.
1041 None if not found.
1042 """
1043 cl_number = query_gerrit(gerrit.GetCrosExternal(), change_id)
1044 if cl_number:
1045 return 'chromium', cl_number
1046 cl_number = query_gerrit(gerrit.GetCrosInternal(), change_id)
1047 if cl_number:
1048 return 'chrome-internal', cl_number
Paul Fagerburg8d850932020-02-25 14:13:32 -07001049 cl_number = query_coreboot_gerrit(change_id)
1050 if cl_number:
1051 return 'coreboot', cl_number
Paul Fagerburga8c7e342020-02-25 13:30:49 -07001052 return None
1053
1054
1055def save_cl_data(status, commit_key, cl):
1056 """Save the gerrit instance and CL number to the yaml file
1057
1058 Args:
1059 status: variant_status object tracking our board, variant, etc.
1060 commit_key: Which key in the commits map we're processing
1061 cl: Value returned by find_change_id, should be a tuple
1062 of instance_name, cl_number
1063 """
1064 instance_name, cl_number = cl
1065 print(f'Found ({instance_name}, {cl_number}), saving to yaml')
1066 status.commits[commit_key]['gerrit'] = instance_name
1067 status.commits[commit_key]['cl_number'] = cl_number
1068 status.save()
1069
1070
1071def repo_upload(branch_name, cwd):
1072 """Upload a branch to gerrit
1073
1074 This function runs `repo upload` in the specified directory to upload
1075 a branch to gerrit. Because it's operating in a directory and with a
1076 branch name, it could upload more than one commit, which is OK because
1077 we'll look for each commit by change-id before trying to upload in that
1078 directory. For example, this happens in Zork, where the cb_config step
1079 and the cras_config step both have a commit in src/overlays. When we're
1080 processing the cb_config step and we `repo upload` in src/overlays, it
1081 will also upload the commit for cras_config. Then we come around to the
1082 cras_config step, and since we can find a CL with the change-id, we don't
1083 try to upload again.
1084
1085 Args:
1086 branch_name: the name of the branch to upload. Gets passed to
1087 repo upload with the --br flag
1088 cwd: directory where we want to upload. Gets set as the working
1089 directory for executing repo upload.
1090
1091 Returns:
1092 True if repo upload exits with a successful error code, false otherwise
1093 """
1094 return bool(run_process(
1095 ['repo',
1096 'upload',
1097 '.',
1098 '--br=' + branch_name,
1099 '--wip',
1100 '--verify',
1101 '--yes'],
1102 cwd=cwd))
1103
1104
Paul Fagerburg3b534f92019-11-07 15:05:22 -07001105def upload_CLs(status):
1106 """Upload all CLs to chromiumos
1107
Paul Fagerburg92fcb4b2020-02-19 21:21:43 -07001108 Args:
1109 status: variant_status object tracking our board, variant, etc.
Paul Fagerburg3b534f92019-11-07 15:05:22 -07001110
1111 Returns:
1112 True if the build succeeded, False if something failed
1113 """
Paul Fagerburgbab5dde2020-01-10 15:10:29 -07001114 logging.info('Running step upload_CLs')
Paul Fagerburga8c7e342020-02-25 13:30:49 -07001115
1116 for commit_key in status.repo_upload_list:
1117 logging.debug(f'Processing key {commit_key}')
1118 commit = status.commits[commit_key]
1119 if 'gerrit' not in commit or 'cl_number' not in commit:
1120 change_id = commit['change_id']
1121 cl = find_change_id(change_id)
1122 if cl is not None:
1123 save_cl_data(status, commit_key, cl)
1124 else:
1125 logging.debug(f'Not found {change_id}, need to upload')
1126 if not repo_upload(commit['branch_name'], commit['dir']):
1127 branch_name = commit['branch_name']
1128 dirname = commit['dir']
1129 logging.error(f'Repo upload {branch_name} in {dirname} failed!')
1130 return False
1131 cl = find_change_id(change_id)
1132 if cl is None:
1133 logging.error(f'repo upload {commit_key} succeeded, ' \
1134 'but change_id is not found!')
1135 return False
1136 save_cl_data(status, commit_key, cl)
1137 else:
1138 instance_name = commit['gerrit']
1139 cl_number = commit['cl_number']
1140 logging.debug(f'Already uploaded ({instance_name}, {cl_number})')
1141
Paul Fagerburg3b534f92019-11-07 15:05:22 -07001142 return True
1143
1144
1145def find_coreboot_upstream(status):
1146 """Find the coreboot CL after it has been upstreamed to chromiumos
1147
Paul Fagerburg92fcb4b2020-02-19 21:21:43 -07001148 Args:
1149 status: variant_status object tracking our board, variant, etc.
Paul Fagerburg3b534f92019-11-07 15:05:22 -07001150
1151 Returns:
1152 True if the build succeeded, False if something failed
1153 """
Paul Fagerburgbab5dde2020-01-10 15:10:29 -07001154 logging.info('Running step find_coreboot_upstream')
Paul Fagerburg3b534f92019-11-07 15:05:22 -07001155 del status # unused parameter
1156 logging.error('TODO (pfagerburg): implement find_coreboot_upstream')
1157 return True
1158
1159
1160def add_cq_depends(status):
1161 """Add Cq-Depends to all of the CLs in chromiumos
1162
1163 The CL in coreboot needs to be pushed to coreboot.org, get merged,
1164 and then get upstreamed into the chromiumos tree before the other
1165 CLs can cq-depend on it and pass CQ.
1166
Paul Fagerburg92fcb4b2020-02-19 21:21:43 -07001167 Args:
1168 status: variant_status object tracking our board, variant, etc.
Paul Fagerburg3b534f92019-11-07 15:05:22 -07001169
1170 Returns:
1171 True if the build succeeded, False if something failed
1172 """
Paul Fagerburgbab5dde2020-01-10 15:10:29 -07001173 logging.info('Running step add_cq_depends')
Paul Fagerburg3b534f92019-11-07 15:05:22 -07001174 del status # unused parameter
1175 logging.error('TODO (pfagerburg): implement add_cq_depends')
1176 return True
1177
1178
1179def clean_up(status):
1180 """Final clean-up, including delete the status file
1181
Paul Fagerburg92fcb4b2020-02-19 21:21:43 -07001182 Args:
1183 status: variant_status object tracking our board, variant, etc.
Paul Fagerburg3b534f92019-11-07 15:05:22 -07001184
1185 Returns:
1186 True
1187 """
Paul Fagerburgbab5dde2020-01-10 15:10:29 -07001188 logging.info('Running step clean_up')
Paul Fagerburg3b534f92019-11-07 15:05:22 -07001189 status.rm()
1190 return True
1191
1192
1193if __name__ == '__main__':
1194 sys.exit(not int(main()))