blob: a830e3ff15f87a2fae2fb10577158c221abb9ede [file] [log] [blame]
Don Garrett13cbbff2016-08-09 14:18:38 -07001 # 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 Sosa1dc96132012-05-11 15:40:50 -070024import multiprocessing
Chris Sosa1dc96132012-05-11 15:40:50 -070025import os
Mike Frysinger212e4292014-05-24 15:15:44 -040026import tempfile
Chris Sosa1dc96132012-05-11 15:40:50 -070027
Aviv Keshetb7519e12016-10-04 00:50:00 -070028from chromite.lib import constants
David James14e97772014-06-04 18:44:49 -070029from chromite.cbuildbot import commands
David James6450a0a2012-12-04 07:59:53 -080030from chromite.lib import binpkg
Mike Frysinger86509232014-05-24 13:18:37 -040031from chromite.lib import commandline
Chris Sosa1dc96132012-05-11 15:40:50 -070032from chromite.lib import cros_build_lib
Ralph Nathan446aee92015-03-23 14:44:56 -070033from chromite.lib import cros_logging as logging
David James97d95872012-11-16 15:09:56 -080034from chromite.lib import git
Julio Hurtadofad17992021-05-20 21:24:24 +000035from chromite.lib import gerrit
Brian Harring7904b482012-08-08 02:54:12 -070036from chromite.lib import gs
Brian Harringaf019fb2012-05-10 15:06:13 -070037from chromite.lib import osutils
David James6450a0a2012-12-04 07:59:53 -080038from chromite.lib import parallel
Alex Deymo075c2292014-09-04 18:31:50 -070039from chromite.lib import portage_util
Mike Frysinger8e727a32013-01-16 16:57:53 -050040from chromite.lib import toolchain
Alex Klein18a60af2020-06-11 12:08:47 -060041from chromite.lib.parser import package_info
Chris Sosa1dc96132012-05-11 15:40:50 -070042
Mike Frysinger72b7cf92020-04-19 06:00:51 -040043
David James015af872012-06-19 15:24:36 -070044# How many times to retry uploads.
45_RETRIES = 10
46
47# Multiplier for how long to sleep (in seconds) between retries; will delay
48# (1*sleep) the first time, then (2*sleep), continuing via attempt * sleep.
49_SLEEP_TIME = 60
50
David James5ab67e32014-10-24 08:19:59 -070051# The length of time (in seconds) that Portage should wait before refetching
52# binpkgs from the same binhost. We don't ever modify binhosts, so this should
53# be something big.
54_BINPKG_TTL = 60 * 60 * 24 * 365
55
David James8c846492011-01-25 17:07:29 -080056_HOST_PACKAGES_PATH = 'chroot/var/lib/portage/pkgs'
David James05bcb2b2011-02-09 09:25:47 -080057_CATEGORIES_PATH = 'chroot/etc/portage/categories'
David James615e5b52011-06-03 11:10:15 -070058_PYM_PATH = 'chroot/usr/lib/portage/pym'
David James4058b0d2011-12-08 21:24:50 -080059_HOST_ARCH = 'amd64'
David James8c846492011-01-25 17:07:29 -080060_BOARD_PATH = 'chroot/build/%(board)s'
David James4058b0d2011-12-08 21:24:50 -080061_REL_BOARD_PATH = 'board/%(target)s/%(version)s'
62_REL_HOST_PATH = 'host/%(host_arch)s/%(target)s/%(version)s'
David James8c846492011-01-25 17:07:29 -080063# Private overlays to look at for builds to filter
64# relative to build path
65_PRIVATE_OVERLAY_DIR = 'src/private-overlays'
Gabe Black40169e62014-06-17 15:23:47 -070066_GOOGLESTORAGE_GSUTIL_FILE = 'googlestorage_acl.txt'
David James3753d942014-04-23 10:55:48 -070067_BINHOST_BASE_URL = 'gs://chromeos-prebuilt'
David James8c846492011-01-25 17:07:29 -080068_PREBUILT_BASE_DIR = 'src/third_party/chromiumos-overlay/chromeos/config/'
69# Created in the event of new host targets becoming available
70_PREBUILT_MAKE_CONF = {'amd64': os.path.join(_PREBUILT_BASE_DIR,
71 'make.conf.amd64-host')}
David James8c846492011-01-25 17:07:29 -080072
73
David James4058b0d2011-12-08 21:24:50 -080074class BuildTarget(object):
75 """A board/variant/profile tuple."""
76
77 def __init__(self, board_variant, profile=None):
78 self.board_variant = board_variant
79 self.board, _, self.variant = board_variant.partition('_')
80 self.profile = profile
81
82 def __str__(self):
83 if self.profile:
84 return '%s_%s' % (self.board_variant, self.profile)
85 else:
86 return self.board_variant
87
88 def __eq__(self, other):
89 return str(other) == str(self)
90
91 def __hash__(self):
92 return hash(str(self))
93
94
David James8c846492011-01-25 17:07:29 -080095def UpdateLocalFile(filename, value, key='PORTAGE_BINHOST'):
96 """Update the key in file with the value passed.
Mike Frysinger1a736a82013-12-12 01:50:59 -050097
David James8c846492011-01-25 17:07:29 -080098 File format:
99 key="value"
100 Note quotes are added automatically
101
102 Args:
103 filename: Name of file to modify.
104 value: Value to write with the key.
105 key: The variable key to update. (Default: PORTAGE_BINHOST)
David Jamesb26b9312014-12-15 11:26:46 -0800106
107 Returns:
108 True if changes were made to the file.
David James8c846492011-01-25 17:07:29 -0800109 """
110 if os.path.exists(filename):
111 file_fh = open(filename)
112 else:
113 file_fh = open(filename, 'w+')
114 file_lines = []
115 found = False
David Jamesb26b9312014-12-15 11:26:46 -0800116 made_changes = False
David James8c846492011-01-25 17:07:29 -0800117 keyval_str = '%(key)s=%(value)s'
118 for line in file_fh:
119 # Strip newlines from end of line. We already add newlines below.
Mike Frysinger80de5012019-08-01 14:10:53 -0400120 line = line.rstrip('\n')
David James8c846492011-01-25 17:07:29 -0800121
122 if len(line.split('=')) != 2:
123 # Skip any line that doesn't fit key=val.
124 file_lines.append(line)
125 continue
126
127 file_var, file_val = line.split('=')
128 if file_var == key:
129 found = True
Mike Frysingerff441bf2014-05-24 13:47:21 -0400130 print('Updating %s=%s to %s="%s"' % (file_var, file_val, key, value))
David James8c846492011-01-25 17:07:29 -0800131 value = '"%s"' % value
David Jamesb26b9312014-12-15 11:26:46 -0800132 made_changes |= (file_val != value)
David James8c846492011-01-25 17:07:29 -0800133 file_lines.append(keyval_str % {'key': key, 'value': value})
134 else:
135 file_lines.append(keyval_str % {'key': file_var, 'value': file_val})
136
137 if not found:
Brian Harring2a014302012-05-12 00:53:33 -0700138 value = '"%s"' % value
David Jamesb26b9312014-12-15 11:26:46 -0800139 made_changes = True
David James8c846492011-01-25 17:07:29 -0800140 file_lines.append(keyval_str % {'key': key, 'value': value})
141
142 file_fh.close()
143 # write out new file
Brian Harringaf019fb2012-05-10 15:06:13 -0700144 osutils.WriteFile(filename, '\n'.join(file_lines) + '\n')
David Jamesb26b9312014-12-15 11:26:46 -0800145 return made_changes
David James8c846492011-01-25 17:07:29 -0800146
147
Mike Nicholsa6818c52018-04-09 11:05:42 -0600148def RevGitFile(filename, data, dryrun=False):
David James8c846492011-01-25 17:07:29 -0800149 """Update and push the git file.
150
Mike Frysinger5b34d732013-01-17 15:11:58 -0500151 Args:
152 filename: file to modify that is in a git repo already
153 data: A dict of key/values to update in |filename|
Matt Tennante8179042013-10-01 15:47:32 -0700154 dryrun: If True, do not actually commit the change.
David James8c846492011-01-25 17:07:29 -0800155 """
156 prebuilt_branch = 'prebuilt_branch'
David James1b6e67a2011-05-19 21:32:38 -0700157 cwd = os.path.abspath(os.path.dirname(filename))
Julio Hurtadofad17992021-05-20 21:24:24 +0000158 remote_name = git.RunGit(cwd, ['remote']).stdout.strip()
159 gerrit_helper = gerrit.GetGerritHelper(remote_name)
160 remote_url = git.RunGit(
161 cwd,['config', '--get', f'remote.{remote_name}.url']).stdout.strip()
Mike Frysinger5b34d732013-01-17 15:11:58 -0500162 description = '%s: updating %s' % (os.path.basename(filename),
163 ', '.join(data.keys()))
164 # UpdateLocalFile will print out the keys/values for us.
Mike Frysingerff441bf2014-05-24 13:47:21 -0400165 print('Revving git file %s' % filename)
Julio Hurtadofad17992021-05-20 21:24:24 +0000166 git.CreatePushBranch(prebuilt_branch, cwd)
167 for key, value in data.items():
168 UpdateLocalFile(filename, value, key)
169 git.RunGit(cwd, ['add', filename])
170 git.RunGit(cwd, ['commit', '-m', description])
Julio Hurtado2d4817d2021-04-29 16:03:58 +0000171
Julio Hurtadofad17992021-05-20 21:24:24 +0000172 tracking_info = git.GetTrackingBranch(
173 cwd, prebuilt_branch, for_push=True, for_checkout=False)
174 gpatch = gerrit_helper.CreateGerritPatch(
175 cwd, remote_url, ref=tracking_info.ref)
176 gerrit_helper.SetReview(gpatch, labels={'Bot-Commit': 1}, dryrun=dryrun)
177 gerrit_helper.SubmitChange(gpatch, dryrun=dryrun)
David James8c846492011-01-25 17:07:29 -0800178
179
180def GetVersion():
181 """Get the version to put in LATEST and update the git version with."""
Mike Frysinger0b92cfe2012-12-13 02:13:45 -0500182 return datetime.datetime.now().strftime('%Y.%m.%d.%H%M%S')
David James8c846492011-01-25 17:07:29 -0800183
184
Mike Frysinger540883b2014-05-24 13:46:16 -0400185def _GsUpload(gs_context, acl, local_file, remote_file):
David James8c846492011-01-25 17:07:29 -0800186 """Upload to GS bucket.
187
188 Args:
Mike Frysinger540883b2014-05-24 13:46:16 -0400189 gs_context: A lib.gs.GSContext instance.
190 acl: The ACL to use for uploading the file.
Matt Tennante8179042013-10-01 15:47:32 -0700191 local_file: The local file to be uploaded.
192 remote_file: The remote location to upload to.
David James8c846492011-01-25 17:07:29 -0800193 """
Scott Zawalskiab1bed32011-03-16 15:24:24 -0700194 CANNED_ACLS = ['public-read', 'private', 'bucket-owner-read',
195 'authenticated-read', 'bucket-owner-full-control',
196 'public-read-write']
Scott Zawalskiab1bed32011-03-16 15:24:24 -0700197 if acl in CANNED_ACLS:
David James9374aac2013-10-08 16:00:17 -0700198 gs_context.Copy(local_file, remote_file, acl=acl)
Scott Zawalskiab1bed32011-03-16 15:24:24 -0700199 else:
200 # For private uploads we assume that the overlay board is set up properly
David James015af872012-06-19 15:24:36 -0700201 # and a googlestore_acl.xml is present. Otherwise, this script errors.
David James7b7d7c32015-04-02 13:48:17 -0700202 # We set version=0 here to ensure that the ACL is set only once (see
203 # http://b/15883752#comment54).
204 try:
205 gs_context.Copy(local_file, remote_file, version=0)
206 except gs.GSContextPreconditionFailed as ex:
207 # If we received a GSContextPreconditionFailed error, we know that the
208 # file exists now, but we don't know whether our specific update
209 # succeeded. See http://b/15883752#comment62
210 logging.warning(
211 'Assuming upload succeeded despite PreconditionFailed errors: %s', ex)
212
Gabe Black40169e62014-06-17 15:23:47 -0700213 if acl.endswith('.xml'):
214 # Apply the passed in ACL xml file to the uploaded object.
215 gs_context.SetACL(remote_file, acl=acl)
216 else:
Mike Frysinger5186f262017-09-13 10:26:19 -0400217 gs_context.ChangeACL(remote_file, acl_args_file=acl)
Scott Zawalskiab1bed32011-03-16 15:24:24 -0700218
Mike Frysingercc838832014-05-24 13:10:30 -0400219
Mike Frysinger540883b2014-05-24 13:46:16 -0400220def RemoteUpload(gs_context, acl, files, pool=10):
David James8c846492011-01-25 17:07:29 -0800221 """Upload to google storage.
222
223 Create a pool of process and call _GsUpload with the proper arguments.
224
225 Args:
Mike Frysinger540883b2014-05-24 13:46:16 -0400226 gs_context: A lib.gs.GSContext instance.
David Jamesfd0b0852011-02-23 11:15:36 -0800227 acl: The canned acl used for uploading. acl can be one of: "public-read",
228 "public-read-write", "authenticated-read", "bucket-owner-read",
229 "bucket-owner-full-control", or "private".
David James8c846492011-01-25 17:07:29 -0800230 files: dictionary with keys to local files and values to remote path.
231 pool: integer of maximum proesses to have at the same time.
232
233 Returns:
234 Return a set of tuple arguments of the failed uploads
235 """
Mike Frysinger540883b2014-05-24 13:46:16 -0400236 upload = functools.partial(_GsUpload, gs_context, acl)
Mike Frysinger0bdbc102019-06-13 15:27:29 -0400237 tasks = [[key, value] for key, value in files.items()]
Mike Frysinger540883b2014-05-24 13:46:16 -0400238 parallel.RunTasksInProcessPool(upload, tasks, pool)
David James8c846492011-01-25 17:07:29 -0800239
240
241def GenerateUploadDict(base_local_path, base_remote_path, pkgs):
242 """Build a dictionary of local remote file key pairs to upload.
243
244 Args:
245 base_local_path: The base path to the files on the local hard drive.
Matt Tennante8179042013-10-01 15:47:32 -0700246 base_remote_path: The base path to the remote paths.
David James8c846492011-01-25 17:07:29 -0800247 pkgs: The packages to upload.
248
249 Returns:
250 Returns a dictionary of local_path/remote_path pairs
251 """
252 upload_files = {}
253 for pkg in pkgs:
254 suffix = pkg['CPV'] + '.tbz2'
255 local_path = os.path.join(base_local_path, suffix)
David James7b7d7c32015-04-02 13:48:17 -0700256 assert os.path.exists(local_path), '%s does not exist' % local_path
Bertrand SIMONNET811bcde2014-11-20 15:21:25 -0800257 upload_files[local_path] = os.path.join(base_remote_path, suffix)
David James8c846492011-01-25 17:07:29 -0800258
Bertrand SIMONNET811bcde2014-11-20 15:21:25 -0800259 if pkg.get('DEBUG_SYMBOLS') == 'yes':
260 debugsuffix = pkg['CPV'] + '.debug.tbz2'
261 local_path = os.path.join(base_local_path, debugsuffix)
262 assert os.path.exists(local_path)
263 upload_files[local_path] = os.path.join(base_remote_path, debugsuffix)
Bertrand SIMONNET22e828b2014-11-11 16:27:06 -0800264
David James8c846492011-01-25 17:07:29 -0800265 return upload_files
266
Mike Frysingercc838832014-05-24 13:10:30 -0400267
Peter Mayo950e41a2014-02-06 21:07:33 +0000268def GetBoardOverlay(build_path, target):
David Jamese5867812012-10-19 12:02:20 -0700269 """Get the path to the board variant.
Mike Frysinger1a736a82013-12-12 01:50:59 -0500270
Mike Frysinger6f3c48e2015-05-06 02:38:51 -0400271 Args:
272 build_path: The path to the root of the build directory
273 target: The target board as a BuildTarget object.
Mike Frysinger1a736a82013-12-12 01:50:59 -0500274
Mike Frysinger6f3c48e2015-05-06 02:38:51 -0400275 Returns:
276 The last overlay configured for the given board as a string.
David James8c846492011-01-25 17:07:29 -0800277 """
David Jamese5867812012-10-19 12:02:20 -0700278 board = target.board_variant
Alex Deymo075c2292014-09-04 18:31:50 -0700279 overlays = portage_util.FindOverlays(constants.BOTH_OVERLAYS, board,
280 buildroot=build_path)
David Jamese5867812012-10-19 12:02:20 -0700281 # We only care about the last entry.
282 return overlays[-1]
David James8c846492011-01-25 17:07:29 -0800283
284
285def DeterminePrebuiltConfFile(build_path, target):
286 """Determine the prebuilt.conf file that needs to be updated for prebuilts.
287
Mike Frysinger1a736a82013-12-12 01:50:59 -0500288 Args:
289 build_path: The path to the root of the build directory
290 target: String representation of the board. This includes host and board
291 targets
David James8c846492011-01-25 17:07:29 -0800292
Mike Frysinger1a736a82013-12-12 01:50:59 -0500293 Returns:
294 A string path to a prebuilt.conf file to be updated.
David James8c846492011-01-25 17:07:29 -0800295 """
David James4058b0d2011-12-08 21:24:50 -0800296 if _HOST_ARCH == target:
David James8c846492011-01-25 17:07:29 -0800297 # We are host.
298 # Without more examples of hosts this is a kludge for now.
299 # TODO(Scottz): as new host targets come online expand this to
300 # work more like boards.
Chris Sosa471532a2011-02-01 15:10:06 -0800301 make_path = _PREBUILT_MAKE_CONF[target]
David James8c846492011-01-25 17:07:29 -0800302 else:
303 # We are a board
Peter Mayo950e41a2014-02-06 21:07:33 +0000304 board = GetBoardOverlay(build_path, target)
David James8c846492011-01-25 17:07:29 -0800305 make_path = os.path.join(board, 'prebuilt.conf')
306
307 return make_path
308
309
310def UpdateBinhostConfFile(path, key, value):
311 """Update binhost config file file with key=value.
312
313 Args:
314 path: Filename to update.
315 key: Key to update.
316 value: New value for key.
317 """
David Jamesb26b9312014-12-15 11:26:46 -0800318 cwd, filename = os.path.split(os.path.abspath(path))
Brian Harringaf019fb2012-05-10 15:06:13 -0700319 osutils.SafeMakedirs(cwd)
David Jamesf6e8fb72013-05-10 08:58:43 -0700320 if not git.GetCurrentBranch(cwd):
321 git.CreatePushBranch(constants.STABLE_EBUILD_BRANCH, cwd, sync=False)
Brian Harring22edb442012-05-11 23:55:18 -0700322 osutils.WriteFile(path, '', mode='a')
David Jamesb26b9312014-12-15 11:26:46 -0800323 if UpdateLocalFile(path, value, key):
324 desc = '%s: %s %s' % (filename, 'updating' if value else 'clearing', key)
325 git.AddPath(path)
326 git.Commit(cwd, desc)
David James8c846492011-01-25 17:07:29 -0800327
Achuith Bhandarkar03d924a2018-01-02 10:50:44 -0800328def GenerateHtmlIndex(files, index, board, version, remote_location):
Mike Frysinger212e4292014-05-24 15:15:44 -0400329 """Given the list of |files|, generate an index.html at |index|.
330
331 Args:
332 files: The list of files to link to.
333 index: The path to the html index.
334 board: Name of the board this index is for.
335 version: Build version this index is for.
Achuith Bhandarkar03d924a2018-01-02 10:50:44 -0800336 remote_location: Remote gs location prebuilts are uploaded to.
Mike Frysinger212e4292014-05-24 15:15:44 -0400337 """
Don Garrett13cbbff2016-08-09 14:18:38 -0700338 title = 'Package Prebuilt Index: %s / %s' % (board, version)
Mike Frysinger212e4292014-05-24 15:15:44 -0400339
340 files = files + [
341 '.|Google Storage Index',
342 '..|',
343 ]
Achuith Bhandarkar03d924a2018-01-02 10:50:44 -0800344 commands.GenerateHtmlIndex(index, files, title=title,
345 url_base=gs.GsUrlToHttp(remote_location))
Mike Frysinger212e4292014-05-24 15:15:44 -0400346
347
David Jamesce093af2011-02-23 15:21:58 -0800348def _GrabAllRemotePackageIndexes(binhost_urls):
David James05bcb2b2011-02-09 09:25:47 -0800349 """Grab all of the packages files associated with a list of binhost_urls.
350
David James05bcb2b2011-02-09 09:25:47 -0800351 Args:
352 binhost_urls: The URLs for the directories containing the Packages files we
353 want to grab.
David James05bcb2b2011-02-09 09:25:47 -0800354
355 Returns:
356 A list of PackageIndex objects.
357 """
358 pkg_indexes = []
359 for url in binhost_urls:
David James32faafe2012-06-08 14:25:03 -0700360 pkg_index = binpkg.GrabRemotePackageIndex(url)
David James05bcb2b2011-02-09 09:25:47 -0800361 if pkg_index:
362 pkg_indexes.append(pkg_index)
David James05bcb2b2011-02-09 09:25:47 -0800363 return pkg_indexes
364
365
David Jamesc0f158a2011-02-22 16:07:29 -0800366class PrebuiltUploader(object):
367 """Synchronize host and board prebuilts."""
David James8c846492011-01-25 17:07:29 -0800368
Mike Frysinger86509232014-05-24 13:18:37 -0400369 def __init__(self, upload_location, acl, binhost_base_url, pkg_indexes,
370 build_path, packages, skip_upload, binhost_conf_dir, dryrun,
Mike Frysinger8092a632014-05-24 13:25:46 -0400371 target, slave_targets, version):
David Jamesc0f158a2011-02-22 16:07:29 -0800372 """Constructor for prebuilt uploader object.
David James8c846492011-01-25 17:07:29 -0800373
David Jamesc0f158a2011-02-22 16:07:29 -0800374 This object can upload host or prebuilt files to Google Storage.
David James8c846492011-01-25 17:07:29 -0800375
David Jamesc0f158a2011-02-22 16:07:29 -0800376 Args:
377 upload_location: The upload location.
David Jamesfd0b0852011-02-23 11:15:36 -0800378 acl: The canned acl used for uploading to Google Storage. acl can be one
379 of: "public-read", "public-read-write", "authenticated-read",
Matt Tennante8179042013-10-01 15:47:32 -0700380 "bucket-owner-read", "bucket-owner-full-control", "project-private",
381 or "private" (see "gsutil help acls"). If we are not uploading to
382 Google Storage, this parameter is unused.
David Jamesfd0b0852011-02-23 11:15:36 -0800383 binhost_base_url: The URL used for downloading the prebuilts.
David Jamesc0f158a2011-02-22 16:07:29 -0800384 pkg_indexes: Old uploaded prebuilts to compare against. Instead of
385 uploading duplicate files, we just link to the old files.
David James615e5b52011-06-03 11:10:15 -0700386 build_path: The path to the directory containing the chroot.
387 packages: Packages to upload.
David James32b0b2f2011-07-13 20:56:50 -0700388 skip_upload: Don't actually upload the tarballs.
389 binhost_conf_dir: Directory where to store binhost.conf files.
Mike Frysinger86509232014-05-24 13:18:37 -0400390 dryrun: Don't push or upload prebuilts.
David James4058b0d2011-12-08 21:24:50 -0800391 target: BuildTarget managed by this builder.
392 slave_targets: List of BuildTargets managed by slave builders.
Mike Frysinger8092a632014-05-24 13:25:46 -0400393 version: A unique string, intended to be included in the upload path,
394 which identifies the version number of the uploaded prebuilts.
David Jamesc0f158a2011-02-22 16:07:29 -0800395 """
396 self._upload_location = upload_location
David Jamesfd0b0852011-02-23 11:15:36 -0800397 self._acl = acl
David Jamesc0f158a2011-02-22 16:07:29 -0800398 self._binhost_base_url = binhost_base_url
399 self._pkg_indexes = pkg_indexes
David James615e5b52011-06-03 11:10:15 -0700400 self._build_path = build_path
401 self._packages = set(packages)
Mike Frysingerf5f809a2013-02-12 13:47:37 -0500402 self._found_packages = set()
David James8ece7ee2011-06-29 16:02:30 -0700403 self._skip_upload = skip_upload
David James32b0b2f2011-07-13 20:56:50 -0700404 self._binhost_conf_dir = binhost_conf_dir
Mike Frysinger86509232014-05-24 13:18:37 -0400405 self._dryrun = dryrun
David James4058b0d2011-12-08 21:24:50 -0800406 self._target = target
407 self._slave_targets = slave_targets
Mike Frysinger8092a632014-05-24 13:25:46 -0400408 self._version = version
Mike Frysinger540883b2014-05-24 13:46:16 -0400409 self._gs_context = gs.GSContext(retries=_RETRIES, sleep=_SLEEP_TIME,
410 dry_run=self._dryrun)
411
412 def _Upload(self, local_file, remote_file):
413 """Wrapper around _GsUpload"""
414 _GsUpload(self._gs_context, self._acl, local_file, remote_file)
David James615e5b52011-06-03 11:10:15 -0700415
416 def _ShouldFilterPackage(self, pkg):
417 if not self._packages:
418 return False
Alex Klein18a60af2020-06-11 12:08:47 -0600419 cpv = package_info.SplitCPV(pkg['CPV'])
Alex Klein9f93b482018-10-01 09:26:51 -0600420 self._found_packages.add(cpv.cp)
421 return cpv.package not in self._packages and cpv.cp not in self._packages
David James8c846492011-01-25 17:07:29 -0800422
David Jamesc0f158a2011-02-22 16:07:29 -0800423 def _UploadPrebuilt(self, package_path, url_suffix):
424 """Upload host or board prebuilt files to Google Storage space.
David James8c846492011-01-25 17:07:29 -0800425
David Jamesc0f158a2011-02-22 16:07:29 -0800426 Args:
427 package_path: The path to the packages dir.
David Jamesce093af2011-02-23 15:21:58 -0800428 url_suffix: The remote subdirectory where we should upload the packages.
David Jamesc0f158a2011-02-22 16:07:29 -0800429 """
David Jamesc0f158a2011-02-22 16:07:29 -0800430 # Process Packages file, removing duplicates and filtered packages.
David James32faafe2012-06-08 14:25:03 -0700431 pkg_index = binpkg.GrabLocalPackageIndex(package_path)
David Jamesc0f158a2011-02-22 16:07:29 -0800432 pkg_index.SetUploadLocation(self._binhost_base_url, url_suffix)
David James615e5b52011-06-03 11:10:15 -0700433 pkg_index.RemoveFilteredPackages(self._ShouldFilterPackage)
David Jamesc0f158a2011-02-22 16:07:29 -0800434 uploads = pkg_index.ResolveDuplicateUploads(self._pkg_indexes)
Mike Frysingerf5f809a2013-02-12 13:47:37 -0500435 unmatched_pkgs = self._packages - self._found_packages
436 if unmatched_pkgs:
Lann Martinffb95162018-08-28 12:02:54 -0600437 logging.warning('unable to match packages: %r', unmatched_pkgs)
David James05bcb2b2011-02-09 09:25:47 -0800438
David Jamesc0f158a2011-02-22 16:07:29 -0800439 # Write Packages file.
David James5ab67e32014-10-24 08:19:59 -0700440 pkg_index.header['TTL'] = _BINPKG_TTL
David Jamesc0f158a2011-02-22 16:07:29 -0800441 tmp_packages_file = pkg_index.WriteToNamedTemporaryFile()
David James05bcb2b2011-02-09 09:25:47 -0800442
David Jamesc0f158a2011-02-22 16:07:29 -0800443 remote_location = '%s/%s' % (self._upload_location.rstrip('/'), url_suffix)
David James015af872012-06-19 15:24:36 -0700444 assert remote_location.startswith('gs://')
David James05bcb2b2011-02-09 09:25:47 -0800445
David James015af872012-06-19 15:24:36 -0700446 upload_files = GenerateUploadDict(package_path, remote_location, uploads)
447 remote_file = '%s/Packages' % remote_location.rstrip('/')
448 upload_files[tmp_packages_file.name] = remote_file
449
Mike Frysinger9bb6cd82020-08-20 03:02:23 -0400450 # Build list of files to upload. Manually include the dev-only files but
451 # skip them if not present.
452 dev_only = os.path.join(package_path, 'dev-only-extras.tar.xz')
453 if os.path.exists(dev_only):
454 upload_files[dev_only] = '%s/%s' % (
455 remote_location.rstrip('/'), os.path.basename(dev_only))
456
Mike Frysinger540883b2014-05-24 13:46:16 -0400457 RemoteUpload(self._gs_context, self._acl, upload_files)
David James8c846492011-01-25 17:07:29 -0800458
Mike Frysinger212e4292014-05-24 15:15:44 -0400459 with tempfile.NamedTemporaryFile(
460 prefix='chromite.upload_prebuilts.index.') as index:
461 GenerateHtmlIndex(
462 [x[len(remote_location) + 1:] for x in upload_files.values()],
Achuith Bhandarkar03d924a2018-01-02 10:50:44 -0800463 index.name, self._target, self._version, remote_location)
Mike Frysinger212e4292014-05-24 15:15:44 -0400464 self._Upload(index.name, '%s/index.html' % remote_location.rstrip('/'))
465
466 link_name = 'Prebuilts[%s]: %s' % (self._target, self._version)
467 url = '%s%s/index.html' % (gs.PUBLIC_BASE_HTTPS_URL,
468 remote_location[len(gs.BASE_GS_URL):])
Prathmesh Prabhu17f07422015-07-17 11:40:40 -0700469 logging.PrintBuildbotLink(link_name, url)
Mike Frysinger212e4292014-05-24 15:15:44 -0400470
Mike Frysinger8092a632014-05-24 13:25:46 -0400471 def _UploadSdkTarball(self, board_path, url_suffix, prepackaged,
Gilad Arnold2b79e2d2015-06-02 11:26:07 -0700472 toolchains_overlay_tarballs,
473 toolchains_overlay_upload_path,
Mike Frysinger9e979b92012-11-29 02:55:09 -0500474 toolchain_tarballs, toolchain_upload_path):
475 """Upload a tarball of the sdk at the specified path to Google Storage.
David James8fa34ea2011-04-15 13:00:20 -0700476
477 Args:
478 board_path: The path to the board dir.
479 url_suffix: The remote subdirectory where we should upload the packages.
Zdenek Behan62a57792012-08-31 15:09:08 +0200480 prepackaged: If given, a tarball that has been packaged outside of this
481 script and should be used.
Gilad Arnold2b79e2d2015-06-02 11:26:07 -0700482 toolchains_overlay_tarballs: List of toolchains overlay tarball
483 specifications to upload. Items take the form
484 "toolchains_spec:/path/to/tarball".
485 toolchains_overlay_upload_path: Path template under the bucket to place
486 toolchains overlay tarballs.
Mike Frysinger9e979b92012-11-29 02:55:09 -0500487 toolchain_tarballs: List of toolchain tarballs to upload.
488 toolchain_upload_path: Path under the bucket to place toolchain tarballs.
David James8fa34ea2011-04-15 13:00:20 -0700489 """
490 remote_location = '%s/%s' % (self._upload_location.rstrip('/'), url_suffix)
491 assert remote_location.startswith('gs://')
Zdenek Behan86c15e92012-10-13 00:55:47 +0200492 boardname = os.path.basename(board_path.rstrip('/'))
493 # We do not upload non SDK board tarballs,
494 assert boardname == constants.CHROOT_BUILDER_BOARD
495 assert prepackaged is not None
Zdenek Behan62a57792012-08-31 15:09:08 +0200496
Mike Frysinger8092a632014-05-24 13:25:46 -0400497 version_str = self._version[len('chroot-'):]
Mike Frysinger8e727a32013-01-16 16:57:53 -0500498 remote_tarfile = toolchain.GetSdkURL(
499 for_gsutil=True, suburl='cros-sdk-%s.tar.xz' % (version_str,))
Zdenek Behan86c15e92012-10-13 00:55:47 +0200500 # For SDK, also upload the manifest which is guaranteed to exist
501 # by the builderstage.
Mike Frysinger540883b2014-05-24 13:46:16 -0400502 self._Upload(prepackaged + '.Manifest', remote_tarfile + '.Manifest')
503 self._Upload(prepackaged, remote_tarfile)
Zdenek Behan86c15e92012-10-13 00:55:47 +0200504
Gilad Arnold2b79e2d2015-06-02 11:26:07 -0700505 # Upload SDK toolchains overlays and toolchain tarballs, if given.
Gilad Arnoldad333182015-05-27 15:50:41 -0700506 for tarball_list, upload_path, qualifier_name in (
Gilad Arnold2b79e2d2015-06-02 11:26:07 -0700507 (toolchains_overlay_tarballs, toolchains_overlay_upload_path,
508 'toolchains'),
Gilad Arnoldad333182015-05-27 15:50:41 -0700509 (toolchain_tarballs, toolchain_upload_path, 'target')):
Gilad Arnold2b79e2d2015-06-02 11:26:07 -0700510 for tarball_spec in tarball_list:
511 qualifier_val, local_path = tarball_spec.split(':')
Gilad Arnoldad333182015-05-27 15:50:41 -0700512 suburl = upload_path % {qualifier_name: qualifier_val}
513 remote_path = toolchain.GetSdkURL(for_gsutil=True, suburl=suburl)
514 self._Upload(local_path, remote_path)
Mike Frysinger9e979b92012-11-29 02:55:09 -0500515
Zdenek Behan86c15e92012-10-13 00:55:47 +0200516 # Finally, also update the pointer to the latest SDK on which polling
517 # scripts rely.
David James4bc13702013-03-26 08:08:04 -0700518 with osutils.TempDir() as tmpdir:
Zdenek Behan86c15e92012-10-13 00:55:47 +0200519 pointerfile = os.path.join(tmpdir, 'cros-sdk-latest.conf')
Mike Frysinger8e727a32013-01-16 16:57:53 -0500520 remote_pointerfile = toolchain.GetSdkURL(for_gsutil=True,
521 suburl='cros-sdk-latest.conf')
Zdenek Behan86c15e92012-10-13 00:55:47 +0200522 osutils.WriteFile(pointerfile, 'LATEST_SDK="%s"' % version_str)
Mike Frysinger540883b2014-05-24 13:46:16 -0400523 self._Upload(pointerfile, remote_pointerfile)
Zdenek Behan33a34112012-09-10 21:07:51 +0200524
Chris Sosa6a5dceb2012-05-14 13:48:56 -0700525 def _GetTargets(self):
526 """Retuns the list of targets to use."""
527 targets = self._slave_targets[:]
528 if self._target:
529 targets.append(self._target)
530
531 return targets
532
Mike Frysinger8092a632014-05-24 13:25:46 -0400533 def SyncHostPrebuilts(self, key, git_sync, sync_binhost_conf):
David Jamesc0f158a2011-02-22 16:07:29 -0800534 """Synchronize host prebuilt files.
David James05bcb2b2011-02-09 09:25:47 -0800535
David Jamesc0f158a2011-02-22 16:07:29 -0800536 This function will sync both the standard host packages, plus the host
537 packages associated with all targets that have been "setup" with the
538 current host's chroot. For instance, if this host has been used to build
539 x86-generic, it will sync the host packages associated with
540 'i686-pc-linux-gnu'. If this host has also been used to build arm-generic,
541 it will also sync the host packages associated with
542 'armv7a-cros-linux-gnueabi'.
David James05bcb2b2011-02-09 09:25:47 -0800543
David Jamesc0f158a2011-02-22 16:07:29 -0800544 Args:
David Jamesc0f158a2011-02-22 16:07:29 -0800545 key: The variable key to update in the git file.
546 git_sync: If set, update make.conf of target to reference the latest
547 prebuilt packages generated here.
548 sync_binhost_conf: If set, update binhost config file in
549 chromiumos-overlay for the host.
550 """
Mike Nicholsa1414162021-04-22 20:07:22 +0000551 # Slave boards are listed before the master board so that the master board
David Jamese2488642011-11-14 16:15:20 -0800552 # takes priority (i.e. x86-generic preflight host prebuilts takes priority
553 # over preflight host prebuilts from other builders.)
554 binhost_urls = []
Chris Sosa6a5dceb2012-05-14 13:48:56 -0700555 for target in self._GetTargets():
Mike Frysinger8092a632014-05-24 13:25:46 -0400556 url_suffix = _REL_HOST_PATH % {'version': self._version,
David James4058b0d2011-12-08 21:24:50 -0800557 'host_arch': _HOST_ARCH,
558 'target': target}
David Jamese2488642011-11-14 16:15:20 -0800559 packages_url_suffix = '%s/packages' % url_suffix.rstrip('/')
David James05bcb2b2011-02-09 09:25:47 -0800560
Mike Frysinger540883b2014-05-24 13:46:16 -0400561 if self._target == target and not self._skip_upload:
David Jamese2488642011-11-14 16:15:20 -0800562 # Upload prebuilts.
563 package_path = os.path.join(self._build_path, _HOST_PACKAGES_PATH)
564 self._UploadPrebuilt(package_path, packages_url_suffix)
David James8ece7ee2011-06-29 16:02:30 -0700565
David Jamese2488642011-11-14 16:15:20 -0800566 # Record URL where prebuilts were uploaded.
567 binhost_urls.append('%s/%s/' % (self._binhost_base_url.rstrip('/'),
568 packages_url_suffix.rstrip('/')))
569
David James20b2b6f2011-11-18 15:11:58 -0800570 binhost = ' '.join(binhost_urls)
David James8ece7ee2011-06-29 16:02:30 -0700571 if git_sync:
David Jamesb26b9312014-12-15 11:26:46 -0800572 git_file = os.path.join(self._build_path, _PREBUILT_MAKE_CONF[_HOST_ARCH])
Mike Frysinger86509232014-05-24 13:18:37 -0400573 RevGitFile(git_file, {key: binhost}, dryrun=self._dryrun)
David James8ece7ee2011-06-29 16:02:30 -0700574 if sync_binhost_conf:
David Jamesb26b9312014-12-15 11:26:46 -0800575 binhost_conf = os.path.join(
576 self._binhost_conf_dir, 'host', '%s-%s.conf' % (_HOST_ARCH, key))
David Jamese2488642011-11-14 16:15:20 -0800577 UpdateBinhostConfFile(binhost_conf, key, binhost)
David Jamesc0f158a2011-02-22 16:07:29 -0800578
Mike Frysinger8092a632014-05-24 13:25:46 -0400579 def SyncBoardPrebuilts(self, key, git_sync, sync_binhost_conf,
Mike Frysinger9e979b92012-11-29 02:55:09 -0500580 upload_board_tarball, prepackaged_board,
Gilad Arnold2b79e2d2015-06-02 11:26:07 -0700581 toolchains_overlay_tarballs,
582 toolchains_overlay_upload_path,
Mike Frysinger9e979b92012-11-29 02:55:09 -0500583 toolchain_tarballs, toolchain_upload_path):
David Jamesc0f158a2011-02-22 16:07:29 -0800584 """Synchronize board prebuilt files.
585
586 Args:
David Jamesc0f158a2011-02-22 16:07:29 -0800587 key: The variable key to update in the git file.
588 git_sync: If set, update make.conf of target to reference the latest
589 prebuilt packages generated here.
590 sync_binhost_conf: If set, update binhost config file in
591 chromiumos-overlay for the current board.
David James8fa34ea2011-04-15 13:00:20 -0700592 upload_board_tarball: Include a tarball of the board in our upload.
Zdenek Behan62a57792012-08-31 15:09:08 +0200593 prepackaged_board: A tarball of the board built outside of this script.
Gilad Arnold2b79e2d2015-06-02 11:26:07 -0700594 toolchains_overlay_tarballs: List of toolchains overlay tarball
595 specifications to upload. Items take the form
596 "toolchains_spec:/path/to/tarball".
597 toolchains_overlay_upload_path: Path template under the bucket to place
598 toolchains overlay tarballs.
Mike Frysinger9e979b92012-11-29 02:55:09 -0500599 toolchain_tarballs: A list of toolchain tarballs to upload.
600 toolchain_upload_path: Path under the bucket to place toolchain tarballs.
David Jamesc0f158a2011-02-22 16:07:29 -0800601 """
David Jamesb26b9312014-12-15 11:26:46 -0800602 updated_binhosts = set()
Chris Sosa6a5dceb2012-05-14 13:48:56 -0700603 for target in self._GetTargets():
David Jamese2488642011-11-14 16:15:20 -0800604 board_path = os.path.join(self._build_path,
David James4058b0d2011-12-08 21:24:50 -0800605 _BOARD_PATH % {'board': target.board_variant})
David Jamese2488642011-11-14 16:15:20 -0800606 package_path = os.path.join(board_path, 'packages')
Mike Frysinger8092a632014-05-24 13:25:46 -0400607 url_suffix = _REL_BOARD_PATH % {'target': target,
608 'version': self._version}
David Jamese2488642011-11-14 16:15:20 -0800609 packages_url_suffix = '%s/packages' % url_suffix.rstrip('/')
David James8fa34ea2011-04-15 13:00:20 -0700610
Matt Tennante8179042013-10-01 15:47:32 -0700611 # Process the target board differently if it is the main --board.
Mike Frysinger540883b2014-05-24 13:46:16 -0400612 if self._target == target and not self._skip_upload:
Matt Tennante8179042013-10-01 15:47:32 -0700613 # This strips "chroot" prefix because that is sometimes added as the
614 # --prepend-version argument (e.g. by chromiumos-sdk bot).
615 # TODO(build): Clean it up to be less hard-coded.
Mike Frysinger8092a632014-05-24 13:25:46 -0400616 version_str = self._version[len('chroot-'):]
Mike Frysinger9e979b92012-11-29 02:55:09 -0500617
David Jamese2488642011-11-14 16:15:20 -0800618 # Upload board tarballs in the background.
619 if upload_board_tarball:
Mike Frysinger9e979b92012-11-29 02:55:09 -0500620 if toolchain_upload_path:
621 toolchain_upload_path %= {'version': version_str}
Gilad Arnold2b79e2d2015-06-02 11:26:07 -0700622 if toolchains_overlay_upload_path:
623 toolchains_overlay_upload_path %= {'version': version_str}
Mike Frysinger9e979b92012-11-29 02:55:09 -0500624 tar_process = multiprocessing.Process(
625 target=self._UploadSdkTarball,
Mike Frysinger8092a632014-05-24 13:25:46 -0400626 args=(board_path, url_suffix, prepackaged_board,
Gilad Arnold2b79e2d2015-06-02 11:26:07 -0700627 toolchains_overlay_tarballs,
628 toolchains_overlay_upload_path, toolchain_tarballs,
629 toolchain_upload_path))
David Jamese2488642011-11-14 16:15:20 -0800630 tar_process.start()
David James8fa34ea2011-04-15 13:00:20 -0700631
David Jamese2488642011-11-14 16:15:20 -0800632 # Upload prebuilts.
633 self._UploadPrebuilt(package_path, packages_url_suffix)
David James8fa34ea2011-04-15 13:00:20 -0700634
David Jamese2488642011-11-14 16:15:20 -0800635 # Make sure we finished uploading the board tarballs.
636 if upload_board_tarball:
637 tar_process.join()
638 assert tar_process.exitcode == 0
David Jamesc0f158a2011-02-22 16:07:29 -0800639
David Jamese2488642011-11-14 16:15:20 -0800640 # Record URL where prebuilts were uploaded.
641 url_value = '%s/%s/' % (self._binhost_base_url.rstrip('/'),
642 packages_url_suffix.rstrip('/'))
643
644 if git_sync:
David James4058b0d2011-12-08 21:24:50 -0800645 git_file = DeterminePrebuiltConfFile(self._build_path, target)
Mike Frysinger86509232014-05-24 13:18:37 -0400646 RevGitFile(git_file, {key: url_value}, dryrun=self._dryrun)
Matt Tennante8179042013-10-01 15:47:32 -0700647
David Jamese2488642011-11-14 16:15:20 -0800648 if sync_binhost_conf:
Matt Tennante8179042013-10-01 15:47:32 -0700649 # Update the binhost configuration file in git.
David Jamesb26b9312014-12-15 11:26:46 -0800650 binhost_conf = os.path.join(
651 self._binhost_conf_dir, 'target', '%s-%s.conf' % (target, key))
652 updated_binhosts.add(binhost_conf)
David Jamese2488642011-11-14 16:15:20 -0800653 UpdateBinhostConfFile(binhost_conf, key, url_value)
David James05bcb2b2011-02-09 09:25:47 -0800654
David Jamesb26b9312014-12-15 11:26:46 -0800655 if sync_binhost_conf:
656 # Clear all old binhosts. The files must be left empty in case anybody
657 # is referring to them.
658 all_binhosts = set(glob.glob(os.path.join(
659 self._binhost_conf_dir, 'target', '*-%s.conf' % key)))
660 for binhost_conf in all_binhosts - updated_binhosts:
661 UpdateBinhostConfFile(binhost_conf, key, '')
662
David James05bcb2b2011-02-09 09:25:47 -0800663
Mike Nicholsa1414162021-04-22 20:07:22 +0000664class _AddSlaveBoardAction(argparse.Action):
665 """Callback that adds a slave board to the list of slave targets."""
Mike Frysingerb87bb782015-06-04 02:46:50 -0400666 def __call__(self, parser, namespace, values, option_string=None):
667 getattr(namespace, self.dest).append(BuildTarget(values))
David James4058b0d2011-12-08 21:24:50 -0800668
669
Mike Nicholsa1414162021-04-22 20:07:22 +0000670class _AddSlaveProfileAction(argparse.Action):
671 """Callback that adds a slave profile to the list of slave targets."""
Mike Frysingerb87bb782015-06-04 02:46:50 -0400672 def __call__(self, parser, namespace, values, option_string=None):
673 if not namespace.slave_targets:
674 parser.error('Must specify --slave-board before --slave-profile')
675 if namespace.slave_targets[-1].profile is not None:
676 parser.error('Cannot specify --slave-profile twice for same board')
677 namespace.slave_targets[-1].profile = values
David James4058b0d2011-12-08 21:24:50 -0800678
679
Mike Frysinger86509232014-05-24 13:18:37 -0400680def ParseOptions(argv):
Chris Sosa6a5dceb2012-05-14 13:48:56 -0700681 """Returns options given by the user and the target specified.
682
Mike Frysinger86509232014-05-24 13:18:37 -0400683 Args:
684 argv: The args to parse.
685
Mike Frysinger1a736a82013-12-12 01:50:59 -0500686 Returns:
687 A tuple containing a parsed options object and BuildTarget.
688 The target instance is None if no board is specified.
Chris Sosa6a5dceb2012-05-14 13:48:56 -0700689 """
Mike Frysingerb87bb782015-06-04 02:46:50 -0400690 parser = commandline.ArgumentParser()
691 parser.add_argument('-H', '--binhost-base-url', default=_BINHOST_BASE_URL,
692 help='Base URL to use for binhost in make.conf updates')
693 parser.add_argument('--previous-binhost-url', action='append', default=[],
694 help='Previous binhost URL')
695 parser.add_argument('-b', '--board',
696 help='Board type that was built on this machine')
697 parser.add_argument('-B', '--prepackaged-tarball', type='path',
698 help='Board tarball prebuilt outside of this script.')
Gilad Arnold2b79e2d2015-06-02 11:26:07 -0700699 parser.add_argument('--toolchains-overlay-tarball',
700 dest='toolchains_overlay_tarballs',
Mike Frysingerb87bb782015-06-04 02:46:50 -0400701 action='append', default=[],
Gilad Arnold2b79e2d2015-06-02 11:26:07 -0700702 help='Toolchains overlay tarball specification to '
703 'upload. Takes the form '
704 '"toolchains_spec:/path/to/tarball".')
705 parser.add_argument('--toolchains-overlay-upload-path', default='',
706 help='Path template for uploading toolchains overlays.')
Mike Frysingerb87bb782015-06-04 02:46:50 -0400707 parser.add_argument('--toolchain-tarball', dest='toolchain_tarballs',
708 action='append', default=[],
709 help='Redistributable toolchain tarball.')
Gilad Arnold2b79e2d2015-06-02 11:26:07 -0700710 parser.add_argument('--toolchain-upload-path', default='',
Mike Frysingerb87bb782015-06-04 02:46:50 -0400711 help='Path to place toolchain tarballs in the sdk tree.')
712 parser.add_argument('--profile',
713 help='Profile that was built on this machine')
Mike Nicholsa1414162021-04-22 20:07:22 +0000714 parser.add_argument('--slave-board', default=[], action=_AddSlaveBoardAction,
Mike Frysingerb87bb782015-06-04 02:46:50 -0400715 dest='slave_targets',
716 help='Board type that was built on a slave machine. To '
717 'add a profile to this board, use --slave-profile.')
Mike Nicholsa1414162021-04-22 20:07:22 +0000718 parser.add_argument('--slave-profile', action=_AddSlaveProfileAction,
Mike Frysingerb87bb782015-06-04 02:46:50 -0400719 help='Board profile that was built on a slave machine. '
720 'Applies to previous slave board.')
721 parser.add_argument('-p', '--build-path', required=True,
722 help='Path to the directory containing the chroot')
723 parser.add_argument('--packages', action='append', default=[],
724 help='Only include the specified packages. '
725 '(Default is to include all packages.)')
726 parser.add_argument('-s', '--sync-host', default=False, action='store_true',
727 help='Sync host prebuilts')
728 parser.add_argument('-g', '--git-sync', default=False, action='store_true',
729 help='Enable git version sync (This commits to a repo.) '
730 'This is used by full builders to commit directly '
731 'to board overlays.')
732 parser.add_argument('-u', '--upload',
733 help='Upload location')
734 parser.add_argument('-V', '--prepend-version',
735 help='Add an identifier to the front of the version')
736 parser.add_argument('-f', '--filters', action='store_true', default=False,
737 help='Turn on filtering of private ebuild packages')
738 parser.add_argument('-k', '--key', default='PORTAGE_BINHOST',
739 help='Key to update in make.conf / binhost.conf')
740 parser.add_argument('--set-version',
741 help='Specify the version string')
742 parser.add_argument('--sync-binhost-conf', default=False, action='store_true',
743 help='Update binhost.conf in chromiumos-overlay or '
Mike Frysinger80de5012019-08-01 14:10:53 -0400744 "chromeos-overlay. Commit the changes, but don't "
Mike Frysingerb87bb782015-06-04 02:46:50 -0400745 'push them. This is used for preflight binhosts.')
746 parser.add_argument('--binhost-conf-dir',
747 help='Directory to commit binhost config with '
748 '--sync-binhost-conf.')
749 parser.add_argument('-P', '--private', action='store_true', default=False,
750 help='Mark gs:// uploads as private.')
751 parser.add_argument('--skip-upload', action='store_true', default=False,
752 help='Skip upload step.')
753 parser.add_argument('--upload-board-tarball', action='store_true',
754 default=False,
755 help='Upload board tarball to Google Storage.')
756 parser.add_argument('-n', '--dry-run', dest='dryrun',
757 action='store_true', default=False,
Mike Frysinger80de5012019-08-01 14:10:53 -0400758 help="Don't push or upload prebuilts.")
David James8c846492011-01-25 17:07:29 -0800759
Mike Frysingerb87bb782015-06-04 02:46:50 -0400760 options = parser.parse_args(argv)
David James8ece7ee2011-06-29 16:02:30 -0700761 if not options.upload and not options.skip_upload:
Mike Frysinger86509232014-05-24 13:18:37 -0400762 parser.error('you need to provide an upload location using -u')
David James8ece7ee2011-06-29 16:02:30 -0700763 if not options.set_version and options.skip_upload:
Mike Frysinger86509232014-05-24 13:18:37 -0400764 parser.error('If you are using --skip-upload, you must specify a '
765 'version number using --set-version.')
Scott Zawalskiab1bed32011-03-16 15:24:24 -0700766
Chris Sosa6a5dceb2012-05-14 13:48:56 -0700767 target = None
768 if options.board:
769 target = BuildTarget(options.board, options.profile)
770
771 if target in options.slave_targets:
Mike Frysinger86509232014-05-24 13:18:37 -0400772 parser.error('--board/--profile must not also be a slave target.')
David Jamese2488642011-11-14 16:15:20 -0800773
David James4058b0d2011-12-08 21:24:50 -0800774 if len(set(options.slave_targets)) != len(options.slave_targets):
Mike Frysinger86509232014-05-24 13:18:37 -0400775 parser.error('--slave-boards must not have duplicates.')
David Jamese2488642011-11-14 16:15:20 -0800776
David James4058b0d2011-12-08 21:24:50 -0800777 if options.slave_targets and options.git_sync:
Mike Frysinger86509232014-05-24 13:18:37 -0400778 parser.error('--slave-boards is not compatible with --git-sync')
David Jamese2488642011-11-14 16:15:20 -0800779
David James8ece7ee2011-06-29 16:02:30 -0700780 if (options.upload_board_tarball and options.skip_upload and
781 options.board == 'amd64-host'):
Mike Frysinger86509232014-05-24 13:18:37 -0400782 parser.error('--skip-upload is not compatible with '
783 '--upload-board-tarball and --board=amd64-host')
David James8fa34ea2011-04-15 13:00:20 -0700784
David James8ece7ee2011-06-29 16:02:30 -0700785 if (options.upload_board_tarball and not options.skip_upload and
786 not options.upload.startswith('gs://')):
Mike Frysinger86509232014-05-24 13:18:37 -0400787 parser.error('--upload-board-tarball only works with gs:// URLs.\n'
788 '--upload must be a gs:// URL.')
David James8fa34ea2011-04-15 13:00:20 -0700789
Zdenek Behan86c15e92012-10-13 00:55:47 +0200790 if options.upload_board_tarball and options.prepackaged_tarball is None:
Mike Frysinger86509232014-05-24 13:18:37 -0400791 parser.error('--upload-board-tarball requires --prepackaged-tarball')
Zdenek Behan86c15e92012-10-13 00:55:47 +0200792
Scott Zawalskiab1bed32011-03-16 15:24:24 -0700793 if options.private:
794 if options.sync_host:
Mike Frysinger86509232014-05-24 13:18:37 -0400795 parser.error('--private and --sync-host/-s cannot be specified '
796 'together; we do not support private host prebuilts')
Scott Zawalskiab1bed32011-03-16 15:24:24 -0700797
David James8ece7ee2011-06-29 16:02:30 -0700798 if not options.upload or not options.upload.startswith('gs://'):
Mike Frysinger86509232014-05-24 13:18:37 -0400799 parser.error('--private is only valid for gs:// URLs; '
800 '--upload must be a gs:// URL.')
Scott Zawalskiab1bed32011-03-16 15:24:24 -0700801
802 if options.binhost_base_url != _BINHOST_BASE_URL:
Mike Frysinger86509232014-05-24 13:18:37 -0400803 parser.error('when using --private the --binhost-base-url '
804 'is automatically derived.')
David James27fa7d12011-06-29 17:24:14 -0700805
David Jamesc31168e2014-06-05 14:40:05 -0700806 if options.sync_binhost_conf and not options.binhost_conf_dir:
807 parser.error('--sync-binhost-conf requires --binhost-conf-dir')
808
Gilad Arnold2b79e2d2015-06-02 11:26:07 -0700809 if (options.toolchains_overlay_tarballs and
810 not options.toolchains_overlay_upload_path):
811 parser.error('--toolchains-overlay-tarball requires '
812 '--toolchains-overlay-upload-path')
Gilad Arnoldad333182015-05-27 15:50:41 -0700813
Chris Sosa6a5dceb2012-05-14 13:48:56 -0700814 return options, target
David Jamesc0f158a2011-02-22 16:07:29 -0800815
Mike Frysingercc838832014-05-24 13:10:30 -0400816
Mike Frysinger86509232014-05-24 13:18:37 -0400817def main(argv):
David Jamesdb401072011-06-10 12:17:16 -0700818 # Set umask to a sane value so that files created as root are readable.
Mike Frysinger60ec1012013-10-21 00:11:10 -0400819 os.umask(0o22)
David Jamesdb401072011-06-10 12:17:16 -0700820
Mike Frysinger86509232014-05-24 13:18:37 -0400821 options, target = ParseOptions(argv)
David Jamesc0f158a2011-02-22 16:07:29 -0800822
David James05bcb2b2011-02-09 09:25:47 -0800823 # Calculate a list of Packages index files to compare against. Whenever we
824 # upload a package, we check to make sure it's not already stored in one of
825 # the packages files we uploaded. This list of packages files might contain
826 # both board and host packages.
David Jamesce093af2011-02-23 15:21:58 -0800827 pkg_indexes = _GrabAllRemotePackageIndexes(options.previous_binhost_url)
David James8c846492011-01-25 17:07:29 -0800828
David James8ece7ee2011-06-29 16:02:30 -0700829 if options.set_version:
830 version = options.set_version
831 else:
832 version = GetVersion()
Matt Tennante8179042013-10-01 15:47:32 -0700833
David Jamesc0f158a2011-02-22 16:07:29 -0800834 if options.prepend_version:
835 version = '%s-%s' % (options.prepend_version, version)
836
Scott Zawalskiab1bed32011-03-16 15:24:24 -0700837 acl = 'public-read'
838 binhost_base_url = options.binhost_base_url
839
David Jamesadd21432013-05-21 10:04:07 -0700840 if options.private:
Scott Zawalskiab1bed32011-03-16 15:24:24 -0700841 binhost_base_url = options.upload
David Jamesadd21432013-05-21 10:04:07 -0700842 if target:
Prathmesh Prabhu421eef22014-10-16 17:13:19 -0700843 acl = portage_util.FindOverlayFile(_GOOGLESTORAGE_GSUTIL_FILE,
844 board=target.board_variant,
845 buildroot=options.build_path)
Ben Chan067de492015-01-06 17:19:13 -0800846 if acl is None:
847 cros_build_lib.Die('No Google Storage ACL file %s found in %s overlay.',
848 _GOOGLESTORAGE_GSUTIL_FILE, target.board_variant)
Scott Zawalskiab1bed32011-03-16 15:24:24 -0700849
David Jamesb26b9312014-12-15 11:26:46 -0800850 binhost_conf_dir = None
851 if options.binhost_conf_dir:
852 binhost_conf_dir = os.path.join(options.build_path,
853 options.binhost_conf_dir)
854
Scott Zawalskiab1bed32011-03-16 15:24:24 -0700855 uploader = PrebuiltUploader(options.upload, acl, binhost_base_url,
David James615e5b52011-06-03 11:10:15 -0700856 pkg_indexes, options.build_path,
David James27fa7d12011-06-29 17:24:14 -0700857 options.packages, options.skip_upload,
David Jamesb26b9312014-12-15 11:26:46 -0800858 binhost_conf_dir, options.dryrun,
Mike Frysinger8092a632014-05-24 13:25:46 -0400859 target, options.slave_targets, version)
David Jamesc0f158a2011-02-22 16:07:29 -0800860
David James8c846492011-01-25 17:07:29 -0800861 if options.sync_host:
Mike Frysinger8092a632014-05-24 13:25:46 -0400862 uploader.SyncHostPrebuilts(options.key, options.git_sync,
Chris Sosa6a5dceb2012-05-14 13:48:56 -0700863 options.sync_binhost_conf)
David James8c846492011-01-25 17:07:29 -0800864
Chris Sosa62c8ff52012-06-04 15:03:12 -0700865 if options.board or options.slave_targets:
Mike Frysinger8092a632014-05-24 13:25:46 -0400866 uploader.SyncBoardPrebuilts(options.key, options.git_sync,
Chris Sosa6a5dceb2012-05-14 13:48:56 -0700867 options.sync_binhost_conf,
Zdenek Behan62a57792012-08-31 15:09:08 +0200868 options.upload_board_tarball,
Mike Frysinger9e979b92012-11-29 02:55:09 -0500869 options.prepackaged_tarball,
Gilad Arnold2b79e2d2015-06-02 11:26:07 -0700870 options.toolchains_overlay_tarballs,
871 options.toolchains_overlay_upload_path,
Mike Frysinger9e979b92012-11-29 02:55:09 -0500872 options.toolchain_tarballs,
873 options.toolchain_upload_path)