blob: 775453feaee94fdd01ae6989c2a26a0752ec8f6a [file] [log] [blame]
Mike Frysingerf1ba7ad2022-09-12 05:42:57 -04001# Copyright 2012 The ChromiumOS Authors
Brian Harring3fec5a82012-03-01 05:57:03 -08002# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5"""Main builder code for Chromium OS.
6
7Used by Chromium OS buildbot configuration for all Chromium OS builds including
8full and pre-flight-queue builds.
9"""
10
Mike Frysinger321fecd2023-06-16 10:40:51 -040011import contextlib
Chris McDonaldb55b7032021-06-17 16:41:32 -060012import distutils.version # pylint: disable=import-error,no-name-in-module
Brian Harring3fec5a82012-03-01 05:57:03 -080013import glob
Aviv Keshet669eb5e2014-06-23 08:53:01 -070014import json
Chris McDonaldb55b7032021-06-17 16:41:32 -060015import logging
Mike Frysingerb0b0caa2015-11-07 01:05:18 -050016import optparse # pylint: disable=deprecated-module
Brian Harring3fec5a82012-03-01 05:57:03 -080017import os
Aviv Keshetcf9c2722014-02-25 15:15:10 -080018import pickle
Brian Harring3fec5a82012-03-01 05:57:03 -080019import sys
Mike Frysingerace4eae2023-05-26 21:09:43 -040020import tempfile
Brian Harring3fec5a82012-03-01 05:57:03 -080021
Mike Frysingere4d68c22015-02-04 21:26:24 -050022from chromite.cbuildbot import builders
Chris McDonaldb55b7032021-06-17 16:41:32 -060023from chromite.cbuildbot import cbuildbot_alerts
Don Garrett88b8d782014-05-13 17:30:55 -070024from chromite.cbuildbot import cbuildbot_run
Don Garrett88b8d782014-05-13 17:30:55 -070025from chromite.cbuildbot import repository
Aviv Keshet420de512015-05-18 14:28:48 -070026from chromite.cbuildbot import topology
Don Garrett88b8d782014-05-13 17:30:55 -070027from chromite.cbuildbot.stages import completion_stages
Ningning Xiaf342b952017-02-15 14:13:33 -080028from chromite.lib import builder_status_lib
Brian Harringc92a7012012-02-29 10:11:34 -080029from chromite.lib import cgroups
Chris McDonaldb55b7032021-06-17 16:41:32 -060030from chromite.lib import cidb
Brian Harringa184efa2012-03-04 11:51:25 -080031from chromite.lib import cleanup
Brian Harringb6cf9142012-09-01 20:43:17 -070032from chromite.lib import commandline
Ningning Xia6a718052016-12-22 10:08:15 -080033from chromite.lib import config_lib
34from chromite.lib import constants
Brian Harring1b8c4c82012-05-29 23:03:04 -070035from chromite.lib import cros_build_lib
Ningning Xia6a718052016-12-22 10:08:15 -080036from chromite.lib import failures_lib
David James97d95872012-11-16 15:09:56 -080037from chromite.lib import git
Stefan Zagerd49d9ff2014-08-15 21:33:37 -070038from chromite.lib import gob_util
Brian Harringaf019fb2012-05-10 15:06:13 -070039from chromite.lib import osutils
David James6450a0a2012-12-04 07:59:53 -080040from chromite.lib import parallel
Don Garrettb4318362014-10-03 15:49:36 -070041from chromite.lib import retry_stats
Brian Harring3fec5a82012-03-01 05:57:03 -080042from chromite.lib import sudo
Michael Mortensen3e86c1e2019-11-21 15:51:54 -070043from chromite.lib import tee
David James3432acd2013-11-27 10:02:18 -080044from chromite.lib import timeout_util
Paul Hobbsfcf10342015-12-29 15:52:31 -080045from chromite.lib import ts_mon_config
Dhanya Ganesh39a48a82018-12-06 16:01:11 -070046from chromite.lib.buildstore import BuildStore
Brian Harring3fec5a82012-03-01 05:57:03 -080047
Ryan Cuiadd49122012-03-21 22:19:58 -070048
Alex Klein1699fab2022-09-08 08:46:06 -060049_DEFAULT_LOG_DIR = "cbuildbot_logs"
50_BUILDBOT_LOG_FILE = "cbuildbot.log"
51_DEFAULT_EXT_BUILDROOT = "trybot"
52_DEFAULT_INT_BUILDROOT = "trybot-internal"
53_BUILDBOT_REQUIRED_BINARIES = ("pbzip2",)
54_API_VERSION_ATTR = "api_version"
Brian Harring3fec5a82012-03-01 05:57:03 -080055
56
Brian Harring3fec5a82012-03-01 05:57:03 -080057def _BackupPreviousLog(log_file, backup_limit=25):
Alex Klein1699fab2022-09-08 08:46:06 -060058 """Rename previous log.
Brian Harring3fec5a82012-03-01 05:57:03 -080059
Alex Klein1699fab2022-09-08 08:46:06 -060060 Args:
Trent Apted66736d82023-05-25 10:38:28 +100061 log_file: The absolute path to the previous log.
62 backup_limit: Maximum number of old logs to keep.
Alex Klein1699fab2022-09-08 08:46:06 -060063 """
64 if os.path.exists(log_file):
65 old_logs = sorted(
66 glob.glob(log_file + ".*"), key=distutils.version.LooseVersion
67 )
Brian Harring3fec5a82012-03-01 05:57:03 -080068
Alex Klein1699fab2022-09-08 08:46:06 -060069 if len(old_logs) >= backup_limit:
70 os.remove(old_logs[0])
Brian Harring3fec5a82012-03-01 05:57:03 -080071
Alex Klein1699fab2022-09-08 08:46:06 -060072 last = 0
73 if old_logs:
74 last = int(old_logs.pop().rpartition(".")[2])
Brian Harring3fec5a82012-03-01 05:57:03 -080075
Alex Klein1699fab2022-09-08 08:46:06 -060076 os.rename(log_file, log_file + "." + str(last + 1))
Brian Harring3fec5a82012-03-01 05:57:03 -080077
Ryan Cui5616a512012-08-17 13:39:36 -070078
Gaurav Shah298aa372014-01-31 09:27:24 -080079def _IsDistributedBuilder(options, chrome_rev, build_config):
Alex Klein1699fab2022-09-08 08:46:06 -060080 """Determines whether the builder should be a DistributedBuilder.
Gaurav Shah298aa372014-01-31 09:27:24 -080081
Alex Klein1699fab2022-09-08 08:46:06 -060082 Args:
Trent Apted66736d82023-05-25 10:38:28 +100083 options: options passed on the commandline.
84 chrome_rev: Chrome revision to build.
85 build_config: Builder configuration dictionary.
Gaurav Shah298aa372014-01-31 09:27:24 -080086
Alex Klein1699fab2022-09-08 08:46:06 -060087 Returns:
Trent Apted66736d82023-05-25 10:38:28 +100088 True if the builder should be a distributed_builder
Alex Klein1699fab2022-09-08 08:46:06 -060089 """
90 if not options.buildbot:
91 return False
92 elif chrome_rev in (
93 constants.CHROME_REV_TOT,
94 constants.CHROME_REV_LOCAL,
95 constants.CHROME_REV_SPEC,
96 ):
97 # We don't do distributed logic to TOT Chrome PFQ's, nor local
98 # chrome roots (e.g. chrome try bots)
99 # TODO(davidjames): Update any builders that rely on this logic to use
100 # manifest_version=False instead.
101 return False
102 elif build_config["manifest_version"]:
103 return True
104
Gaurav Shah298aa372014-01-31 09:27:24 -0800105 return False
Gaurav Shah298aa372014-01-31 09:27:24 -0800106
107
Don Garretta52a5b02015-06-02 14:52:57 -0700108def _RunBuildStagesWrapper(options, site_config, build_config):
Alex Klein1699fab2022-09-08 08:46:06 -0600109 """Helper function that wraps RunBuildStages()."""
110 logging.info(
111 "cbuildbot was executed with args %s", cros_build_lib.CmdToStr(sys.argv)
112 )
Brian Harring3fec5a82012-03-01 05:57:03 -0800113
Alex Klein1699fab2022-09-08 08:46:06 -0600114 chrome_rev = build_config["chrome_rev"]
115 if options.chrome_rev:
116 chrome_rev = options.chrome_rev
117 if chrome_rev == constants.CHROME_REV_TOT:
118 options.chrome_version = gob_util.GetTipOfTrunkRevision(
119 constants.CHROMIUM_GOB_URL
120 )
121 options.chrome_rev = constants.CHROME_REV_SPEC
David Jamesa0a664e2013-02-13 09:52:01 -0800122
Alex Klein1699fab2022-09-08 08:46:06 -0600123 # If it's likely we'll need to build Chrome, fetch the source.
124 if build_config["sync_chrome"] is None:
125 options.managed_chrome = chrome_rev != constants.CHROME_REV_LOCAL and (
126 not build_config["usepkg_build_packages"]
127 or chrome_rev
128 or build_config["profile"]
129 )
Matt Tennant0940c382014-01-21 20:43:55 -0800130 else:
Alex Klein1699fab2022-09-08 08:46:06 -0600131 options.managed_chrome = build_config["sync_chrome"]
Mike Frysingere4d68c22015-02-04 21:26:24 -0500132
Alex Klein1699fab2022-09-08 08:46:06 -0600133 chrome_root_mgr = None
134 if options.managed_chrome:
135 # Create a temp directory for syncing Chrome source.
136 chrome_root_mgr = osutils.TempDir(prefix="chrome_root_")
137 options.chrome_root = chrome_root_mgr.tempdir
138
139 # We are done munging options values, so freeze options object now to avoid
140 # further abuse of it.
141 # TODO(mtennant): one by one identify each options value override and see if
142 # it can be handled another way. Try to push this freeze closer and closer
143 # to the start of the script (e.g. in or after _PostParseCheck).
144 options.Freeze()
145
146 metadata_dump_dict = {
147 # A detected default has been set before now if it wasn't explicit.
148 "branch": options.branch,
149 }
150 if options.metadata_dump:
Mike Frysinger31fdddd2023-02-24 15:50:55 -0500151 with open(options.metadata_dump, "rb") as metadata_file:
152 metadata_dump_dict = json.load(metadata_file)
Alex Klein1699fab2022-09-08 08:46:06 -0600153
154 with parallel.Manager() as manager:
155 builder_run = cbuildbot_run.BuilderRun(
156 options, site_config, build_config, manager
157 )
158 buildstore = BuildStore()
159 if metadata_dump_dict:
160 builder_run.attrs.metadata.UpdateWithDict(metadata_dump_dict)
161
162 if builder_run.config.builder_class_name is None:
163 # TODO: This should get relocated to chromeos_config.
164 if _IsDistributedBuilder(options, chrome_rev, build_config):
165 builder_cls_name = "simple_builders.DistributedBuilder"
166 else:
167 builder_cls_name = "simple_builders.SimpleBuilder"
168 builder_cls = builders.GetBuilderClass(builder_cls_name)
169 builder = builder_cls(builder_run, buildstore)
170 else:
171 builder = builders.Builder(builder_run, buildstore)
172
173 try:
174 if not builder.Run():
175 sys.exit(1)
176 finally:
177 if chrome_root_mgr:
178 chrome_root_mgr.Cleanup()
Brian Harring3fec5a82012-03-01 05:57:03 -0800179
180
Brian Harring3fec5a82012-03-01 05:57:03 -0800181def _CheckChromeVersionOption(_option, _opt_str, value, parser):
Alex Klein1699fab2022-09-08 08:46:06 -0600182 """Upgrade other options based on chrome_version being passed."""
183 value = value.strip()
Brian Harring3fec5a82012-03-01 05:57:03 -0800184
Alex Klein1699fab2022-09-08 08:46:06 -0600185 if parser.values.chrome_rev is None and value:
186 parser.values.chrome_rev = constants.CHROME_REV_SPEC
Brian Harring3fec5a82012-03-01 05:57:03 -0800187
Alex Klein1699fab2022-09-08 08:46:06 -0600188 parser.values.chrome_version = value
Brian Harring3fec5a82012-03-01 05:57:03 -0800189
190
191def _CheckChromeRootOption(_option, _opt_str, value, parser):
Alex Klein1699fab2022-09-08 08:46:06 -0600192 """Validate and convert chrome_root to full-path form."""
193 if parser.values.chrome_rev is None:
194 parser.values.chrome_rev = constants.CHROME_REV_LOCAL
Brian Harring3fec5a82012-03-01 05:57:03 -0800195
Alex Klein1699fab2022-09-08 08:46:06 -0600196 parser.values.chrome_root = value
Brian Harring3fec5a82012-03-01 05:57:03 -0800197
198
David Jamesac8c2a72013-02-13 18:44:33 -0800199def FindCacheDir(_parser, _options):
Alex Klein1699fab2022-09-08 08:46:06 -0600200 return None
Brian Harringae0a5322012-09-15 01:46:51 -0700201
202
Ryan Cui5ba7e152012-05-10 14:36:52 -0700203class CustomGroup(optparse.OptionGroup):
Alex Klein1699fab2022-09-08 08:46:06 -0600204 """Custom option group which supports arguments passed-through to trybot."""
David Jameseecba232014-06-11 11:35:11 -0700205
Alex Klein1699fab2022-09-08 08:46:06 -0600206 def add_remote_option(self, *args, **kwargs):
207 """For arguments that are passed-through to remote trybot."""
208 return optparse.OptionGroup.add_option(
209 self, *args, remote_pass_through=True, **kwargs
210 )
Ryan Cui5ba7e152012-05-10 14:36:52 -0700211
212
Ryan Cui1c13a252012-10-16 15:00:16 -0700213class CustomOption(commandline.FilteringOption):
Alex Klein1699fab2022-09-08 08:46:06 -0600214 """Subclass FilteringOption class to implement pass-through and api."""
Ryan Cui5ba7e152012-05-10 14:36:52 -0700215
Alex Klein1699fab2022-09-08 08:46:06 -0600216 def __init__(self, *args, **kwargs):
217 # The remote_pass_through argument specifies whether we should directly
218 # pass the argument (with its value) onto the remote trybot.
219 self.pass_through = kwargs.pop("remote_pass_through", False)
220 self.api_version = int(kwargs.pop("api", "0"))
221 commandline.FilteringOption.__init__(self, *args, **kwargs)
Ryan Cui5ba7e152012-05-10 14:36:52 -0700222
Ryan Cui5ba7e152012-05-10 14:36:52 -0700223
Ryan Cui1c13a252012-10-16 15:00:16 -0700224class CustomParser(commandline.FilteringParser):
Alex Klein1699fab2022-09-08 08:46:06 -0600225 """Custom option parser which supports arguments passed-through to trybot"""
Matt Tennante8179042013-10-01 15:47:32 -0700226
Alex Klein1699fab2022-09-08 08:46:06 -0600227 DEFAULT_OPTION_CLASS = CustomOption
Brian Harringb6cf9142012-09-01 20:43:17 -0700228
Alex Klein1699fab2022-09-08 08:46:06 -0600229 def add_remote_option(self, *args, **kwargs):
230 """For arguments that are passed-through to remote trybot."""
231 return self.add_option(*args, remote_pass_through=True, **kwargs)
Brian Harringb6cf9142012-09-01 20:43:17 -0700232
233
Don Garrett86881cb2017-02-15 15:41:55 -0800234def CreateParser():
Alex Klein1699fab2022-09-08 08:46:06 -0600235 """Expose _CreateParser publicly."""
236 # Name _CreateParser is needed for commandline library.
237 return _CreateParser()
Don Garrett86881cb2017-02-15 15:41:55 -0800238
239
Brian Harring3fec5a82012-03-01 05:57:03 -0800240def _CreateParser():
Alex Klein1699fab2022-09-08 08:46:06 -0600241 """Generate and return the parser with all the options."""
242 # Parse options
243 usage = "usage: %prog [options] buildbot_config [buildbot_config ...]"
244 parser = CustomParser(usage=usage, caching=FindCacheDir)
Brian Harring3fec5a82012-03-01 05:57:03 -0800245
Alex Klein1699fab2022-09-08 08:46:06 -0600246 # Main options
247 parser.add_remote_option(
248 "-b",
249 "--branch",
Trent Apted66736d82023-05-25 10:38:28 +1000250 help=(
251 "The manifest branch to test. The branch to "
252 "check the buildroot out to."
253 ),
Alex Klein1699fab2022-09-08 08:46:06 -0600254 )
255 parser.add_option(
256 "-r",
257 "--buildroot",
258 type="path",
259 dest="buildroot",
Trent Apted66736d82023-05-25 10:38:28 +1000260 help=(
261 "Root directory where source is checked out to, and "
262 "where the build occurs. For external build configs, "
263 "defaults to 'trybot' directory at top level of your "
264 "repo-managed checkout."
265 ),
Alex Klein1699fab2022-09-08 08:46:06 -0600266 )
267 parser.add_option(
268 "--workspace",
269 type="path",
270 api=constants.REEXEC_API_WORKSPACE,
271 help="Root directory for a secondary checkout .",
272 )
273 parser.add_option(
274 "--bootstrap-dir",
275 type="path",
Trent Apted66736d82023-05-25 10:38:28 +1000276 help=(
277 "Bootstrapping cbuildbot may involve checking out "
278 "multiple copies of chromite. All these checkouts "
279 "will be contained in the directory specified here. "
Mike Frysingerace4eae2023-05-26 21:09:43 -0400280 f"(Default: {tempfile.gettempdir()})"
281 ),
Alex Klein1699fab2022-09-08 08:46:06 -0600282 )
283 parser.add_remote_option(
Alex Klein1699fab2022-09-08 08:46:06 -0600284 "--chrome_rev",
285 type="choice",
286 choices=constants.VALID_CHROME_REVISIONS,
287 help=(
288 "Revision of Chrome to use, of type [%s]"
289 % "|".join(constants.VALID_CHROME_REVISIONS)
290 ),
291 )
292 parser.add_remote_option(
293 "--profile", help="Name of profile to sub-specify board variant."
294 )
295 # TODO(crbug.com/279618): Running GOMA is under development. Following
296 # flags are added for development purpose due to repository dependency,
297 # but not officially supported yet.
298 parser.add_option(
299 "--goma_dir",
300 type="path",
301 api=constants.REEXEC_API_GOMA,
Trent Apted66736d82023-05-25 10:38:28 +1000302 help=(
303 "Specify a directory containing goma. When this is "
304 "set, GOMA is used to build Chrome."
305 ),
Alex Klein1699fab2022-09-08 08:46:06 -0600306 )
307 parser.add_option(
308 "--chromeos_goma_dir",
309 type="path",
310 api=constants.REEXEC_API_CHROMEOS_GOMA_DIR,
Trent Apted66736d82023-05-25 10:38:28 +1000311 help="Specify a directory containing goma for build package.",
Alex Klein1699fab2022-09-08 08:46:06 -0600312 )
Alex Klein1699fab2022-09-08 08:46:06 -0600313 group = CustomGroup(parser, "Deprecated Options")
Don Garrett211df8c2017-09-06 13:33:02 -0700314
Alex Klein1699fab2022-09-08 08:46:06 -0600315 parser.add_option(
316 "--local",
317 action="store_true",
318 default=False,
319 help="Deprecated. See cros tryjob.",
320 )
321 parser.add_option(
322 "--remote",
323 action="store_true",
324 default=False,
325 help="Deprecated. See cros tryjob.",
326 )
Don Garrett211df8c2017-09-06 13:33:02 -0700327
Alex Klein1699fab2022-09-08 08:46:06 -0600328 #
329 # Patch selection options.
330 #
Mike Frysinger81af6ef2013-04-03 02:24:09 -0400331
Alex Klein1699fab2022-09-08 08:46:06 -0600332 group = CustomGroup(parser, "Patch Options")
Mike Frysinger81af6ef2013-04-03 02:24:09 -0400333
Alex Klein1699fab2022-09-08 08:46:06 -0600334 group.add_remote_option(
335 "-g",
336 "--gerrit-patches",
337 action="split_extend",
338 type="string",
339 default=[],
340 metavar="'Id1 *int_Id2...IdN'",
Trent Apted66736d82023-05-25 10:38:28 +1000341 help=(
342 "Space-separated list of short-form Gerrit "
343 "Change-Id's or change numbers to patch. "
344 "Please prepend '*' to internal Change-Id's"
345 ),
Alex Klein1699fab2022-09-08 08:46:06 -0600346 )
Mike Frysinger81af6ef2013-04-03 02:24:09 -0400347
Alex Klein1699fab2022-09-08 08:46:06 -0600348 parser.add_argument_group(group)
Mike Frysinger81af6ef2013-04-03 02:24:09 -0400349
Alex Klein1699fab2022-09-08 08:46:06 -0600350 #
351 # Remote trybot options.
352 #
Mike Frysinger81af6ef2013-04-03 02:24:09 -0400353
Alex Klein1699fab2022-09-08 08:46:06 -0600354 group = CustomGroup(parser, "Options used to configure tryjob behavior.")
355 group.add_remote_option(
Alex Klein1699fab2022-09-08 08:46:06 -0600356 "--channel",
357 action="split_extend",
358 dest="channels",
359 default=[],
Trent Apted66736d82023-05-25 10:38:28 +1000360 help=(
361 "Specify a channel for a payloads trybot. Can "
362 "be specified multiple times. No valid for "
363 "non-payloads configs."
364 ),
Alex Klein1699fab2022-09-08 08:46:06 -0600365 )
Mike Frysinger81af6ef2013-04-03 02:24:09 -0400366
Alex Klein1699fab2022-09-08 08:46:06 -0600367 parser.add_argument_group(group)
Mike Frysinger81af6ef2013-04-03 02:24:09 -0400368
Alex Klein1699fab2022-09-08 08:46:06 -0600369 #
370 # Advanced options.
371 #
Ryan Cuif4f84be2012-07-09 18:50:41 -0700372
Alex Klein1699fab2022-09-08 08:46:06 -0600373 group = CustomGroup(
374 parser,
375 "Advanced Options",
376 "Caution: use these options at your own risk.",
377 )
Brian Harring3fec5a82012-03-01 05:57:03 -0800378
Alex Klein1699fab2022-09-08 08:46:06 -0600379 group.add_remote_option(
380 "--bootstrap-args",
381 action="append",
382 default=[],
Trent Apted66736d82023-05-25 10:38:28 +1000383 help=(
384 "Args passed directly to the bootstrap re-exec "
385 "to skip verification by the bootstrap code"
386 ),
Alex Klein1699fab2022-09-08 08:46:06 -0600387 )
388 group.add_remote_option(
389 "--buildbot",
390 action="store_true",
391 dest="buildbot",
392 default=False,
Trent Apted66736d82023-05-25 10:38:28 +1000393 help=(
394 "This is running on a buildbot. "
395 "This can be used to make a build operate "
396 "like an official builder, e.g. generate "
397 "new version numbers and archive official "
398 "artifacts and such. This should only be "
399 "used if you are confident in what you are "
400 "doing, as it will make automated commits."
401 ),
Alex Klein1699fab2022-09-08 08:46:06 -0600402 )
403 parser.add_remote_option(
404 "--repo-cache",
405 type="path",
406 dest="_repo_cache",
407 help="Present for backwards compatibility, ignored.",
408 )
409 group.add_remote_option(
410 "--no-buildbot-tags",
411 action="store_false",
412 dest="enable_buildbot_tags",
413 default=True,
Trent Apted66736d82023-05-25 10:38:28 +1000414 help=(
415 "Suppress buildbot specific tags from log "
416 "output. This is used to hide recursive "
417 "cbuilbot runs on the waterfall."
418 ),
Alex Klein1699fab2022-09-08 08:46:06 -0600419 )
420 group.add_remote_option(
421 "--buildnumber", type="int", default=0, help="build number"
422 )
423 group.add_option(
424 "--chrome_root",
425 action="callback",
426 type="path",
427 callback=_CheckChromeRootOption,
428 help="Local checkout of Chrome to use.",
429 )
430 group.add_remote_option(
431 "--chrome_version",
432 action="callback",
433 type="string",
434 dest="chrome_version",
435 callback=_CheckChromeVersionOption,
Trent Apted66736d82023-05-25 10:38:28 +1000436 help=(
437 "Used with SPEC logic to force a particular "
438 "git revision of chrome rather than the "
439 "latest."
440 ),
Alex Klein1699fab2022-09-08 08:46:06 -0600441 )
442 group.add_remote_option(
443 "--clobber",
444 action="store_true",
445 default=False,
446 help="Clears an old checkout before syncing",
447 )
448 group.add_remote_option(
449 "--latest-toolchain",
450 action="store_true",
451 default=False,
452 help="Use the latest toolchain.",
453 )
454 parser.add_option(
455 "--log_dir",
456 dest="log_dir",
457 type="path",
458 help="Directory where logs are stored.",
459 )
460 group.add_remote_option(
461 "--maxarchives",
462 type="int",
463 dest="max_archive_builds",
464 default=3,
465 help="Change the local saved build count limit.",
466 )
467 parser.add_remote_option(
468 "--manifest-repo-url", help="Overrides the default manifest repo url."
469 )
470 group.add_remote_option(
Alex Klein1699fab2022-09-08 08:46:06 -0600471 "--noarchive",
472 action="store_false",
473 dest="archive",
474 default=True,
475 help="Don't run archive stage.",
476 )
477 group.add_remote_option(
478 "--nobootstrap",
479 action="store_false",
480 dest="bootstrap",
481 default=True,
Trent Apted66736d82023-05-25 10:38:28 +1000482 help="Don't checkout and run from a standalone chromite repo.",
Alex Klein1699fab2022-09-08 08:46:06 -0600483 )
484 group.add_remote_option(
485 "--nobuild",
486 action="store_false",
487 dest="build",
488 default=True,
489 help="Don't actually build (for cbuildbot dev)",
490 )
491 group.add_remote_option(
492 "--noclean",
493 action="store_false",
494 dest="clean",
495 default=True,
496 help="Don't clean the buildroot",
497 )
498 group.add_remote_option(
499 "--nocgroups",
500 action="store_false",
501 dest="cgroups",
502 default=True,
503 help="Disable cbuildbots usage of cgroups.",
504 )
505 group.add_remote_option(
506 "--nochromesdk",
507 action="store_false",
508 dest="chrome_sdk",
509 default=True,
Trent Apted66736d82023-05-25 10:38:28 +1000510 help=(
511 "Don't run the ChromeSDK stage which builds "
512 "Chrome outside of the chroot."
513 ),
Alex Klein1699fab2022-09-08 08:46:06 -0600514 )
515 group.add_remote_option(
516 "--noprebuilts",
517 action="store_false",
518 dest="prebuilts",
519 default=True,
520 help="Don't upload prebuilts.",
521 )
522 group.add_remote_option(
523 "--nopatch",
524 action="store_false",
525 dest="postsync_patch",
526 default=True,
Trent Apted66736d82023-05-25 10:38:28 +1000527 help=(
528 "Don't run PatchChanges stage. This does not "
529 "disable patching in of chromite patches "
530 "during BootstrapStage."
531 ),
Alex Klein1699fab2022-09-08 08:46:06 -0600532 )
533 group.add_remote_option(
534 "--nopaygen",
535 action="store_false",
536 dest="paygen",
537 default=True,
538 help="Don't generate payloads.",
539 )
540 group.add_remote_option(
541 "--noreexec",
542 action="store_false",
543 dest="postsync_reexec",
544 default=True,
545 help="Don't reexec into the buildroot after syncing.",
546 )
547 group.add_remote_option(
548 "--nosdk",
549 action="store_true",
550 default=False,
551 help="Re-create the SDK from scratch.",
552 )
553 group.add_remote_option(
554 "--nosync",
555 action="store_false",
556 dest="sync",
557 default=True,
558 help="Don't sync before building.",
559 )
560 group.add_remote_option(
561 "--notests",
562 action="store_false",
563 dest="tests",
564 default=True,
Trent Apted66736d82023-05-25 10:38:28 +1000565 help=(
566 "Override values from buildconfig, run no "
567 "tests, and build no autotest and artifacts."
568 ),
Alex Klein1699fab2022-09-08 08:46:06 -0600569 )
570 group.add_remote_option(
571 "--novmtests",
572 action="store_false",
573 dest="vmtests",
574 default=True,
Trent Apted66736d82023-05-25 10:38:28 +1000575 help="Override values from buildconfig, run no vmtests.",
Alex Klein1699fab2022-09-08 08:46:06 -0600576 )
577 group.add_remote_option(
578 "--noimagetests",
579 action="store_false",
580 dest="image_test",
581 default=True,
Trent Apted66736d82023-05-25 10:38:28 +1000582 help="Override values from buildconfig and run no image tests.",
Alex Klein1699fab2022-09-08 08:46:06 -0600583 )
584 group.add_remote_option(
585 "--nouprev",
586 action="store_false",
587 dest="uprev",
588 default=True,
Trent Apted66736d82023-05-25 10:38:28 +1000589 help="Override values from buildconfig and never uprev.",
Alex Klein1699fab2022-09-08 08:46:06 -0600590 )
591 group.add_option(
592 "--reference-repo",
Trent Apted66736d82023-05-25 10:38:28 +1000593 help=(
594 "Reuse git data stored in an existing repo "
595 "checkout. This can drastically reduce the network "
596 "time spent setting up the trybot checkout. By "
597 "default, if this option isn't given but cbuildbot "
598 "is invoked from a repo checkout, cbuildbot will "
599 "use the repo root."
600 ),
Alex Klein1699fab2022-09-08 08:46:06 -0600601 )
602 group.add_option(
603 "--resume",
604 action="store_true",
605 default=False,
606 help="Skip stages already successfully completed.",
607 )
608 group.add_remote_option(
609 "--timeout",
610 type="int",
611 default=0,
Trent Apted66736d82023-05-25 10:38:28 +1000612 help=(
613 "Specify the maximum amount of time this job "
614 "can run for, at which point the build will be "
615 "aborted. If set to zero, then there is no "
616 "timeout."
617 ),
Alex Klein1699fab2022-09-08 08:46:06 -0600618 )
619 group.add_remote_option(
620 "--version",
621 dest="force_version",
Trent Apted66736d82023-05-25 10:38:28 +1000622 help=(
623 "Used with manifest logic. Forces use of this "
624 "version rather than create or get latest. "
625 "Examples: 4815.0.0-rc1, 4815.1.2"
626 ),
Alex Klein1699fab2022-09-08 08:46:06 -0600627 )
628 group.add_remote_option(
629 "--git-cache-dir",
630 type="path",
631 api=constants.REEXEC_API_GIT_CACHE_DIR,
Trent Apted66736d82023-05-25 10:38:28 +1000632 help=(
633 "Specify the cache directory to store the "
634 "project caches populated by the git-cache "
635 "tool. Bootstrap the projects based on the git "
636 "cache files instead of fetching them directly "
637 "from the GoB servers."
638 ),
Alex Klein1699fab2022-09-08 08:46:06 -0600639 )
640 group.add_remote_option(
641 "--chrome-preload-dir",
642 type="path",
643 api=constants.REEXEC_API_CHROME_PRELOAD_DIR,
Trent Apted66736d82023-05-25 10:38:28 +1000644 help=(
645 "Specify a preloaded chrome source cache "
646 "directory populated by the git-cache tool. "
647 "Bootstrap chrome based on the cached files "
648 "instead of fetching them directly from the GoB "
649 "servers. When both this argument and "
650 "--git-cache-dir are provided this value will "
651 "be preferred for the chrome source cache."
652 ),
Alex Klein1699fab2022-09-08 08:46:06 -0600653 )
654 group.add_remote_option(
655 "--source_cache",
656 action="store_true",
657 default=False,
658 help="Whether to utilize cache snapshot mounts.",
659 )
660 group.add_remote_option(
661 "--debug-cidb",
662 action="store_true",
663 default=False,
664 help="Force Debug CIDB to be used.",
665 )
666 # cbuildbot ChromeOS Findit options
667 group.add_remote_option(
668 "--cbb_build_packages",
669 action="split_extend",
670 dest="cbb_build_packages",
671 default=[],
Trent Apted66736d82023-05-25 10:38:28 +1000672 help=(
673 "Specify an explicit list of packages to build "
674 "for integration with Findit."
675 ),
Alex Klein1699fab2022-09-08 08:46:06 -0600676 )
677 group.add_remote_option(
678 "--cbb_snapshot_revision",
679 type="string",
680 dest="cbb_snapshot_revision",
681 default=None,
Trent Apted66736d82023-05-25 10:38:28 +1000682 help="Snapshot manifest revision to sync to for building.",
Alex Klein1699fab2022-09-08 08:46:06 -0600683 )
684 group.add_remote_option(
685 "--no-publish-prebuilt-confs",
686 dest="publish",
687 action="store_false",
688 default=True,
689 help="Don't publish git commits to prebuilt.conf or sdk_version.conf",
690 )
Mike Frysinger81af6ef2013-04-03 02:24:09 -0400691
Alex Klein1699fab2022-09-08 08:46:06 -0600692 parser.add_argument_group(group)
Mike Frysinger81af6ef2013-04-03 02:24:09 -0400693
Alex Klein1699fab2022-09-08 08:46:06 -0600694 #
695 # Internal options.
696 #
Mike Frysinger81af6ef2013-04-03 02:24:09 -0400697
Alex Klein1699fab2022-09-08 08:46:06 -0600698 group = CustomGroup(
699 parser,
700 "Internal Chromium OS Build Team Options",
701 "Caution: these are for meant for the Chromium OS build team only",
702 )
Mike Frysinger81af6ef2013-04-03 02:24:09 -0400703
Alex Klein1699fab2022-09-08 08:46:06 -0600704 group.add_remote_option(
705 "--archive-base",
706 type="gs_path",
Trent Apted66736d82023-05-25 10:38:28 +1000707 help=(
708 "Base GS URL (gs://<bucket_name>/<path>) to "
709 "upload archive artifacts to"
710 ),
Alex Klein1699fab2022-09-08 08:46:06 -0600711 )
712 group.add_remote_option(
713 "--cq-gerrit-query",
714 dest="cq_gerrit_override",
Trent Apted66736d82023-05-25 10:38:28 +1000715 help=(
716 "If given, this gerrit query will be used to find what patches to "
717 "test, rather than the normal 'CommitQueue>=1 AND Verified=1 AND "
718 "CodeReview=2' query it defaults to. Use with care- note "
719 "additionally this setting only has an effect if the buildbot "
720 "target is a cq target, and we're in buildbot mode."
721 ),
Alex Klein1699fab2022-09-08 08:46:06 -0600722 )
723 group.add_option(
724 "--pass-through",
725 action="append",
726 type="string",
727 dest="pass_through_args",
728 default=[],
729 )
730 group.add_option(
731 "--reexec-api-version",
732 action="store_true",
733 dest="output_api_version",
734 default=False,
Trent Apted66736d82023-05-25 10:38:28 +1000735 help=(
736 "Used for handling forwards/backwards compatibility "
737 "with --resume and --bootstrap"
738 ),
Alex Klein1699fab2022-09-08 08:46:06 -0600739 )
740 group.add_option(
741 "--remote-trybot",
742 action="store_true",
743 default=False,
744 help="Indicates this is running on a remote trybot machine",
745 )
746 group.add_option(
747 "--buildbucket-id",
748 api=constants.REEXEC_API_GOMA, # Approximate.
Trent Apted66736d82023-05-25 10:38:28 +1000749 help=(
750 "The unique ID in buildbucket of current build "
751 "generated by buildbucket."
752 ),
Alex Klein1699fab2022-09-08 08:46:06 -0600753 )
754 group.add_remote_option(
755 "--remote-patches",
756 action="split_extend",
757 default=[],
Trent Apted66736d82023-05-25 10:38:28 +1000758 help=(
759 "Patches uploaded by the trybot client when run using the -p option"
760 ),
Alex Klein1699fab2022-09-08 08:46:06 -0600761 )
762 # Note the default here needs to be hardcoded to 3; that is the last version
763 # that lacked this functionality.
764 group.add_option(
765 "--remote-version",
766 type="int",
767 default=3,
768 help="Deprecated and ignored.",
769 )
770 group.add_option("--sourceroot", type="path", default=constants.SOURCE_ROOT)
771 group.add_remote_option(
772 "--test-bootstrap",
773 action="store_true",
774 default=False,
Trent Apted66736d82023-05-25 10:38:28 +1000775 help=(
776 "Causes cbuildbot to bootstrap itself twice, "
777 "in the sequence A->B->C: A(unpatched) patches "
778 "and bootstraps B; B patches and bootstraps C"
779 ),
Alex Klein1699fab2022-09-08 08:46:06 -0600780 )
781 group.add_remote_option(
782 "--validation_pool",
Trent Apted66736d82023-05-25 10:38:28 +1000783 help=(
784 "Path to a pickled validation pool. Intended "
785 "for use only with the commit queue."
786 ),
Alex Klein1699fab2022-09-08 08:46:06 -0600787 )
788 group.add_remote_option(
789 "--metadata_dump",
Trent Apted66736d82023-05-25 10:38:28 +1000790 help=(
791 "Path to a json dumped metadata file. This "
792 "will be used as the initial metadata."
793 ),
Alex Klein1699fab2022-09-08 08:46:06 -0600794 )
795 group.add_remote_option(
796 "--master-build-id",
797 type="int",
798 api=constants.REEXEC_API_MASTER_BUILD_ID,
Trent Apted66736d82023-05-25 10:38:28 +1000799 help="cidb build id of the master build to this slave build.",
Alex Klein1699fab2022-09-08 08:46:06 -0600800 )
801 group.add_remote_option(
802 "--master-buildbucket-id",
803 api=constants.REEXEC_API_MASTER_BUILDBUCKET_ID,
Trent Apted66736d82023-05-25 10:38:28 +1000804 help="buildbucket id of the master build to this slave build.",
Alex Klein1699fab2022-09-08 08:46:06 -0600805 )
806 # TODO(nxia): crbug.com/778838
807 # cbuildbot doesn't use pickle files anymore, remove this.
808 group.add_remote_option(
809 "--mock-slave-status",
810 metavar="MOCK_SLAVE_STATUS_PICKLE_FILE",
Trent Apted66736d82023-05-25 10:38:28 +1000811 help=(
812 "Override the result of the _FetchSlaveStatuses "
813 "method of MasterSlaveSyncCompletionStage, by "
814 "specifying a file with a pickle of the result "
815 "to be returned."
816 ),
Alex Klein1699fab2022-09-08 08:46:06 -0600817 )
818 group.add_option(
819 "--previous-build-state",
820 type="string",
821 default="",
822 api=constants.REEXEC_API_PREVIOUS_BUILD_STATE,
Trent Apted66736d82023-05-25 10:38:28 +1000823 help=(
824 "A base64-encoded BuildSummary object describing the "
825 "previous build run on the same build machine."
826 ),
Alex Klein1699fab2022-09-08 08:46:06 -0600827 )
Mike Frysinger81af6ef2013-04-03 02:24:09 -0400828
Alex Klein1699fab2022-09-08 08:46:06 -0600829 parser.add_argument_group(group)
Ryan Cuif4f84be2012-07-09 18:50:41 -0700830
Alex Klein1699fab2022-09-08 08:46:06 -0600831 #
832 # Debug options
833 #
834 # Temporary hack; in place till --dry-run replaces --debug.
835 # pylint: disable=protected-access
836 group = parser.debug_group
837 debug = [x for x in group.option_list if x._long_opts == ["--debug"]][0]
838 debug.help += " Currently functions as --dry-run in addition."
839 debug.pass_through = True
840 group.add_option(
841 "--notee",
842 action="store_false",
843 dest="tee",
844 default=True,
Trent Apted66736d82023-05-25 10:38:28 +1000845 help=(
846 "Disable logging and internal tee process. Primarily "
847 "used for debugging cbuildbot itself."
848 ),
Alex Klein1699fab2022-09-08 08:46:06 -0600849 )
850 return parser
Brian Harring3fec5a82012-03-01 05:57:03 -0800851
852
Mike Frysinger80bba8a2017-08-18 15:28:36 -0400853def _FinishParsing(options):
Alex Klein1699fab2022-09-08 08:46:06 -0600854 """Perform some parsing tasks that need to take place after optparse.
Ryan Cui85867972012-02-23 18:21:49 -0800855
Alex Klein1699fab2022-09-08 08:46:06 -0600856 This function needs to be easily testable! Keep it free of
857 environment-dependent code. Put more detailed usage validation in
858 _PostParseCheck().
Brian Harring3fec5a82012-03-01 05:57:03 -0800859
Alex Klein1699fab2022-09-08 08:46:06 -0600860 Args:
Trent Apted66736d82023-05-25 10:38:28 +1000861 options: The options object returned by optparse
Alex Klein1699fab2022-09-08 08:46:06 -0600862 """
863 # Populate options.pass_through_args.
864 accepted, _ = commandline.FilteringParser.FilterArgs(
865 options.parsed_args, lambda x: x.opt_inst.pass_through
866 )
867 options.pass_through_args.extend(accepted)
Brian Harring07039b52012-05-13 17:56:47 -0700868
Alex Klein1699fab2022-09-08 08:46:06 -0600869 if options.local or options.remote:
870 cros_build_lib.Die("Deprecated usage. Please use cros tryjob instead.")
Don Garrettcc0ee522017-09-13 14:28:42 -0700871
Alex Klein1699fab2022-09-08 08:46:06 -0600872 if not options.buildroot:
873 cros_build_lib.Die("A buildroot is required to build.")
Don Garrett211df8c2017-09-06 13:33:02 -0700874
Alex Klein1699fab2022-09-08 08:46:06 -0600875 if options.chrome_root:
876 if options.chrome_rev != constants.CHROME_REV_LOCAL:
877 cros_build_lib.Die(
878 "Chrome rev must be %s if chrome_root is set."
879 % constants.CHROME_REV_LOCAL
880 )
881 elif options.chrome_rev == constants.CHROME_REV_LOCAL:
882 cros_build_lib.Die(
883 "Chrome root must be set if chrome_rev is %s."
884 % constants.CHROME_REV_LOCAL
885 )
Brian Harring3fec5a82012-03-01 05:57:03 -0800886
Alex Klein1699fab2022-09-08 08:46:06 -0600887 if options.chrome_version:
888 if options.chrome_rev != constants.CHROME_REV_SPEC:
889 cros_build_lib.Die(
890 "Chrome rev must be %s if chrome_version is set."
891 % constants.CHROME_REV_SPEC
892 )
893 elif options.chrome_rev == constants.CHROME_REV_SPEC:
894 cros_build_lib.Die(
895 "Chrome rev must not be %s if chrome_version is not set."
896 % constants.CHROME_REV_SPEC
897 )
Brian Harring3fec5a82012-03-01 05:57:03 -0800898
Alex Klein1699fab2022-09-08 08:46:06 -0600899 patches = bool(options.gerrit_patches)
Ryan Cuieaa9efd2012-04-25 17:56:45 -0700900
Alex Klein9e7b29e2023-04-11 16:10:31 -0600901 # When running in release mode, make sure we are running with checked-in
902 # code. We want checked-in cbuildbot/scripts to prevent errors, and we want
903 # to build a release image with checked-in code for CrOS packages.
Alex Klein1699fab2022-09-08 08:46:06 -0600904 if options.buildbot and patches and not options.debug:
905 cros_build_lib.Die(
906 "Cannot provide patches when running with --buildbot!"
907 )
David James5734ea32012-08-15 20:23:49 -0700908
Alex Klein1699fab2022-09-08 08:46:06 -0600909 if options.buildbot and options.remote_trybot:
910 cros_build_lib.Die(
911 "--buildbot and --remote-trybot cannot be used together."
912 )
Ryan Cuiba41ad32012-03-08 17:15:29 -0800913
Alex Klein1699fab2022-09-08 08:46:06 -0600914 # Record whether --debug was set explicitly vs. it was inferred.
915 options.debug_forced = options.debug
916 # We force --debug to be set for builds that are not 'official'.
917 options.debug = options.debug or not options.buildbot
Brian Harring3fec5a82012-03-01 05:57:03 -0800918
Brian Harring3fec5a82012-03-01 05:57:03 -0800919
Mike Frysinger27e21b72018-07-12 14:20:21 -0400920# pylint: disable=unused-argument
Mike Frysinger80bba8a2017-08-18 15:28:36 -0400921def _PostParseCheck(parser, options, site_config):
Alex Klein1699fab2022-09-08 08:46:06 -0600922 """Perform some usage validation after we've parsed the arguments
Brian Harring3fec5a82012-03-01 05:57:03 -0800923
Alex Klein1699fab2022-09-08 08:46:06 -0600924 Args:
Trent Apted66736d82023-05-25 10:38:28 +1000925 parser: Option parser that was used to parse arguments.
926 options: The options returned by optparse.
927 site_config: config_lib.SiteConfig containing all config info.
Alex Klein1699fab2022-09-08 08:46:06 -0600928 """
Don Garrett0a873e02015-06-30 17:55:10 -0700929
Alex Klein1699fab2022-09-08 08:46:06 -0600930 if not options.branch:
931 options.branch = git.GetChromiteTrackingBranch()
Ryan Cuie1e4e662012-05-21 16:39:46 -0700932
Alex Klein1699fab2022-09-08 08:46:06 -0600933 # Because the default cache dir depends on other options, FindCacheDir
934 # always returns None, and we setup the default here.
935 if options.cache_dir is None:
936 # Note, options.sourceroot is set regardless of the path
937 # actually existing.
938 options.cache_dir = os.path.join(options.buildroot, ".cache")
939 options.cache_dir = os.path.abspath(options.cache_dir)
940 parser.ConfigureCacheDir(options.cache_dir)
Brian Harringae0a5322012-09-15 01:46:51 -0700941
Alex Klein1699fab2022-09-08 08:46:06 -0600942 osutils.SafeMakedirsNonRoot(options.cache_dir)
Ryan Cui5ba7e152012-05-10 14:36:52 -0700943
Alex Klein1699fab2022-09-08 08:46:06 -0600944 # Ensure that all args are legitimate config targets.
945 if options.build_config_name not in site_config:
946 cros_build_lib.Die(
947 'Unknown build config: "%s"' % options.build_config_name
948 )
Don Garrett4bb21682014-03-03 16:16:23 -0800949
Alex Klein1699fab2022-09-08 08:46:06 -0600950 build_config = site_config[options.build_config_name]
951 is_payloads_build = build_config.build_type == constants.PAYLOADS_TYPE
Don Garrett4af20982015-05-29 19:02:23 -0700952
Alex Klein1699fab2022-09-08 08:46:06 -0600953 if options.channels and not is_payloads_build:
954 cros_build_lib.Die(
955 "--channel must only be used with a payload config,"
956 " not target (%s)." % options.build_config_name
957 )
Don Garrett5af1d262014-05-16 15:49:37 -0700958
Alex Klein1699fab2022-09-08 08:46:06 -0600959 if not options.channels and is_payloads_build:
960 cros_build_lib.Die(
Trent Apted66736d82023-05-25 10:38:28 +1000961 "payload configs (%s) require --channel to do anything useful."
962 % options.build_config_name
Alex Klein1699fab2022-09-08 08:46:06 -0600963 )
Matt Tennant763497d2014-01-17 16:45:54 -0800964
Alex Klein1699fab2022-09-08 08:46:06 -0600965 # If the build config explicitly forces the debug flag, set the debug flag
966 # as if it was set from the command line.
967 if build_config.debug:
968 options.debug = True
Don Garrett370839f2017-10-19 18:32:34 -0700969
Alex Klein1699fab2022-09-08 08:46:06 -0600970 if not (config_lib.isTryjobConfig(build_config) or options.buildbot):
971 cros_build_lib.Die(
972 "Refusing to run non-tryjob config as a tryjob.\n"
973 'Please "repo sync && cros tryjob --list %s" for alternatives.\n'
974 "See go/cros-explicit-tryjob-build-configs-psa.",
975 build_config.name,
976 )
Don Garrett02d2f582017-11-08 14:01:24 -0800977
Alex Klein1699fab2022-09-08 08:46:06 -0600978 # The --version option is not compatible with an external target unless the
979 # --buildbot option is specified. More correctly, only "paladin versions"
980 # will work with external targets, and those are only used with --buildbot.
981 # If --buildbot is specified, then user should know what they are doing and
982 # only specify a version that will work. See crbug.com/311648.
983 if options.force_version and not (
984 options.buildbot or build_config.internal
985 ):
986 cros_build_lib.Die(
987 "Cannot specify --version without --buildbot for an"
988 " external target (%s)." % options.build_config_name
989 )
Matt Tennant763497d2014-01-17 16:45:54 -0800990
Ryan Cui85867972012-02-23 18:21:49 -0800991
Don Garrett597ddff2017-02-17 18:29:37 -0800992def ParseCommandLine(parser, argv):
Alex Klein1699fab2022-09-08 08:46:06 -0600993 """Completely parse the commandline arguments"""
994 (options, args) = parser.parse_args(argv)
Brian Harring37e559b2012-05-22 20:47:32 -0700995
Alex Klein1699fab2022-09-08 08:46:06 -0600996 # Handle the request for the reexec command line API version number.
997 if options.output_api_version:
998 print(constants.REEXEC_API_VERSION)
999 sys.exit(0)
Brian Harring37e559b2012-05-22 20:47:32 -07001000
Alex Klein1699fab2022-09-08 08:46:06 -06001001 # Record the configs targeted. Strip out null arguments.
1002 build_config_names = [x for x in args if x]
1003 if len(build_config_names) != 1:
1004 cros_build_lib.Die(
1005 "Expected exactly one build config. Got: %r", build_config_names
1006 )
1007 options.build_config_name = build_config_names[-1]
Don Garrettf0761152017-10-19 19:38:27 -07001008
Alex Klein1699fab2022-09-08 08:46:06 -06001009 _FinishParsing(options)
1010 return options
Ryan Cui85867972012-02-23 18:21:49 -08001011
1012
Alex Klein1699fab2022-09-08 08:46:06 -06001013_ENVIRONMENT_PROD = "prod"
1014_ENVIRONMENT_DEBUG = "debug"
1015_ENVIRONMENT_STANDALONE = "standalone"
Aviv Keshet420de512015-05-18 14:28:48 -07001016
1017
1018def _GetRunEnvironment(options, build_config):
Alex Klein1699fab2022-09-08 08:46:06 -06001019 """Determine whether this is a prod/debug/standalone run."""
1020 if options.debug_cidb:
1021 return _ENVIRONMENT_DEBUG
Don Garretta90f0142018-02-28 14:25:19 -08001022
Alex Klein1699fab2022-09-08 08:46:06 -06001023 # One of these arguments should always be set if running on a real builder.
1024 # If we aren't on a real builder, we are standalone.
1025 if not options.buildbot and not options.remote_trybot:
1026 return _ENVIRONMENT_STANDALONE
Aviv Keshet420de512015-05-18 14:28:48 -07001027
Alex Klein1699fab2022-09-08 08:46:06 -06001028 if build_config["debug_cidb"]:
1029 return _ENVIRONMENT_DEBUG
Aviv Keshet420de512015-05-18 14:28:48 -07001030
Alex Klein1699fab2022-09-08 08:46:06 -06001031 return _ENVIRONMENT_PROD
Aviv Keshet420de512015-05-18 14:28:48 -07001032
1033
Gabe Blackde694a32015-02-19 15:11:11 -08001034def _SetupConnections(options, build_config):
George Engelbrecht7e07c702022-09-19 17:03:55 -06001035 """Set up CIDB connections using the appropriate Setup call.
Aviv Keshet2982af52014-08-13 16:07:57 -07001036
Alex Klein1699fab2022-09-08 08:46:06 -06001037 Args:
Trent Apted66736d82023-05-25 10:38:28 +10001038 options: Command line options structure.
1039 build_config: Config object for this build.
Alex Klein1699fab2022-09-08 08:46:06 -06001040 """
George Engelbrecht7e07c702022-09-19 17:03:55 -06001041 # Outline:
1042 # 1) Based on options and build_config, decide whether we are a production
1043 # run, debug run, or standalone run.
1044 # 2) Set up cidb instance accordingly.
Alex Klein9e7b29e2023-04-11 16:10:31 -06001045 # 3) Update topology info from cidb, so that any other service set up can
1046 # use topology.
George Engelbrecht7e07c702022-09-19 17:03:55 -06001047 # 4) Set up any other services.
1048 run_type = _GetRunEnvironment(options, build_config)
1049
1050 if run_type == _ENVIRONMENT_PROD:
1051 cidb.CIDBConnectionFactory.SetupProdCidb()
1052 context = ts_mon_config.SetupTsMonGlobalState(
1053 "cbuildbot", indirect=True
1054 )
1055 elif run_type == _ENVIRONMENT_DEBUG:
1056 cidb.CIDBConnectionFactory.SetupDebugCidb()
1057 context = ts_mon_config.TrivialContextManager()
1058 else:
1059 cidb.CIDBConnectionFactory.SetupNoCidb()
1060 context = ts_mon_config.TrivialContextManager()
Aviv Keshet62d1a0e2014-08-22 21:16:13 -07001061
Alex Klein1699fab2022-09-08 08:46:06 -06001062 topology.FetchTopology()
1063 return context
Paul Hobbsd5a0f812016-07-26 16:10:31 -07001064
Aviv Keshet2982af52014-08-13 16:07:57 -07001065
Alex Klein074f94f2023-06-22 10:32:06 -06001066class _MockMethodWithReturnValue:
Alex Klein1699fab2022-09-08 08:46:06 -06001067 """A method mocker which just returns the specific value."""
Dean Liaoe5b0aca2018-01-24 15:27:26 +08001068
Alex Klein1699fab2022-09-08 08:46:06 -06001069 def __init__(self, return_value):
1070 self.return_value = return_value
1071
1072 def __call__(self, *args, **kwargs):
1073 return self.return_value
Dean Liaoe5b0aca2018-01-24 15:27:26 +08001074
1075
Alex Klein074f94f2023-06-22 10:32:06 -06001076class _ObjectMethodPatcher:
Alex Klein1699fab2022-09-08 08:46:06 -06001077 """A simplified mock.object.patch.
Dean Liaoe5b0aca2018-01-24 15:27:26 +08001078
Alex Klein1699fab2022-09-08 08:46:06 -06001079 It is a context manager that patches an object's method with specified
1080 return value.
Dean Liaoe5b0aca2018-01-24 15:27:26 +08001081 """
Dean Liaoe5b0aca2018-01-24 15:27:26 +08001082
Alex Klein1699fab2022-09-08 08:46:06 -06001083 def __init__(self, target, attr, return_value=None):
1084 """Constructor.
Dean Liaoe5b0aca2018-01-24 15:27:26 +08001085
Alex Klein1699fab2022-09-08 08:46:06 -06001086 Args:
Trent Apted66736d82023-05-25 10:38:28 +10001087 target: object to patch.
1088 attr: method name of the object to patch.
1089 return_value: the return value when calling target.attr
Alex Klein1699fab2022-09-08 08:46:06 -06001090 """
1091 self.target = target
1092 self.attr = attr
1093 self.return_value = return_value
1094 self.original_attr = None
1095 self.new_attr = _MockMethodWithReturnValue(self.return_value)
1096
1097 def __enter__(self):
1098 self.original_attr = self.target.__dict__[self.attr]
1099 setattr(self.target, self.attr, self.new_attr)
1100
1101 def __exit__(self, *args):
1102 if self.target and self.original_attr:
1103 setattr(self.target, self.attr, self.original_attr)
Dean Liaoe5b0aca2018-01-24 15:27:26 +08001104
1105
Matt Tennant759e2352013-09-27 15:14:44 -07001106# TODO(build): This function is too damn long.
Ryan Cui85867972012-02-23 18:21:49 -08001107def main(argv):
Alex Klein1699fab2022-09-08 08:46:06 -06001108 # We get false positives with the options object.
1109 # pylint: disable=attribute-defined-outside-init
Mike Frysinger80bba8a2017-08-18 15:28:36 -04001110
Alex Klein1699fab2022-09-08 08:46:06 -06001111 # Turn on strict sudo checks.
1112 cros_build_lib.STRICT_SUDO = True
David James59a0a2b2013-03-22 14:04:44 -07001113
Alex Klein1699fab2022-09-08 08:46:06 -06001114 # Set umask to 022 so files created by buildbot are readable.
1115 os.umask(0o22)
Ryan Cui85867972012-02-23 18:21:49 -08001116
Alex Klein1699fab2022-09-08 08:46:06 -06001117 parser = _CreateParser()
1118 options = ParseCommandLine(parser, argv)
Don Garrett0a873e02015-06-30 17:55:10 -07001119
Alex Klein1699fab2022-09-08 08:46:06 -06001120 # Fetch our site_config now, because we need it to do anything else.
1121 site_config = config_lib.GetConfig()
Don Garrettb85658c2015-06-30 19:07:22 -07001122
Alex Klein1699fab2022-09-08 08:46:06 -06001123 _PostParseCheck(parser, options, site_config)
Brian Harring3fec5a82012-03-01 05:57:03 -08001124
Alex Klein1699fab2022-09-08 08:46:06 -06001125 cros_build_lib.AssertOutsideChroot()
Zdenek Behan98ec2fb2012-08-31 17:12:18 +02001126
Alex Klein1699fab2022-09-08 08:46:06 -06001127 if options.enable_buildbot_tags:
1128 cbuildbot_alerts.EnableBuildbotMarkers()
Matt Tennant759e2352013-09-27 15:14:44 -07001129
Alex Klein1699fab2022-09-08 08:46:06 -06001130 if (
1131 options.buildbot
1132 and not options.debug
1133 and not cros_build_lib.HostIsCIBuilder()
1134 ):
1135 # --buildbot can only be used on a real builder, unless it's debug.
1136 cros_build_lib.Die("This host is not a supported build machine.")
Ningning Xiac691e432016-08-11 14:52:59 -07001137
Alex Klein1699fab2022-09-08 08:46:06 -06001138 # Only one config arg is allowed in this mode, which was confirmed earlier.
1139 build_config = site_config[options.build_config_name]
Brian Harring3fec5a82012-03-01 05:57:03 -08001140
Alex Klein1699fab2022-09-08 08:46:06 -06001141 # TODO: Re-enable this block when reference_repo support handles this
1142 # properly. (see chromium:330775)
1143 # if options.reference_repo is None:
1144 # repo_path = os.path.join(options.sourceroot, '.repo')
1145 # # If we're being run from a repo checkout, reuse the repo's git pool to
1146 # # cut down on sync time.
1147 # if os.path.exists(repo_path):
1148 # options.reference_repo = options.sourceroot
Don Garrettbbd7b552014-05-16 13:15:21 -07001149
Alex Klein1699fab2022-09-08 08:46:06 -06001150 if options.reference_repo:
1151 if not os.path.exists(options.reference_repo):
1152 parser.error(
1153 "Reference path %s does not exist" % (options.reference_repo,)
1154 )
1155 elif not os.path.exists(os.path.join(options.reference_repo, ".repo")):
1156 parser.error(
1157 "Reference path %s does not look to be the base of a "
1158 "repo checkout; no .repo exists in the root."
1159 % (options.reference_repo,)
1160 )
David Jamesdac7a912013-11-18 11:14:44 -08001161
Alex Klein1699fab2022-09-08 08:46:06 -06001162 if (options.buildbot or options.remote_trybot) and not options.resume:
1163 missing = osutils.FindMissingBinaries(_BUILDBOT_REQUIRED_BINARIES)
1164 if missing:
1165 parser.error(
1166 "Option --buildbot/--remote-trybot requires the following "
1167 "binaries which couldn't be found in $PATH: %s"
Trent Apted66736d82023-05-25 10:38:28 +10001168 % ", ".join(missing)
Alex Klein1699fab2022-09-08 08:46:06 -06001169 )
Brian Harring351ce442012-03-09 16:38:14 -08001170
Alex Klein1699fab2022-09-08 08:46:06 -06001171 if options.reference_repo:
1172 options.reference_repo = os.path.abspath(options.reference_repo)
David Jamesdac7a912013-11-18 11:14:44 -08001173
Alex Klein1699fab2022-09-08 08:46:06 -06001174 # Sanity check of buildroot- specifically that it's not pointing into the
1175 # midst of an existing repo since git-repo doesn't support nesting.
1176 if not repository.IsARepoRoot(options.buildroot) and git.FindRepoDir(
1177 options.buildroot
1178 ):
1179 cros_build_lib.Die(
1180 "Configured buildroot %s is a subdir of an existing repo checkout."
1181 % options.buildroot
1182 )
Brian Harring3fec5a82012-03-01 05:57:03 -08001183
Alex Klein1699fab2022-09-08 08:46:06 -06001184 if not options.log_dir:
1185 options.log_dir = os.path.join(options.buildroot, _DEFAULT_LOG_DIR)
Chris Sosab5ea3b42012-10-25 15:25:20 -07001186
Alex Klein1699fab2022-09-08 08:46:06 -06001187 log_file = None
1188 if options.tee:
1189 log_file = os.path.join(options.log_dir, _BUILDBOT_LOG_FILE)
1190 osutils.SafeMakedirs(options.log_dir)
1191 _BackupPreviousLog(log_file)
Brian Harringd166aaf2012-05-14 18:31:53 -07001192
Mike Frysinger321fecd2023-06-16 10:40:51 -04001193 with contextlib.ExitStack() as stack:
Alex Klein1699fab2022-09-08 08:46:06 -06001194 # Preserve chromite; we might be running from there!
1195 options.preserve_paths = set(["chromite"])
1196 if log_file is not None:
Alex Klein9e7b29e2023-04-11 16:10:31 -06001197 # We don't want the critical section to try to clean up the tee
1198 # process, so we run Tee (forked off) outside of it. This prevents a
1199 # deadlock because the Tee process only exits when its pipe is
1200 # closed, and the critical section accidentally holds on to that
1201 # file handle.
Mike Frysinger321fecd2023-06-16 10:40:51 -04001202 stack.enter_context(tee.Tee(log_file))
Alex Klein1699fab2022-09-08 08:46:06 -06001203 options.preserve_paths.add(_DEFAULT_LOG_DIR)
David Jamescebc7272013-07-17 16:45:05 -07001204
Mike Frysinger321fecd2023-06-16 10:40:51 -04001205 critical_section = stack.enter_context(cleanup.EnforcedCleanupSection())
1206 stack.enter_context(sudo.SudoKeepAlive())
Brian Harringd166aaf2012-05-14 18:31:53 -07001207
Alex Klein1699fab2022-09-08 08:46:06 -06001208 if not options.resume:
1209 # If we're in resume mode, use our parents tempdir rather than
1210 # nesting another layer.
Mike Frysinger321fecd2023-06-16 10:40:51 -04001211 stack.enter_context(osutils.TempDir(prefix="cbb", set_global=True))
Alex Klein1699fab2022-09-08 08:46:06 -06001212 logging.debug("Cbuildbot tempdir is %r.", os.environ.get("TMP"))
Brian Harringd166aaf2012-05-14 18:31:53 -07001213
Alex Klein1699fab2022-09-08 08:46:06 -06001214 if options.cgroups:
Mike Frysinger321fecd2023-06-16 10:40:51 -04001215 stack.enter_context(cgroups.SimpleContainChildren("cbuildbot"))
Brian Harringa184efa2012-03-04 11:51:25 -08001216
Alex Klein1699fab2022-09-08 08:46:06 -06001217 # Mark everything between EnforcedCleanupSection and here as having to
1218 # be rolled back via the contextmanager cleanup handlers. This
1219 # ensures that sudo bits cannot outlive cbuildbot, that anything
1220 # cgroups would kill gets killed, etc.
Mike Frysinger321fecd2023-06-16 10:40:51 -04001221 stack.enter_context(critical_section.ForkWatchdog())
Brian Harringd166aaf2012-05-14 18:31:53 -07001222
Alex Klein1699fab2022-09-08 08:46:06 -06001223 if options.mock_slave_status is not None:
Mike Frysinger31fdddd2023-02-24 15:50:55 -05001224 with open(options.mock_slave_status, "rb") as f:
Alex Klein1699fab2022-09-08 08:46:06 -06001225 mock_statuses = pickle.load(f)
1226 for key, value in mock_statuses.items():
1227 mock_statuses[key] = builder_status_lib.BuilderStatus(
1228 **value
1229 )
Mike Frysinger321fecd2023-06-16 10:40:51 -04001230 stack.enter_context(
1231 _ObjectMethodPatcher(
1232 completion_stages.MasterSlaveSyncCompletionStage,
1233 "_FetchSlaveStatuses",
1234 return_value=mock_statuses,
1235 )
Alex Klein1699fab2022-09-08 08:46:06 -06001236 )
Aviv Keshetcf9c2722014-02-25 15:15:10 -08001237
Mike Frysinger321fecd2023-06-16 10:40:51 -04001238 stack.enter_context(_SetupConnections(options, build_config))
Alex Klein1699fab2022-09-08 08:46:06 -06001239 retry_stats.SetupStats()
Aviv Keshet2982af52014-08-13 16:07:57 -07001240
Alex Klein1699fab2022-09-08 08:46:06 -06001241 timeout_display_message = (
1242 "This build has reached the timeout deadline set by the master. "
1243 "Either this stage or a previous one took too long (see stage "
1244 "timing historical summary in ReportStage) or the build failed "
1245 "to start on time."
1246 )
Prathmesh Prabhu80e05df2014-12-11 15:20:33 -08001247
Alex Klein1699fab2022-09-08 08:46:06 -06001248 if options.timeout > 0:
Mike Frysinger321fecd2023-06-16 10:40:51 -04001249 stack.enter_context(
1250 timeout_util.FatalTimeout(
1251 options.timeout,
1252 timeout_display_message,
1253 )
Alex Klein1699fab2022-09-08 08:46:06 -06001254 )
1255 try:
1256 _RunBuildStagesWrapper(options, site_config, build_config)
1257 except failures_lib.ExitEarlyException as ex:
Alex Klein9e7b29e2023-04-11 16:10:31 -06001258 # This build finished successfully. Do not re-raise
1259 # ExitEarlyException.
Alex Klein1699fab2022-09-08 08:46:06 -06001260 logging.info("One stage exited early: %s", ex)