blob: 15bb4a468830c7937c2206c7d4ab209292013ada [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 Fagerburgbab5dde2020-01-10 15:10:29 -0700215 * step_list - list of steps (named in step_names.py) to run in sequence
Paul Fagerburge868e832020-01-22 17:14:04 -0700216 to create the new variant of the reference board
217 * fsp - package name for FSP. This may be None, depending on the
218 processor on the reference board
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700219 * fitimage_pkg - package name for the fitimage
220 * fitimage_dir - directory for fitimage; prepend '~/trunk/src/' in chroot,
221 prepend '~/chromiumos/src' outside the chroot
222 * workon_pkgs - list of packages to cros_workon
223 * emerge_cmd - the emerge command, e.g. 'emerge-hatch'
224 * emerge_pkgs - list of packages to emerge
225 * yaml_emerge_pkgs - list of packages to emerge just to build the yaml
226 * private_yaml_dir - directory for the private yaml file
227
228 Additionally, the following fields will be set:
229
Paul Fagerburge868e832020-01-22 17:14:04 -0700230 * board - the name of the reference board, e.g. 'hatch'
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700231 * variant - the name of the variant, e.g. 'sushi'
232 * bug - optional text for a bug ID, used in the git commit messages.
233 Could be 'None' (as text, not the python None), or something like
234 'b:12345' for buganizer, or 'chromium:12345'
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700235 * step - internal state tracking, what step of the variant creation
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700236 we are at.
237 * yaml_file - internal, just the name of the file where all this data
238 gets saved.
239
240 These data might come from the status file (because we read it), or
241 they might be the initial values after we created the file (because
242 it did not already exist).
243
244 Params:
Paul Fagerburge868e832020-01-22 17:14:04 -0700245 board Name of the reference board
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700246 variant Name of the variant being created
247 bug Text for bug number, if any ('None' otherwise)
248 continue_flag Flag if --continue was specified
249
250 Returns:
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700251 variant_status object with all the data mentioned above
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700252 """
253 status = variant_status.variant_status()
254 if continue_flag:
255 if not status.yaml_file_exists():
256 logging.error(
257 'new_variant is not in progress; nothing to --continue')
258 return None
259 else:
260 if status.yaml_file_exists():
261 logging.error(
262 'new_variant already in progress; did you forget --continue?')
263 return None
264
265 status.board = board
266 status.variant = variant
267 status.bug = bug
Paul Fagerburgdd3e9c32020-01-07 14:00:35 -0700268
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700269 # We're just starting out, so load the appropriate module and copy
270 # all the data from it.
271 try:
272 module = importlib.import_module(board)
273 except ImportError:
Paul Fagerburge868e832020-01-22 17:14:04 -0700274 print('Unsupported board "' + board + '"')
Paul Fagerburgdd3e9c32020-01-07 14:00:35 -0700275 sys.exit(1)
276
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700277 # pylint: disable=bad-whitespace
278 # Allow extra spaces around = so that we can line things up nicely
Paul Fagerburge868e832020-01-22 17:14:04 -0700279 status.base = module.base
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700280 status.emerge_cmd = module.emerge_cmd
281 status.emerge_pkgs = module.emerge_pkgs
282 status.fitimage_dir = module.fitimage_dir
283 status.fitimage_pkg = module.fitimage_pkg
Paul Fagerburg55dabf42020-01-27 15:30:09 -0700284 status.fitimage_cmd = module.fitimage_cmd
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700285 status.fsp = module.fsp
286 status.private_yaml_dir = module.private_yaml_dir
287 status.step_list = module.step_list
288 status.workon_pkgs = module.workon_pkgs
289 status.yaml_emerge_pkgs = module.yaml_emerge_pkgs
290 # pylint: enable=bad-whitespace
Paul Fagerburgdd3e9c32020-01-07 14:00:35 -0700291
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700292 # Start at the first entry in the step list
293 status.step = status.step_list[0]
Paul Fagerburgdd3e9c32020-01-07 14:00:35 -0700294
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700295 status.save()
296
297 return status
298
299
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700300def perform_step(status):
301 """Call the appropriate function for the current step
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700302
303 Params:
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700304 status variant_status object tracking our board, variant, etc.
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700305
306 Returns:
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700307 True if the step succeeded, False if it failed
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700308 """
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700309 # Function to call based on the step
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700310 dispatch = {
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700311 step_names.CB_VARIANT: create_coreboot_variant,
312 step_names.CB_CONFIG: create_coreboot_config,
Paul Fagerburge868e832020-01-22 17:14:04 -0700313 step_names.COPY_CONFIG: copy_coreboot_config,
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700314 step_names.ADD_FIT: add_fitimage,
315 step_names.GEN_FIT: gen_fit_image_outside_chroot,
316 step_names.COMMIT_FIT: commit_fitimage,
317 step_names.EC_IMAGE: create_initial_ec_image,
318 step_names.EC_BUILDALL: ec_buildall,
319 step_names.ADD_YAML: add_variant_to_yaml,
320 step_names.BUILD_YAML: build_yaml,
321 step_names.EMERGE: emerge_all,
322 step_names.PUSH: push_coreboot,
323 step_names.UPLOAD: upload_CLs,
324 step_names.FIND: find_coreboot_upstream,
325 step_names.CQ_DEPEND: add_cq_depends,
326 step_names.CLEAN_UP: clean_up,
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700327 }
328
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700329 if status.step not in dispatch:
330 logging.error('Unknown step "%s", aborting...', status.step)
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700331 sys.exit(1)
332
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700333 return dispatch[status.step](status)
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700334
335
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700336def move_to_next_step(status):
337 """Move to the next step in the list
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700338
339 Params:
340 status variant_status object tracking our board, variant, etc.
341 """
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700342 if status.step not in status.step_list:
343 logging.error('Unknown step "%s", aborting...', status.step)
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700344 sys.exit(1)
345
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700346 idx = status.step_list.index(status.step)
347 if idx == len(status.step_list)-1:
348 status.step = None
Paul Fagerburgdd3e9c32020-01-07 14:00:35 -0700349 else:
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700350 status.step = status.step_list[idx+1]
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700351
352
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700353def run_process(args, cwd=None, env=None, capture_output=False):
354 """Run a process, log debug messages, return text output of process
355
356 The capture_output parameter allows us to capture the output when we
357 care about it (and not sending it to the screen), or ignoring it when
358 we don't care, and letting the user see the output so they know that
359 the build is still running, etc.
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700360
361 Params:
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700362 args List of the command and its params
363 cwd If not None, cd to this directory before running
364 env Environment to use for execution; if needed, get
365 os.environ.copy() and add variables. If None, just
366 use the current environment
367 capture_output True if we should capture the stdout, false
368 if we just care about success or not.
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700369
370 Returns:
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700371 If capture_output == True, we return the text output from running
372 the subprocess as a list of lines, or None if the process failed.
373 If capture_output == False, we return a True if it successed, or
374 None if the process failed.
375
376 The caller can evaluate as a bool, because bool(None) == False, and
377 bool() of a non-empty list is True, or the caller can use the returned
378 text for further processing.
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700379 """
380 logging.debug('Run %s', str(args))
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700381 try:
382 if capture_output:
383 output = subprocess.check_output(args, cwd=cwd, env=env,
384 stderr=subprocess.STDOUT)
385 else:
386 subprocess.run(args, cwd=cwd, env=env, check=True)
387 # Just something to decode so we don't get an empty list
388 output = b'True'
389
390 logging.debug('process returns 0')
391 # Convert from byte string to ASCII
392 decoded = output.decode('utf-8')
393 # Split into array of individual lines
394 lines = decoded.split('\n')
395 return lines
396 except subprocess.CalledProcessError as err:
397 logging.debug('process returns %s', str(err.returncode))
398 return None
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700399
400
401def cros_workon(status, action):
402 """Call cros_workon for all the 9999 ebuilds we'll be touching
403
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700404 Params:
405 status variant_status object tracking our board, variant, etc.
406 action 'start' or 'stop'
407
408 Returns:
409 True if the call to cros_workon was successful, False if failed
410 """
411
412 # Build up the command from all the packages in the list
Paul Fagerburge868e832020-01-22 17:14:04 -0700413 workon_cmd = ['cros_workon', '--board=' + status.base, action] + status.workon_pkgs
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700414 return bool(run_process(workon_cmd))
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700415
416
417def create_coreboot_variant(status):
Paul Fagerburge868e832020-01-22 17:14:04 -0700418 """Create source files for a new variant of the reference board in coreboot
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700419
420 This function calls create_coreboot_variant.sh to set up a new variant
Paul Fagerburge868e832020-01-22 17:14:04 -0700421 of the reference board.
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700422
423 Params:
424 status variant_status object tracking our board, variant, etc.
425
426 Returns:
427 True if everything succeeded, False if something failed
428 """
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700429 logging.info('Running step create_coreboot_variant')
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700430 create_coreboot_variant_sh = os.path.join(
431 os.path.expanduser('~/trunk/src/third_party/coreboot'),
Paul Fagerburg7b516d72019-12-20 13:13:41 -0700432 'util/mainboard/google/create_coreboot_variant.sh')
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700433 return bool(run_process(
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700434 [create_coreboot_variant_sh,
Paul Fagerburge868e832020-01-22 17:14:04 -0700435 status.base,
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700436 status.variant,
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700437 status.bug]))
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700438
439
440def create_coreboot_config(status):
441 """Create a coreboot configuration for a new variant
442
443 This function calls create_coreboot_config.sh, which will make a copy
444 of coreboot.${BOARD} into coreboot.${VARIANT}.
445
446 Params:
447 status variant_status object tracking our board, variant, etc.
448
449 Returns:
450 True if the script and test build succeeded, False if something failed
451 """
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700452 logging.info('Running step create_coreboot_config')
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700453 create_coreboot_config_sh = os.path.expanduser(
454 '~/trunk/src/platform/dev/contrib/variant/create_coreboot_config.sh')
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700455 return bool(run_process(
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700456 [create_coreboot_config_sh,
Paul Fagerburge868e832020-01-22 17:14:04 -0700457 status.base,
458 status.board,
459 status.variant,
460 status.bug]))
461
462
463def copy_coreboot_config(status):
464 """Copy the coreboot configuration for a new variant
465
466 This is only necessary for the Zork baseboard right now.
467 This function calls copy_coreboot_config.sh, which will copy
468 coreboot.${VARIANT} from
469 third_party/chromiumos-overlay/sys-boot/coreboot/files/configs
470 to
471 src/overlays/overlay-${BASE}/sys-boot/coreboot-${BASE}/files/configs
472
473 Params:
474 status variant_status object tracking our board, variant, etc.
475
476 Returns:
477 True if the script and test build succeeded, False if something failed
478 """
479 logging.info('Running step copy_coreboot_config')
480 copy_coreboot_config_sh = os.path.expanduser(
481 '~/trunk/src/platform/dev/contrib/variant/copy_coreboot_config.sh')
482 return bool(run_process(
483 [copy_coreboot_config_sh,
484 status.base,
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700485 status.board,
486 status.variant,
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700487 status.bug]))
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700488
489
490def add_fitimage(status):
491 """Add the source files for a fitimage for the new variant
492
493 This function calls add_fitimage.sh to create a new XSL file for the
Paul Fagerburge868e832020-01-22 17:14:04 -0700494 variant's fitimage, which can override settings from the reference board's
495 XSL. When this is done, the user will have to build the fitimage by running
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700496 gen_fit_image.sh outside of the chroot (and outside of this program's
497 control) because gen_fit_image.sh uses WINE, which is not installed in
498 the chroot. (There is a linux version of FIT, but it requires Open GL,
499 which is also not installed in the chroot.)
500
501 Params:
502 status variant_status object tracking our board, variant, etc.
503
504 Returns:
505 True if the script succeeded, False otherwise
506 """
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700507 logging.info('Running step add_fitimage')
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700508 add_fitimage_sh = os.path.expanduser(os.path.join(
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700509 '~/trunk/src', status.fitimage_dir, 'files/add_fitimage.sh'))
510 return bool(run_process(
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700511 [add_fitimage_sh,
512 status.variant,
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700513 status.bug]))
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700514
515
516def gen_fit_image_outside_chroot(status):
517 """Tell the user to run gen_fit_image.sh outside the chroot
518
519 As noted for add_Fitimage(), gen_fit_image.sh cannot run inside the
520 chroot. This function tells the user to run gen_fit_image.sh in
521 their normal environment, and then come back (--continue) when that
522 is done.
523
524 Params:
525 status variant_status object tracking our board, variant, etc.
526
527 Returns:
528 True
529 """
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700530 logging.info('Running step gen_fit_image_outside_chroot')
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700531 fit_image_files = check_fit_image_files(status)
532 # If the list is empty, then `not` of the list is True, so the files
533 # we need are all present and we can continue.
534 if not fit_image_files:
535 return True
536
537 logging.info('The following files need to be generated:')
538 for filename in fit_image_files:
539 logging.info('* %s', filename)
540 logging.info('The fitimage sources are ready for gen_fit_image.sh to process.')
541 logging.info('gen_fit_image.sh cannot run inside the chroot. Please open a new terminal')
542 logging.info('window, change to the directory where gen_fit_image.sh is located, and run')
Paul Fagerburg55dabf42020-01-27 15:30:09 -0700543 logging.info(status.fitimage_cmd, status.variant)
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700544 logging.info('Then re-start this program with --continue.')
545 logging.info('If your chroot is based in ~/chromiumos, then the folder you want is')
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700546 logging.info('~/chromiumos/src/%s/asset_generation', status.fitimage_dir)
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700547 return False
548
549
550def check_fit_image_files(status):
551 """Check if the fitimage has been generated
552
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700553 This function is not called directly as a step, and so it doesn't need
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700554 to produce any error messages to the user (except with --verbose).
555 gen_fit_image_outside_chroot will call this function to see if the
556 fitimage files exist, and if not, then that function will print the
557 message about how the user needs to run gen_fit_image.sh outside the
558 chroot.
559
560 Params:
561 status variant_status object tracking our board, variant, etc.
562
563 Returns:
564 List of files that *DO NOT* exist and need to be created, [] if
565 all files are present.
566 """
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700567 outputs_dir = os.path.expanduser(os.path.join(
568 '~/trunk/src', status.fitimage_dir, 'asset_generation/outputs'))
569 logging.debug('outputs_dir = "%s"', outputs_dir)
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700570
571 files = []
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700572 if not file_exists(outputs_dir, 'fitimage-' + status.variant + '.bin'):
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700573 files.append('fitimage-' + status.variant + '.bin')
574
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700575 if not file_exists(outputs_dir,
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700576 'fitimage-' + status.variant + '-versions.txt'):
577 files.append('fitimage-' + status.variant + '-versions.txt')
578
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700579 if not file_exists(outputs_dir, 'fit.log'):
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700580 files.append('fit.log')
581
582 return files
583
584
585def move_fitimage_file(fitimage_dir, filename):
586 """Move fitimage files from create-place to commit-place
587
588 commit_fitimage needs to move the fitimage files from the place where
589 they were created to a different directory in the tree. This utility
590 function handles joining paths and calling a file move function.
591
592 Params:
593 fitimage_dir Directory where the fitimage files are
594 filename Name of the file being moved
595
596 Returns:
597 True if the move succeeded, False if it failed
598 """
599 src_dir = os.path.join(fitimage_dir, 'asset_generation/outputs')
600 src = os.path.join(src_dir, filename)
601 dest_dir = os.path.join(fitimage_dir, 'files')
602 dest = os.path.join(dest_dir, filename)
603 # If src does not exist and dest does, the move is already done => success!
604 if not file_exists(src_dir, filename) and file_exists(dest_dir, filename):
605 logging.debug('move "%s", "%s" unnecessary because dest exists and'
606 ' src does not exist', src, dest)
607 return True
608
609 logging.debug('move "%s", "%s"', src, dest)
610 return shutil.move(src, dest)
611
612
613def commit_fitimage(status):
614 """Move the fitimage files and add them to a git commit
615
616 This function moves the fitimage binary and -versions files from
617 asset_generation/outputs to files/ and then adds those files and
618 fit.log to the existing git commit.
619
620 Params:
621 status variant_status object tracking our board, variant, etc.
622
623 Returns:
624 True if the copy, git add, and git commit --amend all succeeded.
625 False if something failed.
626 """
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700627 logging.info('Running step commit_fitimage')
628 fitimage_dir = os.path.expanduser(os.path.join('~/trunk/src', status.fitimage_dir))
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700629 logging.debug('fitimage_dir = "%s"', fitimage_dir)
630
631 # The copy operation will check that the source file exists, so no
632 # need to check separately.
633 if not move_fitimage_file(fitimage_dir,
634 'fitimage-' + status.variant + '.bin'):
635 logging.error('Moving fitimage binary failed')
636 return False
637
638 if not move_fitimage_file(fitimage_dir,
639 'fitimage-' + status.variant + '-versions.txt'):
640 logging.error('Moving fitimage versions.txt failed')
641 return False
642
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700643 if not bool(run_process(
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700644 ['git', 'add',
645 'asset_generation/outputs/fit.log',
646 'files/fitimage-' + status.variant + '.bin',
647 'files/fitimage-' + status.variant + '-versions.txt'
648 ],
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700649 cwd=fitimage_dir)):
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700650 return False
651
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700652 return bool(run_process(['git', 'commit', '--amend', '--no-edit'],
653 cwd=fitimage_dir))
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700654
655
656def create_initial_ec_image(status):
Paul Fagerburge868e832020-01-22 17:14:04 -0700657 """Create an EC image for the variant as a clone of the reference board
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700658
659 This function calls create_initial_ec_image.sh, which will clone the
Paul Fagerburge868e832020-01-22 17:14:04 -0700660 reference board to create the variant. The shell script will build the
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700661 EC code for the variant, but the repo upload hook insists that we
662 have done a `make buildall` before it will allow an upload, so this
663 function does the buildall.
664
665 Params:
666 status variant_status object tracking our board, variant, etc.
667
668 Returns:
669 True if the script and test build succeeded, False if something failed
670 """
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700671 logging.info('Running step create_initial_ec_image')
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700672 create_initial_ec_image_sh = os.path.expanduser(
673 '~/trunk/src/platform/dev/contrib/variant/create_initial_ec_image.sh')
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700674 if not bool(run_process(
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700675 [create_initial_ec_image_sh,
676 status.board,
677 status.variant,
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700678 status.bug])):
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700679 return False
680
681 # create_initial_ec_image.sh will build the ec.bin for this variant
682 # if successful.
683 ec = os.path.expanduser('~/trunk/src/platform/ec')
684 logging.debug('ec = "%s"', ec)
685 ec_bin = 'build/' + status.variant + '/ec.bin'
686 logging.debug('ec.bin = "%s"', ec_bin)
687
688 return file_exists(ec, ec_bin)
689
690
691def ec_buildall(status):
692 """Do a make buildall -j for the EC, which is required for repo upload
693
694 The upload hook checks to ensure that the entire EC codebase builds
695 without error, so we have to run make buildall -j before uploading.
696
697 Params:
698 status variant_status object tracking our board, variant, etc.
699
700 Returns:
701 True if the script and test build succeeded, False if something failed
702 """
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700703 logging.info('Running step ec_buildall')
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700704 del status # unused parameter
705 ec = os.path.expanduser('~/trunk/src/platform/ec')
706 logging.debug('ec = "%s"', ec)
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700707 return bool(run_process(['make', 'buildall', '-j'], cwd=ec))
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700708
709
710def add_variant_to_yaml(status):
711 """Add the new variant to the public and private model.yaml files
712
713 This function calls add_variant_to_yaml.sh (the public yaml) and
714 add_variant.sh (the private yaml) to add the new variant to
715 the yaml files.
716
717 Params:
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700718 status variant_status object tracking our board, variant, etc.
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700719
720 Returns:
721 True if the scripts and build succeeded, False is something failed
722 """
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700723 logging.info('Running step add_variant_to_yaml')
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700724 add_variant_to_yaml_sh = os.path.expanduser(
725 '~/trunk/src/platform/dev/contrib/variant/add_variant_to_yaml.sh')
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700726 if not bool(run_process(
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700727 [add_variant_to_yaml_sh,
Paul Fagerburge868e832020-01-22 17:14:04 -0700728 status.base,
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700729 status.variant,
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700730 status.bug])):
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700731 return False
732
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700733 add_variant_sh = os.path.expanduser(os.path.join(status.private_yaml_dir, 'add_variant.sh'))
734 return bool(run_process(
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700735 [add_variant_sh,
736 status.variant,
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700737 status.bug]))
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700738
739
740def build_yaml(status):
741 """Build config files from the yaml files
742
743 This function builds the yaml files into the JSON and C code that
744 mosys and other tools use, then verifies that the new variant's name
745 shows up in all of the output files.
746
747 Params:
748 status variant_status object tracking our board, variant, etc.
749
750 Returns:
751 True if the scripts and build succeeded, False is something failed
752 """
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700753 logging.info('Running step build_yaml')
754 if not bool(run_process([status.emerge_cmd] + status.yaml_emerge_pkgs)):
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700755 return False
756
757 # Check generated files for occurences of the variant name.
758 # Each file should have at least one occurence, so use `grep -c` to
759 # count the occurrences of the variant name in each file.
760 # The results will be something like this:
761 # config.json:10
762 # yaml/config.c:6
763 # yaml/config.yaml:27
764 # yaml/model.yaml:6
765 # yaml/private-model.yaml:10
766 # If the variant name doesn't show up in the file, then the count
767 # will be 0, so we would see, e.g.
768 # config.json:0
Paul Fagerburge868e832020-01-22 17:14:04 -0700769 # Note that we leave out yaml/model.yaml (the public one) because for
770 # some boards, there is nothing in the public yaml file.
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700771 # We gather the output from grep, then look for any of the strings
772 # ending in :0. If none of them match, then we're good, but if even
773 # one of them ends with :0 then there was a problem with generating
774 # the files from the yaml.
Paul Fagerburge868e832020-01-22 17:14:04 -0700775 chromeos_config = '/build/' + status.base + '/usr/share/chromeos-config'
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700776 logging.debug('chromeos_config = "%s"', chromeos_config)
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700777 grep = run_process(
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700778 ['grep',
Paul Fagerburge868e832020-01-22 17:14:04 -0700779 '-ci',
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700780 status.variant,
781 'config.json',
782 'yaml/config.c',
783 'yaml/config.yaml',
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700784 'yaml/private-model.yaml'], cwd=chromeos_config, capture_output=True)
785
786 if grep is None:
787 return False
788
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700789 return not bool([s for s in grep if re.search(r':0$', s)])
790
791
792def emerge_all(status):
793 """Build the coreboot BIOS and EC code for the new variant
794
795 Params:
796 status variant_status object tracking our board, variant, etc.
797
798 Returns:
799 True if the build succeeded, False if something failed
800 """
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700801 logging.info('Running step emerge_all')
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700802 cros_workon(status, 'start')
803 environ = os.environ.copy()
804 environ['FW_NAME'] = status.variant
805 # Build up the command for emerge from all the packages in the list
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700806 emerge_cmd_and_params = [status.emerge_cmd] + status.emerge_pkgs
807 if not bool(run_process(emerge_cmd_and_params, env=environ)):
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700808 return False
809
810 cros_workon(status, 'stop')
Paul Fagerburge868e832020-01-22 17:14:04 -0700811 build_path = '/build/' + status.base + '/firmware'
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700812 logging.debug('build_path = "%s"', build_path)
813 if not file_exists(build_path, 'image-' + status.variant + '.bin'):
814 logging.error('emerge failed because image-%s.bin does not exist',
815 status.variant)
816 return False
817
818 if not file_exists(build_path, 'image-' + status.variant + '.dev.bin'):
819 logging.error('emerge failed because image-%s.dev.bin does not exist',
820 status.variant)
821 return False
822
823 if not file_exists(build_path, 'image-' + status.variant + '.net.bin'):
824 logging.error('emerge failed because image-%s.net.bin does not exist',
825 status.variant)
826 return False
827
828 if not file_exists(build_path, 'image-' + status.variant + '.serial.bin'):
829 logging.error('emerge failed because image-%s.serial.bin does not exist',
830 status.variant)
831 return False
832
833 return True
834
835
836def push_coreboot(status):
837 """Push the coreboot CL to coreboot.org
838
839 Params:
840 status variant_status object tracking our board, variant, etc.
841
842 Returns:
843 True if the build succeeded, False if something failed
844 """
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700845 logging.info('Running step push_coreboot')
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700846 del status # unused parameter
847 logging.error('TODO (pfagerburg): implement push_coreboot')
848 return True
849
850
851def upload_CLs(status):
852 """Upload all CLs to chromiumos
853
854 Params:
855 status variant_status object tracking our board, variant, etc.
856
857 Returns:
858 True if the build succeeded, False if something failed
859 """
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700860 logging.info('Running step upload_CLs')
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700861 del status # unused parameter
862 logging.error('TODO (pfagerburg): implement upload_CLs')
863 return True
864
865
866def find_coreboot_upstream(status):
867 """Find the coreboot CL after it has been upstreamed to chromiumos
868
869 Params:
870 status variant_status object tracking our board, variant, etc.
871
872 Returns:
873 True if the build succeeded, False if something failed
874 """
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700875 logging.info('Running step find_coreboot_upstream')
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700876 del status # unused parameter
877 logging.error('TODO (pfagerburg): implement find_coreboot_upstream')
878 return True
879
880
881def add_cq_depends(status):
882 """Add Cq-Depends to all of the CLs in chromiumos
883
884 The CL in coreboot needs to be pushed to coreboot.org, get merged,
885 and then get upstreamed into the chromiumos tree before the other
886 CLs can cq-depend on it and pass CQ.
887
888 Params:
889 status variant_status object tracking our board, variant, etc.
890
891 Returns:
892 True if the build succeeded, False if something failed
893 """
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700894 logging.info('Running step add_cq_depends')
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700895 del status # unused parameter
896 logging.error('TODO (pfagerburg): implement add_cq_depends')
897 return True
898
899
900def clean_up(status):
901 """Final clean-up, including delete the status file
902
903 Params:
904 status variant_status object tracking our board, variant, etc.
905
906 Returns:
907 True
908 """
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700909 logging.info('Running step clean_up')
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700910 status.rm()
911 return True
912
913
914if __name__ == '__main__':
915 sys.exit(not int(main()))