blob: 0b80f2d715184f074eec12343b2322615b3e92bc [file] [log] [blame]
Mike Frysingerd6925b52012-07-16 16:11:00 -04001# Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
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
Chris McDonaldb55b7032021-06-17 16:41:32 -060011import distutils.version # pylint: disable=import-error,no-name-in-module
Brian Harring3fec5a82012-03-01 05:57:03 -080012import glob
Aviv Keshet669eb5e2014-06-23 08:53:01 -070013import json
Chris McDonaldb55b7032021-06-17 16:41:32 -060014import logging
Mike Frysingerb0b0caa2015-11-07 01:05:18 -050015import optparse # pylint: disable=deprecated-module
Brian Harring3fec5a82012-03-01 05:57:03 -080016import os
Aviv Keshetcf9c2722014-02-25 15:15:10 -080017import pickle
Brian Harring3fec5a82012-03-01 05:57:03 -080018import sys
19
Mike Frysingere4d68c22015-02-04 21:26:24 -050020from chromite.cbuildbot import builders
Chris McDonaldb55b7032021-06-17 16:41:32 -060021from chromite.cbuildbot import cbuildbot_alerts
Don Garrett88b8d782014-05-13 17:30:55 -070022from chromite.cbuildbot import cbuildbot_run
Don Garrett88b8d782014-05-13 17:30:55 -070023from chromite.cbuildbot import repository
Aviv Keshet420de512015-05-18 14:28:48 -070024from chromite.cbuildbot import topology
Don Garrett88b8d782014-05-13 17:30:55 -070025from chromite.cbuildbot.stages import completion_stages
Jared Loucksa9e94bf2021-06-28 10:03:31 -060026from chromite.cbuildbot.stages import test_stages
Ningning Xiaf342b952017-02-15 14:13:33 -080027from chromite.lib import builder_status_lib
Brian Harringc92a7012012-02-29 10:11:34 -080028from chromite.lib import cgroups
Chris McDonaldb55b7032021-06-17 16:41:32 -060029from chromite.lib import cidb
Brian Harringa184efa2012-03-04 11:51:25 -080030from chromite.lib import cleanup
Brian Harringb6cf9142012-09-01 20:43:17 -070031from chromite.lib import commandline
Ningning Xia6a718052016-12-22 10:08:15 -080032from chromite.lib import config_lib
33from chromite.lib import constants
Brian Harring1b8c4c82012-05-29 23:03:04 -070034from chromite.lib import cros_build_lib
Ningning Xia6a718052016-12-22 10:08:15 -080035from chromite.lib import failures_lib
David James97d95872012-11-16 15:09:56 -080036from chromite.lib import git
Stefan Zagerd49d9ff2014-08-15 21:33:37 -070037from chromite.lib import gob_util
Brian Harringaf019fb2012-05-10 15:06:13 -070038from chromite.lib import osutils
David James6450a0a2012-12-04 07:59:53 -080039from chromite.lib import parallel
Don Garrettb4318362014-10-03 15:49:36 -070040from chromite.lib import retry_stats
Brian Harring3fec5a82012-03-01 05:57:03 -080041from chromite.lib import sudo
Michael Mortensen3e86c1e2019-11-21 15:51:54 -070042from chromite.lib import tee
David James3432acd2013-11-27 10:02:18 -080043from chromite.lib import timeout_util
Paul Hobbsfcf10342015-12-29 15:52:31 -080044from chromite.lib import ts_mon_config
Dhanya Ganesh39a48a82018-12-06 16:01:11 -070045from chromite.lib.buildstore import BuildStore
Brian Harring3fec5a82012-03-01 05:57:03 -080046
Ryan Cuiadd49122012-03-21 22:19:58 -070047
Brian Harring3fec5a82012-03-01 05:57:03 -080048_DEFAULT_LOG_DIR = 'cbuildbot_logs'
49_BUILDBOT_LOG_FILE = 'cbuildbot.log'
50_DEFAULT_EXT_BUILDROOT = 'trybot'
51_DEFAULT_INT_BUILDROOT = 'trybot-internal'
Brian Harring351ce442012-03-09 16:38:14 -080052_BUILDBOT_REQUIRED_BINARIES = ('pbzip2',)
Ryan Cui1c13a252012-10-16 15:00:16 -070053_API_VERSION_ATTR = 'api_version'
Jared Loucksa9e94bf2021-06-28 10:03:31 -060054BOARD_DIM_LABEL = 'label-board'
55MODEL_DIM_LABEL = 'label-model'
56POOL_DIM_LABEL = 'label-pool'
Brian Harring3fec5a82012-03-01 05:57:03 -080057
58
Brian Harring3fec5a82012-03-01 05:57:03 -080059def _BackupPreviousLog(log_file, backup_limit=25):
60 """Rename previous log.
61
62 Args:
63 log_file: The absolute path to the previous log.
Aviv Keshet9e4236b2013-12-13 13:07:50 -080064 backup_limit: Maximum number of old logs to keep.
Brian Harring3fec5a82012-03-01 05:57:03 -080065 """
66 if os.path.exists(log_file):
67 old_logs = sorted(glob.glob(log_file + '.*'),
68 key=distutils.version.LooseVersion)
69
70 if len(old_logs) >= backup_limit:
71 os.remove(old_logs[0])
72
73 last = 0
74 if old_logs:
75 last = int(old_logs.pop().rpartition('.')[2])
76
77 os.rename(log_file, log_file + '.' + str(last + 1))
78
Ryan Cui5616a512012-08-17 13:39:36 -070079
Gaurav Shah298aa372014-01-31 09:27:24 -080080def _IsDistributedBuilder(options, chrome_rev, build_config):
81 """Determines whether the builder should be a DistributedBuilder.
82
83 Args:
84 options: options passed on the commandline.
85 chrome_rev: Chrome revision to build.
86 build_config: Builder configuration dictionary.
87
88 Returns:
89 True if the builder should be a distributed_builder
90 """
Mike Frysingerc3e88fa2020-03-26 02:49:02 -040091 if not options.buildbot:
Gaurav Shah298aa372014-01-31 09:27:24 -080092 return False
93 elif chrome_rev in (constants.CHROME_REV_TOT,
94 constants.CHROME_REV_LOCAL,
95 constants.CHROME_REV_SPEC):
96 # We don't do distributed logic to TOT Chrome PFQ's, nor local
97 # chrome roots (e.g. chrome try bots)
98 # TODO(davidjames): Update any builders that rely on this logic to use
99 # manifest_version=False instead.
100 return False
101 elif build_config['manifest_version']:
102 return True
103
104 return False
105
106
Don Garretta52a5b02015-06-02 14:52:57 -0700107def _RunBuildStagesWrapper(options, site_config, build_config):
Brian Harring3fec5a82012-03-01 05:57:03 -0800108 """Helper function that wraps RunBuildStages()."""
Lann Martinffb95162018-08-28 12:02:54 -0600109 logging.info('cbuildbot was executed with args %s',
Ralph Nathan03047282015-03-23 11:09:32 -0700110 cros_build_lib.CmdToStr(sys.argv))
Brian Harring3fec5a82012-03-01 05:57:03 -0800111
David Jamesa0a664e2013-02-13 09:52:01 -0800112 chrome_rev = build_config['chrome_rev']
113 if options.chrome_rev:
114 chrome_rev = options.chrome_rev
115 if chrome_rev == constants.CHROME_REV_TOT:
Stefan Zagerd49d9ff2014-08-15 21:33:37 -0700116 options.chrome_version = gob_util.GetTipOfTrunkRevision(
117 constants.CHROMIUM_GOB_URL)
David Jamesa0a664e2013-02-13 09:52:01 -0800118 options.chrome_rev = constants.CHROME_REV_SPEC
119
David James4a404a52013-02-19 13:07:59 -0800120 # If it's likely we'll need to build Chrome, fetch the source.
Mike Frysingerf4d9ab82013-03-05 19:38:05 -0500121 if build_config['sync_chrome'] is None:
David Jameseecba232014-06-11 11:35:11 -0700122 options.managed_chrome = (
123 chrome_rev != constants.CHROME_REV_LOCAL and
Mike Frysingerf4d9ab82013-03-05 19:38:05 -0500124 (not build_config['usepkg_build_packages'] or chrome_rev or
Mike Frysinger8b1bd822017-08-11 16:11:42 -0400125 build_config['profile']))
Mike Frysingerf4d9ab82013-03-05 19:38:05 -0500126 else:
127 options.managed_chrome = build_config['sync_chrome']
David James2333c182013-02-13 16:16:15 -0800128
Don Garrett94c603f2019-02-01 16:26:43 -0800129 chrome_root_mgr = None
David James2333c182013-02-13 16:16:15 -0800130 if options.managed_chrome:
Don Garrett94c603f2019-02-01 16:26:43 -0800131 # Create a temp directory for syncing Chrome source.
132 chrome_root_mgr = osutils.TempDir(prefix='chrome_root_')
133 options.chrome_root = chrome_root_mgr.tempdir
David James2333c182013-02-13 16:16:15 -0800134
Matt Tennant95a42ad2013-12-27 15:38:36 -0800135 # We are done munging options values, so freeze options object now to avoid
136 # further abuse of it.
137 # TODO(mtennant): one by one identify each options value override and see if
138 # it can be handled another way. Try to push this freeze closer and closer
139 # to the start of the script (e.g. in or after _PostParseCheck).
140 options.Freeze()
141
Don Garrett5ba2c452018-01-30 16:34:41 -0800142 metadata_dump_dict = {
143 # A detected default has been set before now if it wasn't explicit.
144 'branch': options.branch,
145 }
146 if options.metadata_dump:
147 with open(options.metadata_dump, 'r') as metadata_file:
148 metadata_dump_dict = json.loads(metadata_file.read())
149
Matt Tennant0940c382014-01-21 20:43:55 -0800150 with parallel.Manager() as manager:
Don Garretta52a5b02015-06-02 14:52:57 -0700151 builder_run = cbuildbot_run.BuilderRun(
152 options, site_config, build_config, manager)
Dhanya Ganesh39a48a82018-12-06 16:01:11 -0700153 buildstore = BuildStore()
Aviv Keshet669eb5e2014-06-23 08:53:01 -0700154 if metadata_dump_dict:
155 builder_run.attrs.metadata.UpdateWithDict(metadata_dump_dict)
Mike Frysingere4d68c22015-02-04 21:26:24 -0500156
Mike Frysinger05c5faf2015-02-04 21:46:46 -0500157 if builder_run.config.builder_class_name is None:
Don Garrett56e6ed32015-06-23 16:52:20 -0700158 # TODO: This should get relocated to chromeos_config.
Mike Frysingere4d68c22015-02-04 21:26:24 -0500159 if _IsDistributedBuilder(options, chrome_rev, build_config):
Mike Frysinger05c5faf2015-02-04 21:46:46 -0500160 builder_cls_name = 'simple_builders.DistributedBuilder'
Mike Frysingere4d68c22015-02-04 21:26:24 -0500161 else:
Mike Frysinger05c5faf2015-02-04 21:46:46 -0500162 builder_cls_name = 'simple_builders.SimpleBuilder'
163 builder_cls = builders.GetBuilderClass(builder_cls_name)
Dhanya Ganesh39a48a82018-12-06 16:01:11 -0700164 builder = builder_cls(builder_run, buildstore)
Matt Tennant0940c382014-01-21 20:43:55 -0800165 else:
Dhanya Ganesh39a48a82018-12-06 16:01:11 -0700166 builder = builders.Builder(builder_run, buildstore)
Mike Frysingere4d68c22015-02-04 21:26:24 -0500167
Don Garrett94c603f2019-02-01 16:26:43 -0800168 try:
169 if not builder.Run():
170 sys.exit(1)
171 finally:
172 if chrome_root_mgr:
173 chrome_root_mgr.Cleanup()
Brian Harring3fec5a82012-03-01 05:57:03 -0800174
175
Brian Harring3fec5a82012-03-01 05:57:03 -0800176def _CheckChromeVersionOption(_option, _opt_str, value, parser):
177 """Upgrade other options based on chrome_version being passed."""
178 value = value.strip()
179
180 if parser.values.chrome_rev is None and value:
181 parser.values.chrome_rev = constants.CHROME_REV_SPEC
182
183 parser.values.chrome_version = value
184
185
186def _CheckChromeRootOption(_option, _opt_str, value, parser):
187 """Validate and convert chrome_root to full-path form."""
Brian Harring3fec5a82012-03-01 05:57:03 -0800188 if parser.values.chrome_rev is None:
189 parser.values.chrome_rev = constants.CHROME_REV_LOCAL
190
Ryan Cui5ba7e152012-05-10 14:36:52 -0700191 parser.values.chrome_root = value
Brian Harring3fec5a82012-03-01 05:57:03 -0800192
193
David Jamesac8c2a72013-02-13 18:44:33 -0800194def FindCacheDir(_parser, _options):
Brian Harringae0a5322012-09-15 01:46:51 -0700195 return None
196
197
Ryan Cui5ba7e152012-05-10 14:36:52 -0700198class CustomGroup(optparse.OptionGroup):
Aviv Keshet9e4236b2013-12-13 13:07:50 -0800199 """Custom option group which supports arguments passed-through to trybot."""
David Jameseecba232014-06-11 11:35:11 -0700200
Ryan Cui5ba7e152012-05-10 14:36:52 -0700201 def add_remote_option(self, *args, **kwargs):
202 """For arguments that are passed-through to remote trybot."""
203 return optparse.OptionGroup.add_option(self, *args,
204 remote_pass_through=True,
205 **kwargs)
206
207
Ryan Cui1c13a252012-10-16 15:00:16 -0700208class CustomOption(commandline.FilteringOption):
209 """Subclass FilteringOption class to implement pass-through and api."""
Ryan Cui5ba7e152012-05-10 14:36:52 -0700210
Ryan Cui5ba7e152012-05-10 14:36:52 -0700211 def __init__(self, *args, **kwargs):
212 # The remote_pass_through argument specifies whether we should directly
213 # pass the argument (with its value) onto the remote trybot.
214 self.pass_through = kwargs.pop('remote_pass_through', False)
Ryan Cui1c13a252012-10-16 15:00:16 -0700215 self.api_version = int(kwargs.pop('api', '0'))
216 commandline.FilteringOption.__init__(self, *args, **kwargs)
Ryan Cui5ba7e152012-05-10 14:36:52 -0700217
Ryan Cui5ba7e152012-05-10 14:36:52 -0700218
Ryan Cui1c13a252012-10-16 15:00:16 -0700219class CustomParser(commandline.FilteringParser):
Gregory Meinke5a25ac72019-01-31 13:20:51 -0700220 """Custom option parser which supports arguments passed-through to trybot"""
Matt Tennante8179042013-10-01 15:47:32 -0700221
Brian Harringb6cf9142012-09-01 20:43:17 -0700222 DEFAULT_OPTION_CLASS = CustomOption
223
224 def add_remote_option(self, *args, **kwargs):
225 """For arguments that are passed-through to remote trybot."""
Ryan Cui1c13a252012-10-16 15:00:16 -0700226 return self.add_option(*args, remote_pass_through=True, **kwargs)
Brian Harringb6cf9142012-09-01 20:43:17 -0700227
228
Don Garrett86881cb2017-02-15 15:41:55 -0800229def CreateParser():
230 """Expose _CreateParser publicly."""
231 # Name _CreateParser is needed for commandline library.
232 return _CreateParser()
233
234
Brian Harring3fec5a82012-03-01 05:57:03 -0800235def _CreateParser():
Ryan Cui16d9e1f2012-05-11 10:50:18 -0700236 """Generate and return the parser with all the options."""
Brian Harring3fec5a82012-03-01 05:57:03 -0800237 # Parse options
David Jameseecba232014-06-11 11:35:11 -0700238 usage = 'usage: %prog [options] buildbot_config [buildbot_config ...]'
Brian Harringae0a5322012-09-15 01:46:51 -0700239 parser = CustomParser(usage=usage, caching=FindCacheDir)
Brian Harring3fec5a82012-03-01 05:57:03 -0800240
241 # Main options
Ryan Cuie1e4e662012-05-21 16:39:46 -0700242 parser.add_remote_option('-b', '--branch',
Hidehiko Abe863d7882017-03-09 22:27:28 +0900243 help='The manifest branch to test. The branch to '
244 'check the buildroot out to.')
245 parser.add_option('-r', '--buildroot', type='path', dest='buildroot',
246 help='Root directory where source is checked out to, and '
247 'where the build occurs. For external build configs, '
248 "defaults to 'trybot' directory at top level of your "
249 'repo-managed checkout.')
Don Garrett10210fa2018-06-29 18:25:41 -0700250 parser.add_option('--workspace', type='path',
251 api=constants.REEXEC_API_WORKSPACE,
252 help='Root directory for a secondary checkout .')
Hidehiko Abe863d7882017-03-09 22:27:28 +0900253 parser.add_option('--bootstrap-dir', type='path',
Prathmesh Prabhu867c1172015-06-02 17:57:59 -0700254 help='Bootstrapping cbuildbot may involve checking out '
255 'multiple copies of chromite. All these checkouts '
256 'will be contained in the directory specified here. '
257 'Default:%s' % osutils.GetGlobalTempDir())
Hidehiko Abe863d7882017-03-09 22:27:28 +0900258 parser.add_remote_option('--android_rev', type='choice',
David Riley486b2612016-02-22 19:59:26 -0800259 choices=constants.VALID_ANDROID_REVISIONS,
260 help=('Revision of Android to use, of type [%s]'
261 % '|'.join(constants.VALID_ANDROID_REVISIONS)))
Hidehiko Abe863d7882017-03-09 22:27:28 +0900262 parser.add_remote_option('--chrome_rev', type='choice',
David Riley486b2612016-02-22 19:59:26 -0800263 choices=constants.VALID_CHROME_REVISIONS,
Ryan Cuieaa9efd2012-04-25 17:56:45 -0700264 help=('Revision of Chrome to use, of type [%s]'
265 % '|'.join(constants.VALID_CHROME_REVISIONS)))
Hidehiko Abe863d7882017-03-09 22:27:28 +0900266 parser.add_remote_option('--profile',
Ryan Cuieaa9efd2012-04-25 17:56:45 -0700267 help='Name of profile to sub-specify board variant.')
Hidehiko Abe95d7cf62017-03-07 23:34:30 +0900268 # TODO(crbug.com/279618): Running GOMA is under development. Following
269 # flags are added for development purpose due to repository dependency,
270 # but not officially supported yet.
271 parser.add_option('--goma_dir', type='path',
272 api=constants.REEXEC_API_GOMA,
273 help='Specify a directory containing goma. When this is '
274 'set, GOMA is used to build Chrome.')
Yoshisato Yanagisawa13d55b32019-08-15 09:44:44 +0900275 parser.add_option('--chromeos_goma_dir', type='path',
276 api=constants.REEXEC_API_CHROMEOS_GOMA_DIR,
277 help='Specify a directory containing goma for '
278 'build package.')
Fumitoshi Ukaica711872022-09-06 16:37:27 +0900279 # TODO(crbug.com/1359171): cleanup the flag.
Hidehiko Abe95d7cf62017-03-07 23:34:30 +0900280 parser.add_option('--goma_client_json', type='path',
281 api=constants.REEXEC_API_GOMA,
Fumitoshi Ukaica711872022-09-06 16:37:27 +0900282 help='Specify a service-account-goma-client.json path.')
Brian Harring3fec5a82012-03-01 05:57:03 -0800283
Don Garrett211df8c2017-09-06 13:33:02 -0700284 group = CustomGroup(
285 parser,
286 'Deprecated Options')
287
288 parser.add_option('--local', action='store_true', default=False,
Don Garrettcc0ee522017-09-13 14:28:42 -0700289 help='Deprecated. See cros tryjob.')
Don Garrett211df8c2017-09-06 13:33:02 -0700290 parser.add_option('--remote', action='store_true', default=False,
Don Garrettcc0ee522017-09-13 14:28:42 -0700291 help='Deprecated. See cros tryjob.')
Don Garrett211df8c2017-09-06 13:33:02 -0700292
Ryan Cuif4f84be2012-07-09 18:50:41 -0700293 #
Mike Frysinger81af6ef2013-04-03 02:24:09 -0400294 # Patch selection options.
295 #
296
297 group = CustomGroup(
298 parser,
299 'Patch Options')
300
Mike Frysingerdad205d2017-08-11 16:00:14 -0400301 group.add_remote_option('-g', '--gerrit-patches', action='split_extend',
Hidehiko Abe863d7882017-03-09 22:27:28 +0900302 type='string', default=[],
Mike Frysinger81af6ef2013-04-03 02:24:09 -0400303 metavar="'Id1 *int_Id2...IdN'",
Hidehiko Abe863d7882017-03-09 22:27:28 +0900304 help='Space-separated list of short-form Gerrit '
305 "Change-Id's or change numbers to patch. "
306 "Please prepend '*' to internal Change-Id's")
Mike Frysinger81af6ef2013-04-03 02:24:09 -0400307
Mike Frysinger68893242017-08-11 14:16:39 -0400308 parser.add_argument_group(group)
Mike Frysinger81af6ef2013-04-03 02:24:09 -0400309
310 #
311 # Remote trybot options.
312 #
313
314 group = CustomGroup(
315 parser,
Don Garrett211df8c2017-09-06 13:33:02 -0700316 'Options used to configure tryjob behavior.')
Hidehiko Abe863d7882017-03-09 22:27:28 +0900317 group.add_remote_option('--hwtest', action='store_true', default=False,
David Jameseecba232014-06-11 11:35:11 -0700318 help='Run the HWTest stage (tests on real hardware)')
Jared Loucksa9e94bf2021-06-28 10:03:31 -0600319 group.add_option('--hwtest_dut_dimensions', type='string',
320 action='split_extend', default=None,
321 help='Space-separated list of key:val Swarming bot '
322 'dimensions to run each builders SkylabHWTest '
323 'stages against (this overrides the configured '
324 'DUT dimensions for each test). Requires at least '
325 '"label-board", "label-model", and "label-pool".')
Mike Frysingerdad205d2017-08-11 16:00:14 -0400326 group.add_remote_option('--channel', action='split_extend', dest='channels',
Don Garrett4bb21682014-03-03 16:16:23 -0800327 default=[],
Hidehiko Abe863d7882017-03-09 22:27:28 +0900328 help='Specify a channel for a payloads trybot. Can '
329 'be specified multiple times. No valid for '
330 'non-payloads configs.')
Mike Frysinger81af6ef2013-04-03 02:24:09 -0400331
Mike Frysinger68893242017-08-11 14:16:39 -0400332 parser.add_argument_group(group)
Mike Frysinger81af6ef2013-04-03 02:24:09 -0400333
334 #
335 # Advanced options.
Ryan Cuif4f84be2012-07-09 18:50:41 -0700336 #
337
Ryan Cuieaa9efd2012-04-25 17:56:45 -0700338 group = CustomGroup(
Brian Harring3fec5a82012-03-01 05:57:03 -0800339 parser,
340 'Advanced Options',
341 'Caution: use these options at your own risk.')
342
Mike Frysinger81af6ef2013-04-03 02:24:09 -0400343 group.add_remote_option('--bootstrap-args', action='append', default=[],
Hidehiko Abe863d7882017-03-09 22:27:28 +0900344 help='Args passed directly to the bootstrap re-exec '
345 'to skip verification by the bootstrap code')
346 group.add_remote_option('--buildbot', action='store_true', dest='buildbot',
Bernie Thompson63f30062016-12-21 15:24:25 -0800347 default=False,
348 help='This is running on a buildbot. '
349 'This can be used to make a build operate '
350 'like an official builder, e.g. generate '
351 'new version numbers and archive official '
352 'artifacts and such. This should only be '
353 'used if you are confident in what you are '
354 'doing, as it will make automated commits.')
Don Garrett07d46262017-04-13 12:06:44 -0700355 parser.add_remote_option('--repo-cache', type='path', dest='_repo_cache',
356 help='Present for backwards compatibility, ignored.')
Prathmesh Prabhu51d774f2015-07-17 15:11:49 -0700357 group.add_remote_option('--no-buildbot-tags', action='store_false',
358 dest='enable_buildbot_tags', default=True,
359 help='Suppress buildbot specific tags from log '
360 'output. This is used to hide recursive '
361 'cbuilbot runs on the waterfall.')
Hidehiko Abe863d7882017-03-09 22:27:28 +0900362 group.add_remote_option('--buildnumber', type='int', default=0,
363 help='build number')
364 group.add_option('--chrome_root', action='callback', type='path',
365 callback=_CheckChromeRootOption,
366 help='Local checkout of Chrome to use.')
367 group.add_remote_option('--chrome_version', action='callback', type='string',
368 dest='chrome_version',
Ryan Cuieaa9efd2012-04-25 17:56:45 -0700369 callback=_CheckChromeVersionOption,
Hidehiko Abe863d7882017-03-09 22:27:28 +0900370 help='Used with SPEC logic to force a particular '
371 'git revision of chrome rather than the '
372 'latest.')
373 group.add_remote_option('--clobber', action='store_true', default=False,
Ryan Cuieaa9efd2012-04-25 17:56:45 -0700374 help='Clears an old checkout before syncing')
Mike Frysinger81af6ef2013-04-03 02:24:09 -0400375 group.add_remote_option('--latest-toolchain', action='store_true',
376 default=False,
377 help='Use the latest toolchain.')
Ryan Cui5ba7e152012-05-10 14:36:52 -0700378 parser.add_option('--log_dir', dest='log_dir', type='path',
Hidehiko Abe863d7882017-03-09 22:27:28 +0900379 help='Directory where logs are stored.')
380 group.add_remote_option('--maxarchives', type='int',
381 dest='max_archive_builds', default=3,
David Jameseecba232014-06-11 11:35:11 -0700382 help='Change the local saved build count limit.')
Ryan Cuibbd3d4b2012-08-17 12:20:37 -0700383 parser.add_remote_option('--manifest-repo-url',
Hidehiko Abe863d7882017-03-09 22:27:28 +0900384 help='Overrides the default manifest repo url.')
David James565bc9a2013-04-08 14:54:45 -0700385 group.add_remote_option('--compilecheck', action='store_true', default=False,
386 help='Only verify compilation and unit tests.')
Ryan Cuieaa9efd2012-04-25 17:56:45 -0700387 group.add_remote_option('--noarchive', action='store_false', dest='archive',
388 default=True, help="Don't run archive stage.")
Ryan Cuif7f24692012-05-18 16:35:33 -0700389 group.add_remote_option('--nobootstrap', action='store_false',
390 dest='bootstrap', default=True,
Hidehiko Abe863d7882017-03-09 22:27:28 +0900391 help="Don't checkout and run from a standalone "
392 'chromite repo.')
Ryan Cuieaa9efd2012-04-25 17:56:45 -0700393 group.add_remote_option('--nobuild', action='store_false', dest='build',
394 default=True,
395 help="Don't actually build (for cbuildbot dev)")
396 group.add_remote_option('--noclean', action='store_false', dest='clean',
397 default=True, help="Don't clean the buildroot")
Ryan Cuif7f24692012-05-18 16:35:33 -0700398 group.add_remote_option('--nocgroups', action='store_false', dest='cgroups',
399 default=True,
400 help='Disable cbuildbots usage of cgroups.')
Ryan Cui3ea98e02013-08-07 16:01:48 -0700401 group.add_remote_option('--nochromesdk', action='store_false',
402 dest='chrome_sdk', default=True,
Hidehiko Abe863d7882017-03-09 22:27:28 +0900403 help="Don't run the ChromeSDK stage which builds "
404 'Chrome outside of the chroot.')
Ryan Cuieaa9efd2012-04-25 17:56:45 -0700405 group.add_remote_option('--noprebuilts', action='store_false',
406 dest='prebuilts', default=True,
407 help="Don't upload prebuilts.")
Ryan Cui88b901c2013-06-21 11:35:30 -0700408 group.add_remote_option('--nopatch', action='store_false',
409 dest='postsync_patch', default=True,
Hidehiko Abe863d7882017-03-09 22:27:28 +0900410 help="Don't run PatchChanges stage. This does not "
411 'disable patching in of chromite patches '
412 'during BootstrapStage.')
Don Garrett82c0ae82014-02-03 18:25:11 -0800413 group.add_remote_option('--nopaygen', action='store_false',
414 dest='paygen', default=True,
415 help="Don't generate payloads.")
Ryan Cui88b901c2013-06-21 11:35:30 -0700416 group.add_remote_option('--noreexec', action='store_false',
417 dest='postsync_reexec', default=True,
418 help="Don't reexec into the buildroot after syncing.")
Hidehiko Abe863d7882017-03-09 22:27:28 +0900419 group.add_remote_option('--nosdk', action='store_true', default=False,
Mike Frysinger81af6ef2013-04-03 02:24:09 -0400420 help='Re-create the SDK from scratch.')
Ryan Cuieaa9efd2012-04-25 17:56:45 -0700421 group.add_remote_option('--nosync', action='store_false', dest='sync',
422 default=True, help="Don't sync before building.")
Ryan Cuieaa9efd2012-04-25 17:56:45 -0700423 group.add_remote_option('--notests', action='store_false', dest='tests',
424 default=True,
xixuan7774ba82017-06-22 16:04:00 -0700425 help='Override values from buildconfig, run no '
426 'tests, and build no autotest and artifacts.')
427 group.add_remote_option('--novmtests', action='store_false', dest='vmtests',
428 default=True,
429 help='Override values from buildconfig, run no '
430 'vmtests.')
Nam T. Nguyenc93f1342014-07-11 14:40:54 -0700431 group.add_remote_option('--noimagetests', action='store_false',
432 dest='image_test', default=True,
Hidehiko Abe863d7882017-03-09 22:27:28 +0900433 help='Override values from buildconfig and run no '
434 'image tests.')
Ryan Cuieaa9efd2012-04-25 17:56:45 -0700435 group.add_remote_option('--nouprev', action='store_false', dest='uprev',
436 default=True,
Hidehiko Abe863d7882017-03-09 22:27:28 +0900437 help='Override values from buildconfig and never '
438 'uprev.')
439 group.add_option('--reference-repo',
440 help='Reuse git data stored in an existing repo '
441 'checkout. This can drastically reduce the network '
442 'time spent setting up the trybot checkout. By '
443 "default, if this option isn't given but cbuildbot "
444 'is invoked from a repo checkout, cbuildbot will '
445 'use the repo root.')
Ryan Cuicedd8a52012-03-22 02:28:35 -0700446 group.add_option('--resume', action='store_true', default=False,
Ryan Cuieaa9efd2012-04-25 17:56:45 -0700447 help='Skip stages already successfully completed.')
Hidehiko Abe863d7882017-03-09 22:27:28 +0900448 group.add_remote_option('--timeout', type='int', default=0,
449 help='Specify the maximum amount of time this job '
450 'can run for, at which point the build will be '
451 'aborted. If set to zero, then there is no '
452 'timeout.')
453 group.add_remote_option('--version', dest='force_version',
454 help='Used with manifest logic. Forces use of this '
455 'version rather than create or get latest. '
456 'Examples: 4815.0.0-rc1, 4815.1.2')
457 group.add_remote_option('--git-cache-dir', type='path',
Don Garrettbb79be92016-09-27 11:14:07 -0700458 api=constants.REEXEC_API_GIT_CACHE_DIR,
Hidehiko Abe863d7882017-03-09 22:27:28 +0900459 help='Specify the cache directory to store the '
460 'project caches populated by the git-cache '
461 'tool. Bootstrap the projects based on the git '
462 'cache files instead of fetching them directly '
463 'from the GoB servers.')
David Burger33c7d3c2020-02-19 09:57:54 -0700464 group.add_remote_option('--chrome-preload-dir', type='path',
465 api=constants.REEXEC_API_CHROME_PRELOAD_DIR,
466 help='Specify a preloaded chrome source cache '
467 'directory populated by the git-cache tool. '
468 'Bootstrap chrome based on the cached files '
469 'instead of fetching them directly from the GoB '
470 'servers. When both this argument and '
471 '--git-cache-dir are provided this value will '
472 'be preferred for the chrome source cache.')
Mike Nicholsb49ceb92021-09-01 15:43:37 -0400473 group.add_remote_option('--source_cache', action='store_true', default=False,
474 help='Whether to utilize cache snapshot mounts.')
Don Garretta90f0142018-02-28 14:25:19 -0800475 group.add_remote_option('--debug-cidb', action='store_true', default=False,
476 help='Force Debug CIDB to be used.')
Gregory Meinke5a25ac72019-01-31 13:20:51 -0700477 # cbuildbot ChromeOS Findit options
478 group.add_remote_option('--cbb_build_packages', action='split_extend',
479 dest='cbb_build_packages',
480 default=[],
481 help='Specify an explicit list of packages to build '
482 'for integration with Findit.')
Gregory Meinkead6d5672019-02-19 08:41:12 -0700483 group.add_remote_option('--cbb_snapshot_revision', type='string',
484 dest='cbb_snapshot_revision', default=None,
485 help='Snapshot manifest revision to sync to '
486 'for building.')
Chris McDonald2921fd42020-02-25 14:30:06 -0700487 group.add_remote_option(
488 '--no-publish-prebuilt-confs',
489 dest='publish',
490 action='store_false',
491 default=True,
492 help="Don't publish git commits to prebuilt.conf or sdk_version.conf")
Mike Frysinger81af6ef2013-04-03 02:24:09 -0400493
Mike Frysinger68893242017-08-11 14:16:39 -0400494 parser.add_argument_group(group)
Mike Frysinger81af6ef2013-04-03 02:24:09 -0400495
496 #
497 # Internal options.
498 #
499
500 group = CustomGroup(
501 parser,
Mike Frysinger34db8692013-11-11 14:54:08 -0500502 'Internal Chromium OS Build Team Options',
503 'Caution: these are for meant for the Chromium OS build team only')
Mike Frysinger81af6ef2013-04-03 02:24:09 -0400504
505 group.add_remote_option('--archive-base', type='gs_path',
Hidehiko Abe863d7882017-03-09 22:27:28 +0900506 help='Base GS URL (gs://<bucket_name>/<path>) to '
507 'upload archive artifacts to')
David Jameseecba232014-06-11 11:35:11 -0700508 group.add_remote_option(
Hidehiko Abe863d7882017-03-09 22:27:28 +0900509 '--cq-gerrit-query', dest='cq_gerrit_override',
510 help='If given, this gerrit query will be used to find what patches to '
511 "test, rather than the normal 'CommitQueue>=1 AND Verified=1 AND "
512 "CodeReview=2' query it defaults to. Use with care- note "
513 'additionally this setting only has an effect if the buildbot '
514 "target is a cq target, and we're in buildbot mode.")
515 group.add_option('--pass-through', action='append', type='string',
516 dest='pass_through_args', default=[])
517 group.add_option('--reexec-api-version', action='store_true',
518 dest='output_api_version', default=False,
519 help='Used for handling forwards/backwards compatibility '
520 'with --resume and --bootstrap')
521 group.add_option('--remote-trybot', action='store_true', default=False,
Mike Frysinger81af6ef2013-04-03 02:24:09 -0400522 help='Indicates this is running on a remote trybot machine')
Hidehiko Abe863d7882017-03-09 22:27:28 +0900523 group.add_option('--buildbucket-id',
Don Garrettb01a8e62017-12-11 17:47:18 -0800524 api=constants.REEXEC_API_GOMA, # Approximate.
Hidehiko Abe863d7882017-03-09 22:27:28 +0900525 help='The unique ID in buildbucket of current build '
526 'generated by buildbucket.')
Mike Frysingerdad205d2017-08-11 16:00:14 -0400527 group.add_remote_option('--remote-patches', action='split_extend', default=[],
Hidehiko Abe863d7882017-03-09 22:27:28 +0900528 help='Patches uploaded by the trybot client when '
529 'run using the -p option')
Brian Harringf611e6e2012-07-17 18:47:44 -0700530 # Note the default here needs to be hardcoded to 3; that is the last version
531 # that lacked this functionality.
Hidehiko Abe863d7882017-03-09 22:27:28 +0900532 group.add_option('--remote-version', type='int', default=3,
Don Garrettbb965dc2017-09-14 17:24:18 -0700533 help='Deprecated and ignored.')
Mike Frysinger81af6ef2013-04-03 02:24:09 -0400534 group.add_option('--sourceroot', type='path', default=constants.SOURCE_ROOT)
535 group.add_remote_option('--test-bootstrap', action='store_true',
536 default=False,
Hidehiko Abe863d7882017-03-09 22:27:28 +0900537 help='Causes cbuildbot to bootstrap itself twice, '
538 'in the sequence A->B->C: A(unpatched) patches '
539 'and bootstraps B; B patches and bootstraps C')
540 group.add_remote_option('--validation_pool',
541 help='Path to a pickled validation pool. Intended '
542 'for use only with the commit queue.')
543 group.add_remote_option('--metadata_dump',
544 help='Path to a json dumped metadata file. This '
545 'will be used as the initial metadata.')
546 group.add_remote_option('--master-build-id', type='int',
Aviv Keshetacf4cfb2014-07-30 12:31:22 -0700547 api=constants.REEXEC_API_MASTER_BUILD_ID,
Hidehiko Abe863d7882017-03-09 22:27:28 +0900548 help='cidb build id of the master build to this '
549 'slave build.')
Dhanya Ganesh6e0e0282019-03-06 16:06:16 -0700550 group.add_remote_option('--master-buildbucket-id',
551 api=constants.REEXEC_API_MASTER_BUILDBUCKET_ID,
552 help='buildbucket id of the master build to this '
553 'slave build.')
Ningning Xia6c381652017-10-24 16:03:29 -0700554 # TODO(nxia): crbug.com/778838
555 # cbuildbot doesn't use pickle files anymore, remove this.
Hidehiko Abe863d7882017-03-09 22:27:28 +0900556 group.add_remote_option('--mock-slave-status',
557 metavar='MOCK_SLAVE_STATUS_PICKLE_FILE',
Mike Nicholsa1414162021-04-22 20:07:22 +0000558 help='Override the result of the _FetchSlaveStatuses '
559 'method of MasterSlaveSyncCompletionStage, by '
560 'specifying a file with a pickle of the result '
561 'to be returned.')
Benjamin Gordon0443cb82018-04-17 12:38:49 -0600562 group.add_option('--previous-build-state', type='string', default='',
563 api=constants.REEXEC_API_PREVIOUS_BUILD_STATE,
564 help='A base64-encoded BuildSummary object describing the '
565 'previous build run on the same build machine.')
Mike Frysinger81af6ef2013-04-03 02:24:09 -0400566
Mike Frysinger68893242017-08-11 14:16:39 -0400567 parser.add_argument_group(group)
Ryan Cuif4f84be2012-07-09 18:50:41 -0700568
569 #
Brian Harring3fec5a82012-03-01 05:57:03 -0800570 # Debug options
Ryan Cuif4f84be2012-07-09 18:50:41 -0700571 #
Brian Harringfec89fe2012-09-23 07:30:54 -0700572 # Temporary hack; in place till --dry-run replaces --debug.
Mike Frysinger27e21b72018-07-12 14:20:21 -0400573 # pylint: disable=protected-access
Brian Harring009db502012-10-10 02:21:37 -0700574 group = parser.debug_group
Brian Harringfec89fe2012-09-23 07:30:54 -0700575 debug = [x for x in group.option_list if x._long_opts == ['--debug']][0]
David Jameseecba232014-06-11 11:35:11 -0700576 debug.help += ' Currently functions as --dry-run in addition.'
Brian Harringfec89fe2012-09-23 07:30:54 -0700577 debug.pass_through = True
Brian Harring3fec5a82012-03-01 05:57:03 -0800578 group.add_option('--notee', action='store_false', dest='tee', default=True,
Hidehiko Abe863d7882017-03-09 22:27:28 +0900579 help='Disable logging and internal tee process. Primarily '
580 'used for debugging cbuildbot itself.')
Brian Harring3fec5a82012-03-01 05:57:03 -0800581 return parser
582
583
Mike Frysinger80bba8a2017-08-18 15:28:36 -0400584def _FinishParsing(options):
Ryan Cui85867972012-02-23 18:21:49 -0800585 """Perform some parsing tasks that need to take place after optparse.
586
587 This function needs to be easily testable! Keep it free of
588 environment-dependent code. Put more detailed usage validation in
589 _PostParseCheck().
Brian Harring3fec5a82012-03-01 05:57:03 -0800590
591 Args:
Matt Tennant759e2352013-09-27 15:14:44 -0700592 options: The options object returned by optparse
Brian Harring3fec5a82012-03-01 05:57:03 -0800593 """
Ryan Cui41023d92012-11-13 19:59:50 -0800594 # Populate options.pass_through_args.
595 accepted, _ = commandline.FilteringParser.FilterArgs(
596 options.parsed_args, lambda x: x.opt_inst.pass_through)
597 options.pass_through_args.extend(accepted)
Brian Harring07039b52012-05-13 17:56:47 -0700598
Don Garrettcc0ee522017-09-13 14:28:42 -0700599 if options.local or options.remote:
600 cros_build_lib.Die('Deprecated usage. Please use cros tryjob instead.')
601
Don Garrett211df8c2017-09-06 13:33:02 -0700602 if not options.buildroot:
603 cros_build_lib.Die('A buildroot is required to build.')
604
Brian Harring3fec5a82012-03-01 05:57:03 -0800605 if options.chrome_root:
606 if options.chrome_rev != constants.CHROME_REV_LOCAL:
Brian Harring1b8c4c82012-05-29 23:03:04 -0700607 cros_build_lib.Die('Chrome rev must be %s if chrome_root is set.' %
608 constants.CHROME_REV_LOCAL)
David Jamesa0a664e2013-02-13 09:52:01 -0800609 elif options.chrome_rev == constants.CHROME_REV_LOCAL:
610 cros_build_lib.Die('Chrome root must be set if chrome_rev is %s.' %
611 constants.CHROME_REV_LOCAL)
Brian Harring3fec5a82012-03-01 05:57:03 -0800612
613 if options.chrome_version:
614 if options.chrome_rev != constants.CHROME_REV_SPEC:
Brian Harring1b8c4c82012-05-29 23:03:04 -0700615 cros_build_lib.Die('Chrome rev must be %s if chrome_version is set.' %
616 constants.CHROME_REV_SPEC)
David Jamesa0a664e2013-02-13 09:52:01 -0800617 elif options.chrome_rev == constants.CHROME_REV_SPEC:
618 cros_build_lib.Die(
619 'Chrome rev must not be %s if chrome_version is not set.'
620 % constants.CHROME_REV_SPEC)
Brian Harring3fec5a82012-03-01 05:57:03 -0800621
Don Garrett211df8c2017-09-06 13:33:02 -0700622 patches = bool(options.gerrit_patches)
Ryan Cuieaa9efd2012-04-25 17:56:45 -0700623
David James5734ea32012-08-15 20:23:49 -0700624 # When running in release mode, make sure we are running with checked-in code.
625 # We want checked-in cbuildbot/scripts to prevent errors, and we want to build
626 # a release image with checked-in code for CrOS packages.
Don Garrett211df8c2017-09-06 13:33:02 -0700627 if options.buildbot and patches and not options.debug:
David James5734ea32012-08-15 20:23:49 -0700628 cros_build_lib.Die(
629 'Cannot provide patches when running with --buildbot!')
630
Ryan Cuiba41ad32012-03-08 17:15:29 -0800631 if options.buildbot and options.remote_trybot:
Brian Harring1b8c4c82012-05-29 23:03:04 -0700632 cros_build_lib.Die(
633 '--buildbot and --remote-trybot cannot be used together.')
Ryan Cuiba41ad32012-03-08 17:15:29 -0800634
Ryan Cui85867972012-02-23 18:21:49 -0800635 # Record whether --debug was set explicitly vs. it was inferred.
Don Garrett211df8c2017-09-06 13:33:02 -0700636 options.debug_forced = options.debug
637 # We force --debug to be set for builds that are not 'official'.
638 options.debug = options.debug or not options.buildbot
Brian Harring3fec5a82012-03-01 05:57:03 -0800639
Jared Loucksa9e94bf2021-06-28 10:03:31 -0600640 options.hwtest_dut_override = ParseHWTestDUTDims(
641 options.hwtest_dut_dimensions)
642
643def ParseHWTestDUTDims(dims):
644 """Parse HWTest DUT dimensions into a valid HWTestDUTOverride object.
645
646 Raises an error if any of board, model, or pool is missing.
647 """
648 if not dims:
649 return None
650 board = model = pool = None
651 extra_dims = []
652 for dim in dims:
653 if dim.startswith(BOARD_DIM_LABEL):
654 # Remove one extra character to account for the ":" or "=" symbol
655 # separating the label from the dimension itself.
656 board = dim[len(BOARD_DIM_LABEL)+1:]
657 elif dim.startswith(MODEL_DIM_LABEL):
658 model = dim[len(MODEL_DIM_LABEL)+1:]
659 elif dim.startswith(POOL_DIM_LABEL):
660 pool = dim[len(POOL_DIM_LABEL)+1:]
661 else:
662 extra_dims.append(dim)
663
664 if not (board and model and pool):
665 cros_build_lib.Die('HWTest DUT dimensions must include board, model, and '
666 'pool (given %s).' % dims)
667
668 return test_stages.HWTestDUTOverride(board, model, pool, extra_dims)
669
Brian Harring3fec5a82012-03-01 05:57:03 -0800670
Mike Frysinger27e21b72018-07-12 14:20:21 -0400671# pylint: disable=unused-argument
Mike Frysinger80bba8a2017-08-18 15:28:36 -0400672def _PostParseCheck(parser, options, site_config):
Ryan Cui85867972012-02-23 18:21:49 -0800673 """Perform some usage validation after we've parsed the arguments
Brian Harring3fec5a82012-03-01 05:57:03 -0800674
Ryan Cui85867972012-02-23 18:21:49 -0800675 Args:
Aviv Keshet9e4236b2013-12-13 13:07:50 -0800676 parser: Option parser that was used to parse arguments.
677 options: The options returned by optparse.
Don Garrett4af20982015-05-29 19:02:23 -0700678 site_config: config_lib.SiteConfig containing all config info.
Ryan Cui85867972012-02-23 18:21:49 -0800679 """
Don Garrett0a873e02015-06-30 17:55:10 -0700680
Ryan Cuie1e4e662012-05-21 16:39:46 -0700681 if not options.branch:
David James97d95872012-11-16 15:09:56 -0800682 options.branch = git.GetChromiteTrackingBranch()
Ryan Cuie1e4e662012-05-21 16:39:46 -0700683
David Jamesac8c2a72013-02-13 18:44:33 -0800684 # Because the default cache dir depends on other options, FindCacheDir
685 # always returns None, and we setup the default here.
Brian Harringae0a5322012-09-15 01:46:51 -0700686 if options.cache_dir is None:
687 # Note, options.sourceroot is set regardless of the path
688 # actually existing.
Don Garrett211df8c2017-09-06 13:33:02 -0700689 options.cache_dir = os.path.join(options.buildroot, '.cache')
Brian Harringae0a5322012-09-15 01:46:51 -0700690 options.cache_dir = os.path.abspath(options.cache_dir)
Brian Harring8c1d7b12012-10-04 17:36:32 -0700691 parser.ConfigureCacheDir(options.cache_dir)
Brian Harringae0a5322012-09-15 01:46:51 -0700692
Yu-Ju Hong2c066762013-10-28 14:05:08 -0700693 osutils.SafeMakedirsNonRoot(options.cache_dir)
Ryan Cui5ba7e152012-05-10 14:36:52 -0700694
Matt Tennant763497d2014-01-17 16:45:54 -0800695 # Ensure that all args are legitimate config targets.
Don Garrettf0761152017-10-19 19:38:27 -0700696 if options.build_config_name not in site_config:
Stephen Boydeb0cd632019-04-25 11:51:08 -0700697 cros_build_lib.Die('Unknown build config: "%s"' % options.build_config_name)
Don Garrett4bb21682014-03-03 16:16:23 -0800698
Don Garrettf0761152017-10-19 19:38:27 -0700699 build_config = site_config[options.build_config_name]
700 is_payloads_build = build_config.build_type == constants.PAYLOADS_TYPE
Don Garrett4af20982015-05-29 19:02:23 -0700701
Don Garrettf0761152017-10-19 19:38:27 -0700702 if options.channels and not is_payloads_build:
703 cros_build_lib.Die('--channel must only be used with a payload config,'
704 ' not target (%s).' % options.build_config_name)
Don Garrett5af1d262014-05-16 15:49:37 -0700705
Don Garrettf0761152017-10-19 19:38:27 -0700706 if not options.channels and is_payloads_build:
707 cros_build_lib.Die('payload configs (%s) require --channel to do anything'
708 ' useful.' % options.build_config_name)
Matt Tennant763497d2014-01-17 16:45:54 -0800709
Don Garrett370839f2017-10-19 18:32:34 -0700710 # If the build config explicitly forces the debug flag, set the debug flag
711 # as if it was set from the command line.
712 if build_config.debug:
713 options.debug = True
714
Don Garrett8bd52562017-11-20 14:16:37 -0800715 if not (config_lib.isTryjobConfig(build_config) or options.buildbot):
Don Garrett02d2f582017-11-08 14:01:24 -0800716 cros_build_lib.Die(
717 'Refusing to run non-tryjob config as a tryjob.\n'
Don Garrett8bd52562017-11-20 14:16:37 -0800718 'Please "repo sync && cros tryjob --list %s" for alternatives.\n'
Don Garrettf6661792017-11-15 13:13:23 -0800719 'See go/cros-explicit-tryjob-build-configs-psa.',
Don Garrett02d2f582017-11-08 14:01:24 -0800720 build_config.name)
721
Don Garrettf0761152017-10-19 19:38:27 -0700722 # The --version option is not compatible with an external target unless the
723 # --buildbot option is specified. More correctly, only "paladin versions"
724 # will work with external targets, and those are only used with --buildbot.
725 # If --buildbot is specified, then user should know what they are doing and
726 # only specify a version that will work. See crbug.com/311648.
727 if (options.force_version and
728 not (options.buildbot or build_config.internal)):
729 cros_build_lib.Die('Cannot specify --version without --buildbot for an'
730 ' external target (%s).' % options.build_config_name)
Matt Tennant763497d2014-01-17 16:45:54 -0800731
Ryan Cui85867972012-02-23 18:21:49 -0800732
Don Garrett597ddff2017-02-17 18:29:37 -0800733def ParseCommandLine(parser, argv):
Ryan Cui85867972012-02-23 18:21:49 -0800734 """Completely parse the commandline arguments"""
Brian Harring3fec5a82012-03-01 05:57:03 -0800735 (options, args) = parser.parse_args(argv)
Brian Harring37e559b2012-05-22 20:47:32 -0700736
Don Garrettf0761152017-10-19 19:38:27 -0700737 # Handle the request for the reexec command line API version number.
Brian Harring37e559b2012-05-22 20:47:32 -0700738 if options.output_api_version:
Mike Frysinger383367e2014-09-16 15:06:17 -0400739 print(constants.REEXEC_API_VERSION)
Brian Harring37e559b2012-05-22 20:47:32 -0700740 sys.exit(0)
741
Don Garrettf0761152017-10-19 19:38:27 -0700742 # Record the configs targeted. Strip out null arguments.
743 build_config_names = [x for x in args if x]
744 if len(build_config_names) != 1:
745 cros_build_lib.Die('Expected exactly one build config. Got: %r',
746 build_config_names)
747 options.build_config_name = build_config_names[-1]
748
Mike Frysinger80bba8a2017-08-18 15:28:36 -0400749 _FinishParsing(options)
750 return options
Ryan Cui85867972012-02-23 18:21:49 -0800751
752
Aviv Keshet420de512015-05-18 14:28:48 -0700753_ENVIRONMENT_PROD = 'prod'
754_ENVIRONMENT_DEBUG = 'debug'
755_ENVIRONMENT_STANDALONE = 'standalone'
756
757
758def _GetRunEnvironment(options, build_config):
759 """Determine whether this is a prod/debug/standalone run."""
Don Garretta90f0142018-02-28 14:25:19 -0800760 if options.debug_cidb:
761 return _ENVIRONMENT_DEBUG
762
Don Garrett63765c42017-11-03 16:54:20 -0700763 # One of these arguments should always be set if running on a real builder.
764 # If we aren't on a real builder, we are standalone.
765 if not options.buildbot and not options.remote_trybot:
Aviv Keshet420de512015-05-18 14:28:48 -0700766 return _ENVIRONMENT_STANDALONE
767
Don Garrett63765c42017-11-03 16:54:20 -0700768 if build_config['debug_cidb']:
769 return _ENVIRONMENT_DEBUG
Aviv Keshet420de512015-05-18 14:28:48 -0700770
Don Garrett63765c42017-11-03 16:54:20 -0700771 return _ENVIRONMENT_PROD
Aviv Keshet420de512015-05-18 14:28:48 -0700772
773
Gabe Blackde694a32015-02-19 15:11:11 -0800774def _SetupConnections(options, build_config):
Aviv Keshet55491242017-07-13 17:04:07 -0700775 """Set up CIDB connections using the appropriate Setup call.
Aviv Keshet2982af52014-08-13 16:07:57 -0700776
777 Args:
778 options: Command line options structure.
Aviv Keshet64133022014-08-25 15:50:52 -0700779 build_config: Config object for this build.
Aviv Keshet2982af52014-08-13 16:07:57 -0700780 """
Aviv Keshet420de512015-05-18 14:28:48 -0700781 # Outline:
782 # 1) Based on options and build_config, decide whether we are a production
783 # run, debug run, or standalone run.
784 # 2) Set up cidb instance accordingly.
785 # 3) Update topology info from cidb, so that any other service set up can use
786 # topology.
787 # 4) Set up any other services.
788 run_type = _GetRunEnvironment(options, build_config)
789
790 if run_type == _ENVIRONMENT_PROD:
791 cidb.CIDBConnectionFactory.SetupProdCidb()
Mike Frysingercc292b42019-12-11 13:12:35 -0500792 context = ts_mon_config.SetupTsMonGlobalState('cbuildbot', indirect=True)
Aviv Keshet420de512015-05-18 14:28:48 -0700793 elif run_type == _ENVIRONMENT_DEBUG:
794 cidb.CIDBConnectionFactory.SetupDebugCidb()
Paul Hobbsd5a0f812016-07-26 16:10:31 -0700795 context = ts_mon_config.TrivialContextManager()
Aviv Keshet420de512015-05-18 14:28:48 -0700796 else:
Aviv Keshet62d1a0e2014-08-22 21:16:13 -0700797 cidb.CIDBConnectionFactory.SetupNoCidb()
Paul Hobbsd5a0f812016-07-26 16:10:31 -0700798 context = ts_mon_config.TrivialContextManager()
Aviv Keshet62d1a0e2014-08-22 21:16:13 -0700799
Dhanya Ganeshef0cd5b2019-02-06 16:29:36 -0700800 topology.FetchTopology()
Paul Hobbsd5a0f812016-07-26 16:10:31 -0700801 return context
802
Aviv Keshet2982af52014-08-13 16:07:57 -0700803
Dean Liaoe5b0aca2018-01-24 15:27:26 +0800804class _MockMethodWithReturnValue(object):
805 """A method mocker which just returns the specific value."""
806 def __init__(self, return_value):
807 self.return_value = return_value
808
809 def __call__(self, *args, **kwargs):
810 return self.return_value
811
812
813class _ObjectMethodPatcher(object):
814 """A simplified mock.object.patch.
815
816 It is a context manager that patches an object's method with specified
817 return value.
818 """
819 def __init__(self, target, attr, return_value=None):
820 """Constructor.
821
822 Args:
823 target: object to patch.
824 attr: method name of the object to patch.
825 return_value: the return value when calling target.attr
826 """
827 self.target = target
828 self.attr = attr
829 self.return_value = return_value
830 self.original_attr = None
831 self.new_attr = _MockMethodWithReturnValue(self.return_value)
832
833 def __enter__(self):
834 self.original_attr = self.target.__dict__[self.attr]
835 setattr(self.target, self.attr, self.new_attr)
836
837 def __exit__(self, *args):
838 if self.target and self.original_attr:
839 setattr(self.target, self.attr, self.original_attr)
840
841
Matt Tennant759e2352013-09-27 15:14:44 -0700842# TODO(build): This function is too damn long.
Ryan Cui85867972012-02-23 18:21:49 -0800843def main(argv):
Mike Frysinger80bba8a2017-08-18 15:28:36 -0400844 # We get false positives with the options object.
845 # pylint: disable=attribute-defined-outside-init
846
David James59a0a2b2013-03-22 14:04:44 -0700847 # Turn on strict sudo checks.
848 cros_build_lib.STRICT_SUDO = True
849
Ryan Cui85867972012-02-23 18:21:49 -0800850 # Set umask to 022 so files created by buildbot are readable.
Mike Frysinger60ec1012013-10-21 00:11:10 -0400851 os.umask(0o22)
Ryan Cui85867972012-02-23 18:21:49 -0800852
Ryan Cui85867972012-02-23 18:21:49 -0800853 parser = _CreateParser()
Mike Frysinger80bba8a2017-08-18 15:28:36 -0400854 options = ParseCommandLine(parser, argv)
Don Garrett0a873e02015-06-30 17:55:10 -0700855
Don Garrettb85658c2015-06-30 19:07:22 -0700856 # Fetch our site_config now, because we need it to do anything else.
Don Garrettde81cc72015-07-07 13:23:28 -0700857 site_config = config_lib.GetConfig()
Don Garrettb85658c2015-06-30 19:07:22 -0700858
Mike Frysinger80bba8a2017-08-18 15:28:36 -0400859 _PostParseCheck(parser, options, site_config)
Brian Harring3fec5a82012-03-01 05:57:03 -0800860
Mike Frysinger8fd67dc2012-12-03 23:51:18 -0500861 cros_build_lib.AssertOutsideChroot()
Zdenek Behan98ec2fb2012-08-31 17:12:18 +0200862
Prathmesh Prabhu51d774f2015-07-17 15:11:49 -0700863 if options.enable_buildbot_tags:
Chris McDonaldb55b7032021-06-17 16:41:32 -0600864 cbuildbot_alerts.EnableBuildbotMarkers()
Matt Tennant759e2352013-09-27 15:14:44 -0700865
Don Garrett0c6e0272017-12-13 17:05:21 -0800866 if (options.buildbot and
867 not options.debug and
Don Garrett0c6e0272017-12-13 17:05:21 -0800868 not cros_build_lib.HostIsCIBuilder()):
Evan Hernandez73263be2019-03-14 15:17:59 -0600869 # --buildbot can only be used on a real builder, unless it's debug.
Don Garrett0c6e0272017-12-13 17:05:21 -0800870 cros_build_lib.Die('This host is not a supported build machine.')
Ningning Xiac691e432016-08-11 14:52:59 -0700871
Matt Tennant759e2352013-09-27 15:14:44 -0700872 # Only one config arg is allowed in this mode, which was confirmed earlier.
Don Garrettf0761152017-10-19 19:38:27 -0700873 build_config = site_config[options.build_config_name]
Brian Harring3fec5a82012-03-01 05:57:03 -0800874
Don Garrettbbd7b552014-05-16 13:15:21 -0700875 # TODO: Re-enable this block when reference_repo support handles this
876 # properly. (see chromium:330775)
877 # if options.reference_repo is None:
878 # repo_path = os.path.join(options.sourceroot, '.repo')
879 # # If we're being run from a repo checkout, reuse the repo's git pool to
880 # # cut down on sync time.
881 # if os.path.exists(repo_path):
882 # options.reference_repo = options.sourceroot
883
884 if options.reference_repo:
David Jamesdac7a912013-11-18 11:14:44 -0800885 if not os.path.exists(options.reference_repo):
886 parser.error('Reference path %s does not exist'
887 % (options.reference_repo,))
888 elif not os.path.exists(os.path.join(options.reference_repo, '.repo')):
889 parser.error('Reference path %s does not look to be the base of a '
890 'repo checkout; no .repo exists in the root.'
891 % (options.reference_repo,))
892
Brian Harringf11bf682012-05-14 15:53:43 -0700893 if (options.buildbot or options.remote_trybot) and not options.resume:
David Jamesaad5cc72012-10-26 15:03:13 -0700894 missing = osutils.FindMissingBinaries(_BUILDBOT_REQUIRED_BINARIES)
Brian Harring351ce442012-03-09 16:38:14 -0800895 if missing:
David Jameseecba232014-06-11 11:35:11 -0700896 parser.error('Option --buildbot/--remote-trybot requires the following '
Ryan Cuid4a24212012-04-04 18:08:12 -0700897 "binaries which couldn't be found in $PATH: %s"
Brian Harring351ce442012-03-09 16:38:14 -0800898 % (', '.join(missing)))
899
David Jamesdac7a912013-11-18 11:14:44 -0800900 if options.reference_repo:
901 options.reference_repo = os.path.abspath(options.reference_repo)
902
Brian Harring3fec5a82012-03-01 05:57:03 -0800903 # Sanity check of buildroot- specifically that it's not pointing into the
904 # midst of an existing repo since git-repo doesn't support nesting.
Brian Harring3fec5a82012-03-01 05:57:03 -0800905 if (not repository.IsARepoRoot(options.buildroot) and
David James13a69c92013-05-09 10:37:42 -0700906 git.FindRepoDir(options.buildroot)):
Don Garrett211df8c2017-09-06 13:33:02 -0700907 cros_build_lib.Die(
908 'Configured buildroot %s is a subdir of an existing repo checkout.'
909 % options.buildroot)
Brian Harring3fec5a82012-03-01 05:57:03 -0800910
Chris Sosab5ea3b42012-10-25 15:25:20 -0700911 if not options.log_dir:
912 options.log_dir = os.path.join(options.buildroot, _DEFAULT_LOG_DIR)
913
Brian Harringd166aaf2012-05-14 18:31:53 -0700914 log_file = None
915 if options.tee:
Chris Sosab5ea3b42012-10-25 15:25:20 -0700916 log_file = os.path.join(options.log_dir, _BUILDBOT_LOG_FILE)
917 osutils.SafeMakedirs(options.log_dir)
Brian Harringd166aaf2012-05-14 18:31:53 -0700918 _BackupPreviousLog(log_file)
919
Brian Harring1b8c4c82012-05-29 23:03:04 -0700920 with cros_build_lib.ContextManagerStack() as stack:
Lann Martin8cc2eab2018-09-05 17:17:57 -0600921 # Preserve chromite; we might be running from there!
922 options.preserve_paths = set(['chromite'])
David Jamescebc7272013-07-17 16:45:05 -0700923 if log_file is not None:
924 # We don't want the critical section to try to clean up the tee process,
925 # so we run Tee (forked off) outside of it. This prevents a deadlock
926 # because the Tee process only exits when its pipe is closed, and the
927 # critical section accidentally holds on to that file handle.
928 stack.Add(tee.Tee, log_file)
929 options.preserve_paths.add(_DEFAULT_LOG_DIR)
930
Brian Harringc2d09d92012-05-13 22:03:15 -0700931 critical_section = stack.Add(cleanup.EnforcedCleanupSection)
932 stack.Add(sudo.SudoKeepAlive)
Brian Harringd166aaf2012-05-14 18:31:53 -0700933
Brian Harringc2d09d92012-05-13 22:03:15 -0700934 if not options.resume:
Brian Harring2bf55e12012-05-13 21:31:55 -0700935 # If we're in resume mode, use our parents tempdir rather than
936 # nesting another layer.
David James4bc13702013-03-26 08:08:04 -0700937 stack.Add(osutils.TempDir, prefix='cbuildbot-tmp', set_global=True)
David Jameseecba232014-06-11 11:35:11 -0700938 logging.debug('Cbuildbot tempdir is %r.', os.environ.get('TMP'))
Brian Harringd166aaf2012-05-14 18:31:53 -0700939
Brian Harringc2d09d92012-05-13 22:03:15 -0700940 if options.cgroups:
Mike Nicholsa1414162021-04-22 20:07:22 +0000941 stack.Add(cgroups.SimpleContainChildren, 'cbuildbot')
Brian Harringa184efa2012-03-04 11:51:25 -0800942
Brian Harringc2d09d92012-05-13 22:03:15 -0700943 # Mark everything between EnforcedCleanupSection and here as having to
944 # be rolled back via the contextmanager cleanup handlers. This
945 # ensures that sudo bits cannot outlive cbuildbot, that anything
946 # cgroups would kill gets killed, etc.
David Jamesfb3aac92013-10-16 13:26:52 -0700947 stack.Add(critical_section.ForkWatchdog)
Brian Harringd166aaf2012-05-14 18:31:53 -0700948
Aviv Keshetcf9c2722014-02-25 15:15:10 -0800949 if options.mock_slave_status is not None:
950 with open(options.mock_slave_status, 'r') as f:
Aviv Keshet4e750022014-03-07 16:50:34 -0800951 mock_statuses = pickle.load(f)
Mike Frysinger0bdbc102019-06-13 15:27:29 -0400952 for key, value in mock_statuses.items():
Ningning Xiaf342b952017-02-15 14:13:33 -0800953 mock_statuses[key] = builder_status_lib.BuilderStatus(**value)
Dean Liaoe5b0aca2018-01-24 15:27:26 +0800954 stack.Add(_ObjectMethodPatcher,
Mike Nicholsa1414162021-04-22 20:07:22 +0000955 completion_stages.MasterSlaveSyncCompletionStage,
956 '_FetchSlaveStatuses',
Yu-Ju Hongd0fda382014-05-09 15:28:24 -0700957 return_value=mock_statuses)
Aviv Keshetcf9c2722014-02-25 15:15:10 -0800958
Paul Hobbsd5a0f812016-07-26 16:10:31 -0700959 stack.Add(_SetupConnections, options, build_config)
Don Garrettb4318362014-10-03 15:49:36 -0700960 retry_stats.SetupStats()
Aviv Keshet2982af52014-08-13 16:07:57 -0700961
Dhanya Ganesh4339cbc2019-03-08 12:02:14 -0700962 timeout_display_message = (
963 'This build has reached the timeout deadline set by the master. '
964 'Either this stage or a previous one took too long (see stage '
965 'timing historical summary in ReportStage) or the build failed '
966 'to start on time.')
Prathmesh Prabhu80e05df2014-12-11 15:20:33 -0800967
968 if options.timeout > 0:
Aviv Keshet446f07f2016-03-08 11:32:31 -0800969 stack.Add(timeout_util.FatalTimeout, options.timeout,
970 timeout_display_message)
Ningning Xiaad483542016-05-24 12:27:21 -0700971 try:
972 _RunBuildStagesWrapper(options, site_config, build_config)
973 except failures_lib.ExitEarlyException as ex:
974 # This build finished successfully. Do not re-raise ExitEarlyException.
975 logging.info('One stage exited early: %s', ex)