blob: 0c39184c635bd059128ac85ba9639a168d45ac8b [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
Brian Harring7904b482012-08-08 02:54:12 -070035from chromite.lib import gs
Brian Harringaf019fb2012-05-10 15:06:13 -070036from chromite.lib import osutils
David James6450a0a2012-12-04 07:59:53 -080037from chromite.lib import parallel
Alex Deymo075c2292014-09-04 18:31:50 -070038from chromite.lib import portage_util
Mike Frysinger8e727a32013-01-16 16:57:53 -050039from chromite.lib import toolchain
Alex Klein18a60af2020-06-11 12:08:47 -060040from chromite.lib.parser import package_info
Chris Sosa1dc96132012-05-11 15:40:50 -070041
Mike Frysinger72b7cf92020-04-19 06:00:51 -040042
David James015af872012-06-19 15:24:36 -070043# How many times to retry uploads.
44_RETRIES = 10
45
46# Multiplier for how long to sleep (in seconds) between retries; will delay
47# (1*sleep) the first time, then (2*sleep), continuing via attempt * sleep.
48_SLEEP_TIME = 60
49
David James5ab67e32014-10-24 08:19:59 -070050# The length of time (in seconds) that Portage should wait before refetching
51# binpkgs from the same binhost. We don't ever modify binhosts, so this should
52# be something big.
53_BINPKG_TTL = 60 * 60 * 24 * 365
54
David James8c846492011-01-25 17:07:29 -080055_HOST_PACKAGES_PATH = 'chroot/var/lib/portage/pkgs'
David James05bcb2b2011-02-09 09:25:47 -080056_CATEGORIES_PATH = 'chroot/etc/portage/categories'
David James615e5b52011-06-03 11:10:15 -070057_PYM_PATH = 'chroot/usr/lib/portage/pym'
David James4058b0d2011-12-08 21:24:50 -080058_HOST_ARCH = 'amd64'
David James8c846492011-01-25 17:07:29 -080059_BOARD_PATH = 'chroot/build/%(board)s'
David James4058b0d2011-12-08 21:24:50 -080060_REL_BOARD_PATH = 'board/%(target)s/%(version)s'
61_REL_HOST_PATH = 'host/%(host_arch)s/%(target)s/%(version)s'
David James8c846492011-01-25 17:07:29 -080062# Private overlays to look at for builds to filter
63# relative to build path
64_PRIVATE_OVERLAY_DIR = 'src/private-overlays'
Gabe Black40169e62014-06-17 15:23:47 -070065_GOOGLESTORAGE_GSUTIL_FILE = 'googlestorage_acl.txt'
David James3753d942014-04-23 10:55:48 -070066_BINHOST_BASE_URL = 'gs://chromeos-prebuilt'
David James8c846492011-01-25 17:07:29 -080067_PREBUILT_BASE_DIR = 'src/third_party/chromiumos-overlay/chromeos/config/'
68# Created in the event of new host targets becoming available
69_PREBUILT_MAKE_CONF = {'amd64': os.path.join(_PREBUILT_BASE_DIR,
70 'make.conf.amd64-host')}
David James8c846492011-01-25 17:07:29 -080071
72
David James4058b0d2011-12-08 21:24:50 -080073class BuildTarget(object):
74 """A board/variant/profile tuple."""
75
76 def __init__(self, board_variant, profile=None):
77 self.board_variant = board_variant
78 self.board, _, self.variant = board_variant.partition('_')
79 self.profile = profile
80
81 def __str__(self):
82 if self.profile:
83 return '%s_%s' % (self.board_variant, self.profile)
84 else:
85 return self.board_variant
86
87 def __eq__(self, other):
88 return str(other) == str(self)
89
90 def __hash__(self):
91 return hash(str(self))
92
93
David James8c846492011-01-25 17:07:29 -080094def UpdateLocalFile(filename, value, key='PORTAGE_BINHOST'):
95 """Update the key in file with the value passed.
Mike Frysinger1a736a82013-12-12 01:50:59 -050096
David James8c846492011-01-25 17:07:29 -080097 File format:
98 key="value"
99 Note quotes are added automatically
100
101 Args:
102 filename: Name of file to modify.
103 value: Value to write with the key.
104 key: The variable key to update. (Default: PORTAGE_BINHOST)
David Jamesb26b9312014-12-15 11:26:46 -0800105
106 Returns:
107 True if changes were made to the file.
David James8c846492011-01-25 17:07:29 -0800108 """
109 if os.path.exists(filename):
110 file_fh = open(filename)
111 else:
112 file_fh = open(filename, 'w+')
113 file_lines = []
114 found = False
David Jamesb26b9312014-12-15 11:26:46 -0800115 made_changes = False
David James8c846492011-01-25 17:07:29 -0800116 keyval_str = '%(key)s=%(value)s'
117 for line in file_fh:
118 # Strip newlines from end of line. We already add newlines below.
Mike Frysinger80de5012019-08-01 14:10:53 -0400119 line = line.rstrip('\n')
David James8c846492011-01-25 17:07:29 -0800120
121 if len(line.split('=')) != 2:
122 # Skip any line that doesn't fit key=val.
123 file_lines.append(line)
124 continue
125
126 file_var, file_val = line.split('=')
127 if file_var == key:
128 found = True
Mike Frysingerff441bf2014-05-24 13:47:21 -0400129 print('Updating %s=%s to %s="%s"' % (file_var, file_val, key, value))
David James8c846492011-01-25 17:07:29 -0800130 value = '"%s"' % value
David Jamesb26b9312014-12-15 11:26:46 -0800131 made_changes |= (file_val != value)
David James8c846492011-01-25 17:07:29 -0800132 file_lines.append(keyval_str % {'key': key, 'value': value})
133 else:
134 file_lines.append(keyval_str % {'key': file_var, 'value': file_val})
135
136 if not found:
Brian Harring2a014302012-05-12 00:53:33 -0700137 value = '"%s"' % value
David Jamesb26b9312014-12-15 11:26:46 -0800138 made_changes = True
David James8c846492011-01-25 17:07:29 -0800139 file_lines.append(keyval_str % {'key': key, 'value': value})
140
141 file_fh.close()
142 # write out new file
Brian Harringaf019fb2012-05-10 15:06:13 -0700143 osutils.WriteFile(filename, '\n'.join(file_lines) + '\n')
David Jamesb26b9312014-12-15 11:26:46 -0800144 return made_changes
David James8c846492011-01-25 17:07:29 -0800145
146
Mike Nicholsa6818c52018-04-09 11:05:42 -0600147def RevGitFile(filename, data, dryrun=False):
David James8c846492011-01-25 17:07:29 -0800148 """Update and push the git file.
149
Mike Frysinger5b34d732013-01-17 15:11:58 -0500150 Args:
151 filename: file to modify that is in a git repo already
152 data: A dict of key/values to update in |filename|
Matt Tennante8179042013-10-01 15:47:32 -0700153 dryrun: If True, do not actually commit the change.
David James8c846492011-01-25 17:07:29 -0800154 """
155 prebuilt_branch = 'prebuilt_branch'
David James1b6e67a2011-05-19 21:32:38 -0700156 cwd = os.path.abspath(os.path.dirname(filename))
Julio Hurtado180a42f2021-05-13 21:42:08 +0000157 commit = git.RunGit(cwd, ['rev-parse', 'HEAD']).output.rstrip()
Mike Frysinger5b34d732013-01-17 15:11:58 -0500158 description = '%s: updating %s' % (os.path.basename(filename),
159 ', '.join(data.keys()))
160 # UpdateLocalFile will print out the keys/values for us.
Mike Frysingerff441bf2014-05-24 13:47:21 -0400161 print('Revving git file %s' % filename)
Julio Hurtado2d4817d2021-04-29 16:03:58 +0000162
Julio Hurtado180a42f2021-05-13 21:42:08 +0000163 try:
164 git.CreatePushBranch(prebuilt_branch, cwd)
165 for key, value in data.items():
166 UpdateLocalFile(filename, value, key)
167 git.RunGit(cwd, ['add', filename])
168 git.RunGit(cwd, ['commit', '-m', description])
169 git.PushBranch(prebuilt_branch, cwd, dryrun=dryrun, auto_merge=True)
170 finally:
171 # We reset the index and the working tree state in case there are any
172 # uncommitted or pending changes, but we don't change any existing commits.
173 git.RunGit(cwd, ['reset', '--hard'])
174
175 # Check out the last good commit as a sanity fallback.
176 git.RunGit(cwd, ['checkout', commit])
David James8c846492011-01-25 17:07:29 -0800177
178
179def GetVersion():
180 """Get the version to put in LATEST and update the git version with."""
Mike Frysinger0b92cfe2012-12-13 02:13:45 -0500181 return datetime.datetime.now().strftime('%Y.%m.%d.%H%M%S')
David James8c846492011-01-25 17:07:29 -0800182
183
Mike Frysinger540883b2014-05-24 13:46:16 -0400184def _GsUpload(gs_context, acl, local_file, remote_file):
David James8c846492011-01-25 17:07:29 -0800185 """Upload to GS bucket.
186
187 Args:
Mike Frysinger540883b2014-05-24 13:46:16 -0400188 gs_context: A lib.gs.GSContext instance.
189 acl: The ACL to use for uploading the file.
Matt Tennante8179042013-10-01 15:47:32 -0700190 local_file: The local file to be uploaded.
191 remote_file: The remote location to upload to.
David James8c846492011-01-25 17:07:29 -0800192 """
Scott Zawalskiab1bed32011-03-16 15:24:24 -0700193 CANNED_ACLS = ['public-read', 'private', 'bucket-owner-read',
194 'authenticated-read', 'bucket-owner-full-control',
195 'public-read-write']
Scott Zawalskiab1bed32011-03-16 15:24:24 -0700196 if acl in CANNED_ACLS:
David James9374aac2013-10-08 16:00:17 -0700197 gs_context.Copy(local_file, remote_file, acl=acl)
Scott Zawalskiab1bed32011-03-16 15:24:24 -0700198 else:
199 # For private uploads we assume that the overlay board is set up properly
David James015af872012-06-19 15:24:36 -0700200 # and a googlestore_acl.xml is present. Otherwise, this script errors.
David James7b7d7c32015-04-02 13:48:17 -0700201 # We set version=0 here to ensure that the ACL is set only once (see
202 # http://b/15883752#comment54).
203 try:
204 gs_context.Copy(local_file, remote_file, version=0)
205 except gs.GSContextPreconditionFailed as ex:
206 # If we received a GSContextPreconditionFailed error, we know that the
207 # file exists now, but we don't know whether our specific update
208 # succeeded. See http://b/15883752#comment62
209 logging.warning(
210 'Assuming upload succeeded despite PreconditionFailed errors: %s', ex)
211
Gabe Black40169e62014-06-17 15:23:47 -0700212 if acl.endswith('.xml'):
213 # Apply the passed in ACL xml file to the uploaded object.
214 gs_context.SetACL(remote_file, acl=acl)
215 else:
Mike Frysinger5186f262017-09-13 10:26:19 -0400216 gs_context.ChangeACL(remote_file, acl_args_file=acl)
Scott Zawalskiab1bed32011-03-16 15:24:24 -0700217
Mike Frysingercc838832014-05-24 13:10:30 -0400218
Mike Frysinger540883b2014-05-24 13:46:16 -0400219def RemoteUpload(gs_context, acl, files, pool=10):
David James8c846492011-01-25 17:07:29 -0800220 """Upload to google storage.
221
222 Create a pool of process and call _GsUpload with the proper arguments.
223
224 Args:
Mike Frysinger540883b2014-05-24 13:46:16 -0400225 gs_context: A lib.gs.GSContext instance.
David Jamesfd0b0852011-02-23 11:15:36 -0800226 acl: The canned acl used for uploading. acl can be one of: "public-read",
227 "public-read-write", "authenticated-read", "bucket-owner-read",
228 "bucket-owner-full-control", or "private".
David James8c846492011-01-25 17:07:29 -0800229 files: dictionary with keys to local files and values to remote path.
230 pool: integer of maximum proesses to have at the same time.
231
232 Returns:
233 Return a set of tuple arguments of the failed uploads
234 """
Mike Frysinger540883b2014-05-24 13:46:16 -0400235 upload = functools.partial(_GsUpload, gs_context, acl)
Mike Frysinger0bdbc102019-06-13 15:27:29 -0400236 tasks = [[key, value] for key, value in files.items()]
Mike Frysinger540883b2014-05-24 13:46:16 -0400237 parallel.RunTasksInProcessPool(upload, tasks, pool)
David James8c846492011-01-25 17:07:29 -0800238
239
240def GenerateUploadDict(base_local_path, base_remote_path, pkgs):
241 """Build a dictionary of local remote file key pairs to upload.
242
243 Args:
244 base_local_path: The base path to the files on the local hard drive.
Matt Tennante8179042013-10-01 15:47:32 -0700245 base_remote_path: The base path to the remote paths.
David James8c846492011-01-25 17:07:29 -0800246 pkgs: The packages to upload.
247
248 Returns:
249 Returns a dictionary of local_path/remote_path pairs
250 """
251 upload_files = {}
252 for pkg in pkgs:
253 suffix = pkg['CPV'] + '.tbz2'
254 local_path = os.path.join(base_local_path, suffix)
David James7b7d7c32015-04-02 13:48:17 -0700255 assert os.path.exists(local_path), '%s does not exist' % local_path
Bertrand SIMONNET811bcde2014-11-20 15:21:25 -0800256 upload_files[local_path] = os.path.join(base_remote_path, suffix)
David James8c846492011-01-25 17:07:29 -0800257
Bertrand SIMONNET811bcde2014-11-20 15:21:25 -0800258 if pkg.get('DEBUG_SYMBOLS') == 'yes':
259 debugsuffix = pkg['CPV'] + '.debug.tbz2'
260 local_path = os.path.join(base_local_path, debugsuffix)
261 assert os.path.exists(local_path)
262 upload_files[local_path] = os.path.join(base_remote_path, debugsuffix)
Bertrand SIMONNET22e828b2014-11-11 16:27:06 -0800263
David James8c846492011-01-25 17:07:29 -0800264 return upload_files
265
Mike Frysingercc838832014-05-24 13:10:30 -0400266
Peter Mayo950e41a2014-02-06 21:07:33 +0000267def GetBoardOverlay(build_path, target):
David Jamese5867812012-10-19 12:02:20 -0700268 """Get the path to the board variant.
Mike Frysinger1a736a82013-12-12 01:50:59 -0500269
Mike Frysinger6f3c48e2015-05-06 02:38:51 -0400270 Args:
271 build_path: The path to the root of the build directory
272 target: The target board as a BuildTarget object.
Mike Frysinger1a736a82013-12-12 01:50:59 -0500273
Mike Frysinger6f3c48e2015-05-06 02:38:51 -0400274 Returns:
275 The last overlay configured for the given board as a string.
David James8c846492011-01-25 17:07:29 -0800276 """
David Jamese5867812012-10-19 12:02:20 -0700277 board = target.board_variant
Alex Deymo075c2292014-09-04 18:31:50 -0700278 overlays = portage_util.FindOverlays(constants.BOTH_OVERLAYS, board,
279 buildroot=build_path)
David Jamese5867812012-10-19 12:02:20 -0700280 # We only care about the last entry.
281 return overlays[-1]
David James8c846492011-01-25 17:07:29 -0800282
283
284def DeterminePrebuiltConfFile(build_path, target):
285 """Determine the prebuilt.conf file that needs to be updated for prebuilts.
286
Mike Frysinger1a736a82013-12-12 01:50:59 -0500287 Args:
288 build_path: The path to the root of the build directory
289 target: String representation of the board. This includes host and board
290 targets
David James8c846492011-01-25 17:07:29 -0800291
Mike Frysinger1a736a82013-12-12 01:50:59 -0500292 Returns:
293 A string path to a prebuilt.conf file to be updated.
David James8c846492011-01-25 17:07:29 -0800294 """
David James4058b0d2011-12-08 21:24:50 -0800295 if _HOST_ARCH == target:
David James8c846492011-01-25 17:07:29 -0800296 # We are host.
297 # Without more examples of hosts this is a kludge for now.
298 # TODO(Scottz): as new host targets come online expand this to
299 # work more like boards.
Chris Sosa471532a2011-02-01 15:10:06 -0800300 make_path = _PREBUILT_MAKE_CONF[target]
David James8c846492011-01-25 17:07:29 -0800301 else:
302 # We are a board
Peter Mayo950e41a2014-02-06 21:07:33 +0000303 board = GetBoardOverlay(build_path, target)
David James8c846492011-01-25 17:07:29 -0800304 make_path = os.path.join(board, 'prebuilt.conf')
305
306 return make_path
307
308
309def UpdateBinhostConfFile(path, key, value):
310 """Update binhost config file file with key=value.
311
312 Args:
313 path: Filename to update.
314 key: Key to update.
315 value: New value for key.
316 """
David Jamesb26b9312014-12-15 11:26:46 -0800317 cwd, filename = os.path.split(os.path.abspath(path))
Brian Harringaf019fb2012-05-10 15:06:13 -0700318 osutils.SafeMakedirs(cwd)
David Jamesf6e8fb72013-05-10 08:58:43 -0700319 if not git.GetCurrentBranch(cwd):
320 git.CreatePushBranch(constants.STABLE_EBUILD_BRANCH, cwd, sync=False)
Brian Harring22edb442012-05-11 23:55:18 -0700321 osutils.WriteFile(path, '', mode='a')
David Jamesb26b9312014-12-15 11:26:46 -0800322 if UpdateLocalFile(path, value, key):
323 desc = '%s: %s %s' % (filename, 'updating' if value else 'clearing', key)
324 git.AddPath(path)
325 git.Commit(cwd, desc)
David James8c846492011-01-25 17:07:29 -0800326
Achuith Bhandarkar03d924a2018-01-02 10:50:44 -0800327def GenerateHtmlIndex(files, index, board, version, remote_location):
Mike Frysinger212e4292014-05-24 15:15:44 -0400328 """Given the list of |files|, generate an index.html at |index|.
329
330 Args:
331 files: The list of files to link to.
332 index: The path to the html index.
333 board: Name of the board this index is for.
334 version: Build version this index is for.
Achuith Bhandarkar03d924a2018-01-02 10:50:44 -0800335 remote_location: Remote gs location prebuilts are uploaded to.
Mike Frysinger212e4292014-05-24 15:15:44 -0400336 """
Don Garrett13cbbff2016-08-09 14:18:38 -0700337 title = 'Package Prebuilt Index: %s / %s' % (board, version)
Mike Frysinger212e4292014-05-24 15:15:44 -0400338
339 files = files + [
340 '.|Google Storage Index',
341 '..|',
342 ]
Achuith Bhandarkar03d924a2018-01-02 10:50:44 -0800343 commands.GenerateHtmlIndex(index, files, title=title,
344 url_base=gs.GsUrlToHttp(remote_location))
Mike Frysinger212e4292014-05-24 15:15:44 -0400345
346
David Jamesce093af2011-02-23 15:21:58 -0800347def _GrabAllRemotePackageIndexes(binhost_urls):
David James05bcb2b2011-02-09 09:25:47 -0800348 """Grab all of the packages files associated with a list of binhost_urls.
349
David James05bcb2b2011-02-09 09:25:47 -0800350 Args:
351 binhost_urls: The URLs for the directories containing the Packages files we
352 want to grab.
David James05bcb2b2011-02-09 09:25:47 -0800353
354 Returns:
355 A list of PackageIndex objects.
356 """
357 pkg_indexes = []
358 for url in binhost_urls:
David James32faafe2012-06-08 14:25:03 -0700359 pkg_index = binpkg.GrabRemotePackageIndex(url)
David James05bcb2b2011-02-09 09:25:47 -0800360 if pkg_index:
361 pkg_indexes.append(pkg_index)
David James05bcb2b2011-02-09 09:25:47 -0800362 return pkg_indexes
363
364
David Jamesc0f158a2011-02-22 16:07:29 -0800365class PrebuiltUploader(object):
366 """Synchronize host and board prebuilts."""
David James8c846492011-01-25 17:07:29 -0800367
Mike Frysinger86509232014-05-24 13:18:37 -0400368 def __init__(self, upload_location, acl, binhost_base_url, pkg_indexes,
369 build_path, packages, skip_upload, binhost_conf_dir, dryrun,
Mike Frysinger8092a632014-05-24 13:25:46 -0400370 target, slave_targets, version):
David Jamesc0f158a2011-02-22 16:07:29 -0800371 """Constructor for prebuilt uploader object.
David James8c846492011-01-25 17:07:29 -0800372
David Jamesc0f158a2011-02-22 16:07:29 -0800373 This object can upload host or prebuilt files to Google Storage.
David James8c846492011-01-25 17:07:29 -0800374
David Jamesc0f158a2011-02-22 16:07:29 -0800375 Args:
376 upload_location: The upload location.
David Jamesfd0b0852011-02-23 11:15:36 -0800377 acl: The canned acl used for uploading to Google Storage. acl can be one
378 of: "public-read", "public-read-write", "authenticated-read",
Matt Tennante8179042013-10-01 15:47:32 -0700379 "bucket-owner-read", "bucket-owner-full-control", "project-private",
380 or "private" (see "gsutil help acls"). If we are not uploading to
381 Google Storage, this parameter is unused.
David Jamesfd0b0852011-02-23 11:15:36 -0800382 binhost_base_url: The URL used for downloading the prebuilts.
David Jamesc0f158a2011-02-22 16:07:29 -0800383 pkg_indexes: Old uploaded prebuilts to compare against. Instead of
384 uploading duplicate files, we just link to the old files.
David James615e5b52011-06-03 11:10:15 -0700385 build_path: The path to the directory containing the chroot.
386 packages: Packages to upload.
David James32b0b2f2011-07-13 20:56:50 -0700387 skip_upload: Don't actually upload the tarballs.
388 binhost_conf_dir: Directory where to store binhost.conf files.
Mike Frysinger86509232014-05-24 13:18:37 -0400389 dryrun: Don't push or upload prebuilts.
David James4058b0d2011-12-08 21:24:50 -0800390 target: BuildTarget managed by this builder.
391 slave_targets: List of BuildTargets managed by slave builders.
Mike Frysinger8092a632014-05-24 13:25:46 -0400392 version: A unique string, intended to be included in the upload path,
393 which identifies the version number of the uploaded prebuilts.
David Jamesc0f158a2011-02-22 16:07:29 -0800394 """
395 self._upload_location = upload_location
David Jamesfd0b0852011-02-23 11:15:36 -0800396 self._acl = acl
David Jamesc0f158a2011-02-22 16:07:29 -0800397 self._binhost_base_url = binhost_base_url
398 self._pkg_indexes = pkg_indexes
David James615e5b52011-06-03 11:10:15 -0700399 self._build_path = build_path
400 self._packages = set(packages)
Mike Frysingerf5f809a2013-02-12 13:47:37 -0500401 self._found_packages = set()
David James8ece7ee2011-06-29 16:02:30 -0700402 self._skip_upload = skip_upload
David James32b0b2f2011-07-13 20:56:50 -0700403 self._binhost_conf_dir = binhost_conf_dir
Mike Frysinger86509232014-05-24 13:18:37 -0400404 self._dryrun = dryrun
David James4058b0d2011-12-08 21:24:50 -0800405 self._target = target
406 self._slave_targets = slave_targets
Mike Frysinger8092a632014-05-24 13:25:46 -0400407 self._version = version
Mike Frysinger540883b2014-05-24 13:46:16 -0400408 self._gs_context = gs.GSContext(retries=_RETRIES, sleep=_SLEEP_TIME,
409 dry_run=self._dryrun)
410
411 def _Upload(self, local_file, remote_file):
412 """Wrapper around _GsUpload"""
413 _GsUpload(self._gs_context, self._acl, local_file, remote_file)
David James615e5b52011-06-03 11:10:15 -0700414
415 def _ShouldFilterPackage(self, pkg):
416 if not self._packages:
417 return False
Alex Klein18a60af2020-06-11 12:08:47 -0600418 cpv = package_info.SplitCPV(pkg['CPV'])
Alex Klein9f93b482018-10-01 09:26:51 -0600419 self._found_packages.add(cpv.cp)
420 return cpv.package not in self._packages and cpv.cp not in self._packages
David James8c846492011-01-25 17:07:29 -0800421
David Jamesc0f158a2011-02-22 16:07:29 -0800422 def _UploadPrebuilt(self, package_path, url_suffix):
423 """Upload host or board prebuilt files to Google Storage space.
David James8c846492011-01-25 17:07:29 -0800424
David Jamesc0f158a2011-02-22 16:07:29 -0800425 Args:
426 package_path: The path to the packages dir.
David Jamesce093af2011-02-23 15:21:58 -0800427 url_suffix: The remote subdirectory where we should upload the packages.
David Jamesc0f158a2011-02-22 16:07:29 -0800428 """
David Jamesc0f158a2011-02-22 16:07:29 -0800429 # Process Packages file, removing duplicates and filtered packages.
David James32faafe2012-06-08 14:25:03 -0700430 pkg_index = binpkg.GrabLocalPackageIndex(package_path)
David Jamesc0f158a2011-02-22 16:07:29 -0800431 pkg_index.SetUploadLocation(self._binhost_base_url, url_suffix)
David James615e5b52011-06-03 11:10:15 -0700432 pkg_index.RemoveFilteredPackages(self._ShouldFilterPackage)
David Jamesc0f158a2011-02-22 16:07:29 -0800433 uploads = pkg_index.ResolveDuplicateUploads(self._pkg_indexes)
Mike Frysingerf5f809a2013-02-12 13:47:37 -0500434 unmatched_pkgs = self._packages - self._found_packages
435 if unmatched_pkgs:
Lann Martinffb95162018-08-28 12:02:54 -0600436 logging.warning('unable to match packages: %r', unmatched_pkgs)
David James05bcb2b2011-02-09 09:25:47 -0800437
David Jamesc0f158a2011-02-22 16:07:29 -0800438 # Write Packages file.
David James5ab67e32014-10-24 08:19:59 -0700439 pkg_index.header['TTL'] = _BINPKG_TTL
David Jamesc0f158a2011-02-22 16:07:29 -0800440 tmp_packages_file = pkg_index.WriteToNamedTemporaryFile()
David James05bcb2b2011-02-09 09:25:47 -0800441
David Jamesc0f158a2011-02-22 16:07:29 -0800442 remote_location = '%s/%s' % (self._upload_location.rstrip('/'), url_suffix)
David James015af872012-06-19 15:24:36 -0700443 assert remote_location.startswith('gs://')
David James05bcb2b2011-02-09 09:25:47 -0800444
David James015af872012-06-19 15:24:36 -0700445 upload_files = GenerateUploadDict(package_path, remote_location, uploads)
446 remote_file = '%s/Packages' % remote_location.rstrip('/')
447 upload_files[tmp_packages_file.name] = remote_file
448
Mike Frysinger9bb6cd82020-08-20 03:02:23 -0400449 # Build list of files to upload. Manually include the dev-only files but
450 # skip them if not present.
451 dev_only = os.path.join(package_path, 'dev-only-extras.tar.xz')
452 if os.path.exists(dev_only):
453 upload_files[dev_only] = '%s/%s' % (
454 remote_location.rstrip('/'), os.path.basename(dev_only))
455
Mike Frysinger540883b2014-05-24 13:46:16 -0400456 RemoteUpload(self._gs_context, self._acl, upload_files)
David James8c846492011-01-25 17:07:29 -0800457
Mike Frysinger212e4292014-05-24 15:15:44 -0400458 with tempfile.NamedTemporaryFile(
459 prefix='chromite.upload_prebuilts.index.') as index:
460 GenerateHtmlIndex(
461 [x[len(remote_location) + 1:] for x in upload_files.values()],
Achuith Bhandarkar03d924a2018-01-02 10:50:44 -0800462 index.name, self._target, self._version, remote_location)
Mike Frysinger212e4292014-05-24 15:15:44 -0400463 self._Upload(index.name, '%s/index.html' % remote_location.rstrip('/'))
464
465 link_name = 'Prebuilts[%s]: %s' % (self._target, self._version)
466 url = '%s%s/index.html' % (gs.PUBLIC_BASE_HTTPS_URL,
467 remote_location[len(gs.BASE_GS_URL):])
Prathmesh Prabhu17f07422015-07-17 11:40:40 -0700468 logging.PrintBuildbotLink(link_name, url)
Mike Frysinger212e4292014-05-24 15:15:44 -0400469
Mike Frysinger8092a632014-05-24 13:25:46 -0400470 def _UploadSdkTarball(self, board_path, url_suffix, prepackaged,
Gilad Arnold2b79e2d2015-06-02 11:26:07 -0700471 toolchains_overlay_tarballs,
472 toolchains_overlay_upload_path,
Mike Frysinger9e979b92012-11-29 02:55:09 -0500473 toolchain_tarballs, toolchain_upload_path):
474 """Upload a tarball of the sdk at the specified path to Google Storage.
David James8fa34ea2011-04-15 13:00:20 -0700475
476 Args:
477 board_path: The path to the board dir.
478 url_suffix: The remote subdirectory where we should upload the packages.
Zdenek Behan62a57792012-08-31 15:09:08 +0200479 prepackaged: If given, a tarball that has been packaged outside of this
480 script and should be used.
Gilad Arnold2b79e2d2015-06-02 11:26:07 -0700481 toolchains_overlay_tarballs: List of toolchains overlay tarball
482 specifications to upload. Items take the form
483 "toolchains_spec:/path/to/tarball".
484 toolchains_overlay_upload_path: Path template under the bucket to place
485 toolchains overlay tarballs.
Mike Frysinger9e979b92012-11-29 02:55:09 -0500486 toolchain_tarballs: List of toolchain tarballs to upload.
487 toolchain_upload_path: Path under the bucket to place toolchain tarballs.
David James8fa34ea2011-04-15 13:00:20 -0700488 """
489 remote_location = '%s/%s' % (self._upload_location.rstrip('/'), url_suffix)
490 assert remote_location.startswith('gs://')
Zdenek Behan86c15e92012-10-13 00:55:47 +0200491 boardname = os.path.basename(board_path.rstrip('/'))
492 # We do not upload non SDK board tarballs,
493 assert boardname == constants.CHROOT_BUILDER_BOARD
494 assert prepackaged is not None
Zdenek Behan62a57792012-08-31 15:09:08 +0200495
Mike Frysinger8092a632014-05-24 13:25:46 -0400496 version_str = self._version[len('chroot-'):]
Mike Frysinger8e727a32013-01-16 16:57:53 -0500497 remote_tarfile = toolchain.GetSdkURL(
498 for_gsutil=True, suburl='cros-sdk-%s.tar.xz' % (version_str,))
Zdenek Behan86c15e92012-10-13 00:55:47 +0200499 # For SDK, also upload the manifest which is guaranteed to exist
500 # by the builderstage.
Mike Frysinger540883b2014-05-24 13:46:16 -0400501 self._Upload(prepackaged + '.Manifest', remote_tarfile + '.Manifest')
502 self._Upload(prepackaged, remote_tarfile)
Zdenek Behan86c15e92012-10-13 00:55:47 +0200503
Gilad Arnold2b79e2d2015-06-02 11:26:07 -0700504 # Upload SDK toolchains overlays and toolchain tarballs, if given.
Gilad Arnoldad333182015-05-27 15:50:41 -0700505 for tarball_list, upload_path, qualifier_name in (
Gilad Arnold2b79e2d2015-06-02 11:26:07 -0700506 (toolchains_overlay_tarballs, toolchains_overlay_upload_path,
507 'toolchains'),
Gilad Arnoldad333182015-05-27 15:50:41 -0700508 (toolchain_tarballs, toolchain_upload_path, 'target')):
Gilad Arnold2b79e2d2015-06-02 11:26:07 -0700509 for tarball_spec in tarball_list:
510 qualifier_val, local_path = tarball_spec.split(':')
Gilad Arnoldad333182015-05-27 15:50:41 -0700511 suburl = upload_path % {qualifier_name: qualifier_val}
512 remote_path = toolchain.GetSdkURL(for_gsutil=True, suburl=suburl)
513 self._Upload(local_path, remote_path)
Mike Frysinger9e979b92012-11-29 02:55:09 -0500514
Zdenek Behan86c15e92012-10-13 00:55:47 +0200515 # Finally, also update the pointer to the latest SDK on which polling
516 # scripts rely.
David James4bc13702013-03-26 08:08:04 -0700517 with osutils.TempDir() as tmpdir:
Zdenek Behan86c15e92012-10-13 00:55:47 +0200518 pointerfile = os.path.join(tmpdir, 'cros-sdk-latest.conf')
Mike Frysinger8e727a32013-01-16 16:57:53 -0500519 remote_pointerfile = toolchain.GetSdkURL(for_gsutil=True,
520 suburl='cros-sdk-latest.conf')
Zdenek Behan86c15e92012-10-13 00:55:47 +0200521 osutils.WriteFile(pointerfile, 'LATEST_SDK="%s"' % version_str)
Mike Frysinger540883b2014-05-24 13:46:16 -0400522 self._Upload(pointerfile, remote_pointerfile)
Zdenek Behan33a34112012-09-10 21:07:51 +0200523
Chris Sosa6a5dceb2012-05-14 13:48:56 -0700524 def _GetTargets(self):
525 """Retuns the list of targets to use."""
526 targets = self._slave_targets[:]
527 if self._target:
528 targets.append(self._target)
529
530 return targets
531
Mike Frysinger8092a632014-05-24 13:25:46 -0400532 def SyncHostPrebuilts(self, key, git_sync, sync_binhost_conf):
David Jamesc0f158a2011-02-22 16:07:29 -0800533 """Synchronize host prebuilt files.
David James05bcb2b2011-02-09 09:25:47 -0800534
David Jamesc0f158a2011-02-22 16:07:29 -0800535 This function will sync both the standard host packages, plus the host
536 packages associated with all targets that have been "setup" with the
537 current host's chroot. For instance, if this host has been used to build
538 x86-generic, it will sync the host packages associated with
539 'i686-pc-linux-gnu'. If this host has also been used to build arm-generic,
540 it will also sync the host packages associated with
541 'armv7a-cros-linux-gnueabi'.
David James05bcb2b2011-02-09 09:25:47 -0800542
David Jamesc0f158a2011-02-22 16:07:29 -0800543 Args:
David Jamesc0f158a2011-02-22 16:07:29 -0800544 key: The variable key to update in the git file.
545 git_sync: If set, update make.conf of target to reference the latest
546 prebuilt packages generated here.
547 sync_binhost_conf: If set, update binhost config file in
548 chromiumos-overlay for the host.
549 """
Mike Nicholsa1414162021-04-22 20:07:22 +0000550 # Slave boards are listed before the master board so that the master board
David Jamese2488642011-11-14 16:15:20 -0800551 # takes priority (i.e. x86-generic preflight host prebuilts takes priority
552 # over preflight host prebuilts from other builders.)
553 binhost_urls = []
Chris Sosa6a5dceb2012-05-14 13:48:56 -0700554 for target in self._GetTargets():
Mike Frysinger8092a632014-05-24 13:25:46 -0400555 url_suffix = _REL_HOST_PATH % {'version': self._version,
David James4058b0d2011-12-08 21:24:50 -0800556 'host_arch': _HOST_ARCH,
557 'target': target}
David Jamese2488642011-11-14 16:15:20 -0800558 packages_url_suffix = '%s/packages' % url_suffix.rstrip('/')
David James05bcb2b2011-02-09 09:25:47 -0800559
Mike Frysinger540883b2014-05-24 13:46:16 -0400560 if self._target == target and not self._skip_upload:
David Jamese2488642011-11-14 16:15:20 -0800561 # Upload prebuilts.
562 package_path = os.path.join(self._build_path, _HOST_PACKAGES_PATH)
563 self._UploadPrebuilt(package_path, packages_url_suffix)
David James8ece7ee2011-06-29 16:02:30 -0700564
David Jamese2488642011-11-14 16:15:20 -0800565 # Record URL where prebuilts were uploaded.
566 binhost_urls.append('%s/%s/' % (self._binhost_base_url.rstrip('/'),
567 packages_url_suffix.rstrip('/')))
568
David James20b2b6f2011-11-18 15:11:58 -0800569 binhost = ' '.join(binhost_urls)
David James8ece7ee2011-06-29 16:02:30 -0700570 if git_sync:
David Jamesb26b9312014-12-15 11:26:46 -0800571 git_file = os.path.join(self._build_path, _PREBUILT_MAKE_CONF[_HOST_ARCH])
Mike Frysinger86509232014-05-24 13:18:37 -0400572 RevGitFile(git_file, {key: binhost}, dryrun=self._dryrun)
David James8ece7ee2011-06-29 16:02:30 -0700573 if sync_binhost_conf:
David Jamesb26b9312014-12-15 11:26:46 -0800574 binhost_conf = os.path.join(
575 self._binhost_conf_dir, 'host', '%s-%s.conf' % (_HOST_ARCH, key))
David Jamese2488642011-11-14 16:15:20 -0800576 UpdateBinhostConfFile(binhost_conf, key, binhost)
David Jamesc0f158a2011-02-22 16:07:29 -0800577
Mike Frysinger8092a632014-05-24 13:25:46 -0400578 def SyncBoardPrebuilts(self, key, git_sync, sync_binhost_conf,
Mike Frysinger9e979b92012-11-29 02:55:09 -0500579 upload_board_tarball, prepackaged_board,
Gilad Arnold2b79e2d2015-06-02 11:26:07 -0700580 toolchains_overlay_tarballs,
581 toolchains_overlay_upload_path,
Mike Frysinger9e979b92012-11-29 02:55:09 -0500582 toolchain_tarballs, toolchain_upload_path):
David Jamesc0f158a2011-02-22 16:07:29 -0800583 """Synchronize board prebuilt files.
584
585 Args:
David Jamesc0f158a2011-02-22 16:07:29 -0800586 key: The variable key to update in the git file.
587 git_sync: If set, update make.conf of target to reference the latest
588 prebuilt packages generated here.
589 sync_binhost_conf: If set, update binhost config file in
590 chromiumos-overlay for the current board.
David James8fa34ea2011-04-15 13:00:20 -0700591 upload_board_tarball: Include a tarball of the board in our upload.
Zdenek Behan62a57792012-08-31 15:09:08 +0200592 prepackaged_board: A tarball of the board built outside of this script.
Gilad Arnold2b79e2d2015-06-02 11:26:07 -0700593 toolchains_overlay_tarballs: List of toolchains overlay tarball
594 specifications to upload. Items take the form
595 "toolchains_spec:/path/to/tarball".
596 toolchains_overlay_upload_path: Path template under the bucket to place
597 toolchains overlay tarballs.
Mike Frysinger9e979b92012-11-29 02:55:09 -0500598 toolchain_tarballs: A list of toolchain tarballs to upload.
599 toolchain_upload_path: Path under the bucket to place toolchain tarballs.
David Jamesc0f158a2011-02-22 16:07:29 -0800600 """
David Jamesb26b9312014-12-15 11:26:46 -0800601 updated_binhosts = set()
Chris Sosa6a5dceb2012-05-14 13:48:56 -0700602 for target in self._GetTargets():
David Jamese2488642011-11-14 16:15:20 -0800603 board_path = os.path.join(self._build_path,
David James4058b0d2011-12-08 21:24:50 -0800604 _BOARD_PATH % {'board': target.board_variant})
David Jamese2488642011-11-14 16:15:20 -0800605 package_path = os.path.join(board_path, 'packages')
Mike Frysinger8092a632014-05-24 13:25:46 -0400606 url_suffix = _REL_BOARD_PATH % {'target': target,
607 'version': self._version}
David Jamese2488642011-11-14 16:15:20 -0800608 packages_url_suffix = '%s/packages' % url_suffix.rstrip('/')
David James8fa34ea2011-04-15 13:00:20 -0700609
Matt Tennante8179042013-10-01 15:47:32 -0700610 # Process the target board differently if it is the main --board.
Mike Frysinger540883b2014-05-24 13:46:16 -0400611 if self._target == target and not self._skip_upload:
Matt Tennante8179042013-10-01 15:47:32 -0700612 # This strips "chroot" prefix because that is sometimes added as the
613 # --prepend-version argument (e.g. by chromiumos-sdk bot).
614 # TODO(build): Clean it up to be less hard-coded.
Mike Frysinger8092a632014-05-24 13:25:46 -0400615 version_str = self._version[len('chroot-'):]
Mike Frysinger9e979b92012-11-29 02:55:09 -0500616
David Jamese2488642011-11-14 16:15:20 -0800617 # Upload board tarballs in the background.
618 if upload_board_tarball:
Mike Frysinger9e979b92012-11-29 02:55:09 -0500619 if toolchain_upload_path:
620 toolchain_upload_path %= {'version': version_str}
Gilad Arnold2b79e2d2015-06-02 11:26:07 -0700621 if toolchains_overlay_upload_path:
622 toolchains_overlay_upload_path %= {'version': version_str}
Mike Frysinger9e979b92012-11-29 02:55:09 -0500623 tar_process = multiprocessing.Process(
624 target=self._UploadSdkTarball,
Mike Frysinger8092a632014-05-24 13:25:46 -0400625 args=(board_path, url_suffix, prepackaged_board,
Gilad Arnold2b79e2d2015-06-02 11:26:07 -0700626 toolchains_overlay_tarballs,
627 toolchains_overlay_upload_path, toolchain_tarballs,
628 toolchain_upload_path))
David Jamese2488642011-11-14 16:15:20 -0800629 tar_process.start()
David James8fa34ea2011-04-15 13:00:20 -0700630
David Jamese2488642011-11-14 16:15:20 -0800631 # Upload prebuilts.
632 self._UploadPrebuilt(package_path, packages_url_suffix)
David James8fa34ea2011-04-15 13:00:20 -0700633
David Jamese2488642011-11-14 16:15:20 -0800634 # Make sure we finished uploading the board tarballs.
635 if upload_board_tarball:
636 tar_process.join()
637 assert tar_process.exitcode == 0
David Jamesc0f158a2011-02-22 16:07:29 -0800638
David Jamese2488642011-11-14 16:15:20 -0800639 # Record URL where prebuilts were uploaded.
640 url_value = '%s/%s/' % (self._binhost_base_url.rstrip('/'),
641 packages_url_suffix.rstrip('/'))
642
643 if git_sync:
David James4058b0d2011-12-08 21:24:50 -0800644 git_file = DeterminePrebuiltConfFile(self._build_path, target)
Mike Frysinger86509232014-05-24 13:18:37 -0400645 RevGitFile(git_file, {key: url_value}, dryrun=self._dryrun)
Matt Tennante8179042013-10-01 15:47:32 -0700646
David Jamese2488642011-11-14 16:15:20 -0800647 if sync_binhost_conf:
Matt Tennante8179042013-10-01 15:47:32 -0700648 # Update the binhost configuration file in git.
David Jamesb26b9312014-12-15 11:26:46 -0800649 binhost_conf = os.path.join(
650 self._binhost_conf_dir, 'target', '%s-%s.conf' % (target, key))
651 updated_binhosts.add(binhost_conf)
David Jamese2488642011-11-14 16:15:20 -0800652 UpdateBinhostConfFile(binhost_conf, key, url_value)
David James05bcb2b2011-02-09 09:25:47 -0800653
David Jamesb26b9312014-12-15 11:26:46 -0800654 if sync_binhost_conf:
655 # Clear all old binhosts. The files must be left empty in case anybody
656 # is referring to them.
657 all_binhosts = set(glob.glob(os.path.join(
658 self._binhost_conf_dir, 'target', '*-%s.conf' % key)))
659 for binhost_conf in all_binhosts - updated_binhosts:
660 UpdateBinhostConfFile(binhost_conf, key, '')
661
David James05bcb2b2011-02-09 09:25:47 -0800662
Mike Nicholsa1414162021-04-22 20:07:22 +0000663class _AddSlaveBoardAction(argparse.Action):
664 """Callback that adds a slave board to the list of slave targets."""
Mike Frysingerb87bb782015-06-04 02:46:50 -0400665 def __call__(self, parser, namespace, values, option_string=None):
666 getattr(namespace, self.dest).append(BuildTarget(values))
David James4058b0d2011-12-08 21:24:50 -0800667
668
Mike Nicholsa1414162021-04-22 20:07:22 +0000669class _AddSlaveProfileAction(argparse.Action):
670 """Callback that adds a slave profile to the list of slave targets."""
Mike Frysingerb87bb782015-06-04 02:46:50 -0400671 def __call__(self, parser, namespace, values, option_string=None):
672 if not namespace.slave_targets:
673 parser.error('Must specify --slave-board before --slave-profile')
674 if namespace.slave_targets[-1].profile is not None:
675 parser.error('Cannot specify --slave-profile twice for same board')
676 namespace.slave_targets[-1].profile = values
David James4058b0d2011-12-08 21:24:50 -0800677
678
Mike Frysinger86509232014-05-24 13:18:37 -0400679def ParseOptions(argv):
Chris Sosa6a5dceb2012-05-14 13:48:56 -0700680 """Returns options given by the user and the target specified.
681
Mike Frysinger86509232014-05-24 13:18:37 -0400682 Args:
683 argv: The args to parse.
684
Mike Frysinger1a736a82013-12-12 01:50:59 -0500685 Returns:
686 A tuple containing a parsed options object and BuildTarget.
687 The target instance is None if no board is specified.
Chris Sosa6a5dceb2012-05-14 13:48:56 -0700688 """
Mike Frysingerb87bb782015-06-04 02:46:50 -0400689 parser = commandline.ArgumentParser()
690 parser.add_argument('-H', '--binhost-base-url', default=_BINHOST_BASE_URL,
691 help='Base URL to use for binhost in make.conf updates')
692 parser.add_argument('--previous-binhost-url', action='append', default=[],
693 help='Previous binhost URL')
694 parser.add_argument('-b', '--board',
695 help='Board type that was built on this machine')
696 parser.add_argument('-B', '--prepackaged-tarball', type='path',
697 help='Board tarball prebuilt outside of this script.')
Gilad Arnold2b79e2d2015-06-02 11:26:07 -0700698 parser.add_argument('--toolchains-overlay-tarball',
699 dest='toolchains_overlay_tarballs',
Mike Frysingerb87bb782015-06-04 02:46:50 -0400700 action='append', default=[],
Gilad Arnold2b79e2d2015-06-02 11:26:07 -0700701 help='Toolchains overlay tarball specification to '
702 'upload. Takes the form '
703 '"toolchains_spec:/path/to/tarball".')
704 parser.add_argument('--toolchains-overlay-upload-path', default='',
705 help='Path template for uploading toolchains overlays.')
Mike Frysingerb87bb782015-06-04 02:46:50 -0400706 parser.add_argument('--toolchain-tarball', dest='toolchain_tarballs',
707 action='append', default=[],
708 help='Redistributable toolchain tarball.')
Gilad Arnold2b79e2d2015-06-02 11:26:07 -0700709 parser.add_argument('--toolchain-upload-path', default='',
Mike Frysingerb87bb782015-06-04 02:46:50 -0400710 help='Path to place toolchain tarballs in the sdk tree.')
711 parser.add_argument('--profile',
712 help='Profile that was built on this machine')
Mike Nicholsa1414162021-04-22 20:07:22 +0000713 parser.add_argument('--slave-board', default=[], action=_AddSlaveBoardAction,
Mike Frysingerb87bb782015-06-04 02:46:50 -0400714 dest='slave_targets',
715 help='Board type that was built on a slave machine. To '
716 'add a profile to this board, use --slave-profile.')
Mike Nicholsa1414162021-04-22 20:07:22 +0000717 parser.add_argument('--slave-profile', action=_AddSlaveProfileAction,
Mike Frysingerb87bb782015-06-04 02:46:50 -0400718 help='Board profile that was built on a slave machine. '
719 'Applies to previous slave board.')
720 parser.add_argument('-p', '--build-path', required=True,
721 help='Path to the directory containing the chroot')
722 parser.add_argument('--packages', action='append', default=[],
723 help='Only include the specified packages. '
724 '(Default is to include all packages.)')
725 parser.add_argument('-s', '--sync-host', default=False, action='store_true',
726 help='Sync host prebuilts')
727 parser.add_argument('-g', '--git-sync', default=False, action='store_true',
728 help='Enable git version sync (This commits to a repo.) '
729 'This is used by full builders to commit directly '
730 'to board overlays.')
731 parser.add_argument('-u', '--upload',
732 help='Upload location')
733 parser.add_argument('-V', '--prepend-version',
734 help='Add an identifier to the front of the version')
735 parser.add_argument('-f', '--filters', action='store_true', default=False,
736 help='Turn on filtering of private ebuild packages')
737 parser.add_argument('-k', '--key', default='PORTAGE_BINHOST',
738 help='Key to update in make.conf / binhost.conf')
739 parser.add_argument('--set-version',
740 help='Specify the version string')
741 parser.add_argument('--sync-binhost-conf', default=False, action='store_true',
742 help='Update binhost.conf in chromiumos-overlay or '
Mike Frysinger80de5012019-08-01 14:10:53 -0400743 "chromeos-overlay. Commit the changes, but don't "
Mike Frysingerb87bb782015-06-04 02:46:50 -0400744 'push them. This is used for preflight binhosts.')
745 parser.add_argument('--binhost-conf-dir',
746 help='Directory to commit binhost config with '
747 '--sync-binhost-conf.')
748 parser.add_argument('-P', '--private', action='store_true', default=False,
749 help='Mark gs:// uploads as private.')
750 parser.add_argument('--skip-upload', action='store_true', default=False,
751 help='Skip upload step.')
752 parser.add_argument('--upload-board-tarball', action='store_true',
753 default=False,
754 help='Upload board tarball to Google Storage.')
755 parser.add_argument('-n', '--dry-run', dest='dryrun',
756 action='store_true', default=False,
Mike Frysinger80de5012019-08-01 14:10:53 -0400757 help="Don't push or upload prebuilts.")
David James8c846492011-01-25 17:07:29 -0800758
Mike Frysingerb87bb782015-06-04 02:46:50 -0400759 options = parser.parse_args(argv)
David James8ece7ee2011-06-29 16:02:30 -0700760 if not options.upload and not options.skip_upload:
Mike Frysinger86509232014-05-24 13:18:37 -0400761 parser.error('you need to provide an upload location using -u')
David James8ece7ee2011-06-29 16:02:30 -0700762 if not options.set_version and options.skip_upload:
Mike Frysinger86509232014-05-24 13:18:37 -0400763 parser.error('If you are using --skip-upload, you must specify a '
764 'version number using --set-version.')
Scott Zawalskiab1bed32011-03-16 15:24:24 -0700765
Chris Sosa6a5dceb2012-05-14 13:48:56 -0700766 target = None
767 if options.board:
768 target = BuildTarget(options.board, options.profile)
769
770 if target in options.slave_targets:
Mike Frysinger86509232014-05-24 13:18:37 -0400771 parser.error('--board/--profile must not also be a slave target.')
David Jamese2488642011-11-14 16:15:20 -0800772
David James4058b0d2011-12-08 21:24:50 -0800773 if len(set(options.slave_targets)) != len(options.slave_targets):
Mike Frysinger86509232014-05-24 13:18:37 -0400774 parser.error('--slave-boards must not have duplicates.')
David Jamese2488642011-11-14 16:15:20 -0800775
David James4058b0d2011-12-08 21:24:50 -0800776 if options.slave_targets and options.git_sync:
Mike Frysinger86509232014-05-24 13:18:37 -0400777 parser.error('--slave-boards is not compatible with --git-sync')
David Jamese2488642011-11-14 16:15:20 -0800778
David James8ece7ee2011-06-29 16:02:30 -0700779 if (options.upload_board_tarball and options.skip_upload and
780 options.board == 'amd64-host'):
Mike Frysinger86509232014-05-24 13:18:37 -0400781 parser.error('--skip-upload is not compatible with '
782 '--upload-board-tarball and --board=amd64-host')
David James8fa34ea2011-04-15 13:00:20 -0700783
David James8ece7ee2011-06-29 16:02:30 -0700784 if (options.upload_board_tarball and not options.skip_upload and
785 not options.upload.startswith('gs://')):
Mike Frysinger86509232014-05-24 13:18:37 -0400786 parser.error('--upload-board-tarball only works with gs:// URLs.\n'
787 '--upload must be a gs:// URL.')
David James8fa34ea2011-04-15 13:00:20 -0700788
Zdenek Behan86c15e92012-10-13 00:55:47 +0200789 if options.upload_board_tarball and options.prepackaged_tarball is None:
Mike Frysinger86509232014-05-24 13:18:37 -0400790 parser.error('--upload-board-tarball requires --prepackaged-tarball')
Zdenek Behan86c15e92012-10-13 00:55:47 +0200791
Scott Zawalskiab1bed32011-03-16 15:24:24 -0700792 if options.private:
793 if options.sync_host:
Mike Frysinger86509232014-05-24 13:18:37 -0400794 parser.error('--private and --sync-host/-s cannot be specified '
795 'together; we do not support private host prebuilts')
Scott Zawalskiab1bed32011-03-16 15:24:24 -0700796
David James8ece7ee2011-06-29 16:02:30 -0700797 if not options.upload or not options.upload.startswith('gs://'):
Mike Frysinger86509232014-05-24 13:18:37 -0400798 parser.error('--private is only valid for gs:// URLs; '
799 '--upload must be a gs:// URL.')
Scott Zawalskiab1bed32011-03-16 15:24:24 -0700800
801 if options.binhost_base_url != _BINHOST_BASE_URL:
Mike Frysinger86509232014-05-24 13:18:37 -0400802 parser.error('when using --private the --binhost-base-url '
803 'is automatically derived.')
David James27fa7d12011-06-29 17:24:14 -0700804
David Jamesc31168e2014-06-05 14:40:05 -0700805 if options.sync_binhost_conf and not options.binhost_conf_dir:
806 parser.error('--sync-binhost-conf requires --binhost-conf-dir')
807
Gilad Arnold2b79e2d2015-06-02 11:26:07 -0700808 if (options.toolchains_overlay_tarballs and
809 not options.toolchains_overlay_upload_path):
810 parser.error('--toolchains-overlay-tarball requires '
811 '--toolchains-overlay-upload-path')
Gilad Arnoldad333182015-05-27 15:50:41 -0700812
Chris Sosa6a5dceb2012-05-14 13:48:56 -0700813 return options, target
David Jamesc0f158a2011-02-22 16:07:29 -0800814
Mike Frysingercc838832014-05-24 13:10:30 -0400815
Mike Frysinger86509232014-05-24 13:18:37 -0400816def main(argv):
David Jamesdb401072011-06-10 12:17:16 -0700817 # Set umask to a sane value so that files created as root are readable.
Mike Frysinger60ec1012013-10-21 00:11:10 -0400818 os.umask(0o22)
David Jamesdb401072011-06-10 12:17:16 -0700819
Mike Frysinger86509232014-05-24 13:18:37 -0400820 options, target = ParseOptions(argv)
David Jamesc0f158a2011-02-22 16:07:29 -0800821
David James05bcb2b2011-02-09 09:25:47 -0800822 # Calculate a list of Packages index files to compare against. Whenever we
823 # upload a package, we check to make sure it's not already stored in one of
824 # the packages files we uploaded. This list of packages files might contain
825 # both board and host packages.
David Jamesce093af2011-02-23 15:21:58 -0800826 pkg_indexes = _GrabAllRemotePackageIndexes(options.previous_binhost_url)
David James8c846492011-01-25 17:07:29 -0800827
David James8ece7ee2011-06-29 16:02:30 -0700828 if options.set_version:
829 version = options.set_version
830 else:
831 version = GetVersion()
Matt Tennante8179042013-10-01 15:47:32 -0700832
David Jamesc0f158a2011-02-22 16:07:29 -0800833 if options.prepend_version:
834 version = '%s-%s' % (options.prepend_version, version)
835
Scott Zawalskiab1bed32011-03-16 15:24:24 -0700836 acl = 'public-read'
837 binhost_base_url = options.binhost_base_url
838
David Jamesadd21432013-05-21 10:04:07 -0700839 if options.private:
Scott Zawalskiab1bed32011-03-16 15:24:24 -0700840 binhost_base_url = options.upload
David Jamesadd21432013-05-21 10:04:07 -0700841 if target:
Prathmesh Prabhu421eef22014-10-16 17:13:19 -0700842 acl = portage_util.FindOverlayFile(_GOOGLESTORAGE_GSUTIL_FILE,
843 board=target.board_variant,
844 buildroot=options.build_path)
Ben Chan067de492015-01-06 17:19:13 -0800845 if acl is None:
846 cros_build_lib.Die('No Google Storage ACL file %s found in %s overlay.',
847 _GOOGLESTORAGE_GSUTIL_FILE, target.board_variant)
Scott Zawalskiab1bed32011-03-16 15:24:24 -0700848
David Jamesb26b9312014-12-15 11:26:46 -0800849 binhost_conf_dir = None
850 if options.binhost_conf_dir:
851 binhost_conf_dir = os.path.join(options.build_path,
852 options.binhost_conf_dir)
853
Scott Zawalskiab1bed32011-03-16 15:24:24 -0700854 uploader = PrebuiltUploader(options.upload, acl, binhost_base_url,
David James615e5b52011-06-03 11:10:15 -0700855 pkg_indexes, options.build_path,
David James27fa7d12011-06-29 17:24:14 -0700856 options.packages, options.skip_upload,
David Jamesb26b9312014-12-15 11:26:46 -0800857 binhost_conf_dir, options.dryrun,
Mike Frysinger8092a632014-05-24 13:25:46 -0400858 target, options.slave_targets, version)
David Jamesc0f158a2011-02-22 16:07:29 -0800859
David James8c846492011-01-25 17:07:29 -0800860 if options.sync_host:
Mike Frysinger8092a632014-05-24 13:25:46 -0400861 uploader.SyncHostPrebuilts(options.key, options.git_sync,
Chris Sosa6a5dceb2012-05-14 13:48:56 -0700862 options.sync_binhost_conf)
David James8c846492011-01-25 17:07:29 -0800863
Chris Sosa62c8ff52012-06-04 15:03:12 -0700864 if options.board or options.slave_targets:
Mike Frysinger8092a632014-05-24 13:25:46 -0400865 uploader.SyncBoardPrebuilts(options.key, options.git_sync,
Chris Sosa6a5dceb2012-05-14 13:48:56 -0700866 options.sync_binhost_conf,
Zdenek Behan62a57792012-08-31 15:09:08 +0200867 options.upload_board_tarball,
Mike Frysinger9e979b92012-11-29 02:55:09 -0500868 options.prepackaged_tarball,
Gilad Arnold2b79e2d2015-06-02 11:26:07 -0700869 options.toolchains_overlay_tarballs,
870 options.toolchains_overlay_upload_path,
Mike Frysinger9e979b92012-11-29 02:55:09 -0500871 options.toolchain_tarballs,
872 options.toolchain_upload_path)