blob: 8ad6534f6fbdabfed5b808e0cd396277f4b44460 [file] [log] [blame]
Paul Fagerburg3b534f92019-11-07 15:05:22 -07001#!/usr/bin/env python3
2# -*- coding: utf-8 -*-
3"""Create a new variant of an existing base board
4
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
9* third_party/coreboot/util/mainboard/google/hatch/create_coreboot_variant.sh
10* 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
29Copyright 2019 The Chromium OS Authors. All rights reserved.
30Use of this source code is governed by a BSD-style license that can be
31found in the LICENSE file.
32"""
33
34from __future__ import print_function
35import argparse
36import logging
37import os
38import re
39import shutil
40import subprocess
41import sys
42import variant_status
43
44
45def main():
46 """Create a new variant of an existing base board
47
48 This program automates the creation of a new variant of an existing
49 base board by calling various scripts that clone the base board, modify
50 files for the new variant, stage commits, and upload to gerrit.
51
52 Note that one of the following is required:
53 * --continue
54 * --board=BOARD --variant=VARIANT [--bug=BUG]
55 """
56 board, variant, bug, continue_flag = get_args()
57
58 if not check_flags(board, variant, bug, continue_flag):
59 return False
60
61 status = get_status(board, variant, bug, continue_flag)
62 if status is None:
63 return False
64
65 status.load()
66
67 while status.stage is not None:
68 status.save()
69 if not perform_stage(status):
70 logging.debug('perform_stage returned False; exiting ...')
71 return False
72
73 move_to_next_stage(status)
74
75 return True
76
77
78def get_args():
79 """Parse the command-line arguments
80
81 There doesn't appear to be a way to specify that --continue is
82 mutually exclusive with --board, --variant, and --bug. As a result,
83 all arguments are optional, and another function will apply the logic
84 to check if there is an illegal combination of arguments.
85
86 Returns a list of:
87 board Name of the base board
88 variant Name of the variant being created
89 bug Text for bug number, if any ('None' otherwise)
90 continue_flag Flag if --continue was specified
91 """
92 parser = argparse.ArgumentParser(
93 description=main.__doc__,
94 formatter_class=argparse.RawTextHelpFormatter)
95 parser.add_argument('--board', type=str, help='Name of the base board')
96 parser.add_argument(
97 '--variant', type=str, help='Name of the new variant to create')
98 parser.add_argument(
99 '--bug', type=str, help='Bug number to reference in commits')
100 parser.add_argument(
101 '--continue', action='store_true',
102 dest='continue_flag', help='Continue the process from where it paused')
103 parser.add_argument(
104 '--verbose', action='store_true',
105 dest='verbose_flag', help='Enable verbose output of progress')
106 args = parser.parse_args()
107
108 if args.verbose_flag:
109 logging.basicConfig(level=logging.DEBUG)
110 else:
111 logging.basicConfig(level=logging.INFO)
112
113 board = args.board
114 if board is not None:
115 board = board.lower()
116
117 variant = args.variant
118 if variant is not None:
119 variant = variant.lower()
120
121 bug = args.bug or 'None'
122
123 return (board, variant, bug, args.continue_flag)
124
125
126def check_flags(board, variant, bug, continue_flag):
127 """Check the flags to ensure no invalid combinations
128
129 We allow any of the following:
130 --continue
131 --board=board_name --variant=variant_name
132 --board=board_name --variant=variant_name --bug=bug_text
133
134 The argument parser does have the functionality to represent the
135 combination of --board and --variant as a single mutually-exclusive
136 argument, so we have to use this function to do the checking.
137
138 Params:
139 board Name of the base board
140 variant Name of the variant being created
141 bug Text for bug number, if any ('None' otherwise)
142 continue_flag Flag if --continue was specified
143
144 Returns:
145 True if the arguments are acceptable, False otherwise
146 """
147 if continue_flag:
148 if board is not None or variant is not None:
149 logging.error('--continue cannot have other options')
150 return False
151
152 if bug != 'None':
153 logging.error('--continue cannot have other options')
154 return False
155 else:
156 if board is None:
157 logging.error('--board must be specified')
158 return False
159
160 if variant is None:
161 logging.error('--variant must be specified')
162 return False
163
164 return True
165
166
167def file_exists(filepath, filename):
168 """Determine if a path and file exists
169
170 Params:
171 filepath Path where build outputs should be found, e.g.
172 /build/hatch/firmware
173 filename File that should exist in that path, e.g.
174 image-sushi.bin
175
176 Returns:
177 True if file exists in that path, False otherwise
178 """
179 fullname = os.path.join(filepath, filename)
180 return os.path.exists(fullname) and os.path.isfile(fullname)
181
182
183def get_status(board, variant, bug, continue_flag):
184 """Create the status file or get the previous status
185
186 This program can stop at several places as we have to wait for CLs
187 to work through CQ or be upstreamed into the chromiumos tree, so just
188 like a git cherry-pick, there is a --continue option to pick up where
189 you left off.
190
191 If the --continue flag is present, make sure that the status file
192 exists, and fail if it doesn't.
193
194 If the --continue flag is not present, then create the status file
195 with the board, variant, and bug details. If the status file already
196 exists, this is an error case.
197
198 The function returns an object with several fields:
199 * board - the name of the baseboard, e.g. 'hatch'
200 * variant - the name of the variant, e.g. 'sushi'
201 * bug - optional text for a bug ID, used in the git commit messages.
202 Could be 'None' (as text, not the python None), or something like
203 'b:12345' for buganizer, or 'chromium:12345'
204 * workon - list of packages that will need `cros_workon start` before
205 we can `emerge`. Each function can add package names to this list.
206 * emerge - list of packages that we need to `emerge` at the end. Each
207 functions can add package names to this list.
208 * stage - internal state tracking, what stage of the variant creation
209 we are at.
210 * yaml_file - internal, just the name of the file where all this data
211 gets saved.
212
213 These data might come from the status file (because we read it), or
214 they might be the initial values after we created the file (because
215 it did not already exist).
216
217 Params:
218 board Name of the base board
219 variant Name of the variant being created
220 bug Text for bug number, if any ('None' otherwise)
221 continue_flag Flag if --continue was specified
222
223 Returns:
224 variant_status object that points to the yaml file
225 """
226 status = variant_status.variant_status()
227 if continue_flag:
228 if not status.yaml_file_exists():
229 logging.error(
230 'new_variant is not in progress; nothing to --continue')
231 return None
232 else:
233 if status.yaml_file_exists():
234 logging.error(
235 'new_variant already in progress; did you forget --continue?')
236 return None
237
238 status.board = board
239 status.variant = variant
240 status.bug = bug
Paul Fagerburgdd3e9c32020-01-07 14:00:35 -0700241
242 if board not in ['hatch', 'volteer']:
243 print('Unsupported baseboard "' + board + '"')
244 sys.exit(1)
245
246 # Depending on the board, we can have different values here
247 if board == 'hatch':
248 status.stage = 'cb_variant'
249 status.stage_list = [CB_VARIANT, CB_CONFIG, ADD_FIT, GEN_FIT,
250 COMMIT_FIT, EC_IMAGE, EC_BUILDALL, ADD_YAML, BUILD_YAML,
251 EMERGE, PUSH, UPLOAD, FIND, CQ_DEPEND, CLEAN_UP]
252
253 if board == 'volteer':
254 # TODO(pfagerburg) this list of stages will change
255 status.stage = 'cb_variant'
256 status.stage_list = [CB_VARIANT, CB_CONFIG, ADD_FIT, GEN_FIT,
257 COMMIT_FIT, EC_IMAGE, EC_BUILDALL, ADD_YAML, BUILD_YAML,
258 EMERGE, PUSH, UPLOAD, FIND, CQ_DEPEND, CLEAN_UP]
259
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700260 status.save()
261
262 return status
263
264
265# Constants for the stages, so we don't have to worry about misspelling them
266# pylint: disable=bad-whitespace
267# Allow extra spaces around = so that we can line things up nicely
268CB_VARIANT = 'cb_variant'
269CB_CONFIG = 'cb_config'
270ADD_FIT = 'add_fit'
271GEN_FIT = 'gen_fit'
272COMMIT_FIT = 'commit_fit'
273EC_IMAGE = 'ec_image'
274EC_BUILDALL = 'ec_buildall'
275ADD_YAML = 'add_yaml'
276BUILD_YAML = 'build_yaml'
277EMERGE = 'emerge'
278PUSH = 'push'
279UPLOAD = 'upload'
280FIND = 'find'
281CQ_DEPEND = 'cq_depend'
282CLEAN_UP = 'clean_up'
283# pylint: enable=bad-whitespace
284
285
286def perform_stage(status):
287 """Call the appropriate function for the current stage
288
289 Params:
290 st dictionary that provides details including
291 the board name, variant name, and bug ID
292
293 Returns:
294 True if the stage succeeded, False if it failed
295 """
296 # Function to call based on the stage
297 dispatch = {
298 CB_VARIANT: create_coreboot_variant,
299 CB_CONFIG: create_coreboot_config,
300 ADD_FIT: add_fitimage,
301 GEN_FIT: gen_fit_image_outside_chroot,
302 COMMIT_FIT: commit_fitimage,
303 EC_IMAGE: create_initial_ec_image,
304 EC_BUILDALL: ec_buildall,
305 ADD_YAML: add_variant_to_yaml,
306 BUILD_YAML: build_yaml,
307 EMERGE: emerge_all,
308 PUSH: push_coreboot,
309 UPLOAD: upload_CLs,
310 FIND: find_coreboot_upstream,
311 CQ_DEPEND: add_cq_depends,
312 CLEAN_UP: clean_up,
313 }
314
315 if status.stage not in dispatch:
316 logging.error('Unknown stage "%s", aborting...', status.stage)
317 sys.exit(1)
318
319 return dispatch[status.stage](status)
320
321
322def move_to_next_stage(status):
Paul Fagerburgdd3e9c32020-01-07 14:00:35 -0700323 """Move to the next stage in the list
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700324
325 Params:
326 status variant_status object tracking our board, variant, etc.
327 """
Paul Fagerburgdd3e9c32020-01-07 14:00:35 -0700328 if status.stage not in status.stage_list:
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700329 logging.error('Unknown stage "%s", aborting...', status.stage)
330 sys.exit(1)
331
Paul Fagerburgdd3e9c32020-01-07 14:00:35 -0700332 idx = status.stage_list.index(status.stage)
333 if idx == len(status.stage_list)-1:
334 status.stage = None
335 else:
336 status.stage = status.stage_list[idx+1]
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700337
338
339def run_process(args, *, cwd=None, env=None):
340 """Wrapper for subprocess.run that will produce debug-level messages
341
342 Params:
343 LImited subset, same as for subprocess.run
344
345 Returns:
346 Return value from subprocess.run
347 """
348 logging.debug('Run %s', str(args))
349 retval = subprocess.run(args, cwd=cwd, env=env).returncode
350 logging.debug('process returns %s', str(retval))
351 return retval
352
353
354def cros_workon(status, action):
355 """Call cros_workon for all the 9999 ebuilds we'll be touching
356
357 TODO(pfagerburg) detect 9999 ebuild to know if we have to workon the package
358
359 Params:
360 status variant_status object tracking our board, variant, etc.
361 action 'start' or 'stop'
362
363 Returns:
364 True if the call to cros_workon was successful, False if failed
365 """
366
367 # Build up the command from all the packages in the list
368 workon_cmd = ['cros_workon', '--board=' + status.board, action] + status.workon
369 return run_process(workon_cmd) == 0
370
371
372def create_coreboot_variant(status):
373 """Create source files for a new variant of the base board in coreboot
374
375 This function calls create_coreboot_variant.sh to set up a new variant
376 of the base board.
377
378 Params:
379 status variant_status object tracking our board, variant, etc.
380
381 Returns:
382 True if everything succeeded, False if something failed
383 """
384 logging.info('Running stage create_coreboot_variant')
385 status.workon += ['coreboot', 'libpayload', 'vboot_reference',
386 'depthcharge']
387 # Despite doing the workon here, we don't add this to emerge, because
388 # without the configuration (create_coreboot_config), `emerge coreboot`
389 # won't build the new variant.
390 status.emerge += ['libpayload', 'vboot_reference', 'depthcharge',
391 'chromeos-bootimage']
392
393 create_coreboot_variant_sh = os.path.join(
394 os.path.expanduser('~/trunk/src/third_party/coreboot'),
Paul Fagerburg7b516d72019-12-20 13:13:41 -0700395 'util/mainboard/google/create_coreboot_variant.sh')
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700396 return run_process(
397 [create_coreboot_variant_sh,
Paul Fagerburgdd3e9c32020-01-07 14:00:35 -0700398 status.board,
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700399 status.variant,
400 status.bug]) == 0
401
402
403def create_coreboot_config(status):
404 """Create a coreboot configuration for a new variant
405
406 This function calls create_coreboot_config.sh, which will make a copy
407 of coreboot.${BOARD} into coreboot.${VARIANT}.
408
409 Params:
410 status variant_status object tracking our board, variant, etc.
411
412 Returns:
413 True if the script and test build succeeded, False if something failed
414 """
415 logging.info('Running stage create_coreboot_config')
416 status.emerge += ['coreboot']
417 create_coreboot_config_sh = os.path.expanduser(
418 '~/trunk/src/platform/dev/contrib/variant/create_coreboot_config.sh')
419 return run_process(
420 [create_coreboot_config_sh,
421 status.board,
422 status.variant,
423 status.bug]) == 0
424
425
426def add_fitimage(status):
427 """Add the source files for a fitimage for the new variant
428
429 This function calls add_fitimage.sh to create a new XSL file for the
430 variant's fitimage, which can override settings from the base board's XSL.
431 When this is done, the user will have to build the fitimage by running
432 gen_fit_image.sh outside of the chroot (and outside of this program's
433 control) because gen_fit_image.sh uses WINE, which is not installed in
434 the chroot. (There is a linux version of FIT, but it requires Open GL,
435 which is also not installed in the chroot.)
436
437 Params:
438 status variant_status object tracking our board, variant, etc.
439
440 Returns:
441 True if the script succeeded, False otherwise
442 """
443 logging.info('Running stage add_fitimage')
Paul Fagerburg266886b2020-01-07 17:06:13 -0700444 pkg = 'coreboot-private-files-' + status.board
445 # The FSP depends on the baseboard model. We don't have to check for
446 # the baseboard not being in this hash because we already checked
447 # for an unsupported baseboard when the script started.
448 fsp = {
449 'hatch': 'intel-cmlfsp',
450 'volteer': 'intel-tglfsp'
451 }
452 status.workon += [fsp[status.board], pkg]
453 status.emerge += [fsp[status.board], pkg]
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700454 add_fitimage_sh = os.path.expanduser(os.path.join(
455 '~/trunk/src/private-overlays',
456 'baseboard-' + status.board + '-private',
457 'sys-boot',
458 'coreboot-private-files-' + status.board,
459 'files/add_fitimage.sh'))
460 return run_process(
461 [add_fitimage_sh,
462 status.variant,
463 status.bug]) == 0
464
465
466def gen_fit_image_outside_chroot(status):
467 """Tell the user to run gen_fit_image.sh outside the chroot
468
469 As noted for add_Fitimage(), gen_fit_image.sh cannot run inside the
470 chroot. This function tells the user to run gen_fit_image.sh in
471 their normal environment, and then come back (--continue) when that
472 is done.
473
474 Params:
475 status variant_status object tracking our board, variant, etc.
476
477 Returns:
478 True
479 """
480 logging.info('Running stage gen_fit_image_outside_chroot')
481 fit_image_files = check_fit_image_files(status)
482 # If the list is empty, then `not` of the list is True, so the files
483 # we need are all present and we can continue.
484 if not fit_image_files:
485 return True
486
487 logging.info('The following files need to be generated:')
488 for filename in fit_image_files:
489 logging.info('* %s', filename)
490 logging.info('The fitimage sources are ready for gen_fit_image.sh to process.')
491 logging.info('gen_fit_image.sh cannot run inside the chroot. Please open a new terminal')
492 logging.info('window, change to the directory where gen_fit_image.sh is located, and run')
493 logging.info('./gen_fit_image.sh %s [location of FIT] -b', status.variant)
494 logging.info('Then re-start this program with --continue.')
495 logging.info('If your chroot is based in ~/chromiumos, then the folder you want is')
496 logging.info('~/chromiumos/src/private-overlays/baseboard-%s-private/sys-boot'
497 '/coreboot-private-files-%s/asset_generation', status.board, status.board)
498 return False
499
500
501def check_fit_image_files(status):
502 """Check if the fitimage has been generated
503
504 This function is not called directly as a stage, and so it doesn't need
505 to produce any error messages to the user (except with --verbose).
506 gen_fit_image_outside_chroot will call this function to see if the
507 fitimage files exist, and if not, then that function will print the
508 message about how the user needs to run gen_fit_image.sh outside the
509 chroot.
510
511 Params:
512 status variant_status object tracking our board, variant, etc.
513
514 Returns:
515 List of files that *DO NOT* exist and need to be created, [] if
516 all files are present.
517 """
518 fitimage_dir = os.path.expanduser(os.path.join(
519 '~/trunk/src/private-overlays',
520 'baseboard-' + status.board + '-private',
521 'sys-boot',
522 'coreboot-private-files-' + status.board,
523 'asset_generation/outputs'))
524 logging.debug('fitimage_dir = "%s"', fitimage_dir)
525
526 files = []
527 if not file_exists(fitimage_dir, 'fitimage-' + status.variant + '.bin'):
528 files.append('fitimage-' + status.variant + '.bin')
529
530 if not file_exists(fitimage_dir,
531 'fitimage-' + status.variant + '-versions.txt'):
532 files.append('fitimage-' + status.variant + '-versions.txt')
533
534 if not file_exists(fitimage_dir, 'fit.log'):
535 files.append('fit.log')
536
537 return files
538
539
540def move_fitimage_file(fitimage_dir, filename):
541 """Move fitimage files from create-place to commit-place
542
543 commit_fitimage needs to move the fitimage files from the place where
544 they were created to a different directory in the tree. This utility
545 function handles joining paths and calling a file move function.
546
547 Params:
548 fitimage_dir Directory where the fitimage files are
549 filename Name of the file being moved
550
551 Returns:
552 True if the move succeeded, False if it failed
553 """
554 src_dir = os.path.join(fitimage_dir, 'asset_generation/outputs')
555 src = os.path.join(src_dir, filename)
556 dest_dir = os.path.join(fitimage_dir, 'files')
557 dest = os.path.join(dest_dir, filename)
558 # If src does not exist and dest does, the move is already done => success!
559 if not file_exists(src_dir, filename) and file_exists(dest_dir, filename):
560 logging.debug('move "%s", "%s" unnecessary because dest exists and'
561 ' src does not exist', src, dest)
562 return True
563
564 logging.debug('move "%s", "%s"', src, dest)
565 return shutil.move(src, dest)
566
567
568def commit_fitimage(status):
569 """Move the fitimage files and add them to a git commit
570
571 This function moves the fitimage binary and -versions files from
572 asset_generation/outputs to files/ and then adds those files and
573 fit.log to the existing git commit.
574
575 Params:
576 status variant_status object tracking our board, variant, etc.
577
578 Returns:
579 True if the copy, git add, and git commit --amend all succeeded.
580 False if something failed.
581 """
582 logging.info('Running stage commit_fitimage')
583 fitimage_dir = os.path.expanduser(os.path.join(
584 '~/trunk/src/private-overlays',
585 'baseboard-' + status.board + '-private',
586 'sys-boot',
587 'coreboot-private-files-' + status.board))
588 logging.debug('fitimage_dir = "%s"', fitimage_dir)
589
590 # The copy operation will check that the source file exists, so no
591 # need to check separately.
592 if not move_fitimage_file(fitimage_dir,
593 'fitimage-' + status.variant + '.bin'):
594 logging.error('Moving fitimage binary failed')
595 return False
596
597 if not move_fitimage_file(fitimage_dir,
598 'fitimage-' + status.variant + '-versions.txt'):
599 logging.error('Moving fitimage versions.txt failed')
600 return False
601
602 if run_process(
603 ['git', 'add',
604 'asset_generation/outputs/fit.log',
605 'files/fitimage-' + status.variant + '.bin',
606 'files/fitimage-' + status.variant + '-versions.txt'
607 ],
608 cwd=fitimage_dir) != 0:
609 return False
610
611 return run_process(['git', 'commit', '--amend', '--no-edit'],
612 cwd=fitimage_dir) == 0
613
614
615def create_initial_ec_image(status):
616 """Create an EC image for the variant as a clone of the base board
617
618 This function calls create_initial_ec_image.sh, which will clone the
619 base board to create the variant. The shell script will build the
620 EC code for the variant, but the repo upload hook insists that we
621 have done a `make buildall` before it will allow an upload, so this
622 function does the buildall.
623
624 Params:
625 status variant_status object tracking our board, variant, etc.
626
627 Returns:
628 True if the script and test build succeeded, False if something failed
629 """
630 logging.info('Running stage create_initial_ec_image')
631 status.workon += ['chromeos-ec']
632 status.emerge += ['chromeos-ec']
633 create_initial_ec_image_sh = os.path.expanduser(
634 '~/trunk/src/platform/dev/contrib/variant/create_initial_ec_image.sh')
635 if run_process(
636 [create_initial_ec_image_sh,
637 status.board,
638 status.variant,
639 status.bug]) != 0:
640 return False
641
642 # create_initial_ec_image.sh will build the ec.bin for this variant
643 # if successful.
644 ec = os.path.expanduser('~/trunk/src/platform/ec')
645 logging.debug('ec = "%s"', ec)
646 ec_bin = 'build/' + status.variant + '/ec.bin'
647 logging.debug('ec.bin = "%s"', ec_bin)
648
649 return file_exists(ec, ec_bin)
650
651
652def ec_buildall(status):
653 """Do a make buildall -j for the EC, which is required for repo upload
654
655 The upload hook checks to ensure that the entire EC codebase builds
656 without error, so we have to run make buildall -j before uploading.
657
658 Params:
659 status variant_status object tracking our board, variant, etc.
660
661 Returns:
662 True if the script and test build succeeded, False if something failed
663 """
664 logging.info('Running stage ec_buildall')
665 del status # unused parameter
666 ec = os.path.expanduser('~/trunk/src/platform/ec')
667 logging.debug('ec = "%s"', ec)
668 return run_process(['make', 'buildall', '-j'], cwd=ec) == 0
669
670
671def add_variant_to_yaml(status):
672 """Add the new variant to the public and private model.yaml files
673
674 This function calls add_variant_to_yaml.sh (the public yaml) and
675 add_variant.sh (the private yaml) to add the new variant to
676 the yaml files.
677
678 Params:
679 st dictionary that provides details including
680 the board name, variant name, and bug ID
681
682 Returns:
683 True if the scripts and build succeeded, False is something failed
684 """
685 logging.info('Running stage add_variant_to_yaml')
Paul Fagerburg266886b2020-01-07 17:06:13 -0700686 # TODO(pfagerburg) these can change in response to firmware changes
687 # or new board-specific support scripts that might handle the entire
688 # build or at least specify the packages so that this program doesn't
689 # have to know.
690 status.workon += ['chromeos-config-bsp-' + status.board + '-private']
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700691 status.emerge += ['chromeos-config', 'chromeos-config-bsp',
Paul Fagerburg266886b2020-01-07 17:06:13 -0700692 'chromeos-config-bsp-' + status.board,
693 'chromeos-config-bsp-' + status.board + '-private',
694 'coreboot-private-files', 'coreboot-private-files-' + status.board]
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700695 add_variant_to_yaml_sh = os.path.expanduser(
696 '~/trunk/src/platform/dev/contrib/variant/add_variant_to_yaml.sh')
697 if run_process(
698 [add_variant_to_yaml_sh,
699 status.board,
700 status.variant,
701 status.bug
702 ]) != 0:
703 return False
704
705 add_variant_sh = os.path.expanduser(os.path.join(
706 '~/trunk/src/private-overlays',
707 'overlay-' + status.board + '-private',
708 'chromeos-base',
709 'chromeos-config-bsp-' + status.board + '-private',
710 'add_variant.sh'))
711 if run_process(
712 [add_variant_sh,
713 status.variant,
714 status.bug
715 ]) != 0:
716 return False
717
718 return True
719
720
721def build_yaml(status):
722 """Build config files from the yaml files
723
724 This function builds the yaml files into the JSON and C code that
725 mosys and other tools use, then verifies that the new variant's name
726 shows up in all of the output files.
727
728 Params:
729 status variant_status object tracking our board, variant, etc.
730
731 Returns:
732 True if the scripts and build succeeded, False is something failed
733 """
734 logging.info('Running stage build_yaml')
735 if run_process(
736 ['emerge-' + status.board,
737 'chromeos-config-bsp-' + status.board,
738 'chromeos-config-bsp-' + status.board + '-private',
739 'chromeos-config-bsp',
740 'chromeos-config']) != 0:
741 return False
742
743 # Check generated files for occurences of the variant name.
744 # Each file should have at least one occurence, so use `grep -c` to
745 # count the occurrences of the variant name in each file.
746 # The results will be something like this:
747 # config.json:10
748 # yaml/config.c:6
749 # yaml/config.yaml:27
750 # yaml/model.yaml:6
751 # yaml/private-model.yaml:10
752 # If the variant name doesn't show up in the file, then the count
753 # will be 0, so we would see, e.g.
754 # config.json:0
755 # We gather the output from grep, decode as UTF-8, split along newlines,
756 # and then look for any of the strings ending in :0. If none of them
757 # match, then we're good, but if even one of them ends with :0 then
758 # there was a problem with generating the files from the yaml.
759 chromeos_config = '/build/' + status.board + '/usr/share/chromeos-config'
760 logging.debug('chromeos_config = "%s"', chromeos_config)
761 # Can't use run because we need to capture the output instead
762 # of a status code.
763 grep = subprocess.check_output(
764 ['grep',
765 '-c',
766 status.variant,
767 'config.json',
768 'yaml/config.c',
769 'yaml/config.yaml',
770 'yaml/model.yaml',
771 'yaml/private-model.yaml'], cwd=chromeos_config)
772 # Convert from byte string to ASCII
773 grep = grep.decode('utf-8')
774 # Split into array of individual lines
775 grep = grep.split('\n')
776 return not bool([s for s in grep if re.search(r':0$', s)])
777
778
779def emerge_all(status):
780 """Build the coreboot BIOS and EC code for the new variant
781
782 Params:
783 status variant_status object tracking our board, variant, etc.
784
785 Returns:
786 True if the build succeeded, False if something failed
787 """
788 logging.info('Running stage emerge_all')
789 cros_workon(status, 'start')
790 environ = os.environ.copy()
791 environ['FW_NAME'] = status.variant
792 # Build up the command for emerge from all the packages in the list
793 emerge_cmd_and_params = ['emerge-' + status.board] + status.emerge
794 if run_process(emerge_cmd_and_params, env=environ) != 0:
795 return False
796
797 cros_workon(status, 'stop')
798 build_path = '/build/' + status.board + '/firmware'
799 logging.debug('build_path = "%s"', build_path)
800 if not file_exists(build_path, 'image-' + status.variant + '.bin'):
801 logging.error('emerge failed because image-%s.bin does not exist',
802 status.variant)
803 return False
804
805 if not file_exists(build_path, 'image-' + status.variant + '.dev.bin'):
806 logging.error('emerge failed because image-%s.dev.bin does not exist',
807 status.variant)
808 return False
809
810 if not file_exists(build_path, 'image-' + status.variant + '.net.bin'):
811 logging.error('emerge failed because image-%s.net.bin does not exist',
812 status.variant)
813 return False
814
815 if not file_exists(build_path, 'image-' + status.variant + '.serial.bin'):
816 logging.error('emerge failed because image-%s.serial.bin does not exist',
817 status.variant)
818 return False
819
820 return True
821
822
823def push_coreboot(status):
824 """Push the coreboot CL to coreboot.org
825
826 Params:
827 status variant_status object tracking our board, variant, etc.
828
829 Returns:
830 True if the build succeeded, False if something failed
831 """
832 logging.info('Running stage push_coreboot')
833 del status # unused parameter
834 logging.error('TODO (pfagerburg): implement push_coreboot')
835 return True
836
837
838def upload_CLs(status):
839 """Upload all CLs to chromiumos
840
841 Params:
842 status variant_status object tracking our board, variant, etc.
843
844 Returns:
845 True if the build succeeded, False if something failed
846 """
847 logging.info('Running stage upload_CLs')
848 del status # unused parameter
849 logging.error('TODO (pfagerburg): implement upload_CLs')
850 return True
851
852
853def find_coreboot_upstream(status):
854 """Find the coreboot CL after it has been upstreamed to chromiumos
855
856 Params:
857 status variant_status object tracking our board, variant, etc.
858
859 Returns:
860 True if the build succeeded, False if something failed
861 """
862 logging.info('Running stage find_coreboot_upstream')
863 del status # unused parameter
864 logging.error('TODO (pfagerburg): implement find_coreboot_upstream')
865 return True
866
867
868def add_cq_depends(status):
869 """Add Cq-Depends to all of the CLs in chromiumos
870
871 The CL in coreboot needs to be pushed to coreboot.org, get merged,
872 and then get upstreamed into the chromiumos tree before the other
873 CLs can cq-depend on it and pass CQ.
874
875 Params:
876 status variant_status object tracking our board, variant, etc.
877
878 Returns:
879 True if the build succeeded, False if something failed
880 """
881 logging.info('Running stage add_cq_depends')
882 del status # unused parameter
883 logging.error('TODO (pfagerburg): implement add_cq_depends')
884 return True
885
886
887def clean_up(status):
888 """Final clean-up, including delete the status file
889
890 Params:
891 status variant_status object tracking our board, variant, etc.
892
893 Returns:
894 True
895 """
896 logging.info('Running stage clean_up')
897 status.rm()
898 return True
899
900
901if __name__ == '__main__':
902 sys.exit(not int(main()))