blob: 4036e82cd094452bd50274f871e06de77c92a29a [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 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
David James97d95872012-11-16 15:09:56 -080035from chromite.lib import git
Julio Hurtadofad17992021-05-20 21:24:24 +000036from chromite.lib import gerrit
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
David James8c846492011-01-25 17:07:29 -080057_HOST_PACKAGES_PATH = 'chroot/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 """
111 if os.path.exists(filename):
112 file_fh = open(filename)
113 else:
114 file_fh = open(filename, 'w+')
115 file_lines = []
116 found = False
David Jamesb26b9312014-12-15 11:26:46 -0800117 made_changes = False
David James8c846492011-01-25 17:07:29 -0800118 keyval_str = '%(key)s=%(value)s'
119 for line in file_fh:
120 # Strip newlines from end of line. We already add newlines below.
Mike Frysinger80de5012019-08-01 14:10:53 -0400121 line = line.rstrip('\n')
David James8c846492011-01-25 17:07:29 -0800122
123 if len(line.split('=')) != 2:
124 # Skip any line that doesn't fit key=val.
125 file_lines.append(line)
126 continue
127
128 file_var, file_val = line.split('=')
129 if file_var == key:
130 found = True
Mike Frysingerff441bf2014-05-24 13:47:21 -0400131 print('Updating %s=%s to %s="%s"' % (file_var, file_val, key, value))
David James8c846492011-01-25 17:07:29 -0800132 value = '"%s"' % value
David Jamesb26b9312014-12-15 11:26:46 -0800133 made_changes |= (file_val != value)
David James8c846492011-01-25 17:07:29 -0800134 file_lines.append(keyval_str % {'key': key, 'value': value})
135 else:
136 file_lines.append(keyval_str % {'key': file_var, 'value': file_val})
137
138 if not found:
Brian Harring2a014302012-05-12 00:53:33 -0700139 value = '"%s"' % value
David Jamesb26b9312014-12-15 11:26:46 -0800140 made_changes = True
David James8c846492011-01-25 17:07:29 -0800141 file_lines.append(keyval_str % {'key': key, 'value': value})
142
143 file_fh.close()
144 # write out new file
Brian Harringaf019fb2012-05-10 15:06:13 -0700145 osutils.WriteFile(filename, '\n'.join(file_lines) + '\n')
David Jamesb26b9312014-12-15 11:26:46 -0800146 return made_changes
David James8c846492011-01-25 17:07:29 -0800147
148
Mike Nicholsa6818c52018-04-09 11:05:42 -0600149def RevGitFile(filename, data, dryrun=False):
David James8c846492011-01-25 17:07:29 -0800150 """Update and push the git file.
151
Mike Frysinger5b34d732013-01-17 15:11:58 -0500152 Args:
153 filename: file to modify that is in a git repo already
154 data: A dict of key/values to update in |filename|
Matt Tennante8179042013-10-01 15:47:32 -0700155 dryrun: If True, do not actually commit the change.
David James8c846492011-01-25 17:07:29 -0800156 """
157 prebuilt_branch = 'prebuilt_branch'
David James1b6e67a2011-05-19 21:32:38 -0700158 cwd = os.path.abspath(os.path.dirname(filename))
Julio Hurtadofad17992021-05-20 21:24:24 +0000159 remote_name = git.RunGit(cwd, ['remote']).stdout.strip()
160 gerrit_helper = gerrit.GetGerritHelper(remote_name)
161 remote_url = git.RunGit(
Julio Hurtadoef27d992021-06-29 15:51:13 +0000162 cwd, ['config', '--get', f'remote.{remote_name}.url']).stdout.strip()
Mike Frysinger5b34d732013-01-17 15:11:58 -0500163 description = '%s: updating %s' % (os.path.basename(filename),
164 ', '.join(data.keys()))
165 # UpdateLocalFile will print out the keys/values for us.
Mike Frysingerff441bf2014-05-24 13:47:21 -0400166 print('Revving git file %s' % filename)
Julio Hurtadofad17992021-05-20 21:24:24 +0000167 git.CreatePushBranch(prebuilt_branch, cwd)
168 for key, value in data.items():
169 UpdateLocalFile(filename, value, key)
170 git.RunGit(cwd, ['add', filename])
171 git.RunGit(cwd, ['commit', '-m', description])
Julio Hurtado2d4817d2021-04-29 16:03:58 +0000172
Julio Hurtadofad17992021-05-20 21:24:24 +0000173 tracking_info = git.GetTrackingBranch(
174 cwd, prebuilt_branch, for_push=True, for_checkout=False)
175 gpatch = gerrit_helper.CreateGerritPatch(
Julio Hurtado8f716a32021-07-14 21:32:13 +0000176 cwd, remote_url, ref=tracking_info.ref, notify='NONE')
Julio Hurtadoef27d992021-06-29 15:51:13 +0000177 gerrit_helper.SetReview(
178 gpatch, labels={'Bot-Commit': 1}, dryrun=dryrun, notify='NONE')
179 gerrit_helper.SubmitChange(gpatch, dryrun=dryrun, notify='NONE')
David James8c846492011-01-25 17:07:29 -0800180
181
182def GetVersion():
183 """Get the version to put in LATEST and update the git version with."""
Mike Frysinger0b92cfe2012-12-13 02:13:45 -0500184 return datetime.datetime.now().strftime('%Y.%m.%d.%H%M%S')
David James8c846492011-01-25 17:07:29 -0800185
186
Mike Frysinger540883b2014-05-24 13:46:16 -0400187def _GsUpload(gs_context, acl, local_file, remote_file):
David James8c846492011-01-25 17:07:29 -0800188 """Upload to GS bucket.
189
190 Args:
Mike Frysinger540883b2014-05-24 13:46:16 -0400191 gs_context: A lib.gs.GSContext instance.
192 acl: The ACL to use for uploading the file.
Matt Tennante8179042013-10-01 15:47:32 -0700193 local_file: The local file to be uploaded.
194 remote_file: The remote location to upload to.
David James8c846492011-01-25 17:07:29 -0800195 """
Scott Zawalskiab1bed32011-03-16 15:24:24 -0700196 CANNED_ACLS = ['public-read', 'private', 'bucket-owner-read',
197 'authenticated-read', 'bucket-owner-full-control',
198 'public-read-write']
Scott Zawalskiab1bed32011-03-16 15:24:24 -0700199 if acl in CANNED_ACLS:
David James9374aac2013-10-08 16:00:17 -0700200 gs_context.Copy(local_file, remote_file, acl=acl)
Scott Zawalskiab1bed32011-03-16 15:24:24 -0700201 else:
202 # For private uploads we assume that the overlay board is set up properly
David James015af872012-06-19 15:24:36 -0700203 # and a googlestore_acl.xml is present. Otherwise, this script errors.
David James7b7d7c32015-04-02 13:48:17 -0700204 # We set version=0 here to ensure that the ACL is set only once (see
205 # http://b/15883752#comment54).
206 try:
207 gs_context.Copy(local_file, remote_file, version=0)
208 except gs.GSContextPreconditionFailed as ex:
209 # If we received a GSContextPreconditionFailed error, we know that the
210 # file exists now, but we don't know whether our specific update
211 # succeeded. See http://b/15883752#comment62
212 logging.warning(
213 'Assuming upload succeeded despite PreconditionFailed errors: %s', ex)
214
Gabe Black40169e62014-06-17 15:23:47 -0700215 if acl.endswith('.xml'):
216 # Apply the passed in ACL xml file to the uploaded object.
217 gs_context.SetACL(remote_file, acl=acl)
218 else:
Mike Frysinger5186f262017-09-13 10:26:19 -0400219 gs_context.ChangeACL(remote_file, acl_args_file=acl)
Scott Zawalskiab1bed32011-03-16 15:24:24 -0700220
Mike Frysingercc838832014-05-24 13:10:30 -0400221
Mike Frysinger540883b2014-05-24 13:46:16 -0400222def RemoteUpload(gs_context, acl, files, pool=10):
David James8c846492011-01-25 17:07:29 -0800223 """Upload to google storage.
224
225 Create a pool of process and call _GsUpload with the proper arguments.
226
227 Args:
Mike Frysinger540883b2014-05-24 13:46:16 -0400228 gs_context: A lib.gs.GSContext instance.
David Jamesfd0b0852011-02-23 11:15:36 -0800229 acl: The canned acl used for uploading. acl can be one of: "public-read",
230 "public-read-write", "authenticated-read", "bucket-owner-read",
231 "bucket-owner-full-control", or "private".
David James8c846492011-01-25 17:07:29 -0800232 files: dictionary with keys to local files and values to remote path.
233 pool: integer of maximum proesses to have at the same time.
234
235 Returns:
236 Return a set of tuple arguments of the failed uploads
237 """
Mike Frysinger540883b2014-05-24 13:46:16 -0400238 upload = functools.partial(_GsUpload, gs_context, acl)
Mike Frysinger0bdbc102019-06-13 15:27:29 -0400239 tasks = [[key, value] for key, value in files.items()]
Mike Frysinger540883b2014-05-24 13:46:16 -0400240 parallel.RunTasksInProcessPool(upload, tasks, pool)
David James8c846492011-01-25 17:07:29 -0800241
242
243def GenerateUploadDict(base_local_path, base_remote_path, pkgs):
244 """Build a dictionary of local remote file key pairs to upload.
245
246 Args:
247 base_local_path: The base path to the files on the local hard drive.
Matt Tennante8179042013-10-01 15:47:32 -0700248 base_remote_path: The base path to the remote paths.
David James8c846492011-01-25 17:07:29 -0800249 pkgs: The packages to upload.
250
251 Returns:
252 Returns a dictionary of local_path/remote_path pairs
253 """
254 upload_files = {}
255 for pkg in pkgs:
256 suffix = pkg['CPV'] + '.tbz2'
257 local_path = os.path.join(base_local_path, suffix)
David James7b7d7c32015-04-02 13:48:17 -0700258 assert os.path.exists(local_path), '%s does not exist' % local_path
Bertrand SIMONNET811bcde2014-11-20 15:21:25 -0800259 upload_files[local_path] = os.path.join(base_remote_path, suffix)
David James8c846492011-01-25 17:07:29 -0800260
Bertrand SIMONNET811bcde2014-11-20 15:21:25 -0800261 if pkg.get('DEBUG_SYMBOLS') == 'yes':
262 debugsuffix = pkg['CPV'] + '.debug.tbz2'
263 local_path = os.path.join(base_local_path, debugsuffix)
264 assert os.path.exists(local_path)
265 upload_files[local_path] = os.path.join(base_remote_path, debugsuffix)
Bertrand SIMONNET22e828b2014-11-11 16:27:06 -0800266
David James8c846492011-01-25 17:07:29 -0800267 return upload_files
268
Mike Frysingercc838832014-05-24 13:10:30 -0400269
Peter Mayo950e41a2014-02-06 21:07:33 +0000270def GetBoardOverlay(build_path, target):
David Jamese5867812012-10-19 12:02:20 -0700271 """Get the path to the board variant.
Mike Frysinger1a736a82013-12-12 01:50:59 -0500272
Mike Frysinger6f3c48e2015-05-06 02:38:51 -0400273 Args:
274 build_path: The path to the root of the build directory
275 target: The target board as a BuildTarget object.
Mike Frysinger1a736a82013-12-12 01:50:59 -0500276
Mike Frysinger6f3c48e2015-05-06 02:38:51 -0400277 Returns:
278 The last overlay configured for the given board as a string.
David James8c846492011-01-25 17:07:29 -0800279 """
David Jamese5867812012-10-19 12:02:20 -0700280 board = target.board_variant
Alex Deymo075c2292014-09-04 18:31:50 -0700281 overlays = portage_util.FindOverlays(constants.BOTH_OVERLAYS, board,
282 buildroot=build_path)
David Jamese5867812012-10-19 12:02:20 -0700283 # We only care about the last entry.
284 return overlays[-1]
David James8c846492011-01-25 17:07:29 -0800285
286
287def DeterminePrebuiltConfFile(build_path, target):
288 """Determine the prebuilt.conf file that needs to be updated for prebuilts.
289
Mike Frysinger1a736a82013-12-12 01:50:59 -0500290 Args:
291 build_path: The path to the root of the build directory
292 target: String representation of the board. This includes host and board
293 targets
David James8c846492011-01-25 17:07:29 -0800294
Mike Frysinger1a736a82013-12-12 01:50:59 -0500295 Returns:
296 A string path to a prebuilt.conf file to be updated.
David James8c846492011-01-25 17:07:29 -0800297 """
David James4058b0d2011-12-08 21:24:50 -0800298 if _HOST_ARCH == target:
David James8c846492011-01-25 17:07:29 -0800299 # We are host.
300 # Without more examples of hosts this is a kludge for now.
301 # TODO(Scottz): as new host targets come online expand this to
302 # work more like boards.
Chris Sosa471532a2011-02-01 15:10:06 -0800303 make_path = _PREBUILT_MAKE_CONF[target]
David James8c846492011-01-25 17:07:29 -0800304 else:
305 # We are a board
Peter Mayo950e41a2014-02-06 21:07:33 +0000306 board = GetBoardOverlay(build_path, target)
David James8c846492011-01-25 17:07:29 -0800307 make_path = os.path.join(board, 'prebuilt.conf')
308
309 return make_path
310
311
312def UpdateBinhostConfFile(path, key, value):
313 """Update binhost config file file with key=value.
314
315 Args:
316 path: Filename to update.
317 key: Key to update.
318 value: New value for key.
319 """
David Jamesb26b9312014-12-15 11:26:46 -0800320 cwd, filename = os.path.split(os.path.abspath(path))
Brian Harringaf019fb2012-05-10 15:06:13 -0700321 osutils.SafeMakedirs(cwd)
David Jamesf6e8fb72013-05-10 08:58:43 -0700322 if not git.GetCurrentBranch(cwd):
323 git.CreatePushBranch(constants.STABLE_EBUILD_BRANCH, cwd, sync=False)
Brian Harring22edb442012-05-11 23:55:18 -0700324 osutils.WriteFile(path, '', mode='a')
David Jamesb26b9312014-12-15 11:26:46 -0800325 if UpdateLocalFile(path, value, key):
326 desc = '%s: %s %s' % (filename, 'updating' if value else 'clearing', key)
327 git.AddPath(path)
328 git.Commit(cwd, desc)
David James8c846492011-01-25 17:07:29 -0800329
Achuith Bhandarkar03d924a2018-01-02 10:50:44 -0800330def GenerateHtmlIndex(files, index, board, version, remote_location):
Mike Frysinger212e4292014-05-24 15:15:44 -0400331 """Given the list of |files|, generate an index.html at |index|.
332
333 Args:
334 files: The list of files to link to.
335 index: The path to the html index.
336 board: Name of the board this index is for.
337 version: Build version this index is for.
Achuith Bhandarkar03d924a2018-01-02 10:50:44 -0800338 remote_location: Remote gs location prebuilts are uploaded to.
Mike Frysinger212e4292014-05-24 15:15:44 -0400339 """
Don Garrett13cbbff2016-08-09 14:18:38 -0700340 title = 'Package Prebuilt Index: %s / %s' % (board, version)
Mike Frysinger212e4292014-05-24 15:15:44 -0400341
342 files = files + [
343 '.|Google Storage Index',
344 '..|',
345 ]
Achuith Bhandarkar03d924a2018-01-02 10:50:44 -0800346 commands.GenerateHtmlIndex(index, files, title=title,
347 url_base=gs.GsUrlToHttp(remote_location))
Mike Frysinger212e4292014-05-24 15:15:44 -0400348
349
David Jamesce093af2011-02-23 15:21:58 -0800350def _GrabAllRemotePackageIndexes(binhost_urls):
David James05bcb2b2011-02-09 09:25:47 -0800351 """Grab all of the packages files associated with a list of binhost_urls.
352
David James05bcb2b2011-02-09 09:25:47 -0800353 Args:
354 binhost_urls: The URLs for the directories containing the Packages files we
355 want to grab.
David James05bcb2b2011-02-09 09:25:47 -0800356
357 Returns:
358 A list of PackageIndex objects.
359 """
360 pkg_indexes = []
361 for url in binhost_urls:
David James32faafe2012-06-08 14:25:03 -0700362 pkg_index = binpkg.GrabRemotePackageIndex(url)
David James05bcb2b2011-02-09 09:25:47 -0800363 if pkg_index:
364 pkg_indexes.append(pkg_index)
David James05bcb2b2011-02-09 09:25:47 -0800365 return pkg_indexes
366
367
David Jamesc0f158a2011-02-22 16:07:29 -0800368class PrebuiltUploader(object):
369 """Synchronize host and board prebuilts."""
David James8c846492011-01-25 17:07:29 -0800370
Mike Frysinger86509232014-05-24 13:18:37 -0400371 def __init__(self, upload_location, acl, binhost_base_url, pkg_indexes,
372 build_path, packages, skip_upload, binhost_conf_dir, dryrun,
Mike Frysinger8092a632014-05-24 13:25:46 -0400373 target, slave_targets, version):
David Jamesc0f158a2011-02-22 16:07:29 -0800374 """Constructor for prebuilt uploader object.
David James8c846492011-01-25 17:07:29 -0800375
David Jamesc0f158a2011-02-22 16:07:29 -0800376 This object can upload host or prebuilt files to Google Storage.
David James8c846492011-01-25 17:07:29 -0800377
David Jamesc0f158a2011-02-22 16:07:29 -0800378 Args:
379 upload_location: The upload location.
David Jamesfd0b0852011-02-23 11:15:36 -0800380 acl: The canned acl used for uploading to Google Storage. acl can be one
381 of: "public-read", "public-read-write", "authenticated-read",
Matt Tennante8179042013-10-01 15:47:32 -0700382 "bucket-owner-read", "bucket-owner-full-control", "project-private",
383 or "private" (see "gsutil help acls"). If we are not uploading to
384 Google Storage, this parameter is unused.
David Jamesfd0b0852011-02-23 11:15:36 -0800385 binhost_base_url: The URL used for downloading the prebuilts.
David Jamesc0f158a2011-02-22 16:07:29 -0800386 pkg_indexes: Old uploaded prebuilts to compare against. Instead of
387 uploading duplicate files, we just link to the old files.
David James615e5b52011-06-03 11:10:15 -0700388 build_path: The path to the directory containing the chroot.
389 packages: Packages to upload.
David James32b0b2f2011-07-13 20:56:50 -0700390 skip_upload: Don't actually upload the tarballs.
391 binhost_conf_dir: Directory where to store binhost.conf files.
Mike Frysinger86509232014-05-24 13:18:37 -0400392 dryrun: Don't push or upload prebuilts.
David James4058b0d2011-12-08 21:24:50 -0800393 target: BuildTarget managed by this builder.
394 slave_targets: List of BuildTargets managed by slave builders.
Mike Frysinger8092a632014-05-24 13:25:46 -0400395 version: A unique string, intended to be included in the upload path,
396 which identifies the version number of the uploaded prebuilts.
David Jamesc0f158a2011-02-22 16:07:29 -0800397 """
398 self._upload_location = upload_location
David Jamesfd0b0852011-02-23 11:15:36 -0800399 self._acl = acl
David Jamesc0f158a2011-02-22 16:07:29 -0800400 self._binhost_base_url = binhost_base_url
401 self._pkg_indexes = pkg_indexes
David James615e5b52011-06-03 11:10:15 -0700402 self._build_path = build_path
403 self._packages = set(packages)
Mike Frysingerf5f809a2013-02-12 13:47:37 -0500404 self._found_packages = set()
David James8ece7ee2011-06-29 16:02:30 -0700405 self._skip_upload = skip_upload
David James32b0b2f2011-07-13 20:56:50 -0700406 self._binhost_conf_dir = binhost_conf_dir
Mike Frysinger86509232014-05-24 13:18:37 -0400407 self._dryrun = dryrun
David James4058b0d2011-12-08 21:24:50 -0800408 self._target = target
409 self._slave_targets = slave_targets
Mike Frysinger8092a632014-05-24 13:25:46 -0400410 self._version = version
Mike Frysinger540883b2014-05-24 13:46:16 -0400411 self._gs_context = gs.GSContext(retries=_RETRIES, sleep=_SLEEP_TIME,
412 dry_run=self._dryrun)
413
414 def _Upload(self, local_file, remote_file):
415 """Wrapper around _GsUpload"""
416 _GsUpload(self._gs_context, self._acl, local_file, remote_file)
David James615e5b52011-06-03 11:10:15 -0700417
418 def _ShouldFilterPackage(self, pkg):
419 if not self._packages:
420 return False
Alex Klein18a60af2020-06-11 12:08:47 -0600421 cpv = package_info.SplitCPV(pkg['CPV'])
Alex Klein9f93b482018-10-01 09:26:51 -0600422 self._found_packages.add(cpv.cp)
423 return cpv.package not in self._packages and cpv.cp not in self._packages
David James8c846492011-01-25 17:07:29 -0800424
David Jamesc0f158a2011-02-22 16:07:29 -0800425 def _UploadPrebuilt(self, package_path, url_suffix):
426 """Upload host or board prebuilt files to Google Storage space.
David James8c846492011-01-25 17:07:29 -0800427
David Jamesc0f158a2011-02-22 16:07:29 -0800428 Args:
429 package_path: The path to the packages dir.
David Jamesce093af2011-02-23 15:21:58 -0800430 url_suffix: The remote subdirectory where we should upload the packages.
David Jamesc0f158a2011-02-22 16:07:29 -0800431 """
David Jamesc0f158a2011-02-22 16:07:29 -0800432 # Process Packages file, removing duplicates and filtered packages.
David James32faafe2012-06-08 14:25:03 -0700433 pkg_index = binpkg.GrabLocalPackageIndex(package_path)
David Jamesc0f158a2011-02-22 16:07:29 -0800434 pkg_index.SetUploadLocation(self._binhost_base_url, url_suffix)
David James615e5b52011-06-03 11:10:15 -0700435 pkg_index.RemoveFilteredPackages(self._ShouldFilterPackage)
David Jamesc0f158a2011-02-22 16:07:29 -0800436 uploads = pkg_index.ResolveDuplicateUploads(self._pkg_indexes)
Mike Frysingerf5f809a2013-02-12 13:47:37 -0500437 unmatched_pkgs = self._packages - self._found_packages
438 if unmatched_pkgs:
Lann Martinffb95162018-08-28 12:02:54 -0600439 logging.warning('unable to match packages: %r', unmatched_pkgs)
David James05bcb2b2011-02-09 09:25:47 -0800440
David Jamesc0f158a2011-02-22 16:07:29 -0800441 # Write Packages file.
David James5ab67e32014-10-24 08:19:59 -0700442 pkg_index.header['TTL'] = _BINPKG_TTL
David Jamesc0f158a2011-02-22 16:07:29 -0800443 tmp_packages_file = pkg_index.WriteToNamedTemporaryFile()
David James05bcb2b2011-02-09 09:25:47 -0800444
David Jamesc0f158a2011-02-22 16:07:29 -0800445 remote_location = '%s/%s' % (self._upload_location.rstrip('/'), url_suffix)
David James015af872012-06-19 15:24:36 -0700446 assert remote_location.startswith('gs://')
David James05bcb2b2011-02-09 09:25:47 -0800447
David James015af872012-06-19 15:24:36 -0700448 upload_files = GenerateUploadDict(package_path, remote_location, uploads)
449 remote_file = '%s/Packages' % remote_location.rstrip('/')
450 upload_files[tmp_packages_file.name] = remote_file
451
Mike Frysinger9bb6cd82020-08-20 03:02:23 -0400452 # Build list of files to upload. Manually include the dev-only files but
453 # skip them if not present.
454 dev_only = os.path.join(package_path, 'dev-only-extras.tar.xz')
455 if os.path.exists(dev_only):
456 upload_files[dev_only] = '%s/%s' % (
457 remote_location.rstrip('/'), os.path.basename(dev_only))
458
Mike Frysinger540883b2014-05-24 13:46:16 -0400459 RemoteUpload(self._gs_context, self._acl, upload_files)
David James8c846492011-01-25 17:07:29 -0800460
Mike Frysinger212e4292014-05-24 15:15:44 -0400461 with tempfile.NamedTemporaryFile(
462 prefix='chromite.upload_prebuilts.index.') as index:
463 GenerateHtmlIndex(
464 [x[len(remote_location) + 1:] for x in upload_files.values()],
Achuith Bhandarkar03d924a2018-01-02 10:50:44 -0800465 index.name, self._target, self._version, remote_location)
Mike Frysinger212e4292014-05-24 15:15:44 -0400466 self._Upload(index.name, '%s/index.html' % remote_location.rstrip('/'))
467
468 link_name = 'Prebuilts[%s]: %s' % (self._target, self._version)
469 url = '%s%s/index.html' % (gs.PUBLIC_BASE_HTTPS_URL,
470 remote_location[len(gs.BASE_GS_URL):])
Chris McDonaldb55b7032021-06-17 16:41:32 -0600471 cbuildbot_alerts.PrintBuildbotLink(link_name, url)
Mike Frysinger212e4292014-05-24 15:15:44 -0400472
Mike Frysinger8092a632014-05-24 13:25:46 -0400473 def _UploadSdkTarball(self, board_path, url_suffix, prepackaged,
Gilad Arnold2b79e2d2015-06-02 11:26:07 -0700474 toolchains_overlay_tarballs,
475 toolchains_overlay_upload_path,
Mike Frysinger9e979b92012-11-29 02:55:09 -0500476 toolchain_tarballs, toolchain_upload_path):
477 """Upload a tarball of the sdk at the specified path to Google Storage.
David James8fa34ea2011-04-15 13:00:20 -0700478
479 Args:
480 board_path: The path to the board dir.
481 url_suffix: The remote subdirectory where we should upload the packages.
Zdenek Behan62a57792012-08-31 15:09:08 +0200482 prepackaged: If given, a tarball that has been packaged outside of this
483 script and should be used.
Gilad Arnold2b79e2d2015-06-02 11:26:07 -0700484 toolchains_overlay_tarballs: List of toolchains overlay tarball
485 specifications to upload. Items take the form
486 "toolchains_spec:/path/to/tarball".
487 toolchains_overlay_upload_path: Path template under the bucket to place
488 toolchains overlay tarballs.
Mike Frysinger9e979b92012-11-29 02:55:09 -0500489 toolchain_tarballs: List of toolchain tarballs to upload.
490 toolchain_upload_path: Path under the bucket to place toolchain tarballs.
David James8fa34ea2011-04-15 13:00:20 -0700491 """
492 remote_location = '%s/%s' % (self._upload_location.rstrip('/'), url_suffix)
493 assert remote_location.startswith('gs://')
Zdenek Behan86c15e92012-10-13 00:55:47 +0200494 boardname = os.path.basename(board_path.rstrip('/'))
495 # We do not upload non SDK board tarballs,
496 assert boardname == constants.CHROOT_BUILDER_BOARD
497 assert prepackaged is not None
Zdenek Behan62a57792012-08-31 15:09:08 +0200498
Mike Frysinger8092a632014-05-24 13:25:46 -0400499 version_str = self._version[len('chroot-'):]
Mike Frysinger8e727a32013-01-16 16:57:53 -0500500 remote_tarfile = toolchain.GetSdkURL(
501 for_gsutil=True, suburl='cros-sdk-%s.tar.xz' % (version_str,))
Zdenek Behan86c15e92012-10-13 00:55:47 +0200502 # For SDK, also upload the manifest which is guaranteed to exist
503 # by the builderstage.
Mike Frysinger540883b2014-05-24 13:46:16 -0400504 self._Upload(prepackaged + '.Manifest', remote_tarfile + '.Manifest')
505 self._Upload(prepackaged, remote_tarfile)
Zdenek Behan86c15e92012-10-13 00:55:47 +0200506
Gilad Arnold2b79e2d2015-06-02 11:26:07 -0700507 # Upload SDK toolchains overlays and toolchain tarballs, if given.
Gilad Arnoldad333182015-05-27 15:50:41 -0700508 for tarball_list, upload_path, qualifier_name in (
Gilad Arnold2b79e2d2015-06-02 11:26:07 -0700509 (toolchains_overlay_tarballs, toolchains_overlay_upload_path,
510 'toolchains'),
Gilad Arnoldad333182015-05-27 15:50:41 -0700511 (toolchain_tarballs, toolchain_upload_path, 'target')):
Gilad Arnold2b79e2d2015-06-02 11:26:07 -0700512 for tarball_spec in tarball_list:
513 qualifier_val, local_path = tarball_spec.split(':')
Gilad Arnoldad333182015-05-27 15:50:41 -0700514 suburl = upload_path % {qualifier_name: qualifier_val}
515 remote_path = toolchain.GetSdkURL(for_gsutil=True, suburl=suburl)
516 self._Upload(local_path, remote_path)
Mike Frysinger9e979b92012-11-29 02:55:09 -0500517
Zdenek Behan86c15e92012-10-13 00:55:47 +0200518 # Finally, also update the pointer to the latest SDK on which polling
519 # scripts rely.
David James4bc13702013-03-26 08:08:04 -0700520 with osutils.TempDir() as tmpdir:
Zdenek Behan86c15e92012-10-13 00:55:47 +0200521 pointerfile = os.path.join(tmpdir, 'cros-sdk-latest.conf')
Mike Frysinger8e727a32013-01-16 16:57:53 -0500522 remote_pointerfile = toolchain.GetSdkURL(for_gsutil=True,
523 suburl='cros-sdk-latest.conf')
Zdenek Behan86c15e92012-10-13 00:55:47 +0200524 osutils.WriteFile(pointerfile, 'LATEST_SDK="%s"' % version_str)
Mike Frysinger540883b2014-05-24 13:46:16 -0400525 self._Upload(pointerfile, remote_pointerfile)
Zdenek Behan33a34112012-09-10 21:07:51 +0200526
Chris Sosa6a5dceb2012-05-14 13:48:56 -0700527 def _GetTargets(self):
528 """Retuns the list of targets to use."""
529 targets = self._slave_targets[:]
530 if self._target:
531 targets.append(self._target)
532
533 return targets
534
Mike Frysinger8092a632014-05-24 13:25:46 -0400535 def SyncHostPrebuilts(self, key, git_sync, sync_binhost_conf):
David Jamesc0f158a2011-02-22 16:07:29 -0800536 """Synchronize host prebuilt files.
David James05bcb2b2011-02-09 09:25:47 -0800537
David Jamesc0f158a2011-02-22 16:07:29 -0800538 This function will sync both the standard host packages, plus the host
539 packages associated with all targets that have been "setup" with the
540 current host's chroot. For instance, if this host has been used to build
541 x86-generic, it will sync the host packages associated with
542 'i686-pc-linux-gnu'. If this host has also been used to build arm-generic,
543 it will also sync the host packages associated with
544 'armv7a-cros-linux-gnueabi'.
David James05bcb2b2011-02-09 09:25:47 -0800545
David Jamesc0f158a2011-02-22 16:07:29 -0800546 Args:
David Jamesc0f158a2011-02-22 16:07:29 -0800547 key: The variable key to update in the git file.
548 git_sync: If set, update make.conf of target to reference the latest
549 prebuilt packages generated here.
550 sync_binhost_conf: If set, update binhost config file in
551 chromiumos-overlay for the host.
552 """
Mike Nicholsa1414162021-04-22 20:07:22 +0000553 # Slave boards are listed before the master board so that the master board
David Jamese2488642011-11-14 16:15:20 -0800554 # takes priority (i.e. x86-generic preflight host prebuilts takes priority
555 # over preflight host prebuilts from other builders.)
556 binhost_urls = []
Chris Sosa6a5dceb2012-05-14 13:48:56 -0700557 for target in self._GetTargets():
Mike Frysinger8092a632014-05-24 13:25:46 -0400558 url_suffix = _REL_HOST_PATH % {'version': self._version,
David James4058b0d2011-12-08 21:24:50 -0800559 'host_arch': _HOST_ARCH,
560 'target': target}
David Jamese2488642011-11-14 16:15:20 -0800561 packages_url_suffix = '%s/packages' % url_suffix.rstrip('/')
David James05bcb2b2011-02-09 09:25:47 -0800562
Mike Frysinger540883b2014-05-24 13:46:16 -0400563 if self._target == target and not self._skip_upload:
David Jamese2488642011-11-14 16:15:20 -0800564 # Upload prebuilts.
565 package_path = os.path.join(self._build_path, _HOST_PACKAGES_PATH)
566 self._UploadPrebuilt(package_path, packages_url_suffix)
David James8ece7ee2011-06-29 16:02:30 -0700567
David Jamese2488642011-11-14 16:15:20 -0800568 # Record URL where prebuilts were uploaded.
569 binhost_urls.append('%s/%s/' % (self._binhost_base_url.rstrip('/'),
570 packages_url_suffix.rstrip('/')))
571
David James20b2b6f2011-11-18 15:11:58 -0800572 binhost = ' '.join(binhost_urls)
David James8ece7ee2011-06-29 16:02:30 -0700573 if git_sync:
David Jamesb26b9312014-12-15 11:26:46 -0800574 git_file = os.path.join(self._build_path, _PREBUILT_MAKE_CONF[_HOST_ARCH])
Mike Frysinger86509232014-05-24 13:18:37 -0400575 RevGitFile(git_file, {key: binhost}, dryrun=self._dryrun)
David James8ece7ee2011-06-29 16:02:30 -0700576 if sync_binhost_conf:
David Jamesb26b9312014-12-15 11:26:46 -0800577 binhost_conf = os.path.join(
578 self._binhost_conf_dir, 'host', '%s-%s.conf' % (_HOST_ARCH, key))
David Jamese2488642011-11-14 16:15:20 -0800579 UpdateBinhostConfFile(binhost_conf, key, binhost)
David Jamesc0f158a2011-02-22 16:07:29 -0800580
Mike Frysinger8092a632014-05-24 13:25:46 -0400581 def SyncBoardPrebuilts(self, key, git_sync, sync_binhost_conf,
Mike Frysinger9e979b92012-11-29 02:55:09 -0500582 upload_board_tarball, prepackaged_board,
Gilad Arnold2b79e2d2015-06-02 11:26:07 -0700583 toolchains_overlay_tarballs,
584 toolchains_overlay_upload_path,
Mike Frysinger9e979b92012-11-29 02:55:09 -0500585 toolchain_tarballs, toolchain_upload_path):
David Jamesc0f158a2011-02-22 16:07:29 -0800586 """Synchronize board prebuilt files.
587
588 Args:
David Jamesc0f158a2011-02-22 16:07:29 -0800589 key: The variable key to update in the git file.
590 git_sync: If set, update make.conf of target to reference the latest
591 prebuilt packages generated here.
592 sync_binhost_conf: If set, update binhost config file in
593 chromiumos-overlay for the current board.
David James8fa34ea2011-04-15 13:00:20 -0700594 upload_board_tarball: Include a tarball of the board in our upload.
Zdenek Behan62a57792012-08-31 15:09:08 +0200595 prepackaged_board: A tarball of the board built outside of this script.
Gilad Arnold2b79e2d2015-06-02 11:26:07 -0700596 toolchains_overlay_tarballs: List of toolchains overlay tarball
597 specifications to upload. Items take the form
598 "toolchains_spec:/path/to/tarball".
599 toolchains_overlay_upload_path: Path template under the bucket to place
600 toolchains overlay tarballs.
Mike Frysinger9e979b92012-11-29 02:55:09 -0500601 toolchain_tarballs: A list of toolchain tarballs to upload.
602 toolchain_upload_path: Path under the bucket to place toolchain tarballs.
David Jamesc0f158a2011-02-22 16:07:29 -0800603 """
David Jamesb26b9312014-12-15 11:26:46 -0800604 updated_binhosts = set()
Chris Sosa6a5dceb2012-05-14 13:48:56 -0700605 for target in self._GetTargets():
David Jamese2488642011-11-14 16:15:20 -0800606 board_path = os.path.join(self._build_path,
David James4058b0d2011-12-08 21:24:50 -0800607 _BOARD_PATH % {'board': target.board_variant})
David Jamese2488642011-11-14 16:15:20 -0800608 package_path = os.path.join(board_path, 'packages')
Mike Frysinger8092a632014-05-24 13:25:46 -0400609 url_suffix = _REL_BOARD_PATH % {'target': target,
610 'version': self._version}
David Jamese2488642011-11-14 16:15:20 -0800611 packages_url_suffix = '%s/packages' % url_suffix.rstrip('/')
David James8fa34ea2011-04-15 13:00:20 -0700612
Matt Tennante8179042013-10-01 15:47:32 -0700613 # Process the target board differently if it is the main --board.
Mike Frysinger540883b2014-05-24 13:46:16 -0400614 if self._target == target and not self._skip_upload:
Matt Tennante8179042013-10-01 15:47:32 -0700615 # This strips "chroot" prefix because that is sometimes added as the
616 # --prepend-version argument (e.g. by chromiumos-sdk bot).
617 # TODO(build): Clean it up to be less hard-coded.
Mike Frysinger8092a632014-05-24 13:25:46 -0400618 version_str = self._version[len('chroot-'):]
Mike Frysinger9e979b92012-11-29 02:55:09 -0500619
David Jamese2488642011-11-14 16:15:20 -0800620 # Upload board tarballs in the background.
621 if upload_board_tarball:
Mike Frysinger9e979b92012-11-29 02:55:09 -0500622 if toolchain_upload_path:
623 toolchain_upload_path %= {'version': version_str}
Gilad Arnold2b79e2d2015-06-02 11:26:07 -0700624 if toolchains_overlay_upload_path:
625 toolchains_overlay_upload_path %= {'version': version_str}
Mike Frysinger9e979b92012-11-29 02:55:09 -0500626 tar_process = multiprocessing.Process(
627 target=self._UploadSdkTarball,
Mike Frysinger8092a632014-05-24 13:25:46 -0400628 args=(board_path, url_suffix, prepackaged_board,
Gilad Arnold2b79e2d2015-06-02 11:26:07 -0700629 toolchains_overlay_tarballs,
630 toolchains_overlay_upload_path, toolchain_tarballs,
631 toolchain_upload_path))
David Jamese2488642011-11-14 16:15:20 -0800632 tar_process.start()
David James8fa34ea2011-04-15 13:00:20 -0700633
David Jamese2488642011-11-14 16:15:20 -0800634 # Upload prebuilts.
635 self._UploadPrebuilt(package_path, packages_url_suffix)
David James8fa34ea2011-04-15 13:00:20 -0700636
David Jamese2488642011-11-14 16:15:20 -0800637 # Make sure we finished uploading the board tarballs.
638 if upload_board_tarball:
639 tar_process.join()
640 assert tar_process.exitcode == 0
David Jamesc0f158a2011-02-22 16:07:29 -0800641
David Jamese2488642011-11-14 16:15:20 -0800642 # Record URL where prebuilts were uploaded.
643 url_value = '%s/%s/' % (self._binhost_base_url.rstrip('/'),
644 packages_url_suffix.rstrip('/'))
645
646 if git_sync:
David James4058b0d2011-12-08 21:24:50 -0800647 git_file = DeterminePrebuiltConfFile(self._build_path, target)
Mike Frysinger86509232014-05-24 13:18:37 -0400648 RevGitFile(git_file, {key: url_value}, dryrun=self._dryrun)
Matt Tennante8179042013-10-01 15:47:32 -0700649
David Jamese2488642011-11-14 16:15:20 -0800650 if sync_binhost_conf:
Matt Tennante8179042013-10-01 15:47:32 -0700651 # Update the binhost configuration file in git.
David Jamesb26b9312014-12-15 11:26:46 -0800652 binhost_conf = os.path.join(
653 self._binhost_conf_dir, 'target', '%s-%s.conf' % (target, key))
654 updated_binhosts.add(binhost_conf)
David Jamese2488642011-11-14 16:15:20 -0800655 UpdateBinhostConfFile(binhost_conf, key, url_value)
David James05bcb2b2011-02-09 09:25:47 -0800656
David Jamesb26b9312014-12-15 11:26:46 -0800657 if sync_binhost_conf:
658 # Clear all old binhosts. The files must be left empty in case anybody
659 # is referring to them.
660 all_binhosts = set(glob.glob(os.path.join(
661 self._binhost_conf_dir, 'target', '*-%s.conf' % key)))
662 for binhost_conf in all_binhosts - updated_binhosts:
663 UpdateBinhostConfFile(binhost_conf, key, '')
664
David James05bcb2b2011-02-09 09:25:47 -0800665
Mike Nicholsa1414162021-04-22 20:07:22 +0000666class _AddSlaveBoardAction(argparse.Action):
667 """Callback that adds a slave board to the list of slave targets."""
Mike Frysingerb87bb782015-06-04 02:46:50 -0400668 def __call__(self, parser, namespace, values, option_string=None):
669 getattr(namespace, self.dest).append(BuildTarget(values))
David James4058b0d2011-12-08 21:24:50 -0800670
671
Mike Nicholsa1414162021-04-22 20:07:22 +0000672class _AddSlaveProfileAction(argparse.Action):
673 """Callback that adds a slave profile to the list of slave targets."""
Mike Frysingerb87bb782015-06-04 02:46:50 -0400674 def __call__(self, parser, namespace, values, option_string=None):
675 if not namespace.slave_targets:
676 parser.error('Must specify --slave-board before --slave-profile')
677 if namespace.slave_targets[-1].profile is not None:
678 parser.error('Cannot specify --slave-profile twice for same board')
679 namespace.slave_targets[-1].profile = values
David James4058b0d2011-12-08 21:24:50 -0800680
681
Mike Frysinger86509232014-05-24 13:18:37 -0400682def ParseOptions(argv):
Chris Sosa6a5dceb2012-05-14 13:48:56 -0700683 """Returns options given by the user and the target specified.
684
Mike Frysinger86509232014-05-24 13:18:37 -0400685 Args:
686 argv: The args to parse.
687
Mike Frysinger1a736a82013-12-12 01:50:59 -0500688 Returns:
689 A tuple containing a parsed options object and BuildTarget.
690 The target instance is None if no board is specified.
Chris Sosa6a5dceb2012-05-14 13:48:56 -0700691 """
Mike Frysingerb87bb782015-06-04 02:46:50 -0400692 parser = commandline.ArgumentParser()
693 parser.add_argument('-H', '--binhost-base-url', default=_BINHOST_BASE_URL,
694 help='Base URL to use for binhost in make.conf updates')
695 parser.add_argument('--previous-binhost-url', action='append', default=[],
696 help='Previous binhost URL')
697 parser.add_argument('-b', '--board',
698 help='Board type that was built on this machine')
699 parser.add_argument('-B', '--prepackaged-tarball', type='path',
700 help='Board tarball prebuilt outside of this script.')
Gilad Arnold2b79e2d2015-06-02 11:26:07 -0700701 parser.add_argument('--toolchains-overlay-tarball',
702 dest='toolchains_overlay_tarballs',
Mike Frysingerb87bb782015-06-04 02:46:50 -0400703 action='append', default=[],
Gilad Arnold2b79e2d2015-06-02 11:26:07 -0700704 help='Toolchains overlay tarball specification to '
705 'upload. Takes the form '
706 '"toolchains_spec:/path/to/tarball".')
707 parser.add_argument('--toolchains-overlay-upload-path', default='',
708 help='Path template for uploading toolchains overlays.')
Mike Frysingerb87bb782015-06-04 02:46:50 -0400709 parser.add_argument('--toolchain-tarball', dest='toolchain_tarballs',
710 action='append', default=[],
711 help='Redistributable toolchain tarball.')
Gilad Arnold2b79e2d2015-06-02 11:26:07 -0700712 parser.add_argument('--toolchain-upload-path', default='',
Mike Frysingerb87bb782015-06-04 02:46:50 -0400713 help='Path to place toolchain tarballs in the sdk tree.')
714 parser.add_argument('--profile',
715 help='Profile that was built on this machine')
Mike Nicholsa1414162021-04-22 20:07:22 +0000716 parser.add_argument('--slave-board', default=[], action=_AddSlaveBoardAction,
Mike Frysingerb87bb782015-06-04 02:46:50 -0400717 dest='slave_targets',
718 help='Board type that was built on a slave machine. To '
719 'add a profile to this board, use --slave-profile.')
Mike Nicholsa1414162021-04-22 20:07:22 +0000720 parser.add_argument('--slave-profile', action=_AddSlaveProfileAction,
Mike Frysingerb87bb782015-06-04 02:46:50 -0400721 help='Board profile that was built on a slave machine. '
722 'Applies to previous slave board.')
723 parser.add_argument('-p', '--build-path', required=True,
724 help='Path to the directory containing the chroot')
725 parser.add_argument('--packages', action='append', default=[],
726 help='Only include the specified packages. '
727 '(Default is to include all packages.)')
728 parser.add_argument('-s', '--sync-host', default=False, action='store_true',
729 help='Sync host prebuilts')
730 parser.add_argument('-g', '--git-sync', default=False, action='store_true',
731 help='Enable git version sync (This commits to a repo.) '
732 'This is used by full builders to commit directly '
733 'to board overlays.')
734 parser.add_argument('-u', '--upload',
735 help='Upload location')
736 parser.add_argument('-V', '--prepend-version',
737 help='Add an identifier to the front of the version')
738 parser.add_argument('-f', '--filters', action='store_true', default=False,
739 help='Turn on filtering of private ebuild packages')
740 parser.add_argument('-k', '--key', default='PORTAGE_BINHOST',
741 help='Key to update in make.conf / binhost.conf')
742 parser.add_argument('--set-version',
743 help='Specify the version string')
744 parser.add_argument('--sync-binhost-conf', default=False, action='store_true',
745 help='Update binhost.conf in chromiumos-overlay or '
Mike Frysinger80de5012019-08-01 14:10:53 -0400746 "chromeos-overlay. Commit the changes, but don't "
Mike Frysingerb87bb782015-06-04 02:46:50 -0400747 'push them. This is used for preflight binhosts.')
748 parser.add_argument('--binhost-conf-dir',
749 help='Directory to commit binhost config with '
750 '--sync-binhost-conf.')
751 parser.add_argument('-P', '--private', action='store_true', default=False,
752 help='Mark gs:// uploads as private.')
753 parser.add_argument('--skip-upload', action='store_true', default=False,
754 help='Skip upload step.')
755 parser.add_argument('--upload-board-tarball', action='store_true',
756 default=False,
757 help='Upload board tarball to Google Storage.')
758 parser.add_argument('-n', '--dry-run', dest='dryrun',
759 action='store_true', default=False,
Mike Frysinger80de5012019-08-01 14:10:53 -0400760 help="Don't push or upload prebuilts.")
David James8c846492011-01-25 17:07:29 -0800761
Mike Frysingerb87bb782015-06-04 02:46:50 -0400762 options = parser.parse_args(argv)
David James8ece7ee2011-06-29 16:02:30 -0700763 if not options.upload and not options.skip_upload:
Mike Frysinger86509232014-05-24 13:18:37 -0400764 parser.error('you need to provide an upload location using -u')
David James8ece7ee2011-06-29 16:02:30 -0700765 if not options.set_version and options.skip_upload:
Mike Frysinger86509232014-05-24 13:18:37 -0400766 parser.error('If you are using --skip-upload, you must specify a '
767 'version number using --set-version.')
Scott Zawalskiab1bed32011-03-16 15:24:24 -0700768
Chris Sosa6a5dceb2012-05-14 13:48:56 -0700769 target = None
770 if options.board:
771 target = BuildTarget(options.board, options.profile)
772
773 if target in options.slave_targets:
Mike Frysinger86509232014-05-24 13:18:37 -0400774 parser.error('--board/--profile must not also be a slave target.')
David Jamese2488642011-11-14 16:15:20 -0800775
David James4058b0d2011-12-08 21:24:50 -0800776 if len(set(options.slave_targets)) != len(options.slave_targets):
Mike Frysinger86509232014-05-24 13:18:37 -0400777 parser.error('--slave-boards must not have duplicates.')
David Jamese2488642011-11-14 16:15:20 -0800778
David James4058b0d2011-12-08 21:24:50 -0800779 if options.slave_targets and options.git_sync:
Mike Frysinger86509232014-05-24 13:18:37 -0400780 parser.error('--slave-boards is not compatible with --git-sync')
David Jamese2488642011-11-14 16:15:20 -0800781
David James8ece7ee2011-06-29 16:02:30 -0700782 if (options.upload_board_tarball and options.skip_upload and
783 options.board == 'amd64-host'):
Mike Frysinger86509232014-05-24 13:18:37 -0400784 parser.error('--skip-upload is not compatible with '
785 '--upload-board-tarball and --board=amd64-host')
David James8fa34ea2011-04-15 13:00:20 -0700786
David James8ece7ee2011-06-29 16:02:30 -0700787 if (options.upload_board_tarball and not options.skip_upload and
788 not options.upload.startswith('gs://')):
Mike Frysinger86509232014-05-24 13:18:37 -0400789 parser.error('--upload-board-tarball only works with gs:// URLs.\n'
790 '--upload must be a gs:// URL.')
David James8fa34ea2011-04-15 13:00:20 -0700791
Zdenek Behan86c15e92012-10-13 00:55:47 +0200792 if options.upload_board_tarball and options.prepackaged_tarball is None:
Mike Frysinger86509232014-05-24 13:18:37 -0400793 parser.error('--upload-board-tarball requires --prepackaged-tarball')
Zdenek Behan86c15e92012-10-13 00:55:47 +0200794
Scott Zawalskiab1bed32011-03-16 15:24:24 -0700795 if options.private:
796 if options.sync_host:
Mike Frysinger86509232014-05-24 13:18:37 -0400797 parser.error('--private and --sync-host/-s cannot be specified '
798 'together; we do not support private host prebuilts')
Scott Zawalskiab1bed32011-03-16 15:24:24 -0700799
David James8ece7ee2011-06-29 16:02:30 -0700800 if not options.upload or not options.upload.startswith('gs://'):
Mike Frysinger86509232014-05-24 13:18:37 -0400801 parser.error('--private is only valid for gs:// URLs; '
802 '--upload must be a gs:// URL.')
Scott Zawalskiab1bed32011-03-16 15:24:24 -0700803
804 if options.binhost_base_url != _BINHOST_BASE_URL:
Mike Frysinger86509232014-05-24 13:18:37 -0400805 parser.error('when using --private the --binhost-base-url '
806 'is automatically derived.')
David James27fa7d12011-06-29 17:24:14 -0700807
David Jamesc31168e2014-06-05 14:40:05 -0700808 if options.sync_binhost_conf and not options.binhost_conf_dir:
809 parser.error('--sync-binhost-conf requires --binhost-conf-dir')
810
Gilad Arnold2b79e2d2015-06-02 11:26:07 -0700811 if (options.toolchains_overlay_tarballs and
812 not options.toolchains_overlay_upload_path):
813 parser.error('--toolchains-overlay-tarball requires '
814 '--toolchains-overlay-upload-path')
Gilad Arnoldad333182015-05-27 15:50:41 -0700815
Chris Sosa6a5dceb2012-05-14 13:48:56 -0700816 return options, target
David Jamesc0f158a2011-02-22 16:07:29 -0800817
Mike Frysingercc838832014-05-24 13:10:30 -0400818
Mike Frysinger86509232014-05-24 13:18:37 -0400819def main(argv):
David Jamesdb401072011-06-10 12:17:16 -0700820 # Set umask to a sane value so that files created as root are readable.
Mike Frysinger60ec1012013-10-21 00:11:10 -0400821 os.umask(0o22)
David Jamesdb401072011-06-10 12:17:16 -0700822
Mike Frysinger86509232014-05-24 13:18:37 -0400823 options, target = ParseOptions(argv)
David Jamesc0f158a2011-02-22 16:07:29 -0800824
David James05bcb2b2011-02-09 09:25:47 -0800825 # Calculate a list of Packages index files to compare against. Whenever we
826 # upload a package, we check to make sure it's not already stored in one of
827 # the packages files we uploaded. This list of packages files might contain
828 # both board and host packages.
David Jamesce093af2011-02-23 15:21:58 -0800829 pkg_indexes = _GrabAllRemotePackageIndexes(options.previous_binhost_url)
David James8c846492011-01-25 17:07:29 -0800830
David James8ece7ee2011-06-29 16:02:30 -0700831 if options.set_version:
832 version = options.set_version
833 else:
834 version = GetVersion()
Matt Tennante8179042013-10-01 15:47:32 -0700835
David Jamesc0f158a2011-02-22 16:07:29 -0800836 if options.prepend_version:
837 version = '%s-%s' % (options.prepend_version, version)
838
Scott Zawalskiab1bed32011-03-16 15:24:24 -0700839 acl = 'public-read'
840 binhost_base_url = options.binhost_base_url
841
David Jamesadd21432013-05-21 10:04:07 -0700842 if options.private:
Scott Zawalskiab1bed32011-03-16 15:24:24 -0700843 binhost_base_url = options.upload
David Jamesadd21432013-05-21 10:04:07 -0700844 if target:
Prathmesh Prabhu421eef22014-10-16 17:13:19 -0700845 acl = portage_util.FindOverlayFile(_GOOGLESTORAGE_GSUTIL_FILE,
846 board=target.board_variant,
847 buildroot=options.build_path)
Ben Chan067de492015-01-06 17:19:13 -0800848 if acl is None:
849 cros_build_lib.Die('No Google Storage ACL file %s found in %s overlay.',
850 _GOOGLESTORAGE_GSUTIL_FILE, target.board_variant)
Scott Zawalskiab1bed32011-03-16 15:24:24 -0700851
David Jamesb26b9312014-12-15 11:26:46 -0800852 binhost_conf_dir = None
853 if options.binhost_conf_dir:
854 binhost_conf_dir = os.path.join(options.build_path,
855 options.binhost_conf_dir)
856
Scott Zawalskiab1bed32011-03-16 15:24:24 -0700857 uploader = PrebuiltUploader(options.upload, acl, binhost_base_url,
David James615e5b52011-06-03 11:10:15 -0700858 pkg_indexes, options.build_path,
David James27fa7d12011-06-29 17:24:14 -0700859 options.packages, options.skip_upload,
David Jamesb26b9312014-12-15 11:26:46 -0800860 binhost_conf_dir, options.dryrun,
Mike Frysinger8092a632014-05-24 13:25:46 -0400861 target, options.slave_targets, version)
David Jamesc0f158a2011-02-22 16:07:29 -0800862
David James8c846492011-01-25 17:07:29 -0800863 if options.sync_host:
Mike Frysinger8092a632014-05-24 13:25:46 -0400864 uploader.SyncHostPrebuilts(options.key, options.git_sync,
Chris Sosa6a5dceb2012-05-14 13:48:56 -0700865 options.sync_binhost_conf)
David James8c846492011-01-25 17:07:29 -0800866
Chris Sosa62c8ff52012-06-04 15:03:12 -0700867 if options.board or options.slave_targets:
Mike Frysinger8092a632014-05-24 13:25:46 -0400868 uploader.SyncBoardPrebuilts(options.key, options.git_sync,
Chris Sosa6a5dceb2012-05-14 13:48:56 -0700869 options.sync_binhost_conf,
Zdenek Behan62a57792012-08-31 15:09:08 +0200870 options.upload_board_tarball,
Mike Frysinger9e979b92012-11-29 02:55:09 -0500871 options.prepackaged_tarball,
Gilad Arnold2b79e2d2015-06-02 11:26:07 -0700872 options.toolchains_overlay_tarballs,
873 options.toolchains_overlay_upload_path,
Mike Frysinger9e979b92012-11-29 02:55:09 -0500874 options.toolchain_tarballs,
875 options.toolchain_upload_path)