blob: 1c12fd3ba91606959c1a1585fcb8ce1b4aa92b20 [file] [log] [blame]
Bob Haarmand1225ea2022-01-19 22:01:42 +00001# Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
David James8c846492011-01-25 17:07:29 -08002# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
Brian Harringaf019fb2012-05-10 15:06:13 -07005"""This script is used to upload host prebuilts as well as board BINHOSTS.
David James8c846492011-01-25 17:07:29 -08006
David James015af872012-06-19 15:24:36 -07007Prebuilts are uploaded using gsutil to Google Storage. After these prebuilts
8are successfully uploaded, a file is updated with the proper BINHOST version.
David James8c846492011-01-25 17:07:29 -08009
10To read more about prebuilts/binhost binary packages please refer to:
David James015af872012-06-19 15:24:36 -070011http://goto/chromeos-prebuilts
David James8c846492011-01-25 17:07:29 -080012
13Example of uploading prebuilt amd64 host files to Google Storage:
Mike Nicholsd0acc7f2021-05-21 17:18:24 +000014upload_prebuilts -p /b/cbuild/build -s -u gs://chromeos-prebuilt
David James8c846492011-01-25 17:07:29 -080015
16Example of uploading x86-dogfood binhosts to Google Storage:
Mike Nicholsd0acc7f2021-05-21 17:18:24 +000017upload_prebuilts -b x86-dogfood -p /b/cbuild/build/ -u gs://chromeos-prebuilt -g
David James8c846492011-01-25 17:07:29 -080018"""
19
Mike Frysingerb87bb782015-06-04 02:46:50 -040020import argparse
Chris Sosa1dc96132012-05-11 15:40:50 -070021import datetime
Mike Frysinger540883b2014-05-24 13:46:16 -040022import functools
David Jamesb26b9312014-12-15 11:26:46 -080023import glob
Chris McDonaldb55b7032021-06-17 16:41:32 -060024import logging
Chris Sosa1dc96132012-05-11 15:40:50 -070025import multiprocessing
Chris Sosa1dc96132012-05-11 15:40:50 -070026import os
Mike Frysinger212e4292014-05-24 15:15:44 -040027import tempfile
Chris Sosa1dc96132012-05-11 15:40:50 -070028
Chris McDonaldb55b7032021-06-17 16:41:32 -060029from chromite.cbuildbot import cbuildbot_alerts
David James14e97772014-06-04 18:44:49 -070030from chromite.cbuildbot import commands
David James6450a0a2012-12-04 07:59:53 -080031from chromite.lib import binpkg
Mike Frysinger86509232014-05-24 13:18:37 -040032from chromite.lib import commandline
Chris McDonaldb55b7032021-06-17 16:41:32 -060033from chromite.lib import constants
Chris Sosa1dc96132012-05-11 15:40:50 -070034from chromite.lib import cros_build_lib
Julio Hurtadofad17992021-05-20 21:24:24 +000035from chromite.lib import gerrit
Mike Frysinger807d8282022-04-28 22:45:17 -040036from chromite.lib import git
Brian Harring7904b482012-08-08 02:54:12 -070037from chromite.lib import gs
Brian Harringaf019fb2012-05-10 15:06:13 -070038from chromite.lib import osutils
David James6450a0a2012-12-04 07:59:53 -080039from chromite.lib import parallel
Alex Deymo075c2292014-09-04 18:31:50 -070040from chromite.lib import portage_util
Mike Frysinger8e727a32013-01-16 16:57:53 -050041from chromite.lib import toolchain
Alex Klein18a60af2020-06-11 12:08:47 -060042from chromite.lib.parser import package_info
Chris Sosa1dc96132012-05-11 15:40:50 -070043
Mike Frysinger72b7cf92020-04-19 06:00:51 -040044
David James015af872012-06-19 15:24:36 -070045# How many times to retry uploads.
46_RETRIES = 10
47
48# Multiplier for how long to sleep (in seconds) between retries; will delay
49# (1*sleep) the first time, then (2*sleep), continuing via attempt * sleep.
50_SLEEP_TIME = 60
51
David James5ab67e32014-10-24 08:19:59 -070052# The length of time (in seconds) that Portage should wait before refetching
53# binpkgs from the same binhost. We don't ever modify binhosts, so this should
54# be something big.
55_BINPKG_TTL = 60 * 60 * 24 * 365
56
Bob Haarmand1225ea2022-01-19 22:01:42 +000057_HOST_PACKAGES_PATH = 'var/lib/portage/pkgs'
David James05bcb2b2011-02-09 09:25:47 -080058_CATEGORIES_PATH = 'chroot/etc/portage/categories'
David James615e5b52011-06-03 11:10:15 -070059_PYM_PATH = 'chroot/usr/lib/portage/pym'
David James4058b0d2011-12-08 21:24:50 -080060_HOST_ARCH = 'amd64'
David James8c846492011-01-25 17:07:29 -080061_BOARD_PATH = 'chroot/build/%(board)s'
David James4058b0d2011-12-08 21:24:50 -080062_REL_BOARD_PATH = 'board/%(target)s/%(version)s'
63_REL_HOST_PATH = 'host/%(host_arch)s/%(target)s/%(version)s'
David James8c846492011-01-25 17:07:29 -080064# Private overlays to look at for builds to filter
65# relative to build path
66_PRIVATE_OVERLAY_DIR = 'src/private-overlays'
Gabe Black40169e62014-06-17 15:23:47 -070067_GOOGLESTORAGE_GSUTIL_FILE = 'googlestorage_acl.txt'
David James3753d942014-04-23 10:55:48 -070068_BINHOST_BASE_URL = 'gs://chromeos-prebuilt'
David James8c846492011-01-25 17:07:29 -080069_PREBUILT_BASE_DIR = 'src/third_party/chromiumos-overlay/chromeos/config/'
70# Created in the event of new host targets becoming available
71_PREBUILT_MAKE_CONF = {'amd64': os.path.join(_PREBUILT_BASE_DIR,
72 'make.conf.amd64-host')}
David James8c846492011-01-25 17:07:29 -080073
74
David James4058b0d2011-12-08 21:24:50 -080075class BuildTarget(object):
76 """A board/variant/profile tuple."""
77
78 def __init__(self, board_variant, profile=None):
79 self.board_variant = board_variant
80 self.board, _, self.variant = board_variant.partition('_')
81 self.profile = profile
82
83 def __str__(self):
84 if self.profile:
85 return '%s_%s' % (self.board_variant, self.profile)
86 else:
87 return self.board_variant
88
89 def __eq__(self, other):
90 return str(other) == str(self)
91
92 def __hash__(self):
93 return hash(str(self))
94
95
David James8c846492011-01-25 17:07:29 -080096def UpdateLocalFile(filename, value, key='PORTAGE_BINHOST'):
97 """Update the key in file with the value passed.
Mike Frysinger1a736a82013-12-12 01:50:59 -050098
David James8c846492011-01-25 17:07:29 -080099 File format:
100 key="value"
101 Note quotes are added automatically
102
103 Args:
104 filename: Name of file to modify.
105 value: Value to write with the key.
106 key: The variable key to update. (Default: PORTAGE_BINHOST)
David Jamesb26b9312014-12-15 11:26:46 -0800107
108 Returns:
109 True if changes were made to the file.
David James8c846492011-01-25 17:07:29 -0800110 """
Sergey Frolov0cd98cc2022-06-06 17:47:32 -0600111 with open(filename, 'a+') as file_fh:
112 file_lines = []
113 found = False
114 made_changes = False
115 keyval_str = '%(key)s=%(value)s'
116 for line in file_fh:
117 # Strip newlines from end of line. We already add newlines below.
118 line = line.rstrip('\n')
David James8c846492011-01-25 17:07:29 -0800119
Sergey Frolov0cd98cc2022-06-06 17:47:32 -0600120 if len(line.split('=')) != 2:
121 # Skip any line that doesn't fit key=val.
122 file_lines.append(line)
123 continue
David James8c846492011-01-25 17:07:29 -0800124
Sergey Frolov0cd98cc2022-06-06 17:47:32 -0600125 file_var, file_val = line.split('=')
126 if file_var == key:
127 found = True
128 print('Updating %s=%s to %s="%s"' % (file_var, file_val, key, value))
129 value = '"%s"' % value
130 made_changes |= (file_val != value)
131 file_lines.append(keyval_str % {'key': key, 'value': value})
132 else:
133 file_lines.append(keyval_str % {'key': file_var, 'value': file_val})
134
135 if not found:
David James8c846492011-01-25 17:07:29 -0800136 value = '"%s"' % value
Sergey Frolov0cd98cc2022-06-06 17:47:32 -0600137 made_changes = True
David James8c846492011-01-25 17:07:29 -0800138 file_lines.append(keyval_str % {'key': key, 'value': value})
David James8c846492011-01-25 17:07:29 -0800139
David James8c846492011-01-25 17:07:29 -0800140 # write out new file
Brian Harringaf019fb2012-05-10 15:06:13 -0700141 osutils.WriteFile(filename, '\n'.join(file_lines) + '\n')
David Jamesb26b9312014-12-15 11:26:46 -0800142 return made_changes
David James8c846492011-01-25 17:07:29 -0800143
144
Mike Nicholsa6818c52018-04-09 11:05:42 -0600145def RevGitFile(filename, data, dryrun=False):
David James8c846492011-01-25 17:07:29 -0800146 """Update and push the git file.
147
Mike Frysinger5b34d732013-01-17 15:11:58 -0500148 Args:
149 filename: file to modify that is in a git repo already
150 data: A dict of key/values to update in |filename|
Matt Tennante8179042013-10-01 15:47:32 -0700151 dryrun: If True, do not actually commit the change.
David James8c846492011-01-25 17:07:29 -0800152 """
153 prebuilt_branch = 'prebuilt_branch'
David James1b6e67a2011-05-19 21:32:38 -0700154 cwd = os.path.abspath(os.path.dirname(filename))
Julio Hurtadofad17992021-05-20 21:24:24 +0000155 remote_name = git.RunGit(cwd, ['remote']).stdout.strip()
156 gerrit_helper = gerrit.GetGerritHelper(remote_name)
157 remote_url = git.RunGit(
Julio Hurtadoef27d992021-06-29 15:51:13 +0000158 cwd, ['config', '--get', f'remote.{remote_name}.url']).stdout.strip()
Mike Frysinger5b34d732013-01-17 15:11:58 -0500159 description = '%s: updating %s' % (os.path.basename(filename),
160 ', '.join(data.keys()))
161 # UpdateLocalFile will print out the keys/values for us.
Mike Frysingerff441bf2014-05-24 13:47:21 -0400162 print('Revving git file %s' % filename)
Julio Hurtadofad17992021-05-20 21:24:24 +0000163 git.CreatePushBranch(prebuilt_branch, cwd)
164 for key, value in data.items():
165 UpdateLocalFile(filename, value, key)
166 git.RunGit(cwd, ['add', filename])
167 git.RunGit(cwd, ['commit', '-m', description])
Julio Hurtado2d4817d2021-04-29 16:03:58 +0000168
Julio Hurtadofad17992021-05-20 21:24:24 +0000169 tracking_info = git.GetTrackingBranch(
170 cwd, prebuilt_branch, for_push=True, for_checkout=False)
171 gpatch = gerrit_helper.CreateGerritPatch(
Julio Hurtado8f716a32021-07-14 21:32:13 +0000172 cwd, remote_url, ref=tracking_info.ref, notify='NONE')
Julio Hurtadoef27d992021-06-29 15:51:13 +0000173 gerrit_helper.SetReview(
174 gpatch, labels={'Bot-Commit': 1}, dryrun=dryrun, notify='NONE')
175 gerrit_helper.SubmitChange(gpatch, dryrun=dryrun, notify='NONE')
David James8c846492011-01-25 17:07:29 -0800176
177
178def GetVersion():
179 """Get the version to put in LATEST and update the git version with."""
Mike Frysinger0b92cfe2012-12-13 02:13:45 -0500180 return datetime.datetime.now().strftime('%Y.%m.%d.%H%M%S')
David James8c846492011-01-25 17:07:29 -0800181
182
Mike Frysinger540883b2014-05-24 13:46:16 -0400183def _GsUpload(gs_context, acl, local_file, remote_file):
David James8c846492011-01-25 17:07:29 -0800184 """Upload to GS bucket.
185
186 Args:
Mike Frysinger540883b2014-05-24 13:46:16 -0400187 gs_context: A lib.gs.GSContext instance.
188 acl: The ACL to use for uploading the file.
Matt Tennante8179042013-10-01 15:47:32 -0700189 local_file: The local file to be uploaded.
190 remote_file: The remote location to upload to.
David James8c846492011-01-25 17:07:29 -0800191 """
Scott Zawalskiab1bed32011-03-16 15:24:24 -0700192 CANNED_ACLS = ['public-read', 'private', 'bucket-owner-read',
193 'authenticated-read', 'bucket-owner-full-control',
194 'public-read-write']
Scott Zawalskiab1bed32011-03-16 15:24:24 -0700195 if acl in CANNED_ACLS:
David James9374aac2013-10-08 16:00:17 -0700196 gs_context.Copy(local_file, remote_file, acl=acl)
Scott Zawalskiab1bed32011-03-16 15:24:24 -0700197 else:
198 # For private uploads we assume that the overlay board is set up properly
David James015af872012-06-19 15:24:36 -0700199 # and a googlestore_acl.xml is present. Otherwise, this script errors.
David James7b7d7c32015-04-02 13:48:17 -0700200 # We set version=0 here to ensure that the ACL is set only once (see
201 # http://b/15883752#comment54).
202 try:
203 gs_context.Copy(local_file, remote_file, version=0)
204 except gs.GSContextPreconditionFailed as ex:
205 # If we received a GSContextPreconditionFailed error, we know that the
206 # file exists now, but we don't know whether our specific update
207 # succeeded. See http://b/15883752#comment62
208 logging.warning(
209 'Assuming upload succeeded despite PreconditionFailed errors: %s', ex)
210
Gabe Black40169e62014-06-17 15:23:47 -0700211 if acl.endswith('.xml'):
212 # Apply the passed in ACL xml file to the uploaded object.
213 gs_context.SetACL(remote_file, acl=acl)
214 else:
Mike Frysinger5186f262017-09-13 10:26:19 -0400215 gs_context.ChangeACL(remote_file, acl_args_file=acl)
Scott Zawalskiab1bed32011-03-16 15:24:24 -0700216
Mike Frysingercc838832014-05-24 13:10:30 -0400217
Mike Frysinger540883b2014-05-24 13:46:16 -0400218def RemoteUpload(gs_context, acl, files, pool=10):
David James8c846492011-01-25 17:07:29 -0800219 """Upload to google storage.
220
221 Create a pool of process and call _GsUpload with the proper arguments.
222
223 Args:
Mike Frysinger540883b2014-05-24 13:46:16 -0400224 gs_context: A lib.gs.GSContext instance.
David Jamesfd0b0852011-02-23 11:15:36 -0800225 acl: The canned acl used for uploading. acl can be one of: "public-read",
226 "public-read-write", "authenticated-read", "bucket-owner-read",
227 "bucket-owner-full-control", or "private".
David James8c846492011-01-25 17:07:29 -0800228 files: dictionary with keys to local files and values to remote path.
229 pool: integer of maximum proesses to have at the same time.
230
231 Returns:
232 Return a set of tuple arguments of the failed uploads
233 """
Mike Frysinger540883b2014-05-24 13:46:16 -0400234 upload = functools.partial(_GsUpload, gs_context, acl)
Mike Frysinger0bdbc102019-06-13 15:27:29 -0400235 tasks = [[key, value] for key, value in files.items()]
Mike Frysinger540883b2014-05-24 13:46:16 -0400236 parallel.RunTasksInProcessPool(upload, tasks, pool)
David James8c846492011-01-25 17:07:29 -0800237
238
239def GenerateUploadDict(base_local_path, base_remote_path, pkgs):
240 """Build a dictionary of local remote file key pairs to upload.
241
242 Args:
243 base_local_path: The base path to the files on the local hard drive.
Matt Tennante8179042013-10-01 15:47:32 -0700244 base_remote_path: The base path to the remote paths.
David James8c846492011-01-25 17:07:29 -0800245 pkgs: The packages to upload.
246
247 Returns:
248 Returns a dictionary of local_path/remote_path pairs
249 """
250 upload_files = {}
251 for pkg in pkgs:
252 suffix = pkg['CPV'] + '.tbz2'
253 local_path = os.path.join(base_local_path, suffix)
David James7b7d7c32015-04-02 13:48:17 -0700254 assert os.path.exists(local_path), '%s does not exist' % local_path
Bertrand SIMONNET811bcde2014-11-20 15:21:25 -0800255 upload_files[local_path] = os.path.join(base_remote_path, suffix)
David James8c846492011-01-25 17:07:29 -0800256
Bertrand SIMONNET811bcde2014-11-20 15:21:25 -0800257 if pkg.get('DEBUG_SYMBOLS') == 'yes':
258 debugsuffix = pkg['CPV'] + '.debug.tbz2'
259 local_path = os.path.join(base_local_path, debugsuffix)
260 assert os.path.exists(local_path)
261 upload_files[local_path] = os.path.join(base_remote_path, debugsuffix)
Bertrand SIMONNET22e828b2014-11-11 16:27:06 -0800262
David James8c846492011-01-25 17:07:29 -0800263 return upload_files
264
Mike Frysingercc838832014-05-24 13:10:30 -0400265
Peter Mayo950e41a2014-02-06 21:07:33 +0000266def GetBoardOverlay(build_path, target):
David Jamese5867812012-10-19 12:02:20 -0700267 """Get the path to the board variant.
Mike Frysinger1a736a82013-12-12 01:50:59 -0500268
Mike Frysinger6f3c48e2015-05-06 02:38:51 -0400269 Args:
270 build_path: The path to the root of the build directory
271 target: The target board as a BuildTarget object.
Mike Frysinger1a736a82013-12-12 01:50:59 -0500272
Mike Frysinger6f3c48e2015-05-06 02:38:51 -0400273 Returns:
274 The last overlay configured for the given board as a string.
David James8c846492011-01-25 17:07:29 -0800275 """
David Jamese5867812012-10-19 12:02:20 -0700276 board = target.board_variant
Alex Deymo075c2292014-09-04 18:31:50 -0700277 overlays = portage_util.FindOverlays(constants.BOTH_OVERLAYS, board,
278 buildroot=build_path)
David Jamese5867812012-10-19 12:02:20 -0700279 # We only care about the last entry.
280 return overlays[-1]
David James8c846492011-01-25 17:07:29 -0800281
282
283def DeterminePrebuiltConfFile(build_path, target):
284 """Determine the prebuilt.conf file that needs to be updated for prebuilts.
285
Mike Frysinger1a736a82013-12-12 01:50:59 -0500286 Args:
287 build_path: The path to the root of the build directory
288 target: String representation of the board. This includes host and board
289 targets
David James8c846492011-01-25 17:07:29 -0800290
Mike Frysinger1a736a82013-12-12 01:50:59 -0500291 Returns:
292 A string path to a prebuilt.conf file to be updated.
David James8c846492011-01-25 17:07:29 -0800293 """
David James4058b0d2011-12-08 21:24:50 -0800294 if _HOST_ARCH == target:
David James8c846492011-01-25 17:07:29 -0800295 # We are host.
296 # Without more examples of hosts this is a kludge for now.
297 # TODO(Scottz): as new host targets come online expand this to
298 # work more like boards.
Chris Sosa471532a2011-02-01 15:10:06 -0800299 make_path = _PREBUILT_MAKE_CONF[target]
David James8c846492011-01-25 17:07:29 -0800300 else:
301 # We are a board
Peter Mayo950e41a2014-02-06 21:07:33 +0000302 board = GetBoardOverlay(build_path, target)
David James8c846492011-01-25 17:07:29 -0800303 make_path = os.path.join(board, 'prebuilt.conf')
304
305 return make_path
306
307
308def UpdateBinhostConfFile(path, key, value):
309 """Update binhost config file file with key=value.
310
311 Args:
312 path: Filename to update.
313 key: Key to update.
314 value: New value for key.
315 """
David Jamesb26b9312014-12-15 11:26:46 -0800316 cwd, filename = os.path.split(os.path.abspath(path))
Brian Harringaf019fb2012-05-10 15:06:13 -0700317 osutils.SafeMakedirs(cwd)
David Jamesf6e8fb72013-05-10 08:58:43 -0700318 if not git.GetCurrentBranch(cwd):
319 git.CreatePushBranch(constants.STABLE_EBUILD_BRANCH, cwd, sync=False)
Brian Harring22edb442012-05-11 23:55:18 -0700320 osutils.WriteFile(path, '', mode='a')
David Jamesb26b9312014-12-15 11:26:46 -0800321 if UpdateLocalFile(path, value, key):
322 desc = '%s: %s %s' % (filename, 'updating' if value else 'clearing', key)
323 git.AddPath(path)
324 git.Commit(cwd, desc)
David James8c846492011-01-25 17:07:29 -0800325
Achuith Bhandarkar03d924a2018-01-02 10:50:44 -0800326def GenerateHtmlIndex(files, index, board, version, remote_location):
Mike Frysinger212e4292014-05-24 15:15:44 -0400327 """Given the list of |files|, generate an index.html at |index|.
328
329 Args:
330 files: The list of files to link to.
331 index: The path to the html index.
332 board: Name of the board this index is for.
333 version: Build version this index is for.
Achuith Bhandarkar03d924a2018-01-02 10:50:44 -0800334 remote_location: Remote gs location prebuilts are uploaded to.
Mike Frysinger212e4292014-05-24 15:15:44 -0400335 """
Don Garrett13cbbff2016-08-09 14:18:38 -0700336 title = 'Package Prebuilt Index: %s / %s' % (board, version)
Mike Frysinger212e4292014-05-24 15:15:44 -0400337
338 files = files + [
339 '.|Google Storage Index',
340 '..|',
341 ]
Achuith Bhandarkar03d924a2018-01-02 10:50:44 -0800342 commands.GenerateHtmlIndex(index, files, title=title,
343 url_base=gs.GsUrlToHttp(remote_location))
Mike Frysinger212e4292014-05-24 15:15:44 -0400344
345
David Jamesce093af2011-02-23 15:21:58 -0800346def _GrabAllRemotePackageIndexes(binhost_urls):
David James05bcb2b2011-02-09 09:25:47 -0800347 """Grab all of the packages files associated with a list of binhost_urls.
348
David James05bcb2b2011-02-09 09:25:47 -0800349 Args:
350 binhost_urls: The URLs for the directories containing the Packages files we
351 want to grab.
David James05bcb2b2011-02-09 09:25:47 -0800352
353 Returns:
354 A list of PackageIndex objects.
355 """
356 pkg_indexes = []
357 for url in binhost_urls:
David James32faafe2012-06-08 14:25:03 -0700358 pkg_index = binpkg.GrabRemotePackageIndex(url)
David James05bcb2b2011-02-09 09:25:47 -0800359 if pkg_index:
360 pkg_indexes.append(pkg_index)
David James05bcb2b2011-02-09 09:25:47 -0800361 return pkg_indexes
362
363
David Jamesc0f158a2011-02-22 16:07:29 -0800364class PrebuiltUploader(object):
365 """Synchronize host and board prebuilts."""
David James8c846492011-01-25 17:07:29 -0800366
Mike Frysinger86509232014-05-24 13:18:37 -0400367 def __init__(self, upload_location, acl, binhost_base_url, pkg_indexes,
368 build_path, packages, skip_upload, binhost_conf_dir, dryrun,
Bob Haarmand1225ea2022-01-19 22:01:42 +0000369 target, slave_targets, version, chroot=None):
David Jamesc0f158a2011-02-22 16:07:29 -0800370 """Constructor for prebuilt uploader object.
David James8c846492011-01-25 17:07:29 -0800371
David Jamesc0f158a2011-02-22 16:07:29 -0800372 This object can upload host or prebuilt files to Google Storage.
David James8c846492011-01-25 17:07:29 -0800373
David Jamesc0f158a2011-02-22 16:07:29 -0800374 Args:
375 upload_location: The upload location.
David Jamesfd0b0852011-02-23 11:15:36 -0800376 acl: The canned acl used for uploading to Google Storage. acl can be one
377 of: "public-read", "public-read-write", "authenticated-read",
Matt Tennante8179042013-10-01 15:47:32 -0700378 "bucket-owner-read", "bucket-owner-full-control", "project-private",
379 or "private" (see "gsutil help acls"). If we are not uploading to
380 Google Storage, this parameter is unused.
David Jamesfd0b0852011-02-23 11:15:36 -0800381 binhost_base_url: The URL used for downloading the prebuilts.
David Jamesc0f158a2011-02-22 16:07:29 -0800382 pkg_indexes: Old uploaded prebuilts to compare against. Instead of
383 uploading duplicate files, we just link to the old files.
David James615e5b52011-06-03 11:10:15 -0700384 build_path: The path to the directory containing the chroot.
385 packages: Packages to upload.
David James32b0b2f2011-07-13 20:56:50 -0700386 skip_upload: Don't actually upload the tarballs.
387 binhost_conf_dir: Directory where to store binhost.conf files.
Mike Frysinger86509232014-05-24 13:18:37 -0400388 dryrun: Don't push or upload prebuilts.
David James4058b0d2011-12-08 21:24:50 -0800389 target: BuildTarget managed by this builder.
390 slave_targets: List of BuildTargets managed by slave builders.
Mike Frysinger8092a632014-05-24 13:25:46 -0400391 version: A unique string, intended to be included in the upload path,
392 which identifies the version number of the uploaded prebuilts.
Bob Haarmand1225ea2022-01-19 22:01:42 +0000393 chroot: Path to the chroot containing the prebuilts.
David Jamesc0f158a2011-02-22 16:07:29 -0800394 """
395 self._upload_location = upload_location
David Jamesfd0b0852011-02-23 11:15:36 -0800396 self._acl = acl
David Jamesc0f158a2011-02-22 16:07:29 -0800397 self._binhost_base_url = binhost_base_url
398 self._pkg_indexes = pkg_indexes
David James615e5b52011-06-03 11:10:15 -0700399 self._build_path = build_path
400 self._packages = set(packages)
Mike Frysingerf5f809a2013-02-12 13:47:37 -0500401 self._found_packages = set()
David James8ece7ee2011-06-29 16:02:30 -0700402 self._skip_upload = skip_upload
David James32b0b2f2011-07-13 20:56:50 -0700403 self._binhost_conf_dir = binhost_conf_dir
Mike Frysinger86509232014-05-24 13:18:37 -0400404 self._dryrun = dryrun
David James4058b0d2011-12-08 21:24:50 -0800405 self._target = target
406 self._slave_targets = slave_targets
Mike Frysinger8092a632014-05-24 13:25:46 -0400407 self._version = version
Bob Haarmand1225ea2022-01-19 22:01:42 +0000408 self._chroot = chroot or os.path.join(build_path,
409 constants.DEFAULT_CHROOT_DIR)
Mike Frysinger540883b2014-05-24 13:46:16 -0400410 self._gs_context = gs.GSContext(retries=_RETRIES, sleep=_SLEEP_TIME,
411 dry_run=self._dryrun)
412
413 def _Upload(self, local_file, remote_file):
414 """Wrapper around _GsUpload"""
415 _GsUpload(self._gs_context, self._acl, local_file, remote_file)
David James615e5b52011-06-03 11:10:15 -0700416
417 def _ShouldFilterPackage(self, pkg):
418 if not self._packages:
419 return False
Alex Klein18a60af2020-06-11 12:08:47 -0600420 cpv = package_info.SplitCPV(pkg['CPV'])
Alex Klein9f93b482018-10-01 09:26:51 -0600421 self._found_packages.add(cpv.cp)
422 return cpv.package not in self._packages and cpv.cp not in self._packages
David James8c846492011-01-25 17:07:29 -0800423
David Jamesc0f158a2011-02-22 16:07:29 -0800424 def _UploadPrebuilt(self, package_path, url_suffix):
425 """Upload host or board prebuilt files to Google Storage space.
David James8c846492011-01-25 17:07:29 -0800426
David Jamesc0f158a2011-02-22 16:07:29 -0800427 Args:
428 package_path: The path to the packages dir.
David Jamesce093af2011-02-23 15:21:58 -0800429 url_suffix: The remote subdirectory where we should upload the packages.
David Jamesc0f158a2011-02-22 16:07:29 -0800430 """
David Jamesc0f158a2011-02-22 16:07:29 -0800431 # Process Packages file, removing duplicates and filtered packages.
David James32faafe2012-06-08 14:25:03 -0700432 pkg_index = binpkg.GrabLocalPackageIndex(package_path)
David Jamesc0f158a2011-02-22 16:07:29 -0800433 pkg_index.SetUploadLocation(self._binhost_base_url, url_suffix)
David James615e5b52011-06-03 11:10:15 -0700434 pkg_index.RemoveFilteredPackages(self._ShouldFilterPackage)
David Jamesc0f158a2011-02-22 16:07:29 -0800435 uploads = pkg_index.ResolveDuplicateUploads(self._pkg_indexes)
Mike Frysingerf5f809a2013-02-12 13:47:37 -0500436 unmatched_pkgs = self._packages - self._found_packages
437 if unmatched_pkgs:
Lann Martinffb95162018-08-28 12:02:54 -0600438 logging.warning('unable to match packages: %r', unmatched_pkgs)
David James05bcb2b2011-02-09 09:25:47 -0800439
David Jamesc0f158a2011-02-22 16:07:29 -0800440 # Write Packages file.
David James5ab67e32014-10-24 08:19:59 -0700441 pkg_index.header['TTL'] = _BINPKG_TTL
David Jamesc0f158a2011-02-22 16:07:29 -0800442 tmp_packages_file = pkg_index.WriteToNamedTemporaryFile()
David James05bcb2b2011-02-09 09:25:47 -0800443
David Jamesc0f158a2011-02-22 16:07:29 -0800444 remote_location = '%s/%s' % (self._upload_location.rstrip('/'), url_suffix)
David James015af872012-06-19 15:24:36 -0700445 assert remote_location.startswith('gs://')
David James05bcb2b2011-02-09 09:25:47 -0800446
David James015af872012-06-19 15:24:36 -0700447 upload_files = GenerateUploadDict(package_path, remote_location, uploads)
448 remote_file = '%s/Packages' % remote_location.rstrip('/')
449 upload_files[tmp_packages_file.name] = remote_file
450
Mike Frysinger9bb6cd82020-08-20 03:02:23 -0400451 # Build list of files to upload. Manually include the dev-only files but
452 # skip them if not present.
453 dev_only = os.path.join(package_path, 'dev-only-extras.tar.xz')
454 if os.path.exists(dev_only):
455 upload_files[dev_only] = '%s/%s' % (
456 remote_location.rstrip('/'), os.path.basename(dev_only))
457
Mike Frysinger540883b2014-05-24 13:46:16 -0400458 RemoteUpload(self._gs_context, self._acl, upload_files)
David James8c846492011-01-25 17:07:29 -0800459
Mike Frysinger212e4292014-05-24 15:15:44 -0400460 with tempfile.NamedTemporaryFile(
461 prefix='chromite.upload_prebuilts.index.') as index:
462 GenerateHtmlIndex(
463 [x[len(remote_location) + 1:] for x in upload_files.values()],
Achuith Bhandarkar03d924a2018-01-02 10:50:44 -0800464 index.name, self._target, self._version, remote_location)
Mike Frysinger212e4292014-05-24 15:15:44 -0400465 self._Upload(index.name, '%s/index.html' % remote_location.rstrip('/'))
466
467 link_name = 'Prebuilts[%s]: %s' % (self._target, self._version)
468 url = '%s%s/index.html' % (gs.PUBLIC_BASE_HTTPS_URL,
469 remote_location[len(gs.BASE_GS_URL):])
Chris McDonaldb55b7032021-06-17 16:41:32 -0600470 cbuildbot_alerts.PrintBuildbotLink(link_name, url)
Mike Frysinger212e4292014-05-24 15:15:44 -0400471
Mike Frysinger8092a632014-05-24 13:25:46 -0400472 def _UploadSdkTarball(self, board_path, url_suffix, prepackaged,
Gilad Arnold2b79e2d2015-06-02 11:26:07 -0700473 toolchains_overlay_tarballs,
474 toolchains_overlay_upload_path,
Mike Frysinger9e979b92012-11-29 02:55:09 -0500475 toolchain_tarballs, toolchain_upload_path):
476 """Upload a tarball of the sdk at the specified path to Google Storage.
David James8fa34ea2011-04-15 13:00:20 -0700477
478 Args:
479 board_path: The path to the board dir.
480 url_suffix: The remote subdirectory where we should upload the packages.
Zdenek Behan62a57792012-08-31 15:09:08 +0200481 prepackaged: If given, a tarball that has been packaged outside of this
482 script and should be used.
Gilad Arnold2b79e2d2015-06-02 11:26:07 -0700483 toolchains_overlay_tarballs: List of toolchains overlay tarball
484 specifications to upload. Items take the form
485 "toolchains_spec:/path/to/tarball".
486 toolchains_overlay_upload_path: Path template under the bucket to place
487 toolchains overlay tarballs.
Mike Frysinger9e979b92012-11-29 02:55:09 -0500488 toolchain_tarballs: List of toolchain tarballs to upload.
489 toolchain_upload_path: Path under the bucket to place toolchain tarballs.
David James8fa34ea2011-04-15 13:00:20 -0700490 """
491 remote_location = '%s/%s' % (self._upload_location.rstrip('/'), url_suffix)
492 assert remote_location.startswith('gs://')
Zdenek Behan86c15e92012-10-13 00:55:47 +0200493 boardname = os.path.basename(board_path.rstrip('/'))
494 # We do not upload non SDK board tarballs,
495 assert boardname == constants.CHROOT_BUILDER_BOARD
496 assert prepackaged is not None
Zdenek Behan62a57792012-08-31 15:09:08 +0200497
Mike Frysinger8092a632014-05-24 13:25:46 -0400498 version_str = self._version[len('chroot-'):]
Mike Frysinger8e727a32013-01-16 16:57:53 -0500499 remote_tarfile = toolchain.GetSdkURL(
500 for_gsutil=True, suburl='cros-sdk-%s.tar.xz' % (version_str,))
Zdenek Behan86c15e92012-10-13 00:55:47 +0200501 # For SDK, also upload the manifest which is guaranteed to exist
502 # by the builderstage.
Mike Frysinger540883b2014-05-24 13:46:16 -0400503 self._Upload(prepackaged + '.Manifest', remote_tarfile + '.Manifest')
504 self._Upload(prepackaged, remote_tarfile)
Zdenek Behan86c15e92012-10-13 00:55:47 +0200505
Gilad Arnold2b79e2d2015-06-02 11:26:07 -0700506 # Upload SDK toolchains overlays and toolchain tarballs, if given.
Gilad Arnoldad333182015-05-27 15:50:41 -0700507 for tarball_list, upload_path, qualifier_name in (
Gilad Arnold2b79e2d2015-06-02 11:26:07 -0700508 (toolchains_overlay_tarballs, toolchains_overlay_upload_path,
509 'toolchains'),
Gilad Arnoldad333182015-05-27 15:50:41 -0700510 (toolchain_tarballs, toolchain_upload_path, 'target')):
Gilad Arnold2b79e2d2015-06-02 11:26:07 -0700511 for tarball_spec in tarball_list:
512 qualifier_val, local_path = tarball_spec.split(':')
Gilad Arnoldad333182015-05-27 15:50:41 -0700513 suburl = upload_path % {qualifier_name: qualifier_val}
514 remote_path = toolchain.GetSdkURL(for_gsutil=True, suburl=suburl)
515 self._Upload(local_path, remote_path)
Mike Frysinger9e979b92012-11-29 02:55:09 -0500516
Zdenek Behan86c15e92012-10-13 00:55:47 +0200517 # Finally, also update the pointer to the latest SDK on which polling
518 # scripts rely.
David James4bc13702013-03-26 08:08:04 -0700519 with osutils.TempDir() as tmpdir:
Zdenek Behan86c15e92012-10-13 00:55:47 +0200520 pointerfile = os.path.join(tmpdir, 'cros-sdk-latest.conf')
Mike Frysinger8e727a32013-01-16 16:57:53 -0500521 remote_pointerfile = toolchain.GetSdkURL(for_gsutil=True,
522 suburl='cros-sdk-latest.conf')
Zdenek Behan86c15e92012-10-13 00:55:47 +0200523 osutils.WriteFile(pointerfile, 'LATEST_SDK="%s"' % version_str)
Mike Frysinger540883b2014-05-24 13:46:16 -0400524 self._Upload(pointerfile, remote_pointerfile)
Zdenek Behan33a34112012-09-10 21:07:51 +0200525
Chris Sosa6a5dceb2012-05-14 13:48:56 -0700526 def _GetTargets(self):
527 """Retuns the list of targets to use."""
528 targets = self._slave_targets[:]
529 if self._target:
530 targets.append(self._target)
531
532 return targets
533
Mike Frysinger8092a632014-05-24 13:25:46 -0400534 def SyncHostPrebuilts(self, key, git_sync, sync_binhost_conf):
David Jamesc0f158a2011-02-22 16:07:29 -0800535 """Synchronize host prebuilt files.
David James05bcb2b2011-02-09 09:25:47 -0800536
David Jamesc0f158a2011-02-22 16:07:29 -0800537 This function will sync both the standard host packages, plus the host
538 packages associated with all targets that have been "setup" with the
539 current host's chroot. For instance, if this host has been used to build
540 x86-generic, it will sync the host packages associated with
541 'i686-pc-linux-gnu'. If this host has also been used to build arm-generic,
542 it will also sync the host packages associated with
543 'armv7a-cros-linux-gnueabi'.
David James05bcb2b2011-02-09 09:25:47 -0800544
David Jamesc0f158a2011-02-22 16:07:29 -0800545 Args:
David Jamesc0f158a2011-02-22 16:07:29 -0800546 key: The variable key to update in the git file.
547 git_sync: If set, update make.conf of target to reference the latest
548 prebuilt packages generated here.
549 sync_binhost_conf: If set, update binhost config file in
550 chromiumos-overlay for the host.
551 """
Mike Nicholsa1414162021-04-22 20:07:22 +0000552 # Slave boards are listed before the master board so that the master board
David Jamese2488642011-11-14 16:15:20 -0800553 # takes priority (i.e. x86-generic preflight host prebuilts takes priority
554 # over preflight host prebuilts from other builders.)
555 binhost_urls = []
Chris Sosa6a5dceb2012-05-14 13:48:56 -0700556 for target in self._GetTargets():
Mike Frysinger8092a632014-05-24 13:25:46 -0400557 url_suffix = _REL_HOST_PATH % {'version': self._version,
David James4058b0d2011-12-08 21:24:50 -0800558 'host_arch': _HOST_ARCH,
559 'target': target}
David Jamese2488642011-11-14 16:15:20 -0800560 packages_url_suffix = '%s/packages' % url_suffix.rstrip('/')
David James05bcb2b2011-02-09 09:25:47 -0800561
Mike Frysinger540883b2014-05-24 13:46:16 -0400562 if self._target == target and not self._skip_upload:
David Jamese2488642011-11-14 16:15:20 -0800563 # Upload prebuilts.
Bob Haarmand1225ea2022-01-19 22:01:42 +0000564 package_path = os.path.join(self._chroot, _HOST_PACKAGES_PATH)
David Jamese2488642011-11-14 16:15:20 -0800565 self._UploadPrebuilt(package_path, packages_url_suffix)
David James8ece7ee2011-06-29 16:02:30 -0700566
David Jamese2488642011-11-14 16:15:20 -0800567 # Record URL where prebuilts were uploaded.
568 binhost_urls.append('%s/%s/' % (self._binhost_base_url.rstrip('/'),
569 packages_url_suffix.rstrip('/')))
570
David James20b2b6f2011-11-18 15:11:58 -0800571 binhost = ' '.join(binhost_urls)
David James8ece7ee2011-06-29 16:02:30 -0700572 if git_sync:
David Jamesb26b9312014-12-15 11:26:46 -0800573 git_file = os.path.join(self._build_path, _PREBUILT_MAKE_CONF[_HOST_ARCH])
Mike Frysinger86509232014-05-24 13:18:37 -0400574 RevGitFile(git_file, {key: binhost}, dryrun=self._dryrun)
David James8ece7ee2011-06-29 16:02:30 -0700575 if sync_binhost_conf:
David Jamesb26b9312014-12-15 11:26:46 -0800576 binhost_conf = os.path.join(
577 self._binhost_conf_dir, 'host', '%s-%s.conf' % (_HOST_ARCH, key))
David Jamese2488642011-11-14 16:15:20 -0800578 UpdateBinhostConfFile(binhost_conf, key, binhost)
David Jamesc0f158a2011-02-22 16:07:29 -0800579
Mike Frysinger8092a632014-05-24 13:25:46 -0400580 def SyncBoardPrebuilts(self, key, git_sync, sync_binhost_conf,
Mike Frysinger9e979b92012-11-29 02:55:09 -0500581 upload_board_tarball, prepackaged_board,
Gilad Arnold2b79e2d2015-06-02 11:26:07 -0700582 toolchains_overlay_tarballs,
583 toolchains_overlay_upload_path,
Mike Frysinger9e979b92012-11-29 02:55:09 -0500584 toolchain_tarballs, toolchain_upload_path):
David Jamesc0f158a2011-02-22 16:07:29 -0800585 """Synchronize board prebuilt files.
586
587 Args:
David Jamesc0f158a2011-02-22 16:07:29 -0800588 key: The variable key to update in the git file.
589 git_sync: If set, update make.conf of target to reference the latest
590 prebuilt packages generated here.
591 sync_binhost_conf: If set, update binhost config file in
592 chromiumos-overlay for the current board.
David James8fa34ea2011-04-15 13:00:20 -0700593 upload_board_tarball: Include a tarball of the board in our upload.
Zdenek Behan62a57792012-08-31 15:09:08 +0200594 prepackaged_board: A tarball of the board built outside of this script.
Gilad Arnold2b79e2d2015-06-02 11:26:07 -0700595 toolchains_overlay_tarballs: List of toolchains overlay tarball
596 specifications to upload. Items take the form
597 "toolchains_spec:/path/to/tarball".
598 toolchains_overlay_upload_path: Path template under the bucket to place
599 toolchains overlay tarballs.
Mike Frysinger9e979b92012-11-29 02:55:09 -0500600 toolchain_tarballs: A list of toolchain tarballs to upload.
601 toolchain_upload_path: Path under the bucket to place toolchain tarballs.
David Jamesc0f158a2011-02-22 16:07:29 -0800602 """
David Jamesb26b9312014-12-15 11:26:46 -0800603 updated_binhosts = set()
Chris Sosa6a5dceb2012-05-14 13:48:56 -0700604 for target in self._GetTargets():
David Jamese2488642011-11-14 16:15:20 -0800605 board_path = os.path.join(self._build_path,
David James4058b0d2011-12-08 21:24:50 -0800606 _BOARD_PATH % {'board': target.board_variant})
David Jamese2488642011-11-14 16:15:20 -0800607 package_path = os.path.join(board_path, 'packages')
Mike Frysinger8092a632014-05-24 13:25:46 -0400608 url_suffix = _REL_BOARD_PATH % {'target': target,
609 'version': self._version}
David Jamese2488642011-11-14 16:15:20 -0800610 packages_url_suffix = '%s/packages' % url_suffix.rstrip('/')
David James8fa34ea2011-04-15 13:00:20 -0700611
Matt Tennante8179042013-10-01 15:47:32 -0700612 # Process the target board differently if it is the main --board.
Mike Frysinger540883b2014-05-24 13:46:16 -0400613 if self._target == target and not self._skip_upload:
Matt Tennante8179042013-10-01 15:47:32 -0700614 # This strips "chroot" prefix because that is sometimes added as the
615 # --prepend-version argument (e.g. by chromiumos-sdk bot).
616 # TODO(build): Clean it up to be less hard-coded.
Mike Frysinger8092a632014-05-24 13:25:46 -0400617 version_str = self._version[len('chroot-'):]
Mike Frysinger9e979b92012-11-29 02:55:09 -0500618
David Jamese2488642011-11-14 16:15:20 -0800619 # Upload board tarballs in the background.
620 if upload_board_tarball:
Mike Frysinger9e979b92012-11-29 02:55:09 -0500621 if toolchain_upload_path:
622 toolchain_upload_path %= {'version': version_str}
Gilad Arnold2b79e2d2015-06-02 11:26:07 -0700623 if toolchains_overlay_upload_path:
624 toolchains_overlay_upload_path %= {'version': version_str}
Mike Frysinger9e979b92012-11-29 02:55:09 -0500625 tar_process = multiprocessing.Process(
626 target=self._UploadSdkTarball,
Mike Frysinger8092a632014-05-24 13:25:46 -0400627 args=(board_path, url_suffix, prepackaged_board,
Gilad Arnold2b79e2d2015-06-02 11:26:07 -0700628 toolchains_overlay_tarballs,
629 toolchains_overlay_upload_path, toolchain_tarballs,
630 toolchain_upload_path))
David Jamese2488642011-11-14 16:15:20 -0800631 tar_process.start()
David James8fa34ea2011-04-15 13:00:20 -0700632
David Jamese2488642011-11-14 16:15:20 -0800633 # Upload prebuilts.
634 self._UploadPrebuilt(package_path, packages_url_suffix)
David James8fa34ea2011-04-15 13:00:20 -0700635
David Jamese2488642011-11-14 16:15:20 -0800636 # Make sure we finished uploading the board tarballs.
637 if upload_board_tarball:
638 tar_process.join()
639 assert tar_process.exitcode == 0
David Jamesc0f158a2011-02-22 16:07:29 -0800640
David Jamese2488642011-11-14 16:15:20 -0800641 # Record URL where prebuilts were uploaded.
642 url_value = '%s/%s/' % (self._binhost_base_url.rstrip('/'),
643 packages_url_suffix.rstrip('/'))
644
645 if git_sync:
David James4058b0d2011-12-08 21:24:50 -0800646 git_file = DeterminePrebuiltConfFile(self._build_path, target)
Mike Frysinger86509232014-05-24 13:18:37 -0400647 RevGitFile(git_file, {key: url_value}, dryrun=self._dryrun)
Matt Tennante8179042013-10-01 15:47:32 -0700648
David Jamese2488642011-11-14 16:15:20 -0800649 if sync_binhost_conf:
Matt Tennante8179042013-10-01 15:47:32 -0700650 # Update the binhost configuration file in git.
David Jamesb26b9312014-12-15 11:26:46 -0800651 binhost_conf = os.path.join(
652 self._binhost_conf_dir, 'target', '%s-%s.conf' % (target, key))
653 updated_binhosts.add(binhost_conf)
David Jamese2488642011-11-14 16:15:20 -0800654 UpdateBinhostConfFile(binhost_conf, key, url_value)
David James05bcb2b2011-02-09 09:25:47 -0800655
David Jamesb26b9312014-12-15 11:26:46 -0800656 if sync_binhost_conf:
657 # Clear all old binhosts. The files must be left empty in case anybody
658 # is referring to them.
659 all_binhosts = set(glob.glob(os.path.join(
660 self._binhost_conf_dir, 'target', '*-%s.conf' % key)))
661 for binhost_conf in all_binhosts - updated_binhosts:
662 UpdateBinhostConfFile(binhost_conf, key, '')
663
David James05bcb2b2011-02-09 09:25:47 -0800664
Mike Nicholsa1414162021-04-22 20:07:22 +0000665class _AddSlaveBoardAction(argparse.Action):
666 """Callback that adds a slave board to the list of slave targets."""
Mike Frysingerb87bb782015-06-04 02:46:50 -0400667 def __call__(self, parser, namespace, values, option_string=None):
668 getattr(namespace, self.dest).append(BuildTarget(values))
David James4058b0d2011-12-08 21:24:50 -0800669
670
Mike Nicholsa1414162021-04-22 20:07:22 +0000671class _AddSlaveProfileAction(argparse.Action):
672 """Callback that adds a slave profile to the list of slave targets."""
Mike Frysingerb87bb782015-06-04 02:46:50 -0400673 def __call__(self, parser, namespace, values, option_string=None):
674 if not namespace.slave_targets:
675 parser.error('Must specify --slave-board before --slave-profile')
676 if namespace.slave_targets[-1].profile is not None:
677 parser.error('Cannot specify --slave-profile twice for same board')
678 namespace.slave_targets[-1].profile = values
David James4058b0d2011-12-08 21:24:50 -0800679
680
Mike Frysinger86509232014-05-24 13:18:37 -0400681def ParseOptions(argv):
Chris Sosa6a5dceb2012-05-14 13:48:56 -0700682 """Returns options given by the user and the target specified.
683
Mike Frysinger86509232014-05-24 13:18:37 -0400684 Args:
685 argv: The args to parse.
686
Mike Frysinger1a736a82013-12-12 01:50:59 -0500687 Returns:
688 A tuple containing a parsed options object and BuildTarget.
689 The target instance is None if no board is specified.
Chris Sosa6a5dceb2012-05-14 13:48:56 -0700690 """
Mike Frysingerb87bb782015-06-04 02:46:50 -0400691 parser = commandline.ArgumentParser()
692 parser.add_argument('-H', '--binhost-base-url', default=_BINHOST_BASE_URL,
693 help='Base URL to use for binhost in make.conf updates')
694 parser.add_argument('--previous-binhost-url', action='append', default=[],
695 help='Previous binhost URL')
696 parser.add_argument('-b', '--board',
697 help='Board type that was built on this machine')
698 parser.add_argument('-B', '--prepackaged-tarball', type='path',
699 help='Board tarball prebuilt outside of this script.')
Gilad Arnold2b79e2d2015-06-02 11:26:07 -0700700 parser.add_argument('--toolchains-overlay-tarball',
701 dest='toolchains_overlay_tarballs',
Mike Frysingerb87bb782015-06-04 02:46:50 -0400702 action='append', default=[],
Gilad Arnold2b79e2d2015-06-02 11:26:07 -0700703 help='Toolchains overlay tarball specification to '
704 'upload. Takes the form '
705 '"toolchains_spec:/path/to/tarball".')
706 parser.add_argument('--toolchains-overlay-upload-path', default='',
707 help='Path template for uploading toolchains overlays.')
Mike Frysingerb87bb782015-06-04 02:46:50 -0400708 parser.add_argument('--toolchain-tarball', dest='toolchain_tarballs',
709 action='append', default=[],
710 help='Redistributable toolchain tarball.')
Gilad Arnold2b79e2d2015-06-02 11:26:07 -0700711 parser.add_argument('--toolchain-upload-path', default='',
Mike Frysingerb87bb782015-06-04 02:46:50 -0400712 help='Path to place toolchain tarballs in the sdk tree.')
713 parser.add_argument('--profile',
714 help='Profile that was built on this machine')
Mike Nicholsa1414162021-04-22 20:07:22 +0000715 parser.add_argument('--slave-board', default=[], action=_AddSlaveBoardAction,
Mike Frysingerb87bb782015-06-04 02:46:50 -0400716 dest='slave_targets',
717 help='Board type that was built on a slave machine. To '
718 'add a profile to this board, use --slave-profile.')
Mike Nicholsa1414162021-04-22 20:07:22 +0000719 parser.add_argument('--slave-profile', action=_AddSlaveProfileAction,
Mike Frysingerb87bb782015-06-04 02:46:50 -0400720 help='Board profile that was built on a slave machine. '
721 'Applies to previous slave board.')
722 parser.add_argument('-p', '--build-path', required=True,
723 help='Path to the directory containing the chroot')
Bob Haarmand1225ea2022-01-19 22:01:42 +0000724 parser.add_argument('--chroot',
725 help='Path where the chroot is located. '
726 '(Default: {build_path}/chroot)')
Mike Frysingerb87bb782015-06-04 02:46:50 -0400727 parser.add_argument('--packages', action='append', default=[],
728 help='Only include the specified packages. '
729 '(Default is to include all packages.)')
730 parser.add_argument('-s', '--sync-host', default=False, action='store_true',
731 help='Sync host prebuilts')
732 parser.add_argument('-g', '--git-sync', default=False, action='store_true',
733 help='Enable git version sync (This commits to a repo.) '
734 'This is used by full builders to commit directly '
735 'to board overlays.')
736 parser.add_argument('-u', '--upload',
737 help='Upload location')
738 parser.add_argument('-V', '--prepend-version',
739 help='Add an identifier to the front of the version')
740 parser.add_argument('-f', '--filters', action='store_true', default=False,
741 help='Turn on filtering of private ebuild packages')
742 parser.add_argument('-k', '--key', default='PORTAGE_BINHOST',
743 help='Key to update in make.conf / binhost.conf')
744 parser.add_argument('--set-version',
745 help='Specify the version string')
746 parser.add_argument('--sync-binhost-conf', default=False, action='store_true',
747 help='Update binhost.conf in chromiumos-overlay or '
Mike Frysinger80de5012019-08-01 14:10:53 -0400748 "chromeos-overlay. Commit the changes, but don't "
Mike Frysingerb87bb782015-06-04 02:46:50 -0400749 'push them. This is used for preflight binhosts.')
750 parser.add_argument('--binhost-conf-dir',
751 help='Directory to commit binhost config with '
752 '--sync-binhost-conf.')
753 parser.add_argument('-P', '--private', action='store_true', default=False,
754 help='Mark gs:// uploads as private.')
755 parser.add_argument('--skip-upload', action='store_true', default=False,
756 help='Skip upload step.')
757 parser.add_argument('--upload-board-tarball', action='store_true',
758 default=False,
759 help='Upload board tarball to Google Storage.')
760 parser.add_argument('-n', '--dry-run', dest='dryrun',
761 action='store_true', default=False,
Mike Frysinger80de5012019-08-01 14:10:53 -0400762 help="Don't push or upload prebuilts.")
David James8c846492011-01-25 17:07:29 -0800763
Mike Frysingerb87bb782015-06-04 02:46:50 -0400764 options = parser.parse_args(argv)
David James8ece7ee2011-06-29 16:02:30 -0700765 if not options.upload and not options.skip_upload:
Mike Frysinger86509232014-05-24 13:18:37 -0400766 parser.error('you need to provide an upload location using -u')
David James8ece7ee2011-06-29 16:02:30 -0700767 if not options.set_version and options.skip_upload:
Mike Frysinger86509232014-05-24 13:18:37 -0400768 parser.error('If you are using --skip-upload, you must specify a '
769 'version number using --set-version.')
Scott Zawalskiab1bed32011-03-16 15:24:24 -0700770
Chris Sosa6a5dceb2012-05-14 13:48:56 -0700771 target = None
772 if options.board:
773 target = BuildTarget(options.board, options.profile)
774
775 if target in options.slave_targets:
Mike Frysinger86509232014-05-24 13:18:37 -0400776 parser.error('--board/--profile must not also be a slave target.')
David Jamese2488642011-11-14 16:15:20 -0800777
David James4058b0d2011-12-08 21:24:50 -0800778 if len(set(options.slave_targets)) != len(options.slave_targets):
Mike Frysinger86509232014-05-24 13:18:37 -0400779 parser.error('--slave-boards must not have duplicates.')
David Jamese2488642011-11-14 16:15:20 -0800780
David James4058b0d2011-12-08 21:24:50 -0800781 if options.slave_targets and options.git_sync:
Mike Frysinger86509232014-05-24 13:18:37 -0400782 parser.error('--slave-boards is not compatible with --git-sync')
David Jamese2488642011-11-14 16:15:20 -0800783
David James8ece7ee2011-06-29 16:02:30 -0700784 if (options.upload_board_tarball and options.skip_upload and
785 options.board == 'amd64-host'):
Mike Frysinger86509232014-05-24 13:18:37 -0400786 parser.error('--skip-upload is not compatible with '
787 '--upload-board-tarball and --board=amd64-host')
David James8fa34ea2011-04-15 13:00:20 -0700788
David James8ece7ee2011-06-29 16:02:30 -0700789 if (options.upload_board_tarball and not options.skip_upload and
790 not options.upload.startswith('gs://')):
Mike Frysinger86509232014-05-24 13:18:37 -0400791 parser.error('--upload-board-tarball only works with gs:// URLs.\n'
792 '--upload must be a gs:// URL.')
David James8fa34ea2011-04-15 13:00:20 -0700793
Zdenek Behan86c15e92012-10-13 00:55:47 +0200794 if options.upload_board_tarball and options.prepackaged_tarball is None:
Mike Frysinger86509232014-05-24 13:18:37 -0400795 parser.error('--upload-board-tarball requires --prepackaged-tarball')
Zdenek Behan86c15e92012-10-13 00:55:47 +0200796
Scott Zawalskiab1bed32011-03-16 15:24:24 -0700797 if options.private:
798 if options.sync_host:
Mike Frysinger86509232014-05-24 13:18:37 -0400799 parser.error('--private and --sync-host/-s cannot be specified '
800 'together; we do not support private host prebuilts')
Scott Zawalskiab1bed32011-03-16 15:24:24 -0700801
David James8ece7ee2011-06-29 16:02:30 -0700802 if not options.upload or not options.upload.startswith('gs://'):
Mike Frysinger86509232014-05-24 13:18:37 -0400803 parser.error('--private is only valid for gs:// URLs; '
804 '--upload must be a gs:// URL.')
Scott Zawalskiab1bed32011-03-16 15:24:24 -0700805
806 if options.binhost_base_url != _BINHOST_BASE_URL:
Mike Frysinger86509232014-05-24 13:18:37 -0400807 parser.error('when using --private the --binhost-base-url '
808 'is automatically derived.')
David James27fa7d12011-06-29 17:24:14 -0700809
David Jamesc31168e2014-06-05 14:40:05 -0700810 if options.sync_binhost_conf and not options.binhost_conf_dir:
811 parser.error('--sync-binhost-conf requires --binhost-conf-dir')
812
Gilad Arnold2b79e2d2015-06-02 11:26:07 -0700813 if (options.toolchains_overlay_tarballs and
814 not options.toolchains_overlay_upload_path):
815 parser.error('--toolchains-overlay-tarball requires '
816 '--toolchains-overlay-upload-path')
Gilad Arnoldad333182015-05-27 15:50:41 -0700817
Chris Sosa6a5dceb2012-05-14 13:48:56 -0700818 return options, target
David Jamesc0f158a2011-02-22 16:07:29 -0800819
Mike Frysingercc838832014-05-24 13:10:30 -0400820
Mike Frysinger86509232014-05-24 13:18:37 -0400821def main(argv):
David Jamesdb401072011-06-10 12:17:16 -0700822 # Set umask to a sane value so that files created as root are readable.
Mike Frysinger60ec1012013-10-21 00:11:10 -0400823 os.umask(0o22)
David Jamesdb401072011-06-10 12:17:16 -0700824
Mike Frysinger86509232014-05-24 13:18:37 -0400825 options, target = ParseOptions(argv)
David Jamesc0f158a2011-02-22 16:07:29 -0800826
David James05bcb2b2011-02-09 09:25:47 -0800827 # Calculate a list of Packages index files to compare against. Whenever we
828 # upload a package, we check to make sure it's not already stored in one of
829 # the packages files we uploaded. This list of packages files might contain
830 # both board and host packages.
David Jamesce093af2011-02-23 15:21:58 -0800831 pkg_indexes = _GrabAllRemotePackageIndexes(options.previous_binhost_url)
David James8c846492011-01-25 17:07:29 -0800832
David James8ece7ee2011-06-29 16:02:30 -0700833 if options.set_version:
834 version = options.set_version
835 else:
836 version = GetVersion()
Matt Tennante8179042013-10-01 15:47:32 -0700837
David Jamesc0f158a2011-02-22 16:07:29 -0800838 if options.prepend_version:
839 version = '%s-%s' % (options.prepend_version, version)
840
Scott Zawalskiab1bed32011-03-16 15:24:24 -0700841 acl = 'public-read'
842 binhost_base_url = options.binhost_base_url
843
David Jamesadd21432013-05-21 10:04:07 -0700844 if options.private:
Scott Zawalskiab1bed32011-03-16 15:24:24 -0700845 binhost_base_url = options.upload
David Jamesadd21432013-05-21 10:04:07 -0700846 if target:
Prathmesh Prabhu421eef22014-10-16 17:13:19 -0700847 acl = portage_util.FindOverlayFile(_GOOGLESTORAGE_GSUTIL_FILE,
848 board=target.board_variant,
849 buildroot=options.build_path)
Ben Chan067de492015-01-06 17:19:13 -0800850 if acl is None:
851 cros_build_lib.Die('No Google Storage ACL file %s found in %s overlay.',
852 _GOOGLESTORAGE_GSUTIL_FILE, target.board_variant)
Scott Zawalskiab1bed32011-03-16 15:24:24 -0700853
David Jamesb26b9312014-12-15 11:26:46 -0800854 binhost_conf_dir = None
855 if options.binhost_conf_dir:
856 binhost_conf_dir = os.path.join(options.build_path,
857 options.binhost_conf_dir)
858
Scott Zawalskiab1bed32011-03-16 15:24:24 -0700859 uploader = PrebuiltUploader(options.upload, acl, binhost_base_url,
David James615e5b52011-06-03 11:10:15 -0700860 pkg_indexes, options.build_path,
David James27fa7d12011-06-29 17:24:14 -0700861 options.packages, options.skip_upload,
David Jamesb26b9312014-12-15 11:26:46 -0800862 binhost_conf_dir, options.dryrun,
Bob Haarmand1225ea2022-01-19 22:01:42 +0000863 target, options.slave_targets, version,
864 options.chroot)
David Jamesc0f158a2011-02-22 16:07:29 -0800865
David James8c846492011-01-25 17:07:29 -0800866 if options.sync_host:
Mike Frysinger8092a632014-05-24 13:25:46 -0400867 uploader.SyncHostPrebuilts(options.key, options.git_sync,
Chris Sosa6a5dceb2012-05-14 13:48:56 -0700868 options.sync_binhost_conf)
David James8c846492011-01-25 17:07:29 -0800869
Chris Sosa62c8ff52012-06-04 15:03:12 -0700870 if options.board or options.slave_targets:
Mike Frysinger8092a632014-05-24 13:25:46 -0400871 uploader.SyncBoardPrebuilts(options.key, options.git_sync,
Chris Sosa6a5dceb2012-05-14 13:48:56 -0700872 options.sync_binhost_conf,
Zdenek Behan62a57792012-08-31 15:09:08 +0200873 options.upload_board_tarball,
Mike Frysinger9e979b92012-11-29 02:55:09 -0500874 options.prepackaged_tarball,
Gilad Arnold2b79e2d2015-06-02 11:26:07 -0700875 options.toolchains_overlay_tarballs,
876 options.toolchains_overlay_upload_path,
Mike Frysinger9e979b92012-11-29 02:55:09 -0500877 options.toolchain_tarballs,
878 options.toolchain_upload_path)