blob: 5d2e146ad97f91adee44e59c22b2d41ac87b7874 [file] [log] [blame]
Paul Fagerburg3b534f92019-11-07 15:05:22 -07001#!/usr/bin/env python3
2# -*- coding: utf-8 -*-
Paul Fagerburg92fcb4b2020-02-19 21:21:43 -07003#
4# Copyright 2020 The Chromium OS Authors. All rights reserved.
5# Use of this source code is governed by a BSD-style license that can be
6# found in the LICENSE file.
7#
Paul Fagerburge868e832020-01-22 17:14:04 -07008"""Create a new variant of an existing reference board
Paul Fagerburg3b534f92019-11-07 15:05:22 -07009
10This program will call all of the scripts that create the various pieces
11of a new variant. For example to create a new variant of the hatch base
12board, the following scripts are called:
13
Paul Fagerburg5f794bf2020-02-12 13:01:36 -070014* platform/dev/contrib/variant/create_coreboot_variant.sh
Paul Fagerburg3b534f92019-11-07 15:05:22 -070015* platform/dev/contrib/variant/create_coreboot_config.sh
16* private-overlays/baseboard-hatch-private/sys-boot/
17 * coreboot-private-files-hatch/files/add_fitimage.sh
18 * coreboot-private-files-hatch/asset_generation/gen_fit_image.sh
19 * Outside the chroot, because it uses WINE to run the FIT tools
20* platform/dev/contrib/variant/create_initial_ec_image.sh
21* platform/dev/contrib/variant/add_variant_to_yaml.sh
22* private-overlays/overlay-hatch-private/chromeos-base/
23 * chromeos-config-bsp-hatch-private/add_variant.sh
24
25Once the scripts are done, the following repos have changes
26
27* third_party/coreboot
28* third_party/chromiumos-overlay
29* private-overlays/baseboard-hatch-private
30* platform/ec
31* private-overlays/overlay-hatch-private
32* overlays
33
Paul Fagerburge868e832020-01-22 17:14:04 -070034The program has support for multiple reference boards, so the repos, directories,
35and scripts above can change depending on what the reference board is.
Paul Fagerburg3b534f92019-11-07 15:05:22 -070036"""
37
38from __future__ import print_function
39import argparse
Paul Fagerburgbab5dde2020-01-10 15:10:29 -070040import importlib
Paul Fagerburg8d850932020-02-25 14:13:32 -070041import json
Paul Fagerburg3b534f92019-11-07 15:05:22 -070042import logging
43import os
Paul Fagerburg3b534f92019-11-07 15:05:22 -070044import shutil
45import subprocess
46import sys
Paul Fagerburg1d043c32020-02-03 08:57:08 -070047from chromite.lib import git
Paul Fagerburga8c7e342020-02-25 13:30:49 -070048from chromite.lib import gerrit
Paul Fagerburga95dd162020-03-24 16:27:18 -060049from chromite.lib import osutils
Paul Fagerburg75398072020-03-16 13:51:24 -060050from chromite.lib import workon_helper
51from chromite.lib.build_target_lib import BuildTarget
Paul Fagerburg8d850932020-02-25 14:13:32 -070052import requests
Paul Fagerburgbab5dde2020-01-10 15:10:29 -070053import step_names
Paul Fagerburg3b534f92019-11-07 15:05:22 -070054import variant_status
55
56
57def main():
Paul Fagerburge868e832020-01-22 17:14:04 -070058 """Create a new variant of an existing reference board
Paul Fagerburg3b534f92019-11-07 15:05:22 -070059
60 This program automates the creation of a new variant of an existing
Paul Fagerburge868e832020-01-22 17:14:04 -070061 reference board by calling various scripts that copy the reference board,
62 modify files for the new variant, stage commits, and upload to gerrit.
Paul Fagerburg3b534f92019-11-07 15:05:22 -070063
64 Note that one of the following is required:
65 * --continue
66 * --board=BOARD --variant=VARIANT [--bug=BUG]
67 """
Paul Fagerburg042a5252020-03-16 21:49:18 -060068 board, variant, bug, continue_flag, abort_flag = get_args()
Paul Fagerburg3b534f92019-11-07 15:05:22 -070069
Paul Fagerburg042a5252020-03-16 21:49:18 -060070 if not check_flags(board, variant, bug, continue_flag, abort_flag):
Paul Fagerburg3b534f92019-11-07 15:05:22 -070071 return False
72
Paul Fagerburg042a5252020-03-16 21:49:18 -060073 status = get_status(board, variant, bug, continue_flag, abort_flag)
Paul Fagerburg3b534f92019-11-07 15:05:22 -070074 if status is None:
75 return False
76
77 status.load()
78
Paul Fagerburg5f794bf2020-02-12 13:01:36 -070079 # Where is new_variant.py located?
80 status.my_loc = os.path.dirname(os.path.abspath(__file__))
81
Paul Fagerburg042a5252020-03-16 21:49:18 -060082 # If the user specified --abort, override the current step.
83 if abort_flag:
84 status.step = step_names.ABORT
85
Paul Fagerburgbab5dde2020-01-10 15:10:29 -070086 while status.step is not None:
Paul Fagerburg3b534f92019-11-07 15:05:22 -070087 status.save()
Paul Fagerburgbab5dde2020-01-10 15:10:29 -070088 if not perform_step(status):
89 logging.debug('perform_step returned False; exiting ...')
Paul Fagerburg3b534f92019-11-07 15:05:22 -070090 return False
91
Paul Fagerburgbab5dde2020-01-10 15:10:29 -070092 move_to_next_step(status)
Paul Fagerburg3b534f92019-11-07 15:05:22 -070093
94 return True
95
96
97def get_args():
98 """Parse the command-line arguments
99
100 There doesn't appear to be a way to specify that --continue is
101 mutually exclusive with --board, --variant, and --bug. As a result,
102 all arguments are optional, and another function will apply the logic
103 to check if there is an illegal combination of arguments.
104
105 Returns a list of:
Paul Fagerburge868e832020-01-22 17:14:04 -0700106 board Name of the reference board
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700107 variant Name of the variant being created
108 bug Text for bug number, if any ('None' otherwise)
109 continue_flag Flag if --continue was specified
110 """
111 parser = argparse.ArgumentParser(
112 description=main.__doc__,
113 formatter_class=argparse.RawTextHelpFormatter)
Paul Fagerburge868e832020-01-22 17:14:04 -0700114 parser.add_argument('--board', type=str, help='Name of the reference board')
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700115 parser.add_argument(
116 '--variant', type=str, help='Name of the new variant to create')
117 parser.add_argument(
118 '--bug', type=str, help='Bug number to reference in commits')
Paul Fagerburg2e48a192020-03-24 17:57:05 -0600119 # Use a group so that we can enforce mutually-exclusive argurments.
120 # argparse does not support nesting groups, so we can't put board,
121 # variant, and bug into a group and have that group as another mutually
122 # exclusive option.
123 group = parser.add_mutually_exclusive_group()
124 group.add_argument(
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700125 '--continue', action='store_true',
126 dest='continue_flag', help='Continue the process from where it paused')
Paul Fagerburg2e48a192020-03-24 17:57:05 -0600127 group.add_argument(
Paul Fagerburg042a5252020-03-16 21:49:18 -0600128 '--abort', action='store_true',
129 dest='abort_flag', help='Cancel the process and abandon all commits')
130 parser.add_argument(
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700131 '--verbose', action='store_true',
132 dest='verbose_flag', help='Enable verbose output of progress')
133 args = parser.parse_args()
134
135 if args.verbose_flag:
136 logging.basicConfig(level=logging.DEBUG)
137 else:
138 logging.basicConfig(level=logging.INFO)
139
140 board = args.board
141 if board is not None:
142 board = board.lower()
143
144 variant = args.variant
145 if variant is not None:
146 variant = variant.lower()
147
148 bug = args.bug or 'None'
149
Paul Fagerburg042a5252020-03-16 21:49:18 -0600150 return (board, variant, bug, args.continue_flag, args.abort_flag)
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700151
152
Paul Fagerburg042a5252020-03-16 21:49:18 -0600153def check_flags(board, variant, bug, continue_flag, abort_flag):
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700154 """Check the flags to ensure no invalid combinations
155
156 We allow any of the following:
Paul Fagerburg042a5252020-03-16 21:49:18 -0600157 --abort
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700158 --continue
159 --board=board_name --variant=variant_name
160 --board=board_name --variant=variant_name --bug=bug_text
161
162 The argument parser does have the functionality to represent the
163 combination of --board and --variant as a single mutually-exclusive
164 argument, so we have to use this function to do the checking.
165
Paul Fagerburg92fcb4b2020-02-19 21:21:43 -0700166 Args:
167 board: Name of the reference board
168 variant: Name of the variant being created
169 bug: Text for bug number, if any ('None' otherwise)
170 continue_flag: Flag if --continue was specified
Paul Fagerburg042a5252020-03-16 21:49:18 -0600171 abort_flag: Flag if --abort was specified
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700172
173 Returns:
174 True if the arguments are acceptable, False otherwise
175 """
Paul Fagerburg042a5252020-03-16 21:49:18 -0600176 # If either --abort or --continue is set, then disallow any of the
177 # board name, variant name, or bug number to be set.
178 if continue_flag or abort_flag:
179 if board is not None or variant is not None or bug != 'None':
180 logging.error('Do not use --board, --variant, or --bug with '
181 '--continue or --abort')
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700182 return False
Paul Fagerburg042a5252020-03-16 21:49:18 -0600183 return True
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700184
Paul Fagerburg042a5252020-03-16 21:49:18 -0600185 # At this point, neither --continue nor --abort are set, so we must have
186 # both --board and --variant values.
187 if board is None or variant is None:
188 logging.error('Both --board and --variant must be specified')
189 return False
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700190
191 return True
192
193
Paul Fagerburg042a5252020-03-16 21:49:18 -0600194def get_status(board, variant, bug, continue_flag, abort_flag):
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700195 """Create the status file or get the previous status
196
197 This program can stop at several places as we have to wait for CLs
198 to work through CQ or be upstreamed into the chromiumos tree, so just
199 like a git cherry-pick, there is a --continue option to pick up where
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700200 you left off by reading a specially-named status file.
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700201
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700202 If --continue is specified, the status file must exist.
203 If the status file exists, then --continue must be specified.
204 When --continue is specified, we read the status file and return
205 with the contents.
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700206
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700207 If the status file does not exist, we will create the state file with
208 the board, variant, and (optional) bug details.
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700209
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700210 To decouple the list of boards supported from this main program, we
Paul Fagerburge868e832020-01-22 17:14:04 -0700211 try to import a module with the same name as the reference board,
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700212 so --board=hatch means that we import hatch.py. If we can't import
Paul Fagerburge868e832020-01-22 17:14:04 -0700213 the file, then we don't support that reference board.
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700214
215 The board-specific module will set several variables, which we will
216 copy into the object that we return.
217
Paul Fagerburge868e832020-01-22 17:14:04 -0700218 * base - the name of the base board, such as Hatch, Volteer, or Zork.
219 This can be different from the reference board, e.g. the Trembyle
220 reference board in the Zork project.
Paul Fagerburg4d343452020-01-24 15:23:53 -0700221 * coreboot_dir - base directory for coreboot, usually third_party/coreboot
222 but could differ for processors that use a private repo
223 * cb_config_dir - base directory for coreboot configs, usually
224 third_party/chromiumos-overlay/sys-boot/coreboot/files/configs but
225 could differ for processors that use a private repo
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700226 * step_list - list of steps (named in step_names.py) to run in sequence
Paul Fagerburge868e832020-01-22 17:14:04 -0700227 to create the new variant of the reference board
228 * fsp - package name for FSP. This may be None, depending on the
229 processor on the reference board
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700230 * fitimage_pkg - package name for the fitimage
Paul Fagerburg5f794bf2020-02-12 13:01:36 -0700231 * fitimage_dir - directory for fitimage; prepend '/mnt/host/source/src/'
232 in chroot, prepend '~/chromiumos/src' outside the chroot
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700233 * workon_pkgs - list of packages to cros_workon
234 * emerge_cmd - the emerge command, e.g. 'emerge-hatch'
235 * emerge_pkgs - list of packages to emerge
236 * yaml_emerge_pkgs - list of packages to emerge just to build the yaml
237 * private_yaml_dir - directory for the private yaml file
Paul Fagerburga8c7e342020-02-25 13:30:49 -0700238 * commits - map of commits for the various steps. Indexed by step name,
239 and the step names used are the same ones in step_names.py
240 * repo_upload_list - list of commits to upload using `repo upload`
241 * coreboot_push_list - list of commits to upload using `git push` to
242 coreboot
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700243
244 Additionally, the following fields will be set:
245
Paul Fagerburge868e832020-01-22 17:14:04 -0700246 * board - the name of the reference board, e.g. 'hatch'
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700247 * variant - the name of the variant, e.g. 'sushi'
248 * bug - optional text for a bug ID, used in the git commit messages.
249 Could be 'None' (as text, not the python None), or something like
250 'b:12345' for buganizer, or 'chromium:12345'
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700251 * step - internal state tracking, what step of the variant creation
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700252 we are at.
253 * yaml_file - internal, just the name of the file where all this data
254 gets saved.
Paul Fagerburgaec8d992020-02-27 15:51:47 -0700255 * commit - a map of maps that tracks all of the git commit and gerrit CL
256 data for each of the steps in the process. For example,
257 status.commit['add_priv_yaml'] is a map that has all the information
258 about the 'add_priv_yaml' step. The keys in the maps allow us to
259 determine where the commit is, the change_id, if it has been uploaded
260 to gerrit and where.
261
262 branch_name - the name of the git branch
263 change_id - the change-id assigned by the commit hook. Gerrit
264 uses the change_id to track new patchsets in the CL
265 dir - the directory where the commit has been created
266 gerrit - the name of the gerrit instance to which the CL has
267 been uploaded, one of 'chromium', 'chrome-internal', or
268 'coreboot'
269 cl_number - the CL number on the gerrit instance
270
271 When the commit is created, branch_name, change_id, and dir are all
272 set. The gerrit and cl_number keys are not set until the CL has been
273 uploaded to a gerrit instance.
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700274
275 These data might come from the status file (because we read it), or
276 they might be the initial values after we created the file (because
277 it did not already exist).
278
Paul Fagerburg92fcb4b2020-02-19 21:21:43 -0700279 Args:
280 board: Name of the reference board
281 variant: Name of the variant being created
282 bug: Text for bug number, if any ('None' otherwise)
283 continue_flag: Flag if --continue was specified
Paul Fagerburg042a5252020-03-16 21:49:18 -0600284 abort_flag: Flag if --abort was specified
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700285
286 Returns:
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700287 variant_status object with all the data mentioned above
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700288 """
289 status = variant_status.variant_status()
Paul Fagerburg042a5252020-03-16 21:49:18 -0600290 if continue_flag or abort_flag:
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700291 if status.yaml_file_exists():
Paul Fagerburg042a5252020-03-16 21:49:18 -0600292 return status
293 else:
294 if continue_flag:
295 op = '--continue'
296 if abort_flag:
297 op = '--abort'
298 logging.error('%s does not exist; cannot %s', status.yaml_file, op)
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700299 return None
300
Paul Fagerburg042a5252020-03-16 21:49:18 -0600301 # If we get here, the user provided --board and --variant (because
302 # check_flags() returned Trued), but the yaml file already exists,
303 # so we print an error message and bail.
304 if status.yaml_file_exists():
305 logging.error(
306 'new_variant already in progress; did you forget --continue?')
307 return None
Paul Fagerburgdd3e9c32020-01-07 14:00:35 -0700308
Paul Fagerburg042a5252020-03-16 21:49:18 -0600309 # At this point, it's not --continue, not --abort, the yaml file doesn't
310 # exist, and we have valid values for --board, --variant, and --bug (bug
311 # might be the default value of "None"). Create the yaml file with data
312 # from the reference board's loadable module.
313 status.board = board
314 status.variant = variant
315 status.bug = bug
Paul Fagerburgdd3e9c32020-01-07 14:00:35 -0700316
Paul Fagerburg042a5252020-03-16 21:49:18 -0600317 # Load the appropriate module and copy all the data from it.
318 try:
319 module = importlib.import_module(board)
320 except ImportError:
321 print('Unsupported board "' + board + '"')
322 sys.exit(1)
Paul Fagerburgdd3e9c32020-01-07 14:00:35 -0700323
Paul Fagerburg042a5252020-03-16 21:49:18 -0600324 # pylint: disable=bad-whitespace
325 # Allow extra spaces around = so that we can line things up nicely
326 status.base = module.base
327 status.coreboot_dir = module.coreboot_dir
328 status.cb_config_dir = module.cb_config_dir
329 status.emerge_cmd = module.emerge_cmd
330 status.emerge_pkgs = module.emerge_pkgs
331 status.fitimage_dir = module.fitimage_dir
332 status.fitimage_pkg = module.fitimage_pkg
333 status.fitimage_cmd = module.fitimage_cmd
334 status.fsp = module.fsp
335 status.private_yaml_dir = module.private_yaml_dir
336 status.step_list = module.step_list
337 status.workon_pkgs = module.workon_pkgs
338 status.yaml_emerge_pkgs = module.yaml_emerge_pkgs
339 status.coreboot_push_list = module.coreboot_push_list
340 status.repo_upload_list = module.repo_upload_list
341 # pylint: enable=bad-whitespace
Paul Fagerburgdd3e9c32020-01-07 14:00:35 -0700342
Paul Fagerburg042a5252020-03-16 21:49:18 -0600343 # Start at the first entry in the step list
344 status.step = status.step_list[0]
Paul Fagerburg1d043c32020-02-03 08:57:08 -0700345
Paul Fagerburg042a5252020-03-16 21:49:18 -0600346 # Start an empty map for tracking CL data
347 status.commits = {}
348
349 status.save()
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700350
351 return status
352
353
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700354def perform_step(status):
355 """Call the appropriate function for the current step
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700356
Paul Fagerburg92fcb4b2020-02-19 21:21:43 -0700357 Args:
358 status: variant_status object tracking our board, variant, etc.
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700359
360 Returns:
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700361 True if the step succeeded, False if it failed
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700362 """
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700363 # Function to call based on the step
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700364 dispatch = {
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700365 step_names.CB_VARIANT: create_coreboot_variant,
366 step_names.CB_CONFIG: create_coreboot_config,
Paul Fagerburg2fd23f42020-02-07 14:04:48 -0700367 step_names.CRAS_CONFIG: copy_cras_config,
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700368 step_names.ADD_FIT: add_fitimage,
369 step_names.GEN_FIT: gen_fit_image_outside_chroot,
370 step_names.COMMIT_FIT: commit_fitimage,
371 step_names.EC_IMAGE: create_initial_ec_image,
372 step_names.EC_BUILDALL: ec_buildall,
Paul Fagerburg1d043c32020-02-03 08:57:08 -0700373 step_names.ADD_PUB_YAML: add_variant_to_public_yaml,
374 step_names.ADD_PRIV_YAML: add_variant_to_private_yaml,
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700375 step_names.BUILD_YAML: build_yaml,
376 step_names.EMERGE: emerge_all,
377 step_names.PUSH: push_coreboot,
378 step_names.UPLOAD: upload_CLs,
379 step_names.FIND: find_coreboot_upstream,
380 step_names.CQ_DEPEND: add_cq_depends,
381 step_names.CLEAN_UP: clean_up,
Paul Fagerburg042a5252020-03-16 21:49:18 -0600382 step_names.ABORT: abort,
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700383 }
384
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700385 if status.step not in dispatch:
386 logging.error('Unknown step "%s", aborting...', status.step)
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700387 sys.exit(1)
388
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700389 return dispatch[status.step](status)
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700390
391
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700392def move_to_next_step(status):
393 """Move to the next step in the list
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700394
Paul Fagerburg92fcb4b2020-02-19 21:21:43 -0700395 Args:
396 status: variant_status object tracking our board, variant, etc.
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700397 """
Paul Fagerburg042a5252020-03-16 21:49:18 -0600398 # Special case: the next step after 'abort' is 'clean_up'. Always.
399 if status.step == step_names.ABORT:
400 status.step = step_names.CLEAN_UP
401 return
402
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700403 if status.step not in status.step_list:
404 logging.error('Unknown step "%s", aborting...', status.step)
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700405 sys.exit(1)
406
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700407 idx = status.step_list.index(status.step)
408 if idx == len(status.step_list)-1:
409 status.step = None
Paul Fagerburgdd3e9c32020-01-07 14:00:35 -0700410 else:
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700411 status.step = status.step_list[idx+1]
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700412
413
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700414def run_process(args, cwd=None, env=None, capture_output=False):
415 """Run a process, log debug messages, return text output of process
416
417 The capture_output parameter allows us to capture the output when we
418 care about it (and not sending it to the screen), or ignoring it when
419 we don't care, and letting the user see the output so they know that
420 the build is still running, etc.
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700421
Paul Fagerburg92fcb4b2020-02-19 21:21:43 -0700422 Args:
423 args: List of the command and its params
424 cwd: If not None, cd to this directory before running
425 env: Environment to use for execution; if needed, get os.environ.copy()
426 and add variables. If None, just use the current environment
427 capture_output: True if we should capture the stdout, false if we
428 just care about success or not.
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700429
430 Returns:
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700431 If capture_output == True, we return the text output from running
432 the subprocess as a list of lines, or None if the process failed.
433 If capture_output == False, we return a True if it successed, or
434 None if the process failed.
435
436 The caller can evaluate as a bool, because bool(None) == False, and
437 bool() of a non-empty list is True, or the caller can use the returned
438 text for further processing.
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700439 """
440 logging.debug('Run %s', str(args))
Paul Fagerburga8c7e342020-02-25 13:30:49 -0700441 if cwd is not None:
442 logging.debug('cwd = %s', cwd)
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700443 try:
444 if capture_output:
Paul Fagerburga8c7e342020-02-25 13:30:49 -0700445 output = subprocess.run(args, cwd=cwd, env=env, check=True,
446 stderr=subprocess.STDOUT, stdout=subprocess.PIPE).stdout
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700447 else:
448 subprocess.run(args, cwd=cwd, env=env, check=True)
449 # Just something to decode so we don't get an empty list
450 output = b'True'
451
452 logging.debug('process returns 0')
453 # Convert from byte string to ASCII
454 decoded = output.decode('utf-8')
455 # Split into array of individual lines
456 lines = decoded.split('\n')
457 return lines
458 except subprocess.CalledProcessError as err:
459 logging.debug('process returns %s', str(err.returncode))
460 return None
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700461
462
Paul Fagerburg1d043c32020-02-03 08:57:08 -0700463def get_git_commit_data(cwd):
464 """Get the branch name and change id of the current commit
465
Paul Fagerburg92fcb4b2020-02-19 21:21:43 -0700466 Args:
467 cwd: The current working directory, where we want to get the branch
468 name and change id
Paul Fagerburg1d043c32020-02-03 08:57:08 -0700469
470 Returns:
471 Map with 'dir', 'branch_name' and 'change_id' keys. The 'dir'
472 key maps to the value of os.path.expanduser(cwd)
473 """
Paul Fagerburga8c7e342020-02-25 13:30:49 -0700474 cwd = git.FindGitTopLevel(os.path.expanduser(cwd))
Paul Fagerburg1d043c32020-02-03 08:57:08 -0700475 logging.debug('get_git_commit_data(%s)', cwd)
476
477 branch_name = git.GetCurrentBranch(cwd)
478 if branch_name is None:
479 logging.error('Cannot determine git branch name in %s; exiting', cwd)
480 sys.exit(1)
481 logging.debug('git current branch is %s', branch_name)
482
483 change_id = git.GetChangeId(cwd)
484 if change_id is None:
485 logging.error('Cannot determine Change-Id in %s; exiting', cwd)
486 sys.exit(1)
487 logging.debug('git Change-Id is %s', change_id)
488
489 return {
490 'dir': cwd,
491 'branch_name': branch_name,
492 'change_id': change_id
493 }
494
495
Paul Fagerburg75398072020-03-16 13:51:24 -0600496def cros_workon(status, action, workon_pkgs):
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700497 """Call cros_workon for all the 9999 ebuilds we'll be touching
498
Paul Fagerburg92fcb4b2020-02-19 21:21:43 -0700499 Args:
500 status: variant_status object tracking our board, variant, etc.
501 action: 'start' or 'stop'
Paul Fagerburg75398072020-03-16 13:51:24 -0600502 workon_pkgs: list of packages to start or stop
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700503
504 Returns:
505 True if the call to cros_workon was successful, False if failed
506 """
507
508 # Build up the command from all the packages in the list
Paul Fagerburg75398072020-03-16 13:51:24 -0600509 workon_cmd = ['cros_workon', '--board=' + status.base, action] + workon_pkgs
Paul Fagerburg042a5252020-03-16 21:49:18 -0600510 return run_process(workon_cmd)
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700511
512
513def create_coreboot_variant(status):
Paul Fagerburge868e832020-01-22 17:14:04 -0700514 """Create source files for a new variant of the reference board in coreboot
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700515
516 This function calls create_coreboot_variant.sh to set up a new variant
Paul Fagerburge868e832020-01-22 17:14:04 -0700517 of the reference board.
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700518
Paul Fagerburg92fcb4b2020-02-19 21:21:43 -0700519 Args:
520 status: variant_status object tracking our board, variant, etc.
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700521
522 Returns:
523 True if everything succeeded, False if something failed
524 """
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700525 logging.info('Running step create_coreboot_variant')
Paul Fagerburg5f794bf2020-02-12 13:01:36 -0700526 cb_src_dir = os.path.join('/mnt/host/source/src/', status.coreboot_dir)
527 environ = os.environ.copy()
528 environ['CB_SRC_DIR'] = cb_src_dir
529 create_coreboot_variant_sh = os.path.join(status.my_loc,
530 'create_coreboot_variant.sh')
Paul Fagerburg042a5252020-03-16 21:49:18 -0600531 rc = run_process(
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700532 [create_coreboot_variant_sh,
Paul Fagerburge868e832020-01-22 17:14:04 -0700533 status.base,
Paul Fagerburgabb15622020-02-07 15:41:29 -0700534 status.board,
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700535 status.variant,
Paul Fagerburg042a5252020-03-16 21:49:18 -0600536 status.bug], env=environ)
Paul Fagerburg1d043c32020-02-03 08:57:08 -0700537 if rc:
Paul Fagerburga8c7e342020-02-25 13:30:49 -0700538 status.commits[step_names.CB_VARIANT] = get_git_commit_data(cb_src_dir)
Paul Fagerburg1d043c32020-02-03 08:57:08 -0700539 return rc
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700540
541
542def create_coreboot_config(status):
543 """Create a coreboot configuration for a new variant
544
545 This function calls create_coreboot_config.sh, which will make a copy
546 of coreboot.${BOARD} into coreboot.${VARIANT}.
547
Paul Fagerburg92fcb4b2020-02-19 21:21:43 -0700548 Args:
549 status: variant_status object tracking our board, variant, etc.
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700550
551 Returns:
552 True if the script and test build succeeded, False if something failed
553 """
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700554 logging.info('Running step create_coreboot_config')
Paul Fagerburg4d343452020-01-24 15:23:53 -0700555 environ = os.environ.copy()
556 if status.cb_config_dir is not None:
557 environ['CB_CONFIG_DIR'] = status.cb_config_dir
Paul Fagerburg5f794bf2020-02-12 13:01:36 -0700558 create_coreboot_config_sh = os.path.join(status.my_loc,
559 'create_coreboot_config.sh')
Paul Fagerburg042a5252020-03-16 21:49:18 -0600560 rc = run_process(
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700561 [create_coreboot_config_sh,
Paul Fagerburge868e832020-01-22 17:14:04 -0700562 status.base,
563 status.board,
564 status.variant,
Paul Fagerburg042a5252020-03-16 21:49:18 -0600565 status.bug], env=environ)
Paul Fagerburg1d043c32020-02-03 08:57:08 -0700566 if rc:
567 # Use status.cb_config_dir if defined, or if not, use
Paul Fagerburg5f794bf2020-02-12 13:01:36 -0700568 # '/mnt/host/source/src/third_party/chromiumos-overlay'
Paul Fagerburg1d043c32020-02-03 08:57:08 -0700569 if status.cb_config_dir is not None:
Paul Fagerburg5f794bf2020-02-12 13:01:36 -0700570 cb_config_dir = os.path.join('/mnt/host/source/src/', status.cb_config_dir)
Paul Fagerburg1d043c32020-02-03 08:57:08 -0700571 else:
Paul Fagerburg5f794bf2020-02-12 13:01:36 -0700572 cb_config_dir = '/mnt/host/source/src/third_party/chromiumos-overlay'
Paul Fagerburga8c7e342020-02-25 13:30:49 -0700573 status.commits[step_names.CB_CONFIG] = get_git_commit_data(cb_config_dir)
Paul Fagerburg1d043c32020-02-03 08:57:08 -0700574 return rc
Paul Fagerburge868e832020-01-22 17:14:04 -0700575
576
Paul Fagerburg2fd23f42020-02-07 14:04:48 -0700577def copy_cras_config(status):
578 """Copy the cras config for a new variant
579
580 This is only necessary for the Zork baseboard right now.
581 This function calls copy_cras_config.sh, which will copy the
582 cras config in
583 overlays/overlay-${BASE}/chromeos-base/chromeos-bsp-${BASE}/files/cras-config/${BASE}
584 to .../${VARIANT}
585
Paul Fagerburg92fcb4b2020-02-19 21:21:43 -0700586 Args:
587 status: variant_status object tracking our board, variant, etc.
Paul Fagerburg2fd23f42020-02-07 14:04:48 -0700588
589 Returns:
590 True if the script and test build succeeded, False if something failed
591 """
592 logging.info('Running step copy_cras_config')
Paul Fagerburg5f794bf2020-02-12 13:01:36 -0700593 copy_cras_config_sh = os.path.join(status.my_loc, 'copy_cras_config.sh')
Paul Fagerburg042a5252020-03-16 21:49:18 -0600594 rc = run_process(
Paul Fagerburg2fd23f42020-02-07 14:04:48 -0700595 [copy_cras_config_sh,
596 status.base,
597 status.board,
598 status.variant,
Paul Fagerburg042a5252020-03-16 21:49:18 -0600599 status.bug])
Paul Fagerburg1d043c32020-02-03 08:57:08 -0700600 if rc:
Paul Fagerburga8c7e342020-02-25 13:30:49 -0700601 status.commits[step_names.CRAS_CONFIG] = get_git_commit_data(
Paul Fagerburg5f794bf2020-02-12 13:01:36 -0700602 '/mnt/host/source/src/overlays')
Paul Fagerburg1d043c32020-02-03 08:57:08 -0700603 return rc
Paul Fagerburg2fd23f42020-02-07 14:04:48 -0700604
605
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700606def add_fitimage(status):
607 """Add the source files for a fitimage for the new variant
608
609 This function calls add_fitimage.sh to create a new XSL file for the
Paul Fagerburge868e832020-01-22 17:14:04 -0700610 variant's fitimage, which can override settings from the reference board's
611 XSL. When this is done, the user will have to build the fitimage by running
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700612 gen_fit_image.sh outside of the chroot (and outside of this program's
613 control) because gen_fit_image.sh uses WINE, which is not installed in
614 the chroot. (There is a linux version of FIT, but it requires Open GL,
615 which is also not installed in the chroot.)
616
Paul Fagerburg92fcb4b2020-02-19 21:21:43 -0700617 Args:
618 status: variant_status object tracking our board, variant, etc.
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700619
620 Returns:
621 True if the script succeeded, False otherwise
622 """
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700623 logging.info('Running step add_fitimage')
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700624 add_fitimage_sh = os.path.expanduser(os.path.join(
Paul Fagerburg5f794bf2020-02-12 13:01:36 -0700625 '/mnt/host/source/src', status.fitimage_dir, 'files/add_fitimage.sh'))
Paul Fagerburg042a5252020-03-16 21:49:18 -0600626 rc = run_process(
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700627 [add_fitimage_sh,
628 status.variant,
Paul Fagerburg042a5252020-03-16 21:49:18 -0600629 status.bug])
Paul Fagerburg1d043c32020-02-03 08:57:08 -0700630 if rc:
Paul Fagerburg5f794bf2020-02-12 13:01:36 -0700631 fitimage_dir = os.path.join('/mnt/host/source/src', status.fitimage_dir)
Paul Fagerburga8c7e342020-02-25 13:30:49 -0700632 status.commits[step_names.COMMIT_FIT] = get_git_commit_data(fitimage_dir)
Paul Fagerburg1d043c32020-02-03 08:57:08 -0700633 return rc
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700634
635
636def gen_fit_image_outside_chroot(status):
637 """Tell the user to run gen_fit_image.sh outside the chroot
638
639 As noted for add_Fitimage(), gen_fit_image.sh cannot run inside the
640 chroot. This function tells the user to run gen_fit_image.sh in
641 their normal environment, and then come back (--continue) when that
642 is done.
643
Paul Fagerburg92fcb4b2020-02-19 21:21:43 -0700644 Args:
645 status: variant_status object tracking our board, variant, etc.
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700646
647 Returns:
648 True
649 """
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700650 logging.info('Running step gen_fit_image_outside_chroot')
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700651 fit_image_files = check_fit_image_files(status)
652 # If the list is empty, then `not` of the list is True, so the files
653 # we need are all present and we can continue.
654 if not fit_image_files:
655 return True
656
Paul Fagerburgaec8d992020-02-27 15:51:47 -0700657 logging.error('The following files need to be generated:')
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700658 for filename in fit_image_files:
Paul Fagerburgaec8d992020-02-27 15:51:47 -0700659 logging.error('* %s', filename)
660 logging.error('The fitimage sources are ready for gen_fit_image.sh to process.')
661 logging.error('gen_fit_image.sh cannot run inside the chroot. Please open a new terminal')
662 logging.error('window, change to the directory where gen_fit_image.sh is located, and run')
663 logging.error(status.fitimage_cmd, status.variant)
664 logging.error('Then re-start this program with --continue.')
665 logging.error('If your chroot is based in ~/chromiumos, then the folder you want is')
666 logging.error('~/chromiumos/src/%s/asset_generation', status.fitimage_dir)
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700667 return False
668
669
670def check_fit_image_files(status):
671 """Check if the fitimage has been generated
672
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700673 This function is not called directly as a step, and so it doesn't need
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700674 to produce any error messages to the user (except with --verbose).
675 gen_fit_image_outside_chroot will call this function to see if the
676 fitimage files exist, and if not, then that function will print the
677 message about how the user needs to run gen_fit_image.sh outside the
678 chroot.
679
Paul Fagerburg92fcb4b2020-02-19 21:21:43 -0700680 Args:
681 status: variant_status object tracking our board, variant, etc.
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700682
683 Returns:
684 List of files that *DO NOT* exist and need to be created, [] if
685 all files are present.
686 """
Paul Fagerburg5f794bf2020-02-12 13:01:36 -0700687 outputs_dir = os.path.join('/mnt/host/source/src', status.fitimage_dir,
688 'asset_generation/outputs')
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700689 logging.debug('outputs_dir = "%s"', outputs_dir)
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700690
Paul Fagerburg8021dab2020-03-25 21:23:33 -0600691 files_not_found = []
692 fitimage_bin = 'fitimage-' + status.variant + '.bin'
693 if not os.path.isfile(os.path.join(outputs_dir, fitimage_bin)):
694 files_not_found.append(fitimage_bin)
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700695
Paul Fagerburg8021dab2020-03-25 21:23:33 -0600696 fitimage_versions = 'fitimage-' + status.variant + '-versions.txt'
697 if not os.path.isfile(os.path.join(outputs_dir, fitimage_versions)):
698 files_not_found.append(fitimage_versions)
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700699
Paul Fagerburg8021dab2020-03-25 21:23:33 -0600700 fit_log = 'fit.log'
701 if not os.path.isfile(os.path.join(outputs_dir, fit_log)):
702 files_not_found.append(fit_log)
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700703
Paul Fagerburg8021dab2020-03-25 21:23:33 -0600704 return files_not_found
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700705
706
707def move_fitimage_file(fitimage_dir, filename):
708 """Move fitimage files from create-place to commit-place
709
710 commit_fitimage needs to move the fitimage files from the place where
711 they were created to a different directory in the tree. This utility
712 function handles joining paths and calling a file move function.
713
Paul Fagerburg92fcb4b2020-02-19 21:21:43 -0700714 Args:
715 fitimage_dir: Directory where the fitimage files are
716 filename: Name of the file being moved
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700717
718 Returns:
719 True if the move succeeded, False if it failed
720 """
721 src_dir = os.path.join(fitimage_dir, 'asset_generation/outputs')
722 src = os.path.join(src_dir, filename)
723 dest_dir = os.path.join(fitimage_dir, 'files')
724 dest = os.path.join(dest_dir, filename)
725 # If src does not exist and dest does, the move is already done => success!
Paul Fagerburg8021dab2020-03-25 21:23:33 -0600726 if not os.path.isfile(src) and os.path.isfile(dest):
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700727 logging.debug('move "%s", "%s" unnecessary because dest exists and'
728 ' src does not exist', src, dest)
729 return True
730
731 logging.debug('move "%s", "%s"', src, dest)
732 return shutil.move(src, dest)
733
734
735def commit_fitimage(status):
736 """Move the fitimage files and add them to a git commit
737
738 This function moves the fitimage binary and -versions files from
739 asset_generation/outputs to files/ and then adds those files and
740 fit.log to the existing git commit.
741
Paul Fagerburg92fcb4b2020-02-19 21:21:43 -0700742 Args:
743 status: variant_status object tracking our board, variant, etc.
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700744
745 Returns:
746 True if the copy, git add, and git commit --amend all succeeded.
747 False if something failed.
748 """
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700749 logging.info('Running step commit_fitimage')
Paul Fagerburg5f794bf2020-02-12 13:01:36 -0700750 fitimage_dir = os.path.join('/mnt/host/source/src', status.fitimage_dir)
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700751 logging.debug('fitimage_dir = "%s"', fitimage_dir)
752
753 # The copy operation will check that the source file exists, so no
754 # need to check separately.
755 if not move_fitimage_file(fitimage_dir,
756 'fitimage-' + status.variant + '.bin'):
757 logging.error('Moving fitimage binary failed')
758 return False
759
760 if not move_fitimage_file(fitimage_dir,
761 'fitimage-' + status.variant + '-versions.txt'):
762 logging.error('Moving fitimage versions.txt failed')
763 return False
764
Paul Fagerburg1d043c32020-02-03 08:57:08 -0700765 # TODO(pfagerburg) volteer also needs files/blobs/descriptor-${VARIANT}.bin
Paul Fagerburg042a5252020-03-16 21:49:18 -0600766 if not run_process(
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700767 ['git', 'add',
768 'asset_generation/outputs/fit.log',
769 'files/fitimage-' + status.variant + '.bin',
770 'files/fitimage-' + status.variant + '-versions.txt'
771 ],
Paul Fagerburg042a5252020-03-16 21:49:18 -0600772 cwd=fitimage_dir):
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700773 return False
774
Paul Fagerburg042a5252020-03-16 21:49:18 -0600775 return run_process(['git', 'commit', '--amend', '--no-edit'],
776 cwd=fitimage_dir)
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700777
778
779def create_initial_ec_image(status):
Paul Fagerburge868e832020-01-22 17:14:04 -0700780 """Create an EC image for the variant as a clone of the reference board
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700781
782 This function calls create_initial_ec_image.sh, which will clone the
Paul Fagerburge868e832020-01-22 17:14:04 -0700783 reference board to create the variant. The shell script will build the
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700784 EC code for the variant, but the repo upload hook insists that we
785 have done a `make buildall` before it will allow an upload, so this
786 function does the buildall.
787
Paul Fagerburg92fcb4b2020-02-19 21:21:43 -0700788 Args:
789 status: variant_status object tracking our board, variant, etc.
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700790
791 Returns:
792 True if the script and test build succeeded, False if something failed
793 """
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700794 logging.info('Running step create_initial_ec_image')
Paul Fagerburg5f794bf2020-02-12 13:01:36 -0700795 create_initial_ec_image_sh = os.path.join(status.my_loc,
796 'create_initial_ec_image.sh')
Paul Fagerburg042a5252020-03-16 21:49:18 -0600797 if not run_process(
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700798 [create_initial_ec_image_sh,
799 status.board,
800 status.variant,
Paul Fagerburg042a5252020-03-16 21:49:18 -0600801 status.bug]):
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700802 return False
803
Paul Fagerburg1d043c32020-02-03 08:57:08 -0700804 # No need to `if rc:` because we already tested the run_process result above
Paul Fagerburga8c7e342020-02-25 13:30:49 -0700805 status.commits[step_names.EC_IMAGE] = get_git_commit_data(
Paul Fagerburg5f794bf2020-02-12 13:01:36 -0700806 '/mnt/host/source/src/platform/ec/board')
Paul Fagerburg1d043c32020-02-03 08:57:08 -0700807
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700808 # create_initial_ec_image.sh will build the ec.bin for this variant
809 # if successful.
Paul Fagerburg8021dab2020-03-25 21:23:33 -0600810 ec_dir = '/mnt/host/source/src/platform/ec'
811 ec_bin = os.path.join(ec_dir, 'build', status.variant, 'ec.bin')
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700812 logging.debug('ec.bin = "%s"', ec_bin)
813
Paul Fagerburg8021dab2020-03-25 21:23:33 -0600814 if not os.path.isfile(ec_bin):
Paul Fagerburga8c7e342020-02-25 13:30:49 -0700815 logging.error('EC binary %s not found', ec_bin)
816 return False
817 return True
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700818
819
820def ec_buildall(status):
821 """Do a make buildall -j for the EC, which is required for repo upload
822
823 The upload hook checks to ensure that the entire EC codebase builds
824 without error, so we have to run make buildall -j before uploading.
825
Paul Fagerburg92fcb4b2020-02-19 21:21:43 -0700826 Args:
827 status: variant_status object tracking our board, variant, etc.
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700828
829 Returns:
830 True if the script and test build succeeded, False if something failed
831 """
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700832 logging.info('Running step ec_buildall')
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700833 del status # unused parameter
Paul Fagerburg5f794bf2020-02-12 13:01:36 -0700834 ec = '/mnt/host/source/src/platform/ec'
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700835 logging.debug('ec = "%s"', ec)
Paul Fagerburg042a5252020-03-16 21:49:18 -0600836 return run_process(['make', 'buildall', '-j'], cwd=ec)
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700837
838
Paul Fagerburg1d043c32020-02-03 08:57:08 -0700839def add_variant_to_public_yaml(status):
840 """Add the new variant to the public model.yaml file
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700841
Paul Fagerburg1d043c32020-02-03 08:57:08 -0700842 This function calls add_variant_to_yaml.sh to add the new variant to
843 the public model.yaml file.
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700844
Paul Fagerburg92fcb4b2020-02-19 21:21:43 -0700845 Args:
846 status: variant_status object tracking our board, variant, etc.
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700847
848 Returns:
Paul Fagerburg1d043c32020-02-03 08:57:08 -0700849 True if the script succeeded, False is something failed
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700850 """
Paul Fagerburg1d043c32020-02-03 08:57:08 -0700851 logging.info('Running step add_variant_to_public_yaml')
Paul Fagerburg5f794bf2020-02-12 13:01:36 -0700852 add_variant_to_yaml_sh = os.path.join(status.my_loc,
853 'add_variant_to_yaml.sh')
Paul Fagerburg042a5252020-03-16 21:49:18 -0600854 rc = run_process(
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700855 [add_variant_to_yaml_sh,
Paul Fagerburge868e832020-01-22 17:14:04 -0700856 status.base,
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700857 status.variant,
Paul Fagerburg042a5252020-03-16 21:49:18 -0600858 status.bug])
Paul Fagerburg1d043c32020-02-03 08:57:08 -0700859 if rc:
Paul Fagerburga8c7e342020-02-25 13:30:49 -0700860 status.commits[step_names.ADD_PUB_YAML] = get_git_commit_data(
Paul Fagerburg5f794bf2020-02-12 13:01:36 -0700861 '/mnt/host/source/src/overlays')
Paul Fagerburg1d043c32020-02-03 08:57:08 -0700862 return rc
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700863
Paul Fagerburg1d043c32020-02-03 08:57:08 -0700864
865def add_variant_to_private_yaml(status):
866 """Add the new variant to the private model.yaml file
867
868 This function calls add_variant.sh to add the new variant to
869 the private model.yaml file.
870
Paul Fagerburg92fcb4b2020-02-19 21:21:43 -0700871 Args:
872 status: variant_status object tracking our board, variant, etc.
Paul Fagerburg1d043c32020-02-03 08:57:08 -0700873
874 Returns:
875 True if the script succeeded, False is something failed
876 """
877 logging.info('Running step add_variant_to_private_yaml')
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700878 add_variant_sh = os.path.expanduser(os.path.join(status.private_yaml_dir, 'add_variant.sh'))
Paul Fagerburg042a5252020-03-16 21:49:18 -0600879 rc = run_process(
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700880 [add_variant_sh,
881 status.variant,
Paul Fagerburg042a5252020-03-16 21:49:18 -0600882 status.bug])
Paul Fagerburg1d043c32020-02-03 08:57:08 -0700883 if rc:
Paul Fagerburga8c7e342020-02-25 13:30:49 -0700884 status.commits[step_names.ADD_PRIV_YAML] = get_git_commit_data(status.private_yaml_dir)
Paul Fagerburg1d043c32020-02-03 08:57:08 -0700885 return rc
886
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700887
888
889def build_yaml(status):
890 """Build config files from the yaml files
891
892 This function builds the yaml files into the JSON and C code that
893 mosys and other tools use, then verifies that the new variant's name
894 shows up in all of the output files.
895
Paul Fagerburg92fcb4b2020-02-19 21:21:43 -0700896 Args:
897 status: variant_status object tracking our board, variant, etc.
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700898
899 Returns:
900 True if the scripts and build succeeded, False is something failed
901 """
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700902 logging.info('Running step build_yaml')
Paul Fagerburg042a5252020-03-16 21:49:18 -0600903 if not run_process([status.emerge_cmd] + status.yaml_emerge_pkgs):
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700904 return False
905
Paul Fagerburga95dd162020-03-24 16:27:18 -0600906 # Check the generated config.yaml file for occurences of the variant
907 # name to determine if the emerge was successful.
908 config_yaml = os.path.join(
909 '/build', status.base, 'usr/share/chromeos-config/yaml/config.yaml')
910 logging.debug('config_yaml = "%s"', config_yaml)
Paul Fagerburg8021dab2020-03-25 21:23:33 -0600911 if not os.path.isfile(config_yaml):
Paul Fagerburga95dd162020-03-24 16:27:18 -0600912 logging.error('%s does not exist', config_yaml)
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700913 return False
914
Paul Fagerburga95dd162020-03-24 16:27:18 -0600915 if not status.variant in osutils.ReadFile(config_yaml):
916 logging.error('variant name %s not found in yaml file %s',
917 status.variant, config_yaml)
918 return False
919
920 return True
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700921
922
923def emerge_all(status):
924 """Build the coreboot BIOS and EC code for the new variant
925
Paul Fagerburg75398072020-03-16 13:51:24 -0600926 This build step will cros_workon start a list of packages provided by
927 the reference board data as status.workon_pkgs, then emerge a list of
928 packages (status.emerge_pkgs), and then cros_workon stop any packages
929 that it started, as opposed to ones that were already being worked on.
930
931 To determine which packages this program started and which ones were
932 already started, we query the list of packages being worked on, then
933 cros_workon start the entire list (which will produce a "package already
934 being worked on" type of message for anything already started), and then
935 query the list of packages being worked on again. The difference between
936 the before and after lists are the packages that this program started,
937 and so that's the list of packages to cros_workon stop after the emerge
938 is done.
939
Paul Fagerburg92fcb4b2020-02-19 21:21:43 -0700940 Args:
941 status: variant_status object tracking our board, variant, etc.
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700942
943 Returns:
944 True if the build succeeded, False if something failed
945 """
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700946 logging.info('Running step emerge_all')
Paul Fagerburg75398072020-03-16 13:51:24 -0600947 # Get the list of packages that are already cros_workon started.
948 build_target = BuildTarget(status.base)
949 workon = workon_helper.WorkonHelper(build_target.root, build_target.name)
950 before_workon = workon.ListAtoms()
951
952 # Start working on the list of packages specified by the reference board.
953 cros_workon(status, 'start', status.workon_pkgs)
954
955 # Get the list of packages that are cros_workon started now.
956 after_workon = workon.ListAtoms()
957 # Determine which packages we need to cros_workon stop.
958 stop_packages = list(set(after_workon) - set(before_workon))
959
960 # Build up the command for emerge from all the packages in the list.
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700961 environ = os.environ.copy()
962 environ['FW_NAME'] = status.variant
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700963 emerge_cmd_and_params = [status.emerge_cmd] + status.emerge_pkgs
Paul Fagerburg042a5252020-03-16 21:49:18 -0600964 emerge_result = run_process(emerge_cmd_and_params, env=environ)
Paul Fagerburg75398072020-03-16 13:51:24 -0600965
966 # cros_workon stop before possibly returning an error code.
967 cros_workon(status, 'stop', stop_packages)
968
969 # Check if emerge failed, and then check if the expected build outputs
970 # exist.
971 if not emerge_result:
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700972 return False
973
Paul Fagerburge868e832020-01-22 17:14:04 -0700974 build_path = '/build/' + status.base + '/firmware'
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700975 logging.debug('build_path = "%s"', build_path)
Paul Fagerburg8021dab2020-03-25 21:23:33 -0600976 image_bin = 'image-' + status.variant + '.bin'
977 if not os.path.isfile(os.path.join(build_path, image_bin)):
978 logging.error('emerge failed because %s does not exist', image_bin)
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700979 return False
980
Paul Fagerburg8021dab2020-03-25 21:23:33 -0600981 serial_bin = 'image-' + status.variant + '.serial.bin'
982 if not os.path.isfile(os.path.join(build_path, serial_bin)):
983 logging.error('emerge failed because %s does not exist', serial_bin)
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700984 return False
985
986 return True
987
988
989def push_coreboot(status):
990 """Push the coreboot CL to coreboot.org
991
Paul Fagerburg92fcb4b2020-02-19 21:21:43 -0700992 Args:
993 status: variant_status object tracking our board, variant, etc.
Paul Fagerburg3b534f92019-11-07 15:05:22 -0700994
995 Returns:
996 True if the build succeeded, False if something failed
997 """
Paul Fagerburgbab5dde2020-01-10 15:10:29 -0700998 logging.info('Running step push_coreboot')
Paul Fagerburg8d850932020-02-25 14:13:32 -0700999
1000 # Set up a return code that may change to False if we find that a
1001 # coreboot CL has not been uploaded.
1002 rc = True
1003
1004 for commit_key in status.coreboot_push_list:
1005 logging.debug(f'Processing key {commit_key}')
1006 commit = status.commits[commit_key]
1007 if 'gerrit' not in commit or 'cl_number' not in commit:
1008 change_id = commit['change_id']
1009 cl = find_change_id(change_id)
1010 if cl is not None:
1011 save_cl_data(status, commit_key, cl)
1012 else:
1013 logging.debug(f'Not found {change_id}, need to upload')
Paul Fagerburgaec8d992020-02-27 15:51:47 -07001014 logging.error('The following commit needs to be pushed to coreboot.org:')
1015 logging.error(' Branch "%s"', commit['branch_name'])
1016 logging.error(' in directory "%s"', commit['dir'])
1017 logging.error(' with change-id "%s"', commit['change_id'])
1018 logging.error('Please push the branch to review.coreboot.org, '
1019 'and then re-start this program with --continue')
Paul Fagerburg8d850932020-02-25 14:13:32 -07001020 # Since this commit needs to be uploaded, do not continue after
1021 # this step returns.
1022 rc = False
1023 else:
1024 instance_name = commit['gerrit']
1025 cl_number = commit['cl_number']
1026 logging.debug(f'Already uploaded ({instance_name}, {cl_number})')
1027
1028 return rc
Paul Fagerburg3b534f92019-11-07 15:05:22 -07001029
1030
Paul Fagerburga8c7e342020-02-25 13:30:49 -07001031def query_gerrit(instance, change_id):
1032 """Search a gerrit instance for a specific change_id
1033
1034 Args:
1035 instance: gerrit instance to query. Suitable values come from
1036 gerrit.GetCrosInternal() and gerrit.GetCrosExternal()
1037 change_id: The change_id to search for
1038
1039 Returns:
1040 CL number if found, None if not
1041 """
1042 raw = instance.Query(change=change_id, raw=True)
1043 if raw:
1044 # If the CL was found by change_id, there will be only one,
1045 # because the change_id is used to recognize a new patchset
1046 # on an existing CL.
1047 return raw[0]['number']
1048
1049 return None
1050
1051
Paul Fagerburg8d850932020-02-25 14:13:32 -07001052def query_coreboot_gerrit(change_id):
1053 """Search the coreboot gerrit for a specific change_id
1054
1055 Use the REST API to look for the change_id. See
1056 https://gerrit-review.googlesource.com/Documentation/rest-api-changes.html
1057 for details on the REST API to search for a change-id.
1058
1059 We can't use query_gerrit with a manually constructed GerritHelper
1060 because we need the user's private SSH key to access review.coreboot.org,
1061 but these are not available inside the chroot.
1062
1063 Args:
1064 change_id: The change_id to search for
1065
1066 Returns:
1067 CL number if found, None if not
1068 """
1069 r = requests.get('https://review.coreboot.org/changes/' + change_id)
1070 response = r.content.decode('utf-8')
1071 # Check if the response starts with 'Not found', in which case return None
1072 if response.startswith('Not found:'):
1073 return None
1074 # Strip off the initial )]}'\n that is used as XSS protections, see
1075 # https://gerrit-review.googlesource.com/Documentation/rest-api.html#output
1076 # and decode as JSON.
1077 data = json.loads(response[5:])
1078 if '_number' in data:
Paul Fagerburgaec8d992020-02-27 15:51:47 -07001079 return str(data['_number'])
Paul Fagerburg8d850932020-02-25 14:13:32 -07001080 return None
1081
1082
Paul Fagerburga8c7e342020-02-25 13:30:49 -07001083def find_change_id(change_id):
1084 """Search the public and private ChromeOS gerrit instances for a change-id
1085
1086 Args:
1087 change_id: Change-Id to search for in both gerrit instances
1088
1089 Returns:
1090 Tuple of the gerrit instance ('chromium' or 'chrome-internal') and
1091 the CL number if the Change-Id is found.
1092 None if not found.
1093 """
1094 cl_number = query_gerrit(gerrit.GetCrosExternal(), change_id)
1095 if cl_number:
1096 return 'chromium', cl_number
1097 cl_number = query_gerrit(gerrit.GetCrosInternal(), change_id)
1098 if cl_number:
1099 return 'chrome-internal', cl_number
Paul Fagerburg8d850932020-02-25 14:13:32 -07001100 cl_number = query_coreboot_gerrit(change_id)
1101 if cl_number:
1102 return 'coreboot', cl_number
Paul Fagerburga8c7e342020-02-25 13:30:49 -07001103 return None
1104
1105
1106def save_cl_data(status, commit_key, cl):
1107 """Save the gerrit instance and CL number to the yaml file
1108
1109 Args:
1110 status: variant_status object tracking our board, variant, etc.
1111 commit_key: Which key in the commits map we're processing
1112 cl: Value returned by find_change_id, should be a tuple
1113 of instance_name, cl_number
1114 """
1115 instance_name, cl_number = cl
1116 print(f'Found ({instance_name}, {cl_number}), saving to yaml')
1117 status.commits[commit_key]['gerrit'] = instance_name
1118 status.commits[commit_key]['cl_number'] = cl_number
1119 status.save()
1120
1121
1122def repo_upload(branch_name, cwd):
1123 """Upload a branch to gerrit
1124
1125 This function runs `repo upload` in the specified directory to upload
1126 a branch to gerrit. Because it's operating in a directory and with a
1127 branch name, it could upload more than one commit, which is OK because
1128 we'll look for each commit by change-id before trying to upload in that
1129 directory. For example, this happens in Zork, where the cb_config step
1130 and the cras_config step both have a commit in src/overlays. When we're
1131 processing the cb_config step and we `repo upload` in src/overlays, it
1132 will also upload the commit for cras_config. Then we come around to the
1133 cras_config step, and since we can find a CL with the change-id, we don't
1134 try to upload again.
1135
1136 Args:
1137 branch_name: the name of the branch to upload. Gets passed to
1138 repo upload with the --br flag
1139 cwd: directory where we want to upload. Gets set as the working
1140 directory for executing repo upload.
1141
1142 Returns:
1143 True if repo upload exits with a successful error code, false otherwise
1144 """
Paul Fagerburg042a5252020-03-16 21:49:18 -06001145 return run_process(
Paul Fagerburga8c7e342020-02-25 13:30:49 -07001146 ['repo',
1147 'upload',
1148 '.',
1149 '--br=' + branch_name,
1150 '--wip',
1151 '--verify',
1152 '--yes'],
Paul Fagerburg042a5252020-03-16 21:49:18 -06001153 cwd=cwd)
Paul Fagerburga8c7e342020-02-25 13:30:49 -07001154
1155
Paul Fagerburg3b534f92019-11-07 15:05:22 -07001156def upload_CLs(status):
1157 """Upload all CLs to chromiumos
1158
Paul Fagerburg92fcb4b2020-02-19 21:21:43 -07001159 Args:
1160 status: variant_status object tracking our board, variant, etc.
Paul Fagerburg3b534f92019-11-07 15:05:22 -07001161
1162 Returns:
1163 True if the build succeeded, False if something failed
1164 """
Paul Fagerburgbab5dde2020-01-10 15:10:29 -07001165 logging.info('Running step upload_CLs')
Paul Fagerburga8c7e342020-02-25 13:30:49 -07001166
1167 for commit_key in status.repo_upload_list:
1168 logging.debug(f'Processing key {commit_key}')
1169 commit = status.commits[commit_key]
1170 if 'gerrit' not in commit or 'cl_number' not in commit:
1171 change_id = commit['change_id']
1172 cl = find_change_id(change_id)
1173 if cl is not None:
1174 save_cl_data(status, commit_key, cl)
1175 else:
1176 logging.debug(f'Not found {change_id}, need to upload')
1177 if not repo_upload(commit['branch_name'], commit['dir']):
1178 branch_name = commit['branch_name']
1179 dirname = commit['dir']
1180 logging.error(f'Repo upload {branch_name} in {dirname} failed!')
1181 return False
1182 cl = find_change_id(change_id)
1183 if cl is None:
1184 logging.error(f'repo upload {commit_key} succeeded, ' \
1185 'but change_id is not found!')
1186 return False
1187 save_cl_data(status, commit_key, cl)
1188 else:
1189 instance_name = commit['gerrit']
1190 cl_number = commit['cl_number']
1191 logging.debug(f'Already uploaded ({instance_name}, {cl_number})')
1192
Paul Fagerburg3b534f92019-11-07 15:05:22 -07001193 return True
1194
1195
1196def find_coreboot_upstream(status):
1197 """Find the coreboot CL after it has been upstreamed to chromiumos
1198
Paul Fagerburgaec8d992020-02-27 15:51:47 -07001199 When the coreboot variant CL is first uploaded to review.coreboot.org,
1200 it is not visible in the chromiumos tree (and also cannot be used as
1201 a target for cq-depend). There is a process for upstreaming CLs from
1202 coreboot after they have been reviewed, approved, and merged. We can
1203 track a specific coreboot CL if we know the change-id that it used on
1204 the coreboot gerrit instance, by looking for that change-id as
1205 'original-change-id' in the public chromium gerrit instance.
1206
1207 The change-id for the coreboot variant will be under the 'cb_variant' key,
1208 but this is for the 'coreboot' gerrit instance.
1209
1210 When we find the upstreamed CL, we will record the gerrit instance and
1211 CL number in the yaml file under the 'find' key ("find upstream coreboot")
1212 so that we don't need to search coreboot again.
1213
Paul Fagerburg92fcb4b2020-02-19 21:21:43 -07001214 Args:
1215 status: variant_status object tracking our board, variant, etc.
Paul Fagerburg3b534f92019-11-07 15:05:22 -07001216
1217 Returns:
1218 True if the build succeeded, False if something failed
1219 """
Paul Fagerburgbab5dde2020-01-10 15:10:29 -07001220 logging.info('Running step find_coreboot_upstream')
Paul Fagerburgaec8d992020-02-27 15:51:47 -07001221
1222 # If we have already found the upstream coreboot CL, then exit with success
1223 if step_names.FIND in status.commits:
1224 commit = status.commits[step_names.FIND]
1225 if 'gerrit' in commit and 'cl_number' in commit:
1226 instance_name = commit['gerrit']
1227 cl_number = commit['cl_number']
1228 logging.debug(f'Already found ({instance_name}, {cl_number})')
1229 return True
1230
1231 # Make sure we have a CB_VARIANT commit and a change_id for it
1232 if step_names.CB_VARIANT not in status.commits:
1233 logging.error('Key %s not found in status.commits',
1234 step_names.CB_VARIANT)
1235 return False
1236 if 'change_id' not in status.commits[step_names.CB_VARIANT]:
1237 logging.error('Key change_id not found in status.commits[%s]',
1238 step_names.CB_VARIANT)
1239 return False
1240
1241 # Find the CL by the Original-Change-Id
1242 original_change_id = status.commits[step_names.CB_VARIANT]['change_id']
1243 gerrit_query_args = {
1244 'Original-Change-Id': original_change_id
1245 }
1246 cros = gerrit.GetCrosExternal()
1247 upstream = cros.Query(**gerrit_query_args)
1248 # If nothing is found, the patch hasn't been upstreamed yet
1249 if not upstream:
1250 logging.error('Program cannot continue until coreboot CL is upstreamed.')
1251 logging.error('(coreboot:%s, change-id %s)',
1252 status.commits[step_names.CB_VARIANT]['cl_number'],
1253 status.commits[step_names.CB_VARIANT]['change_id'])
1254 logging.error('Please wait for the CL to be upstreamed, then run this'
1255 ' program again with --continue')
1256 return False
1257
1258 # If more than one CL is found, something is very wrong
1259 if len(upstream) != 1:
1260 logging.error('More than one CL was found with Original-Change-Id %s',
1261 original_change_id)
1262 return False
1263
1264 # At this point, we know there is only one CL and we can get the
1265 # repo and CL number by splitting on the colon between them.
1266 patchlink = upstream[0].PatchLink()
1267 instance_name, cl_number = patchlink.split(':')
1268
1269 # Can't use get_git_commit_data because we're not pulling this
1270 # information from a git commit, but rather from gerrit.
1271 # We only need the gerrit instance and the CL number so we can have
1272 # other CLs cq-depend on this CL. The other keys are not needed because:
1273 # dir - not needed because we're not going to `cd` there to `repo upload`
1274 # branch_name - not valid; the CL is already merged
1275 # change_id - we use the change_id to find a CL number, and since we
1276 # just found the CL number via original-change-id, this is moot.
1277 status.commits[step_names.FIND] = {
1278 'gerrit': instance_name,
1279 'cl_number': str(cl_number)
1280 }
1281
Paul Fagerburg3b534f92019-11-07 15:05:22 -07001282 return True
1283
1284
1285def add_cq_depends(status):
1286 """Add Cq-Depends to all of the CLs in chromiumos
1287
1288 The CL in coreboot needs to be pushed to coreboot.org, get merged,
1289 and then get upstreamed into the chromiumos tree before the other
1290 CLs can cq-depend on it and pass CQ.
1291
Paul Fagerburg92fcb4b2020-02-19 21:21:43 -07001292 Args:
1293 status: variant_status object tracking our board, variant, etc.
Paul Fagerburg3b534f92019-11-07 15:05:22 -07001294
1295 Returns:
1296 True if the build succeeded, False if something failed
1297 """
Paul Fagerburgbab5dde2020-01-10 15:10:29 -07001298 logging.info('Running step add_cq_depends')
Paul Fagerburg3b534f92019-11-07 15:05:22 -07001299 del status # unused parameter
1300 logging.error('TODO (pfagerburg): implement add_cq_depends')
1301 return True
1302
1303
1304def clean_up(status):
1305 """Final clean-up, including delete the status file
1306
Paul Fagerburg92fcb4b2020-02-19 21:21:43 -07001307 Args:
1308 status: variant_status object tracking our board, variant, etc.
Paul Fagerburg3b534f92019-11-07 15:05:22 -07001309
1310 Returns:
1311 True
1312 """
Paul Fagerburgbab5dde2020-01-10 15:10:29 -07001313 logging.info('Running step clean_up')
Paul Fagerburg3b534f92019-11-07 15:05:22 -07001314 status.rm()
1315 return True
1316
1317
Paul Fagerburg042a5252020-03-16 21:49:18 -06001318def abort(status):
1319 """Abort the creation of a new variant by abandoning commits
1320
1321 When the user specifies the --abort flag, we override status.step to
1322 be 'abort' and there is no transition from 'abort' to anything else.
1323 We look at status.commits and for each key, see if we have already
1324 been in that directory and abandoned that specific branch. If not,
1325 abandon the commit and then add the branch+dir to a list of abandoned
1326 commits. We do this because some boards (such as Zork) can have multiple
1327 commits in the same directory and with the same branch name, and we only
1328 want to repo abandon that branch once.
1329
1330 Args:
1331 status: variant_status object tracking our board, variant, etc.
1332
1333 Returns:
1334 True
1335 """
1336 logging.info('Running step abort')
1337 # Use the set 'abandoned' to keep track of each branch+dir abandoned.
1338 abandoned = set()
1339 for step in status.commits:
1340 logging.debug('Processing step %s', step)
1341 commit = status.commits[step]
1342 branch = commit['branch_name']
1343 cwd = commit['dir']
1344 if (branch, cwd) in abandoned:
1345 logging.debug('Branch %s in directory %s already abandoned',
1346 branch, cwd)
1347 else:
1348 logging.info('Abandoning branch %s in directory %s',
1349 branch, cwd)
1350 if run_process(['repo', 'abandon', branch, '.'], cwd=cwd):
1351 abandoned.add((branch, cwd))
1352 else:
1353 logging.error('Error while abandoning branch %s', branch)
1354 return False
1355
1356 return True
1357
1358
Paul Fagerburg3b534f92019-11-07 15:05:22 -07001359if __name__ == '__main__':
1360 sys.exit(not int(main()))