blob: d38eebe5897ceb452ee1e1f2ed9e83211911847e [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
David James1fddb8f2013-04-25 15:23:07 -070013import collections
Mike Frysingera0753de2015-01-13 03:32:48 -050014import datetime
Brian Harring3fec5a82012-03-01 05:57:03 -080015import distutils.version
16import glob
Aviv Keshet669eb5e2014-06-23 08:53:01 -070017import json
Chris Sosa4f6ffaf2012-05-01 17:05:44 -070018import logging
Luis Lozanoe0505bd2013-11-08 17:45:48 -080019import multiprocessing
Brian Harring3fec5a82012-03-01 05:57:03 -080020import optparse
21import os
Aviv Keshetcf9c2722014-02-25 15:15:10 -080022import pickle
Brian Harring3fec5a82012-03-01 05:57:03 -080023import sys
Aviv Keshet669eb5e2014-06-23 08:53:01 -070024import tempfile
David James3541a132013-03-18 13:21:58 -070025import traceback
Brian Harring3fec5a82012-03-01 05:57:03 -080026
Luis Lozanoe0505bd2013-11-08 17:45:48 -080027from chromite.cbuildbot import afdo
Don Garrett88b8d782014-05-13 17:30:55 -070028from chromite.cbuildbot import cbuildbot_config
Don Garrett88b8d782014-05-13 17:30:55 -070029from chromite.cbuildbot import cbuildbot_run
30from chromite.cbuildbot import constants
Luis Lozanoe0505bd2013-11-08 17:45:48 -080031from chromite.cbuildbot import failures_lib
Don Garrett88b8d782014-05-13 17:30:55 -070032from chromite.cbuildbot import manifest_version
33from chromite.cbuildbot import remote_try
34from chromite.cbuildbot import repository
Luis Lozanoe0505bd2013-11-08 17:45:48 -080035from chromite.cbuildbot import results_lib
Don Garrett88b8d782014-05-13 17:30:55 -070036from chromite.cbuildbot import tee
Prathmesh Prabhud51d7502014-12-21 01:42:55 -080037from chromite.cbuildbot import tree_status
Don Garrett88b8d782014-05-13 17:30:55 -070038from chromite.cbuildbot import trybot_patch_pool
Luis Lozanoe0505bd2013-11-08 17:45:48 -080039from chromite.cbuildbot.stages import afdo_stages
Don Garrett88b8d782014-05-13 17:30:55 -070040from chromite.cbuildbot.stages import artifact_stages
41from chromite.cbuildbot.stages import branch_stages
42from chromite.cbuildbot.stages import build_stages
43from chromite.cbuildbot.stages import chrome_stages
44from chromite.cbuildbot.stages import completion_stages
45from chromite.cbuildbot.stages import generic_stages
46from chromite.cbuildbot.stages import release_stages
47from chromite.cbuildbot.stages import report_stages
48from chromite.cbuildbot.stages import sdk_stages
49from chromite.cbuildbot.stages import sync_stages
50from chromite.cbuildbot.stages import test_stages
Yu-Ju Hongd0fda382014-05-09 15:28:24 -070051
Brian Harring3fec5a82012-03-01 05:57:03 -080052
Aviv Keshet2982af52014-08-13 16:07:57 -070053from chromite.lib import cidb
Brian Harringc92a7012012-02-29 10:11:34 -080054from chromite.lib import cgroups
Brian Harringa184efa2012-03-04 11:51:25 -080055from chromite.lib import cleanup
Brian Harringb6cf9142012-09-01 20:43:17 -070056from chromite.lib import commandline
Brian Harring1b8c4c82012-05-29 23:03:04 -070057from chromite.lib import cros_build_lib
Brian Harring511055e2012-10-10 02:58:59 -070058from chromite.lib import gerrit
David James97d95872012-11-16 15:09:56 -080059from chromite.lib import git
Stefan Zagerd49d9ff2014-08-15 21:33:37 -070060from chromite.lib import gob_util
Brian Harringaf019fb2012-05-10 15:06:13 -070061from chromite.lib import osutils
Brian Harring511055e2012-10-10 02:58:59 -070062from chromite.lib import patch as cros_patch
David James6450a0a2012-12-04 07:59:53 -080063from chromite.lib import parallel
Don Garrettb4318362014-10-03 15:49:36 -070064from chromite.lib import retry_stats
Brian Harring3fec5a82012-03-01 05:57:03 -080065from chromite.lib import sudo
David James3432acd2013-11-27 10:02:18 -080066from chromite.lib import timeout_util
Brian Harring3fec5a82012-03-01 05:57:03 -080067
Aviv Kesheta0159be2013-12-12 13:56:28 -080068import mock
69
Ryan Cuiadd49122012-03-21 22:19:58 -070070
Brian Harring3fec5a82012-03-01 05:57:03 -080071_DEFAULT_LOG_DIR = 'cbuildbot_logs'
72_BUILDBOT_LOG_FILE = 'cbuildbot.log'
73_DEFAULT_EXT_BUILDROOT = 'trybot'
74_DEFAULT_INT_BUILDROOT = 'trybot-internal'
Brian Harring351ce442012-03-09 16:38:14 -080075_BUILDBOT_REQUIRED_BINARIES = ('pbzip2',)
Ryan Cui1c13a252012-10-16 15:00:16 -070076_API_VERSION_ATTR = 'api_version'
Brian Harring3fec5a82012-03-01 05:57:03 -080077
78
Ryan Cui4f6cf7e2012-04-18 16:12:27 -070079def _PrintValidConfigs(display_all=False):
Brian Harring3fec5a82012-03-01 05:57:03 -080080 """Print a list of valid buildbot configs.
81
Mike Frysinger02e1e072013-11-10 22:11:34 -050082 Args:
Ryan Cui4f6cf7e2012-04-18 16:12:27 -070083 display_all: Print all configs. Otherwise, prints only configs with
84 trybot_list=True.
Brian Harring3fec5a82012-03-01 05:57:03 -080085 """
Ryan Cui4f6cf7e2012-04-18 16:12:27 -070086 def _GetSortKey(config_name):
87 config_dict = cbuildbot_config.config[config_name]
88 return (not config_dict['trybot_list'], config_dict['description'],
89 config_name)
90
Brian Harring3fec5a82012-03-01 05:57:03 -080091 COLUMN_WIDTH = 45
Mike Frysinger383367e2014-09-16 15:06:17 -040092 print()
93 print('config'.ljust(COLUMN_WIDTH), 'description')
94 print('------'.ljust(COLUMN_WIDTH), '-----------')
Brian Harring3fec5a82012-03-01 05:57:03 -080095 config_names = cbuildbot_config.config.keys()
Ryan Cui4f6cf7e2012-04-18 16:12:27 -070096 config_names.sort(key=_GetSortKey)
Brian Harring3fec5a82012-03-01 05:57:03 -080097 for name in config_names:
Ryan Cui4f6cf7e2012-04-18 16:12:27 -070098 if display_all or cbuildbot_config.config[name]['trybot_list']:
99 desc = cbuildbot_config.config[name].get('description')
100 desc = desc if desc else ''
Mike Frysinger383367e2014-09-16 15:06:17 -0400101 print(name.ljust(COLUMN_WIDTH), desc)
Brian Harring3fec5a82012-03-01 05:57:03 -0800102
Mike Frysinger383367e2014-09-16 15:06:17 -0400103 print()
Matt Tennant763497d2014-01-17 16:45:54 -0800104
Brian Harring3fec5a82012-03-01 05:57:03 -0800105
106def _GetConfig(config_name):
Matt Tennant763497d2014-01-17 16:45:54 -0800107 """Gets the configuration for the build if it exists, None otherwise."""
108 if cbuildbot_config.config.has_key(config_name):
109 return cbuildbot_config.config[config_name]
Brian Harring3fec5a82012-03-01 05:57:03 -0800110
111
Ryan Cuie1e4e662012-05-21 16:39:46 -0700112def AcquirePoolFromOptions(options):
Ryan Cui16d9e1f2012-05-11 10:50:18 -0700113 """Generate patch objects from passed in options.
Brian Harring3fec5a82012-03-01 05:57:03 -0800114
115 Args:
Ryan Cui16d9e1f2012-05-11 10:50:18 -0700116 options: The options object generated by optparse.
Brian Harring3fec5a82012-03-01 05:57:03 -0800117
Ryan Cuif7f24692012-05-18 16:35:33 -0700118 Returns:
119 trybot_patch_pool.TrybotPatchPool object.
120
Ryan Cui16d9e1f2012-05-11 10:50:18 -0700121 Raises:
Brian Harring511055e2012-10-10 02:58:59 -0700122 gerrit.GerritException, cros_patch.PatchException
Brian Harring3fec5a82012-03-01 05:57:03 -0800123 """
Ryan Cui16d9e1f2012-05-11 10:50:18 -0700124 gerrit_patches = []
125 local_patches = []
126 remote_patches = []
Brian Harring3fec5a82012-03-01 05:57:03 -0800127
Ryan Cui16d9e1f2012-05-11 10:50:18 -0700128 if options.gerrit_patches:
Brian Harring511055e2012-10-10 02:58:59 -0700129 gerrit_patches = gerrit.GetGerritPatchInfo(
Ryan Cui16d9e1f2012-05-11 10:50:18 -0700130 options.gerrit_patches)
131 for patch in gerrit_patches:
132 if patch.IsAlreadyMerged():
Brian Harring1b8c4c82012-05-29 23:03:04 -0700133 cros_build_lib.Warning('Patch %s has already been merged.' % str(patch))
Brian Harring3fec5a82012-03-01 05:57:03 -0800134
Ryan Cui16d9e1f2012-05-11 10:50:18 -0700135 if options.local_patches:
David James97d95872012-11-16 15:09:56 -0800136 manifest = git.ManifestCheckout.Cached(options.sourceroot)
Brian Harring609dc4e2012-05-07 02:17:44 -0700137 local_patches = cros_patch.PrepareLocalPatches(manifest,
138 options.local_patches)
Brian Harring3fec5a82012-03-01 05:57:03 -0800139
Ryan Cui16d9e1f2012-05-11 10:50:18 -0700140 if options.remote_patches:
141 remote_patches = cros_patch.PrepareRemotePatches(
142 options.remote_patches)
Brian Harring3fec5a82012-03-01 05:57:03 -0800143
Ryan Cui16d9e1f2012-05-11 10:50:18 -0700144 return trybot_patch_pool.TrybotPatchPool(gerrit_patches, local_patches,
145 remote_patches)
Brian Harring3fec5a82012-03-01 05:57:03 -0800146
147
Brian Harring3fec5a82012-03-01 05:57:03 -0800148class Builder(object):
149 """Parent class for all builder types.
150
Matt Tennant759e2352013-09-27 15:14:44 -0700151 This class functions as an abstract parent class for various build types.
152 Its intended use is builder_instance.Run().
Brian Harring3fec5a82012-03-01 05:57:03 -0800153
Matt Tennant3f351552014-01-03 14:28:00 -0800154 Attributes:
155 _run: The BuilderRun object for this run.
156 archive_stages: Dict of BuildConfig keys to ArchiveStage values.
157 patch_pool: TrybotPatchPool.
Brian Harring3fec5a82012-03-01 05:57:03 -0800158 """
159
Matt Tennantefb59522013-10-18 13:49:28 -0700160 def __init__(self, builder_run):
Brian Harring3fec5a82012-03-01 05:57:03 -0800161 """Initializes instance variables. Must be called by all subclasses."""
Matt Tennantefb59522013-10-18 13:49:28 -0700162 self._run = builder_run
Brian Harring3fec5a82012-03-01 05:57:03 -0800163
Matt Tennantefb59522013-10-18 13:49:28 -0700164 if self._run.config.chromeos_official:
Brian Harring3fec5a82012-03-01 05:57:03 -0800165 os.environ['CHROMEOS_OFFICIAL'] = '1'
166
David James58e0c092012-03-04 20:31:12 -0800167 self.archive_stages = {}
Brian Harring76d1bf62012-06-01 13:52:48 -0700168 self.patch_pool = trybot_patch_pool.TrybotPatchPool()
David James5596d0e2014-03-14 06:40:41 -0700169 self._build_image_lock = multiprocessing.Lock()
Brian Harring3fec5a82012-03-01 05:57:03 -0800170
171 def Initialize(self):
172 """Runs through the initialization steps of an actual build."""
Matt Tennantefb59522013-10-18 13:49:28 -0700173 if self._run.options.resume:
174 results_lib.LoadCheckpoint(self._run.buildroot)
Brian Harring3fec5a82012-03-01 05:57:03 -0800175
Aviv Keshet2982af52014-08-13 16:07:57 -0700176 self._RunStage(report_stages.BuildStartStage)
177
Yu-Ju Hongd0fda382014-05-09 15:28:24 -0700178 self._RunStage(build_stages.CleanUpStage)
Brian Harring3fec5a82012-03-01 05:57:03 -0800179
180 def _GetStageInstance(self, stage, *args, **kwargs):
Matt Tennant759e2352013-09-27 15:14:44 -0700181 """Helper function to get a stage instance given the args.
Brian Harring3fec5a82012-03-01 05:57:03 -0800182
Matt Tennantefb59522013-10-18 13:49:28 -0700183 Useful as almost all stages just take in builder_run.
Brian Harring3fec5a82012-03-01 05:57:03 -0800184 """
Matt Tennantefb59522013-10-18 13:49:28 -0700185 # Normally the default BuilderRun (self._run) is used, but it can
186 # be overridden with "builder_run" kwargs (e.g. for child configs).
187 builder_run = kwargs.pop('builder_run', self._run)
188 return stage(builder_run, *args, **kwargs)
Brian Harring3fec5a82012-03-01 05:57:03 -0800189
190 def _SetReleaseTag(self):
Matt Tennant9c1c8492014-02-27 13:09:07 -0800191 """Sets run.attrs.release_tag from the manifest manager used in sync.
Brian Harring3fec5a82012-03-01 05:57:03 -0800192
Matt Tennantf4980ee2014-01-29 09:21:27 -0800193 Must be run after sync stage as syncing enables us to have a release tag,
194 and must be run before any usage of attrs.release_tag.
Matt Tennantefb59522013-10-18 13:49:28 -0700195
196 TODO(mtennant): Find a bottleneck place in syncing that can set this
Matt Tennantf4980ee2014-01-29 09:21:27 -0800197 directly. Be careful, as there are several kinds of syncing stages, and
198 sync stages have been known to abort with sys.exit calls.
Brian Harring3fec5a82012-03-01 05:57:03 -0800199 """
Matt Tennantefb59522013-10-18 13:49:28 -0700200 manifest_manager = getattr(self._run.attrs, 'manifest_manager', None)
Brian Harring3fec5a82012-03-01 05:57:03 -0800201 if manifest_manager:
Matt Tennantefb59522013-10-18 13:49:28 -0700202 self._run.attrs.release_tag = manifest_manager.current_version
Matt Tennant3f351552014-01-03 14:28:00 -0800203 else:
204 self._run.attrs.release_tag = None
Brian Harring3fec5a82012-03-01 05:57:03 -0800205
Matt Tennanta42a5742014-02-09 13:42:12 -0800206 cros_build_lib.Debug('Saved release_tag value for run: %r',
207 self._run.attrs.release_tag)
208
Brian Harring3fec5a82012-03-01 05:57:03 -0800209 def _RunStage(self, stage, *args, **kwargs):
Matt Tennant759e2352013-09-27 15:14:44 -0700210 """Wrapper to run a stage.
211
212 Args:
213 stage: A BuilderStage class.
214 args: args to pass to stage constructor.
215 kwargs: kwargs to pass to stage constructor.
Mike Frysinger1a736a82013-12-12 01:50:59 -0500216
Matt Tennant759e2352013-09-27 15:14:44 -0700217 Returns:
Matt Tennant759e2352013-09-27 15:14:44 -0700218 Whatever the stage's Run method returns.
219 """
Brian Harring3fec5a82012-03-01 05:57:03 -0800220 stage_instance = self._GetStageInstance(stage, *args, **kwargs)
221 return stage_instance.Run()
222
David Jamese1c8ab62014-03-27 12:30:58 -0700223 @staticmethod
224 def _RunParallelStages(stage_objs):
225 """Run the specified stages in parallel.
226
227 Args:
228 stage_objs: BuilderStage objects.
229 """
230 steps = [stage.Run for stage in stage_objs]
231 try:
232 parallel.RunParallelSteps(steps)
233
234 except BaseException as ex:
235 # If a stage threw an exception, it might not have correctly reported
236 # results (e.g. because it was killed before it could report the
237 # results.) In this case, attribute the exception to any stages that
238 # didn't report back correctly (if any).
239 for stage in stage_objs:
240 for name in stage.GetStageNames():
241 if not results_lib.Results.StageHasResults(name):
242 results_lib.Results.Record(name, ex, str(ex))
243
Prathmesh Prabhu749137e2014-12-17 20:53:31 -0800244 if cidb.CIDBConnectionFactory.IsCIDBSetup():
245 db = cidb.CIDBConnectionFactory.GetCIDBConnectionForBuilder()
246 if db:
247 for stage in stage_objs:
248 for build_stage_id in stage.GetBuildStageIDs():
249 if not db.HasBuildStageFailed(build_stage_id):
250 failures_lib.ReportStageFailureToCIDB(db,
251 build_stage_id,
252 ex)
253
David Jamese1c8ab62014-03-27 12:30:58 -0700254 raise
255
Matt Tennantf4980ee2014-01-29 09:21:27 -0800256 def _RunSyncStage(self, sync_instance):
257 """Run given |sync_instance| stage and be sure attrs.release_tag set."""
258 try:
259 sync_instance.Run()
260 finally:
261 self._SetReleaseTag()
262
Brian Harring3fec5a82012-03-01 05:57:03 -0800263 def GetSyncInstance(self):
264 """Returns an instance of a SyncStage that should be run.
265
266 Subclasses must override this method.
267 """
268 raise NotImplementedError()
269
Aviv Keshet5c39b6a2013-10-07 15:44:54 -0400270 def GetCompletionInstance(self):
Aviv Keshetf2746152013-11-26 10:42:46 -0800271 """Returns the MasterSlaveSyncCompletionStage for this build.
Aviv Keshet5c39b6a2013-10-07 15:44:54 -0400272
273 Subclasses may override this method.
274
Mike Frysinger02e1e072013-11-10 22:11:34 -0500275 Returns:
276 None
Aviv Keshet5c39b6a2013-10-07 15:44:54 -0400277 """
278 return None
279
Brian Harring3fec5a82012-03-01 05:57:03 -0800280 def RunStages(self):
281 """Subclasses must override this method. Runs the appropriate code."""
282 raise NotImplementedError()
283
Brian Harring3fec5a82012-03-01 05:57:03 -0800284 def _ReExecuteInBuildroot(self, sync_instance):
285 """Reexecutes self in buildroot and returns True if build succeeds.
286
287 This allows the buildbot code to test itself when changes are patched for
288 buildbot-related code. This is a no-op if the buildroot == buildroot
289 of the running chromite checkout.
290
291 Args:
Matt Tennant85348852014-01-10 15:16:02 -0800292 sync_instance: Instance of the sync stage that was run to sync.
Brian Harring3fec5a82012-03-01 05:57:03 -0800293
294 Returns:
295 True if the Build succeeded.
296 """
Matt Tennantefb59522013-10-18 13:49:28 -0700297 if not self._run.options.resume:
298 results_lib.WriteCheckpoint(self._run.options.buildroot)
Brian Harring3fec5a82012-03-01 05:57:03 -0800299
Yu-Ju Hongd0fda382014-05-09 15:28:24 -0700300 args = sync_stages.BootstrapStage.FilterArgsForTargetCbuildbot(
Matt Tennantefb59522013-10-18 13:49:28 -0700301 self._run.options.buildroot, constants.PATH_TO_CBUILDBOT,
302 self._run.options)
Brian Harring37e559b2012-05-22 20:47:32 -0700303
David James2333c182013-02-13 16:16:15 -0800304 # Specify a buildroot explicitly (just in case, for local trybot).
Brian Harring3fec5a82012-03-01 05:57:03 -0800305 # Suppress any timeout options given from the commandline in the
306 # invoked cbuildbot; our timeout will enforce it instead.
Ryan Cui1c13a252012-10-16 15:00:16 -0700307 args += ['--resume', '--timeout', '0', '--notee', '--nocgroups',
Matt Tennantefb59522013-10-18 13:49:28 -0700308 '--buildroot', os.path.abspath(self._run.options.buildroot)]
Brian Harringae0a5322012-09-15 01:46:51 -0700309
Matt Tennantefb59522013-10-18 13:49:28 -0700310 if hasattr(self._run.attrs, 'manifest_manager'):
311 # TODO(mtennant): Is this the same as self._run.attrs.release_tag?
312 ver = self._run.attrs.manifest_manager.current_version
Ryan Cui1c13a252012-10-16 15:00:16 -0700313 args += ['--version', ver]
Brian Harring3fec5a82012-03-01 05:57:03 -0800314
David Jamesf421c6d2013-04-11 15:37:57 -0700315 pool = getattr(sync_instance, 'pool', None)
316 if pool:
Matt Tennantefb59522013-10-18 13:49:28 -0700317 filename = os.path.join(self._run.options.buildroot,
318 'validation_pool.dump')
David Jamesf421c6d2013-04-11 15:37:57 -0700319 pool.Save(filename)
320 args += ['--validation_pool', filename]
Brian Harring3fec5a82012-03-01 05:57:03 -0800321
David Jamesac8c2a72013-02-13 18:44:33 -0800322 # Reset the cache dir so that the child will calculate it automatically.
Matt Tennantefb59522013-10-18 13:49:28 -0700323 if not self._run.options.cache_dir_specified:
David Jamesac8c2a72013-02-13 18:44:33 -0800324 commandline.BaseParser.ConfigureCacheDir(None)
325
Aviv Keshet669eb5e2014-06-23 08:53:01 -0700326 with tempfile.NamedTemporaryFile(prefix='metadata') as metadata_file:
327 metadata_file.write(self._run.attrs.metadata.GetJSON())
328 metadata_file.flush()
329 args += ['--metadata_dump', metadata_file.name]
330
331 # Re-run the command in the buildroot.
332 # Finally, be generous and give the invoked cbuildbot 30s to shutdown
333 # when something occurs. It should exit quicker, but the sigterm may
334 # hit while the system is particularly busy.
335 return_obj = cros_build_lib.RunCommand(
336 args, cwd=self._run.options.buildroot, error_code_ok=True,
337 kill_timeout=30)
338 return return_obj.returncode == 0
Brian Harring3fec5a82012-03-01 05:57:03 -0800339
Ryan Cuif7f24692012-05-18 16:35:33 -0700340 def _InitializeTrybotPatchPool(self):
341 """Generate patch pool from patches specified on the command line.
342
343 Do this only if we need to patch changes later on.
344 """
Yu-Ju Hongd0fda382014-05-09 15:28:24 -0700345 changes_stage = sync_stages.PatchChangesStage.StageNamePrefix()
Ryan Cuif7f24692012-05-18 16:35:33 -0700346 check_func = results_lib.Results.PreviouslyCompletedRecord
Matt Tennantefb59522013-10-18 13:49:28 -0700347 if not check_func(changes_stage) or self._run.options.bootstrap:
348 self.patch_pool = AcquirePoolFromOptions(self._run.options)
Ryan Cuif7f24692012-05-18 16:35:33 -0700349
350 def _GetBootstrapStage(self):
351 """Constructs and returns the BootStrapStage object.
352
353 We return None when there are no chromite patches to test, and
354 --test-bootstrap wasn't passed in.
355 """
356 stage = None
357 chromite_pool = self.patch_pool.Filter(project=constants.CHROMITE_PROJECT)
Gabe Blackc17aa8e2014-05-15 22:13:06 -0700358 if self._run.config.internal:
359 manifest_pool = self.patch_pool.FilterIntManifest()
360 else:
361 manifest_pool = self.patch_pool.FilterExtManifest()
David James97d95872012-11-16 15:09:56 -0800362 chromite_branch = git.GetChromiteTrackingBranch()
Matt Tennantefb59522013-10-18 13:49:28 -0700363 if (chromite_pool or manifest_pool or
364 self._run.options.test_bootstrap or
365 chromite_branch != self._run.options.branch):
Yu-Ju Hongd0fda382014-05-09 15:28:24 -0700366 stage = sync_stages.BootstrapStage(self._run, chromite_pool,
367 manifest_pool)
Ryan Cuif7f24692012-05-18 16:35:33 -0700368 return stage
369
Brian Harring3fec5a82012-03-01 05:57:03 -0800370 def Run(self):
Ryan Cuif7f24692012-05-18 16:35:33 -0700371 """Main runner for this builder class. Runs build and prints summary.
372
373 Returns:
374 Whether the build succeeded.
375 """
376 self._InitializeTrybotPatchPool()
377
Matt Tennantefb59522013-10-18 13:49:28 -0700378 if self._run.options.bootstrap:
Ryan Cuif7f24692012-05-18 16:35:33 -0700379 bootstrap_stage = self._GetBootstrapStage()
380 if bootstrap_stage:
381 # BootstrapStage blocks on re-execution of cbuildbot.
382 bootstrap_stage.Run()
383 return bootstrap_stage.returncode == 0
384
Brian Harring3fec5a82012-03-01 05:57:03 -0800385 print_report = True
David James3d4d3502012-04-09 15:12:06 -0700386 exception_thrown = False
Brian Harring3fec5a82012-03-01 05:57:03 -0800387 success = True
David James9ebb2a42013-08-13 20:29:57 -0700388 sync_instance = None
Brian Harring3fec5a82012-03-01 05:57:03 -0800389 try:
390 self.Initialize()
391 sync_instance = self.GetSyncInstance()
Matt Tennantf4980ee2014-01-29 09:21:27 -0800392 self._RunSyncStage(sync_instance)
Brian Harring3fec5a82012-03-01 05:57:03 -0800393
Matt Tennantefb59522013-10-18 13:49:28 -0700394 if self._run.ShouldPatchAfterSync():
Ryan Cui88b901c2013-06-21 11:35:30 -0700395 # Filter out patches to manifest, since PatchChangesStage can't handle
396 # them. Manifest patches are patched in the BootstrapStage.
397 non_manifest_patches = self.patch_pool.FilterManifest(negate=True)
398 if non_manifest_patches:
Yu-Ju Hongd0fda382014-05-09 15:28:24 -0700399 self._RunStage(sync_stages.PatchChangesStage, non_manifest_patches)
Brian Harring3fec5a82012-03-01 05:57:03 -0800400
Matt Tennantefb59522013-10-18 13:49:28 -0700401 if self._run.ShouldReexecAfterSync():
Brian Harring3fec5a82012-03-01 05:57:03 -0800402 print_report = False
403 success = self._ReExecuteInBuildroot(sync_instance)
404 else:
Aviv Keshet2982af52014-08-13 16:07:57 -0700405 self._RunStage(report_stages.BuildReexecutionFinishedStage)
Brian Harring3fec5a82012-03-01 05:57:03 -0800406 self.RunStages()
Matt Tennant759e2352013-09-27 15:14:44 -0700407
David James3541a132013-03-18 13:21:58 -0700408 except Exception as ex:
David James7fbf2d42012-07-14 18:23:49 -0700409 exception_thrown = True
David James3541a132013-03-18 13:21:58 -0700410 if results_lib.Results.BuildSucceededSoFar():
Yu-Ju Hongc7c53722014-06-18 09:00:14 -0700411 # If the build is marked as successful, but threw exceptions, that's a
412 # problem. Print the traceback for debugging.
413 if isinstance(ex, failures_lib.CompoundFailure):
Mike Frysinger383367e2014-09-16 15:06:17 -0400414 print(str(ex))
Yu-Ju Hongc7c53722014-06-18 09:00:14 -0700415
David James3541a132013-03-18 13:21:58 -0700416 traceback.print_exc(file=sys.stdout)
David James7fbf2d42012-07-14 18:23:49 -0700417 raise
Matt Tennant759e2352013-09-27 15:14:44 -0700418
Yu-Ju Hongc54d3342014-05-14 12:42:06 -0700419 if not (print_report and isinstance(ex, failures_lib.StepFailure)):
Yu-Ju Hongc7c53722014-06-18 09:00:14 -0700420 # If the failed build threw a non-StepFailure exception, we
421 # should raise it.
David James3541a132013-03-18 13:21:58 -0700422 raise
Matt Tennant759e2352013-09-27 15:14:44 -0700423
Brian Harring3fec5a82012-03-01 05:57:03 -0800424 finally:
425 if print_report:
Matt Tennantefb59522013-10-18 13:49:28 -0700426 results_lib.WriteCheckpoint(self._run.options.buildroot)
Aviv Keshet5c39b6a2013-10-07 15:44:54 -0400427 completion_instance = self.GetCompletionInstance()
Yu-Ju Hongd0fda382014-05-09 15:28:24 -0700428 self._RunStage(report_stages.ReportStage, sync_instance,
429 completion_instance)
Brian Harring3fec5a82012-03-01 05:57:03 -0800430 success = results_lib.Results.BuildSucceededSoFar()
David James3d4d3502012-04-09 15:12:06 -0700431 if exception_thrown and success:
432 success = False
David Jamesbb20ac82012-07-18 10:59:16 -0700433 cros_build_lib.PrintBuildbotStepWarnings()
Mike Frysinger383367e2014-09-16 15:06:17 -0400434 print("""\
David James3d4d3502012-04-09 15:12:06 -0700435Exception thrown, but all stages marked successful. This is an internal error,
Mike Frysinger383367e2014-09-16 15:06:17 -0400436because the stage that threw the exception should be marked as failing.""")
Brian Harring3fec5a82012-03-01 05:57:03 -0800437
438 return success
439
440
David James1fddb8f2013-04-25 15:23:07 -0700441BoardConfig = collections.namedtuple('BoardConfig', ['board', 'name'])
442
443
Brian Harring3fec5a82012-03-01 05:57:03 -0800444class SimpleBuilder(Builder):
445 """Builder that performs basic vetting operations."""
446
447 def GetSyncInstance(self):
448 """Sync to lkgm or TOT as necessary.
449
Mike Frysinger02e1e072013-11-10 22:11:34 -0500450 Returns:
451 The instance of the sync stage to run.
Brian Harring3fec5a82012-03-01 05:57:03 -0800452 """
Matt Tennantefb59522013-10-18 13:49:28 -0700453 if self._run.options.force_version:
Yu-Ju Hongd0fda382014-05-09 15:28:24 -0700454 sync_stage = self._GetStageInstance(
455 sync_stages.ManifestVersionedSyncStage)
Matt Tennantefb59522013-10-18 13:49:28 -0700456 elif self._run.config.use_lkgm:
Yu-Ju Hongd0fda382014-05-09 15:28:24 -0700457 sync_stage = self._GetStageInstance(sync_stages.LKGMSyncStage)
Matt Tennantefb59522013-10-18 13:49:28 -0700458 elif self._run.config.use_chrome_lkgm:
Yu-Ju Hongd0fda382014-05-09 15:28:24 -0700459 sync_stage = self._GetStageInstance(chrome_stages.ChromeLKGMSyncStage)
Brian Harring3fec5a82012-03-01 05:57:03 -0800460 else:
Yu-Ju Hongd0fda382014-05-09 15:28:24 -0700461 sync_stage = self._GetStageInstance(sync_stages.SyncStage)
Brian Harring3fec5a82012-03-01 05:57:03 -0800462
463 return sync_stage
464
David Jamese1c8ab62014-03-27 12:30:58 -0700465 def _RunHWTests(self, builder_run, board):
466 """Run hwtest-related stages for the specified board.
Matt Tennant759e2352013-09-27 15:14:44 -0700467
468 Args:
David Jamese1c8ab62014-03-27 12:30:58 -0700469 builder_run: BuilderRun object for these background stages.
470 board: Board name.
Matt Tennant759e2352013-09-27 15:14:44 -0700471 """
J. Richard Barnette7ddc5102014-07-24 16:40:40 -0700472 parallel_stages = []
Matt Tennant759e2352013-09-27 15:14:44 -0700473
J. Richard Barnette7ddc5102014-07-24 16:40:40 -0700474 # We can not run hw tests without archiving the payloads.
475 if builder_run.options.archive:
476 for suite_config in builder_run.config.hw_tests:
477 stage_class = None
478 if suite_config.async:
479 stage_class = test_stages.ASyncHWTestStage
480 elif suite_config.suite == constants.HWTEST_AU_SUITE:
481 stage_class = test_stages.AUTestStage
J. Richard Barnette7ddc5102014-07-24 16:40:40 -0700482 else:
483 stage_class = test_stages.HWTestStage
J. Richard Barnette7ddc5102014-07-24 16:40:40 -0700484 if suite_config.blocking:
J. Richard Barnettefd67d4b2014-07-29 14:21:36 -0700485 self._RunStage(stage_class, board, suite_config,
486 builder_run=builder_run)
J. Richard Barnette7ddc5102014-07-24 16:40:40 -0700487 else:
J. Richard Barnettefd67d4b2014-07-29 14:21:36 -0700488 new_stage = self._GetStageInstance(stage_class, board,
489 suite_config,
490 builder_run=builder_run)
J. Richard Barnette7ddc5102014-07-24 16:40:40 -0700491 parallel_stages.append(new_stage)
492
493 self._RunParallelStages(parallel_stages)
David James4f2d8302013-03-19 06:35:58 -0700494
David Jamesb9e48a22014-07-15 21:26:02 -0700495 def _RunBackgroundStagesForBoardAndMarkAsSuccessful(self, builder_run, board):
496 """Run background board-specific stages for the specified board.
497
498 After finishing the build, mark it as successful.
499
500 Args:
501 builder_run: BuilderRun object for these background stages.
502 board: Board name.
503 """
504 self._RunBackgroundStagesForBoard(builder_run, board)
505 board_runattrs = builder_run.GetBoardRunAttrs(board)
506 board_runattrs.SetParallel('success', True)
507
David James5596d0e2014-03-14 06:40:41 -0700508 def _RunBackgroundStagesForBoard(self, builder_run, board):
Matt Tennant759e2352013-09-27 15:14:44 -0700509 """Run background board-specific stages for the specified board.
510
David Jamesb9e48a22014-07-15 21:26:02 -0700511 Used by _RunBackgroundStagesForBoardAndMarkAsSuccessful. Callers should use
512 that method instead.
513
Matt Tennant759e2352013-09-27 15:14:44 -0700514 Args:
Matt Tennantefb59522013-10-18 13:49:28 -0700515 builder_run: BuilderRun object for these background stages.
Matt Tennant759e2352013-09-27 15:14:44 -0700516 board: Board name.
Matt Tennant759e2352013-09-27 15:14:44 -0700517 """
Matt Tennantefb59522013-10-18 13:49:28 -0700518 config = builder_run.config
Matt Tennant066d9322014-01-28 10:37:48 -0800519
520 # TODO(mtennant): This is the last usage of self.archive_stages. We can
521 # kill it once we migrate its uses to BuilderRun so that none of the
522 # stages below need it as an argument.
Matt Tennantefb59522013-10-18 13:49:28 -0700523 archive_stage = self.archive_stages[BoardConfig(board, config.name)]
Luis Lozanoe0505bd2013-11-08 17:45:48 -0800524 if config.afdo_generate_min:
Ahmad Sharifa2db40a2013-07-22 13:51:52 -0400525 self._RunParallelStages([archive_stage])
David James1fddb8f2013-04-25 15:23:07 -0700526 return
Matt Tennant759e2352013-09-27 15:14:44 -0700527
Don Garrett655acb52014-05-21 17:10:06 -0700528 # paygen can't complete without push_image.
529 assert not config.paygen or config.push_image
David James5596d0e2014-03-14 06:40:41 -0700530
531 if config.build_packages_in_background:
Yu-Ju Hongd0fda382014-05-09 15:28:24 -0700532 self._RunStage(build_stages.BuildPackagesStage, board,
Gabe Black472b25e2014-08-18 19:48:47 -0700533 update_metadata=True, builder_run=builder_run,
534 afdo_use=config.afdo_use)
David James5596d0e2014-03-14 06:40:41 -0700535
536 if builder_run.config.compilecheck or builder_run.options.compilecheck:
Yu-Ju Hongd0fda382014-05-09 15:28:24 -0700537 self._RunStage(test_stages.UnitTestStage, board,
Matt Tennantefb59522013-10-18 13:49:28 -0700538 builder_run=builder_run)
David James565bc9a2013-04-08 14:54:45 -0700539 return
Matt Tennant759e2352013-09-27 15:14:44 -0700540
David James5596d0e2014-03-14 06:40:41 -0700541 # Build the image first before doing anything else.
542 # TODO(davidjames): Remove this lock once http://crbug.com/352994 is fixed.
543 with self._build_image_lock:
Yu-Ju Hongd0fda382014-05-09 15:28:24 -0700544 self._RunStage(build_stages.BuildImageStage, board,
Luis Lozanoe0505bd2013-11-08 17:45:48 -0800545 builder_run=builder_run, afdo_use=config.afdo_use)
Don Garrett82c0ae82014-02-03 18:25:11 -0800546
Mike Frysinger31ac04f2013-11-10 21:07:48 -0500547 # While this stage list is run in parallel, the order here dictates the
548 # order that things will be shown in the log. So group things together
549 # that make sense when read in order. Also keep in mind that, since we
550 # gather output manually, early slow stages will prevent any output from
551 # later stages showing up until it finishes.
David Jamesa18d5eb2015-01-07 16:06:29 -0800552 stage_list = [[chrome_stages.ChromeSDKStage, board]]
David James064e7e02014-04-23 17:06:16 -0700553
554 if config.vm_test_runs > 1:
555 # Run the VMTests multiple times to see if they fail.
556 stage_list += [
Yu-Ju Hongd0fda382014-05-09 15:28:24 -0700557 [generic_stages.RepeatStage, config.vm_test_runs,
558 test_stages.VMTestStage, board]]
David James064e7e02014-04-23 17:06:16 -0700559 else:
560 # Give the VMTests one retry attempt in case failures are flaky.
Yu-Ju Hongd0fda382014-05-09 15:28:24 -0700561 stage_list += [[generic_stages.RetryStage, 1, test_stages.VMTestStage,
562 board]]
David James064e7e02014-04-23 17:06:16 -0700563
Luis Lozanoe0505bd2013-11-08 17:45:48 -0800564 if config.afdo_generate:
565 stage_list += [[afdo_stages.AFDODataGenerateStage, board]]
566
David James6b704242013-10-18 14:51:37 -0700567 stage_list += [
Don Garrettbe60b892014-05-20 17:11:45 -0700568 [release_stages.SignerTestStage, board, archive_stage],
Yu-Ju Hong251646c2014-08-18 15:42:45 -0700569 [release_stages.PaygenStage, board, archive_stage],
Nam T. Nguyenf3816362014-06-13 09:26:27 -0700570 [test_stages.ImageTestStage, board],
Yu-Ju Hongd0fda382014-05-09 15:28:24 -0700571 [test_stages.UnitTestStage, board],
572 [artifact_stages.UploadPrebuiltsStage, board],
573 [artifact_stages.DevInstallerPrebuiltsStage, board],
574 [artifact_stages.DebugSymbolsStage, board],
575 [artifact_stages.CPEExportStage, board],
David Jamesc45a7d32014-10-13 15:16:46 -0700576 [artifact_stages.UploadTestArtifactsStage, board],
David James6b704242013-10-18 14:51:37 -0700577 ]
Brian Harring3fec5a82012-03-01 05:57:03 -0800578
Matt Tennantefb59522013-10-18 13:49:28 -0700579 stage_objs = [self._GetStageInstance(*x, builder_run=builder_run)
580 for x in stage_list]
David Jamese1c8ab62014-03-27 12:30:58 -0700581
582 parallel.RunParallelSteps([
583 lambda: self._RunParallelStages(stage_objs + [archive_stage]),
584 lambda: self._RunHWTests(builder_run, board),
585 ])
Brian Harring3fec5a82012-03-01 05:57:03 -0800586
David James3b4bacf2014-02-19 17:25:15 -0800587 def _RunSetupBoard(self):
588 """Run the SetupBoard stage for all child configs and boards."""
589 for builder_run in self._run.GetUngroupedBuilderRuns():
590 for board in builder_run.config.boards:
Yu-Ju Hongd0fda382014-05-09 15:28:24 -0700591 self._RunStage(build_stages.SetupBoardStage, board,
592 builder_run=builder_run)
David James3b4bacf2014-02-19 17:25:15 -0800593
Aviv Keshet7dc300f2013-10-11 12:57:49 -0400594 def _RunChrootBuilderTypeBuild(self):
595 """Runs through stages of a CHROOT_BUILDER_TYPE build."""
Mike Frysingera0753de2015-01-13 03:32:48 -0500596 # Unlike normal CrOS builds, the SDK has no concept of pinned CrOS manifest
597 # or specific Chrome version. Use a datestamp instead.
598 version = datetime.datetime.now().strftime('%Y.%m.%d.%H%M%S')
Yu-Ju Hongd0fda382014-05-09 15:28:24 -0700599 self._RunStage(build_stages.UprevStage, boards=[], enter_chroot=False)
600 self._RunStage(build_stages.InitSDKStage)
601 self._RunStage(build_stages.SetupBoardStage, constants.CHROOT_BUILDER_BOARD)
602 self._RunStage(chrome_stages.SyncChromeStage)
603 self._RunStage(chrome_stages.PatchChromeStage)
Mike Frysingerf47ff372014-11-06 15:37:21 -0500604 self._RunStage(sdk_stages.SDKBuildToolchainsStage)
Mike Frysingera0753de2015-01-13 03:32:48 -0500605 self._RunStage(sdk_stages.SDKPackageStage, version=version)
Yu-Ju Hongd0fda382014-05-09 15:28:24 -0700606 self._RunStage(sdk_stages.SDKTestStage)
607 self._RunStage(artifact_stages.UploadPrebuiltsStage,
Mike Frysingera0753de2015-01-13 03:32:48 -0500608 constants.CHROOT_BUILDER_BOARD, version=version)
Aviv Keshet7dc300f2013-10-11 12:57:49 -0400609
610 def _RunRefreshPackagesTypeBuild(self):
611 """Runs through the stages of a REFRESH_PACKAGES_TYPE build."""
Yu-Ju Hongd0fda382014-05-09 15:28:24 -0700612 self._RunStage(build_stages.InitSDKStage)
David James3b4bacf2014-02-19 17:25:15 -0800613 self._RunSetupBoard()
Yu-Ju Hongd0fda382014-05-09 15:28:24 -0700614 self._RunStage(report_stages.RefreshPackageStatusStage)
Aviv Keshet7dc300f2013-10-11 12:57:49 -0400615
Yu-Ju Hongcbdb0612014-07-25 16:20:48 -0700616 def _RunMasterPaladinOrChromePFQBuild(self):
617 """Runs through the stages of the paladin or chrome PFQ master build."""
Yu-Ju Hongd0fda382014-05-09 15:28:24 -0700618 self._RunStage(build_stages.InitSDKStage)
619 self._RunStage(build_stages.UprevStage)
Yu-Ju Hongcbdb0612014-07-25 16:20:48 -0700620 # The CQ/Chrome PFQ master will not actually run the SyncChrome stage, but
Matt Tennant9c1c8492014-02-27 13:09:07 -0800621 # we want the logic that gets triggered when SyncChrome stage is skipped.
Yu-Ju Hongd0fda382014-05-09 15:28:24 -0700622 self._RunStage(chrome_stages.SyncChromeStage)
623 self._RunStage(artifact_stages.MasterUploadPrebuiltsStage)
Matt Tennante8179042013-10-01 15:47:32 -0700624
Don Garrett4bb21682014-03-03 16:16:23 -0800625 def _RunPayloadsBuild(self):
626 """Run the PaygenStage once for each board."""
627 def _RunStageWrapper(board):
Don Garrettbe60b892014-05-20 17:11:45 -0700628 self._RunStage(release_stages.PaygenStage, board=board,
Don Garrett4bb21682014-03-03 16:16:23 -0800629 channels=self._run.options.channels, archive_stage=None)
630
631 with parallel.BackgroundTaskRunner(_RunStageWrapper) as queue:
632 for board in self._run.config.boards:
633 queue.put([board])
634
Aviv Keshet7dc300f2013-10-11 12:57:49 -0400635 def _RunDefaultTypeBuild(self):
636 """Runs through the stages of a non-special-type build."""
Yu-Ju Hongd0fda382014-05-09 15:28:24 -0700637 self._RunStage(build_stages.InitSDKStage)
638 self._RunStage(build_stages.UprevStage)
David James3b4bacf2014-02-19 17:25:15 -0800639 self._RunSetupBoard()
Yu-Ju Hongd0fda382014-05-09 15:28:24 -0700640 self._RunStage(chrome_stages.SyncChromeStage)
641 self._RunStage(chrome_stages.PatchChromeStage)
Aviv Keshet7dc300f2013-10-11 12:57:49 -0400642
Matt Tennantefb59522013-10-18 13:49:28 -0700643 # Prepare stages to run in background. If child_configs exist then
644 # run each of those here, otherwise use default config.
Matt Tennant950c6cb2014-01-10 16:45:03 -0800645 builder_runs = self._run.GetUngroupedBuilderRuns()
Matt Tennantefb59522013-10-18 13:49:28 -0700646
Aviv Keshet7dc300f2013-10-11 12:57:49 -0400647 tasks = []
Matt Tennantefb59522013-10-18 13:49:28 -0700648 for builder_run in builder_runs:
Matt Tennanta42a5742014-02-09 13:42:12 -0800649 # Prepare a local archive directory for each "run".
650 builder_run.GetArchive().SetupArchivePath()
651
Matt Tennantefb59522013-10-18 13:49:28 -0700652 for board in builder_run.config.boards:
Aviv Keshet7dc300f2013-10-11 12:57:49 -0400653 archive_stage = self._GetStageInstance(
Yu-Ju Hongd0fda382014-05-09 15:28:24 -0700654 artifact_stages.ArchiveStage, board, builder_run=builder_run,
Matt Tennant85348852014-01-10 15:16:02 -0800655 chrome_version=self._run.attrs.chrome_version)
Matt Tennantefb59522013-10-18 13:49:28 -0700656 board_config = BoardConfig(board, builder_run.config.name)
Aviv Keshet7dc300f2013-10-11 12:57:49 -0400657 self.archive_stages[board_config] = archive_stage
David James8281b6e2014-03-27 11:46:56 -0700658 tasks.append((builder_run, board))
Aviv Keshet7dc300f2013-10-11 12:57:49 -0400659
660 # Set up a process pool to run test/archive stages in the background.
David Jamesed8349b2014-03-01 11:27:04 -0800661 # This process runs task(board) for each board added to the queue.
David Jamesb9e48a22014-07-15 21:26:02 -0700662 task_runner = self._RunBackgroundStagesForBoardAndMarkAsSuccessful
Aviv Keshet7dc300f2013-10-11 12:57:49 -0400663 with parallel.BackgroundTaskRunner(task_runner) as queue:
David James8281b6e2014-03-27 11:46:56 -0700664 for builder_run, board in tasks:
David James5596d0e2014-03-14 06:40:41 -0700665 if not builder_run.config.build_packages_in_background:
Luis Lozanoe0505bd2013-11-08 17:45:48 -0800666 # Run BuildPackages in the foreground, generating or using AFDO data
David James5596d0e2014-03-14 06:40:41 -0700667 # if requested.
David James8281b6e2014-03-27 11:46:56 -0700668 kwargs = {'builder_run': builder_run}
Luis Lozanoe0505bd2013-11-08 17:45:48 -0800669 if builder_run.config.afdo_generate_min:
670 kwargs['afdo_generate_min'] = True
671 elif builder_run.config.afdo_use:
672 kwargs['afdo_use'] = True
David Jamesed8349b2014-03-01 11:27:04 -0800673
Gabe Black472b25e2014-08-18 19:48:47 -0700674 self._RunStage(build_stages.BuildPackagesStage, board,
675 update_metadata=True, **kwargs)
David Jamesed8349b2014-03-01 11:27:04 -0800676
Luis Lozanoe0505bd2013-11-08 17:45:48 -0800677 if (builder_run.config.afdo_generate_min and
678 afdo.CanGenerateAFDOData(board)):
679 # Generate the AFDO data before allowing any other tasks to run.
Yu-Ju Hongd0fda382014-05-09 15:28:24 -0700680 self._RunStage(build_stages.BuildImageStage, board, **kwargs)
681 self._RunStage(artifact_stages.UploadTestArtifactsStage, board,
Luis Lozanoe0505bd2013-11-08 17:45:48 -0800682 builder_run=builder_run,
683 suffix='[afdo_generate_min]')
684 suite = cbuildbot_config.AFDORecordTest()
Yu-Ju Hongd0fda382014-05-09 15:28:24 -0700685 self._RunStage(test_stages.HWTestStage, board, suite,
David Jamesed8349b2014-03-01 11:27:04 -0800686 builder_run=builder_run)
Luis Lozanoe0505bd2013-11-08 17:45:48 -0800687 self._RunStage(afdo_stages.AFDODataGenerateStage, board,
688 builder_run=builder_run)
689
690 if (builder_run.config.afdo_generate_min and
691 builder_run.config.afdo_update_ebuild):
692 self._RunStage(afdo_stages.AFDOUpdateEbuildStage,
693 builder_run=builder_run)
David Jamesed8349b2014-03-01 11:27:04 -0800694
695 # Kick off our background stages.
David James5596d0e2014-03-14 06:40:41 -0700696 queue.put([builder_run, board])
Aviv Keshet7dc300f2013-10-11 12:57:49 -0400697
Brian Harring3fec5a82012-03-01 05:57:03 -0800698 def RunStages(self):
699 """Runs through build process."""
Brian Harring3fec5a82012-03-01 05:57:03 -0800700 # TODO(sosa): Split these out into classes.
Matt Tennantefb59522013-10-18 13:49:28 -0700701 if self._run.config.build_type == constants.PRE_CQ_LAUNCHER_TYPE:
Yu-Ju Hongd0fda382014-05-09 15:28:24 -0700702 self._RunStage(sync_stages.PreCQLauncherStage)
Matt Tennantefb59522013-10-18 13:49:28 -0700703 elif self._run.config.build_type == constants.CREATE_BRANCH_TYPE:
Yu-Ju Hongd0fda382014-05-09 15:28:24 -0700704 self._RunStage(branch_stages.BranchUtilStage)
Matt Tennantefb59522013-10-18 13:49:28 -0700705 elif self._run.config.build_type == constants.CHROOT_BUILDER_TYPE:
Aviv Keshet7dc300f2013-10-11 12:57:49 -0400706 self._RunChrootBuilderTypeBuild()
Matt Tennantefb59522013-10-18 13:49:28 -0700707 elif self._run.config.build_type == constants.REFRESH_PACKAGES_TYPE:
Aviv Keshet7dc300f2013-10-11 12:57:49 -0400708 self._RunRefreshPackagesTypeBuild()
Yu-Ju Hongcbdb0612014-07-25 16:20:48 -0700709 elif ((self._run.config.build_type == constants.PALADIN_TYPE or
710 self._run.config.build_type == constants.CHROME_PFQ_TYPE) and
Matt Tennante8179042013-10-01 15:47:32 -0700711 self._run.config.master):
Yu-Ju Hongcbdb0612014-07-25 16:20:48 -0700712 self._RunMasterPaladinOrChromePFQBuild()
Don Garrett4bb21682014-03-03 16:16:23 -0800713 elif self._run.config.build_type == constants.PAYLOADS_TYPE:
714 self._RunPayloadsBuild()
Brian Harring3fec5a82012-03-01 05:57:03 -0800715 else:
Aviv Keshet7dc300f2013-10-11 12:57:49 -0400716 self._RunDefaultTypeBuild()
David James58e0c092012-03-04 20:31:12 -0800717
Brian Harring3fec5a82012-03-01 05:57:03 -0800718
719class DistributedBuilder(SimpleBuilder):
720 """Build class that has special logic to handle distributed builds.
721
722 These builds sync using git/manifest logic in manifest_versions. In general
723 they use a non-distributed builder code for the bulk of the work.
724 """
David Jameseecba232014-06-11 11:35:11 -0700725
Ryan Cuif7f24692012-05-18 16:35:33 -0700726 def __init__(self, *args, **kwargs):
Brian Harring3fec5a82012-03-01 05:57:03 -0800727 """Initializes a buildbot builder.
728
729 Extra variables:
730 completion_stage_class: Stage used to complete a build. Set in the Sync
731 stage.
732 """
Ryan Cuif7f24692012-05-18 16:35:33 -0700733 super(DistributedBuilder, self).__init__(*args, **kwargs)
Brian Harring3fec5a82012-03-01 05:57:03 -0800734 self.completion_stage_class = None
David Jamesf421c6d2013-04-11 15:37:57 -0700735 self.sync_stage = None
Aviv Keshet5c39b6a2013-10-07 15:44:54 -0400736 self._completion_stage = None
Brian Harring3fec5a82012-03-01 05:57:03 -0800737
738 def GetSyncInstance(self):
739 """Syncs the tree using one of the distributed sync logic paths.
740
Mike Frysinger02e1e072013-11-10 22:11:34 -0500741 Returns:
742 The instance of the sync stage to run.
Brian Harring3fec5a82012-03-01 05:57:03 -0800743 """
744 # Determine sync class to use. CQ overrides PFQ bits so should check it
745 # first.
Matt Tennantefb59522013-10-18 13:49:28 -0700746 if self._run.config.pre_cq or self._run.options.pre_cq:
Yu-Ju Hongd0fda382014-05-09 15:28:24 -0700747 sync_stage = self._GetStageInstance(sync_stages.PreCQSyncStage,
David Jamesf421c6d2013-04-11 15:37:57 -0700748 self.patch_pool.gerrit_patches)
Yu-Ju Hongd0fda382014-05-09 15:28:24 -0700749 self.completion_stage_class = completion_stages.PreCQCompletionStage
David Jamesf421c6d2013-04-11 15:37:57 -0700750 self.patch_pool.gerrit_patches = []
Matt Tennantefb59522013-10-18 13:49:28 -0700751 elif cbuildbot_config.IsCQType(self._run.config.build_type):
752 if self._run.config.do_not_apply_cq_patches:
Yu-Ju Hong78a41072014-07-30 16:55:36 -0700753 sync_stage = self._GetStageInstance(
754 sync_stages.MasterSlaveLKGMSyncStage)
Aviv Keshet00bc9512013-11-25 14:58:47 -0800755 else:
Yu-Ju Hongd0fda382014-05-09 15:28:24 -0700756 sync_stage = self._GetStageInstance(sync_stages.CommitQueueSyncStage)
757 self.completion_stage_class = completion_stages.CommitQueueCompletionStage
Matt Tennantefb59522013-10-18 13:49:28 -0700758 elif cbuildbot_config.IsPFQType(self._run.config.build_type):
Yu-Ju Hong78a41072014-07-30 16:55:36 -0700759 sync_stage = self._GetStageInstance(sync_stages.MasterSlaveLKGMSyncStage)
760 self.completion_stage_class = (
761 completion_stages.MasterSlaveSyncCompletionStage)
762 elif cbuildbot_config.IsCanaryType(self._run.config.build_type):
763 sync_stage = self._GetStageInstance(
764 sync_stages.ManifestVersionedSyncStage)
Yu-Ju Hongd0fda382014-05-09 15:28:24 -0700765 self.completion_stage_class = (
Yu-Ju Hong065807f2014-08-07 12:18:38 -0700766 completion_stages.CanaryCompletionStage)
Brian Harring3fec5a82012-03-01 05:57:03 -0800767 else:
Yu-Ju Hongd0fda382014-05-09 15:28:24 -0700768 sync_stage = self._GetStageInstance(
769 sync_stages.ManifestVersionedSyncStage)
770 self.completion_stage_class = (
771 completion_stages.ManifestVersionedSyncCompletionStage)
Brian Harring3fec5a82012-03-01 05:57:03 -0800772
David Jamesf421c6d2013-04-11 15:37:57 -0700773 self.sync_stage = sync_stage
774 return self.sync_stage
Brian Harring3fec5a82012-03-01 05:57:03 -0800775
Aviv Keshet5c39b6a2013-10-07 15:44:54 -0400776 def GetCompletionInstance(self):
777 """Returns the completion_stage_class instance that was used for this build.
778
Mike Frysinger1a736a82013-12-12 01:50:59 -0500779 Returns:
780 None if the completion_stage instance was not yet created (this
781 occurs during Publish).
Aviv Keshet5c39b6a2013-10-07 15:44:54 -0400782 """
783 return self._completion_stage
784
David James0825d5d2014-08-07 19:53:45 -0700785 def Publish(self, was_build_successful, build_finished):
786 """Completes build by publishing any required information.
787
788 Args:
789 was_build_successful: Whether the build succeeded.
790 build_finished: Whether the build completed. A build can be successful
791 without completing if it exits early with sys.exit(0).
792 """
Brian Harring3fec5a82012-03-01 05:57:03 -0800793 completion_stage = self._GetStageInstance(self.completion_stage_class,
David Jamesf421c6d2013-04-11 15:37:57 -0700794 self.sync_stage,
Brian Harring3fec5a82012-03-01 05:57:03 -0800795 was_build_successful)
Aviv Keshet5c39b6a2013-10-07 15:44:54 -0400796 self._completion_stage = completion_stage
David James11fd7e82013-10-23 20:02:16 -0700797 completion_successful = False
798 try:
799 completion_stage.Run()
800 completion_successful = True
Luis Lozanoe0505bd2013-11-08 17:45:48 -0800801 if (self._run.config.afdo_update_ebuild and
802 not self._run.config.afdo_generate_min):
803 self._RunStage(afdo_stages.AFDOUpdateEbuildStage)
David James11fd7e82013-10-23 20:02:16 -0700804 finally:
Matt Tennantefb59522013-10-18 13:49:28 -0700805 if self._run.config.push_overlays:
David James0825d5d2014-08-07 19:53:45 -0700806 publish = (was_build_successful and completion_successful and
807 build_finished)
808 self._RunStage(completion_stages.PublishUprevChangesStage, publish)
Brian Harring3fec5a82012-03-01 05:57:03 -0800809
810 def RunStages(self):
811 """Runs simple builder logic and publishes information to overlays."""
812 was_build_successful = False
David James0825d5d2014-08-07 19:53:45 -0700813 build_finished = False
David James843ed252013-09-11 16:18:10 -0700814 try:
815 super(DistributedBuilder, self).RunStages()
816 was_build_successful = results_lib.Results.BuildSucceededSoFar()
David James0825d5d2014-08-07 19:53:45 -0700817 build_finished = True
David James843ed252013-09-11 16:18:10 -0700818 except SystemExit as ex:
819 # If a stage calls sys.exit(0), it's exiting with success, so that means
820 # we should mark ourselves as successful.
David James0825d5d2014-08-07 19:53:45 -0700821 cros_build_lib.Info('Detected sys.exit(%s)', ex.code)
David James843ed252013-09-11 16:18:10 -0700822 if ex.code == 0:
823 was_build_successful = True
824 raise
825 finally:
David James0825d5d2014-08-07 19:53:45 -0700826 self.Publish(was_build_successful, build_finished)
Brian Harring3fec5a82012-03-01 05:57:03 -0800827
Brian Harring3fec5a82012-03-01 05:57:03 -0800828
829def _ConfirmBuildRoot(buildroot):
830 """Confirm with user the inferred buildroot, and mark it as confirmed."""
Brian Harring521e7242012-11-01 16:57:42 -0700831 cros_build_lib.Warning('Using default directory %s as buildroot', buildroot)
832 if not cros_build_lib.BooleanPrompt(default=False):
833 print('Please specify a different buildroot via the --buildroot option.')
Brian Harring3fec5a82012-03-01 05:57:03 -0800834 sys.exit(0)
835
836 if not os.path.exists(buildroot):
837 os.mkdir(buildroot)
838
839 repository.CreateTrybotMarker(buildroot)
840
841
Ryan Cuieaa9efd2012-04-25 17:56:45 -0700842def _ConfirmRemoteBuildbotRun():
843 """Confirm user wants to run with --buildbot --remote."""
Brian Harring521e7242012-11-01 16:57:42 -0700844 cros_build_lib.Warning(
David Jameseecba232014-06-11 11:35:11 -0700845 'You are about to launch a PRODUCTION job! This is *NOT* a '
846 'trybot run! Are you sure?')
Brian Harring521e7242012-11-01 16:57:42 -0700847 if not cros_build_lib.BooleanPrompt(default=False):
Ryan Cuieaa9efd2012-04-25 17:56:45 -0700848 print('Please specify --pass-through="--debug".')
849 sys.exit(0)
850
851
Ryan Cui5ba7e152012-05-10 14:36:52 -0700852def _DetermineDefaultBuildRoot(sourceroot, internal_build):
Brian Harring3fec5a82012-03-01 05:57:03 -0800853 """Default buildroot to be under the directory that contains current checkout.
854
Mike Frysinger02e1e072013-11-10 22:11:34 -0500855 Args:
Brian Harring3fec5a82012-03-01 05:57:03 -0800856 internal_build: Whether the build is an internal build
Ryan Cui5ba7e152012-05-10 14:36:52 -0700857 sourceroot: Use specified sourceroot.
Brian Harring3fec5a82012-03-01 05:57:03 -0800858 """
Ryan Cui5ba7e152012-05-10 14:36:52 -0700859 if not repository.IsARepoRoot(sourceroot):
Brian Harring1b8c4c82012-05-29 23:03:04 -0700860 cros_build_lib.Die(
861 'Could not find root of local checkout at %s. Please specify '
862 'using the --sourceroot option.' % sourceroot)
Brian Harring3fec5a82012-03-01 05:57:03 -0800863
864 # Place trybot buildroot under the directory containing current checkout.
Ryan Cui5ba7e152012-05-10 14:36:52 -0700865 top_level = os.path.dirname(os.path.realpath(sourceroot))
Brian Harring3fec5a82012-03-01 05:57:03 -0800866 if internal_build:
867 buildroot = os.path.join(top_level, _DEFAULT_INT_BUILDROOT)
868 else:
869 buildroot = os.path.join(top_level, _DEFAULT_EXT_BUILDROOT)
870
871 return buildroot
872
873
874def _BackupPreviousLog(log_file, backup_limit=25):
875 """Rename previous log.
876
877 Args:
878 log_file: The absolute path to the previous log.
Aviv Keshet9e4236b2013-12-13 13:07:50 -0800879 backup_limit: Maximum number of old logs to keep.
Brian Harring3fec5a82012-03-01 05:57:03 -0800880 """
881 if os.path.exists(log_file):
882 old_logs = sorted(glob.glob(log_file + '.*'),
883 key=distutils.version.LooseVersion)
884
885 if len(old_logs) >= backup_limit:
886 os.remove(old_logs[0])
887
888 last = 0
889 if old_logs:
890 last = int(old_logs.pop().rpartition('.')[2])
891
892 os.rename(log_file, log_file + '.' + str(last + 1))
893
Ryan Cui5616a512012-08-17 13:39:36 -0700894
Gaurav Shah298aa372014-01-31 09:27:24 -0800895def _IsDistributedBuilder(options, chrome_rev, build_config):
896 """Determines whether the builder should be a DistributedBuilder.
897
898 Args:
899 options: options passed on the commandline.
900 chrome_rev: Chrome revision to build.
901 build_config: Builder configuration dictionary.
902
903 Returns:
904 True if the builder should be a distributed_builder
905 """
906 if build_config['pre_cq'] or options.pre_cq:
907 return True
908 elif not options.buildbot:
909 return False
910 elif chrome_rev in (constants.CHROME_REV_TOT,
911 constants.CHROME_REV_LOCAL,
912 constants.CHROME_REV_SPEC):
913 # We don't do distributed logic to TOT Chrome PFQ's, nor local
914 # chrome roots (e.g. chrome try bots)
915 # TODO(davidjames): Update any builders that rely on this logic to use
916 # manifest_version=False instead.
917 return False
918 elif build_config['manifest_version']:
919 return True
920
921 return False
922
923
David James944a48e2012-03-07 12:19:03 -0800924def _RunBuildStagesWrapper(options, build_config):
Brian Harring3fec5a82012-03-01 05:57:03 -0800925 """Helper function that wraps RunBuildStages()."""
Matt Tennant7feda352013-12-20 14:03:40 -0800926 cros_build_lib.Info('cbuildbot was executed with args %s' %
927 cros_build_lib.CmdToStr(sys.argv))
Brian Harring3fec5a82012-03-01 05:57:03 -0800928
David Jamesa0a664e2013-02-13 09:52:01 -0800929 chrome_rev = build_config['chrome_rev']
930 if options.chrome_rev:
931 chrome_rev = options.chrome_rev
932 if chrome_rev == constants.CHROME_REV_TOT:
Stefan Zagerd49d9ff2014-08-15 21:33:37 -0700933 options.chrome_version = gob_util.GetTipOfTrunkRevision(
934 constants.CHROMIUM_GOB_URL)
David Jamesa0a664e2013-02-13 09:52:01 -0800935 options.chrome_rev = constants.CHROME_REV_SPEC
936
David James4a404a52013-02-19 13:07:59 -0800937 # If it's likely we'll need to build Chrome, fetch the source.
Mike Frysingerf4d9ab82013-03-05 19:38:05 -0500938 if build_config['sync_chrome'] is None:
David Jameseecba232014-06-11 11:35:11 -0700939 options.managed_chrome = (
940 chrome_rev != constants.CHROME_REV_LOCAL and
Mike Frysingerf4d9ab82013-03-05 19:38:05 -0500941 (not build_config['usepkg_build_packages'] or chrome_rev or
David James3cce4642013-05-10 17:50:23 -0700942 build_config['profile'] or options.rietveld_patches))
Mike Frysingerf4d9ab82013-03-05 19:38:05 -0500943 else:
944 options.managed_chrome = build_config['sync_chrome']
David James2333c182013-02-13 16:16:15 -0800945
946 if options.managed_chrome:
947 # Tell Chrome to fetch the source locally.
Matt Tennant628ffdd2013-11-27 14:44:39 -0800948 internal = constants.USE_CHROME_INTERNAL in build_config['useflags']
David James2333c182013-02-13 16:16:15 -0800949 chrome_src = 'chrome-src-internal' if internal else 'chrome-src'
950 options.chrome_root = os.path.join(options.cache_dir, 'distfiles', 'target',
951 chrome_src)
David James9e27e662013-02-14 13:42:43 -0800952 elif options.rietveld_patches:
David James4a404a52013-02-19 13:07:59 -0800953 cros_build_lib.Die('This builder does not support Rietveld patches.')
David James2333c182013-02-13 16:16:15 -0800954
Aviv Keshet669eb5e2014-06-23 08:53:01 -0700955 metadata_dump_dict = {}
956 if options.metadata_dump:
957 with open(options.metadata_dump, 'r') as metadata_file:
958 metadata_dump_dict = json.loads(metadata_file.read())
959
Matt Tennant95a42ad2013-12-27 15:38:36 -0800960 # We are done munging options values, so freeze options object now to avoid
961 # further abuse of it.
962 # TODO(mtennant): one by one identify each options value override and see if
963 # it can be handled another way. Try to push this freeze closer and closer
964 # to the start of the script (e.g. in or after _PostParseCheck).
965 options.Freeze()
966
Matt Tennant0940c382014-01-21 20:43:55 -0800967 with parallel.Manager() as manager:
968 builder_run = cbuildbot_run.BuilderRun(options, build_config, manager)
Aviv Keshet669eb5e2014-06-23 08:53:01 -0700969 if metadata_dump_dict:
970 builder_run.attrs.metadata.UpdateWithDict(metadata_dump_dict)
Matt Tennant0940c382014-01-21 20:43:55 -0800971 if _IsDistributedBuilder(options, chrome_rev, build_config):
972 builder_cls = DistributedBuilder
973 else:
974 builder_cls = SimpleBuilder
975 builder = builder_cls(builder_run)
976 if not builder.Run():
977 sys.exit(1)
Brian Harring3fec5a82012-03-01 05:57:03 -0800978
979
980# Parser related functions
Ryan Cui5ba7e152012-05-10 14:36:52 -0700981def _CheckLocalPatches(sourceroot, local_patches):
Brian Harring3fec5a82012-03-01 05:57:03 -0800982 """Do an early quick check of the passed-in patches.
983
984 If the branch of a project is not specified we append the current branch the
985 project is on.
Ryan Cui5ba7e152012-05-10 14:36:52 -0700986
David Jamese3b06062013-11-09 18:52:02 -0800987 TODO(davidjames): The project:branch format isn't unique, so this means that
988 we can't differentiate what directory the user intended to apply patches to.
989 We should references by directory instead.
990
Ryan Cui5ba7e152012-05-10 14:36:52 -0700991 Args:
992 sourceroot: The checkout where patches are coming from.
Aviv Keshet9e4236b2013-12-13 13:07:50 -0800993 local_patches: List of patches to check in project:branch format.
David Jamese3b06062013-11-09 18:52:02 -0800994
995 Returns:
996 A list of patches that have been verified, in project:branch format.
Brian Harring3fec5a82012-03-01 05:57:03 -0800997 """
Ryan Cuicedd8a52012-03-22 02:28:35 -0700998 verified_patches = []
David James97d95872012-11-16 15:09:56 -0800999 manifest = git.ManifestCheckout.Cached(sourceroot)
Ryan Cuicedd8a52012-03-22 02:28:35 -07001000 for patch in local_patches:
David Jamese3b06062013-11-09 18:52:02 -08001001 project, _, branch = patch.partition(':')
1002
Gaurav Shah7afb0562013-12-26 15:05:39 -08001003 checkouts = manifest.FindCheckouts(project, only_patchable=True)
David Jamese3b06062013-11-09 18:52:02 -08001004 if not checkouts:
1005 cros_build_lib.Die('Project %s does not exist.' % (project,))
1006 if len(checkouts) > 1:
Brian Harring1b8c4c82012-05-29 23:03:04 -07001007 cros_build_lib.Die(
David Jamese3b06062013-11-09 18:52:02 -08001008 'We do not yet support local patching for projects that are checked '
1009 'out to multiple directories. Try uploading your patch to gerrit '
1010 'and referencing it via the -g option instead.'
1011 )
Brian Harring3fec5a82012-03-01 05:57:03 -08001012
David Jamese3b06062013-11-09 18:52:02 -08001013 ok = False
1014 for checkout in checkouts:
1015 project_dir = checkout.GetPath(absolute=True)
Brian Harring3fec5a82012-03-01 05:57:03 -08001016
David Jamese3b06062013-11-09 18:52:02 -08001017 # If no branch was specified, we use the project's current branch.
Brian Harring3fec5a82012-03-01 05:57:03 -08001018 if not branch:
David Jamese3b06062013-11-09 18:52:02 -08001019 local_branch = git.GetCurrentBranch(project_dir)
1020 else:
1021 local_branch = branch
Brian Harring3fec5a82012-03-01 05:57:03 -08001022
David Jamesf1a07612014-04-28 17:48:52 -07001023 if local_branch and git.DoesCommitExistInRepo(project_dir, local_branch):
David Jamese3b06062013-11-09 18:52:02 -08001024 verified_patches.append('%s:%s' % (project, local_branch))
1025 ok = True
1026
1027 if not ok:
1028 if branch:
1029 cros_build_lib.Die('Project %s does not have branch %s'
David Jameseecba232014-06-11 11:35:11 -07001030 % (project, branch))
David Jamese3b06062013-11-09 18:52:02 -08001031 else:
1032 cros_build_lib.Die('Project %s is not on a branch!' % (project,))
Brian Harring3fec5a82012-03-01 05:57:03 -08001033
Ryan Cuicedd8a52012-03-22 02:28:35 -07001034 return verified_patches
Brian Harring3fec5a82012-03-01 05:57:03 -08001035
1036
Brian Harring3fec5a82012-03-01 05:57:03 -08001037def _CheckChromeVersionOption(_option, _opt_str, value, parser):
1038 """Upgrade other options based on chrome_version being passed."""
1039 value = value.strip()
1040
1041 if parser.values.chrome_rev is None and value:
1042 parser.values.chrome_rev = constants.CHROME_REV_SPEC
1043
1044 parser.values.chrome_version = value
1045
1046
1047def _CheckChromeRootOption(_option, _opt_str, value, parser):
1048 """Validate and convert chrome_root to full-path form."""
Brian Harring3fec5a82012-03-01 05:57:03 -08001049 if parser.values.chrome_rev is None:
1050 parser.values.chrome_rev = constants.CHROME_REV_LOCAL
1051
Ryan Cui5ba7e152012-05-10 14:36:52 -07001052 parser.values.chrome_root = value
Brian Harring3fec5a82012-03-01 05:57:03 -08001053
1054
1055def _CheckChromeRevOption(_option, _opt_str, value, parser):
1056 """Validate the chrome_rev option."""
1057 value = value.strip()
1058 if value not in constants.VALID_CHROME_REVISIONS:
1059 raise optparse.OptionValueError('Invalid chrome rev specified')
1060
1061 parser.values.chrome_rev = value
1062
1063
David Jamesac8c2a72013-02-13 18:44:33 -08001064def FindCacheDir(_parser, _options):
Brian Harringae0a5322012-09-15 01:46:51 -07001065 return None
1066
1067
Ryan Cui5ba7e152012-05-10 14:36:52 -07001068class CustomGroup(optparse.OptionGroup):
Aviv Keshet9e4236b2013-12-13 13:07:50 -08001069 """Custom option group which supports arguments passed-through to trybot."""
David Jameseecba232014-06-11 11:35:11 -07001070
Ryan Cui5ba7e152012-05-10 14:36:52 -07001071 def add_remote_option(self, *args, **kwargs):
1072 """For arguments that are passed-through to remote trybot."""
1073 return optparse.OptionGroup.add_option(self, *args,
1074 remote_pass_through=True,
1075 **kwargs)
1076
1077
Ryan Cui1c13a252012-10-16 15:00:16 -07001078class CustomOption(commandline.FilteringOption):
1079 """Subclass FilteringOption class to implement pass-through and api."""
Ryan Cui5ba7e152012-05-10 14:36:52 -07001080
Ryan Cui1c13a252012-10-16 15:00:16 -07001081 ACTIONS = commandline.FilteringOption.ACTIONS + ('extend',)
1082 STORE_ACTIONS = commandline.FilteringOption.STORE_ACTIONS + ('extend',)
1083 TYPED_ACTIONS = commandline.FilteringOption.TYPED_ACTIONS + ('extend',)
1084 ALWAYS_TYPED_ACTIONS = (commandline.FilteringOption.ALWAYS_TYPED_ACTIONS +
1085 ('extend',))
Ryan Cui79319ab2012-05-21 12:59:18 -07001086
Ryan Cui5ba7e152012-05-10 14:36:52 -07001087 def __init__(self, *args, **kwargs):
1088 # The remote_pass_through argument specifies whether we should directly
1089 # pass the argument (with its value) onto the remote trybot.
1090 self.pass_through = kwargs.pop('remote_pass_through', False)
Ryan Cui1c13a252012-10-16 15:00:16 -07001091 self.api_version = int(kwargs.pop('api', '0'))
1092 commandline.FilteringOption.__init__(self, *args, **kwargs)
Ryan Cui5ba7e152012-05-10 14:36:52 -07001093
1094 def take_action(self, action, dest, opt, value, values, parser):
Ryan Cui79319ab2012-05-21 12:59:18 -07001095 if action == 'extend':
Mike Frysingerd6925b52012-07-16 16:11:00 -04001096 # If there is extra spaces between each argument, we get '' which later
1097 # code barfs on, so skip those. e.g. We see this with the forms:
1098 # cbuildbot -p 'proj:branch ' ...
1099 # cbuildbot -p ' proj:branch' ...
1100 # cbuildbot -p 'proj:branch proj2:branch' ...
1101 lvalue = value.split()
Ryan Cui79319ab2012-05-21 12:59:18 -07001102 values.ensure_value(dest, []).extend(lvalue)
Ryan Cui79319ab2012-05-21 12:59:18 -07001103
Ryan Cui1c13a252012-10-16 15:00:16 -07001104 commandline.FilteringOption.take_action(
1105 self, action, dest, opt, value, values, parser)
Ryan Cui5ba7e152012-05-10 14:36:52 -07001106
1107
Ryan Cui1c13a252012-10-16 15:00:16 -07001108class CustomParser(commandline.FilteringParser):
Aviv Keshet9e4236b2013-12-13 13:07:50 -08001109 """Custom option parser which supports arguments passed-trhough to trybot"""
Matt Tennante8179042013-10-01 15:47:32 -07001110
Brian Harringb6cf9142012-09-01 20:43:17 -07001111 DEFAULT_OPTION_CLASS = CustomOption
1112
1113 def add_remote_option(self, *args, **kwargs):
1114 """For arguments that are passed-through to remote trybot."""
Ryan Cui1c13a252012-10-16 15:00:16 -07001115 return self.add_option(*args, remote_pass_through=True, **kwargs)
Brian Harringb6cf9142012-09-01 20:43:17 -07001116
1117
Brian Harring3fec5a82012-03-01 05:57:03 -08001118def _CreateParser():
Ryan Cui16d9e1f2012-05-11 10:50:18 -07001119 """Generate and return the parser with all the options."""
Brian Harring3fec5a82012-03-01 05:57:03 -08001120 # Parse options
David Jameseecba232014-06-11 11:35:11 -07001121 usage = 'usage: %prog [options] buildbot_config [buildbot_config ...]'
Brian Harringae0a5322012-09-15 01:46:51 -07001122 parser = CustomParser(usage=usage, caching=FindCacheDir)
Brian Harring3fec5a82012-03-01 05:57:03 -08001123
1124 # Main options
Mike Frysinger81af6ef2013-04-03 02:24:09 -04001125 parser.add_option('-l', '--list', action='store_true', dest='list',
1126 default=False,
1127 help='List the suggested trybot configs to use (see --all)')
Brian Harring3fec5a82012-03-01 05:57:03 -08001128 parser.add_option('-a', '--all', action='store_true', dest='print_all',
1129 default=False,
Mike Frysinger81af6ef2013-04-03 02:24:09 -04001130 help='List all of the buildbot configs available w/--list')
1131
1132 parser.add_option('--local', default=False, action='store_true',
David Jameseecba232014-06-11 11:35:11 -07001133 help=('Specifies that this tryjob should be run locally. '
1134 'Implies --debug.'))
Mike Frysinger81af6ef2013-04-03 02:24:09 -04001135 parser.add_option('--remote', default=False, action='store_true',
Ryan Cui88b901c2013-06-21 11:35:30 -07001136 help='Specifies that this tryjob should be run remotely.')
Mike Frysinger81af6ef2013-04-03 02:24:09 -04001137
Ryan Cuie1e4e662012-05-21 16:39:46 -07001138 parser.add_remote_option('-b', '--branch',
David Jameseecba232014-06-11 11:35:11 -07001139 help=('The manifest branch to test. The branch to '
1140 'check the buildroot out to.'))
Ryan Cui5ba7e152012-05-10 14:36:52 -07001141 parser.add_option('-r', '--buildroot', dest='buildroot', type='path',
David Jameseecba232014-06-11 11:35:11 -07001142 help=('Root directory where source is checked out to, and '
1143 'where the build occurs. For external build configs, '
1144 "defaults to 'trybot' directory at top level of your "
1145 'repo-managed checkout.'))
Ryan Cuieaa9efd2012-04-25 17:56:45 -07001146 parser.add_remote_option('--chrome_rev', default=None, type='string',
1147 action='callback', dest='chrome_rev',
1148 callback=_CheckChromeRevOption,
1149 help=('Revision of Chrome to use, of type [%s]'
1150 % '|'.join(constants.VALID_CHROME_REVISIONS)))
Ryan Cuieaa9efd2012-04-25 17:56:45 -07001151 parser.add_remote_option('--profile', default=None, type='string',
1152 action='store', dest='profile',
1153 help='Name of profile to sub-specify board variant.')
Brian Harring3fec5a82012-03-01 05:57:03 -08001154
Ryan Cuif4f84be2012-07-09 18:50:41 -07001155 #
Mike Frysinger81af6ef2013-04-03 02:24:09 -04001156 # Patch selection options.
1157 #
1158
1159 group = CustomGroup(
1160 parser,
1161 'Patch Options')
1162
1163 group.add_remote_option('-g', '--gerrit-patches', action='extend',
1164 default=[], type='string',
1165 metavar="'Id1 *int_Id2...IdN'",
David Jameseecba232014-06-11 11:35:11 -07001166 help=('Space-separated list of short-form Gerrit '
1167 "Change-Id's or change numbers to patch. "
1168 "Please prepend '*' to internal Change-Id's"))
Mike Frysinger81af6ef2013-04-03 02:24:09 -04001169 group.add_remote_option('-G', '--rietveld-patches', action='extend',
1170 default=[], type='string',
1171 metavar="'id1[:subdir1]...idN[:subdirN]'",
David Jameseecba232014-06-11 11:35:11 -07001172 help=('Space-separated list of short-form Rietveld '
1173 'issue numbers to patch. If no subdir is '
1174 'specified, the src directory is used.'))
Mike Frysinger81af6ef2013-04-03 02:24:09 -04001175 group.add_option('-p', '--local-patches', action='extend', default=[],
1176 metavar="'<project1>[:<branch1>]...<projectN>[:<branchN>]'",
David Jameseecba232014-06-11 11:35:11 -07001177 help=('Space-separated list of project branches with '
1178 'patches to apply. Projects are specified by name. '
1179 'If no branch is specified the current branch of the '
1180 'project will be used.'))
Mike Frysinger81af6ef2013-04-03 02:24:09 -04001181
1182 parser.add_option_group(group)
1183
1184 #
1185 # Remote trybot options.
1186 #
1187
1188 group = CustomGroup(
1189 parser,
1190 'Remote Trybot Options (--remote)')
1191
1192 group.add_remote_option('--hwtest', dest='hwtest', action='store_true',
David Jameseecba232014-06-11 11:35:11 -07001193 default=False,
1194 help='Run the HWTest stage (tests on real hardware)')
Mike Frysinger81af6ef2013-04-03 02:24:09 -04001195 group.add_option('--remote-description', default=None,
David Jameseecba232014-06-11 11:35:11 -07001196 help=('Attach an optional description to a --remote run '
1197 'to make it easier to identify the results when it '
1198 'finishes'))
Mike Frysinger81af6ef2013-04-03 02:24:09 -04001199 group.add_option('--slaves', action='extend', default=[],
David Jameseecba232014-06-11 11:35:11 -07001200 help=('Specify specific remote tryslaves to run on (e.g. '
1201 'build149-m2); if the bot is busy, it will be queued'))
Don Garrett4bb21682014-03-03 16:16:23 -08001202 group.add_remote_option('--channel', dest='channels', action='extend',
1203 default=[],
David Jameseecba232014-06-11 11:35:11 -07001204 help=('Specify a channel for a payloads trybot. Can '
1205 'be specified multiple times. No valid for '
1206 'non-payloads configs.'))
Mike Frysinger81af6ef2013-04-03 02:24:09 -04001207 group.add_option('--test-tryjob', action='store_true',
1208 default=False,
David Jameseecba232014-06-11 11:35:11 -07001209 help=('Submit a tryjob to the test repository. Will not '
1210 'show up on the production trybot waterfall.'))
Mike Frysinger81af6ef2013-04-03 02:24:09 -04001211
1212 parser.add_option_group(group)
1213
1214 #
Ryan Cui88b901c2013-06-21 11:35:30 -07001215 # Branch creation options.
1216 #
1217
1218 group = CustomGroup(
1219 parser,
1220 'Branch Creation Options (used with branch-util)')
1221
1222 group.add_remote_option('--branch-name',
1223 help='The branch to create or delete.')
1224 group.add_remote_option('--delete-branch', default=False, action='store_true',
1225 help='Delete the branch specified in --branch-name.')
1226 group.add_remote_option('--rename-to', type='string',
1227 help='Rename a branch to the specified name.')
1228 group.add_remote_option('--force-create', default=False, action='store_true',
1229 help='Overwrites an existing branch.')
1230
1231 parser.add_option_group(group)
1232
1233 #
Mike Frysinger81af6ef2013-04-03 02:24:09 -04001234 # Advanced options.
Ryan Cuif4f84be2012-07-09 18:50:41 -07001235 #
1236
Ryan Cuieaa9efd2012-04-25 17:56:45 -07001237 group = CustomGroup(
Brian Harring3fec5a82012-03-01 05:57:03 -08001238 parser,
1239 'Advanced Options',
1240 'Caution: use these options at your own risk.')
1241
Mike Frysinger81af6ef2013-04-03 02:24:09 -04001242 group.add_remote_option('--bootstrap-args', action='append', default=[],
David Jameseecba232014-06-11 11:35:11 -07001243 help=('Args passed directly to the bootstrap re-exec '
1244 'to skip verification by the bootstrap code'))
Ryan Cuieaa9efd2012-04-25 17:56:45 -07001245 group.add_remote_option('--buildbot', dest='buildbot', action='store_true',
1246 default=False, help='This is running on a buildbot')
1247 group.add_remote_option('--buildnumber', help='build number', type='int',
1248 default=0)
Ryan Cui5ba7e152012-05-10 14:36:52 -07001249 group.add_option('--chrome_root', default=None, type='path',
1250 action='callback', callback=_CheckChromeRootOption,
1251 dest='chrome_root', help='Local checkout of Chrome to use.')
Ryan Cuieaa9efd2012-04-25 17:56:45 -07001252 group.add_remote_option('--chrome_version', default=None, type='string',
1253 action='callback', dest='chrome_version',
1254 callback=_CheckChromeVersionOption,
David Jameseecba232014-06-11 11:35:11 -07001255 help=('Used with SPEC logic to force a particular '
Stefan Zagerd49d9ff2014-08-15 21:33:37 -07001256 'git revision of chrome rather than the '
David Jameseecba232014-06-11 11:35:11 -07001257 'latest.'))
Ryan Cuieaa9efd2012-04-25 17:56:45 -07001258 group.add_remote_option('--clobber', action='store_true', dest='clobber',
1259 default=False,
1260 help='Clears an old checkout before syncing')
Mike Frysinger81af6ef2013-04-03 02:24:09 -04001261 group.add_remote_option('--latest-toolchain', action='store_true',
1262 default=False,
1263 help='Use the latest toolchain.')
Ryan Cui5ba7e152012-05-10 14:36:52 -07001264 parser.add_option('--log_dir', dest='log_dir', type='path',
Brian Harring3fec5a82012-03-01 05:57:03 -08001265 help=('Directory where logs are stored.'))
Ryan Cuieaa9efd2012-04-25 17:56:45 -07001266 group.add_remote_option('--maxarchives', dest='max_archive_builds',
1267 default=3, type='int',
David Jameseecba232014-06-11 11:35:11 -07001268 help='Change the local saved build count limit.')
Ryan Cuibbd3d4b2012-08-17 12:20:37 -07001269 parser.add_remote_option('--manifest-repo-url',
1270 help=('Overrides the default manifest repo url.'))
David James565bc9a2013-04-08 14:54:45 -07001271 group.add_remote_option('--compilecheck', action='store_true', default=False,
1272 help='Only verify compilation and unit tests.')
Ryan Cuieaa9efd2012-04-25 17:56:45 -07001273 group.add_remote_option('--noarchive', action='store_false', dest='archive',
1274 default=True, help="Don't run archive stage.")
Ryan Cuif7f24692012-05-18 16:35:33 -07001275 group.add_remote_option('--nobootstrap', action='store_false',
1276 dest='bootstrap', default=True,
David Jameseecba232014-06-11 11:35:11 -07001277 help=("Don't checkout and run from a standalone "
1278 'chromite repo.'))
Ryan Cuieaa9efd2012-04-25 17:56:45 -07001279 group.add_remote_option('--nobuild', action='store_false', dest='build',
1280 default=True,
1281 help="Don't actually build (for cbuildbot dev)")
1282 group.add_remote_option('--noclean', action='store_false', dest='clean',
1283 default=True, help="Don't clean the buildroot")
Ryan Cuif7f24692012-05-18 16:35:33 -07001284 group.add_remote_option('--nocgroups', action='store_false', dest='cgroups',
1285 default=True,
1286 help='Disable cbuildbots usage of cgroups.')
Ryan Cui3ea98e02013-08-07 16:01:48 -07001287 group.add_remote_option('--nochromesdk', action='store_false',
1288 dest='chrome_sdk', default=True,
David Jameseecba232014-06-11 11:35:11 -07001289 help=("Don't run the ChromeSDK stage which builds "
1290 'Chrome outside of the chroot.'))
Ryan Cuieaa9efd2012-04-25 17:56:45 -07001291 group.add_remote_option('--noprebuilts', action='store_false',
1292 dest='prebuilts', default=True,
1293 help="Don't upload prebuilts.")
Ryan Cui88b901c2013-06-21 11:35:30 -07001294 group.add_remote_option('--nopatch', action='store_false',
1295 dest='postsync_patch', default=True,
1296 help=("Don't run PatchChanges stage. This does not "
David Jameseecba232014-06-11 11:35:11 -07001297 'disable patching in of chromite patches '
1298 'during BootstrapStage.'))
Don Garrett82c0ae82014-02-03 18:25:11 -08001299 group.add_remote_option('--nopaygen', action='store_false',
1300 dest='paygen', default=True,
1301 help="Don't generate payloads.")
Ryan Cui88b901c2013-06-21 11:35:30 -07001302 group.add_remote_option('--noreexec', action='store_false',
1303 dest='postsync_reexec', default=True,
1304 help="Don't reexec into the buildroot after syncing.")
Mike Frysinger81af6ef2013-04-03 02:24:09 -04001305 group.add_remote_option('--nosdk', action='store_true',
1306 default=False,
1307 help='Re-create the SDK from scratch.')
Ryan Cuieaa9efd2012-04-25 17:56:45 -07001308 group.add_remote_option('--nosync', action='store_false', dest='sync',
1309 default=True, help="Don't sync before building.")
Ryan Cuieaa9efd2012-04-25 17:56:45 -07001310 group.add_remote_option('--notests', action='store_false', dest='tests',
1311 default=True,
David Jameseecba232014-06-11 11:35:11 -07001312 help=('Override values from buildconfig and run no '
1313 'tests.'))
Nam T. Nguyenc93f1342014-07-11 14:40:54 -07001314 group.add_remote_option('--noimagetests', action='store_false',
1315 dest='image_test', default=True,
1316 help=('Override values from buildconfig and run no '
1317 'image tests.'))
Ryan Cuieaa9efd2012-04-25 17:56:45 -07001318 group.add_remote_option('--nouprev', action='store_false', dest='uprev',
1319 default=True,
David Jameseecba232014-06-11 11:35:11 -07001320 help=('Override values from buildconfig and never '
1321 'uprev.'))
David Jamesdac7a912013-11-18 11:14:44 -08001322 group.add_option('--reference-repo', action='store', default=None,
1323 dest='reference_repo',
David Jameseecba232014-06-11 11:35:11 -07001324 help=('Reuse git data stored in an existing repo '
1325 'checkout. This can drastically reduce the network '
1326 'time spent setting up the trybot checkout. By '
1327 "default, if this option isn't given but cbuildbot "
1328 'is invoked from a repo checkout, cbuildbot will '
1329 'use the repo root.'))
Ryan Cuicedd8a52012-03-22 02:28:35 -07001330 group.add_option('--resume', action='store_true', default=False,
Ryan Cuieaa9efd2012-04-25 17:56:45 -07001331 help='Skip stages already successfully completed.')
1332 group.add_remote_option('--timeout', action='store', type='int', default=0,
David Jameseecba232014-06-11 11:35:11 -07001333 help=('Specify the maximum amount of time this job '
1334 'can run for, at which point the build will be '
1335 'aborted. If set to zero, then there is no '
1336 'timeout.'))
Ryan Cuieaa9efd2012-04-25 17:56:45 -07001337 group.add_remote_option('--version', dest='force_version', default=None,
David Jameseecba232014-06-11 11:35:11 -07001338 help=('Used with manifest logic. Forces use of this '
1339 'version rather than create or get latest. '
1340 'Examples: 4815.0.0-rc1, 4815.1.2'))
Mike Frysinger81af6ef2013-04-03 02:24:09 -04001341
1342 parser.add_option_group(group)
1343
1344 #
1345 # Internal options.
1346 #
1347
1348 group = CustomGroup(
1349 parser,
Mike Frysinger34db8692013-11-11 14:54:08 -05001350 'Internal Chromium OS Build Team Options',
1351 'Caution: these are for meant for the Chromium OS build team only')
Mike Frysinger81af6ef2013-04-03 02:24:09 -04001352
1353 group.add_remote_option('--archive-base', type='gs_path',
David Jameseecba232014-06-11 11:35:11 -07001354 help=('Base GS URL (gs://<bucket_name>/<path>) to '
1355 'upload archive artifacts to'))
1356 group.add_remote_option(
1357 '--cq-gerrit-query', dest='cq_gerrit_override', default=None,
1358 help=('If given, this gerrit query will be used to find what patches to '
1359 "test, rather than the normal 'CommitQueue>=1 AND Verified=1 AND "
1360 "CodeReview=2' query it defaults to. Use with care- note "
1361 'additionally this setting only has an effect if the buildbot '
1362 "target is a cq target, and we're in buildbot mode."))
Mike Frysinger81af6ef2013-04-03 02:24:09 -04001363 group.add_option('--pass-through', dest='pass_through_args', action='append',
1364 type='string', default=[])
David Jamesf421c6d2013-04-11 15:37:57 -07001365 group.add_remote_option('--pre-cq', action='store_true', default=False,
1366 help='Mark CLs as tested by the PreCQ on success.')
Mike Frysinger81af6ef2013-04-03 02:24:09 -04001367 group.add_option('--reexec-api-version', dest='output_api_version',
Ryan Cuif4f84be2012-07-09 18:50:41 -07001368 action='store_true', default=False,
David Jameseecba232014-06-11 11:35:11 -07001369 help=('Used for handling forwards/backwards compatibility '
1370 'with --resume and --bootstrap'))
Mike Frysinger81af6ef2013-04-03 02:24:09 -04001371 group.add_option('--remote-trybot', dest='remote_trybot',
1372 action='store_true', default=False,
1373 help='Indicates this is running on a remote trybot machine')
1374 group.add_remote_option('--remote-patches', action='extend', default=[],
David Jameseecba232014-06-11 11:35:11 -07001375 help=('Patches uploaded by the trybot client when '
1376 'run using the -p option'))
Brian Harringf611e6e2012-07-17 18:47:44 -07001377 # Note the default here needs to be hardcoded to 3; that is the last version
1378 # that lacked this functionality.
Mike Frysinger81af6ef2013-04-03 02:24:09 -04001379 group.add_option('--remote-version', default=3, type=int, action='store',
David Jameseecba232014-06-11 11:35:11 -07001380 help=('Used for compatibility checks w/tryjobs running in '
1381 'older chromite instances'))
Mike Frysinger81af6ef2013-04-03 02:24:09 -04001382 group.add_option('--sourceroot', type='path', default=constants.SOURCE_ROOT)
1383 group.add_remote_option('--test-bootstrap', action='store_true',
1384 default=False,
David Jameseecba232014-06-11 11:35:11 -07001385 help=('Causes cbuildbot to bootstrap itself twice, '
1386 'in the sequence A->B->C: A(unpatched) patches '
1387 'and bootstraps B; B patches and bootstraps C'))
Mike Frysinger81af6ef2013-04-03 02:24:09 -04001388 group.add_remote_option('--validation_pool', default=None,
David Jameseecba232014-06-11 11:35:11 -07001389 help=('Path to a pickled validation pool. Intended '
1390 'for use only with the commit queue.'))
Aviv Keshet007a24a2014-06-23 08:10:55 -07001391 group.add_remote_option('--metadata_dump', default=None,
Aviv Keshet669eb5e2014-06-23 08:53:01 -07001392 help=('Path to a json dumped metadata file. This '
1393 'will be used as the initial metadata.'))
Aviv Keshetacf4cfb2014-07-30 12:31:22 -07001394 group.add_remote_option('--master-build-id', default=None, type=int,
1395 api=constants.REEXEC_API_MASTER_BUILD_ID,
1396 help=('cidb build id of the master build to this '
1397 'slave build.'))
Aviv Kesheta0159be2013-12-12 13:56:28 -08001398 group.add_remote_option('--mock-tree-status', dest='mock_tree_status',
1399 default=None, action='store',
David Jameseecba232014-06-11 11:35:11 -07001400 help=('Override the tree status value that would be '
1401 'returned from the the actual tree. Example '
1402 'values: open, closed, throttled. When used '
1403 'in conjunction with --debug, the tree status '
1404 'will not be ignored as it usually is in a '
1405 '--debug run.'))
1406 group.add_remote_option(
1407 '--mock-slave-status', dest='mock_slave_status', default=None,
1408 action='store', metavar='MOCK_SLAVE_STATUS_PICKLE_FILE',
1409 help=('Override the result of the _FetchSlaveStatuses method of '
1410 'MasterSlaveSyncCompletionStage, by specifying a file with a '
1411 'pickle of the result to be returned.'))
Mike Frysinger81af6ef2013-04-03 02:24:09 -04001412
1413 parser.add_option_group(group)
Ryan Cuif4f84be2012-07-09 18:50:41 -07001414
1415 #
Brian Harring3fec5a82012-03-01 05:57:03 -08001416 # Debug options
Ryan Cuif4f84be2012-07-09 18:50:41 -07001417 #
Brian Harringfec89fe2012-09-23 07:30:54 -07001418 # Temporary hack; in place till --dry-run replaces --debug.
1419 # pylint: disable=W0212
Brian Harring009db502012-10-10 02:21:37 -07001420 group = parser.debug_group
Brian Harringfec89fe2012-09-23 07:30:54 -07001421 debug = [x for x in group.option_list if x._long_opts == ['--debug']][0]
David Jameseecba232014-06-11 11:35:11 -07001422 debug.help += ' Currently functions as --dry-run in addition.'
Brian Harringfec89fe2012-09-23 07:30:54 -07001423 debug.pass_through = True
Brian Harring3fec5a82012-03-01 05:57:03 -08001424 group.add_option('--notee', action='store_false', dest='tee', default=True,
David Jameseecba232014-06-11 11:35:11 -07001425 help=('Disable logging and internal tee process. Primarily '
1426 'used for debugging cbuildbot itself.'))
Brian Harring3fec5a82012-03-01 05:57:03 -08001427 return parser
1428
1429
Ryan Cui85867972012-02-23 18:21:49 -08001430def _FinishParsing(options, args):
1431 """Perform some parsing tasks that need to take place after optparse.
1432
1433 This function needs to be easily testable! Keep it free of
1434 environment-dependent code. Put more detailed usage validation in
1435 _PostParseCheck().
Brian Harring3fec5a82012-03-01 05:57:03 -08001436
1437 Args:
Matt Tennant759e2352013-09-27 15:14:44 -07001438 options: The options object returned by optparse
1439 args: The args object returned by optparse
Brian Harring3fec5a82012-03-01 05:57:03 -08001440 """
Ryan Cui41023d92012-11-13 19:59:50 -08001441 # Populate options.pass_through_args.
1442 accepted, _ = commandline.FilteringParser.FilterArgs(
1443 options.parsed_args, lambda x: x.opt_inst.pass_through)
1444 options.pass_through_args.extend(accepted)
Brian Harring07039b52012-05-13 17:56:47 -07001445
Brian Harring3fec5a82012-03-01 05:57:03 -08001446 if options.chrome_root:
1447 if options.chrome_rev != constants.CHROME_REV_LOCAL:
Brian Harring1b8c4c82012-05-29 23:03:04 -07001448 cros_build_lib.Die('Chrome rev must be %s if chrome_root is set.' %
1449 constants.CHROME_REV_LOCAL)
David Jamesa0a664e2013-02-13 09:52:01 -08001450 elif options.chrome_rev == constants.CHROME_REV_LOCAL:
1451 cros_build_lib.Die('Chrome root must be set if chrome_rev is %s.' %
1452 constants.CHROME_REV_LOCAL)
Brian Harring3fec5a82012-03-01 05:57:03 -08001453
1454 if options.chrome_version:
1455 if options.chrome_rev != constants.CHROME_REV_SPEC:
Brian Harring1b8c4c82012-05-29 23:03:04 -07001456 cros_build_lib.Die('Chrome rev must be %s if chrome_version is set.' %
1457 constants.CHROME_REV_SPEC)
David Jamesa0a664e2013-02-13 09:52:01 -08001458 elif options.chrome_rev == constants.CHROME_REV_SPEC:
1459 cros_build_lib.Die(
1460 'Chrome rev must not be %s if chrome_version is not set.'
1461 % constants.CHROME_REV_SPEC)
Brian Harring3fec5a82012-03-01 05:57:03 -08001462
David James9e27e662013-02-14 13:42:43 -08001463 patches = bool(options.gerrit_patches or options.local_patches or
1464 options.rietveld_patches)
Ryan Cuieaa9efd2012-04-25 17:56:45 -07001465 if options.remote:
1466 if options.local:
Brian Harring1b8c4c82012-05-29 23:03:04 -07001467 cros_build_lib.Die('Cannot specify both --remote and --local')
Ryan Cui54da0702012-04-19 18:38:08 -07001468
Don Garrett5af1d262014-05-16 15:49:37 -07001469 # options.channels is a convenient way to detect payloads builds.
1470 if not options.buildbot and not options.channels and not patches:
Gaurav Shahed0399e2014-02-03 13:36:22 -08001471 prompt = ('No patches were provided; are you sure you want to just '
1472 'run a remote build of %s?' % (
1473 options.branch if options.branch else 'ToT'))
1474 if not cros_build_lib.BooleanPrompt(prompt=prompt, default=False):
Brian Harring7cc4b932012-11-01 16:58:55 -07001475 cros_build_lib.Die('Must provide patches when running with --remote.')
Brian Harring3fec5a82012-03-01 05:57:03 -08001476
Ryan Cuieaa9efd2012-04-25 17:56:45 -07001477 # --debug needs to be explicitly passed through for remote invocations.
1478 release_mode_with_patches = (options.buildbot and patches and
1479 '--debug' not in options.pass_through_args)
1480 else:
1481 if len(args) > 1:
Brian Harring1b8c4c82012-05-29 23:03:04 -07001482 cros_build_lib.Die('Multiple configs not supported if not running with '
Brian Harringf1aad832012-07-18 10:46:39 -07001483 '--remote. Got %r', args)
Ryan Cuieaa9efd2012-04-25 17:56:45 -07001484
Ryan Cui79319ab2012-05-21 12:59:18 -07001485 if options.slaves:
Brian Harring1b8c4c82012-05-29 23:03:04 -07001486 cros_build_lib.Die('Cannot use --slaves if not running with --remote.')
Ryan Cui79319ab2012-05-21 12:59:18 -07001487
Ryan Cuieaa9efd2012-04-25 17:56:45 -07001488 release_mode_with_patches = (options.buildbot and patches and
1489 not options.debug)
1490
David James5734ea32012-08-15 20:23:49 -07001491 # When running in release mode, make sure we are running with checked-in code.
1492 # We want checked-in cbuildbot/scripts to prevent errors, and we want to build
1493 # a release image with checked-in code for CrOS packages.
1494 if release_mode_with_patches:
1495 cros_build_lib.Die(
1496 'Cannot provide patches when running with --buildbot!')
1497
Ryan Cuiba41ad32012-03-08 17:15:29 -08001498 if options.buildbot and options.remote_trybot:
Brian Harring1b8c4c82012-05-29 23:03:04 -07001499 cros_build_lib.Die(
1500 '--buildbot and --remote-trybot cannot be used together.')
Ryan Cuiba41ad32012-03-08 17:15:29 -08001501
Ryan Cui85867972012-02-23 18:21:49 -08001502 # Record whether --debug was set explicitly vs. it was inferred.
1503 options.debug_forced = False
1504 if options.debug:
1505 options.debug_forced = True
Ryan Cui88b901c2013-06-21 11:35:30 -07001506 if not options.debug:
Ryan Cui16ca5812012-03-08 20:34:27 -08001507 # We don't set debug by default for
1508 # 1. --buildbot invocations.
1509 # 2. --remote invocations, because it needs to push changes to the tryjob
1510 # repo.
1511 options.debug = not options.buildbot and not options.remote
Brian Harring3fec5a82012-03-01 05:57:03 -08001512
Ryan Cui1c13a252012-10-16 15:00:16 -07001513 # Record the configs targeted.
1514 options.build_targets = args[:]
1515
Ryan Cui88b901c2013-06-21 11:35:30 -07001516 if constants.BRANCH_UTIL_CONFIG in options.build_targets:
Ryan Cui7bd8db62013-08-08 16:29:51 -07001517 if options.remote:
1518 cros_build_lib.Die(
Matt Tennanta130ea32013-12-19 09:38:39 -08001519 'Running %s as a remote tryjob is not yet supported.',
1520 constants.BRANCH_UTIL_CONFIG)
Ryan Cui88b901c2013-06-21 11:35:30 -07001521 if len(options.build_targets) > 1:
1522 cros_build_lib.Die(
Matt Tennanta130ea32013-12-19 09:38:39 -08001523 'Cannot run %s with any other configs.',
1524 constants.BRANCH_UTIL_CONFIG)
Ryan Cui88b901c2013-06-21 11:35:30 -07001525 if not options.branch_name:
1526 cros_build_lib.Die(
Matt Tennanta130ea32013-12-19 09:38:39 -08001527 'Must specify --branch-name with the %s config.',
1528 constants.BRANCH_UTIL_CONFIG)
1529 if options.branch and options.branch != options.branch_name:
Ryan Cui88b901c2013-06-21 11:35:30 -07001530 cros_build_lib.Die(
Matt Tennanta130ea32013-12-19 09:38:39 -08001531 'If --branch is specified with the %s config, it must'
1532 ' have the same value as --branch-name.',
1533 constants.BRANCH_UTIL_CONFIG)
1534
1535 exclusive_opts = {'--version': options.force_version,
1536 '--delete-branch': options.delete_branch,
David Jameseecba232014-06-11 11:35:11 -07001537 '--rename-to': options.rename_to}
Matt Tennanta130ea32013-12-19 09:38:39 -08001538 if 1 != sum(1 for x in exclusive_opts.values() if x):
1539 cros_build_lib.Die('When using the %s config, you must'
1540 ' specifiy one and only one of the following'
1541 ' options: %s.', constants.BRANCH_UTIL_CONFIG,
1542 ', '.join(exclusive_opts.keys()))
1543
1544 # When deleting or renaming a branch, the --branch and --nobootstrap
1545 # options are implied.
1546 if options.delete_branch or options.rename_to:
1547 if not options.branch:
1548 cros_build_lib.Info('Automatically enabling sync to branch %s'
1549 ' for this %s flow.', options.branch_name,
1550 constants.BRANCH_UTIL_CONFIG)
1551 options.branch = options.branch_name
1552 if options.bootstrap:
1553 cros_build_lib.Info('Automatically disabling bootstrap step for'
1554 ' this %s flow.', constants.BRANCH_UTIL_CONFIG)
1555 options.bootstrap = False
1556
Ryan Cui88b901c2013-06-21 11:35:30 -07001557 elif any([options.delete_branch, options.rename_to, options.branch_name]):
1558 cros_build_lib.Die(
1559 'Cannot specify --delete-branch, --rename-to or --branch-name when not '
1560 'running the %s config', constants.BRANCH_UTIL_CONFIG)
1561
Brian Harring3fec5a82012-03-01 05:57:03 -08001562
Brian Harring1d7ba942012-04-24 06:37:18 -07001563# pylint: disable=W0613
Brian Harringae0a5322012-09-15 01:46:51 -07001564def _PostParseCheck(parser, options, args):
Ryan Cui85867972012-02-23 18:21:49 -08001565 """Perform some usage validation after we've parsed the arguments
Brian Harring3fec5a82012-03-01 05:57:03 -08001566
Ryan Cui85867972012-02-23 18:21:49 -08001567 Args:
Aviv Keshet9e4236b2013-12-13 13:07:50 -08001568 parser: Option parser that was used to parse arguments.
1569 options: The options returned by optparse.
1570 args: The args returned by optparse.
Ryan Cui85867972012-02-23 18:21:49 -08001571 """
Ryan Cuie1e4e662012-05-21 16:39:46 -07001572 if not options.branch:
David James97d95872012-11-16 15:09:56 -08001573 options.branch = git.GetChromiteTrackingBranch()
Ryan Cuie1e4e662012-05-21 16:39:46 -07001574
Brian Harringae0a5322012-09-15 01:46:51 -07001575 if not repository.IsARepoRoot(options.sourceroot):
1576 if options.local_patches:
1577 raise Exception('Could not find repo checkout at %s!'
1578 % options.sourceroot)
1579
David Jamesac8c2a72013-02-13 18:44:33 -08001580 # Because the default cache dir depends on other options, FindCacheDir
1581 # always returns None, and we setup the default here.
Brian Harringae0a5322012-09-15 01:46:51 -07001582 if options.cache_dir is None:
1583 # Note, options.sourceroot is set regardless of the path
1584 # actually existing.
David Jamesac8c2a72013-02-13 18:44:33 -08001585 if options.buildroot is not None:
Brian Harringae0a5322012-09-15 01:46:51 -07001586 options.cache_dir = os.path.join(options.buildroot, '.cache')
David Jamesac8c2a72013-02-13 18:44:33 -08001587 elif os.path.exists(options.sourceroot):
1588 options.cache_dir = os.path.join(options.sourceroot, '.cache')
Brian Harringae0a5322012-09-15 01:46:51 -07001589 else:
1590 options.cache_dir = parser.FindCacheDir(parser, options)
1591 options.cache_dir = os.path.abspath(options.cache_dir)
Brian Harring8c1d7b12012-10-04 17:36:32 -07001592 parser.ConfigureCacheDir(options.cache_dir)
Brian Harringae0a5322012-09-15 01:46:51 -07001593
Yu-Ju Hong2c066762013-10-28 14:05:08 -07001594 osutils.SafeMakedirsNonRoot(options.cache_dir)
Ryan Cui5ba7e152012-05-10 14:36:52 -07001595
Brian Harring609dc4e2012-05-07 02:17:44 -07001596 if options.local_patches:
Brian Harring1d7ba942012-04-24 06:37:18 -07001597 options.local_patches = _CheckLocalPatches(
Brian Harring609dc4e2012-05-07 02:17:44 -07001598 options.sourceroot, options.local_patches)
Brian Harring1d7ba942012-04-24 06:37:18 -07001599
1600 default = os.environ.get('CBUILDBOT_DEFAULT_MODE')
1601 if (default and not any([options.local, options.buildbot,
1602 options.remote, options.remote_trybot])):
David Jameseecba232014-06-11 11:35:11 -07001603 cros_build_lib.Info('CBUILDBOT_DEFAULT_MODE=%s env var detected, using it.'
Brian Harring1b8c4c82012-05-29 23:03:04 -07001604 % default)
Brian Harring1d7ba942012-04-24 06:37:18 -07001605 default = default.lower()
1606 if default == 'local':
1607 options.local = True
1608 elif default == 'remote':
1609 options.remote = True
1610 elif default == 'buildbot':
1611 options.buildbot = True
1612 else:
Brian Harring1b8c4c82012-05-29 23:03:04 -07001613 cros_build_lib.Die("CBUILDBOT_DEFAULT_MODE value %s isn't supported. "
1614 % default)
Ryan Cui85867972012-02-23 18:21:49 -08001615
Matt Tennant763497d2014-01-17 16:45:54 -08001616 # Ensure that all args are legitimate config targets.
Chris Sosa55cdc942014-04-16 13:08:37 -07001617 invalid_targets = []
Matt Tennant763497d2014-01-17 16:45:54 -08001618 for arg in args:
Matt Tennant2c192032014-01-16 13:49:28 -08001619 build_config = _GetConfig(arg)
Don Garrett4bb21682014-03-03 16:16:23 -08001620
Matt Tennant2c192032014-01-16 13:49:28 -08001621 if not build_config:
Chris Sosa55cdc942014-04-16 13:08:37 -07001622 invalid_targets.append(arg)
Matt Tennant763497d2014-01-17 16:45:54 -08001623 cros_build_lib.Error('No such configuraton target: "%s".', arg)
Don Garrett4bb21682014-03-03 16:16:23 -08001624 continue
1625
Don Garrett5af1d262014-05-16 15:49:37 -07001626 is_payloads_build = build_config.build_type == constants.PAYLOADS_TYPE
1627
1628 if options.channels and not is_payloads_build:
Don Garrett4bb21682014-03-03 16:16:23 -08001629 cros_build_lib.Die('--channel must only be used with a payload config,'
1630 ' not target (%s).' % arg)
Matt Tennant763497d2014-01-17 16:45:54 -08001631
Don Garrett5af1d262014-05-16 15:49:37 -07001632 if not options.channels and is_payloads_build:
1633 cros_build_lib.Die('payload configs (%s) require --channel to do anything'
1634 ' useful.' % arg)
1635
Matt Tennant2c192032014-01-16 13:49:28 -08001636 # The --version option is not compatible with an external target unless the
1637 # --buildbot option is specified. More correctly, only "paladin versions"
1638 # will work with external targets, and those are only used with --buildbot.
1639 # If --buildbot is specified, then user should know what they are doing and
1640 # only specify a version that will work. See crbug.com/311648.
Don Garrett4bb21682014-03-03 16:16:23 -08001641 if (options.force_version and
1642 not (options.buildbot or build_config.internal)):
1643 cros_build_lib.Die('Cannot specify --version without --buildbot for an'
1644 ' external target (%s).' % arg)
Matt Tennant2c192032014-01-16 13:49:28 -08001645
Chris Sosa55cdc942014-04-16 13:08:37 -07001646 if invalid_targets:
1647 cros_build_lib.Die('One or more invalid configuration targets specified. '
1648 'You can check the available configs by running '
1649 '`cbuildbot --list --all`')
Matt Tennant763497d2014-01-17 16:45:54 -08001650
Ryan Cui85867972012-02-23 18:21:49 -08001651
1652def _ParseCommandLine(parser, argv):
1653 """Completely parse the commandline arguments"""
Brian Harring3fec5a82012-03-01 05:57:03 -08001654 (options, args) = parser.parse_args(argv)
Brian Harring37e559b2012-05-22 20:47:32 -07001655
Matt Tennant763497d2014-01-17 16:45:54 -08001656 # Strip out null arguments.
1657 # TODO(rcui): Remove when buildbot is fixed
1658 args = [arg for arg in args if arg]
1659
1660 # A couple options, like --list, trigger a quick exit.
Brian Harring37e559b2012-05-22 20:47:32 -07001661 if options.output_api_version:
Mike Frysinger383367e2014-09-16 15:06:17 -04001662 print(constants.REEXEC_API_VERSION)
Brian Harring37e559b2012-05-22 20:47:32 -07001663 sys.exit(0)
1664
Ryan Cui54da0702012-04-19 18:38:08 -07001665 if options.list:
Matt Tennant763497d2014-01-17 16:45:54 -08001666 if args:
1667 cros_build_lib.Die('No arguments expected with the --list options.')
Ryan Cui54da0702012-04-19 18:38:08 -07001668 _PrintValidConfigs(options.print_all)
1669 sys.exit(0)
1670
Ryan Cui8be16062012-04-24 12:05:26 -07001671 if not args:
Matt Tennant763497d2014-01-17 16:45:54 -08001672 parser.error('Invalid usage: no configuration targets provided.'
1673 'Use -h to see usage. Use -l to list supported configs.')
Ryan Cui8be16062012-04-24 12:05:26 -07001674
Ryan Cui85867972012-02-23 18:21:49 -08001675 _FinishParsing(options, args)
1676 return options, args
1677
1678
Aviv Keshet64133022014-08-25 15:50:52 -07001679def _SetupCidb(options, build_config):
Aviv Keshet2982af52014-08-13 16:07:57 -07001680 """Set up CIDB the appropriate Setup call.
1681
1682 Args:
1683 options: Command line options structure.
Aviv Keshet64133022014-08-25 15:50:52 -07001684 build_config: Config object for this build.
Aviv Keshet2982af52014-08-13 16:07:57 -07001685 """
Aviv Keshet62d1a0e2014-08-22 21:16:13 -07001686 # TODO(akeshet): This is a temporary workaround to make sure that the cidb
1687 # is not used on waterfalls that the db schema does not support (in particular
1688 # the chromeos.chrome waterfall).
Aviv Keshet64133022014-08-25 15:50:52 -07001689 # See crbug.com/406940
Aviv Keshet62d1a0e2014-08-22 21:16:13 -07001690 waterfall = os.environ.get('BUILDBOT_MASTERNAME', '')
Aviv Keshet3e1efcd2014-09-23 12:05:54 -07001691 if not waterfall in constants.CIDB_KNOWN_WATERFALLS:
Aviv Keshet62d1a0e2014-08-22 21:16:13 -07001692 cidb.CIDBConnectionFactory.SetupNoCidb()
1693 return
1694
Aviv Keshet64133022014-08-25 15:50:52 -07001695 # TODO(akeshet): Clean up this code once we have better defined flags to
1696 # specify on-or-off waterfall and on-or-off production runs of cbuildbot.
1697 # See crbug.com/331417
1698
1699 # --buildbot runs should use the production database, unless the --debug flag
1700 # is also present in which case they should use the debug database.
1701 if options.buildbot:
1702 if options.debug:
1703 cidb.CIDBConnectionFactory.SetupDebugCidb()
1704 return
1705 else:
1706 cidb.CIDBConnectionFactory.SetupProdCidb()
1707 return
1708
1709 # --remote-trybot runs should use the debug database. With the exception of
1710 # pre-cq builds, which should use the production database.
1711 if options.remote_trybot:
1712 if build_config['pre_cq']:
1713 cidb.CIDBConnectionFactory.SetupProdCidb()
1714 return
1715 else:
1716 cidb.CIDBConnectionFactory.SetupDebugCidb()
1717 return
1718
1719 # If neither --buildbot nor --remote-trybot flag was used, don't use the
1720 # database.
1721 cidb.CIDBConnectionFactory.SetupNoCidb()
Aviv Keshet2982af52014-08-13 16:07:57 -07001722
1723
Matt Tennant759e2352013-09-27 15:14:44 -07001724# TODO(build): This function is too damn long.
Ryan Cui85867972012-02-23 18:21:49 -08001725def main(argv):
David James59a0a2b2013-03-22 14:04:44 -07001726 # Turn on strict sudo checks.
1727 cros_build_lib.STRICT_SUDO = True
1728
Ryan Cui85867972012-02-23 18:21:49 -08001729 # Set umask to 022 so files created by buildbot are readable.
Mike Frysinger60ec1012013-10-21 00:11:10 -04001730 os.umask(0o22)
Ryan Cui85867972012-02-23 18:21:49 -08001731
Ryan Cui85867972012-02-23 18:21:49 -08001732 parser = _CreateParser()
1733 (options, args) = _ParseCommandLine(parser, argv)
Brian Harring3fec5a82012-03-01 05:57:03 -08001734
Brian Harringae0a5322012-09-15 01:46:51 -07001735 _PostParseCheck(parser, options, args)
Brian Harring3fec5a82012-03-01 05:57:03 -08001736
Mike Frysinger8fd67dc2012-12-03 23:51:18 -05001737 cros_build_lib.AssertOutsideChroot()
Zdenek Behan98ec2fb2012-08-31 17:12:18 +02001738
Brian Harring3fec5a82012-03-01 05:57:03 -08001739 if options.remote:
Brian Harring1b8c4c82012-05-29 23:03:04 -07001740 cros_build_lib.logger.setLevel(logging.WARNING)
Ryan Cui16ca5812012-03-08 20:34:27 -08001741
Brian Harring3fec5a82012-03-01 05:57:03 -08001742 # Verify configs are valid.
Dan Shi0bdb7132013-07-30 16:22:12 -07001743 # If hwtest flag is enabled, post a warning that HWTest step may fail if the
1744 # specified board is not a released platform or it is a generic overlay.
Brian Harring3fec5a82012-03-01 05:57:03 -08001745 for bot in args:
Aviv Kesheta96a2a92013-02-05 17:21:51 -08001746 build_config = _GetConfig(bot)
1747 if options.hwtest:
Dan Shi0bdb7132013-07-30 16:22:12 -07001748 cros_build_lib.Warning(
1749 'If %s is not a released platform or it is a generic overlay, '
1750 'the HWTest step will most likely not run; please ask the lab '
1751 'team for help if this is unexpected.' % build_config['boards'])
Brian Harring3fec5a82012-03-01 05:57:03 -08001752
1753 # Verify gerrit patches are valid.
Mike Frysinger383367e2014-09-16 15:06:17 -04001754 print('Verifying patches...')
Ryan Cuie1e4e662012-05-21 16:39:46 -07001755 patch_pool = AcquirePoolFromOptions(options)
Ryan Cui16d9e1f2012-05-11 10:50:18 -07001756
Ryan Cuieaa9efd2012-04-25 17:56:45 -07001757 # --debug need to be explicitly passed through for remote invocations.
1758 if options.buildbot and '--debug' not in options.pass_through_args:
1759 _ConfirmRemoteBuildbotRun()
1760
Mike Frysinger383367e2014-09-16 15:06:17 -04001761 print('Submitting tryjob...')
Ryan Cui16d9e1f2012-05-11 10:50:18 -07001762 tryjob = remote_try.RemoteTryJob(options, args, patch_pool.local_patches)
Ryan Cuia25d8eb2012-07-11 14:54:27 -07001763 tryjob.Submit(testjob=options.test_tryjob, dryrun=False)
Mike Frysinger383367e2014-09-16 15:06:17 -04001764 print('Tryjob submitted!')
1765 print(('Go to %s to view the status of your job.'
1766 % tryjob.GetTrybotWaterfallLink()))
Brian Harring3fec5a82012-03-01 05:57:03 -08001767 sys.exit(0)
Matt Tennant759e2352013-09-27 15:14:44 -07001768
Ryan Cui54da0702012-04-19 18:38:08 -07001769 elif (not options.buildbot and not options.remote_trybot
1770 and not options.resume and not options.local):
Mike Frysinger5672a2a2014-05-31 22:29:57 -04001771 cros_build_lib.Die('Please use --remote or --local to run trybots')
Brian Harring3fec5a82012-03-01 05:57:03 -08001772
Matt Tennant759e2352013-09-27 15:14:44 -07001773 # Only one config arg is allowed in this mode, which was confirmed earlier.
Ryan Cui8be16062012-04-24 12:05:26 -07001774 bot_id = args[-1]
1775 build_config = _GetConfig(bot_id)
Brian Harring3fec5a82012-03-01 05:57:03 -08001776
Don Garrettbbd7b552014-05-16 13:15:21 -07001777 # TODO: Re-enable this block when reference_repo support handles this
1778 # properly. (see chromium:330775)
1779 # if options.reference_repo is None:
1780 # repo_path = os.path.join(options.sourceroot, '.repo')
1781 # # If we're being run from a repo checkout, reuse the repo's git pool to
1782 # # cut down on sync time.
1783 # if os.path.exists(repo_path):
1784 # options.reference_repo = options.sourceroot
1785
1786 if options.reference_repo:
David Jamesdac7a912013-11-18 11:14:44 -08001787 if not os.path.exists(options.reference_repo):
1788 parser.error('Reference path %s does not exist'
1789 % (options.reference_repo,))
1790 elif not os.path.exists(os.path.join(options.reference_repo, '.repo')):
1791 parser.error('Reference path %s does not look to be the base of a '
1792 'repo checkout; no .repo exists in the root.'
1793 % (options.reference_repo,))
1794
Brian Harringf11bf682012-05-14 15:53:43 -07001795 if (options.buildbot or options.remote_trybot) and not options.resume:
Brian Harring470f6112012-03-02 11:47:10 -08001796 if not options.cgroups:
Ryan Cuid4a24212012-04-04 18:08:12 -07001797 parser.error('Options --buildbot/--remote-trybot and --nocgroups cannot '
1798 'be used together. Cgroup support is required for '
1799 'buildbot/remote-trybot mode.')
Mike Frysingera78a56e2012-11-20 06:02:30 -05001800 if not cgroups.Cgroup.IsSupported():
Ryan Cuid4a24212012-04-04 18:08:12 -07001801 parser.error('Option --buildbot/--remote-trybot was given, but this '
1802 'system does not support cgroups. Failing.')
Brian Harring3fec5a82012-03-01 05:57:03 -08001803
David Jamesaad5cc72012-10-26 15:03:13 -07001804 missing = osutils.FindMissingBinaries(_BUILDBOT_REQUIRED_BINARIES)
Brian Harring351ce442012-03-09 16:38:14 -08001805 if missing:
David Jameseecba232014-06-11 11:35:11 -07001806 parser.error('Option --buildbot/--remote-trybot requires the following '
Ryan Cuid4a24212012-04-04 18:08:12 -07001807 "binaries which couldn't be found in $PATH: %s"
Brian Harring351ce442012-03-09 16:38:14 -08001808 % (', '.join(missing)))
1809
David Jamesdac7a912013-11-18 11:14:44 -08001810 if options.reference_repo:
1811 options.reference_repo = os.path.abspath(options.reference_repo)
1812
Brian Harring3fec5a82012-03-01 05:57:03 -08001813 if not options.buildroot:
1814 if options.buildbot:
Gaurav Shah59abcb52014-12-09 15:27:11 -08001815 parser.error('Please specify a buildroot with the --buildroot option.')
Matt Tennantd55b1f42012-04-13 14:15:01 -07001816
Ryan Cui5ba7e152012-05-10 14:36:52 -07001817 options.buildroot = _DetermineDefaultBuildRoot(options.sourceroot,
1818 build_config['internal'])
Brian Harring470f6112012-03-02 11:47:10 -08001819 # We use a marker file in the buildroot to indicate the user has
1820 # consented to using this directory.
1821 if not os.path.exists(repository.GetTrybotMarkerPath(options.buildroot)):
1822 _ConfirmBuildRoot(options.buildroot)
Brian Harring3fec5a82012-03-01 05:57:03 -08001823
1824 # Sanity check of buildroot- specifically that it's not pointing into the
1825 # midst of an existing repo since git-repo doesn't support nesting.
Brian Harring3fec5a82012-03-01 05:57:03 -08001826 if (not repository.IsARepoRoot(options.buildroot) and
David James13a69c92013-05-09 10:37:42 -07001827 git.FindRepoDir(options.buildroot)):
Brian Harring3fec5a82012-03-01 05:57:03 -08001828 parser.error('Configured buildroot %s points into a repository checkout, '
1829 'rather than the root of it. This is not supported.'
1830 % options.buildroot)
1831
Chris Sosab5ea3b42012-10-25 15:25:20 -07001832 if not options.log_dir:
1833 options.log_dir = os.path.join(options.buildroot, _DEFAULT_LOG_DIR)
1834
Brian Harringd166aaf2012-05-14 18:31:53 -07001835 log_file = None
1836 if options.tee:
Chris Sosab5ea3b42012-10-25 15:25:20 -07001837 log_file = os.path.join(options.log_dir, _BUILDBOT_LOG_FILE)
1838 osutils.SafeMakedirs(options.log_dir)
Brian Harringd166aaf2012-05-14 18:31:53 -07001839 _BackupPreviousLog(log_file)
1840
Brian Harring1b8c4c82012-05-29 23:03:04 -07001841 with cros_build_lib.ContextManagerStack() as stack:
Aaron Gable881fccb2013-09-27 18:35:24 -07001842 # TODO(ferringb): update this once
1843 # https://chromium-review.googlesource.com/25359
David Jamescebc7272013-07-17 16:45:05 -07001844 # is landed- it's sensitive to the manifest-versions cache path.
1845 options.preserve_paths = set(['manifest-versions', '.cache',
Simran Basi47eaa5e2015-01-08 14:38:27 -08001846 'manifest-versions-internal',
1847 'chromite-bootstrap'])
David Jamescebc7272013-07-17 16:45:05 -07001848 if log_file is not None:
1849 # We don't want the critical section to try to clean up the tee process,
1850 # so we run Tee (forked off) outside of it. This prevents a deadlock
1851 # because the Tee process only exits when its pipe is closed, and the
1852 # critical section accidentally holds on to that file handle.
1853 stack.Add(tee.Tee, log_file)
1854 options.preserve_paths.add(_DEFAULT_LOG_DIR)
1855
Brian Harringc2d09d92012-05-13 22:03:15 -07001856 critical_section = stack.Add(cleanup.EnforcedCleanupSection)
1857 stack.Add(sudo.SudoKeepAlive)
Brian Harringd166aaf2012-05-14 18:31:53 -07001858
Brian Harringc2d09d92012-05-13 22:03:15 -07001859 if not options.resume:
Brian Harring2bf55e12012-05-13 21:31:55 -07001860 # If we're in resume mode, use our parents tempdir rather than
1861 # nesting another layer.
David James4bc13702013-03-26 08:08:04 -07001862 stack.Add(osutils.TempDir, prefix='cbuildbot-tmp', set_global=True)
David Jameseecba232014-06-11 11:35:11 -07001863 logging.debug('Cbuildbot tempdir is %r.', os.environ.get('TMP'))
Brian Harringd166aaf2012-05-14 18:31:53 -07001864
Brian Harringc2d09d92012-05-13 22:03:15 -07001865 if options.cgroups:
1866 stack.Add(cgroups.SimpleContainChildren, 'cbuildbot')
Brian Harringa184efa2012-03-04 11:51:25 -08001867
Brian Harringc2d09d92012-05-13 22:03:15 -07001868 # Mark everything between EnforcedCleanupSection and here as having to
1869 # be rolled back via the contextmanager cleanup handlers. This
1870 # ensures that sudo bits cannot outlive cbuildbot, that anything
1871 # cgroups would kill gets killed, etc.
David Jamesfb3aac92013-10-16 13:26:52 -07001872 stack.Add(critical_section.ForkWatchdog)
Brian Harringd166aaf2012-05-14 18:31:53 -07001873
Brian Harringc2d09d92012-05-13 22:03:15 -07001874 if not options.buildbot:
1875 build_config = cbuildbot_config.OverrideConfigForTrybot(
Don Garrett4bb21682014-03-03 16:16:23 -08001876 build_config, options)
Brian Harringc2d09d92012-05-13 22:03:15 -07001877
Aviv Kesheta0159be2013-12-12 13:56:28 -08001878 if options.mock_tree_status is not None:
Prathmesh Prabhud51d7502014-12-21 01:42:55 -08001879 stack.Add(mock.patch.object, tree_status, '_GetStatus',
Aviv Kesheta0159be2013-12-12 13:56:28 -08001880 return_value=options.mock_tree_status)
1881
Aviv Keshetcf9c2722014-02-25 15:15:10 -08001882 if options.mock_slave_status is not None:
1883 with open(options.mock_slave_status, 'r') as f:
Aviv Keshet4e750022014-03-07 16:50:34 -08001884 mock_statuses = pickle.load(f)
1885 for key, value in mock_statuses.iteritems():
1886 mock_statuses[key] = manifest_version.BuilderStatus(**value)
Yu-Ju Hongd0fda382014-05-09 15:28:24 -07001887 stack.Add(mock.patch.object,
1888 completion_stages.MasterSlaveSyncCompletionStage,
1889 '_FetchSlaveStatuses',
1890 return_value=mock_statuses)
Aviv Keshetcf9c2722014-02-25 15:15:10 -08001891
Aviv Keshet64133022014-08-25 15:50:52 -07001892 _SetupCidb(options, build_config)
Don Garrettb4318362014-10-03 15:49:36 -07001893 retry_stats.SetupStats()
Aviv Keshet2982af52014-08-13 16:07:57 -07001894
Prathmesh Prabhu80e05df2014-12-11 15:20:33 -08001895 # For master-slave builds: Update slave's timeout using master's published
1896 # deadline.
1897 if options.buildbot and options.master_build_id is not None:
1898 slave_timeout = None
1899 if cidb.CIDBConnectionFactory.IsCIDBSetup():
1900 cidb_handle = cidb.CIDBConnectionFactory.GetCIDBConnectionForBuilder()
1901 if cidb_handle:
1902 slave_timeout = cidb_handle.GetTimeToDeadline(options.master_build_id)
1903
1904 if slave_timeout is not None:
1905 # Cut me some slack. We artificially add a a small time here to the
1906 # slave_timeout because '0' is handled specially, and because we don't
1907 # want to timeout while trying to set things up.
1908 slave_timeout = slave_timeout + 20
1909 if options.timeout == 0 or slave_timeout < options.timeout:
1910 logging.info('Updating slave build timeout to %d seconds enforced '
1911 'by the master',
1912 slave_timeout)
1913 options.timeout = slave_timeout
1914 else:
1915 logging.warning('Could not get master deadline for master-slave build. '
1916 'Can not set slave timeout.')
1917
1918 if options.timeout > 0:
1919 stack.Add(timeout_util.FatalTimeout, options.timeout)
1920
Brian Harringc2d09d92012-05-13 22:03:15 -07001921 _RunBuildStagesWrapper(options, build_config)