blob: 68521626e7a8e92562bcb398aa0179bcf28cc0aa [file] [log] [blame]
Mike Frysingere58c0e22017-10-04 15:43:30 -04001# -*- coding: utf-8 -*-
Don Garrettc4114cc2016-11-01 20:04:06 -07002# Copyright 2016 The Chromium OS Authors. All rights reserved.
3# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
5
6"""Bootstrap for cbuildbot.
7
8This script is intended to checkout chromite on the branch specified by -b or
9--branch (as normally accepted by cbuildbot), and then invoke cbuildbot. Most
10arguments are not parsed, only passed along. If a branch is not specified, this
11script will use 'master'.
12
13Among other things, this allows us to invoke build configs that exist on a given
14branch, but not on TOT.
15"""
16
17from __future__ import print_function
18
Benjamin Gordon90b2dd92018-04-12 14:04:21 -060019import base64
Don Garrett125d4dc2017-04-25 16:26:03 -070020import functools
Don Garrettc4114cc2016-11-01 20:04:06 -070021import os
Prathmesh Prabhuc41a0f52018-04-03 13:26:52 -070022import time
Don Garrettc4114cc2016-11-01 20:04:06 -070023
24from chromite.cbuildbot import repository
Don Garrett597ddff2017-02-17 18:29:37 -080025from chromite.cbuildbot.stages import sync_stages
Benjamin Gordon90b2dd92018-04-12 14:04:21 -060026from chromite.lib import build_summary
Don Garrett86881cb2017-02-15 15:41:55 -080027from chromite.lib import config_lib
Don Garretta50bf492017-09-28 18:33:02 -070028from chromite.lib import constants
Don Garrettc4114cc2016-11-01 20:04:06 -070029from chromite.lib import cros_build_lib
30from chromite.lib import cros_logging as logging
Benjamin Gordon74645232018-05-04 17:40:42 -060031from chromite.lib import cros_sdk_lib
Don Garrettacbb2392017-05-11 18:27:41 -070032from chromite.lib import metrics
Don Garrettc4114cc2016-11-01 20:04:06 -070033from chromite.lib import osutils
Don Garrettacbb2392017-05-11 18:27:41 -070034from chromite.lib import ts_mon_config
Don Garrett86881cb2017-02-15 15:41:55 -080035from chromite.scripts import cbuildbot
Don Garrettc4114cc2016-11-01 20:04:06 -070036
Don Garrett60967922017-04-12 18:51:44 -070037# This number should be incremented when we change the layout of the buildroot
38# in a non-backwards compatible way. This wipes all buildroots.
Don Garrettbf90cdf2017-05-19 15:54:02 -070039BUILDROOT_BUILDROOT_LAYOUT = 2
Prathmesh Prabhuc41a0f52018-04-03 13:26:52 -070040_DISTFILES_CACHE_EXPIRY_HOURS = 8 * 24
Don Garrett60967922017-04-12 18:51:44 -070041
Don Garrettacbb2392017-05-11 18:27:41 -070042# Metrics reported to Monarch.
Don Garrett45e77412017-06-14 16:57:55 -070043METRIC_ACTIVE = 'chromeos/chromite/cbuildbot_launch/active'
Don Garrettacbb2392017-05-11 18:27:41 -070044METRIC_INVOKED = 'chromeos/chromite/cbuildbot_launch/invoked'
45METRIC_COMPLETED = 'chromeos/chromite/cbuildbot_launch/completed'
46METRIC_PREP = 'chromeos/chromite/cbuildbot_launch/prep_completed'
47METRIC_CLEAN = 'chromeos/chromite/cbuildbot_launch/clean_buildroot_durations'
48METRIC_INITIAL = 'chromeos/chromite/cbuildbot_launch/initial_checkout_durations'
49METRIC_CBUILDBOT = 'chromeos/chromite/cbuildbot_launch/cbuildbot_durations'
50METRIC_CLOBBER = 'chromeos/chromite/cbuildbot_launch/clobber'
51METRIC_BRANCH_CLEANUP = 'chromeos/chromite/cbuildbot_launch/branch_cleanup'
Prathmesh Prabhuc41a0f52018-04-03 13:26:52 -070052METRIC_DISTFILES_CLEANUP = (
53 'chromeos/chromite/cbuildbot_launch/distfiles_cleanup')
Don Garrett066e6f52017-09-28 19:14:01 -070054METRIC_DEPOT_TOOLS = 'chromeos/chromite/cbuildbot_launch/depot_tools_prep'
Don Garrettacbb2392017-05-11 18:27:41 -070055
Benjamin Gordon90b2dd92018-04-12 14:04:21 -060056# Builder state
57BUILDER_STATE_FILENAME = '.cbuildbot_build_state.json'
58
Don Garrett60967922017-04-12 18:51:44 -070059
Don Garrett125d4dc2017-04-25 16:26:03 -070060def StageDecorator(functor):
61 """A Decorator that adds buildbot stage tags around a method.
62
Don Garrettacbb2392017-05-11 18:27:41 -070063 It uses the method name as the stage name, and assumes failure on a true
64 return value, or an exception.
Don Garrett125d4dc2017-04-25 16:26:03 -070065 """
66 @functools.wraps(functor)
67 def wrapped_functor(*args, **kwargs):
68 try:
69 logging.PrintBuildbotStepName(functor.__name__)
Don Garrettacbb2392017-05-11 18:27:41 -070070 result = functor(*args, **kwargs)
Don Garrett125d4dc2017-04-25 16:26:03 -070071 except Exception:
72 logging.PrintBuildbotStepFailure()
73 raise
74
Don Garrettacbb2392017-05-11 18:27:41 -070075 if result:
76 logging.PrintBuildbotStepFailure()
77 return result
78
Don Garrett125d4dc2017-04-25 16:26:03 -070079 return wrapped_functor
80
81
Don Garrettb5fc08b2017-11-20 21:51:16 +000082def field(fields, **kwargs):
Don Garrettacbb2392017-05-11 18:27:41 -070083 """Helper for inserting more fields into a metrics fields dictionary.
84
85 Args:
86 fields: Dictionary of metrics fields.
87 kwargs: Each argument is a key/value pair to insert into dict.
88
89 Returns:
90 Copy of original dictionary with kwargs set as fields.
91 """
92 f = fields.copy()
93 f.update(kwargs)
94 return f
95
Don Garretta50bf492017-09-28 18:33:02 -070096
97def PrependPath(prepend):
98 """Generate path with new directory at the beginning.
99
100 Args:
101 prepend: Directory to add at the beginning of the path.
102
103 Returns:
104 Extended path as a string.
105 """
106 return os.pathsep.join([prepend, os.environ.get('PATH', os.defpath)])
107
108
Don Garrett86881cb2017-02-15 15:41:55 -0800109def PreParseArguments(argv):
Don Garrettc4114cc2016-11-01 20:04:06 -0700110 """Extract the branch name from cbuildbot command line arguments.
111
Don Garrettc4114cc2016-11-01 20:04:06 -0700112 Args:
113 argv: The command line arguments to parse.
114
115 Returns:
116 Branch as a string ('master' if nothing is specified).
117 """
Don Garrett86881cb2017-02-15 15:41:55 -0800118 parser = cbuildbot.CreateParser()
Mike Frysinger80bba8a2017-08-18 15:28:36 -0400119 options = cbuildbot.ParseCommandLine(parser, argv)
Don Garrettd1d90dd2017-06-13 17:35:52 -0700120 options.Freeze()
Don Garrett86881cb2017-02-15 15:41:55 -0800121
122 # This option isn't required for cbuildbot, but is for us.
123 if not options.buildroot:
124 cros_build_lib.Die('--buildroot is a required option.')
125
126 return options
Don Garrettc4114cc2016-11-01 20:04:06 -0700127
128
Benjamin Gordon8b6d4122018-04-26 13:38:39 -0600129def GetCurrentBuildState(options, branch):
Benjamin Gordon90b2dd92018-04-12 14:04:21 -0600130 """Extract information about the current build state from command-line args.
131
132 Args:
133 options: A parsed options object from a cbuildbot parser.
Benjamin Gordon8b6d4122018-04-26 13:38:39 -0600134 branch: The name of the branch this builder was called with.
Benjamin Gordon90b2dd92018-04-12 14:04:21 -0600135
136 Returns:
137 A BuildSummary object describing the current build.
138 """
139 build_state = build_summary.BuildSummary(
Benjamin Gordon8b6d4122018-04-26 13:38:39 -0600140 status=constants.BUILDER_STATUS_INFLIGHT,
141 buildroot_layout=BUILDROOT_BUILDROOT_LAYOUT,
142 branch=branch)
Benjamin Gordon90b2dd92018-04-12 14:04:21 -0600143 if options.buildnumber:
144 build_state.build_number = options.buildnumber
145 if options.buildbucket_id:
146 build_state.buildbucket_id = options.buildbucket_id
147 if options.master_build_id:
148 build_state.master_build_id = options.master_build_id
149 return build_state
150
151
152def GetLastBuildState(root):
153 """Fetch the state of the last build run from |root|.
154
155 If the saved state file can't be read or doesn't contain valid JSON, a default
156 state will be returned.
157
158 Args:
159 root: Root of the working directory tree as a string.
160
161 Returns:
162 A BuildSummary object representing the previous build.
163 """
164 state_file = os.path.join(root, BUILDER_STATE_FILENAME)
165
166 state = build_summary.BuildSummary()
Benjamin Gordon8b6d4122018-04-26 13:38:39 -0600167
Benjamin Gordon90b2dd92018-04-12 14:04:21 -0600168 try:
169 state_raw = osutils.ReadFile(state_file)
170 state.from_json(state_raw)
171 except IOError as e:
172 logging.warning('Unable to read %s: %s', state_file, e)
173 return state
174 except ValueError as e:
175 logging.warning('Saved state file %s is not valid JSON: %s', state_file, e)
176 return state
177
178 if not state.is_valid():
179 logging.warning('Previous build state is not valid. Ignoring.')
Benjamin Gordon8b6d4122018-04-26 13:38:39 -0600180 state = build_summary.BuildSummary()
Benjamin Gordon90b2dd92018-04-12 14:04:21 -0600181
182 return state
183
184
185def SetLastBuildState(root, new_state):
186 """Save the state of the last build under |root|.
187
188 Args:
189 root: Root of the working directory tree as a string.
190 new_state: BuildSummary object containing the state to be saved.
191 """
192 state_file = os.path.join(root, BUILDER_STATE_FILENAME)
193 osutils.WriteFile(state_file, new_state.to_json())
194
Benjamin Gordon8b6d4122018-04-26 13:38:39 -0600195 # Remove old state file. Its contents have been migrated into the new file.
196 old_state_file = os.path.join(root, '.cbuildbot_launch_state')
197 osutils.SafeUnlink(old_state_file)
198
Benjamin Gordon90b2dd92018-04-12 14:04:21 -0600199
Prathmesh Prabhuc41a0f52018-04-03 13:26:52 -0700200def _MaybeCleanDistfiles(repo, distfiles_ts, metrics_fields):
201 """Cleans the distfiles directory if too old.
202
203 Args:
204 repo: repository.RepoRepository instance.
205 distfiles_ts: A timestamp str for the last time distfiles was cleaned. May
206 be None.
207 metrics_fields: Dictionary of fields to include in metrics.
208
209 Returns:
210 The new distfiles_ts to persist in state.
211 """
212
213 if distfiles_ts is None:
214 return None
215
216 distfiles_age = (time.time() - distfiles_ts) / 3600.0
217 if distfiles_age < _DISTFILES_CACHE_EXPIRY_HOURS:
218 return distfiles_ts
219
220 logging.info('Remove old distfiles cache (cache expiry %d hours)',
221 _DISTFILES_CACHE_EXPIRY_HOURS)
222 osutils.RmDir(os.path.join(repo.directory, '.cache', 'distfiles'),
223 ignore_missing=True, sudo=True)
224 metrics.Counter(METRIC_DISTFILES_CLEANUP).increment(
225 field(metrics_fields, reason='cache_expired'))
226 # Cleaned cache, so reset distfiles_ts
227 return None
228
229
Don Garrett125d4dc2017-04-25 16:26:03 -0700230@StageDecorator
Benjamin Gordon90b2dd92018-04-12 14:04:21 -0600231def CleanBuildRoot(root, repo, metrics_fields, build_state):
Don Garrett7ade05a2017-02-17 13:31:47 -0800232 """Some kinds of branch transitions break builds.
233
Don Garrettbf90cdf2017-05-19 15:54:02 -0700234 This method ensures that cbuildbot's buildroot is a clean checkout on the
235 given branch when it starts. If necessary (a branch transition) it will wipe
236 assorted state that cannot be safely reused from the previous build.
Don Garrett7ade05a2017-02-17 13:31:47 -0800237
Don Garrett7ade05a2017-02-17 13:31:47 -0800238 Args:
Don Garrettbf90cdf2017-05-19 15:54:02 -0700239 root: Root directory owned by cbuildbot_launch.
Don Garrettf324bc32017-05-23 14:00:53 -0700240 repo: repository.RepoRepository instance.
Don Garrettacbb2392017-05-11 18:27:41 -0700241 metrics_fields: Dictionary of fields to include in metrics.
Benjamin Gordon90b2dd92018-04-12 14:04:21 -0600242 build_state: BuildSummary object containing the current build state that
Benjamin Gordon8b6d4122018-04-26 13:38:39 -0600243 will be saved into the cleaned root. The distfiles_ts property will
244 be updated if the distfiles cache is cleaned.
Don Garrett7ade05a2017-02-17 13:31:47 -0800245 """
Benjamin Gordon8b6d4122018-04-26 13:38:39 -0600246 previous_state = GetLastBuildState(root)
247 build_state.distfiles_ts = _MaybeCleanDistfiles(
248 repo, previous_state.distfiles_ts, metrics_fields)
Don Garrette17e1d92017-04-12 15:28:19 -0700249
Benjamin Gordon8b6d4122018-04-26 13:38:39 -0600250 if previous_state.buildroot_layout != BUILDROOT_BUILDROOT_LAYOUT:
Don Garrett125d4dc2017-04-25 16:26:03 -0700251 logging.PrintBuildbotStepText('Unknown layout: Wiping buildroot.')
Don Garrettb5fc08b2017-11-20 21:51:16 +0000252 metrics.Counter(METRIC_CLOBBER).increment(
253 field(metrics_fields, reason='layout_change'))
Benjamin Gordonaee36b82018-02-05 14:25:26 -0700254 chroot_dir = os.path.join(root, constants.DEFAULT_CHROOT_DIR)
Don Garrettb5fc08b2017-11-20 21:51:16 +0000255 if os.path.exists(chroot_dir) or os.path.exists(chroot_dir + '.img'):
Benjamin Gordon74645232018-05-04 17:40:42 -0600256 cros_sdk_lib.CleanupChrootMount(chroot_dir, delete_image=True)
Don Garrettb5fc08b2017-11-20 21:51:16 +0000257 osutils.RmDir(root, ignore_missing=True, sudo=True)
Don Garrettf324bc32017-05-23 14:00:53 -0700258 else:
Benjamin Gordon8b6d4122018-04-26 13:38:39 -0600259 if previous_state.branch != repo.branch:
Don Garrettf324bc32017-05-23 14:00:53 -0700260 logging.PrintBuildbotStepText('Branch change: Cleaning buildroot.')
Benjamin Gordon8b6d4122018-04-26 13:38:39 -0600261 logging.info('Unmatched branch: %s -> %s', previous_state.branch,
262 repo.branch)
Don Garrettacbb2392017-05-11 18:27:41 -0700263 metrics.Counter(METRIC_BRANCH_CLEANUP).increment(
Benjamin Gordon8b6d4122018-04-26 13:38:39 -0600264 field(metrics_fields, old_branch=previous_state.branch))
Don Garrett39963602017-02-27 14:41:58 -0800265
Don Garrettf324bc32017-05-23 14:00:53 -0700266 logging.info('Remove Chroot.')
Benjamin Gordonaee36b82018-02-05 14:25:26 -0700267 chroot_dir = os.path.join(repo.directory, constants.DEFAULT_CHROOT_DIR)
Benjamin Gordon59ba2f82017-08-28 15:31:06 -0600268 if os.path.exists(chroot_dir) or os.path.exists(chroot_dir + '.img'):
Benjamin Gordon74645232018-05-04 17:40:42 -0600269 cros_sdk_lib.CleanupChrootMount(chroot_dir, delete_image=True)
Benjamin Gordon59ba2f82017-08-28 15:31:06 -0600270 osutils.RmDir(chroot_dir, ignore_missing=True, sudo=True)
Don Garrett7ade05a2017-02-17 13:31:47 -0800271
Don Garrettf324bc32017-05-23 14:00:53 -0700272 logging.info('Remove Chrome checkout.')
Don Garrettbf90cdf2017-05-19 15:54:02 -0700273 osutils.RmDir(os.path.join(repo.directory, '.cache', 'distfiles'),
Don Garrettf324bc32017-05-23 14:00:53 -0700274 ignore_missing=True, sudo=True)
275
276 try:
277 # If there is any failure doing the cleanup, wipe everything.
278 repo.BuildRootGitCleanup(prune_all=True)
279 except Exception:
280 logging.info('Checkout cleanup failed, wiping buildroot:', exc_info=True)
Don Garrettacbb2392017-05-11 18:27:41 -0700281 metrics.Counter(METRIC_CLOBBER).increment(
Don Garrettb5fc08b2017-11-20 21:51:16 +0000282 field(metrics_fields, reason='repo_cleanup_failure'))
Don Garrettbf90cdf2017-05-19 15:54:02 -0700283 repository.ClearBuildRoot(repo.directory)
Don Garrett39963602017-02-27 14:41:58 -0800284
Don Garrettbf90cdf2017-05-19 15:54:02 -0700285 # Ensure buildroot exists. Save the state we are prepped for.
286 osutils.SafeMakedirs(repo.directory)
Benjamin Gordon8b6d4122018-04-26 13:38:39 -0600287 if not build_state.distfiles_ts:
288 build_state.distfiles_ts = time.time()
Benjamin Gordon90b2dd92018-04-12 14:04:21 -0600289 SetLastBuildState(root, build_state)
Don Garrett7ade05a2017-02-17 13:31:47 -0800290
291
Don Garrett125d4dc2017-04-25 16:26:03 -0700292@StageDecorator
Don Garrettf324bc32017-05-23 14:00:53 -0700293def InitialCheckout(repo):
Don Garrett86881cb2017-02-15 15:41:55 -0800294 """Preliminary ChromeOS checkout.
295
296 Perform a complete checkout of ChromeOS on the specified branch. This does NOT
297 match what the build needs, but ensures the buildroot both has a 'hot'
298 checkout, and is close enough that the branched cbuildbot can successfully get
299 the right checkout.
300
301 This checks out full ChromeOS, even if a ChromiumOS build is going to be
302 performed. This is because we have no knowledge of the build config to be
303 used.
Don Garrettc4114cc2016-11-01 20:04:06 -0700304
305 Args:
Don Garrettf324bc32017-05-23 14:00:53 -0700306 repo: repository.RepoRepository instance.
Don Garrettc4114cc2016-11-01 20:04:06 -0700307 """
Don Garrettf324bc32017-05-23 14:00:53 -0700308 logging.PrintBuildbotStepText('Branch: %s' % repo.branch)
Don Garrett7ade05a2017-02-17 13:31:47 -0800309 logging.info('Bootstrap script starting initial sync on branch: %s',
Don Garrettf324bc32017-05-23 14:00:53 -0700310 repo.branch)
Don Garrett76496912017-05-11 16:59:11 -0700311 repo.Sync(detach=True)
Don Garrettc4114cc2016-11-01 20:04:06 -0700312
313
Don Garrett125d4dc2017-04-25 16:26:03 -0700314@StageDecorator
Don Garrett066e6f52017-09-28 19:14:01 -0700315def DepotToolsEnsureBootstrap(depot_tools_path):
316 """Start cbuildbot in specified directory with all arguments.
317
318 Args:
319 buildroot: Directory to be passed to cbuildbot with --buildroot.
320 depot_tools_path: Directory for depot_tools to be used by cbuildbot.
321 argv: Command line options passed to cbuildbot_launch.
322
323 Returns:
324 Return code of cbuildbot as an integer.
325 """
326 ensure_bootstrap_script = os.path.join(depot_tools_path, 'ensure_bootstrap')
327 if os.path.exists(ensure_bootstrap_script):
328 extra_env = {'PATH': PrependPath(depot_tools_path)}
329 cros_build_lib.RunCommand(
330 [ensure_bootstrap_script], extra_env=extra_env, cwd=depot_tools_path)
331 else:
332 # This is normal when checking out branches older than this script.
333 logging.warn('ensure_bootstrap not found, skipping: %s',
334 ensure_bootstrap_script)
335
336
337@StageDecorator
Don Garrett6e5c6b92018-04-06 17:58:49 -0700338def Cbuildbot(buildroot, depot_tools_path, argv):
Don Garrettc4114cc2016-11-01 20:04:06 -0700339 """Start cbuildbot in specified directory with all arguments.
340
341 Args:
Don Garrettbf90cdf2017-05-19 15:54:02 -0700342 buildroot: Directory to be passed to cbuildbot with --buildroot.
Don Garretta50bf492017-09-28 18:33:02 -0700343 depot_tools_path: Directory for depot_tools to be used by cbuildbot.
Don Garrettd1d90dd2017-06-13 17:35:52 -0700344 argv: Command line options passed to cbuildbot_launch.
Don Garrettc4114cc2016-11-01 20:04:06 -0700345
346 Returns:
347 Return code of cbuildbot as an integer.
348 """
Don Garrettbf90cdf2017-05-19 15:54:02 -0700349 logging.info('Bootstrap cbuildbot in: %s', buildroot)
Don Garrettbf90cdf2017-05-19 15:54:02 -0700350
Don Garrettd1d90dd2017-06-13 17:35:52 -0700351 # Fixup buildroot parameter.
352 argv = argv[:]
353 for i in xrange(len(argv)):
354 if argv[i] in ('-r', '--buildroot'):
355 argv[i+1] = buildroot
Don Garrett597ddff2017-02-17 18:29:37 -0800356
Don Garrettd1d90dd2017-06-13 17:35:52 -0700357 # This filters out command line arguments not supported by older versions
358 # of cbuildbot.
359 parser = cbuildbot.CreateParser()
Mike Frysinger80bba8a2017-08-18 15:28:36 -0400360 options = cbuildbot.ParseCommandLine(parser, argv)
Don Garrettd1d90dd2017-06-13 17:35:52 -0700361 cbuildbot_path = os.path.join(buildroot, 'chromite', 'bin', 'cbuildbot')
Don Garrett597ddff2017-02-17 18:29:37 -0800362 cmd = sync_stages.BootstrapStage.FilterArgsForTargetCbuildbot(
Don Garrettbf90cdf2017-05-19 15:54:02 -0700363 buildroot, cbuildbot_path, options)
Don Garrett597ddff2017-02-17 18:29:37 -0800364
Don Garretta50bf492017-09-28 18:33:02 -0700365 # We want cbuildbot to use branched depot_tools scripts from our manifest,
366 # so that depot_tools is branched to match cbuildbot.
367 logging.info('Adding depot_tools into PATH: %s', depot_tools_path)
368 extra_env = {'PATH': PrependPath(depot_tools_path)}
369
370 result = cros_build_lib.RunCommand(
371 cmd, extra_env=extra_env, error_code_ok=True, cwd=buildroot)
Don Garrettacbb2392017-05-11 18:27:41 -0700372 return result.returncode
Don Garrettc4114cc2016-11-01 20:04:06 -0700373
Don Garrett60967922017-04-12 18:51:44 -0700374
Benjamin Gordonaee36b82018-02-05 14:25:26 -0700375@StageDecorator
376def CleanupChroot(buildroot):
377 """Unmount/clean up an image-based chroot without deleting the backing image.
378
379 Args:
380 buildroot: Directory containing the chroot to be cleaned up.
381 """
382 chroot_dir = os.path.join(buildroot, constants.DEFAULT_CHROOT_DIR)
383 logging.info('Cleaning up chroot at %s', chroot_dir)
384 if os.path.exists(chroot_dir) or os.path.exists(chroot_dir + '.img'):
Benjamin Gordon74645232018-05-04 17:40:42 -0600385 cros_sdk_lib.CleanupChrootMount(chroot_dir, delete_image=False)
Benjamin Gordonaee36b82018-02-05 14:25:26 -0700386
387
Don Garrettf15d65b2017-04-12 12:39:55 -0700388def ConfigureGlobalEnvironment():
389 """Setup process wide environmental changes."""
Don Garrettf15d65b2017-04-12 12:39:55 -0700390 # Set umask to 022 so files created by buildbot are readable.
391 os.umask(0o22)
392
Don Garrett86fec482017-05-17 18:13:33 -0700393 # These variables can interfere with LANG / locale behavior.
394 unwanted_local_vars = [
395 'LC_ALL', 'LC_CTYPE', 'LC_COLLATE', 'LC_TIME', 'LC_NUMERIC',
396 'LC_MONETARY', 'LC_MESSAGES', 'LC_PAPER', 'LC_NAME', 'LC_ADDRESS',
397 'LC_TELEPHONE', 'LC_MEASUREMENT', 'LC_IDENTIFICATION',
398 ]
399 for v in unwanted_local_vars:
400 os.environ.pop(v, None)
401
402 # This variable is required for repo sync's to work in all cases.
403 os.environ['LANG'] = 'en_US.UTF-8'
404
Don Garrettc4114cc2016-11-01 20:04:06 -0700405
Don Garrettacbb2392017-05-11 18:27:41 -0700406def _main(argv):
Don Garrettc4114cc2016-11-01 20:04:06 -0700407 """main method of script.
408
409 Args:
410 argv: All command line arguments to pass as list of strings.
411
412 Returns:
413 Return code of cbuildbot as an integer.
414 """
Don Garrettd1d90dd2017-06-13 17:35:52 -0700415 options = PreParseArguments(argv)
416
417 branchname = options.branch or 'master'
418 root = options.buildroot
419 buildroot = os.path.join(root, 'repository')
Don Garretta50bf492017-09-28 18:33:02 -0700420 depot_tools_path = os.path.join(buildroot, constants.DEPOT_TOOLS_SUBPATH)
Don Garrettd1d90dd2017-06-13 17:35:52 -0700421
422 metrics_fields = {
423 'branch_name': branchname,
Don Garrettf0761152017-10-19 19:38:27 -0700424 'build_config': options.build_config_name,
Don Garrettd1d90dd2017-06-13 17:35:52 -0700425 'tryjob': options.remote_trybot,
426 }
Don Garrettf15d65b2017-04-12 12:39:55 -0700427
Ben Pastenec8e4e792018-05-14 20:20:25 +0000428 # Does the entire build pass or fail.
429 with metrics.Presence(METRIC_ACTIVE, metrics_fields), \
430 metrics.SuccessCounter(METRIC_COMPLETED, metrics_fields) as s_fields:
Don Garrettc4114cc2016-11-01 20:04:06 -0700431
Ben Pastenec8e4e792018-05-14 20:20:25 +0000432 # Preliminary set, mostly command line parsing.
433 with metrics.SuccessCounter(METRIC_INVOKED, metrics_fields):
434 if options.enable_buildbot_tags:
435 logging.EnableBuildbotMarkers()
436 ConfigureGlobalEnvironment()
Don Garrett86881cb2017-02-15 15:41:55 -0800437
Ben Pastenec8e4e792018-05-14 20:20:25 +0000438 # Prepare the buildroot with source for the build.
439 with metrics.SuccessCounter(METRIC_PREP, metrics_fields):
440 site_config = config_lib.GetConfig()
441 manifest_url = site_config.params['MANIFEST_INT_URL']
442 repo = repository.RepoRepository(manifest_url, buildroot,
443 branch=branchname,
444 git_cache_dir=options.git_cache_dir)
445 previous_build_state = GetLastBuildState(root)
Don Garrett86881cb2017-02-15 15:41:55 -0800446
Ben Pastenec8e4e792018-05-14 20:20:25 +0000447 # Clean up the buildroot to a safe state.
448 with metrics.SecondsTimer(METRIC_CLEAN, fields=metrics_fields):
449 build_state = GetCurrentBuildState(options, branchname)
450 CleanBuildRoot(root, repo, metrics_fields, build_state)
Don Garrettacbb2392017-05-11 18:27:41 -0700451
Ben Pastenec8e4e792018-05-14 20:20:25 +0000452 # Get a checkout close enough to the branch that cbuildbot can handle it.
453 if options.sync:
454 with metrics.SecondsTimer(METRIC_INITIAL, fields=metrics_fields):
455 InitialCheckout(repo)
Don Garrettacbb2392017-05-11 18:27:41 -0700456
Ben Pastenec8e4e792018-05-14 20:20:25 +0000457 # Get a checkout close enough to the branch that cbuildbot can handle it.
458 with metrics.SecondsTimer(METRIC_DEPOT_TOOLS, fields=metrics_fields):
459 DepotToolsEnsureBootstrap(depot_tools_path)
Don Garrett066e6f52017-09-28 19:14:01 -0700460
Ben Pastenec8e4e792018-05-14 20:20:25 +0000461 # Run cbuildbot inside the full ChromeOS checkout, on the specified branch.
462 with metrics.SecondsTimer(METRIC_CBUILDBOT, fields=metrics_fields):
463 if previous_build_state.is_valid():
464 argv.append('--previous-build-state')
465 argv.append(base64.b64encode(previous_build_state.to_json()))
Benjamin Gordon90b2dd92018-04-12 14:04:21 -0600466
Ben Pastenec8e4e792018-05-14 20:20:25 +0000467 result = Cbuildbot(buildroot, depot_tools_path, argv)
468 s_fields['success'] = (result == 0)
Benjamin Gordon90b2dd92018-04-12 14:04:21 -0600469
Ben Pastenec8e4e792018-05-14 20:20:25 +0000470 build_state.status = (
471 constants.BUILDER_STATUS_PASSED
472 if result == 0 else constants.BUILDER_STATUS_FAILED)
473 SetLastBuildState(root, build_state)
Benjamin Gordon90b2dd92018-04-12 14:04:21 -0600474
Ben Pastenec8e4e792018-05-14 20:20:25 +0000475 CleanupChroot(buildroot)
476 return result
477
Don Garrettacbb2392017-05-11 18:27:41 -0700478
479def main(argv):
Ben Pastenec8e4e792018-05-14 20:20:25 +0000480 # Enable Monarch metrics gathering.
481 with ts_mon_config.SetupTsMonGlobalState('cbuildbot_launch', indirect=True):
482 return _main(argv)