blob: 3597279defe80e3cb0b7497a9762066689a90694 [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(
Alex Klein1699fab2022-09-08 08:46:06 -0600534 "--noreexec",
535 action="store_false",
536 dest="postsync_reexec",
537 default=True,
538 help="Don't reexec into the buildroot after syncing.",
539 )
540 group.add_remote_option(
541 "--nosdk",
542 action="store_true",
543 default=False,
544 help="Re-create the SDK from scratch.",
545 )
546 group.add_remote_option(
547 "--nosync",
548 action="store_false",
549 dest="sync",
550 default=True,
551 help="Don't sync before building.",
552 )
553 group.add_remote_option(
554 "--notests",
555 action="store_false",
556 dest="tests",
557 default=True,
Trent Apted66736d82023-05-25 10:38:28 +1000558 help=(
559 "Override values from buildconfig, run no "
560 "tests, and build no autotest and artifacts."
561 ),
Alex Klein1699fab2022-09-08 08:46:06 -0600562 )
563 group.add_remote_option(
564 "--novmtests",
565 action="store_false",
566 dest="vmtests",
567 default=True,
Trent Apted66736d82023-05-25 10:38:28 +1000568 help="Override values from buildconfig, run no vmtests.",
Alex Klein1699fab2022-09-08 08:46:06 -0600569 )
570 group.add_remote_option(
571 "--noimagetests",
572 action="store_false",
573 dest="image_test",
574 default=True,
Trent Apted66736d82023-05-25 10:38:28 +1000575 help="Override values from buildconfig and run no image tests.",
Alex Klein1699fab2022-09-08 08:46:06 -0600576 )
577 group.add_remote_option(
578 "--nouprev",
579 action="store_false",
580 dest="uprev",
581 default=True,
Trent Apted66736d82023-05-25 10:38:28 +1000582 help="Override values from buildconfig and never uprev.",
Alex Klein1699fab2022-09-08 08:46:06 -0600583 )
584 group.add_option(
585 "--reference-repo",
Trent Apted66736d82023-05-25 10:38:28 +1000586 help=(
587 "Reuse git data stored in an existing repo "
588 "checkout. This can drastically reduce the network "
589 "time spent setting up the trybot checkout. By "
590 "default, if this option isn't given but cbuildbot "
591 "is invoked from a repo checkout, cbuildbot will "
592 "use the repo root."
593 ),
Alex Klein1699fab2022-09-08 08:46:06 -0600594 )
595 group.add_option(
596 "--resume",
597 action="store_true",
598 default=False,
599 help="Skip stages already successfully completed.",
600 )
601 group.add_remote_option(
602 "--timeout",
603 type="int",
604 default=0,
Trent Apted66736d82023-05-25 10:38:28 +1000605 help=(
606 "Specify the maximum amount of time this job "
607 "can run for, at which point the build will be "
608 "aborted. If set to zero, then there is no "
609 "timeout."
610 ),
Alex Klein1699fab2022-09-08 08:46:06 -0600611 )
612 group.add_remote_option(
613 "--version",
614 dest="force_version",
Trent Apted66736d82023-05-25 10:38:28 +1000615 help=(
616 "Used with manifest logic. Forces use of this "
617 "version rather than create or get latest. "
618 "Examples: 4815.0.0-rc1, 4815.1.2"
619 ),
Alex Klein1699fab2022-09-08 08:46:06 -0600620 )
621 group.add_remote_option(
622 "--git-cache-dir",
623 type="path",
624 api=constants.REEXEC_API_GIT_CACHE_DIR,
Trent Apted66736d82023-05-25 10:38:28 +1000625 help=(
626 "Specify the cache directory to store the "
627 "project caches populated by the git-cache "
628 "tool. Bootstrap the projects based on the git "
629 "cache files instead of fetching them directly "
630 "from the GoB servers."
631 ),
Alex Klein1699fab2022-09-08 08:46:06 -0600632 )
633 group.add_remote_option(
634 "--chrome-preload-dir",
635 type="path",
636 api=constants.REEXEC_API_CHROME_PRELOAD_DIR,
Trent Apted66736d82023-05-25 10:38:28 +1000637 help=(
638 "Specify a preloaded chrome source cache "
639 "directory populated by the git-cache tool. "
640 "Bootstrap chrome based on the cached files "
641 "instead of fetching them directly from the GoB "
642 "servers. When both this argument and "
643 "--git-cache-dir are provided this value will "
644 "be preferred for the chrome source cache."
645 ),
Alex Klein1699fab2022-09-08 08:46:06 -0600646 )
647 group.add_remote_option(
648 "--source_cache",
649 action="store_true",
650 default=False,
651 help="Whether to utilize cache snapshot mounts.",
652 )
653 group.add_remote_option(
654 "--debug-cidb",
655 action="store_true",
656 default=False,
657 help="Force Debug CIDB to be used.",
658 )
659 # cbuildbot ChromeOS Findit options
660 group.add_remote_option(
661 "--cbb_build_packages",
662 action="split_extend",
663 dest="cbb_build_packages",
664 default=[],
Trent Apted66736d82023-05-25 10:38:28 +1000665 help=(
666 "Specify an explicit list of packages to build "
667 "for integration with Findit."
668 ),
Alex Klein1699fab2022-09-08 08:46:06 -0600669 )
670 group.add_remote_option(
671 "--cbb_snapshot_revision",
672 type="string",
673 dest="cbb_snapshot_revision",
674 default=None,
Trent Apted66736d82023-05-25 10:38:28 +1000675 help="Snapshot manifest revision to sync to for building.",
Alex Klein1699fab2022-09-08 08:46:06 -0600676 )
677 group.add_remote_option(
678 "--no-publish-prebuilt-confs",
679 dest="publish",
680 action="store_false",
681 default=True,
682 help="Don't publish git commits to prebuilt.conf or sdk_version.conf",
683 )
Mike Frysinger81af6ef2013-04-03 02:24:09 -0400684
Alex Klein1699fab2022-09-08 08:46:06 -0600685 parser.add_argument_group(group)
Mike Frysinger81af6ef2013-04-03 02:24:09 -0400686
Alex Klein1699fab2022-09-08 08:46:06 -0600687 #
688 # Internal options.
689 #
Mike Frysinger81af6ef2013-04-03 02:24:09 -0400690
Alex Klein1699fab2022-09-08 08:46:06 -0600691 group = CustomGroup(
692 parser,
693 "Internal Chromium OS Build Team Options",
694 "Caution: these are for meant for the Chromium OS build team only",
695 )
Mike Frysinger81af6ef2013-04-03 02:24:09 -0400696
Alex Klein1699fab2022-09-08 08:46:06 -0600697 group.add_remote_option(
698 "--archive-base",
699 type="gs_path",
Trent Apted66736d82023-05-25 10:38:28 +1000700 help=(
701 "Base GS URL (gs://<bucket_name>/<path>) to "
702 "upload archive artifacts to"
703 ),
Alex Klein1699fab2022-09-08 08:46:06 -0600704 )
705 group.add_remote_option(
706 "--cq-gerrit-query",
707 dest="cq_gerrit_override",
Trent Apted66736d82023-05-25 10:38:28 +1000708 help=(
709 "If given, this gerrit query will be used to find what patches to "
710 "test, rather than the normal 'CommitQueue>=1 AND Verified=1 AND "
711 "CodeReview=2' query it defaults to. Use with care- note "
712 "additionally this setting only has an effect if the buildbot "
713 "target is a cq target, and we're in buildbot mode."
714 ),
Alex Klein1699fab2022-09-08 08:46:06 -0600715 )
716 group.add_option(
717 "--pass-through",
718 action="append",
719 type="string",
720 dest="pass_through_args",
721 default=[],
722 )
723 group.add_option(
724 "--reexec-api-version",
725 action="store_true",
726 dest="output_api_version",
727 default=False,
Trent Apted66736d82023-05-25 10:38:28 +1000728 help=(
729 "Used for handling forwards/backwards compatibility "
730 "with --resume and --bootstrap"
731 ),
Alex Klein1699fab2022-09-08 08:46:06 -0600732 )
733 group.add_option(
734 "--remote-trybot",
735 action="store_true",
736 default=False,
737 help="Indicates this is running on a remote trybot machine",
738 )
739 group.add_option(
740 "--buildbucket-id",
741 api=constants.REEXEC_API_GOMA, # Approximate.
Trent Apted66736d82023-05-25 10:38:28 +1000742 help=(
743 "The unique ID in buildbucket of current build "
744 "generated by buildbucket."
745 ),
Alex Klein1699fab2022-09-08 08:46:06 -0600746 )
747 group.add_remote_option(
748 "--remote-patches",
749 action="split_extend",
750 default=[],
Trent Apted66736d82023-05-25 10:38:28 +1000751 help=(
752 "Patches uploaded by the trybot client when run using the -p option"
753 ),
Alex Klein1699fab2022-09-08 08:46:06 -0600754 )
755 # Note the default here needs to be hardcoded to 3; that is the last version
756 # that lacked this functionality.
757 group.add_option(
758 "--remote-version",
759 type="int",
760 default=3,
761 help="Deprecated and ignored.",
762 )
763 group.add_option("--sourceroot", type="path", default=constants.SOURCE_ROOT)
764 group.add_remote_option(
765 "--test-bootstrap",
766 action="store_true",
767 default=False,
Trent Apted66736d82023-05-25 10:38:28 +1000768 help=(
769 "Causes cbuildbot to bootstrap itself twice, "
770 "in the sequence A->B->C: A(unpatched) patches "
771 "and bootstraps B; B patches and bootstraps C"
772 ),
Alex Klein1699fab2022-09-08 08:46:06 -0600773 )
774 group.add_remote_option(
775 "--validation_pool",
Trent Apted66736d82023-05-25 10:38:28 +1000776 help=(
777 "Path to a pickled validation pool. Intended "
778 "for use only with the commit queue."
779 ),
Alex Klein1699fab2022-09-08 08:46:06 -0600780 )
781 group.add_remote_option(
782 "--metadata_dump",
Trent Apted66736d82023-05-25 10:38:28 +1000783 help=(
784 "Path to a json dumped metadata file. This "
785 "will be used as the initial metadata."
786 ),
Alex Klein1699fab2022-09-08 08:46:06 -0600787 )
788 group.add_remote_option(
789 "--master-build-id",
790 type="int",
791 api=constants.REEXEC_API_MASTER_BUILD_ID,
Trent Apted66736d82023-05-25 10:38:28 +1000792 help="cidb build id of the master build to this slave build.",
Alex Klein1699fab2022-09-08 08:46:06 -0600793 )
794 group.add_remote_option(
795 "--master-buildbucket-id",
796 api=constants.REEXEC_API_MASTER_BUILDBUCKET_ID,
Trent Apted66736d82023-05-25 10:38:28 +1000797 help="buildbucket id of the master build to this slave build.",
Alex Klein1699fab2022-09-08 08:46:06 -0600798 )
799 # TODO(nxia): crbug.com/778838
800 # cbuildbot doesn't use pickle files anymore, remove this.
801 group.add_remote_option(
802 "--mock-slave-status",
803 metavar="MOCK_SLAVE_STATUS_PICKLE_FILE",
Trent Apted66736d82023-05-25 10:38:28 +1000804 help=(
805 "Override the result of the _FetchSlaveStatuses "
806 "method of MasterSlaveSyncCompletionStage, by "
807 "specifying a file with a pickle of the result "
808 "to be returned."
809 ),
Alex Klein1699fab2022-09-08 08:46:06 -0600810 )
811 group.add_option(
812 "--previous-build-state",
813 type="string",
814 default="",
815 api=constants.REEXEC_API_PREVIOUS_BUILD_STATE,
Trent Apted66736d82023-05-25 10:38:28 +1000816 help=(
817 "A base64-encoded BuildSummary object describing the "
818 "previous build run on the same build machine."
819 ),
Alex Klein1699fab2022-09-08 08:46:06 -0600820 )
Mike Frysinger81af6ef2013-04-03 02:24:09 -0400821
Alex Klein1699fab2022-09-08 08:46:06 -0600822 parser.add_argument_group(group)
Ryan Cuif4f84be2012-07-09 18:50:41 -0700823
Alex Klein1699fab2022-09-08 08:46:06 -0600824 #
825 # Debug options
826 #
827 # Temporary hack; in place till --dry-run replaces --debug.
828 # pylint: disable=protected-access
829 group = parser.debug_group
830 debug = [x for x in group.option_list if x._long_opts == ["--debug"]][0]
831 debug.help += " Currently functions as --dry-run in addition."
832 debug.pass_through = True
833 group.add_option(
834 "--notee",
835 action="store_false",
836 dest="tee",
837 default=True,
Trent Apted66736d82023-05-25 10:38:28 +1000838 help=(
839 "Disable logging and internal tee process. Primarily "
840 "used for debugging cbuildbot itself."
841 ),
Alex Klein1699fab2022-09-08 08:46:06 -0600842 )
843 return parser
Brian Harring3fec5a82012-03-01 05:57:03 -0800844
845
Mike Frysinger80bba8a2017-08-18 15:28:36 -0400846def _FinishParsing(options):
Alex Klein1699fab2022-09-08 08:46:06 -0600847 """Perform some parsing tasks that need to take place after optparse.
Ryan Cui85867972012-02-23 18:21:49 -0800848
Alex Klein1699fab2022-09-08 08:46:06 -0600849 This function needs to be easily testable! Keep it free of
850 environment-dependent code. Put more detailed usage validation in
851 _PostParseCheck().
Brian Harring3fec5a82012-03-01 05:57:03 -0800852
Alex Klein1699fab2022-09-08 08:46:06 -0600853 Args:
Trent Apted66736d82023-05-25 10:38:28 +1000854 options: The options object returned by optparse
Alex Klein1699fab2022-09-08 08:46:06 -0600855 """
856 # Populate options.pass_through_args.
857 accepted, _ = commandline.FilteringParser.FilterArgs(
858 options.parsed_args, lambda x: x.opt_inst.pass_through
859 )
860 options.pass_through_args.extend(accepted)
Brian Harring07039b52012-05-13 17:56:47 -0700861
Alex Klein1699fab2022-09-08 08:46:06 -0600862 if options.local or options.remote:
863 cros_build_lib.Die("Deprecated usage. Please use cros tryjob instead.")
Don Garrettcc0ee522017-09-13 14:28:42 -0700864
Alex Klein1699fab2022-09-08 08:46:06 -0600865 if not options.buildroot:
866 cros_build_lib.Die("A buildroot is required to build.")
Don Garrett211df8c2017-09-06 13:33:02 -0700867
Alex Klein1699fab2022-09-08 08:46:06 -0600868 if options.chrome_root:
869 if options.chrome_rev != constants.CHROME_REV_LOCAL:
870 cros_build_lib.Die(
871 "Chrome rev must be %s if chrome_root is set."
872 % constants.CHROME_REV_LOCAL
873 )
874 elif options.chrome_rev == constants.CHROME_REV_LOCAL:
875 cros_build_lib.Die(
876 "Chrome root must be set if chrome_rev is %s."
877 % constants.CHROME_REV_LOCAL
878 )
Brian Harring3fec5a82012-03-01 05:57:03 -0800879
Alex Klein1699fab2022-09-08 08:46:06 -0600880 if options.chrome_version:
881 if options.chrome_rev != constants.CHROME_REV_SPEC:
882 cros_build_lib.Die(
883 "Chrome rev must be %s if chrome_version is set."
884 % constants.CHROME_REV_SPEC
885 )
886 elif options.chrome_rev == constants.CHROME_REV_SPEC:
887 cros_build_lib.Die(
888 "Chrome rev must not be %s if chrome_version is not set."
889 % constants.CHROME_REV_SPEC
890 )
Brian Harring3fec5a82012-03-01 05:57:03 -0800891
Alex Klein1699fab2022-09-08 08:46:06 -0600892 patches = bool(options.gerrit_patches)
Ryan Cuieaa9efd2012-04-25 17:56:45 -0700893
Alex Klein9e7b29e2023-04-11 16:10:31 -0600894 # When running in release mode, make sure we are running with checked-in
895 # code. We want checked-in cbuildbot/scripts to prevent errors, and we want
896 # to build a release image with checked-in code for CrOS packages.
Alex Klein1699fab2022-09-08 08:46:06 -0600897 if options.buildbot and patches and not options.debug:
898 cros_build_lib.Die(
899 "Cannot provide patches when running with --buildbot!"
900 )
David James5734ea32012-08-15 20:23:49 -0700901
Alex Klein1699fab2022-09-08 08:46:06 -0600902 if options.buildbot and options.remote_trybot:
903 cros_build_lib.Die(
904 "--buildbot and --remote-trybot cannot be used together."
905 )
Ryan Cuiba41ad32012-03-08 17:15:29 -0800906
Alex Klein1699fab2022-09-08 08:46:06 -0600907 # Record whether --debug was set explicitly vs. it was inferred.
908 options.debug_forced = options.debug
909 # We force --debug to be set for builds that are not 'official'.
910 options.debug = options.debug or not options.buildbot
Brian Harring3fec5a82012-03-01 05:57:03 -0800911
Brian Harring3fec5a82012-03-01 05:57:03 -0800912
Mike Frysinger27e21b72018-07-12 14:20:21 -0400913# pylint: disable=unused-argument
Mike Frysinger80bba8a2017-08-18 15:28:36 -0400914def _PostParseCheck(parser, options, site_config):
Alex Klein1699fab2022-09-08 08:46:06 -0600915 """Perform some usage validation after we've parsed the arguments
Brian Harring3fec5a82012-03-01 05:57:03 -0800916
Alex Klein1699fab2022-09-08 08:46:06 -0600917 Args:
Trent Apted66736d82023-05-25 10:38:28 +1000918 parser: Option parser that was used to parse arguments.
919 options: The options returned by optparse.
920 site_config: config_lib.SiteConfig containing all config info.
Alex Klein1699fab2022-09-08 08:46:06 -0600921 """
Don Garrett0a873e02015-06-30 17:55:10 -0700922
Alex Klein1699fab2022-09-08 08:46:06 -0600923 if not options.branch:
924 options.branch = git.GetChromiteTrackingBranch()
Ryan Cuie1e4e662012-05-21 16:39:46 -0700925
Alex Klein1699fab2022-09-08 08:46:06 -0600926 # Because the default cache dir depends on other options, FindCacheDir
927 # always returns None, and we setup the default here.
928 if options.cache_dir is None:
929 # Note, options.sourceroot is set regardless of the path
930 # actually existing.
931 options.cache_dir = os.path.join(options.buildroot, ".cache")
932 options.cache_dir = os.path.abspath(options.cache_dir)
933 parser.ConfigureCacheDir(options.cache_dir)
Brian Harringae0a5322012-09-15 01:46:51 -0700934
Alex Klein1699fab2022-09-08 08:46:06 -0600935 osutils.SafeMakedirsNonRoot(options.cache_dir)
Ryan Cui5ba7e152012-05-10 14:36:52 -0700936
Alex Klein1699fab2022-09-08 08:46:06 -0600937 # Ensure that all args are legitimate config targets.
938 if options.build_config_name not in site_config:
939 cros_build_lib.Die(
940 'Unknown build config: "%s"' % options.build_config_name
941 )
Don Garrett4bb21682014-03-03 16:16:23 -0800942
Alex Klein1699fab2022-09-08 08:46:06 -0600943 build_config = site_config[options.build_config_name]
Don Garrett4af20982015-05-29 19:02:23 -0700944
Mike Frysingeraf204492023-07-10 02:29:19 -0400945 if options.channels:
Alex Klein1699fab2022-09-08 08:46:06 -0600946 cros_build_lib.Die(
947 "--channel must only be used with a payload config,"
948 " not target (%s)." % options.build_config_name
949 )
Don Garrett5af1d262014-05-16 15:49:37 -0700950
Alex Klein1699fab2022-09-08 08:46:06 -0600951 # If the build config explicitly forces the debug flag, set the debug flag
952 # as if it was set from the command line.
953 if build_config.debug:
954 options.debug = True
Don Garrett370839f2017-10-19 18:32:34 -0700955
Alex Klein1699fab2022-09-08 08:46:06 -0600956 if not (config_lib.isTryjobConfig(build_config) or options.buildbot):
957 cros_build_lib.Die(
958 "Refusing to run non-tryjob config as a tryjob.\n"
959 'Please "repo sync && cros tryjob --list %s" for alternatives.\n'
960 "See go/cros-explicit-tryjob-build-configs-psa.",
961 build_config.name,
962 )
Don Garrett02d2f582017-11-08 14:01:24 -0800963
Alex Klein1699fab2022-09-08 08:46:06 -0600964 # The --version option is not compatible with an external target unless the
965 # --buildbot option is specified. More correctly, only "paladin versions"
966 # will work with external targets, and those are only used with --buildbot.
967 # If --buildbot is specified, then user should know what they are doing and
968 # only specify a version that will work. See crbug.com/311648.
969 if options.force_version and not (
970 options.buildbot or build_config.internal
971 ):
972 cros_build_lib.Die(
973 "Cannot specify --version without --buildbot for an"
974 " external target (%s)." % options.build_config_name
975 )
Matt Tennant763497d2014-01-17 16:45:54 -0800976
Ryan Cui85867972012-02-23 18:21:49 -0800977
Don Garrett597ddff2017-02-17 18:29:37 -0800978def ParseCommandLine(parser, argv):
Alex Klein1699fab2022-09-08 08:46:06 -0600979 """Completely parse the commandline arguments"""
980 (options, args) = parser.parse_args(argv)
Brian Harring37e559b2012-05-22 20:47:32 -0700981
Alex Klein1699fab2022-09-08 08:46:06 -0600982 # Handle the request for the reexec command line API version number.
983 if options.output_api_version:
984 print(constants.REEXEC_API_VERSION)
985 sys.exit(0)
Brian Harring37e559b2012-05-22 20:47:32 -0700986
Alex Klein1699fab2022-09-08 08:46:06 -0600987 # Record the configs targeted. Strip out null arguments.
988 build_config_names = [x for x in args if x]
989 if len(build_config_names) != 1:
990 cros_build_lib.Die(
991 "Expected exactly one build config. Got: %r", build_config_names
992 )
993 options.build_config_name = build_config_names[-1]
Don Garrettf0761152017-10-19 19:38:27 -0700994
Alex Klein1699fab2022-09-08 08:46:06 -0600995 _FinishParsing(options)
996 return options
Ryan Cui85867972012-02-23 18:21:49 -0800997
998
Alex Klein1699fab2022-09-08 08:46:06 -0600999_ENVIRONMENT_PROD = "prod"
1000_ENVIRONMENT_DEBUG = "debug"
1001_ENVIRONMENT_STANDALONE = "standalone"
Aviv Keshet420de512015-05-18 14:28:48 -07001002
1003
1004def _GetRunEnvironment(options, build_config):
Alex Klein1699fab2022-09-08 08:46:06 -06001005 """Determine whether this is a prod/debug/standalone run."""
1006 if options.debug_cidb:
1007 return _ENVIRONMENT_DEBUG
Don Garretta90f0142018-02-28 14:25:19 -08001008
Alex Klein1699fab2022-09-08 08:46:06 -06001009 # One of these arguments should always be set if running on a real builder.
1010 # If we aren't on a real builder, we are standalone.
1011 if not options.buildbot and not options.remote_trybot:
1012 return _ENVIRONMENT_STANDALONE
Aviv Keshet420de512015-05-18 14:28:48 -07001013
Alex Klein1699fab2022-09-08 08:46:06 -06001014 if build_config["debug_cidb"]:
1015 return _ENVIRONMENT_DEBUG
Aviv Keshet420de512015-05-18 14:28:48 -07001016
Alex Klein1699fab2022-09-08 08:46:06 -06001017 return _ENVIRONMENT_PROD
Aviv Keshet420de512015-05-18 14:28:48 -07001018
1019
Gabe Blackde694a32015-02-19 15:11:11 -08001020def _SetupConnections(options, build_config):
George Engelbrecht7e07c702022-09-19 17:03:55 -06001021 """Set up CIDB connections using the appropriate Setup call.
Aviv Keshet2982af52014-08-13 16:07:57 -07001022
Alex Klein1699fab2022-09-08 08:46:06 -06001023 Args:
Trent Apted66736d82023-05-25 10:38:28 +10001024 options: Command line options structure.
1025 build_config: Config object for this build.
Alex Klein1699fab2022-09-08 08:46:06 -06001026 """
George Engelbrecht7e07c702022-09-19 17:03:55 -06001027 # Outline:
1028 # 1) Based on options and build_config, decide whether we are a production
1029 # run, debug run, or standalone run.
1030 # 2) Set up cidb instance accordingly.
Alex Klein9e7b29e2023-04-11 16:10:31 -06001031 # 3) Update topology info from cidb, so that any other service set up can
1032 # use topology.
George Engelbrecht7e07c702022-09-19 17:03:55 -06001033 # 4) Set up any other services.
1034 run_type = _GetRunEnvironment(options, build_config)
1035
1036 if run_type == _ENVIRONMENT_PROD:
1037 cidb.CIDBConnectionFactory.SetupProdCidb()
1038 context = ts_mon_config.SetupTsMonGlobalState(
1039 "cbuildbot", indirect=True
1040 )
1041 elif run_type == _ENVIRONMENT_DEBUG:
1042 cidb.CIDBConnectionFactory.SetupDebugCidb()
1043 context = ts_mon_config.TrivialContextManager()
1044 else:
1045 cidb.CIDBConnectionFactory.SetupNoCidb()
1046 context = ts_mon_config.TrivialContextManager()
Aviv Keshet62d1a0e2014-08-22 21:16:13 -07001047
Alex Klein1699fab2022-09-08 08:46:06 -06001048 topology.FetchTopology()
1049 return context
Paul Hobbsd5a0f812016-07-26 16:10:31 -07001050
Aviv Keshet2982af52014-08-13 16:07:57 -07001051
Alex Klein074f94f2023-06-22 10:32:06 -06001052class _MockMethodWithReturnValue:
Alex Klein1699fab2022-09-08 08:46:06 -06001053 """A method mocker which just returns the specific value."""
Dean Liaoe5b0aca2018-01-24 15:27:26 +08001054
Alex Klein1699fab2022-09-08 08:46:06 -06001055 def __init__(self, return_value):
1056 self.return_value = return_value
1057
1058 def __call__(self, *args, **kwargs):
1059 return self.return_value
Dean Liaoe5b0aca2018-01-24 15:27:26 +08001060
1061
Alex Klein074f94f2023-06-22 10:32:06 -06001062class _ObjectMethodPatcher:
Alex Klein1699fab2022-09-08 08:46:06 -06001063 """A simplified mock.object.patch.
Dean Liaoe5b0aca2018-01-24 15:27:26 +08001064
Alex Klein1699fab2022-09-08 08:46:06 -06001065 It is a context manager that patches an object's method with specified
1066 return value.
Dean Liaoe5b0aca2018-01-24 15:27:26 +08001067 """
Dean Liaoe5b0aca2018-01-24 15:27:26 +08001068
Alex Klein1699fab2022-09-08 08:46:06 -06001069 def __init__(self, target, attr, return_value=None):
1070 """Constructor.
Dean Liaoe5b0aca2018-01-24 15:27:26 +08001071
Alex Klein1699fab2022-09-08 08:46:06 -06001072 Args:
Trent Apted66736d82023-05-25 10:38:28 +10001073 target: object to patch.
1074 attr: method name of the object to patch.
1075 return_value: the return value when calling target.attr
Alex Klein1699fab2022-09-08 08:46:06 -06001076 """
1077 self.target = target
1078 self.attr = attr
1079 self.return_value = return_value
1080 self.original_attr = None
1081 self.new_attr = _MockMethodWithReturnValue(self.return_value)
1082
1083 def __enter__(self):
1084 self.original_attr = self.target.__dict__[self.attr]
1085 setattr(self.target, self.attr, self.new_attr)
1086
1087 def __exit__(self, *args):
1088 if self.target and self.original_attr:
1089 setattr(self.target, self.attr, self.original_attr)
Dean Liaoe5b0aca2018-01-24 15:27:26 +08001090
1091
Matt Tennant759e2352013-09-27 15:14:44 -07001092# TODO(build): This function is too damn long.
Ryan Cui85867972012-02-23 18:21:49 -08001093def main(argv):
Alex Klein1699fab2022-09-08 08:46:06 -06001094 # We get false positives with the options object.
1095 # pylint: disable=attribute-defined-outside-init
Mike Frysinger80bba8a2017-08-18 15:28:36 -04001096
Alex Klein1699fab2022-09-08 08:46:06 -06001097 # Turn on strict sudo checks.
1098 cros_build_lib.STRICT_SUDO = True
David James59a0a2b2013-03-22 14:04:44 -07001099
Alex Klein1699fab2022-09-08 08:46:06 -06001100 # Set umask to 022 so files created by buildbot are readable.
1101 os.umask(0o22)
Ryan Cui85867972012-02-23 18:21:49 -08001102
Alex Klein1699fab2022-09-08 08:46:06 -06001103 parser = _CreateParser()
1104 options = ParseCommandLine(parser, argv)
Don Garrett0a873e02015-06-30 17:55:10 -07001105
Alex Klein1699fab2022-09-08 08:46:06 -06001106 # Fetch our site_config now, because we need it to do anything else.
1107 site_config = config_lib.GetConfig()
Don Garrettb85658c2015-06-30 19:07:22 -07001108
Alex Klein1699fab2022-09-08 08:46:06 -06001109 _PostParseCheck(parser, options, site_config)
Brian Harring3fec5a82012-03-01 05:57:03 -08001110
Alex Klein1699fab2022-09-08 08:46:06 -06001111 cros_build_lib.AssertOutsideChroot()
Zdenek Behan98ec2fb2012-08-31 17:12:18 +02001112
Alex Klein1699fab2022-09-08 08:46:06 -06001113 if options.enable_buildbot_tags:
1114 cbuildbot_alerts.EnableBuildbotMarkers()
Matt Tennant759e2352013-09-27 15:14:44 -07001115
Alex Klein1699fab2022-09-08 08:46:06 -06001116 if (
1117 options.buildbot
1118 and not options.debug
1119 and not cros_build_lib.HostIsCIBuilder()
1120 ):
1121 # --buildbot can only be used on a real builder, unless it's debug.
1122 cros_build_lib.Die("This host is not a supported build machine.")
Ningning Xiac691e432016-08-11 14:52:59 -07001123
Alex Klein1699fab2022-09-08 08:46:06 -06001124 # Only one config arg is allowed in this mode, which was confirmed earlier.
1125 build_config = site_config[options.build_config_name]
Brian Harring3fec5a82012-03-01 05:57:03 -08001126
Alex Klein1699fab2022-09-08 08:46:06 -06001127 # TODO: Re-enable this block when reference_repo support handles this
1128 # properly. (see chromium:330775)
1129 # if options.reference_repo is None:
1130 # repo_path = os.path.join(options.sourceroot, '.repo')
1131 # # If we're being run from a repo checkout, reuse the repo's git pool to
1132 # # cut down on sync time.
1133 # if os.path.exists(repo_path):
1134 # options.reference_repo = options.sourceroot
Don Garrettbbd7b552014-05-16 13:15:21 -07001135
Alex Klein1699fab2022-09-08 08:46:06 -06001136 if options.reference_repo:
1137 if not os.path.exists(options.reference_repo):
1138 parser.error(
1139 "Reference path %s does not exist" % (options.reference_repo,)
1140 )
1141 elif not os.path.exists(os.path.join(options.reference_repo, ".repo")):
1142 parser.error(
1143 "Reference path %s does not look to be the base of a "
1144 "repo checkout; no .repo exists in the root."
1145 % (options.reference_repo,)
1146 )
David Jamesdac7a912013-11-18 11:14:44 -08001147
Alex Klein1699fab2022-09-08 08:46:06 -06001148 if (options.buildbot or options.remote_trybot) and not options.resume:
1149 missing = osutils.FindMissingBinaries(_BUILDBOT_REQUIRED_BINARIES)
1150 if missing:
1151 parser.error(
1152 "Option --buildbot/--remote-trybot requires the following "
1153 "binaries which couldn't be found in $PATH: %s"
Trent Apted66736d82023-05-25 10:38:28 +10001154 % ", ".join(missing)
Alex Klein1699fab2022-09-08 08:46:06 -06001155 )
Brian Harring351ce442012-03-09 16:38:14 -08001156
Alex Klein1699fab2022-09-08 08:46:06 -06001157 if options.reference_repo:
1158 options.reference_repo = os.path.abspath(options.reference_repo)
David Jamesdac7a912013-11-18 11:14:44 -08001159
Alex Klein1699fab2022-09-08 08:46:06 -06001160 # Sanity check of buildroot- specifically that it's not pointing into the
1161 # midst of an existing repo since git-repo doesn't support nesting.
1162 if not repository.IsARepoRoot(options.buildroot) and git.FindRepoDir(
1163 options.buildroot
1164 ):
1165 cros_build_lib.Die(
1166 "Configured buildroot %s is a subdir of an existing repo checkout."
1167 % options.buildroot
1168 )
Brian Harring3fec5a82012-03-01 05:57:03 -08001169
Alex Klein1699fab2022-09-08 08:46:06 -06001170 if not options.log_dir:
1171 options.log_dir = os.path.join(options.buildroot, _DEFAULT_LOG_DIR)
Chris Sosab5ea3b42012-10-25 15:25:20 -07001172
Alex Klein1699fab2022-09-08 08:46:06 -06001173 log_file = None
1174 if options.tee:
1175 log_file = os.path.join(options.log_dir, _BUILDBOT_LOG_FILE)
1176 osutils.SafeMakedirs(options.log_dir)
1177 _BackupPreviousLog(log_file)
Brian Harringd166aaf2012-05-14 18:31:53 -07001178
Mike Frysinger321fecd2023-06-16 10:40:51 -04001179 with contextlib.ExitStack() as stack:
Alex Klein1699fab2022-09-08 08:46:06 -06001180 # Preserve chromite; we might be running from there!
1181 options.preserve_paths = set(["chromite"])
1182 if log_file is not None:
Alex Klein9e7b29e2023-04-11 16:10:31 -06001183 # We don't want the critical section to try to clean up the tee
1184 # process, so we run Tee (forked off) outside of it. This prevents a
1185 # deadlock because the Tee process only exits when its pipe is
1186 # closed, and the critical section accidentally holds on to that
1187 # file handle.
Mike Frysinger321fecd2023-06-16 10:40:51 -04001188 stack.enter_context(tee.Tee(log_file))
Alex Klein1699fab2022-09-08 08:46:06 -06001189 options.preserve_paths.add(_DEFAULT_LOG_DIR)
David Jamescebc7272013-07-17 16:45:05 -07001190
Mike Frysinger321fecd2023-06-16 10:40:51 -04001191 critical_section = stack.enter_context(cleanup.EnforcedCleanupSection())
1192 stack.enter_context(sudo.SudoKeepAlive())
Brian Harringd166aaf2012-05-14 18:31:53 -07001193
Alex Klein1699fab2022-09-08 08:46:06 -06001194 if not options.resume:
1195 # If we're in resume mode, use our parents tempdir rather than
1196 # nesting another layer.
Mike Frysinger321fecd2023-06-16 10:40:51 -04001197 stack.enter_context(osutils.TempDir(prefix="cbb", set_global=True))
Alex Klein1699fab2022-09-08 08:46:06 -06001198 logging.debug("Cbuildbot tempdir is %r.", os.environ.get("TMP"))
Brian Harringd166aaf2012-05-14 18:31:53 -07001199
Alex Klein1699fab2022-09-08 08:46:06 -06001200 if options.cgroups:
Mike Frysinger321fecd2023-06-16 10:40:51 -04001201 stack.enter_context(cgroups.SimpleContainChildren("cbuildbot"))
Brian Harringa184efa2012-03-04 11:51:25 -08001202
Alex Klein1699fab2022-09-08 08:46:06 -06001203 # Mark everything between EnforcedCleanupSection and here as having to
1204 # be rolled back via the contextmanager cleanup handlers. This
1205 # ensures that sudo bits cannot outlive cbuildbot, that anything
1206 # cgroups would kill gets killed, etc.
Mike Frysinger321fecd2023-06-16 10:40:51 -04001207 stack.enter_context(critical_section.ForkWatchdog())
Brian Harringd166aaf2012-05-14 18:31:53 -07001208
Alex Klein1699fab2022-09-08 08:46:06 -06001209 if options.mock_slave_status is not None:
Mike Frysinger31fdddd2023-02-24 15:50:55 -05001210 with open(options.mock_slave_status, "rb") as f:
Alex Klein1699fab2022-09-08 08:46:06 -06001211 mock_statuses = pickle.load(f)
1212 for key, value in mock_statuses.items():
1213 mock_statuses[key] = builder_status_lib.BuilderStatus(
1214 **value
1215 )
Mike Frysinger321fecd2023-06-16 10:40:51 -04001216 stack.enter_context(
1217 _ObjectMethodPatcher(
1218 completion_stages.MasterSlaveSyncCompletionStage,
1219 "_FetchSlaveStatuses",
1220 return_value=mock_statuses,
1221 )
Alex Klein1699fab2022-09-08 08:46:06 -06001222 )
Aviv Keshetcf9c2722014-02-25 15:15:10 -08001223
Mike Frysinger321fecd2023-06-16 10:40:51 -04001224 stack.enter_context(_SetupConnections(options, build_config))
Alex Klein1699fab2022-09-08 08:46:06 -06001225 retry_stats.SetupStats()
Aviv Keshet2982af52014-08-13 16:07:57 -07001226
Alex Klein1699fab2022-09-08 08:46:06 -06001227 timeout_display_message = (
1228 "This build has reached the timeout deadline set by the master. "
1229 "Either this stage or a previous one took too long (see stage "
1230 "timing historical summary in ReportStage) or the build failed "
1231 "to start on time."
1232 )
Prathmesh Prabhu80e05df2014-12-11 15:20:33 -08001233
Alex Klein1699fab2022-09-08 08:46:06 -06001234 if options.timeout > 0:
Mike Frysinger321fecd2023-06-16 10:40:51 -04001235 stack.enter_context(
1236 timeout_util.FatalTimeout(
1237 options.timeout,
1238 timeout_display_message,
1239 )
Alex Klein1699fab2022-09-08 08:46:06 -06001240 )
1241 try:
1242 _RunBuildStagesWrapper(options, site_config, build_config)
1243 except failures_lib.ExitEarlyException as ex:
Alex Klein9e7b29e2023-04-11 16:10:31 -06001244 # This build finished successfully. Do not re-raise
1245 # ExitEarlyException.
Alex Klein1699fab2022-09-08 08:46:06 -06001246 logging.info("One stage exited early: %s", ex)