blob: e0ebcb06daca7bb11801d796a652ec77b05ffb52 [file] [log] [blame]
Don Garrettc4114cc2016-11-01 20:04:06 -07001# Copyright 2016 The Chromium OS Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5"""Bootstrap for cbuildbot.
6
7This script is intended to checkout chromite on the branch specified by -b or
8--branch (as normally accepted by cbuildbot), and then invoke cbuildbot. Most
9arguments are not parsed, only passed along. If a branch is not specified, this
10script will use 'master'.
11
12Among other things, this allows us to invoke build configs that exist on a given
13branch, but not on TOT.
14"""
15
16from __future__ import print_function
17
Don Garrett125d4dc2017-04-25 16:26:03 -070018import functools
Don Garrettc4114cc2016-11-01 20:04:06 -070019import os
20
21from chromite.cbuildbot import repository
Don Garrett597ddff2017-02-17 18:29:37 -080022from chromite.cbuildbot.stages import sync_stages
Don Garrett86881cb2017-02-15 15:41:55 -080023from chromite.lib import config_lib
Don Garrettc4114cc2016-11-01 20:04:06 -070024from chromite.lib import cros_build_lib
25from chromite.lib import cros_logging as logging
Don Garrettc4114cc2016-11-01 20:04:06 -070026from chromite.lib import osutils
Don Garrett86881cb2017-02-15 15:41:55 -080027from chromite.scripts import cbuildbot
Don Garrettc4114cc2016-11-01 20:04:06 -070028
Don Garrett597ddff2017-02-17 18:29:37 -080029
Don Garrett60967922017-04-12 18:51:44 -070030# This number should be incremented when we change the layout of the buildroot
31# in a non-backwards compatible way. This wipes all buildroots.
32BUILDROOT_BUILDROOT_LAYOUT = 1
33
34
Don Garrett125d4dc2017-04-25 16:26:03 -070035def StageDecorator(functor):
36 """A Decorator that adds buildbot stage tags around a method.
37
38 It uses the method name as the stage name, and assumes failure on exception.
39 """
40 @functools.wraps(functor)
41 def wrapped_functor(*args, **kwargs):
42 try:
43 logging.PrintBuildbotStepName(functor.__name__)
44 return functor(*args, **kwargs)
45 except Exception:
46 logging.PrintBuildbotStepFailure()
47 raise
48
49 return wrapped_functor
50
51
Don Garrett86881cb2017-02-15 15:41:55 -080052def PreParseArguments(argv):
Don Garrettc4114cc2016-11-01 20:04:06 -070053 """Extract the branch name from cbuildbot command line arguments.
54
55 Ignores all arguments, other than the branch name.
56
57 Args:
58 argv: The command line arguments to parse.
59
60 Returns:
61 Branch as a string ('master' if nothing is specified).
62 """
Don Garrett86881cb2017-02-15 15:41:55 -080063 parser = cbuildbot.CreateParser()
Don Garrett597ddff2017-02-17 18:29:37 -080064 options, args = cbuildbot.ParseCommandLine(parser, argv)
Don Garrett86881cb2017-02-15 15:41:55 -080065
66 # This option isn't required for cbuildbot, but is for us.
67 if not options.buildroot:
68 cros_build_lib.Die('--buildroot is a required option.')
69
Don Garrett597ddff2017-02-17 18:29:37 -080070 # Save off the build targets, in a mirror of cbuildbot code.
71 options.build_targets = args
72 options.Freeze()
73
Don Garrett86881cb2017-02-15 15:41:55 -080074 return options
Don Garrettc4114cc2016-11-01 20:04:06 -070075
76
Don Garrett60967922017-04-12 18:51:44 -070077def GetBuildrootState(buildroot):
78 state_file = os.path.join(buildroot, '.cbuildbot_launch_state')
79
80 try:
81 state = osutils.ReadFile(state_file)
82 buildroot_layout, branchname = state.split()
83 buildroot_layout = int(buildroot_layout)
84 return buildroot_layout, branchname
85 except (IOError, ValueError):
86 # If we are unable to either read or parse the state file, we get here.
87 return 0, ''
88
89
90def SetBuildrootState(branchname, buildroot):
91 assert branchname
92 state_file = os.path.join(buildroot, '.cbuildbot_launch_state')
93 new_state = '%d %s' % (BUILDROOT_BUILDROOT_LAYOUT, branchname)
94 osutils.WriteFile(state_file, new_state)
95
96
Don Garrett125d4dc2017-04-25 16:26:03 -070097@StageDecorator
Don Garrett7ade05a2017-02-17 13:31:47 -080098def CleanBuildroot(branchname, buildroot):
99 """Some kinds of branch transitions break builds.
100
101 This method tries to detect cases where that can happen, and clobber what's
102 needed to succeed. However, the clobbers are costly, and should be avoided
103 if necessary.
104
Don Garrett7ade05a2017-02-17 13:31:47 -0800105 Args:
Don Garrett125d4dc2017-04-25 16:26:03 -0700106 branchname: Name of branch to checkout.
Don Garrett7ade05a2017-02-17 13:31:47 -0800107 buildroot: Directory with old buildroot to clean as needed.
108 """
Don Garrett60967922017-04-12 18:51:44 -0700109 old_buildroot_layout, old_branch = GetBuildrootState(buildroot)
Don Garrette17e1d92017-04-12 15:28:19 -0700110
Don Garrett60967922017-04-12 18:51:44 -0700111 if old_buildroot_layout != BUILDROOT_BUILDROOT_LAYOUT:
Don Garrett125d4dc2017-04-25 16:26:03 -0700112 logging.PrintBuildbotStepText('Unknown layout: Wiping buildroot.')
Don Garrett60967922017-04-12 18:51:44 -0700113 osutils.RmDir(buildroot, ignore_missing=True, sudo=True)
Don Garrette17e1d92017-04-12 15:28:19 -0700114
Don Garrett60967922017-04-12 18:51:44 -0700115 elif old_branch != branchname:
Don Garrett125d4dc2017-04-25 16:26:03 -0700116 logging.PrintBuildbotStepText('Branch change: Cleaning buildroot.')
Don Garrett60967922017-04-12 18:51:44 -0700117 logging.info('Unmatched branch: %s -> %s', old_branch, branchname)
Don Garrett39963602017-02-27 14:41:58 -0800118
Don Garrett60967922017-04-12 18:51:44 -0700119 logging.info('Remove Chroot.')
Don Garrett7ade05a2017-02-17 13:31:47 -0800120 osutils.RmDir(os.path.join(buildroot, 'chroot'),
121 ignore_missing=True, sudo=True)
122
Don Garrett60967922017-04-12 18:51:44 -0700123 logging.info('Remove Chrome checkout.')
Don Garrett39963602017-02-27 14:41:58 -0800124 osutils.RmDir(os.path.join(buildroot, '.cache', 'distfiles'),
125 ignore_missing=True, sudo=True)
126
Don Garrett60967922017-04-12 18:51:44 -0700127 # Ensure buildroot exists.
128 osutils.SafeMakedirs(buildroot)
129 SetBuildrootState(branchname, buildroot)
Don Garrett7ade05a2017-02-17 13:31:47 -0800130
131
Don Garrett125d4dc2017-04-25 16:26:03 -0700132@StageDecorator
Don Garrett86881cb2017-02-15 15:41:55 -0800133def InitialCheckout(branchname, buildroot, git_cache_dir):
134 """Preliminary ChromeOS checkout.
135
136 Perform a complete checkout of ChromeOS on the specified branch. This does NOT
137 match what the build needs, but ensures the buildroot both has a 'hot'
138 checkout, and is close enough that the branched cbuildbot can successfully get
139 the right checkout.
140
141 This checks out full ChromeOS, even if a ChromiumOS build is going to be
142 performed. This is because we have no knowledge of the build config to be
143 used.
Don Garrettc4114cc2016-11-01 20:04:06 -0700144
145 Args:
Don Garrett125d4dc2017-04-25 16:26:03 -0700146 branchname: Name of branch to checkout.
Don Garrett86881cb2017-02-15 15:41:55 -0800147 buildroot: Directory to checkout into.
148 git_cache_dir: Directory to use for git cache. None to not use it.
Don Garrettc4114cc2016-11-01 20:04:06 -0700149 """
Don Garrett125d4dc2017-04-25 16:26:03 -0700150 logging.PrintBuildbotStepText('Branch: %s' % branchname)
Don Garrett7ade05a2017-02-17 13:31:47 -0800151 logging.info('Bootstrap script starting initial sync on branch: %s',
152 branchname)
153
Don Garrett86881cb2017-02-15 15:41:55 -0800154 site_config = config_lib.GetConfig()
155 manifest_url = site_config.params['MANIFEST_INT_URL']
Don Garrettc4114cc2016-11-01 20:04:06 -0700156
Don Garrett86881cb2017-02-15 15:41:55 -0800157 repo = repository.RepoRepository(manifest_url, buildroot,
158 branch=branchname,
159 git_cache_dir=git_cache_dir)
Don Garrett76496912017-05-11 16:59:11 -0700160 repo.BuildRootGitCleanup(prune_all=True)
161 repo.Sync(detach=True)
Don Garrettc4114cc2016-11-01 20:04:06 -0700162
163
Don Garrett125d4dc2017-04-25 16:26:03 -0700164@StageDecorator
Don Garrett597ddff2017-02-17 18:29:37 -0800165def RunCbuildbot(options):
Don Garrettc4114cc2016-11-01 20:04:06 -0700166 """Start cbuildbot in specified directory with all arguments.
167
168 Args:
Don Garrett597ddff2017-02-17 18:29:37 -0800169 options: Parse command line options.
Don Garrettc4114cc2016-11-01 20:04:06 -0700170
171 Returns:
172 Return code of cbuildbot as an integer.
173 """
Don Garrett597ddff2017-02-17 18:29:37 -0800174 logging.info('Bootstrap cbuildbot in: %s', options.buildroot)
175 cbuildbot_path = os.path.join(
176 options.buildroot, 'chromite', 'bin', 'cbuildbot')
177
178 cmd = sync_stages.BootstrapStage.FilterArgsForTargetCbuildbot(
179 options.buildroot, cbuildbot_path, options)
180
Don Garrett125d4dc2017-04-25 16:26:03 -0700181 cros_build_lib.RunCommand(cmd, cwd=options.buildroot)
Don Garrettc4114cc2016-11-01 20:04:06 -0700182
Don Garrett60967922017-04-12 18:51:44 -0700183
Don Garrettf15d65b2017-04-12 12:39:55 -0700184def ConfigureGlobalEnvironment():
185 """Setup process wide environmental changes."""
Don Garrettf15d65b2017-04-12 12:39:55 -0700186 # Set umask to 022 so files created by buildbot are readable.
187 os.umask(0o22)
188
Don Garrettc4114cc2016-11-01 20:04:06 -0700189
190def main(argv):
191 """main method of script.
192
193 Args:
194 argv: All command line arguments to pass as list of strings.
195
196 Returns:
197 Return code of cbuildbot as an integer.
198 """
Don Garrett125d4dc2017-04-25 16:26:03 -0700199 logging.EnableBuildbotMarkers()
Don Garrettf15d65b2017-04-12 12:39:55 -0700200 ConfigureGlobalEnvironment()
201
Don Garrett86881cb2017-02-15 15:41:55 -0800202 options = PreParseArguments(argv)
Don Garrettc4114cc2016-11-01 20:04:06 -0700203
Don Garrett125d4dc2017-04-25 16:26:03 -0700204 branchname = options.branch or 'master'
Don Garrett86881cb2017-02-15 15:41:55 -0800205 buildroot = options.buildroot
206 git_cache_dir = options.git_cache_dir
207
Don Garrett7ade05a2017-02-17 13:31:47 -0800208 # Sometimes, we have to cleanup things that can break cbuildbot, especially
209 # on the branch.
210 CleanBuildroot(branchname, buildroot)
211
Don Garrett86881cb2017-02-15 15:41:55 -0800212 # Get a checkout close enough the branched cbuildbot can handle it.
213 InitialCheckout(branchname, buildroot, git_cache_dir)
214
215 # Run cbuildbot inside the full ChromeOS checkout, on the specified branch.
Don Garrett125d4dc2017-04-25 16:26:03 -0700216 try:
217 RunCbuildbot(options)
218 except cros_build_lib.RunCommandError as e:
219 return e.result.returncode