blob: 084d2dfadb8d885334a5b764a8aa56403ee6c9ff [file] [log] [blame]
Paul Fagerburg3b534f92019-11-07 15:05:22 -07001#!/usr/bin/env python3
2# -*- coding: utf-8 -*-
Paul Fagerburge868e832020-01-22 17:14:04 -07003"""Create a new variant of an existing reference board
Paul Fagerburg3b534f92019-11-07 15:05:22 -07004
5This program will call all of the scripts that create the various pieces
6of a new variant. For example to create a new variant of the hatch base
7board, the following scripts are called:
8
Paul Fagerburgbab5dde2020-01-10 15:10:29 -07009* third_party/coreboot/util/mainboard/google/create_coreboot_variant.sh
Paul Fagerburg3b534f92019-11-07 15:05:22 -070010* platform/dev/contrib/variant/create_coreboot_config.sh
11* private-overlays/baseboard-hatch-private/sys-boot/
12 * coreboot-private-files-hatch/files/add_fitimage.sh
13 * coreboot-private-files-hatch/asset_generation/gen_fit_image.sh
14 * Outside the chroot, because it uses WINE to run the FIT tools
15* platform/dev/contrib/variant/create_initial_ec_image.sh
16* platform/dev/contrib/variant/add_variant_to_yaml.sh
17* private-overlays/overlay-hatch-private/chromeos-base/
18 * chromeos-config-bsp-hatch-private/add_variant.sh
19
20Once the scripts are done, the following repos have changes
21
22* third_party/coreboot
23* third_party/chromiumos-overlay
24* private-overlays/baseboard-hatch-private
25* platform/ec
26* private-overlays/overlay-hatch-private
27* overlays
28
Paul Fagerburge868e832020-01-22 17:14:04 -070029The program has support for multiple reference boards, so the repos, directories,
30and scripts above can change depending on what the reference board is.
Paul Fagerburgbab5dde2020-01-10 15:10:29 -070031
32Copyright 2020 The Chromium OS Authors. All rights reserved.
Paul Fagerburg3b534f92019-11-07 15:05:22 -070033Use of this source code is governed by a BSD-style license that can be
34found in the LICENSE file.
35"""
36
37from __future__ import print_function
38import argparse
Paul Fagerburgbab5dde2020-01-10 15:10:29 -070039import importlib
Paul Fagerburg3b534f92019-11-07 15:05:22 -070040import logging
41import os
42import re
43import shutil
44import subprocess
45import sys
Paul Fagerburgbab5dde2020-01-10 15:10:29 -070046import step_names
Paul Fagerburg3b534f92019-11-07 15:05:22 -070047import variant_status
48
49
50def main():
Paul Fagerburge868e832020-01-22 17:14:04 -070051 """Create a new variant of an existing reference board
Paul Fagerburg3b534f92019-11-07 15:05:22 -070052
53 This program automates the creation of a new variant of an existing
Paul Fagerburge868e832020-01-22 17:14:04 -070054 reference board by calling various scripts that copy the reference board,
55 modify files for the new variant, stage commits, and upload to gerrit.
Paul Fagerburg3b534f92019-11-07 15:05:22 -070056
57 Note that one of the following is required:
58 * --continue
59 * --board=BOARD --variant=VARIANT [--bug=BUG]
60 """
61 board, variant, bug, continue_flag = get_args()
62
63 if not check_flags(board, variant, bug, continue_flag):
64 return False
65
66 status = get_status(board, variant, bug, continue_flag)
67 if status is None:
68 return False
69
70 status.load()
71
Paul Fagerburgbab5dde2020-01-10 15:10:29 -070072 while status.step is not None:
Paul Fagerburg3b534f92019-11-07 15:05:22 -070073 status.save()
Paul Fagerburgbab5dde2020-01-10 15:10:29 -070074 if not perform_step(status):
75 logging.debug('perform_step returned False; exiting ...')
Paul Fagerburg3b534f92019-11-07 15:05:22 -070076 return False
77
Paul Fagerburgbab5dde2020-01-10 15:10:29 -070078 move_to_next_step(status)
Paul Fagerburg3b534f92019-11-07 15:05:22 -070079
80 return True
81
82
83def get_args():
84 """Parse the command-line arguments
85
86 There doesn't appear to be a way to specify that --continue is
87 mutually exclusive with --board, --variant, and --bug. As a result,
88 all arguments are optional, and another function will apply the logic
89 to check if there is an illegal combination of arguments.
90
91 Returns a list of:
Paul Fagerburge868e832020-01-22 17:14:04 -070092 board Name of the reference board
Paul Fagerburg3b534f92019-11-07 15:05:22 -070093 variant Name of the variant being created
94 bug Text for bug number, if any ('None' otherwise)
95 continue_flag Flag if --continue was specified
96 """
97 parser = argparse.ArgumentParser(
98 description=main.__doc__,
99 formatter_class=argparse.RawTextHelpFormatter)
Paul Fagerburge868e832020-01-22 17:14:04 -0700100 parser.add_argument('--board', type=str, help='Name of the reference board')
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700101 parser.add_argument(
102 '--variant', type=str, help='Name of the new variant to create')
103 parser.add_argument(
104 '--bug', type=str, help='Bug number to reference in commits')
105 parser.add_argument(
106 '--continue', action='store_true',
107 dest='continue_flag', help='Continue the process from where it paused')
108 parser.add_argument(
109 '--verbose', action='store_true',
110 dest='verbose_flag', help='Enable verbose output of progress')
111 args = parser.parse_args()
112
113 if args.verbose_flag:
114 logging.basicConfig(level=logging.DEBUG)
115 else:
116 logging.basicConfig(level=logging.INFO)
117
118 board = args.board
119 if board is not None:
120 board = board.lower()
121
122 variant = args.variant
123 if variant is not None:
124 variant = variant.lower()
125
126 bug = args.bug or 'None'
127
128 return (board, variant, bug, args.continue_flag)
129
130
131def check_flags(board, variant, bug, continue_flag):
132 """Check the flags to ensure no invalid combinations
133
134 We allow any of the following:
135 --continue
136 --board=board_name --variant=variant_name
137 --board=board_name --variant=variant_name --bug=bug_text
138
139 The argument parser does have the functionality to represent the
140 combination of --board and --variant as a single mutually-exclusive
141 argument, so we have to use this function to do the checking.
142
143 Params:
Paul Fagerburge868e832020-01-22 17:14:04 -0700144 board Name of the reference board
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700145 variant Name of the variant being created
146 bug Text for bug number, if any ('None' otherwise)
147 continue_flag Flag if --continue was specified
148
149 Returns:
150 True if the arguments are acceptable, False otherwise
151 """
152 if continue_flag:
153 if board is not None or variant is not None:
154 logging.error('--continue cannot have other options')
155 return False
156
157 if bug != 'None':
158 logging.error('--continue cannot have other options')
159 return False
160 else:
161 if board is None:
162 logging.error('--board must be specified')
163 return False
164
165 if variant is None:
166 logging.error('--variant must be specified')
167 return False
168
169 return True
170
171
172def file_exists(filepath, filename):
173 """Determine if a path and file exists
174
175 Params:
176 filepath Path where build outputs should be found, e.g.
177 /build/hatch/firmware
178 filename File that should exist in that path, e.g.
179 image-sushi.bin
180
181 Returns:
182 True if file exists in that path, False otherwise
183 """
184 fullname = os.path.join(filepath, filename)
185 return os.path.exists(fullname) and os.path.isfile(fullname)
186
187
188def get_status(board, variant, bug, continue_flag):
189 """Create the status file or get the previous status
190
191 This program can stop at several places as we have to wait for CLs
192 to work through CQ or be upstreamed into the chromiumos tree, so just
193 like a git cherry-pick, there is a --continue option to pick up where
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700194 you left off by reading a specially-named status file.
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700195
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700196 If --continue is specified, the status file must exist.
197 If the status file exists, then --continue must be specified.
198 When --continue is specified, we read the status file and return
199 with the contents.
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700200
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700201 If the status file does not exist, we will create the state file with
202 the board, variant, and (optional) bug details.
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700203
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700204 To decouple the list of boards supported from this main program, we
Paul Fagerburge868e832020-01-22 17:14:04 -0700205 try to import a module with the same name as the reference board,
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700206 so --board=hatch means that we import hatch.py. If we can't import
Paul Fagerburge868e832020-01-22 17:14:04 -0700207 the file, then we don't support that reference board.
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700208
209 The board-specific module will set several variables, which we will
210 copy into the object that we return.
211
Paul Fagerburge868e832020-01-22 17:14:04 -0700212 * base - the name of the base board, such as Hatch, Volteer, or Zork.
213 This can be different from the reference board, e.g. the Trembyle
214 reference board in the Zork project.
Paul Fagerburg4d343452020-01-24 15:23:53 -0700215 * coreboot_dir - base directory for coreboot, usually third_party/coreboot
216 but could differ for processors that use a private repo
217 * cb_config_dir - base directory for coreboot configs, usually
218 third_party/chromiumos-overlay/sys-boot/coreboot/files/configs but
219 could differ for processors that use a private repo
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700220 * step_list - list of steps (named in step_names.py) to run in sequence
Paul Fagerburge868e832020-01-22 17:14:04 -0700221 to create the new variant of the reference board
222 * fsp - package name for FSP. This may be None, depending on the
223 processor on the reference board
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700224 * fitimage_pkg - package name for the fitimage
225 * fitimage_dir - directory for fitimage; prepend '~/trunk/src/' in chroot,
226 prepend '~/chromiumos/src' outside the chroot
227 * workon_pkgs - list of packages to cros_workon
228 * emerge_cmd - the emerge command, e.g. 'emerge-hatch'
229 * emerge_pkgs - list of packages to emerge
230 * yaml_emerge_pkgs - list of packages to emerge just to build the yaml
231 * private_yaml_dir - directory for the private yaml file
232
233 Additionally, the following fields will be set:
234
Paul Fagerburge868e832020-01-22 17:14:04 -0700235 * board - the name of the reference board, e.g. 'hatch'
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700236 * variant - the name of the variant, e.g. 'sushi'
237 * bug - optional text for a bug ID, used in the git commit messages.
238 Could be 'None' (as text, not the python None), or something like
239 'b:12345' for buganizer, or 'chromium:12345'
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700240 * step - internal state tracking, what step of the variant creation
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700241 we are at.
242 * yaml_file - internal, just the name of the file where all this data
243 gets saved.
244
245 These data might come from the status file (because we read it), or
246 they might be the initial values after we created the file (because
247 it did not already exist).
248
249 Params:
Paul Fagerburge868e832020-01-22 17:14:04 -0700250 board Name of the reference board
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700251 variant Name of the variant being created
252 bug Text for bug number, if any ('None' otherwise)
253 continue_flag Flag if --continue was specified
254
255 Returns:
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700256 variant_status object with all the data mentioned above
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700257 """
258 status = variant_status.variant_status()
259 if continue_flag:
260 if not status.yaml_file_exists():
261 logging.error(
262 'new_variant is not in progress; nothing to --continue')
263 return None
264 else:
265 if status.yaml_file_exists():
266 logging.error(
267 'new_variant already in progress; did you forget --continue?')
268 return None
269
270 status.board = board
271 status.variant = variant
272 status.bug = bug
Paul Fagerburgdd3e9c32020-01-07 14:00:35 -0700273
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700274 # We're just starting out, so load the appropriate module and copy
275 # all the data from it.
276 try:
277 module = importlib.import_module(board)
278 except ImportError:
Paul Fagerburge868e832020-01-22 17:14:04 -0700279 print('Unsupported board "' + board + '"')
Paul Fagerburgdd3e9c32020-01-07 14:00:35 -0700280 sys.exit(1)
281
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700282 # pylint: disable=bad-whitespace
283 # Allow extra spaces around = so that we can line things up nicely
Paul Fagerburge868e832020-01-22 17:14:04 -0700284 status.base = module.base
Paul Fagerburg4d343452020-01-24 15:23:53 -0700285 status.coreboot_dir = module.coreboot_dir
286 status.cb_config_dir = module.cb_config_dir
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700287 status.emerge_cmd = module.emerge_cmd
288 status.emerge_pkgs = module.emerge_pkgs
289 status.fitimage_dir = module.fitimage_dir
290 status.fitimage_pkg = module.fitimage_pkg
Paul Fagerburg55dabf42020-01-27 15:30:09 -0700291 status.fitimage_cmd = module.fitimage_cmd
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700292 status.fsp = module.fsp
293 status.private_yaml_dir = module.private_yaml_dir
294 status.step_list = module.step_list
295 status.workon_pkgs = module.workon_pkgs
296 status.yaml_emerge_pkgs = module.yaml_emerge_pkgs
297 # pylint: enable=bad-whitespace
Paul Fagerburgdd3e9c32020-01-07 14:00:35 -0700298
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700299 # Start at the first entry in the step list
300 status.step = status.step_list[0]
Paul Fagerburgdd3e9c32020-01-07 14:00:35 -0700301
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700302 status.save()
303
304 return status
305
306
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700307def perform_step(status):
308 """Call the appropriate function for the current step
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700309
310 Params:
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700311 status variant_status object tracking our board, variant, etc.
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700312
313 Returns:
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700314 True if the step succeeded, False if it failed
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700315 """
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700316 # Function to call based on the step
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700317 dispatch = {
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700318 step_names.CB_VARIANT: create_coreboot_variant,
319 step_names.CB_CONFIG: create_coreboot_config,
Paul Fagerburge868e832020-01-22 17:14:04 -0700320 step_names.COPY_CONFIG: copy_coreboot_config,
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700321 step_names.ADD_FIT: add_fitimage,
322 step_names.GEN_FIT: gen_fit_image_outside_chroot,
323 step_names.COMMIT_FIT: commit_fitimage,
324 step_names.EC_IMAGE: create_initial_ec_image,
325 step_names.EC_BUILDALL: ec_buildall,
326 step_names.ADD_YAML: add_variant_to_yaml,
327 step_names.BUILD_YAML: build_yaml,
328 step_names.EMERGE: emerge_all,
329 step_names.PUSH: push_coreboot,
330 step_names.UPLOAD: upload_CLs,
331 step_names.FIND: find_coreboot_upstream,
332 step_names.CQ_DEPEND: add_cq_depends,
333 step_names.CLEAN_UP: clean_up,
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700334 }
335
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700336 if status.step not in dispatch:
337 logging.error('Unknown step "%s", aborting...', status.step)
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700338 sys.exit(1)
339
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700340 return dispatch[status.step](status)
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700341
342
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700343def move_to_next_step(status):
344 """Move to the next step in the list
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700345
346 Params:
347 status variant_status object tracking our board, variant, etc.
348 """
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700349 if status.step not in status.step_list:
350 logging.error('Unknown step "%s", aborting...', status.step)
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700351 sys.exit(1)
352
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700353 idx = status.step_list.index(status.step)
354 if idx == len(status.step_list)-1:
355 status.step = None
Paul Fagerburgdd3e9c32020-01-07 14:00:35 -0700356 else:
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700357 status.step = status.step_list[idx+1]
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700358
359
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700360def run_process(args, cwd=None, env=None, capture_output=False):
361 """Run a process, log debug messages, return text output of process
362
363 The capture_output parameter allows us to capture the output when we
364 care about it (and not sending it to the screen), or ignoring it when
365 we don't care, and letting the user see the output so they know that
366 the build is still running, etc.
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700367
368 Params:
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700369 args List of the command and its params
370 cwd If not None, cd to this directory before running
371 env Environment to use for execution; if needed, get
372 os.environ.copy() and add variables. If None, just
373 use the current environment
374 capture_output True if we should capture the stdout, false
375 if we just care about success or not.
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700376
377 Returns:
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700378 If capture_output == True, we return the text output from running
379 the subprocess as a list of lines, or None if the process failed.
380 If capture_output == False, we return a True if it successed, or
381 None if the process failed.
382
383 The caller can evaluate as a bool, because bool(None) == False, and
384 bool() of a non-empty list is True, or the caller can use the returned
385 text for further processing.
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700386 """
387 logging.debug('Run %s', str(args))
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700388 try:
389 if capture_output:
390 output = subprocess.check_output(args, cwd=cwd, env=env,
391 stderr=subprocess.STDOUT)
392 else:
393 subprocess.run(args, cwd=cwd, env=env, check=True)
394 # Just something to decode so we don't get an empty list
395 output = b'True'
396
397 logging.debug('process returns 0')
398 # Convert from byte string to ASCII
399 decoded = output.decode('utf-8')
400 # Split into array of individual lines
401 lines = decoded.split('\n')
402 return lines
403 except subprocess.CalledProcessError as err:
404 logging.debug('process returns %s', str(err.returncode))
405 return None
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700406
407
408def cros_workon(status, action):
409 """Call cros_workon for all the 9999 ebuilds we'll be touching
410
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700411 Params:
412 status variant_status object tracking our board, variant, etc.
413 action 'start' or 'stop'
414
415 Returns:
416 True if the call to cros_workon was successful, False if failed
417 """
418
419 # Build up the command from all the packages in the list
Paul Fagerburge868e832020-01-22 17:14:04 -0700420 workon_cmd = ['cros_workon', '--board=' + status.base, action] + status.workon_pkgs
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700421 return bool(run_process(workon_cmd))
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700422
423
424def create_coreboot_variant(status):
Paul Fagerburge868e832020-01-22 17:14:04 -0700425 """Create source files for a new variant of the reference board in coreboot
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700426
427 This function calls create_coreboot_variant.sh to set up a new variant
Paul Fagerburge868e832020-01-22 17:14:04 -0700428 of the reference board.
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700429
430 Params:
431 status variant_status object tracking our board, variant, etc.
432
433 Returns:
434 True if everything succeeded, False if something failed
435 """
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700436 logging.info('Running step create_coreboot_variant')
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700437 create_coreboot_variant_sh = os.path.join(
Paul Fagerburg4d343452020-01-24 15:23:53 -0700438 os.path.expanduser('~/trunk/src/'),
439 status.coreboot_dir,
Paul Fagerburg7b516d72019-12-20 13:13:41 -0700440 'util/mainboard/google/create_coreboot_variant.sh')
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700441 return bool(run_process(
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700442 [create_coreboot_variant_sh,
Paul Fagerburge868e832020-01-22 17:14:04 -0700443 status.base,
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700444 status.variant,
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700445 status.bug]))
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700446
447
448def create_coreboot_config(status):
449 """Create a coreboot configuration for a new variant
450
451 This function calls create_coreboot_config.sh, which will make a copy
452 of coreboot.${BOARD} into coreboot.${VARIANT}.
453
454 Params:
455 status variant_status object tracking our board, variant, etc.
456
457 Returns:
458 True if the script and test build succeeded, False if something failed
459 """
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700460 logging.info('Running step create_coreboot_config')
Paul Fagerburg4d343452020-01-24 15:23:53 -0700461 environ = os.environ.copy()
462 if status.cb_config_dir is not None:
463 environ['CB_CONFIG_DIR'] = status.cb_config_dir
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700464 create_coreboot_config_sh = os.path.expanduser(
465 '~/trunk/src/platform/dev/contrib/variant/create_coreboot_config.sh')
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700466 return bool(run_process(
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700467 [create_coreboot_config_sh,
Paul Fagerburge868e832020-01-22 17:14:04 -0700468 status.base,
469 status.board,
470 status.variant,
Paul Fagerburg4d343452020-01-24 15:23:53 -0700471 status.bug], env=environ))
Paul Fagerburge868e832020-01-22 17:14:04 -0700472
473
474def copy_coreboot_config(status):
475 """Copy the coreboot configuration for a new variant
476
477 This is only necessary for the Zork baseboard right now.
478 This function calls copy_coreboot_config.sh, which will copy
479 coreboot.${VARIANT} from
480 third_party/chromiumos-overlay/sys-boot/coreboot/files/configs
481 to
482 src/overlays/overlay-${BASE}/sys-boot/coreboot-${BASE}/files/configs
483
484 Params:
485 status variant_status object tracking our board, variant, etc.
486
487 Returns:
488 True if the script and test build succeeded, False if something failed
489 """
490 logging.info('Running step copy_coreboot_config')
491 copy_coreboot_config_sh = os.path.expanduser(
492 '~/trunk/src/platform/dev/contrib/variant/copy_coreboot_config.sh')
493 return bool(run_process(
494 [copy_coreboot_config_sh,
495 status.base,
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700496 status.board,
497 status.variant,
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700498 status.bug]))
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700499
500
501def add_fitimage(status):
502 """Add the source files for a fitimage for the new variant
503
504 This function calls add_fitimage.sh to create a new XSL file for the
Paul Fagerburge868e832020-01-22 17:14:04 -0700505 variant's fitimage, which can override settings from the reference board's
506 XSL. When this is done, the user will have to build the fitimage by running
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700507 gen_fit_image.sh outside of the chroot (and outside of this program's
508 control) because gen_fit_image.sh uses WINE, which is not installed in
509 the chroot. (There is a linux version of FIT, but it requires Open GL,
510 which is also not installed in the chroot.)
511
512 Params:
513 status variant_status object tracking our board, variant, etc.
514
515 Returns:
516 True if the script succeeded, False otherwise
517 """
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700518 logging.info('Running step add_fitimage')
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700519 add_fitimage_sh = os.path.expanduser(os.path.join(
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700520 '~/trunk/src', status.fitimage_dir, 'files/add_fitimage.sh'))
521 return bool(run_process(
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700522 [add_fitimage_sh,
523 status.variant,
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700524 status.bug]))
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700525
526
527def gen_fit_image_outside_chroot(status):
528 """Tell the user to run gen_fit_image.sh outside the chroot
529
530 As noted for add_Fitimage(), gen_fit_image.sh cannot run inside the
531 chroot. This function tells the user to run gen_fit_image.sh in
532 their normal environment, and then come back (--continue) when that
533 is done.
534
535 Params:
536 status variant_status object tracking our board, variant, etc.
537
538 Returns:
539 True
540 """
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700541 logging.info('Running step gen_fit_image_outside_chroot')
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700542 fit_image_files = check_fit_image_files(status)
543 # If the list is empty, then `not` of the list is True, so the files
544 # we need are all present and we can continue.
545 if not fit_image_files:
546 return True
547
548 logging.info('The following files need to be generated:')
549 for filename in fit_image_files:
550 logging.info('* %s', filename)
551 logging.info('The fitimage sources are ready for gen_fit_image.sh to process.')
552 logging.info('gen_fit_image.sh cannot run inside the chroot. Please open a new terminal')
553 logging.info('window, change to the directory where gen_fit_image.sh is located, and run')
Paul Fagerburg55dabf42020-01-27 15:30:09 -0700554 logging.info(status.fitimage_cmd, status.variant)
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700555 logging.info('Then re-start this program with --continue.')
556 logging.info('If your chroot is based in ~/chromiumos, then the folder you want is')
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700557 logging.info('~/chromiumos/src/%s/asset_generation', status.fitimage_dir)
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700558 return False
559
560
561def check_fit_image_files(status):
562 """Check if the fitimage has been generated
563
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700564 This function is not called directly as a step, and so it doesn't need
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700565 to produce any error messages to the user (except with --verbose).
566 gen_fit_image_outside_chroot will call this function to see if the
567 fitimage files exist, and if not, then that function will print the
568 message about how the user needs to run gen_fit_image.sh outside the
569 chroot.
570
571 Params:
572 status variant_status object tracking our board, variant, etc.
573
574 Returns:
575 List of files that *DO NOT* exist and need to be created, [] if
576 all files are present.
577 """
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700578 outputs_dir = os.path.expanduser(os.path.join(
579 '~/trunk/src', status.fitimage_dir, 'asset_generation/outputs'))
580 logging.debug('outputs_dir = "%s"', outputs_dir)
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700581
582 files = []
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700583 if not file_exists(outputs_dir, 'fitimage-' + status.variant + '.bin'):
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700584 files.append('fitimage-' + status.variant + '.bin')
585
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700586 if not file_exists(outputs_dir,
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700587 'fitimage-' + status.variant + '-versions.txt'):
588 files.append('fitimage-' + status.variant + '-versions.txt')
589
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700590 if not file_exists(outputs_dir, 'fit.log'):
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700591 files.append('fit.log')
592
593 return files
594
595
596def move_fitimage_file(fitimage_dir, filename):
597 """Move fitimage files from create-place to commit-place
598
599 commit_fitimage needs to move the fitimage files from the place where
600 they were created to a different directory in the tree. This utility
601 function handles joining paths and calling a file move function.
602
603 Params:
604 fitimage_dir Directory where the fitimage files are
605 filename Name of the file being moved
606
607 Returns:
608 True if the move succeeded, False if it failed
609 """
610 src_dir = os.path.join(fitimage_dir, 'asset_generation/outputs')
611 src = os.path.join(src_dir, filename)
612 dest_dir = os.path.join(fitimage_dir, 'files')
613 dest = os.path.join(dest_dir, filename)
614 # If src does not exist and dest does, the move is already done => success!
615 if not file_exists(src_dir, filename) and file_exists(dest_dir, filename):
616 logging.debug('move "%s", "%s" unnecessary because dest exists and'
617 ' src does not exist', src, dest)
618 return True
619
620 logging.debug('move "%s", "%s"', src, dest)
621 return shutil.move(src, dest)
622
623
624def commit_fitimage(status):
625 """Move the fitimage files and add them to a git commit
626
627 This function moves the fitimage binary and -versions files from
628 asset_generation/outputs to files/ and then adds those files and
629 fit.log to the existing git commit.
630
631 Params:
632 status variant_status object tracking our board, variant, etc.
633
634 Returns:
635 True if the copy, git add, and git commit --amend all succeeded.
636 False if something failed.
637 """
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700638 logging.info('Running step commit_fitimage')
639 fitimage_dir = os.path.expanduser(os.path.join('~/trunk/src', status.fitimage_dir))
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700640 logging.debug('fitimage_dir = "%s"', fitimage_dir)
641
642 # The copy operation will check that the source file exists, so no
643 # need to check separately.
644 if not move_fitimage_file(fitimage_dir,
645 'fitimage-' + status.variant + '.bin'):
646 logging.error('Moving fitimage binary failed')
647 return False
648
649 if not move_fitimage_file(fitimage_dir,
650 'fitimage-' + status.variant + '-versions.txt'):
651 logging.error('Moving fitimage versions.txt failed')
652 return False
653
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700654 if not bool(run_process(
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700655 ['git', 'add',
656 'asset_generation/outputs/fit.log',
657 'files/fitimage-' + status.variant + '.bin',
658 'files/fitimage-' + status.variant + '-versions.txt'
659 ],
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700660 cwd=fitimage_dir)):
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700661 return False
662
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700663 return bool(run_process(['git', 'commit', '--amend', '--no-edit'],
664 cwd=fitimage_dir))
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700665
666
667def create_initial_ec_image(status):
Paul Fagerburge868e832020-01-22 17:14:04 -0700668 """Create an EC image for the variant as a clone of the reference board
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700669
670 This function calls create_initial_ec_image.sh, which will clone the
Paul Fagerburge868e832020-01-22 17:14:04 -0700671 reference board to create the variant. The shell script will build the
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700672 EC code for the variant, but the repo upload hook insists that we
673 have done a `make buildall` before it will allow an upload, so this
674 function does the buildall.
675
676 Params:
677 status variant_status object tracking our board, variant, etc.
678
679 Returns:
680 True if the script and test build succeeded, False if something failed
681 """
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700682 logging.info('Running step create_initial_ec_image')
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700683 create_initial_ec_image_sh = os.path.expanduser(
684 '~/trunk/src/platform/dev/contrib/variant/create_initial_ec_image.sh')
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700685 if not bool(run_process(
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700686 [create_initial_ec_image_sh,
687 status.board,
688 status.variant,
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700689 status.bug])):
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700690 return False
691
692 # create_initial_ec_image.sh will build the ec.bin for this variant
693 # if successful.
694 ec = os.path.expanduser('~/trunk/src/platform/ec')
695 logging.debug('ec = "%s"', ec)
696 ec_bin = 'build/' + status.variant + '/ec.bin'
697 logging.debug('ec.bin = "%s"', ec_bin)
698
699 return file_exists(ec, ec_bin)
700
701
702def ec_buildall(status):
703 """Do a make buildall -j for the EC, which is required for repo upload
704
705 The upload hook checks to ensure that the entire EC codebase builds
706 without error, so we have to run make buildall -j before uploading.
707
708 Params:
709 status variant_status object tracking our board, variant, etc.
710
711 Returns:
712 True if the script and test build succeeded, False if something failed
713 """
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700714 logging.info('Running step ec_buildall')
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700715 del status # unused parameter
716 ec = os.path.expanduser('~/trunk/src/platform/ec')
717 logging.debug('ec = "%s"', ec)
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700718 return bool(run_process(['make', 'buildall', '-j'], cwd=ec))
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700719
720
721def add_variant_to_yaml(status):
722 """Add the new variant to the public and private model.yaml files
723
724 This function calls add_variant_to_yaml.sh (the public yaml) and
725 add_variant.sh (the private yaml) to add the new variant to
726 the yaml files.
727
728 Params:
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700729 status variant_status object tracking our board, variant, etc.
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700730
731 Returns:
732 True if the scripts and build succeeded, False is something failed
733 """
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700734 logging.info('Running step add_variant_to_yaml')
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700735 add_variant_to_yaml_sh = os.path.expanduser(
736 '~/trunk/src/platform/dev/contrib/variant/add_variant_to_yaml.sh')
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700737 if not bool(run_process(
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700738 [add_variant_to_yaml_sh,
Paul Fagerburge868e832020-01-22 17:14:04 -0700739 status.base,
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700740 status.variant,
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700741 status.bug])):
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700742 return False
743
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700744 add_variant_sh = os.path.expanduser(os.path.join(status.private_yaml_dir, 'add_variant.sh'))
745 return bool(run_process(
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700746 [add_variant_sh,
747 status.variant,
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700748 status.bug]))
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700749
750
751def build_yaml(status):
752 """Build config files from the yaml files
753
754 This function builds the yaml files into the JSON and C code that
755 mosys and other tools use, then verifies that the new variant's name
756 shows up in all of the output files.
757
758 Params:
759 status variant_status object tracking our board, variant, etc.
760
761 Returns:
762 True if the scripts and build succeeded, False is something failed
763 """
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700764 logging.info('Running step build_yaml')
765 if not bool(run_process([status.emerge_cmd] + status.yaml_emerge_pkgs)):
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700766 return False
767
768 # Check generated files for occurences of the variant name.
769 # Each file should have at least one occurence, so use `grep -c` to
770 # count the occurrences of the variant name in each file.
771 # The results will be something like this:
772 # config.json:10
773 # yaml/config.c:6
774 # yaml/config.yaml:27
775 # yaml/model.yaml:6
776 # yaml/private-model.yaml:10
777 # If the variant name doesn't show up in the file, then the count
778 # will be 0, so we would see, e.g.
779 # config.json:0
Paul Fagerburge868e832020-01-22 17:14:04 -0700780 # Note that we leave out yaml/model.yaml (the public one) because for
781 # some boards, there is nothing in the public yaml file.
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700782 # We gather the output from grep, then look for any of the strings
783 # ending in :0. If none of them match, then we're good, but if even
784 # one of them ends with :0 then there was a problem with generating
785 # the files from the yaml.
Paul Fagerburge868e832020-01-22 17:14:04 -0700786 chromeos_config = '/build/' + status.base + '/usr/share/chromeos-config'
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700787 logging.debug('chromeos_config = "%s"', chromeos_config)
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700788 grep = run_process(
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700789 ['grep',
Paul Fagerburge868e832020-01-22 17:14:04 -0700790 '-ci',
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700791 status.variant,
792 'config.json',
793 'yaml/config.c',
794 'yaml/config.yaml',
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700795 'yaml/private-model.yaml'], cwd=chromeos_config, capture_output=True)
796
797 if grep is None:
798 return False
799
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700800 return not bool([s for s in grep if re.search(r':0$', s)])
801
802
803def emerge_all(status):
804 """Build the coreboot BIOS and EC code for the new variant
805
806 Params:
807 status variant_status object tracking our board, variant, etc.
808
809 Returns:
810 True if the build succeeded, False if something failed
811 """
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700812 logging.info('Running step emerge_all')
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700813 cros_workon(status, 'start')
814 environ = os.environ.copy()
815 environ['FW_NAME'] = status.variant
816 # Build up the command for emerge from all the packages in the list
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700817 emerge_cmd_and_params = [status.emerge_cmd] + status.emerge_pkgs
818 if not bool(run_process(emerge_cmd_and_params, env=environ)):
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700819 return False
820
821 cros_workon(status, 'stop')
Paul Fagerburge868e832020-01-22 17:14:04 -0700822 build_path = '/build/' + status.base + '/firmware'
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700823 logging.debug('build_path = "%s"', build_path)
824 if not file_exists(build_path, 'image-' + status.variant + '.bin'):
825 logging.error('emerge failed because image-%s.bin does not exist',
826 status.variant)
827 return False
828
829 if not file_exists(build_path, 'image-' + status.variant + '.dev.bin'):
830 logging.error('emerge failed because image-%s.dev.bin does not exist',
831 status.variant)
832 return False
833
834 if not file_exists(build_path, 'image-' + status.variant + '.net.bin'):
835 logging.error('emerge failed because image-%s.net.bin does not exist',
836 status.variant)
837 return False
838
839 if not file_exists(build_path, 'image-' + status.variant + '.serial.bin'):
840 logging.error('emerge failed because image-%s.serial.bin does not exist',
841 status.variant)
842 return False
843
844 return True
845
846
847def push_coreboot(status):
848 """Push the coreboot CL to coreboot.org
849
850 Params:
851 status variant_status object tracking our board, variant, etc.
852
853 Returns:
854 True if the build succeeded, False if something failed
855 """
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700856 logging.info('Running step push_coreboot')
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700857 del status # unused parameter
858 logging.error('TODO (pfagerburg): implement push_coreboot')
859 return True
860
861
862def upload_CLs(status):
863 """Upload all CLs to chromiumos
864
865 Params:
866 status variant_status object tracking our board, variant, etc.
867
868 Returns:
869 True if the build succeeded, False if something failed
870 """
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700871 logging.info('Running step upload_CLs')
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700872 del status # unused parameter
873 logging.error('TODO (pfagerburg): implement upload_CLs')
874 return True
875
876
877def find_coreboot_upstream(status):
878 """Find the coreboot CL after it has been upstreamed to chromiumos
879
880 Params:
881 status variant_status object tracking our board, variant, etc.
882
883 Returns:
884 True if the build succeeded, False if something failed
885 """
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700886 logging.info('Running step find_coreboot_upstream')
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700887 del status # unused parameter
888 logging.error('TODO (pfagerburg): implement find_coreboot_upstream')
889 return True
890
891
892def add_cq_depends(status):
893 """Add Cq-Depends to all of the CLs in chromiumos
894
895 The CL in coreboot needs to be pushed to coreboot.org, get merged,
896 and then get upstreamed into the chromiumos tree before the other
897 CLs can cq-depend on it and pass CQ.
898
899 Params:
900 status variant_status object tracking our board, variant, etc.
901
902 Returns:
903 True if the build succeeded, False if something failed
904 """
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700905 logging.info('Running step add_cq_depends')
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700906 del status # unused parameter
907 logging.error('TODO (pfagerburg): implement add_cq_depends')
908 return True
909
910
911def clean_up(status):
912 """Final clean-up, including delete the status file
913
914 Params:
915 status variant_status object tracking our board, variant, etc.
916
917 Returns:
918 True
919 """
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700920 logging.info('Running step clean_up')
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700921 status.rm()
922 return True
923
924
925if __name__ == '__main__':
926 sys.exit(not int(main()))