blob: fa08d55d3f1cdaa85a535dbf3c964e793fb71c06 [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
241 status.stage = 'cb_variant'
242 status.save()
243
244 return status
245
246
247# Constants for the stages, so we don't have to worry about misspelling them
248# pylint: disable=bad-whitespace
249# Allow extra spaces around = so that we can line things up nicely
250CB_VARIANT = 'cb_variant'
251CB_CONFIG = 'cb_config'
252ADD_FIT = 'add_fit'
253GEN_FIT = 'gen_fit'
254COMMIT_FIT = 'commit_fit'
255EC_IMAGE = 'ec_image'
256EC_BUILDALL = 'ec_buildall'
257ADD_YAML = 'add_yaml'
258BUILD_YAML = 'build_yaml'
259EMERGE = 'emerge'
260PUSH = 'push'
261UPLOAD = 'upload'
262FIND = 'find'
263CQ_DEPEND = 'cq_depend'
264CLEAN_UP = 'clean_up'
265# pylint: enable=bad-whitespace
266
267
268def perform_stage(status):
269 """Call the appropriate function for the current stage
270
271 Params:
272 st dictionary that provides details including
273 the board name, variant name, and bug ID
274
275 Returns:
276 True if the stage succeeded, False if it failed
277 """
278 # Function to call based on the stage
279 dispatch = {
280 CB_VARIANT: create_coreboot_variant,
281 CB_CONFIG: create_coreboot_config,
282 ADD_FIT: add_fitimage,
283 GEN_FIT: gen_fit_image_outside_chroot,
284 COMMIT_FIT: commit_fitimage,
285 EC_IMAGE: create_initial_ec_image,
286 EC_BUILDALL: ec_buildall,
287 ADD_YAML: add_variant_to_yaml,
288 BUILD_YAML: build_yaml,
289 EMERGE: emerge_all,
290 PUSH: push_coreboot,
291 UPLOAD: upload_CLs,
292 FIND: find_coreboot_upstream,
293 CQ_DEPEND: add_cq_depends,
294 CLEAN_UP: clean_up,
295 }
296
297 if status.stage not in dispatch:
298 logging.error('Unknown stage "%s", aborting...', status.stage)
299 sys.exit(1)
300
301 return dispatch[status.stage](status)
302
303
304def move_to_next_stage(status):
305 """Move to the next state
306
307 Params:
308 status variant_status object tracking our board, variant, etc.
309 """
310
311 # Stage to move to if the current one is successful
312 # TODO(pfagerburg) instead of using a map, have a list of stages that
313 # is saved to the yaml file. Create logic to populate that list at
314 # the beginning of the process, based on the --board argument; hatch
315 # can have a different list of stages compared to e.g. volteer.
316 next_stage = {
317 CB_VARIANT: CB_CONFIG,
318 CB_CONFIG: ADD_FIT,
319 ADD_FIT: GEN_FIT,
320 GEN_FIT: COMMIT_FIT,
321 COMMIT_FIT: EC_IMAGE,
322 EC_IMAGE: EC_BUILDALL,
323 EC_BUILDALL: ADD_YAML,
324 ADD_YAML: BUILD_YAML,
325 BUILD_YAML: EMERGE,
326 EMERGE: PUSH,
327 PUSH: UPLOAD,
328 UPLOAD: FIND,
329 FIND: CQ_DEPEND,
330 CQ_DEPEND: CLEAN_UP,
331 CLEAN_UP: None
332 }
333
334 if status.stage not in next_stage:
335 logging.error('Unknown stage "%s", aborting...', status.stage)
336 sys.exit(1)
337
338 status.stage = next_stage[status.stage]
339
340
341def run_process(args, *, cwd=None, env=None):
342 """Wrapper for subprocess.run that will produce debug-level messages
343
344 Params:
345 LImited subset, same as for subprocess.run
346
347 Returns:
348 Return value from subprocess.run
349 """
350 logging.debug('Run %s', str(args))
351 retval = subprocess.run(args, cwd=cwd, env=env).returncode
352 logging.debug('process returns %s', str(retval))
353 return retval
354
355
356def cros_workon(status, action):
357 """Call cros_workon for all the 9999 ebuilds we'll be touching
358
359 TODO(pfagerburg) detect 9999 ebuild to know if we have to workon the package
360
361 Params:
362 status variant_status object tracking our board, variant, etc.
363 action 'start' or 'stop'
364
365 Returns:
366 True if the call to cros_workon was successful, False if failed
367 """
368
369 # Build up the command from all the packages in the list
370 workon_cmd = ['cros_workon', '--board=' + status.board, action] + status.workon
371 return run_process(workon_cmd) == 0
372
373
374def create_coreboot_variant(status):
375 """Create source files for a new variant of the base board in coreboot
376
377 This function calls create_coreboot_variant.sh to set up a new variant
378 of the base board.
379
380 Params:
381 status variant_status object tracking our board, variant, etc.
382
383 Returns:
384 True if everything succeeded, False if something failed
385 """
386 logging.info('Running stage create_coreboot_variant')
387 status.workon += ['coreboot', 'libpayload', 'vboot_reference',
388 'depthcharge']
389 # Despite doing the workon here, we don't add this to emerge, because
390 # without the configuration (create_coreboot_config), `emerge coreboot`
391 # won't build the new variant.
392 status.emerge += ['libpayload', 'vboot_reference', 'depthcharge',
393 'chromeos-bootimage']
394
395 create_coreboot_variant_sh = os.path.join(
396 os.path.expanduser('~/trunk/src/third_party/coreboot'),
397 'util/mainboard/google/', status.board, 'create_coreboot_variant.sh')
398 return run_process(
399 [create_coreboot_variant_sh,
400 status.variant,
401 status.bug]) == 0
402
403
404def create_coreboot_config(status):
405 """Create a coreboot configuration for a new variant
406
407 This function calls create_coreboot_config.sh, which will make a copy
408 of coreboot.${BOARD} into coreboot.${VARIANT}.
409
410 Params:
411 status variant_status object tracking our board, variant, etc.
412
413 Returns:
414 True if the script and test build succeeded, False if something failed
415 """
416 logging.info('Running stage create_coreboot_config')
417 status.emerge += ['coreboot']
418 create_coreboot_config_sh = os.path.expanduser(
419 '~/trunk/src/platform/dev/contrib/variant/create_coreboot_config.sh')
420 return run_process(
421 [create_coreboot_config_sh,
422 status.board,
423 status.variant,
424 status.bug]) == 0
425
426
427def add_fitimage(status):
428 """Add the source files for a fitimage for the new variant
429
430 This function calls add_fitimage.sh to create a new XSL file for the
431 variant's fitimage, which can override settings from the base board's XSL.
432 When this is done, the user will have to build the fitimage by running
433 gen_fit_image.sh outside of the chroot (and outside of this program's
434 control) because gen_fit_image.sh uses WINE, which is not installed in
435 the chroot. (There is a linux version of FIT, but it requires Open GL,
436 which is also not installed in the chroot.)
437
438 Params:
439 status variant_status object tracking our board, variant, etc.
440
441 Returns:
442 True if the script succeeded, False otherwise
443 """
444 logging.info('Running stage add_fitimage')
445 status.workon += ['intel-cmlfsp']
446 status.emerge += ['intel-cmlfsp']
447 add_fitimage_sh = os.path.expanduser(os.path.join(
448 '~/trunk/src/private-overlays',
449 'baseboard-' + status.board + '-private',
450 'sys-boot',
451 'coreboot-private-files-' + status.board,
452 'files/add_fitimage.sh'))
453 return run_process(
454 [add_fitimage_sh,
455 status.variant,
456 status.bug]) == 0
457
458
459def gen_fit_image_outside_chroot(status):
460 """Tell the user to run gen_fit_image.sh outside the chroot
461
462 As noted for add_Fitimage(), gen_fit_image.sh cannot run inside the
463 chroot. This function tells the user to run gen_fit_image.sh in
464 their normal environment, and then come back (--continue) when that
465 is done.
466
467 Params:
468 status variant_status object tracking our board, variant, etc.
469
470 Returns:
471 True
472 """
473 logging.info('Running stage gen_fit_image_outside_chroot')
474 fit_image_files = check_fit_image_files(status)
475 # If the list is empty, then `not` of the list is True, so the files
476 # we need are all present and we can continue.
477 if not fit_image_files:
478 return True
479
480 logging.info('The following files need to be generated:')
481 for filename in fit_image_files:
482 logging.info('* %s', filename)
483 logging.info('The fitimage sources are ready for gen_fit_image.sh to process.')
484 logging.info('gen_fit_image.sh cannot run inside the chroot. Please open a new terminal')
485 logging.info('window, change to the directory where gen_fit_image.sh is located, and run')
486 logging.info('./gen_fit_image.sh %s [location of FIT] -b', status.variant)
487 logging.info('Then re-start this program with --continue.')
488 logging.info('If your chroot is based in ~/chromiumos, then the folder you want is')
489 logging.info('~/chromiumos/src/private-overlays/baseboard-%s-private/sys-boot'
490 '/coreboot-private-files-%s/asset_generation', status.board, status.board)
491 return False
492
493
494def check_fit_image_files(status):
495 """Check if the fitimage has been generated
496
497 This function is not called directly as a stage, and so it doesn't need
498 to produce any error messages to the user (except with --verbose).
499 gen_fit_image_outside_chroot will call this function to see if the
500 fitimage files exist, and if not, then that function will print the
501 message about how the user needs to run gen_fit_image.sh outside the
502 chroot.
503
504 Params:
505 status variant_status object tracking our board, variant, etc.
506
507 Returns:
508 List of files that *DO NOT* exist and need to be created, [] if
509 all files are present.
510 """
511 fitimage_dir = os.path.expanduser(os.path.join(
512 '~/trunk/src/private-overlays',
513 'baseboard-' + status.board + '-private',
514 'sys-boot',
515 'coreboot-private-files-' + status.board,
516 'asset_generation/outputs'))
517 logging.debug('fitimage_dir = "%s"', fitimage_dir)
518
519 files = []
520 if not file_exists(fitimage_dir, 'fitimage-' + status.variant + '.bin'):
521 files.append('fitimage-' + status.variant + '.bin')
522
523 if not file_exists(fitimage_dir,
524 'fitimage-' + status.variant + '-versions.txt'):
525 files.append('fitimage-' + status.variant + '-versions.txt')
526
527 if not file_exists(fitimage_dir, 'fit.log'):
528 files.append('fit.log')
529
530 return files
531
532
533def move_fitimage_file(fitimage_dir, filename):
534 """Move fitimage files from create-place to commit-place
535
536 commit_fitimage needs to move the fitimage files from the place where
537 they were created to a different directory in the tree. This utility
538 function handles joining paths and calling a file move function.
539
540 Params:
541 fitimage_dir Directory where the fitimage files are
542 filename Name of the file being moved
543
544 Returns:
545 True if the move succeeded, False if it failed
546 """
547 src_dir = os.path.join(fitimage_dir, 'asset_generation/outputs')
548 src = os.path.join(src_dir, filename)
549 dest_dir = os.path.join(fitimage_dir, 'files')
550 dest = os.path.join(dest_dir, filename)
551 # If src does not exist and dest does, the move is already done => success!
552 if not file_exists(src_dir, filename) and file_exists(dest_dir, filename):
553 logging.debug('move "%s", "%s" unnecessary because dest exists and'
554 ' src does not exist', src, dest)
555 return True
556
557 logging.debug('move "%s", "%s"', src, dest)
558 return shutil.move(src, dest)
559
560
561def commit_fitimage(status):
562 """Move the fitimage files and add them to a git commit
563
564 This function moves the fitimage binary and -versions files from
565 asset_generation/outputs to files/ and then adds those files and
566 fit.log to the existing git commit.
567
568 Params:
569 status variant_status object tracking our board, variant, etc.
570
571 Returns:
572 True if the copy, git add, and git commit --amend all succeeded.
573 False if something failed.
574 """
575 logging.info('Running stage commit_fitimage')
576 fitimage_dir = os.path.expanduser(os.path.join(
577 '~/trunk/src/private-overlays',
578 'baseboard-' + status.board + '-private',
579 'sys-boot',
580 'coreboot-private-files-' + status.board))
581 logging.debug('fitimage_dir = "%s"', fitimage_dir)
582
583 # The copy operation will check that the source file exists, so no
584 # need to check separately.
585 if not move_fitimage_file(fitimage_dir,
586 'fitimage-' + status.variant + '.bin'):
587 logging.error('Moving fitimage binary failed')
588 return False
589
590 if not move_fitimage_file(fitimage_dir,
591 'fitimage-' + status.variant + '-versions.txt'):
592 logging.error('Moving fitimage versions.txt failed')
593 return False
594
595 if run_process(
596 ['git', 'add',
597 'asset_generation/outputs/fit.log',
598 'files/fitimage-' + status.variant + '.bin',
599 'files/fitimage-' + status.variant + '-versions.txt'
600 ],
601 cwd=fitimage_dir) != 0:
602 return False
603
604 return run_process(['git', 'commit', '--amend', '--no-edit'],
605 cwd=fitimage_dir) == 0
606
607
608def create_initial_ec_image(status):
609 """Create an EC image for the variant as a clone of the base board
610
611 This function calls create_initial_ec_image.sh, which will clone the
612 base board to create the variant. The shell script will build the
613 EC code for the variant, but the repo upload hook insists that we
614 have done a `make buildall` before it will allow an upload, so this
615 function does the buildall.
616
617 Params:
618 status variant_status object tracking our board, variant, etc.
619
620 Returns:
621 True if the script and test build succeeded, False if something failed
622 """
623 logging.info('Running stage create_initial_ec_image')
624 status.workon += ['chromeos-ec']
625 status.emerge += ['chromeos-ec']
626 create_initial_ec_image_sh = os.path.expanduser(
627 '~/trunk/src/platform/dev/contrib/variant/create_initial_ec_image.sh')
628 if run_process(
629 [create_initial_ec_image_sh,
630 status.board,
631 status.variant,
632 status.bug]) != 0:
633 return False
634
635 # create_initial_ec_image.sh will build the ec.bin for this variant
636 # if successful.
637 ec = os.path.expanduser('~/trunk/src/platform/ec')
638 logging.debug('ec = "%s"', ec)
639 ec_bin = 'build/' + status.variant + '/ec.bin'
640 logging.debug('ec.bin = "%s"', ec_bin)
641
642 return file_exists(ec, ec_bin)
643
644
645def ec_buildall(status):
646 """Do a make buildall -j for the EC, which is required for repo upload
647
648 The upload hook checks to ensure that the entire EC codebase builds
649 without error, so we have to run make buildall -j before uploading.
650
651 Params:
652 status variant_status object tracking our board, variant, etc.
653
654 Returns:
655 True if the script and test build succeeded, False if something failed
656 """
657 logging.info('Running stage ec_buildall')
658 del status # unused parameter
659 ec = os.path.expanduser('~/trunk/src/platform/ec')
660 logging.debug('ec = "%s"', ec)
661 return run_process(['make', 'buildall', '-j'], cwd=ec) == 0
662
663
664def add_variant_to_yaml(status):
665 """Add the new variant to the public and private model.yaml files
666
667 This function calls add_variant_to_yaml.sh (the public yaml) and
668 add_variant.sh (the private yaml) to add the new variant to
669 the yaml files.
670
671 Params:
672 st dictionary that provides details including
673 the board name, variant name, and bug ID
674
675 Returns:
676 True if the scripts and build succeeded, False is something failed
677 """
678 logging.info('Running stage add_variant_to_yaml')
679 status.workon += ['chromeos-config-bsp-hatch-private']
680 status.emerge += ['chromeos-config', 'chromeos-config-bsp',
681 'chromeos-config-bsp-hatch', 'chromeos-config-bsp-hatch-private',
682 'coreboot-private-files', 'coreboot-private-files-hatch']
683 add_variant_to_yaml_sh = os.path.expanduser(
684 '~/trunk/src/platform/dev/contrib/variant/add_variant_to_yaml.sh')
685 if run_process(
686 [add_variant_to_yaml_sh,
687 status.board,
688 status.variant,
689 status.bug
690 ]) != 0:
691 return False
692
693 add_variant_sh = os.path.expanduser(os.path.join(
694 '~/trunk/src/private-overlays',
695 'overlay-' + status.board + '-private',
696 'chromeos-base',
697 'chromeos-config-bsp-' + status.board + '-private',
698 'add_variant.sh'))
699 if run_process(
700 [add_variant_sh,
701 status.variant,
702 status.bug
703 ]) != 0:
704 return False
705
706 return True
707
708
709def build_yaml(status):
710 """Build config files from the yaml files
711
712 This function builds the yaml files into the JSON and C code that
713 mosys and other tools use, then verifies that the new variant's name
714 shows up in all of the output files.
715
716 Params:
717 status variant_status object tracking our board, variant, etc.
718
719 Returns:
720 True if the scripts and build succeeded, False is something failed
721 """
722 logging.info('Running stage build_yaml')
723 if run_process(
724 ['emerge-' + status.board,
725 'chromeos-config-bsp-' + status.board,
726 'chromeos-config-bsp-' + status.board + '-private',
727 'chromeos-config-bsp',
728 'chromeos-config']) != 0:
729 return False
730
731 # Check generated files for occurences of the variant name.
732 # Each file should have at least one occurence, so use `grep -c` to
733 # count the occurrences of the variant name in each file.
734 # The results will be something like this:
735 # config.json:10
736 # yaml/config.c:6
737 # yaml/config.yaml:27
738 # yaml/model.yaml:6
739 # yaml/private-model.yaml:10
740 # If the variant name doesn't show up in the file, then the count
741 # will be 0, so we would see, e.g.
742 # config.json:0
743 # We gather the output from grep, decode as UTF-8, split along newlines,
744 # and then look for any of the strings ending in :0. If none of them
745 # match, then we're good, but if even one of them ends with :0 then
746 # there was a problem with generating the files from the yaml.
747 chromeos_config = '/build/' + status.board + '/usr/share/chromeos-config'
748 logging.debug('chromeos_config = "%s"', chromeos_config)
749 # Can't use run because we need to capture the output instead
750 # of a status code.
751 grep = subprocess.check_output(
752 ['grep',
753 '-c',
754 status.variant,
755 'config.json',
756 'yaml/config.c',
757 'yaml/config.yaml',
758 'yaml/model.yaml',
759 'yaml/private-model.yaml'], cwd=chromeos_config)
760 # Convert from byte string to ASCII
761 grep = grep.decode('utf-8')
762 # Split into array of individual lines
763 grep = grep.split('\n')
764 return not bool([s for s in grep if re.search(r':0$', s)])
765
766
767def emerge_all(status):
768 """Build the coreboot BIOS and EC code for the new variant
769
770 Params:
771 status variant_status object tracking our board, variant, etc.
772
773 Returns:
774 True if the build succeeded, False if something failed
775 """
776 logging.info('Running stage emerge_all')
777 cros_workon(status, 'start')
778 environ = os.environ.copy()
779 environ['FW_NAME'] = status.variant
780 # Build up the command for emerge from all the packages in the list
781 emerge_cmd_and_params = ['emerge-' + status.board] + status.emerge
782 if run_process(emerge_cmd_and_params, env=environ) != 0:
783 return False
784
785 cros_workon(status, 'stop')
786 build_path = '/build/' + status.board + '/firmware'
787 logging.debug('build_path = "%s"', build_path)
788 if not file_exists(build_path, 'image-' + status.variant + '.bin'):
789 logging.error('emerge failed because image-%s.bin does not exist',
790 status.variant)
791 return False
792
793 if not file_exists(build_path, 'image-' + status.variant + '.dev.bin'):
794 logging.error('emerge failed because image-%s.dev.bin does not exist',
795 status.variant)
796 return False
797
798 if not file_exists(build_path, 'image-' + status.variant + '.net.bin'):
799 logging.error('emerge failed because image-%s.net.bin does not exist',
800 status.variant)
801 return False
802
803 if not file_exists(build_path, 'image-' + status.variant + '.serial.bin'):
804 logging.error('emerge failed because image-%s.serial.bin does not exist',
805 status.variant)
806 return False
807
808 return True
809
810
811def push_coreboot(status):
812 """Push the coreboot CL to coreboot.org
813
814 Params:
815 status variant_status object tracking our board, variant, etc.
816
817 Returns:
818 True if the build succeeded, False if something failed
819 """
820 logging.info('Running stage push_coreboot')
821 del status # unused parameter
822 logging.error('TODO (pfagerburg): implement push_coreboot')
823 return True
824
825
826def upload_CLs(status):
827 """Upload all CLs to chromiumos
828
829 Params:
830 status variant_status object tracking our board, variant, etc.
831
832 Returns:
833 True if the build succeeded, False if something failed
834 """
835 logging.info('Running stage upload_CLs')
836 del status # unused parameter
837 logging.error('TODO (pfagerburg): implement upload_CLs')
838 return True
839
840
841def find_coreboot_upstream(status):
842 """Find the coreboot CL after it has been upstreamed to chromiumos
843
844 Params:
845 status variant_status object tracking our board, variant, etc.
846
847 Returns:
848 True if the build succeeded, False if something failed
849 """
850 logging.info('Running stage find_coreboot_upstream')
851 del status # unused parameter
852 logging.error('TODO (pfagerburg): implement find_coreboot_upstream')
853 return True
854
855
856def add_cq_depends(status):
857 """Add Cq-Depends to all of the CLs in chromiumos
858
859 The CL in coreboot needs to be pushed to coreboot.org, get merged,
860 and then get upstreamed into the chromiumos tree before the other
861 CLs can cq-depend on it and pass CQ.
862
863 Params:
864 status variant_status object tracking our board, variant, etc.
865
866 Returns:
867 True if the build succeeded, False if something failed
868 """
869 logging.info('Running stage add_cq_depends')
870 del status # unused parameter
871 logging.error('TODO (pfagerburg): implement add_cq_depends')
872 return True
873
874
875def clean_up(status):
876 """Final clean-up, including delete the status file
877
878 Params:
879 status variant_status object tracking our board, variant, etc.
880
881 Returns:
882 True
883 """
884 logging.info('Running stage clean_up')
885 status.rm()
886 return True
887
888
889if __name__ == '__main__':
890 sys.exit(not int(main()))