blob: d67e9d9b9e851958ff65a14b880c015d68a4c2ac [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
Mike Frysinger383367e2014-09-16 15:06:17 -040011from __future__ import print_function
12
Aviv Keshet593014d2017-07-18 17:28:25 -070013import distutils.version # pylint: disable=import-error,no-name-in-module
Brian Harring3fec5a82012-03-01 05:57:03 -080014import glob
Aviv Keshet669eb5e2014-06-23 08:53:01 -070015import json
Mike Frysinger05c5faf2015-02-04 21:46:46 -050016import mock
Mike Frysingerb0b0caa2015-11-07 01:05:18 -050017import optparse # pylint: disable=deprecated-module
Brian Harring3fec5a82012-03-01 05:57:03 -080018import os
Aviv Keshetcf9c2722014-02-25 15:15:10 -080019import pickle
Brian Harring3fec5a82012-03-01 05:57:03 -080020import sys
21
Mike Frysingere4d68c22015-02-04 21:26:24 -050022from chromite.cbuildbot import builders
Don Garrett88b8d782014-05-13 17:30:55 -070023from chromite.cbuildbot import cbuildbot_run
Don Garrett88b8d782014-05-13 17:30:55 -070024from chromite.cbuildbot import repository
25from chromite.cbuildbot import tee
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
Aviv Keshet593014d2017-07-18 17:28:25 -070028from chromite.lib.const import waterfall
Ningning Xiaf342b952017-02-15 14:13:33 -080029from chromite.lib import builder_status_lib
Aviv Keshet2982af52014-08-13 16:07:57 -070030from chromite.lib import cidb
Brian Harringc92a7012012-02-29 10:11:34 -080031from chromite.lib import cgroups
Brian Harringa184efa2012-03-04 11:51:25 -080032from chromite.lib import cleanup
Brian Harringb6cf9142012-09-01 20:43:17 -070033from chromite.lib import commandline
Ningning Xia6a718052016-12-22 10:08:15 -080034from chromite.lib import config_lib
35from chromite.lib import constants
Brian Harring1b8c4c82012-05-29 23:03:04 -070036from chromite.lib import cros_build_lib
Ralph Nathan91874ca2015-03-19 13:29:41 -070037from chromite.lib import cros_logging as logging
Ningning Xia6a718052016-12-22 10:08:15 -080038from chromite.lib import failures_lib
David James97d95872012-11-16 15:09:56 -080039from chromite.lib import git
Stefan Zagerd49d9ff2014-08-15 21:33:37 -070040from chromite.lib import gob_util
Brian Harringaf019fb2012-05-10 15:06:13 -070041from chromite.lib import osutils
David James6450a0a2012-12-04 07:59:53 -080042from chromite.lib import parallel
Don Garrettb4318362014-10-03 15:49:36 -070043from chromite.lib import retry_stats
Brian Harring3fec5a82012-03-01 05:57:03 -080044from chromite.lib import sudo
David James3432acd2013-11-27 10:02:18 -080045from chromite.lib import timeout_util
Drew Davenportd7c22c12017-06-07 16:16:54 -060046from chromite.lib import tree_status
Paul Hobbsfcf10342015-12-29 15:52:31 -080047from chromite.lib import ts_mon_config
Brian Harring3fec5a82012-03-01 05:57:03 -080048
Ryan Cuiadd49122012-03-21 22:19:58 -070049
Brian Harring3fec5a82012-03-01 05:57:03 -080050_DEFAULT_LOG_DIR = 'cbuildbot_logs'
51_BUILDBOT_LOG_FILE = 'cbuildbot.log'
52_DEFAULT_EXT_BUILDROOT = 'trybot'
53_DEFAULT_INT_BUILDROOT = 'trybot-internal'
Brian Harring351ce442012-03-09 16:38:14 -080054_BUILDBOT_REQUIRED_BINARIES = ('pbzip2',)
Ryan Cui1c13a252012-10-16 15:00:16 -070055_API_VERSION_ATTR = 'api_version'
Brian Harring3fec5a82012-03-01 05:57:03 -080056
57
Brian Harring3fec5a82012-03-01 05:57:03 -080058def _BackupPreviousLog(log_file, backup_limit=25):
59 """Rename previous log.
60
61 Args:
62 log_file: The absolute path to the previous log.
Aviv Keshet9e4236b2013-12-13 13:07:50 -080063 backup_limit: Maximum number of old logs to keep.
Brian Harring3fec5a82012-03-01 05:57:03 -080064 """
65 if os.path.exists(log_file):
66 old_logs = sorted(glob.glob(log_file + '.*'),
67 key=distutils.version.LooseVersion)
68
69 if len(old_logs) >= backup_limit:
70 os.remove(old_logs[0])
71
72 last = 0
73 if old_logs:
74 last = int(old_logs.pop().rpartition('.')[2])
75
76 os.rename(log_file, log_file + '.' + str(last + 1))
77
Ryan Cui5616a512012-08-17 13:39:36 -070078
Gaurav Shah298aa372014-01-31 09:27:24 -080079def _IsDistributedBuilder(options, chrome_rev, build_config):
80 """Determines whether the builder should be a DistributedBuilder.
81
82 Args:
83 options: options passed on the commandline.
84 chrome_rev: Chrome revision to build.
85 build_config: Builder configuration dictionary.
86
87 Returns:
88 True if the builder should be a distributed_builder
89 """
Don Garrett0bc85672015-07-23 19:46:00 +000090 if build_config['pre_cq']:
Gaurav Shah298aa372014-01-31 09:27:24 -080091 return True
92 elif not options.buildbot:
93 return False
94 elif chrome_rev in (constants.CHROME_REV_TOT,
95 constants.CHROME_REV_LOCAL,
96 constants.CHROME_REV_SPEC):
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
105 return False
106
107
Don Garretta52a5b02015-06-02 14:52:57 -0700108def _RunBuildStagesWrapper(options, site_config, build_config):
Brian Harring3fec5a82012-03-01 05:57:03 -0800109 """Helper function that wraps RunBuildStages()."""
Ralph Nathan03047282015-03-23 11:09:32 -0700110 logging.info('cbuildbot was executed with args %s' %
111 cros_build_lib.CmdToStr(sys.argv))
Brian Harring3fec5a82012-03-01 05:57:03 -0800112
David Jamesa0a664e2013-02-13 09:52:01 -0800113 chrome_rev = build_config['chrome_rev']
114 if options.chrome_rev:
115 chrome_rev = options.chrome_rev
116 if chrome_rev == constants.CHROME_REV_TOT:
Stefan Zagerd49d9ff2014-08-15 21:33:37 -0700117 options.chrome_version = gob_util.GetTipOfTrunkRevision(
118 constants.CHROMIUM_GOB_URL)
David Jamesa0a664e2013-02-13 09:52:01 -0800119 options.chrome_rev = constants.CHROME_REV_SPEC
120
David James4a404a52013-02-19 13:07:59 -0800121 # If it's likely we'll need to build Chrome, fetch the source.
Mike Frysingerf4d9ab82013-03-05 19:38:05 -0500122 if build_config['sync_chrome'] is None:
David Jameseecba232014-06-11 11:35:11 -0700123 options.managed_chrome = (
124 chrome_rev != constants.CHROME_REV_LOCAL and
Mike Frysingerf4d9ab82013-03-05 19:38:05 -0500125 (not build_config['usepkg_build_packages'] or chrome_rev or
Mike Frysinger8b1bd822017-08-11 16:11:42 -0400126 build_config['profile']))
Mike Frysingerf4d9ab82013-03-05 19:38:05 -0500127 else:
128 options.managed_chrome = build_config['sync_chrome']
David James2333c182013-02-13 16:16:15 -0800129
130 if options.managed_chrome:
131 # Tell Chrome to fetch the source locally.
Matt Tennant628ffdd2013-11-27 14:44:39 -0800132 internal = constants.USE_CHROME_INTERNAL in build_config['useflags']
David James2333c182013-02-13 16:16:15 -0800133 chrome_src = 'chrome-src-internal' if internal else 'chrome-src'
YH Linb1ea83c2016-10-13 15:47:09 -0700134 target_name = 'target'
135 if options.branch:
136 # Tie the cache per branch
137 target_name = 'target-%s' % options.branch
138 options.chrome_root = os.path.join(options.cache_dir, 'distfiles',
139 target_name, chrome_src)
140 # Create directory if in need
141 osutils.SafeMakedirsNonRoot(options.chrome_root)
David James2333c182013-02-13 16:16:15 -0800142
Aviv Keshet669eb5e2014-06-23 08:53:01 -0700143 metadata_dump_dict = {}
144 if options.metadata_dump:
145 with open(options.metadata_dump, 'r') as metadata_file:
146 metadata_dump_dict = json.loads(metadata_file.read())
147
Matt Tennant95a42ad2013-12-27 15:38:36 -0800148 # We are done munging options values, so freeze options object now to avoid
149 # further abuse of it.
150 # TODO(mtennant): one by one identify each options value override and see if
151 # it can be handled another way. Try to push this freeze closer and closer
152 # to the start of the script (e.g. in or after _PostParseCheck).
153 options.Freeze()
154
Matt Tennant0940c382014-01-21 20:43:55 -0800155 with parallel.Manager() as manager:
Don Garretta52a5b02015-06-02 14:52:57 -0700156 builder_run = cbuildbot_run.BuilderRun(
157 options, site_config, build_config, manager)
Aviv Keshet669eb5e2014-06-23 08:53:01 -0700158 if metadata_dump_dict:
159 builder_run.attrs.metadata.UpdateWithDict(metadata_dump_dict)
Mike Frysingere4d68c22015-02-04 21:26:24 -0500160
Mike Frysinger05c5faf2015-02-04 21:46:46 -0500161 if builder_run.config.builder_class_name is None:
Don Garrett56e6ed32015-06-23 16:52:20 -0700162 # TODO: This should get relocated to chromeos_config.
Mike Frysingere4d68c22015-02-04 21:26:24 -0500163 if _IsDistributedBuilder(options, chrome_rev, build_config):
Mike Frysinger05c5faf2015-02-04 21:46:46 -0500164 builder_cls_name = 'simple_builders.DistributedBuilder'
Mike Frysingere4d68c22015-02-04 21:26:24 -0500165 else:
Mike Frysinger05c5faf2015-02-04 21:46:46 -0500166 builder_cls_name = 'simple_builders.SimpleBuilder'
167 builder_cls = builders.GetBuilderClass(builder_cls_name)
168 builder = builder_cls(builder_run)
Matt Tennant0940c382014-01-21 20:43:55 -0800169 else:
Mike Frysinger05c5faf2015-02-04 21:46:46 -0500170 builder = builders.Builder(builder_run)
Mike Frysingere4d68c22015-02-04 21:26:24 -0500171
Matt Tennant0940c382014-01-21 20:43:55 -0800172 if not builder.Run():
173 sys.exit(1)
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):
Aviv Keshet9e4236b2013-12-13 13:07:50 -0800220 """Custom option parser which supports arguments passed-trhough 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.')
250 parser.add_option('--bootstrap-dir', type='path',
Prathmesh Prabhu867c1172015-06-02 17:57:59 -0700251 help='Bootstrapping cbuildbot may involve checking out '
252 'multiple copies of chromite. All these checkouts '
253 'will be contained in the directory specified here. '
254 'Default:%s' % osutils.GetGlobalTempDir())
Hidehiko Abe863d7882017-03-09 22:27:28 +0900255 parser.add_remote_option('--android_rev', type='choice',
David Riley486b2612016-02-22 19:59:26 -0800256 choices=constants.VALID_ANDROID_REVISIONS,
257 help=('Revision of Android to use, of type [%s]'
258 % '|'.join(constants.VALID_ANDROID_REVISIONS)))
Hidehiko Abe863d7882017-03-09 22:27:28 +0900259 parser.add_remote_option('--chrome_rev', type='choice',
David Riley486b2612016-02-22 19:59:26 -0800260 choices=constants.VALID_CHROME_REVISIONS,
Ryan Cuieaa9efd2012-04-25 17:56:45 -0700261 help=('Revision of Chrome to use, of type [%s]'
262 % '|'.join(constants.VALID_CHROME_REVISIONS)))
Hidehiko Abe863d7882017-03-09 22:27:28 +0900263 parser.add_remote_option('--profile',
Ryan Cuieaa9efd2012-04-25 17:56:45 -0700264 help='Name of profile to sub-specify board variant.')
Hidehiko Abe95d7cf62017-03-07 23:34:30 +0900265 # TODO(crbug.com/279618): Running GOMA is under development. Following
266 # flags are added for development purpose due to repository dependency,
267 # but not officially supported yet.
268 parser.add_option('--goma_dir', type='path',
269 api=constants.REEXEC_API_GOMA,
270 help='Specify a directory containing goma. When this is '
271 'set, GOMA is used to build Chrome.')
272 parser.add_option('--goma_client_json', type='path',
273 api=constants.REEXEC_API_GOMA,
274 help='Specify a service-account-goma-client.json path. '
275 'The file is needed on bots to run GOMA.')
Brian Harring3fec5a82012-03-01 05:57:03 -0800276
Don Garrett211df8c2017-09-06 13:33:02 -0700277 group = CustomGroup(
278 parser,
279 'Deprecated Options')
280
281 parser.add_option('--local', action='store_true', default=False,
Don Garrettcc0ee522017-09-13 14:28:42 -0700282 help='Deprecated. See cros tryjob.')
Don Garrett211df8c2017-09-06 13:33:02 -0700283 parser.add_option('--remote', action='store_true', default=False,
Don Garrettcc0ee522017-09-13 14:28:42 -0700284 help='Deprecated. See cros tryjob.')
Don Garrett211df8c2017-09-06 13:33:02 -0700285
Ryan Cuif4f84be2012-07-09 18:50:41 -0700286 #
Mike Frysinger81af6ef2013-04-03 02:24:09 -0400287 # Patch selection options.
288 #
289
290 group = CustomGroup(
291 parser,
292 'Patch Options')
293
Mike Frysingerdad205d2017-08-11 16:00:14 -0400294 group.add_remote_option('-g', '--gerrit-patches', action='split_extend',
Hidehiko Abe863d7882017-03-09 22:27:28 +0900295 type='string', default=[],
Mike Frysinger81af6ef2013-04-03 02:24:09 -0400296 metavar="'Id1 *int_Id2...IdN'",
Hidehiko Abe863d7882017-03-09 22:27:28 +0900297 help='Space-separated list of short-form Gerrit '
298 "Change-Id's or change numbers to patch. "
299 "Please prepend '*' to internal Change-Id's")
Mike Frysinger81af6ef2013-04-03 02:24:09 -0400300
Mike Frysinger68893242017-08-11 14:16:39 -0400301 parser.add_argument_group(group)
Mike Frysinger81af6ef2013-04-03 02:24:09 -0400302
303 #
304 # Remote trybot options.
305 #
306
307 group = CustomGroup(
308 parser,
Don Garrett211df8c2017-09-06 13:33:02 -0700309 'Options used to configure tryjob behavior.')
Hidehiko Abe863d7882017-03-09 22:27:28 +0900310 group.add_remote_option('--hwtest', action='store_true', default=False,
David Jameseecba232014-06-11 11:35:11 -0700311 help='Run the HWTest stage (tests on real hardware)')
Mike Frysingerdad205d2017-08-11 16:00:14 -0400312 group.add_remote_option('--channel', action='split_extend', dest='channels',
Don Garrett4bb21682014-03-03 16:16:23 -0800313 default=[],
Hidehiko Abe863d7882017-03-09 22:27:28 +0900314 help='Specify a channel for a payloads trybot. Can '
315 'be specified multiple times. No valid for '
316 'non-payloads configs.')
Mike Frysinger81af6ef2013-04-03 02:24:09 -0400317
Mike Frysinger68893242017-08-11 14:16:39 -0400318 parser.add_argument_group(group)
Mike Frysinger81af6ef2013-04-03 02:24:09 -0400319
320 #
Ryan Cui88b901c2013-06-21 11:35:30 -0700321 # Branch creation options.
322 #
323
324 group = CustomGroup(
325 parser,
326 'Branch Creation Options (used with branch-util)')
327
328 group.add_remote_option('--branch-name',
329 help='The branch to create or delete.')
Hidehiko Abe863d7882017-03-09 22:27:28 +0900330 group.add_remote_option('--delete-branch', action='store_true', default=False,
Ryan Cui88b901c2013-06-21 11:35:30 -0700331 help='Delete the branch specified in --branch-name.')
Hidehiko Abe863d7882017-03-09 22:27:28 +0900332 group.add_remote_option('--rename-to',
Ryan Cui88b901c2013-06-21 11:35:30 -0700333 help='Rename a branch to the specified name.')
Hidehiko Abe863d7882017-03-09 22:27:28 +0900334 group.add_remote_option('--force-create', action='store_true', default=False,
Ryan Cui88b901c2013-06-21 11:35:30 -0700335 help='Overwrites an existing branch.')
Hidehiko Abe863d7882017-03-09 22:27:28 +0900336 group.add_remote_option('--skip-remote-push', action='store_true',
337 default=False,
Prathmesh Prabhue5f4d472015-05-07 16:52:10 -0700338 help='Do not actually push to remote git repos. '
339 'Used for end-to-end testing branching.')
Ryan Cui88b901c2013-06-21 11:35:30 -0700340
Mike Frysinger68893242017-08-11 14:16:39 -0400341 parser.add_argument_group(group)
Ryan Cui88b901c2013-06-21 11:35:30 -0700342
343 #
Mike Frysinger81af6ef2013-04-03 02:24:09 -0400344 # Advanced options.
Ryan Cuif4f84be2012-07-09 18:50:41 -0700345 #
346
Ryan Cuieaa9efd2012-04-25 17:56:45 -0700347 group = CustomGroup(
Brian Harring3fec5a82012-03-01 05:57:03 -0800348 parser,
349 'Advanced Options',
350 'Caution: use these options at your own risk.')
351
Mike Frysinger81af6ef2013-04-03 02:24:09 -0400352 group.add_remote_option('--bootstrap-args', action='append', default=[],
Hidehiko Abe863d7882017-03-09 22:27:28 +0900353 help='Args passed directly to the bootstrap re-exec '
354 'to skip verification by the bootstrap code')
355 group.add_remote_option('--buildbot', action='store_true', dest='buildbot',
Bernie Thompson63f30062016-12-21 15:24:25 -0800356 default=False,
357 help='This is running on a buildbot. '
358 'This can be used to make a build operate '
359 'like an official builder, e.g. generate '
360 'new version numbers and archive official '
361 'artifacts and such. This should only be '
362 'used if you are confident in what you are '
363 'doing, as it will make automated commits.')
Don Garrett07d46262017-04-13 12:06:44 -0700364 parser.add_remote_option('--repo-cache', type='path', dest='_repo_cache',
365 help='Present for backwards compatibility, ignored.')
Prathmesh Prabhu51d774f2015-07-17 15:11:49 -0700366 group.add_remote_option('--no-buildbot-tags', action='store_false',
367 dest='enable_buildbot_tags', default=True,
368 help='Suppress buildbot specific tags from log '
369 'output. This is used to hide recursive '
370 'cbuilbot runs on the waterfall.')
Hidehiko Abe863d7882017-03-09 22:27:28 +0900371 group.add_remote_option('--buildnumber', type='int', default=0,
372 help='build number')
373 group.add_option('--chrome_root', action='callback', type='path',
374 callback=_CheckChromeRootOption,
375 help='Local checkout of Chrome to use.')
376 group.add_remote_option('--chrome_version', action='callback', type='string',
377 dest='chrome_version',
Ryan Cuieaa9efd2012-04-25 17:56:45 -0700378 callback=_CheckChromeVersionOption,
Hidehiko Abe863d7882017-03-09 22:27:28 +0900379 help='Used with SPEC logic to force a particular '
380 'git revision of chrome rather than the '
381 'latest.')
382 group.add_remote_option('--clobber', action='store_true', default=False,
Ryan Cuieaa9efd2012-04-25 17:56:45 -0700383 help='Clears an old checkout before syncing')
Mike Frysinger81af6ef2013-04-03 02:24:09 -0400384 group.add_remote_option('--latest-toolchain', action='store_true',
385 default=False,
386 help='Use the latest toolchain.')
Ryan Cui5ba7e152012-05-10 14:36:52 -0700387 parser.add_option('--log_dir', dest='log_dir', type='path',
Hidehiko Abe863d7882017-03-09 22:27:28 +0900388 help='Directory where logs are stored.')
389 group.add_remote_option('--maxarchives', type='int',
390 dest='max_archive_builds', default=3,
David Jameseecba232014-06-11 11:35:11 -0700391 help='Change the local saved build count limit.')
Ryan Cuibbd3d4b2012-08-17 12:20:37 -0700392 parser.add_remote_option('--manifest-repo-url',
Hidehiko Abe863d7882017-03-09 22:27:28 +0900393 help='Overrides the default manifest repo url.')
David James565bc9a2013-04-08 14:54:45 -0700394 group.add_remote_option('--compilecheck', action='store_true', default=False,
395 help='Only verify compilation and unit tests.')
Ryan Cuieaa9efd2012-04-25 17:56:45 -0700396 group.add_remote_option('--noarchive', action='store_false', dest='archive',
397 default=True, help="Don't run archive stage.")
Ryan Cuif7f24692012-05-18 16:35:33 -0700398 group.add_remote_option('--nobootstrap', action='store_false',
399 dest='bootstrap', default=True,
Hidehiko Abe863d7882017-03-09 22:27:28 +0900400 help="Don't checkout and run from a standalone "
401 'chromite repo.')
Ryan Cuieaa9efd2012-04-25 17:56:45 -0700402 group.add_remote_option('--nobuild', action='store_false', dest='build',
403 default=True,
404 help="Don't actually build (for cbuildbot dev)")
405 group.add_remote_option('--noclean', action='store_false', dest='clean',
406 default=True, help="Don't clean the buildroot")
Ryan Cuif7f24692012-05-18 16:35:33 -0700407 group.add_remote_option('--nocgroups', action='store_false', dest='cgroups',
408 default=True,
409 help='Disable cbuildbots usage of cgroups.')
Ryan Cui3ea98e02013-08-07 16:01:48 -0700410 group.add_remote_option('--nochromesdk', action='store_false',
411 dest='chrome_sdk', default=True,
Hidehiko Abe863d7882017-03-09 22:27:28 +0900412 help="Don't run the ChromeSDK stage which builds "
413 'Chrome outside of the chroot.')
Ryan Cuieaa9efd2012-04-25 17:56:45 -0700414 group.add_remote_option('--noprebuilts', action='store_false',
415 dest='prebuilts', default=True,
416 help="Don't upload prebuilts.")
Ryan Cui88b901c2013-06-21 11:35:30 -0700417 group.add_remote_option('--nopatch', action='store_false',
418 dest='postsync_patch', default=True,
Hidehiko Abe863d7882017-03-09 22:27:28 +0900419 help="Don't run PatchChanges stage. This does not "
420 'disable patching in of chromite patches '
421 'during BootstrapStage.')
Don Garrett82c0ae82014-02-03 18:25:11 -0800422 group.add_remote_option('--nopaygen', action='store_false',
423 dest='paygen', default=True,
424 help="Don't generate payloads.")
Ryan Cui88b901c2013-06-21 11:35:30 -0700425 group.add_remote_option('--noreexec', action='store_false',
426 dest='postsync_reexec', default=True,
427 help="Don't reexec into the buildroot after syncing.")
Hidehiko Abe863d7882017-03-09 22:27:28 +0900428 group.add_remote_option('--nosdk', action='store_true', default=False,
Mike Frysinger81af6ef2013-04-03 02:24:09 -0400429 help='Re-create the SDK from scratch.')
Ryan Cuieaa9efd2012-04-25 17:56:45 -0700430 group.add_remote_option('--nosync', action='store_false', dest='sync',
431 default=True, help="Don't sync before building.")
Ryan Cuieaa9efd2012-04-25 17:56:45 -0700432 group.add_remote_option('--notests', action='store_false', dest='tests',
433 default=True,
xixuan7774ba82017-06-22 16:04:00 -0700434 help='Override values from buildconfig, run no '
435 'tests, and build no autotest and artifacts.')
436 group.add_remote_option('--novmtests', action='store_false', dest='vmtests',
437 default=True,
438 help='Override values from buildconfig, run no '
439 'vmtests.')
Nam T. Nguyenc93f1342014-07-11 14:40:54 -0700440 group.add_remote_option('--noimagetests', action='store_false',
441 dest='image_test', default=True,
Hidehiko Abe863d7882017-03-09 22:27:28 +0900442 help='Override values from buildconfig and run no '
443 'image tests.')
Ryan Cuieaa9efd2012-04-25 17:56:45 -0700444 group.add_remote_option('--nouprev', action='store_false', dest='uprev',
445 default=True,
Hidehiko Abe863d7882017-03-09 22:27:28 +0900446 help='Override values from buildconfig and never '
447 'uprev.')
448 group.add_option('--reference-repo',
449 help='Reuse git data stored in an existing repo '
450 'checkout. This can drastically reduce the network '
451 'time spent setting up the trybot checkout. By '
452 "default, if this option isn't given but cbuildbot "
453 'is invoked from a repo checkout, cbuildbot will '
454 'use the repo root.')
Ryan Cuicedd8a52012-03-22 02:28:35 -0700455 group.add_option('--resume', action='store_true', default=False,
Ryan Cuieaa9efd2012-04-25 17:56:45 -0700456 help='Skip stages already successfully completed.')
Hidehiko Abe863d7882017-03-09 22:27:28 +0900457 group.add_remote_option('--timeout', type='int', default=0,
458 help='Specify the maximum amount of time this job '
459 'can run for, at which point the build will be '
460 'aborted. If set to zero, then there is no '
461 'timeout.')
462 group.add_remote_option('--version', dest='force_version',
463 help='Used with manifest logic. Forces use of this '
464 'version rather than create or get latest. '
465 'Examples: 4815.0.0-rc1, 4815.1.2')
466 group.add_remote_option('--git-cache-dir', type='path',
Don Garrettbb79be92016-09-27 11:14:07 -0700467 api=constants.REEXEC_API_GIT_CACHE_DIR,
Hidehiko Abe863d7882017-03-09 22:27:28 +0900468 help='Specify the cache directory to store the '
469 'project caches populated by the git-cache '
470 'tool. Bootstrap the projects based on the git '
471 'cache files instead of fetching them directly '
472 'from the GoB servers.')
Ningning Xia9ab36022017-07-28 16:49:25 -0700473 group.add_remote_option('--sanity-check-build', action='store_true',
474 default=False, dest='sanity_check_build',
475 api=constants.REEXEC_API_SANITY_CHECK_BUILD,
476 help='Run the build as a sanity check build.')
Mike Frysinger81af6ef2013-04-03 02:24:09 -0400477
Mike Frysinger68893242017-08-11 14:16:39 -0400478 parser.add_argument_group(group)
Mike Frysinger81af6ef2013-04-03 02:24:09 -0400479
480 #
481 # Internal options.
482 #
483
484 group = CustomGroup(
485 parser,
Mike Frysinger34db8692013-11-11 14:54:08 -0500486 'Internal Chromium OS Build Team Options',
487 'Caution: these are for meant for the Chromium OS build team only')
Mike Frysinger81af6ef2013-04-03 02:24:09 -0400488
489 group.add_remote_option('--archive-base', type='gs_path',
Hidehiko Abe863d7882017-03-09 22:27:28 +0900490 help='Base GS URL (gs://<bucket_name>/<path>) to '
491 'upload archive artifacts to')
David Jameseecba232014-06-11 11:35:11 -0700492 group.add_remote_option(
Hidehiko Abe863d7882017-03-09 22:27:28 +0900493 '--cq-gerrit-query', dest='cq_gerrit_override',
494 help='If given, this gerrit query will be used to find what patches to '
495 "test, rather than the normal 'CommitQueue>=1 AND Verified=1 AND "
496 "CodeReview=2' query it defaults to. Use with care- note "
497 'additionally this setting only has an effect if the buildbot '
498 "target is a cq target, and we're in buildbot mode.")
499 group.add_option('--pass-through', action='append', type='string',
500 dest='pass_through_args', default=[])
501 group.add_option('--reexec-api-version', action='store_true',
502 dest='output_api_version', default=False,
503 help='Used for handling forwards/backwards compatibility '
504 'with --resume and --bootstrap')
505 group.add_option('--remote-trybot', action='store_true', default=False,
Mike Frysinger81af6ef2013-04-03 02:24:09 -0400506 help='Indicates this is running on a remote trybot machine')
Hidehiko Abe863d7882017-03-09 22:27:28 +0900507 group.add_option('--buildbucket-id',
508 help='The unique ID in buildbucket of current build '
509 'generated by buildbucket.')
Mike Frysingerdad205d2017-08-11 16:00:14 -0400510 group.add_remote_option('--remote-patches', action='split_extend', default=[],
Hidehiko Abe863d7882017-03-09 22:27:28 +0900511 help='Patches uploaded by the trybot client when '
512 'run using the -p option')
Brian Harringf611e6e2012-07-17 18:47:44 -0700513 # Note the default here needs to be hardcoded to 3; that is the last version
514 # that lacked this functionality.
Hidehiko Abe863d7882017-03-09 22:27:28 +0900515 group.add_option('--remote-version', type='int', default=3,
Don Garrettbb965dc2017-09-14 17:24:18 -0700516 help='Deprecated and ignored.')
Mike Frysinger81af6ef2013-04-03 02:24:09 -0400517 group.add_option('--sourceroot', type='path', default=constants.SOURCE_ROOT)
Paul Hobbs3cbdf332017-07-05 22:55:32 -0700518 group.add_option('--ts-mon-task-num', type='int', default=0,
Don Garrett5cd946b2017-07-20 13:42:20 -0700519 api=constants.REEXEC_API_TSMON_TASK_NUM,
Paul Hobbs3cbdf332017-07-05 22:55:32 -0700520 help='The task number of this process. Defaults to 0. '
521 'This argument is useful for running multiple copies '
522 'of cbuildbot without their metrics colliding.')
Mike Frysinger81af6ef2013-04-03 02:24:09 -0400523 group.add_remote_option('--test-bootstrap', action='store_true',
524 default=False,
Hidehiko Abe863d7882017-03-09 22:27:28 +0900525 help='Causes cbuildbot to bootstrap itself twice, '
526 'in the sequence A->B->C: A(unpatched) patches '
527 'and bootstraps B; B patches and bootstraps C')
528 group.add_remote_option('--validation_pool',
529 help='Path to a pickled validation pool. Intended '
530 'for use only with the commit queue.')
531 group.add_remote_option('--metadata_dump',
532 help='Path to a json dumped metadata file. This '
533 'will be used as the initial metadata.')
534 group.add_remote_option('--master-build-id', type='int',
Aviv Keshetacf4cfb2014-07-30 12:31:22 -0700535 api=constants.REEXEC_API_MASTER_BUILD_ID,
Hidehiko Abe863d7882017-03-09 22:27:28 +0900536 help='cidb build id of the master build to this '
537 'slave build.')
538 group.add_remote_option('--mock-tree-status',
539 help='Override the tree status value that would be '
540 'returned from the the actual tree. Example '
541 'values: open, closed, throttled. When used '
542 'in conjunction with --debug, the tree status '
543 'will not be ignored as it usually is in a '
544 '--debug run.')
545 group.add_remote_option('--mock-slave-status',
546 metavar='MOCK_SLAVE_STATUS_PICKLE_FILE',
547 help='Override the result of the _FetchSlaveStatuses '
548 'method of MasterSlaveSyncCompletionStage, by '
549 'specifying a file with a pickle of the result '
550 'to be returned.')
Mike Frysinger81af6ef2013-04-03 02:24:09 -0400551
Mike Frysinger68893242017-08-11 14:16:39 -0400552 parser.add_argument_group(group)
Ryan Cuif4f84be2012-07-09 18:50:41 -0700553
554 #
Brian Harring3fec5a82012-03-01 05:57:03 -0800555 # Debug options
Ryan Cuif4f84be2012-07-09 18:50:41 -0700556 #
Brian Harringfec89fe2012-09-23 07:30:54 -0700557 # Temporary hack; in place till --dry-run replaces --debug.
558 # pylint: disable=W0212
Brian Harring009db502012-10-10 02:21:37 -0700559 group = parser.debug_group
Brian Harringfec89fe2012-09-23 07:30:54 -0700560 debug = [x for x in group.option_list if x._long_opts == ['--debug']][0]
David Jameseecba232014-06-11 11:35:11 -0700561 debug.help += ' Currently functions as --dry-run in addition.'
Brian Harringfec89fe2012-09-23 07:30:54 -0700562 debug.pass_through = True
Brian Harring3fec5a82012-03-01 05:57:03 -0800563 group.add_option('--notee', action='store_false', dest='tee', default=True,
Hidehiko Abe863d7882017-03-09 22:27:28 +0900564 help='Disable logging and internal tee process. Primarily '
565 'used for debugging cbuildbot itself.')
Brian Harring3fec5a82012-03-01 05:57:03 -0800566 return parser
567
568
Mike Frysinger80bba8a2017-08-18 15:28:36 -0400569def _FinishParsing(options):
Ryan Cui85867972012-02-23 18:21:49 -0800570 """Perform some parsing tasks that need to take place after optparse.
571
572 This function needs to be easily testable! Keep it free of
573 environment-dependent code. Put more detailed usage validation in
574 _PostParseCheck().
Brian Harring3fec5a82012-03-01 05:57:03 -0800575
576 Args:
Matt Tennant759e2352013-09-27 15:14:44 -0700577 options: The options object returned by optparse
Brian Harring3fec5a82012-03-01 05:57:03 -0800578 """
Ryan Cui41023d92012-11-13 19:59:50 -0800579 # Populate options.pass_through_args.
580 accepted, _ = commandline.FilteringParser.FilterArgs(
581 options.parsed_args, lambda x: x.opt_inst.pass_through)
582 options.pass_through_args.extend(accepted)
Brian Harring07039b52012-05-13 17:56:47 -0700583
Don Garrettcc0ee522017-09-13 14:28:42 -0700584 if options.local or options.remote:
585 cros_build_lib.Die('Deprecated usage. Please use cros tryjob instead.')
586
Don Garrett211df8c2017-09-06 13:33:02 -0700587 if not options.buildroot:
588 cros_build_lib.Die('A buildroot is required to build.')
589
590 if len(options.build_targets) > 1:
591 cros_build_lib.Die('Multiple configs not supported. Got %r',
592 options.build_targets)
593
Brian Harring3fec5a82012-03-01 05:57:03 -0800594 if options.chrome_root:
595 if options.chrome_rev != constants.CHROME_REV_LOCAL:
Brian Harring1b8c4c82012-05-29 23:03:04 -0700596 cros_build_lib.Die('Chrome rev must be %s if chrome_root is set.' %
597 constants.CHROME_REV_LOCAL)
David Jamesa0a664e2013-02-13 09:52:01 -0800598 elif options.chrome_rev == constants.CHROME_REV_LOCAL:
599 cros_build_lib.Die('Chrome root must be set if chrome_rev is %s.' %
600 constants.CHROME_REV_LOCAL)
Brian Harring3fec5a82012-03-01 05:57:03 -0800601
602 if options.chrome_version:
603 if options.chrome_rev != constants.CHROME_REV_SPEC:
Brian Harring1b8c4c82012-05-29 23:03:04 -0700604 cros_build_lib.Die('Chrome rev must be %s if chrome_version is set.' %
605 constants.CHROME_REV_SPEC)
David Jamesa0a664e2013-02-13 09:52:01 -0800606 elif options.chrome_rev == constants.CHROME_REV_SPEC:
607 cros_build_lib.Die(
608 'Chrome rev must not be %s if chrome_version is not set.'
609 % constants.CHROME_REV_SPEC)
Brian Harring3fec5a82012-03-01 05:57:03 -0800610
Don Garrett211df8c2017-09-06 13:33:02 -0700611 patches = bool(options.gerrit_patches)
Ryan Cuieaa9efd2012-04-25 17:56:45 -0700612
David James5734ea32012-08-15 20:23:49 -0700613 # When running in release mode, make sure we are running with checked-in code.
614 # We want checked-in cbuildbot/scripts to prevent errors, and we want to build
615 # a release image with checked-in code for CrOS packages.
Don Garrett211df8c2017-09-06 13:33:02 -0700616 if options.buildbot and patches and not options.debug:
David James5734ea32012-08-15 20:23:49 -0700617 cros_build_lib.Die(
618 'Cannot provide patches when running with --buildbot!')
619
Ryan Cuiba41ad32012-03-08 17:15:29 -0800620 if options.buildbot and options.remote_trybot:
Brian Harring1b8c4c82012-05-29 23:03:04 -0700621 cros_build_lib.Die(
622 '--buildbot and --remote-trybot cannot be used together.')
Ryan Cuiba41ad32012-03-08 17:15:29 -0800623
Ryan Cui85867972012-02-23 18:21:49 -0800624 # Record whether --debug was set explicitly vs. it was inferred.
Don Garrett211df8c2017-09-06 13:33:02 -0700625 options.debug_forced = options.debug
626 # We force --debug to be set for builds that are not 'official'.
627 options.debug = options.debug or not options.buildbot
Brian Harring3fec5a82012-03-01 05:57:03 -0800628
Ryan Cui88b901c2013-06-21 11:35:30 -0700629 if constants.BRANCH_UTIL_CONFIG in options.build_targets:
Ryan Cui88b901c2013-06-21 11:35:30 -0700630 if not options.branch_name:
631 cros_build_lib.Die(
Matt Tennanta130ea32013-12-19 09:38:39 -0800632 'Must specify --branch-name with the %s config.',
633 constants.BRANCH_UTIL_CONFIG)
634 if options.branch and options.branch != options.branch_name:
Ryan Cui88b901c2013-06-21 11:35:30 -0700635 cros_build_lib.Die(
Matt Tennanta130ea32013-12-19 09:38:39 -0800636 'If --branch is specified with the %s config, it must'
637 ' have the same value as --branch-name.',
638 constants.BRANCH_UTIL_CONFIG)
639
640 exclusive_opts = {'--version': options.force_version,
641 '--delete-branch': options.delete_branch,
David Jameseecba232014-06-11 11:35:11 -0700642 '--rename-to': options.rename_to}
Matt Tennanta130ea32013-12-19 09:38:39 -0800643 if 1 != sum(1 for x in exclusive_opts.values() if x):
644 cros_build_lib.Die('When using the %s config, you must'
645 ' specifiy one and only one of the following'
646 ' options: %s.', constants.BRANCH_UTIL_CONFIG,
647 ', '.join(exclusive_opts.keys()))
648
649 # When deleting or renaming a branch, the --branch and --nobootstrap
650 # options are implied.
651 if options.delete_branch or options.rename_to:
652 if not options.branch:
Ralph Nathan03047282015-03-23 11:09:32 -0700653 logging.info('Automatically enabling sync to branch %s for this %s '
654 'flow.', options.branch_name,
655 constants.BRANCH_UTIL_CONFIG)
Matt Tennanta130ea32013-12-19 09:38:39 -0800656 options.branch = options.branch_name
657 if options.bootstrap:
Ralph Nathan03047282015-03-23 11:09:32 -0700658 logging.info('Automatically disabling bootstrap step for this %s flow.',
659 constants.BRANCH_UTIL_CONFIG)
Matt Tennanta130ea32013-12-19 09:38:39 -0800660 options.bootstrap = False
661
Ryan Cui88b901c2013-06-21 11:35:30 -0700662 elif any([options.delete_branch, options.rename_to, options.branch_name]):
663 cros_build_lib.Die(
664 'Cannot specify --delete-branch, --rename-to or --branch-name when not '
665 'running the %s config', constants.BRANCH_UTIL_CONFIG)
666
Brian Harring3fec5a82012-03-01 05:57:03 -0800667
Brian Harring1d7ba942012-04-24 06:37:18 -0700668# pylint: disable=W0613
Mike Frysinger80bba8a2017-08-18 15:28:36 -0400669def _PostParseCheck(parser, options, site_config):
Ryan Cui85867972012-02-23 18:21:49 -0800670 """Perform some usage validation after we've parsed the arguments
Brian Harring3fec5a82012-03-01 05:57:03 -0800671
Ryan Cui85867972012-02-23 18:21:49 -0800672 Args:
Aviv Keshet9e4236b2013-12-13 13:07:50 -0800673 parser: Option parser that was used to parse arguments.
674 options: The options returned by optparse.
Don Garrett4af20982015-05-29 19:02:23 -0700675 site_config: config_lib.SiteConfig containing all config info.
Ryan Cui85867972012-02-23 18:21:49 -0800676 """
Mike Frysinger80bba8a2017-08-18 15:28:36 -0400677 if not options.build_targets:
Don Garrett0a873e02015-06-30 17:55:10 -0700678 parser.error('Invalid usage: no configuration targets provided.'
679 'Use -h to see usage. Use -l to list supported configs.')
680
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.
Chris Sosa55cdc942014-04-16 13:08:37 -0700696 invalid_targets = []
Mike Frysinger80bba8a2017-08-18 15:28:36 -0400697 for arg in options.build_targets:
Don Garrett4af20982015-05-29 19:02:23 -0700698 if arg not in site_config:
Chris Sosa55cdc942014-04-16 13:08:37 -0700699 invalid_targets.append(arg)
Ralph Nathan59900422015-03-24 10:41:17 -0700700 logging.error('No such configuraton target: "%s".', arg)
Don Garrett4bb21682014-03-03 16:16:23 -0800701 continue
702
Don Garrett4af20982015-05-29 19:02:23 -0700703 build_config = site_config[arg]
704
Don Garrett5af1d262014-05-16 15:49:37 -0700705 is_payloads_build = build_config.build_type == constants.PAYLOADS_TYPE
706
707 if options.channels and not is_payloads_build:
Don Garrett4bb21682014-03-03 16:16:23 -0800708 cros_build_lib.Die('--channel must only be used with a payload config,'
709 ' not target (%s).' % arg)
Matt Tennant763497d2014-01-17 16:45:54 -0800710
Don Garrett5af1d262014-05-16 15:49:37 -0700711 if not options.channels and is_payloads_build:
712 cros_build_lib.Die('payload configs (%s) require --channel to do anything'
713 ' useful.' % arg)
714
Matt Tennant2c192032014-01-16 13:49:28 -0800715 # The --version option is not compatible with an external target unless the
716 # --buildbot option is specified. More correctly, only "paladin versions"
717 # will work with external targets, and those are only used with --buildbot.
718 # If --buildbot is specified, then user should know what they are doing and
719 # only specify a version that will work. See crbug.com/311648.
Don Garrett4bb21682014-03-03 16:16:23 -0800720 if (options.force_version and
721 not (options.buildbot or build_config.internal)):
722 cros_build_lib.Die('Cannot specify --version without --buildbot for an'
723 ' external target (%s).' % arg)
Matt Tennant2c192032014-01-16 13:49:28 -0800724
Chris Sosa55cdc942014-04-16 13:08:37 -0700725 if invalid_targets:
726 cros_build_lib.Die('One or more invalid configuration targets specified. '
727 'You can check the available configs by running '
728 '`cbuildbot --list --all`')
Matt Tennant763497d2014-01-17 16:45:54 -0800729
Ryan Cui85867972012-02-23 18:21:49 -0800730
Don Garrett597ddff2017-02-17 18:29:37 -0800731def ParseCommandLine(parser, argv):
Ryan Cui85867972012-02-23 18:21:49 -0800732 """Completely parse the commandline arguments"""
Brian Harring3fec5a82012-03-01 05:57:03 -0800733 (options, args) = parser.parse_args(argv)
Brian Harring37e559b2012-05-22 20:47:32 -0700734
Mike Frysinger80bba8a2017-08-18 15:28:36 -0400735 # Record the configs targeted.
Matt Tennant763497d2014-01-17 16:45:54 -0800736 # Strip out null arguments.
737 # TODO(rcui): Remove when buildbot is fixed
Mike Frysinger80bba8a2017-08-18 15:28:36 -0400738 options.build_targets = [x for x in args if x]
Matt Tennant763497d2014-01-17 16:45:54 -0800739
Brian Harring37e559b2012-05-22 20:47:32 -0700740 if options.output_api_version:
Mike Frysinger383367e2014-09-16 15:06:17 -0400741 print(constants.REEXEC_API_VERSION)
Brian Harring37e559b2012-05-22 20:47:32 -0700742 sys.exit(0)
743
Mike Frysinger80bba8a2017-08-18 15:28:36 -0400744 _FinishParsing(options)
745 return options
Ryan Cui85867972012-02-23 18:21:49 -0800746
747
Aviv Keshet420de512015-05-18 14:28:48 -0700748_ENVIRONMENT_PROD = 'prod'
749_ENVIRONMENT_DEBUG = 'debug'
750_ENVIRONMENT_STANDALONE = 'standalone'
751
752
753def _GetRunEnvironment(options, build_config):
754 """Determine whether this is a prod/debug/standalone run."""
755 # TODO(akeshet): This is a temporary workaround to make sure that the cidb
756 # is not used on waterfalls that the db schema does not support (in particular
757 # the chromeos.chrome waterfall).
758 # See crbug.com/406940
Aviv Keshet593014d2017-07-18 17:28:25 -0700759 wfall = os.environ.get('BUILDBOT_MASTERNAME', '')
760 if not wfall in waterfall.CIDB_KNOWN_WATERFALLS:
Aviv Keshet420de512015-05-18 14:28:48 -0700761 return _ENVIRONMENT_STANDALONE
762
763 # TODO(akeshet): Clean up this code once we have better defined flags to
764 # specify on-or-off waterfall and on-or-off production runs of cbuildbot.
765 # See crbug.com/331417
766
767 # --buildbot runs should use the production services, unless the --debug flag
768 # is also present.
769 if options.buildbot:
770 if options.debug:
771 return _ENVIRONMENT_DEBUG
772 else:
773 return _ENVIRONMENT_PROD
774
775 # --remote-trybot runs should use the debug services, with the exception of
776 # pre-cq builds, which should use the production services.
777 if options.remote_trybot:
778 if build_config['pre_cq']:
779 return _ENVIRONMENT_PROD
780 else:
781 return _ENVIRONMENT_DEBUG
782
783 # If neither --buildbot nor --remote-trybot flag was used, don't use external
784 # services.
785 return _ENVIRONMENT_STANDALONE
786
787
Gabe Blackde694a32015-02-19 15:11:11 -0800788def _SetupConnections(options, build_config):
Aviv Keshet55491242017-07-13 17:04:07 -0700789 """Set up CIDB connections using the appropriate Setup call.
Aviv Keshet2982af52014-08-13 16:07:57 -0700790
791 Args:
792 options: Command line options structure.
Aviv Keshet64133022014-08-25 15:50:52 -0700793 build_config: Config object for this build.
Aviv Keshet2982af52014-08-13 16:07:57 -0700794 """
Aviv Keshet420de512015-05-18 14:28:48 -0700795 # Outline:
796 # 1) Based on options and build_config, decide whether we are a production
797 # run, debug run, or standalone run.
798 # 2) Set up cidb instance accordingly.
799 # 3) Update topology info from cidb, so that any other service set up can use
800 # topology.
801 # 4) Set up any other services.
802 run_type = _GetRunEnvironment(options, build_config)
803
804 if run_type == _ENVIRONMENT_PROD:
805 cidb.CIDBConnectionFactory.SetupProdCidb()
Paul Hobbs3cbdf332017-07-05 22:55:32 -0700806 context = ts_mon_config.SetupTsMonGlobalState(
807 'cbuildbot', indirect=True, task_num=options.ts_mon_task_num)
Aviv Keshet420de512015-05-18 14:28:48 -0700808 elif run_type == _ENVIRONMENT_DEBUG:
809 cidb.CIDBConnectionFactory.SetupDebugCidb()
Paul Hobbsd5a0f812016-07-26 16:10:31 -0700810 context = ts_mon_config.TrivialContextManager()
Aviv Keshet420de512015-05-18 14:28:48 -0700811 else:
Aviv Keshet62d1a0e2014-08-22 21:16:13 -0700812 cidb.CIDBConnectionFactory.SetupNoCidb()
Paul Hobbsd5a0f812016-07-26 16:10:31 -0700813 context = ts_mon_config.TrivialContextManager()
Aviv Keshet62d1a0e2014-08-22 21:16:13 -0700814
Aviv Keshet420de512015-05-18 14:28:48 -0700815 db = cidb.CIDBConnectionFactory.GetCIDBConnectionForBuilder()
816 topology.FetchTopologyFromCIDB(db)
Aviv Keshet64133022014-08-25 15:50:52 -0700817
Paul Hobbsd5a0f812016-07-26 16:10:31 -0700818 return context
819
Aviv Keshet2982af52014-08-13 16:07:57 -0700820
Matt Tennant759e2352013-09-27 15:14:44 -0700821# TODO(build): This function is too damn long.
Ryan Cui85867972012-02-23 18:21:49 -0800822def main(argv):
Mike Frysinger80bba8a2017-08-18 15:28:36 -0400823 # We get false positives with the options object.
824 # pylint: disable=attribute-defined-outside-init
825
David James59a0a2b2013-03-22 14:04:44 -0700826 # Turn on strict sudo checks.
827 cros_build_lib.STRICT_SUDO = True
828
Ryan Cui85867972012-02-23 18:21:49 -0800829 # Set umask to 022 so files created by buildbot are readable.
Mike Frysinger60ec1012013-10-21 00:11:10 -0400830 os.umask(0o22)
Ryan Cui85867972012-02-23 18:21:49 -0800831
Ryan Cui85867972012-02-23 18:21:49 -0800832 parser = _CreateParser()
Mike Frysinger80bba8a2017-08-18 15:28:36 -0400833 options = ParseCommandLine(parser, argv)
Don Garrett0a873e02015-06-30 17:55:10 -0700834
Don Garrettb85658c2015-06-30 19:07:22 -0700835 # Fetch our site_config now, because we need it to do anything else.
Don Garrettde81cc72015-07-07 13:23:28 -0700836 site_config = config_lib.GetConfig()
Don Garrettb85658c2015-06-30 19:07:22 -0700837
Mike Frysinger80bba8a2017-08-18 15:28:36 -0400838 _PostParseCheck(parser, options, site_config)
Brian Harring3fec5a82012-03-01 05:57:03 -0800839
Mike Frysinger8fd67dc2012-12-03 23:51:18 -0500840 cros_build_lib.AssertOutsideChroot()
Zdenek Behan98ec2fb2012-08-31 17:12:18 +0200841
Prathmesh Prabhu51d774f2015-07-17 15:11:49 -0700842 if options.enable_buildbot_tags:
843 logging.EnableBuildbotMarkers()
Matt Tennant759e2352013-09-27 15:14:44 -0700844
Ryan Cui54da0702012-04-19 18:38:08 -0700845 elif (not options.buildbot and not options.remote_trybot
Don Garrett211df8c2017-09-06 13:33:02 -0700846 and not options.resume):
847 cros_build_lib.Die('Please use cros tryjob to run local builds.')
Brian Harring3fec5a82012-03-01 05:57:03 -0800848
Ningning Xiac691e432016-08-11 14:52:59 -0700849 elif options.buildbot and not options.debug:
Don Garrett211df8c2017-09-06 13:33:02 -0700850 # Cannot run real builds, except on real build machines.
Ningning Xiac691e432016-08-11 14:52:59 -0700851 if not cros_build_lib.HostIsCIBuilder():
Don Garrett211df8c2017-09-06 13:33:02 -0700852 cros_build_lib.Die('This host is not a supported build machine.')
Ningning Xiac691e432016-08-11 14:52:59 -0700853
Matt Tennant759e2352013-09-27 15:14:44 -0700854 # Only one config arg is allowed in this mode, which was confirmed earlier.
Mike Frysinger80bba8a2017-08-18 15:28:36 -0400855 bot_id = options.build_targets[-1]
Don Garrett4af20982015-05-29 19:02:23 -0700856 build_config = site_config[bot_id]
Brian Harring3fec5a82012-03-01 05:57:03 -0800857
Don Garrettbbd7b552014-05-16 13:15:21 -0700858 # TODO: Re-enable this block when reference_repo support handles this
859 # properly. (see chromium:330775)
860 # if options.reference_repo is None:
861 # repo_path = os.path.join(options.sourceroot, '.repo')
862 # # If we're being run from a repo checkout, reuse the repo's git pool to
863 # # cut down on sync time.
864 # if os.path.exists(repo_path):
865 # options.reference_repo = options.sourceroot
866
867 if options.reference_repo:
David Jamesdac7a912013-11-18 11:14:44 -0800868 if not os.path.exists(options.reference_repo):
869 parser.error('Reference path %s does not exist'
870 % (options.reference_repo,))
871 elif not os.path.exists(os.path.join(options.reference_repo, '.repo')):
872 parser.error('Reference path %s does not look to be the base of a '
873 'repo checkout; no .repo exists in the root.'
874 % (options.reference_repo,))
875
Brian Harringf11bf682012-05-14 15:53:43 -0700876 if (options.buildbot or options.remote_trybot) and not options.resume:
Brian Harring470f6112012-03-02 11:47:10 -0800877 if not options.cgroups:
Ryan Cuid4a24212012-04-04 18:08:12 -0700878 parser.error('Options --buildbot/--remote-trybot and --nocgroups cannot '
879 'be used together. Cgroup support is required for '
880 'buildbot/remote-trybot mode.')
Mike Frysingera78a56e2012-11-20 06:02:30 -0500881 if not cgroups.Cgroup.IsSupported():
Ryan Cuid4a24212012-04-04 18:08:12 -0700882 parser.error('Option --buildbot/--remote-trybot was given, but this '
883 'system does not support cgroups. Failing.')
Brian Harring3fec5a82012-03-01 05:57:03 -0800884
David Jamesaad5cc72012-10-26 15:03:13 -0700885 missing = osutils.FindMissingBinaries(_BUILDBOT_REQUIRED_BINARIES)
Brian Harring351ce442012-03-09 16:38:14 -0800886 if missing:
David Jameseecba232014-06-11 11:35:11 -0700887 parser.error('Option --buildbot/--remote-trybot requires the following '
Ryan Cuid4a24212012-04-04 18:08:12 -0700888 "binaries which couldn't be found in $PATH: %s"
Brian Harring351ce442012-03-09 16:38:14 -0800889 % (', '.join(missing)))
890
David Jamesdac7a912013-11-18 11:14:44 -0800891 if options.reference_repo:
892 options.reference_repo = os.path.abspath(options.reference_repo)
893
Brian Harring3fec5a82012-03-01 05:57:03 -0800894 # Sanity check of buildroot- specifically that it's not pointing into the
895 # midst of an existing repo since git-repo doesn't support nesting.
Brian Harring3fec5a82012-03-01 05:57:03 -0800896 if (not repository.IsARepoRoot(options.buildroot) and
David James13a69c92013-05-09 10:37:42 -0700897 git.FindRepoDir(options.buildroot)):
Don Garrett211df8c2017-09-06 13:33:02 -0700898 cros_build_lib.Die(
899 'Configured buildroot %s is a subdir of an existing repo checkout.'
900 % options.buildroot)
Brian Harring3fec5a82012-03-01 05:57:03 -0800901
Chris Sosab5ea3b42012-10-25 15:25:20 -0700902 if not options.log_dir:
903 options.log_dir = os.path.join(options.buildroot, _DEFAULT_LOG_DIR)
904
Brian Harringd166aaf2012-05-14 18:31:53 -0700905 log_file = None
906 if options.tee:
Chris Sosab5ea3b42012-10-25 15:25:20 -0700907 log_file = os.path.join(options.log_dir, _BUILDBOT_LOG_FILE)
908 osutils.SafeMakedirs(options.log_dir)
Brian Harringd166aaf2012-05-14 18:31:53 -0700909 _BackupPreviousLog(log_file)
910
Brian Harring1b8c4c82012-05-29 23:03:04 -0700911 with cros_build_lib.ContextManagerStack() as stack:
Ningning Xia96876d52016-03-31 10:26:39 -0700912 options.preserve_paths = set()
David Jamescebc7272013-07-17 16:45:05 -0700913 if log_file is not None:
914 # We don't want the critical section to try to clean up the tee process,
915 # so we run Tee (forked off) outside of it. This prevents a deadlock
916 # because the Tee process only exits when its pipe is closed, and the
917 # critical section accidentally holds on to that file handle.
918 stack.Add(tee.Tee, log_file)
919 options.preserve_paths.add(_DEFAULT_LOG_DIR)
920
Brian Harringc2d09d92012-05-13 22:03:15 -0700921 critical_section = stack.Add(cleanup.EnforcedCleanupSection)
922 stack.Add(sudo.SudoKeepAlive)
Brian Harringd166aaf2012-05-14 18:31:53 -0700923
Brian Harringc2d09d92012-05-13 22:03:15 -0700924 if not options.resume:
Brian Harring2bf55e12012-05-13 21:31:55 -0700925 # If we're in resume mode, use our parents tempdir rather than
926 # nesting another layer.
David James4bc13702013-03-26 08:08:04 -0700927 stack.Add(osutils.TempDir, prefix='cbuildbot-tmp', set_global=True)
David Jameseecba232014-06-11 11:35:11 -0700928 logging.debug('Cbuildbot tempdir is %r.', os.environ.get('TMP'))
Brian Harringd166aaf2012-05-14 18:31:53 -0700929
Brian Harringc2d09d92012-05-13 22:03:15 -0700930 if options.cgroups:
931 stack.Add(cgroups.SimpleContainChildren, 'cbuildbot')
Brian Harringa184efa2012-03-04 11:51:25 -0800932
Brian Harringc2d09d92012-05-13 22:03:15 -0700933 # Mark everything between EnforcedCleanupSection and here as having to
934 # be rolled back via the contextmanager cleanup handlers. This
935 # ensures that sudo bits cannot outlive cbuildbot, that anything
936 # cgroups would kill gets killed, etc.
David Jamesfb3aac92013-10-16 13:26:52 -0700937 stack.Add(critical_section.ForkWatchdog)
Brian Harringd166aaf2012-05-14 18:31:53 -0700938
Brian Harringc2d09d92012-05-13 22:03:15 -0700939 if not options.buildbot:
Don Garrett6747eba2015-06-25 16:00:16 -0700940 build_config = config_lib.OverrideConfigForTrybot(
Don Garrett4bb21682014-03-03 16:16:23 -0800941 build_config, options)
Brian Harringc2d09d92012-05-13 22:03:15 -0700942
Aviv Kesheta0159be2013-12-12 13:56:28 -0800943 if options.mock_tree_status is not None:
Prathmesh Prabhud51d7502014-12-21 01:42:55 -0800944 stack.Add(mock.patch.object, tree_status, '_GetStatus',
Aviv Kesheta0159be2013-12-12 13:56:28 -0800945 return_value=options.mock_tree_status)
946
Aviv Keshetcf9c2722014-02-25 15:15:10 -0800947 if options.mock_slave_status is not None:
948 with open(options.mock_slave_status, 'r') as f:
Aviv Keshet4e750022014-03-07 16:50:34 -0800949 mock_statuses = pickle.load(f)
950 for key, value in mock_statuses.iteritems():
Ningning Xiaf342b952017-02-15 14:13:33 -0800951 mock_statuses[key] = builder_status_lib.BuilderStatus(**value)
Yu-Ju Hongd0fda382014-05-09 15:28:24 -0700952 stack.Add(mock.patch.object,
953 completion_stages.MasterSlaveSyncCompletionStage,
954 '_FetchSlaveStatuses',
955 return_value=mock_statuses)
Aviv Keshetcf9c2722014-02-25 15:15:10 -0800956
Paul Hobbsd5a0f812016-07-26 16:10:31 -0700957 stack.Add(_SetupConnections, options, build_config)
Don Garrettb4318362014-10-03 15:49:36 -0700958 retry_stats.SetupStats()
Aviv Keshet2982af52014-08-13 16:07:57 -0700959
Aviv Keshet446f07f2016-03-08 11:32:31 -0800960 timeout_display_message = None
Prathmesh Prabhu80e05df2014-12-11 15:20:33 -0800961 # For master-slave builds: Update slave's timeout using master's published
962 # deadline.
963 if options.buildbot and options.master_build_id is not None:
964 slave_timeout = None
965 if cidb.CIDBConnectionFactory.IsCIDBSetup():
966 cidb_handle = cidb.CIDBConnectionFactory.GetCIDBConnectionForBuilder()
967 if cidb_handle:
968 slave_timeout = cidb_handle.GetTimeToDeadline(options.master_build_id)
969
970 if slave_timeout is not None:
Prathmesh Prabhue49f2aa2017-04-25 12:02:18 -0700971 # We artificially set a minimum slave_timeout because '0' is handled
972 # specially, and because we don't want to timeout while trying to set
973 # things up.
974 slave_timeout = max(slave_timeout, 20)
Prathmesh Prabhu80e05df2014-12-11 15:20:33 -0800975 if options.timeout == 0 or slave_timeout < options.timeout:
976 logging.info('Updating slave build timeout to %d seconds enforced '
Ralph Nathan03047282015-03-23 11:09:32 -0700977 'by the master', slave_timeout)
Prathmesh Prabhu80e05df2014-12-11 15:20:33 -0800978 options.timeout = slave_timeout
Aviv Keshet84017582016-05-18 16:59:59 -0700979 timeout_display_message = (
980 'This build has reached the timeout deadline set by the master. '
981 'Either this stage or a previous one took too long (see stage '
982 'timing historical summary in ReportStage) or the build failed '
983 'to start on time.')
Prathmesh Prabhu80e05df2014-12-11 15:20:33 -0800984 else:
985 logging.warning('Could not get master deadline for master-slave build. '
986 'Can not set slave timeout.')
987
988 if options.timeout > 0:
Aviv Keshet446f07f2016-03-08 11:32:31 -0800989 stack.Add(timeout_util.FatalTimeout, options.timeout,
990 timeout_display_message)
Ningning Xiaad483542016-05-24 12:27:21 -0700991 try:
992 _RunBuildStagesWrapper(options, site_config, build_config)
993 except failures_lib.ExitEarlyException as ex:
994 # This build finished successfully. Do not re-raise ExitEarlyException.
995 logging.info('One stage exited early: %s', ex)