blob: 69bbe9df314eff688738faf039a8bae330d3c1f3 [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
18import os
19
20from chromite.cbuildbot import repository
Don Garrett597ddff2017-02-17 18:29:37 -080021from chromite.cbuildbot.stages import sync_stages
Don Garrett86881cb2017-02-15 15:41:55 -080022from chromite.lib import config_lib
Don Garrettc4114cc2016-11-01 20:04:06 -070023from chromite.lib import cros_build_lib
24from chromite.lib import cros_logging as logging
Don Garrettc4114cc2016-11-01 20:04:06 -070025from chromite.lib import osutils
Don Garrett86881cb2017-02-15 15:41:55 -080026from chromite.scripts import cbuildbot
Don Garrettc4114cc2016-11-01 20:04:06 -070027
Don Garrett597ddff2017-02-17 18:29:37 -080028
Don Garrett60967922017-04-12 18:51:44 -070029# This number should be incremented when we change the layout of the buildroot
30# in a non-backwards compatible way. This wipes all buildroots.
31BUILDROOT_BUILDROOT_LAYOUT = 1
32
33
Don Garrett86881cb2017-02-15 15:41:55 -080034def PreParseArguments(argv):
Don Garrettc4114cc2016-11-01 20:04:06 -070035 """Extract the branch name from cbuildbot command line arguments.
36
37 Ignores all arguments, other than the branch name.
38
39 Args:
40 argv: The command line arguments to parse.
41
42 Returns:
43 Branch as a string ('master' if nothing is specified).
44 """
Don Garrett86881cb2017-02-15 15:41:55 -080045 parser = cbuildbot.CreateParser()
Don Garrett597ddff2017-02-17 18:29:37 -080046 options, args = cbuildbot.ParseCommandLine(parser, argv)
Don Garrett86881cb2017-02-15 15:41:55 -080047
48 # This option isn't required for cbuildbot, but is for us.
49 if not options.buildroot:
50 cros_build_lib.Die('--buildroot is a required option.')
51
Don Garrett597ddff2017-02-17 18:29:37 -080052 # Save off the build targets, in a mirror of cbuildbot code.
53 options.build_targets = args
54 options.Freeze()
55
Don Garrett86881cb2017-02-15 15:41:55 -080056 return options
Don Garrettc4114cc2016-11-01 20:04:06 -070057
58
Don Garrett60967922017-04-12 18:51:44 -070059def GetBuildrootState(buildroot):
60 state_file = os.path.join(buildroot, '.cbuildbot_launch_state')
61
62 try:
63 state = osutils.ReadFile(state_file)
64 buildroot_layout, branchname = state.split()
65 buildroot_layout = int(buildroot_layout)
66 return buildroot_layout, branchname
67 except (IOError, ValueError):
68 # If we are unable to either read or parse the state file, we get here.
69 return 0, ''
70
71
72def SetBuildrootState(branchname, buildroot):
73 assert branchname
74 state_file = os.path.join(buildroot, '.cbuildbot_launch_state')
75 new_state = '%d %s' % (BUILDROOT_BUILDROOT_LAYOUT, branchname)
76 osutils.WriteFile(state_file, new_state)
77
78
Don Garrett7ade05a2017-02-17 13:31:47 -080079def CleanBuildroot(branchname, buildroot):
80 """Some kinds of branch transitions break builds.
81
82 This method tries to detect cases where that can happen, and clobber what's
83 needed to succeed. However, the clobbers are costly, and should be avoided
84 if necessary.
85
Don Garrett7ade05a2017-02-17 13:31:47 -080086 Args:
87 branchname: Name of branch to checkout. None for no branch.
88 buildroot: Directory with old buildroot to clean as needed.
89 """
Don Garrett60967922017-04-12 18:51:44 -070090 if branchname is None:
91 # None means TOT for manifest. Not converting to 'master' since I'm not
92 # sure if those are exactly the same in all cases.
93 branchname = 'default'
Don Garrett7ade05a2017-02-17 13:31:47 -080094
Don Garrett60967922017-04-12 18:51:44 -070095 old_buildroot_layout, old_branch = GetBuildrootState(buildroot)
Don Garrette17e1d92017-04-12 15:28:19 -070096
Don Garrett60967922017-04-12 18:51:44 -070097 if old_buildroot_layout != BUILDROOT_BUILDROOT_LAYOUT:
98 logging.warning('Wiping buildboot.')
99 osutils.RmDir(buildroot, ignore_missing=True, sudo=True)
Don Garrette17e1d92017-04-12 15:28:19 -0700100
Don Garrett60967922017-04-12 18:51:44 -0700101 elif old_branch != branchname:
Don Garrett7ade05a2017-02-17 13:31:47 -0800102 # If we are changing branches, clobber the chroot. Note that this chroot
103 # clobber is unsafe if the chroot is in use, but since no build is in
104 # progress (and we don't use chroot the), this should be okay.
Don Garrett60967922017-04-12 18:51:44 -0700105 logging.info('Unmatched branch: %s -> %s', old_branch, branchname)
Don Garrett39963602017-02-27 14:41:58 -0800106
107 # Wipe chroot.
Don Garrett60967922017-04-12 18:51:44 -0700108 logging.info('Remove Chroot.')
Don Garrett7ade05a2017-02-17 13:31:47 -0800109 osutils.RmDir(os.path.join(buildroot, 'chroot'),
110 ignore_missing=True, sudo=True)
111
Don Garrett39963602017-02-27 14:41:58 -0800112 # Wipe Chrome build related files.
Don Garrett60967922017-04-12 18:51:44 -0700113 logging.info('Remove Chrome checkout.')
Don Garrett39963602017-02-27 14:41:58 -0800114 osutils.RmDir(os.path.join(buildroot, '.cache', 'distfiles'),
115 ignore_missing=True, sudo=True)
116
Don Garrett60967922017-04-12 18:51:44 -0700117 # Ensure buildroot exists.
118 osutils.SafeMakedirs(buildroot)
119 SetBuildrootState(branchname, buildroot)
Don Garrett7ade05a2017-02-17 13:31:47 -0800120
121
Don Garrett86881cb2017-02-15 15:41:55 -0800122def InitialCheckout(branchname, buildroot, git_cache_dir):
123 """Preliminary ChromeOS checkout.
124
125 Perform a complete checkout of ChromeOS on the specified branch. This does NOT
126 match what the build needs, but ensures the buildroot both has a 'hot'
127 checkout, and is close enough that the branched cbuildbot can successfully get
128 the right checkout.
129
130 This checks out full ChromeOS, even if a ChromiumOS build is going to be
131 performed. This is because we have no knowledge of the build config to be
132 used.
Don Garrettc4114cc2016-11-01 20:04:06 -0700133
134 Args:
Don Garrett86881cb2017-02-15 15:41:55 -0800135 branchname: Name of branch to checkout. None for no branch.
136 buildroot: Directory to checkout into.
137 git_cache_dir: Directory to use for git cache. None to not use it.
Don Garrettc4114cc2016-11-01 20:04:06 -0700138 """
Don Garrett7ade05a2017-02-17 13:31:47 -0800139 logging.info('Bootstrap script starting initial sync on branch: %s',
140 branchname)
141
Don Garrett86881cb2017-02-15 15:41:55 -0800142 site_config = config_lib.GetConfig()
143 manifest_url = site_config.params['MANIFEST_INT_URL']
Don Garrettc4114cc2016-11-01 20:04:06 -0700144
Don Garrett86881cb2017-02-15 15:41:55 -0800145 repo = repository.RepoRepository(manifest_url, buildroot,
146 branch=branchname,
147 git_cache_dir=git_cache_dir)
148 repo.Sync()
Don Garrettc4114cc2016-11-01 20:04:06 -0700149
150
Don Garrett597ddff2017-02-17 18:29:37 -0800151def RunCbuildbot(options):
Don Garrettc4114cc2016-11-01 20:04:06 -0700152 """Start cbuildbot in specified directory with all arguments.
153
154 Args:
Don Garrett597ddff2017-02-17 18:29:37 -0800155 options: Parse command line options.
Don Garrettc4114cc2016-11-01 20:04:06 -0700156
157 Returns:
158 Return code of cbuildbot as an integer.
159 """
Don Garrett597ddff2017-02-17 18:29:37 -0800160 logging.info('Bootstrap cbuildbot in: %s', options.buildroot)
161 cbuildbot_path = os.path.join(
162 options.buildroot, 'chromite', 'bin', 'cbuildbot')
163
164 cmd = sync_stages.BootstrapStage.FilterArgsForTargetCbuildbot(
165 options.buildroot, cbuildbot_path, options)
166
167 result = cros_build_lib.RunCommand(
168 cmd, error_code_ok=True, cwd=options.buildroot)
Don Garrettc4114cc2016-11-01 20:04:06 -0700169
170 logging.debug('cbuildbot result is: %s', result.returncode)
171 return result.returncode
172
Don Garrett60967922017-04-12 18:51:44 -0700173
Don Garrettf15d65b2017-04-12 12:39:55 -0700174def ConfigureGlobalEnvironment():
175 """Setup process wide environmental changes."""
Don Garrettf15d65b2017-04-12 12:39:55 -0700176 # Set umask to 022 so files created by buildbot are readable.
177 os.umask(0o22)
178
Don Garrettc4114cc2016-11-01 20:04:06 -0700179
180def main(argv):
181 """main method of script.
182
183 Args:
184 argv: All command line arguments to pass as list of strings.
185
186 Returns:
187 Return code of cbuildbot as an integer.
188 """
Don Garrettf15d65b2017-04-12 12:39:55 -0700189 ConfigureGlobalEnvironment()
190
Don Garrettc4114cc2016-11-01 20:04:06 -0700191 # Specified branch, or 'master'
Don Garrett86881cb2017-02-15 15:41:55 -0800192 options = PreParseArguments(argv)
Don Garrettc4114cc2016-11-01 20:04:06 -0700193
Don Garrett86881cb2017-02-15 15:41:55 -0800194 branchname = options.branch
195 buildroot = options.buildroot
196 git_cache_dir = options.git_cache_dir
197
Don Garrett7ade05a2017-02-17 13:31:47 -0800198 # Sometimes, we have to cleanup things that can break cbuildbot, especially
199 # on the branch.
200 CleanBuildroot(branchname, buildroot)
201
Don Garrett86881cb2017-02-15 15:41:55 -0800202 # Get a checkout close enough the branched cbuildbot can handle it.
203 InitialCheckout(branchname, buildroot, git_cache_dir)
204
205 # Run cbuildbot inside the full ChromeOS checkout, on the specified branch.
Don Garrett597ddff2017-02-17 18:29:37 -0800206 return RunCbuildbot(options)