blob: 0d5adeea23dcb6d1f32ce25f424307fba88f7411 [file] [log] [blame]
Mike Frysingere58c0e22017-10-04 15:43:30 -04001# -*- coding: utf-8 -*-
Don Garrett13cbbff2016-08-09 14:18:38 -07002 # Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
David James8c846492011-01-25 17:07:29 -08003# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
5
Brian Harringaf019fb2012-05-10 15:06:13 -07006"""This script is used to upload host prebuilts as well as board BINHOSTS.
David James8c846492011-01-25 17:07:29 -08007
David James015af872012-06-19 15:24:36 -07008Prebuilts are uploaded using gsutil to Google Storage. After these prebuilts
9are successfully uploaded, a file is updated with the proper BINHOST version.
David James8c846492011-01-25 17:07:29 -080010
11To read more about prebuilts/binhost binary packages please refer to:
David James015af872012-06-19 15:24:36 -070012http://goto/chromeos-prebuilts
David James8c846492011-01-25 17:07:29 -080013
14Example of uploading prebuilt amd64 host files to Google Storage:
David Jamesc5cbd472012-06-19 16:25:45 -070015upload_prebuilts -p /b/cbuild/build -s -u gs://chromeos-prebuilt
David James8c846492011-01-25 17:07:29 -080016
17Example of uploading x86-dogfood binhosts to Google Storage:
David Jamesc5cbd472012-06-19 16:25:45 -070018upload_prebuilts -b x86-dogfood -p /b/cbuild/build/ -u gs://chromeos-prebuilt -g
David James8c846492011-01-25 17:07:29 -080019"""
20
Mike Frysingerff441bf2014-05-24 13:47:21 -040021from __future__ import print_function
22
Mike Frysingerb87bb782015-06-04 02:46:50 -040023import argparse
Chris Sosa1dc96132012-05-11 15:40:50 -070024import datetime
Mike Frysinger540883b2014-05-24 13:46:16 -040025import functools
David Jamesb26b9312014-12-15 11:26:46 -080026import glob
Chris Sosa1dc96132012-05-11 15:40:50 -070027import multiprocessing
Chris Sosa1dc96132012-05-11 15:40:50 -070028import os
Mike Frysinger72b7cf92020-04-19 06:00:51 -040029import sys
Mike Frysinger212e4292014-05-24 15:15:44 -040030import tempfile
Chris Sosa1dc96132012-05-11 15:40:50 -070031
Aviv Keshetb7519e12016-10-04 00:50:00 -070032from chromite.lib import constants
David James14e97772014-06-04 18:44:49 -070033from chromite.cbuildbot import commands
David James6450a0a2012-12-04 07:59:53 -080034from chromite.lib import binpkg
Mike Frysinger86509232014-05-24 13:18:37 -040035from chromite.lib import commandline
Chris Sosa1dc96132012-05-11 15:40:50 -070036from chromite.lib import cros_build_lib
Ralph Nathan446aee92015-03-23 14:44:56 -070037from chromite.lib import cros_logging as logging
David James97d95872012-11-16 15:09:56 -080038from chromite.lib import git
Brian Harring7904b482012-08-08 02:54:12 -070039from chromite.lib import gs
Brian Harringaf019fb2012-05-10 15:06:13 -070040from chromite.lib import osutils
David James6450a0a2012-12-04 07:59:53 -080041from chromite.lib import parallel
Alex Deymo075c2292014-09-04 18:31:50 -070042from chromite.lib import portage_util
Mike Frysinger8e727a32013-01-16 16:57:53 -050043from chromite.lib import toolchain
Chris Sosa1dc96132012-05-11 15:40:50 -070044
Mike Frysinger72b7cf92020-04-19 06:00:51 -040045
46assert sys.version_info >= (3, 6), 'This module requires Python 3.6+'
47
48
David James015af872012-06-19 15:24:36 -070049# How many times to retry uploads.
50_RETRIES = 10
51
52# Multiplier for how long to sleep (in seconds) between retries; will delay
53# (1*sleep) the first time, then (2*sleep), continuing via attempt * sleep.
54_SLEEP_TIME = 60
55
David James5ab67e32014-10-24 08:19:59 -070056# The length of time (in seconds) that Portage should wait before refetching
57# binpkgs from the same binhost. We don't ever modify binhosts, so this should
58# be something big.
59_BINPKG_TTL = 60 * 60 * 24 * 365
60
David James8c846492011-01-25 17:07:29 -080061_HOST_PACKAGES_PATH = 'chroot/var/lib/portage/pkgs'
David James05bcb2b2011-02-09 09:25:47 -080062_CATEGORIES_PATH = 'chroot/etc/portage/categories'
David James615e5b52011-06-03 11:10:15 -070063_PYM_PATH = 'chroot/usr/lib/portage/pym'
David James4058b0d2011-12-08 21:24:50 -080064_HOST_ARCH = 'amd64'
David James8c846492011-01-25 17:07:29 -080065_BOARD_PATH = 'chroot/build/%(board)s'
David James4058b0d2011-12-08 21:24:50 -080066_REL_BOARD_PATH = 'board/%(target)s/%(version)s'
67_REL_HOST_PATH = 'host/%(host_arch)s/%(target)s/%(version)s'
David James8c846492011-01-25 17:07:29 -080068# Private overlays to look at for builds to filter
69# relative to build path
70_PRIVATE_OVERLAY_DIR = 'src/private-overlays'
Gabe Black40169e62014-06-17 15:23:47 -070071_GOOGLESTORAGE_GSUTIL_FILE = 'googlestorage_acl.txt'
David James3753d942014-04-23 10:55:48 -070072_BINHOST_BASE_URL = 'gs://chromeos-prebuilt'
David James8c846492011-01-25 17:07:29 -080073_PREBUILT_BASE_DIR = 'src/third_party/chromiumos-overlay/chromeos/config/'
74# Created in the event of new host targets becoming available
75_PREBUILT_MAKE_CONF = {'amd64': os.path.join(_PREBUILT_BASE_DIR,
76 'make.conf.amd64-host')}
David James8c846492011-01-25 17:07:29 -080077
78
David James4058b0d2011-12-08 21:24:50 -080079class BuildTarget(object):
80 """A board/variant/profile tuple."""
81
82 def __init__(self, board_variant, profile=None):
83 self.board_variant = board_variant
84 self.board, _, self.variant = board_variant.partition('_')
85 self.profile = profile
86
87 def __str__(self):
88 if self.profile:
89 return '%s_%s' % (self.board_variant, self.profile)
90 else:
91 return self.board_variant
92
93 def __eq__(self, other):
94 return str(other) == str(self)
95
96 def __hash__(self):
97 return hash(str(self))
98
99
David James8c846492011-01-25 17:07:29 -0800100def UpdateLocalFile(filename, value, key='PORTAGE_BINHOST'):
101 """Update the key in file with the value passed.
Mike Frysinger1a736a82013-12-12 01:50:59 -0500102
David James8c846492011-01-25 17:07:29 -0800103 File format:
104 key="value"
105 Note quotes are added automatically
106
107 Args:
108 filename: Name of file to modify.
109 value: Value to write with the key.
110 key: The variable key to update. (Default: PORTAGE_BINHOST)
David Jamesb26b9312014-12-15 11:26:46 -0800111
112 Returns:
113 True if changes were made to the file.
David James8c846492011-01-25 17:07:29 -0800114 """
115 if os.path.exists(filename):
116 file_fh = open(filename)
117 else:
118 file_fh = open(filename, 'w+')
119 file_lines = []
120 found = False
David Jamesb26b9312014-12-15 11:26:46 -0800121 made_changes = False
David James8c846492011-01-25 17:07:29 -0800122 keyval_str = '%(key)s=%(value)s'
123 for line in file_fh:
124 # Strip newlines from end of line. We already add newlines below.
Mike Frysinger80de5012019-08-01 14:10:53 -0400125 line = line.rstrip('\n')
David James8c846492011-01-25 17:07:29 -0800126
127 if len(line.split('=')) != 2:
128 # Skip any line that doesn't fit key=val.
129 file_lines.append(line)
130 continue
131
132 file_var, file_val = line.split('=')
133 if file_var == key:
134 found = True
Mike Frysingerff441bf2014-05-24 13:47:21 -0400135 print('Updating %s=%s to %s="%s"' % (file_var, file_val, key, value))
David James8c846492011-01-25 17:07:29 -0800136 value = '"%s"' % value
David Jamesb26b9312014-12-15 11:26:46 -0800137 made_changes |= (file_val != value)
David James8c846492011-01-25 17:07:29 -0800138 file_lines.append(keyval_str % {'key': key, 'value': value})
139 else:
140 file_lines.append(keyval_str % {'key': file_var, 'value': file_val})
141
142 if not found:
Brian Harring2a014302012-05-12 00:53:33 -0700143 value = '"%s"' % value
David Jamesb26b9312014-12-15 11:26:46 -0800144 made_changes = True
David James8c846492011-01-25 17:07:29 -0800145 file_lines.append(keyval_str % {'key': key, 'value': value})
146
147 file_fh.close()
148 # write out new file
Brian Harringaf019fb2012-05-10 15:06:13 -0700149 osutils.WriteFile(filename, '\n'.join(file_lines) + '\n')
David Jamesb26b9312014-12-15 11:26:46 -0800150 return made_changes
David James8c846492011-01-25 17:07:29 -0800151
152
Mike Nicholsa6818c52018-04-09 11:05:42 -0600153def RevGitFile(filename, data, dryrun=False):
David James8c846492011-01-25 17:07:29 -0800154 """Update and push the git file.
155
Mike Frysinger5b34d732013-01-17 15:11:58 -0500156 Args:
157 filename: file to modify that is in a git repo already
158 data: A dict of key/values to update in |filename|
Matt Tennante8179042013-10-01 15:47:32 -0700159 dryrun: If True, do not actually commit the change.
David James8c846492011-01-25 17:07:29 -0800160 """
161 prebuilt_branch = 'prebuilt_branch'
David James1b6e67a2011-05-19 21:32:38 -0700162 cwd = os.path.abspath(os.path.dirname(filename))
David James97d95872012-11-16 15:09:56 -0800163 commit = git.RunGit(cwd, ['rev-parse', 'HEAD']).output.rstrip()
Mike Frysinger5b34d732013-01-17 15:11:58 -0500164 description = '%s: updating %s' % (os.path.basename(filename),
165 ', '.join(data.keys()))
166 # UpdateLocalFile will print out the keys/values for us.
Mike Frysingerff441bf2014-05-24 13:47:21 -0400167 print('Revving git file %s' % filename)
David James66009462012-03-25 10:08:38 -0700168
David James8c846492011-01-25 17:07:29 -0800169 try:
David James97d95872012-11-16 15:09:56 -0800170 git.CreatePushBranch(prebuilt_branch, cwd)
Mike Frysinger0bdbc102019-06-13 15:27:29 -0400171 for key, value in data.items():
Mike Frysinger5b34d732013-01-17 15:11:58 -0500172 UpdateLocalFile(filename, value, key)
David James97d95872012-11-16 15:09:56 -0800173 git.RunGit(cwd, ['add', filename])
174 git.RunGit(cwd, ['commit', '-m', description])
Dhanya Ganesh7efc3542019-02-22 10:11:52 -0700175 git.PushBranch(prebuilt_branch, cwd, dryrun=dryrun, auto_merge=True)
David James8c846492011-01-25 17:07:29 -0800176 finally:
Hidehiko Abecb26e282017-08-22 16:28:16 +0900177 # We reset the index and the working tree state in case there are any
178 # uncommitted or pending changes, but we don't change any existing commits.
179 git.RunGit(cwd, ['reset', '--hard'])
180
181 # Check out the last good commit as a sanity fallback.
David James67d73252013-09-19 17:33:12 -0700182 git.RunGit(cwd, ['checkout', commit])
David James8c846492011-01-25 17:07:29 -0800183
184
185def GetVersion():
186 """Get the version to put in LATEST and update the git version with."""
Mike Frysinger0b92cfe2012-12-13 02:13:45 -0500187 return datetime.datetime.now().strftime('%Y.%m.%d.%H%M%S')
David James8c846492011-01-25 17:07:29 -0800188
189
Mike Frysinger540883b2014-05-24 13:46:16 -0400190def _GsUpload(gs_context, acl, local_file, remote_file):
David James8c846492011-01-25 17:07:29 -0800191 """Upload to GS bucket.
192
193 Args:
Mike Frysinger540883b2014-05-24 13:46:16 -0400194 gs_context: A lib.gs.GSContext instance.
195 acl: The ACL to use for uploading the file.
Matt Tennante8179042013-10-01 15:47:32 -0700196 local_file: The local file to be uploaded.
197 remote_file: The remote location to upload to.
David James8c846492011-01-25 17:07:29 -0800198 """
Scott Zawalskiab1bed32011-03-16 15:24:24 -0700199 CANNED_ACLS = ['public-read', 'private', 'bucket-owner-read',
200 'authenticated-read', 'bucket-owner-full-control',
201 'public-read-write']
Scott Zawalskiab1bed32011-03-16 15:24:24 -0700202 if acl in CANNED_ACLS:
David James9374aac2013-10-08 16:00:17 -0700203 gs_context.Copy(local_file, remote_file, acl=acl)
Scott Zawalskiab1bed32011-03-16 15:24:24 -0700204 else:
205 # For private uploads we assume that the overlay board is set up properly
David James015af872012-06-19 15:24:36 -0700206 # and a googlestore_acl.xml is present. Otherwise, this script errors.
David James7b7d7c32015-04-02 13:48:17 -0700207 # We set version=0 here to ensure that the ACL is set only once (see
208 # http://b/15883752#comment54).
209 try:
210 gs_context.Copy(local_file, remote_file, version=0)
211 except gs.GSContextPreconditionFailed as ex:
212 # If we received a GSContextPreconditionFailed error, we know that the
213 # file exists now, but we don't know whether our specific update
214 # succeeded. See http://b/15883752#comment62
215 logging.warning(
216 'Assuming upload succeeded despite PreconditionFailed errors: %s', ex)
217
Gabe Black40169e62014-06-17 15:23:47 -0700218 if acl.endswith('.xml'):
219 # Apply the passed in ACL xml file to the uploaded object.
220 gs_context.SetACL(remote_file, acl=acl)
221 else:
Mike Frysinger5186f262017-09-13 10:26:19 -0400222 gs_context.ChangeACL(remote_file, acl_args_file=acl)
Scott Zawalskiab1bed32011-03-16 15:24:24 -0700223
Mike Frysingercc838832014-05-24 13:10:30 -0400224
Mike Frysinger540883b2014-05-24 13:46:16 -0400225def RemoteUpload(gs_context, acl, files, pool=10):
David James8c846492011-01-25 17:07:29 -0800226 """Upload to google storage.
227
228 Create a pool of process and call _GsUpload with the proper arguments.
229
230 Args:
Mike Frysinger540883b2014-05-24 13:46:16 -0400231 gs_context: A lib.gs.GSContext instance.
David Jamesfd0b0852011-02-23 11:15:36 -0800232 acl: The canned acl used for uploading. acl can be one of: "public-read",
233 "public-read-write", "authenticated-read", "bucket-owner-read",
234 "bucket-owner-full-control", or "private".
David James8c846492011-01-25 17:07:29 -0800235 files: dictionary with keys to local files and values to remote path.
236 pool: integer of maximum proesses to have at the same time.
237
238 Returns:
239 Return a set of tuple arguments of the failed uploads
240 """
Mike Frysinger540883b2014-05-24 13:46:16 -0400241 upload = functools.partial(_GsUpload, gs_context, acl)
Mike Frysinger0bdbc102019-06-13 15:27:29 -0400242 tasks = [[key, value] for key, value in files.items()]
Mike Frysinger540883b2014-05-24 13:46:16 -0400243 parallel.RunTasksInProcessPool(upload, tasks, pool)
David James8c846492011-01-25 17:07:29 -0800244
245
246def GenerateUploadDict(base_local_path, base_remote_path, pkgs):
247 """Build a dictionary of local remote file key pairs to upload.
248
249 Args:
250 base_local_path: The base path to the files on the local hard drive.
Matt Tennante8179042013-10-01 15:47:32 -0700251 base_remote_path: The base path to the remote paths.
David James8c846492011-01-25 17:07:29 -0800252 pkgs: The packages to upload.
253
254 Returns:
255 Returns a dictionary of local_path/remote_path pairs
256 """
257 upload_files = {}
258 for pkg in pkgs:
259 suffix = pkg['CPV'] + '.tbz2'
260 local_path = os.path.join(base_local_path, suffix)
David James7b7d7c32015-04-02 13:48:17 -0700261 assert os.path.exists(local_path), '%s does not exist' % local_path
Bertrand SIMONNET811bcde2014-11-20 15:21:25 -0800262 upload_files[local_path] = os.path.join(base_remote_path, suffix)
David James8c846492011-01-25 17:07:29 -0800263
Bertrand SIMONNET811bcde2014-11-20 15:21:25 -0800264 if pkg.get('DEBUG_SYMBOLS') == 'yes':
265 debugsuffix = pkg['CPV'] + '.debug.tbz2'
266 local_path = os.path.join(base_local_path, debugsuffix)
267 assert os.path.exists(local_path)
268 upload_files[local_path] = os.path.join(base_remote_path, debugsuffix)
Bertrand SIMONNET22e828b2014-11-11 16:27:06 -0800269
David James8c846492011-01-25 17:07:29 -0800270 return upload_files
271
Mike Frysingercc838832014-05-24 13:10:30 -0400272
Peter Mayo950e41a2014-02-06 21:07:33 +0000273def GetBoardOverlay(build_path, target):
David Jamese5867812012-10-19 12:02:20 -0700274 """Get the path to the board variant.
Mike Frysinger1a736a82013-12-12 01:50:59 -0500275
Mike Frysinger6f3c48e2015-05-06 02:38:51 -0400276 Args:
277 build_path: The path to the root of the build directory
278 target: The target board as a BuildTarget object.
Mike Frysinger1a736a82013-12-12 01:50:59 -0500279
Mike Frysinger6f3c48e2015-05-06 02:38:51 -0400280 Returns:
281 The last overlay configured for the given board as a string.
David James8c846492011-01-25 17:07:29 -0800282 """
David Jamese5867812012-10-19 12:02:20 -0700283 board = target.board_variant
Alex Deymo075c2292014-09-04 18:31:50 -0700284 overlays = portage_util.FindOverlays(constants.BOTH_OVERLAYS, board,
285 buildroot=build_path)
David Jamese5867812012-10-19 12:02:20 -0700286 # We only care about the last entry.
287 return overlays[-1]
David James8c846492011-01-25 17:07:29 -0800288
289
290def DeterminePrebuiltConfFile(build_path, target):
291 """Determine the prebuilt.conf file that needs to be updated for prebuilts.
292
Mike Frysinger1a736a82013-12-12 01:50:59 -0500293 Args:
294 build_path: The path to the root of the build directory
295 target: String representation of the board. This includes host and board
296 targets
David James8c846492011-01-25 17:07:29 -0800297
Mike Frysinger1a736a82013-12-12 01:50:59 -0500298 Returns:
299 A string path to a prebuilt.conf file to be updated.
David James8c846492011-01-25 17:07:29 -0800300 """
David James4058b0d2011-12-08 21:24:50 -0800301 if _HOST_ARCH == target:
David James8c846492011-01-25 17:07:29 -0800302 # We are host.
303 # Without more examples of hosts this is a kludge for now.
304 # TODO(Scottz): as new host targets come online expand this to
305 # work more like boards.
Chris Sosa471532a2011-02-01 15:10:06 -0800306 make_path = _PREBUILT_MAKE_CONF[target]
David James8c846492011-01-25 17:07:29 -0800307 else:
308 # We are a board
Peter Mayo950e41a2014-02-06 21:07:33 +0000309 board = GetBoardOverlay(build_path, target)
David James8c846492011-01-25 17:07:29 -0800310 make_path = os.path.join(board, 'prebuilt.conf')
311
312 return make_path
313
314
315def UpdateBinhostConfFile(path, key, value):
316 """Update binhost config file file with key=value.
317
318 Args:
319 path: Filename to update.
320 key: Key to update.
321 value: New value for key.
322 """
David Jamesb26b9312014-12-15 11:26:46 -0800323 cwd, filename = os.path.split(os.path.abspath(path))
Brian Harringaf019fb2012-05-10 15:06:13 -0700324 osutils.SafeMakedirs(cwd)
David Jamesf6e8fb72013-05-10 08:58:43 -0700325 if not git.GetCurrentBranch(cwd):
326 git.CreatePushBranch(constants.STABLE_EBUILD_BRANCH, cwd, sync=False)
Brian Harring22edb442012-05-11 23:55:18 -0700327 osutils.WriteFile(path, '', mode='a')
David Jamesb26b9312014-12-15 11:26:46 -0800328 if UpdateLocalFile(path, value, key):
329 desc = '%s: %s %s' % (filename, 'updating' if value else 'clearing', key)
330 git.AddPath(path)
331 git.Commit(cwd, desc)
David James8c846492011-01-25 17:07:29 -0800332
Achuith Bhandarkar03d924a2018-01-02 10:50:44 -0800333def GenerateHtmlIndex(files, index, board, version, remote_location):
Mike Frysinger212e4292014-05-24 15:15:44 -0400334 """Given the list of |files|, generate an index.html at |index|.
335
336 Args:
337 files: The list of files to link to.
338 index: The path to the html index.
339 board: Name of the board this index is for.
340 version: Build version this index is for.
Achuith Bhandarkar03d924a2018-01-02 10:50:44 -0800341 remote_location: Remote gs location prebuilts are uploaded to.
Mike Frysinger212e4292014-05-24 15:15:44 -0400342 """
Don Garrett13cbbff2016-08-09 14:18:38 -0700343 title = 'Package Prebuilt Index: %s / %s' % (board, version)
Mike Frysinger212e4292014-05-24 15:15:44 -0400344
345 files = files + [
346 '.|Google Storage Index',
347 '..|',
348 ]
Achuith Bhandarkar03d924a2018-01-02 10:50:44 -0800349 commands.GenerateHtmlIndex(index, files, title=title,
350 url_base=gs.GsUrlToHttp(remote_location))
Mike Frysinger212e4292014-05-24 15:15:44 -0400351
352
David Jamesce093af2011-02-23 15:21:58 -0800353def _GrabAllRemotePackageIndexes(binhost_urls):
David James05bcb2b2011-02-09 09:25:47 -0800354 """Grab all of the packages files associated with a list of binhost_urls.
355
David James05bcb2b2011-02-09 09:25:47 -0800356 Args:
357 binhost_urls: The URLs for the directories containing the Packages files we
358 want to grab.
David James05bcb2b2011-02-09 09:25:47 -0800359
360 Returns:
361 A list of PackageIndex objects.
362 """
363 pkg_indexes = []
364 for url in binhost_urls:
David James32faafe2012-06-08 14:25:03 -0700365 pkg_index = binpkg.GrabRemotePackageIndex(url)
David James05bcb2b2011-02-09 09:25:47 -0800366 if pkg_index:
367 pkg_indexes.append(pkg_index)
David James05bcb2b2011-02-09 09:25:47 -0800368 return pkg_indexes
369
370
David Jamesc0f158a2011-02-22 16:07:29 -0800371class PrebuiltUploader(object):
372 """Synchronize host and board prebuilts."""
David James8c846492011-01-25 17:07:29 -0800373
Mike Frysinger86509232014-05-24 13:18:37 -0400374 def __init__(self, upload_location, acl, binhost_base_url, pkg_indexes,
375 build_path, packages, skip_upload, binhost_conf_dir, dryrun,
Mike Frysinger8092a632014-05-24 13:25:46 -0400376 target, slave_targets, version):
David Jamesc0f158a2011-02-22 16:07:29 -0800377 """Constructor for prebuilt uploader object.
David James8c846492011-01-25 17:07:29 -0800378
David Jamesc0f158a2011-02-22 16:07:29 -0800379 This object can upload host or prebuilt files to Google Storage.
David James8c846492011-01-25 17:07:29 -0800380
David Jamesc0f158a2011-02-22 16:07:29 -0800381 Args:
382 upload_location: The upload location.
David Jamesfd0b0852011-02-23 11:15:36 -0800383 acl: The canned acl used for uploading to Google Storage. acl can be one
384 of: "public-read", "public-read-write", "authenticated-read",
Matt Tennante8179042013-10-01 15:47:32 -0700385 "bucket-owner-read", "bucket-owner-full-control", "project-private",
386 or "private" (see "gsutil help acls"). If we are not uploading to
387 Google Storage, this parameter is unused.
David Jamesfd0b0852011-02-23 11:15:36 -0800388 binhost_base_url: The URL used for downloading the prebuilts.
David Jamesc0f158a2011-02-22 16:07:29 -0800389 pkg_indexes: Old uploaded prebuilts to compare against. Instead of
390 uploading duplicate files, we just link to the old files.
David James615e5b52011-06-03 11:10:15 -0700391 build_path: The path to the directory containing the chroot.
392 packages: Packages to upload.
David James32b0b2f2011-07-13 20:56:50 -0700393 skip_upload: Don't actually upload the tarballs.
394 binhost_conf_dir: Directory where to store binhost.conf files.
Mike Frysinger86509232014-05-24 13:18:37 -0400395 dryrun: Don't push or upload prebuilts.
David James4058b0d2011-12-08 21:24:50 -0800396 target: BuildTarget managed by this builder.
397 slave_targets: List of BuildTargets managed by slave builders.
Mike Frysinger8092a632014-05-24 13:25:46 -0400398 version: A unique string, intended to be included in the upload path,
399 which identifies the version number of the uploaded prebuilts.
David Jamesc0f158a2011-02-22 16:07:29 -0800400 """
401 self._upload_location = upload_location
David Jamesfd0b0852011-02-23 11:15:36 -0800402 self._acl = acl
David Jamesc0f158a2011-02-22 16:07:29 -0800403 self._binhost_base_url = binhost_base_url
404 self._pkg_indexes = pkg_indexes
David James615e5b52011-06-03 11:10:15 -0700405 self._build_path = build_path
406 self._packages = set(packages)
Mike Frysingerf5f809a2013-02-12 13:47:37 -0500407 self._found_packages = set()
David James8ece7ee2011-06-29 16:02:30 -0700408 self._skip_upload = skip_upload
David James32b0b2f2011-07-13 20:56:50 -0700409 self._binhost_conf_dir = binhost_conf_dir
Mike Frysinger86509232014-05-24 13:18:37 -0400410 self._dryrun = dryrun
David James4058b0d2011-12-08 21:24:50 -0800411 self._target = target
412 self._slave_targets = slave_targets
Mike Frysinger8092a632014-05-24 13:25:46 -0400413 self._version = version
Mike Frysinger540883b2014-05-24 13:46:16 -0400414 self._gs_context = gs.GSContext(retries=_RETRIES, sleep=_SLEEP_TIME,
415 dry_run=self._dryrun)
416
417 def _Upload(self, local_file, remote_file):
418 """Wrapper around _GsUpload"""
419 _GsUpload(self._gs_context, self._acl, local_file, remote_file)
David James615e5b52011-06-03 11:10:15 -0700420
421 def _ShouldFilterPackage(self, pkg):
422 if not self._packages:
423 return False
Mike Frysinger87b592f2017-09-22 16:18:35 -0400424 cpv = portage_util.SplitCPV(pkg['CPV'])
Alex Klein9f93b482018-10-01 09:26:51 -0600425 self._found_packages.add(cpv.cp)
426 return cpv.package not in self._packages and cpv.cp not in self._packages
David James8c846492011-01-25 17:07:29 -0800427
David Jamesc0f158a2011-02-22 16:07:29 -0800428 def _UploadPrebuilt(self, package_path, url_suffix):
429 """Upload host or board prebuilt files to Google Storage space.
David James8c846492011-01-25 17:07:29 -0800430
David Jamesc0f158a2011-02-22 16:07:29 -0800431 Args:
432 package_path: The path to the packages dir.
David Jamesce093af2011-02-23 15:21:58 -0800433 url_suffix: The remote subdirectory where we should upload the packages.
David Jamesc0f158a2011-02-22 16:07:29 -0800434 """
David Jamesc0f158a2011-02-22 16:07:29 -0800435 # Process Packages file, removing duplicates and filtered packages.
David James32faafe2012-06-08 14:25:03 -0700436 pkg_index = binpkg.GrabLocalPackageIndex(package_path)
David Jamesc0f158a2011-02-22 16:07:29 -0800437 pkg_index.SetUploadLocation(self._binhost_base_url, url_suffix)
David James615e5b52011-06-03 11:10:15 -0700438 pkg_index.RemoveFilteredPackages(self._ShouldFilterPackage)
David Jamesc0f158a2011-02-22 16:07:29 -0800439 uploads = pkg_index.ResolveDuplicateUploads(self._pkg_indexes)
Mike Frysingerf5f809a2013-02-12 13:47:37 -0500440 unmatched_pkgs = self._packages - self._found_packages
441 if unmatched_pkgs:
Lann Martinffb95162018-08-28 12:02:54 -0600442 logging.warning('unable to match packages: %r', unmatched_pkgs)
David James05bcb2b2011-02-09 09:25:47 -0800443
David Jamesc0f158a2011-02-22 16:07:29 -0800444 # Write Packages file.
David James5ab67e32014-10-24 08:19:59 -0700445 pkg_index.header['TTL'] = _BINPKG_TTL
David Jamesc0f158a2011-02-22 16:07:29 -0800446 tmp_packages_file = pkg_index.WriteToNamedTemporaryFile()
David James05bcb2b2011-02-09 09:25:47 -0800447
David Jamesc0f158a2011-02-22 16:07:29 -0800448 remote_location = '%s/%s' % (self._upload_location.rstrip('/'), url_suffix)
David James015af872012-06-19 15:24:36 -0700449 assert remote_location.startswith('gs://')
David James05bcb2b2011-02-09 09:25:47 -0800450
Alex Deymo541ea6f2014-12-23 01:18:14 -0800451 # Build list of files to upload. Manually include the dev-only files but
452 # skip them if not present.
453 # TODO(deymo): Upload dev-only-extras.tbz2 as dev-only-extras.tar.bz2
454 # outside packages/ directory. See crbug.com/448178 for details.
455 if os.path.exists(os.path.join(package_path, 'dev-only-extras.tbz2')):
456 uploads.append({'CPV': 'dev-only-extras'})
David James015af872012-06-19 15:24:36 -0700457 upload_files = GenerateUploadDict(package_path, remote_location, uploads)
458 remote_file = '%s/Packages' % remote_location.rstrip('/')
459 upload_files[tmp_packages_file.name] = remote_file
460
Mike Frysinger540883b2014-05-24 13:46:16 -0400461 RemoteUpload(self._gs_context, self._acl, upload_files)
David James8c846492011-01-25 17:07:29 -0800462
Mike Frysinger212e4292014-05-24 15:15:44 -0400463 with tempfile.NamedTemporaryFile(
464 prefix='chromite.upload_prebuilts.index.') as index:
465 GenerateHtmlIndex(
466 [x[len(remote_location) + 1:] for x in upload_files.values()],
Achuith Bhandarkar03d924a2018-01-02 10:50:44 -0800467 index.name, self._target, self._version, remote_location)
Mike Frysinger212e4292014-05-24 15:15:44 -0400468 self._Upload(index.name, '%s/index.html' % remote_location.rstrip('/'))
469
470 link_name = 'Prebuilts[%s]: %s' % (self._target, self._version)
471 url = '%s%s/index.html' % (gs.PUBLIC_BASE_HTTPS_URL,
472 remote_location[len(gs.BASE_GS_URL):])
Prathmesh Prabhu17f07422015-07-17 11:40:40 -0700473 logging.PrintBuildbotLink(link_name, url)
Mike Frysinger212e4292014-05-24 15:15:44 -0400474
Mike Frysinger8092a632014-05-24 13:25:46 -0400475 def _UploadSdkTarball(self, board_path, url_suffix, prepackaged,
Gilad Arnold2b79e2d2015-06-02 11:26:07 -0700476 toolchains_overlay_tarballs,
477 toolchains_overlay_upload_path,
Mike Frysinger9e979b92012-11-29 02:55:09 -0500478 toolchain_tarballs, toolchain_upload_path):
479 """Upload a tarball of the sdk at the specified path to Google Storage.
David James8fa34ea2011-04-15 13:00:20 -0700480
481 Args:
482 board_path: The path to the board dir.
483 url_suffix: The remote subdirectory where we should upload the packages.
Zdenek Behan62a57792012-08-31 15:09:08 +0200484 prepackaged: If given, a tarball that has been packaged outside of this
485 script and should be used.
Gilad Arnold2b79e2d2015-06-02 11:26:07 -0700486 toolchains_overlay_tarballs: List of toolchains overlay tarball
487 specifications to upload. Items take the form
488 "toolchains_spec:/path/to/tarball".
489 toolchains_overlay_upload_path: Path template under the bucket to place
490 toolchains overlay tarballs.
Mike Frysinger9e979b92012-11-29 02:55:09 -0500491 toolchain_tarballs: List of toolchain tarballs to upload.
492 toolchain_upload_path: Path under the bucket to place toolchain tarballs.
David James8fa34ea2011-04-15 13:00:20 -0700493 """
494 remote_location = '%s/%s' % (self._upload_location.rstrip('/'), url_suffix)
495 assert remote_location.startswith('gs://')
Zdenek Behan86c15e92012-10-13 00:55:47 +0200496 boardname = os.path.basename(board_path.rstrip('/'))
497 # We do not upload non SDK board tarballs,
498 assert boardname == constants.CHROOT_BUILDER_BOARD
499 assert prepackaged is not None
Zdenek Behan62a57792012-08-31 15:09:08 +0200500
Mike Frysinger8092a632014-05-24 13:25:46 -0400501 version_str = self._version[len('chroot-'):]
Mike Frysinger8e727a32013-01-16 16:57:53 -0500502 remote_tarfile = toolchain.GetSdkURL(
503 for_gsutil=True, suburl='cros-sdk-%s.tar.xz' % (version_str,))
Zdenek Behan86c15e92012-10-13 00:55:47 +0200504 # For SDK, also upload the manifest which is guaranteed to exist
505 # by the builderstage.
Mike Frysinger540883b2014-05-24 13:46:16 -0400506 self._Upload(prepackaged + '.Manifest', remote_tarfile + '.Manifest')
507 self._Upload(prepackaged, remote_tarfile)
Zdenek Behan86c15e92012-10-13 00:55:47 +0200508
Gilad Arnold2b79e2d2015-06-02 11:26:07 -0700509 # Upload SDK toolchains overlays and toolchain tarballs, if given.
Gilad Arnoldad333182015-05-27 15:50:41 -0700510 for tarball_list, upload_path, qualifier_name in (
Gilad Arnold2b79e2d2015-06-02 11:26:07 -0700511 (toolchains_overlay_tarballs, toolchains_overlay_upload_path,
512 'toolchains'),
Gilad Arnoldad333182015-05-27 15:50:41 -0700513 (toolchain_tarballs, toolchain_upload_path, 'target')):
Gilad Arnold2b79e2d2015-06-02 11:26:07 -0700514 for tarball_spec in tarball_list:
515 qualifier_val, local_path = tarball_spec.split(':')
Gilad Arnoldad333182015-05-27 15:50:41 -0700516 suburl = upload_path % {qualifier_name: qualifier_val}
517 remote_path = toolchain.GetSdkURL(for_gsutil=True, suburl=suburl)
518 self._Upload(local_path, remote_path)
Mike Frysinger9e979b92012-11-29 02:55:09 -0500519
Zdenek Behan86c15e92012-10-13 00:55:47 +0200520 # Finally, also update the pointer to the latest SDK on which polling
521 # scripts rely.
David James4bc13702013-03-26 08:08:04 -0700522 with osutils.TempDir() as tmpdir:
Zdenek Behan86c15e92012-10-13 00:55:47 +0200523 pointerfile = os.path.join(tmpdir, 'cros-sdk-latest.conf')
Mike Frysinger8e727a32013-01-16 16:57:53 -0500524 remote_pointerfile = toolchain.GetSdkURL(for_gsutil=True,
525 suburl='cros-sdk-latest.conf')
Zdenek Behan86c15e92012-10-13 00:55:47 +0200526 osutils.WriteFile(pointerfile, 'LATEST_SDK="%s"' % version_str)
Mike Frysinger540883b2014-05-24 13:46:16 -0400527 self._Upload(pointerfile, remote_pointerfile)
Zdenek Behan33a34112012-09-10 21:07:51 +0200528
Chris Sosa6a5dceb2012-05-14 13:48:56 -0700529 def _GetTargets(self):
530 """Retuns the list of targets to use."""
531 targets = self._slave_targets[:]
532 if self._target:
533 targets.append(self._target)
534
535 return targets
536
Mike Frysinger8092a632014-05-24 13:25:46 -0400537 def SyncHostPrebuilts(self, key, git_sync, sync_binhost_conf):
David Jamesc0f158a2011-02-22 16:07:29 -0800538 """Synchronize host prebuilt files.
David James05bcb2b2011-02-09 09:25:47 -0800539
David Jamesc0f158a2011-02-22 16:07:29 -0800540 This function will sync both the standard host packages, plus the host
541 packages associated with all targets that have been "setup" with the
542 current host's chroot. For instance, if this host has been used to build
543 x86-generic, it will sync the host packages associated with
544 'i686-pc-linux-gnu'. If this host has also been used to build arm-generic,
545 it will also sync the host packages associated with
546 'armv7a-cros-linux-gnueabi'.
David James05bcb2b2011-02-09 09:25:47 -0800547
David Jamesc0f158a2011-02-22 16:07:29 -0800548 Args:
David Jamesc0f158a2011-02-22 16:07:29 -0800549 key: The variable key to update in the git file.
550 git_sync: If set, update make.conf of target to reference the latest
551 prebuilt packages generated here.
552 sync_binhost_conf: If set, update binhost config file in
553 chromiumos-overlay for the host.
554 """
David Jamese2488642011-11-14 16:15:20 -0800555 # Slave boards are listed before the master board so that the master board
556 # takes priority (i.e. x86-generic preflight host prebuilts takes priority
557 # over preflight host prebuilts from other builders.)
558 binhost_urls = []
Chris Sosa6a5dceb2012-05-14 13:48:56 -0700559 for target in self._GetTargets():
Mike Frysinger8092a632014-05-24 13:25:46 -0400560 url_suffix = _REL_HOST_PATH % {'version': self._version,
David James4058b0d2011-12-08 21:24:50 -0800561 'host_arch': _HOST_ARCH,
562 'target': target}
David Jamese2488642011-11-14 16:15:20 -0800563 packages_url_suffix = '%s/packages' % url_suffix.rstrip('/')
David James05bcb2b2011-02-09 09:25:47 -0800564
Mike Frysinger540883b2014-05-24 13:46:16 -0400565 if self._target == target and not self._skip_upload:
David Jamese2488642011-11-14 16:15:20 -0800566 # Upload prebuilts.
567 package_path = os.path.join(self._build_path, _HOST_PACKAGES_PATH)
568 self._UploadPrebuilt(package_path, packages_url_suffix)
David James8ece7ee2011-06-29 16:02:30 -0700569
David Jamese2488642011-11-14 16:15:20 -0800570 # Record URL where prebuilts were uploaded.
571 binhost_urls.append('%s/%s/' % (self._binhost_base_url.rstrip('/'),
572 packages_url_suffix.rstrip('/')))
573
David James20b2b6f2011-11-18 15:11:58 -0800574 binhost = ' '.join(binhost_urls)
David James8ece7ee2011-06-29 16:02:30 -0700575 if git_sync:
David Jamesb26b9312014-12-15 11:26:46 -0800576 git_file = os.path.join(self._build_path, _PREBUILT_MAKE_CONF[_HOST_ARCH])
Mike Frysinger86509232014-05-24 13:18:37 -0400577 RevGitFile(git_file, {key: binhost}, dryrun=self._dryrun)
David James8ece7ee2011-06-29 16:02:30 -0700578 if sync_binhost_conf:
David Jamesb26b9312014-12-15 11:26:46 -0800579 binhost_conf = os.path.join(
580 self._binhost_conf_dir, 'host', '%s-%s.conf' % (_HOST_ARCH, key))
David Jamese2488642011-11-14 16:15:20 -0800581 UpdateBinhostConfFile(binhost_conf, key, binhost)
David Jamesc0f158a2011-02-22 16:07:29 -0800582
Mike Frysinger8092a632014-05-24 13:25:46 -0400583 def SyncBoardPrebuilts(self, key, git_sync, sync_binhost_conf,
Mike Frysinger9e979b92012-11-29 02:55:09 -0500584 upload_board_tarball, prepackaged_board,
Gilad Arnold2b79e2d2015-06-02 11:26:07 -0700585 toolchains_overlay_tarballs,
586 toolchains_overlay_upload_path,
Mike Frysinger9e979b92012-11-29 02:55:09 -0500587 toolchain_tarballs, toolchain_upload_path):
David Jamesc0f158a2011-02-22 16:07:29 -0800588 """Synchronize board prebuilt files.
589
590 Args:
David Jamesc0f158a2011-02-22 16:07:29 -0800591 key: The variable key to update in the git file.
592 git_sync: If set, update make.conf of target to reference the latest
593 prebuilt packages generated here.
594 sync_binhost_conf: If set, update binhost config file in
595 chromiumos-overlay for the current board.
David James8fa34ea2011-04-15 13:00:20 -0700596 upload_board_tarball: Include a tarball of the board in our upload.
Zdenek Behan62a57792012-08-31 15:09:08 +0200597 prepackaged_board: A tarball of the board built outside of this script.
Gilad Arnold2b79e2d2015-06-02 11:26:07 -0700598 toolchains_overlay_tarballs: List of toolchains overlay tarball
599 specifications to upload. Items take the form
600 "toolchains_spec:/path/to/tarball".
601 toolchains_overlay_upload_path: Path template under the bucket to place
602 toolchains overlay tarballs.
Mike Frysinger9e979b92012-11-29 02:55:09 -0500603 toolchain_tarballs: A list of toolchain tarballs to upload.
604 toolchain_upload_path: Path under the bucket to place toolchain tarballs.
David Jamesc0f158a2011-02-22 16:07:29 -0800605 """
David Jamesb26b9312014-12-15 11:26:46 -0800606 updated_binhosts = set()
Chris Sosa6a5dceb2012-05-14 13:48:56 -0700607 for target in self._GetTargets():
David Jamese2488642011-11-14 16:15:20 -0800608 board_path = os.path.join(self._build_path,
David James4058b0d2011-12-08 21:24:50 -0800609 _BOARD_PATH % {'board': target.board_variant})
David Jamese2488642011-11-14 16:15:20 -0800610 package_path = os.path.join(board_path, 'packages')
Mike Frysinger8092a632014-05-24 13:25:46 -0400611 url_suffix = _REL_BOARD_PATH % {'target': target,
612 'version': self._version}
David Jamese2488642011-11-14 16:15:20 -0800613 packages_url_suffix = '%s/packages' % url_suffix.rstrip('/')
David James8fa34ea2011-04-15 13:00:20 -0700614
Matt Tennante8179042013-10-01 15:47:32 -0700615 # Process the target board differently if it is the main --board.
Mike Frysinger540883b2014-05-24 13:46:16 -0400616 if self._target == target and not self._skip_upload:
Matt Tennante8179042013-10-01 15:47:32 -0700617 # This strips "chroot" prefix because that is sometimes added as the
618 # --prepend-version argument (e.g. by chromiumos-sdk bot).
619 # TODO(build): Clean it up to be less hard-coded.
Mike Frysinger8092a632014-05-24 13:25:46 -0400620 version_str = self._version[len('chroot-'):]
Mike Frysinger9e979b92012-11-29 02:55:09 -0500621
David Jamese2488642011-11-14 16:15:20 -0800622 # Upload board tarballs in the background.
623 if upload_board_tarball:
Mike Frysinger9e979b92012-11-29 02:55:09 -0500624 if toolchain_upload_path:
625 toolchain_upload_path %= {'version': version_str}
Gilad Arnold2b79e2d2015-06-02 11:26:07 -0700626 if toolchains_overlay_upload_path:
627 toolchains_overlay_upload_path %= {'version': version_str}
Mike Frysinger9e979b92012-11-29 02:55:09 -0500628 tar_process = multiprocessing.Process(
629 target=self._UploadSdkTarball,
Mike Frysinger8092a632014-05-24 13:25:46 -0400630 args=(board_path, url_suffix, prepackaged_board,
Gilad Arnold2b79e2d2015-06-02 11:26:07 -0700631 toolchains_overlay_tarballs,
632 toolchains_overlay_upload_path, toolchain_tarballs,
633 toolchain_upload_path))
David Jamese2488642011-11-14 16:15:20 -0800634 tar_process.start()
David James8fa34ea2011-04-15 13:00:20 -0700635
David Jamese2488642011-11-14 16:15:20 -0800636 # Upload prebuilts.
637 self._UploadPrebuilt(package_path, packages_url_suffix)
David James8fa34ea2011-04-15 13:00:20 -0700638
David Jamese2488642011-11-14 16:15:20 -0800639 # Make sure we finished uploading the board tarballs.
640 if upload_board_tarball:
641 tar_process.join()
642 assert tar_process.exitcode == 0
David Jamesc0f158a2011-02-22 16:07:29 -0800643
David Jamese2488642011-11-14 16:15:20 -0800644 # Record URL where prebuilts were uploaded.
645 url_value = '%s/%s/' % (self._binhost_base_url.rstrip('/'),
646 packages_url_suffix.rstrip('/'))
647
648 if git_sync:
David James4058b0d2011-12-08 21:24:50 -0800649 git_file = DeterminePrebuiltConfFile(self._build_path, target)
Mike Frysinger86509232014-05-24 13:18:37 -0400650 RevGitFile(git_file, {key: url_value}, dryrun=self._dryrun)
Matt Tennante8179042013-10-01 15:47:32 -0700651
David Jamese2488642011-11-14 16:15:20 -0800652 if sync_binhost_conf:
Matt Tennante8179042013-10-01 15:47:32 -0700653 # Update the binhost configuration file in git.
David Jamesb26b9312014-12-15 11:26:46 -0800654 binhost_conf = os.path.join(
655 self._binhost_conf_dir, 'target', '%s-%s.conf' % (target, key))
656 updated_binhosts.add(binhost_conf)
David Jamese2488642011-11-14 16:15:20 -0800657 UpdateBinhostConfFile(binhost_conf, key, url_value)
David James05bcb2b2011-02-09 09:25:47 -0800658
David Jamesb26b9312014-12-15 11:26:46 -0800659 if sync_binhost_conf:
660 # Clear all old binhosts. The files must be left empty in case anybody
661 # is referring to them.
662 all_binhosts = set(glob.glob(os.path.join(
663 self._binhost_conf_dir, 'target', '*-%s.conf' % key)))
664 for binhost_conf in all_binhosts - updated_binhosts:
665 UpdateBinhostConfFile(binhost_conf, key, '')
666
David James05bcb2b2011-02-09 09:25:47 -0800667
Mike Frysingerb87bb782015-06-04 02:46:50 -0400668class _AddSlaveBoardAction(argparse.Action):
Chris Sosa6a5dceb2012-05-14 13:48:56 -0700669 """Callback that adds a slave board to the list of slave targets."""
Mike Frysingerb87bb782015-06-04 02:46:50 -0400670 def __call__(self, parser, namespace, values, option_string=None):
671 getattr(namespace, self.dest).append(BuildTarget(values))
David James4058b0d2011-12-08 21:24:50 -0800672
673
Mike Frysingerb87bb782015-06-04 02:46:50 -0400674class _AddSlaveProfileAction(argparse.Action):
Chris Sosa6a5dceb2012-05-14 13:48:56 -0700675 """Callback that adds a slave profile to the list of slave targets."""
Mike Frysingerb87bb782015-06-04 02:46:50 -0400676 def __call__(self, parser, namespace, values, option_string=None):
677 if not namespace.slave_targets:
678 parser.error('Must specify --slave-board before --slave-profile')
679 if namespace.slave_targets[-1].profile is not None:
680 parser.error('Cannot specify --slave-profile twice for same board')
681 namespace.slave_targets[-1].profile = values
David James4058b0d2011-12-08 21:24:50 -0800682
683
Mike Frysinger86509232014-05-24 13:18:37 -0400684def ParseOptions(argv):
Chris Sosa6a5dceb2012-05-14 13:48:56 -0700685 """Returns options given by the user and the target specified.
686
Mike Frysinger86509232014-05-24 13:18:37 -0400687 Args:
688 argv: The args to parse.
689
Mike Frysinger1a736a82013-12-12 01:50:59 -0500690 Returns:
691 A tuple containing a parsed options object and BuildTarget.
692 The target instance is None if no board is specified.
Chris Sosa6a5dceb2012-05-14 13:48:56 -0700693 """
Mike Frysingerb87bb782015-06-04 02:46:50 -0400694 parser = commandline.ArgumentParser()
695 parser.add_argument('-H', '--binhost-base-url', default=_BINHOST_BASE_URL,
696 help='Base URL to use for binhost in make.conf updates')
697 parser.add_argument('--previous-binhost-url', action='append', default=[],
698 help='Previous binhost URL')
699 parser.add_argument('-b', '--board',
700 help='Board type that was built on this machine')
701 parser.add_argument('-B', '--prepackaged-tarball', type='path',
702 help='Board tarball prebuilt outside of this script.')
Gilad Arnold2b79e2d2015-06-02 11:26:07 -0700703 parser.add_argument('--toolchains-overlay-tarball',
704 dest='toolchains_overlay_tarballs',
Mike Frysingerb87bb782015-06-04 02:46:50 -0400705 action='append', default=[],
Gilad Arnold2b79e2d2015-06-02 11:26:07 -0700706 help='Toolchains overlay tarball specification to '
707 'upload. Takes the form '
708 '"toolchains_spec:/path/to/tarball".')
709 parser.add_argument('--toolchains-overlay-upload-path', default='',
710 help='Path template for uploading toolchains overlays.')
Mike Frysingerb87bb782015-06-04 02:46:50 -0400711 parser.add_argument('--toolchain-tarball', dest='toolchain_tarballs',
712 action='append', default=[],
713 help='Redistributable toolchain tarball.')
Gilad Arnold2b79e2d2015-06-02 11:26:07 -0700714 parser.add_argument('--toolchain-upload-path', default='',
Mike Frysingerb87bb782015-06-04 02:46:50 -0400715 help='Path to place toolchain tarballs in the sdk tree.')
716 parser.add_argument('--profile',
717 help='Profile that was built on this machine')
718 parser.add_argument('--slave-board', default=[], action=_AddSlaveBoardAction,
719 dest='slave_targets',
720 help='Board type that was built on a slave machine. To '
721 'add a profile to this board, use --slave-profile.')
722 parser.add_argument('--slave-profile', action=_AddSlaveProfileAction,
723 help='Board profile that was built on a slave machine. '
724 'Applies to previous slave board.')
725 parser.add_argument('-p', '--build-path', required=True,
726 help='Path to the directory containing the chroot')
727 parser.add_argument('--packages', action='append', default=[],
728 help='Only include the specified packages. '
729 '(Default is to include all packages.)')
730 parser.add_argument('-s', '--sync-host', default=False, action='store_true',
731 help='Sync host prebuilts')
732 parser.add_argument('-g', '--git-sync', default=False, action='store_true',
733 help='Enable git version sync (This commits to a repo.) '
734 'This is used by full builders to commit directly '
735 'to board overlays.')
736 parser.add_argument('-u', '--upload',
737 help='Upload location')
738 parser.add_argument('-V', '--prepend-version',
739 help='Add an identifier to the front of the version')
740 parser.add_argument('-f', '--filters', action='store_true', default=False,
741 help='Turn on filtering of private ebuild packages')
742 parser.add_argument('-k', '--key', default='PORTAGE_BINHOST',
743 help='Key to update in make.conf / binhost.conf')
744 parser.add_argument('--set-version',
745 help='Specify the version string')
746 parser.add_argument('--sync-binhost-conf', default=False, action='store_true',
747 help='Update binhost.conf in chromiumos-overlay or '
Mike Frysinger80de5012019-08-01 14:10:53 -0400748 "chromeos-overlay. Commit the changes, but don't "
Mike Frysingerb87bb782015-06-04 02:46:50 -0400749 'push them. This is used for preflight binhosts.')
750 parser.add_argument('--binhost-conf-dir',
751 help='Directory to commit binhost config with '
752 '--sync-binhost-conf.')
753 parser.add_argument('-P', '--private', action='store_true', default=False,
754 help='Mark gs:// uploads as private.')
755 parser.add_argument('--skip-upload', action='store_true', default=False,
756 help='Skip upload step.')
757 parser.add_argument('--upload-board-tarball', action='store_true',
758 default=False,
759 help='Upload board tarball to Google Storage.')
760 parser.add_argument('-n', '--dry-run', dest='dryrun',
761 action='store_true', default=False,
Mike Frysinger80de5012019-08-01 14:10:53 -0400762 help="Don't push or upload prebuilts.")
David James8c846492011-01-25 17:07:29 -0800763
Mike Frysingerb87bb782015-06-04 02:46:50 -0400764 options = parser.parse_args(argv)
David James8ece7ee2011-06-29 16:02:30 -0700765 if not options.upload and not options.skip_upload:
Mike Frysinger86509232014-05-24 13:18:37 -0400766 parser.error('you need to provide an upload location using -u')
David James8ece7ee2011-06-29 16:02:30 -0700767 if not options.set_version and options.skip_upload:
Mike Frysinger86509232014-05-24 13:18:37 -0400768 parser.error('If you are using --skip-upload, you must specify a '
769 'version number using --set-version.')
Scott Zawalskiab1bed32011-03-16 15:24:24 -0700770
Chris Sosa6a5dceb2012-05-14 13:48:56 -0700771 target = None
772 if options.board:
773 target = BuildTarget(options.board, options.profile)
774
775 if target in options.slave_targets:
Mike Frysinger86509232014-05-24 13:18:37 -0400776 parser.error('--board/--profile must not also be a slave target.')
David Jamese2488642011-11-14 16:15:20 -0800777
David James4058b0d2011-12-08 21:24:50 -0800778 if len(set(options.slave_targets)) != len(options.slave_targets):
Mike Frysinger86509232014-05-24 13:18:37 -0400779 parser.error('--slave-boards must not have duplicates.')
David Jamese2488642011-11-14 16:15:20 -0800780
David James4058b0d2011-12-08 21:24:50 -0800781 if options.slave_targets and options.git_sync:
Mike Frysinger86509232014-05-24 13:18:37 -0400782 parser.error('--slave-boards is not compatible with --git-sync')
David Jamese2488642011-11-14 16:15:20 -0800783
David James8ece7ee2011-06-29 16:02:30 -0700784 if (options.upload_board_tarball and options.skip_upload and
785 options.board == 'amd64-host'):
Mike Frysinger86509232014-05-24 13:18:37 -0400786 parser.error('--skip-upload is not compatible with '
787 '--upload-board-tarball and --board=amd64-host')
David James8fa34ea2011-04-15 13:00:20 -0700788
David James8ece7ee2011-06-29 16:02:30 -0700789 if (options.upload_board_tarball and not options.skip_upload and
790 not options.upload.startswith('gs://')):
Mike Frysinger86509232014-05-24 13:18:37 -0400791 parser.error('--upload-board-tarball only works with gs:// URLs.\n'
792 '--upload must be a gs:// URL.')
David James8fa34ea2011-04-15 13:00:20 -0700793
Zdenek Behan86c15e92012-10-13 00:55:47 +0200794 if options.upload_board_tarball and options.prepackaged_tarball is None:
Mike Frysinger86509232014-05-24 13:18:37 -0400795 parser.error('--upload-board-tarball requires --prepackaged-tarball')
Zdenek Behan86c15e92012-10-13 00:55:47 +0200796
Scott Zawalskiab1bed32011-03-16 15:24:24 -0700797 if options.private:
798 if options.sync_host:
Mike Frysinger86509232014-05-24 13:18:37 -0400799 parser.error('--private and --sync-host/-s cannot be specified '
800 'together; we do not support private host prebuilts')
Scott Zawalskiab1bed32011-03-16 15:24:24 -0700801
David James8ece7ee2011-06-29 16:02:30 -0700802 if not options.upload or not options.upload.startswith('gs://'):
Mike Frysinger86509232014-05-24 13:18:37 -0400803 parser.error('--private is only valid for gs:// URLs; '
804 '--upload must be a gs:// URL.')
Scott Zawalskiab1bed32011-03-16 15:24:24 -0700805
806 if options.binhost_base_url != _BINHOST_BASE_URL:
Mike Frysinger86509232014-05-24 13:18:37 -0400807 parser.error('when using --private the --binhost-base-url '
808 'is automatically derived.')
David James27fa7d12011-06-29 17:24:14 -0700809
David Jamesc31168e2014-06-05 14:40:05 -0700810 if options.sync_binhost_conf and not options.binhost_conf_dir:
811 parser.error('--sync-binhost-conf requires --binhost-conf-dir')
812
Gilad Arnold2b79e2d2015-06-02 11:26:07 -0700813 if (options.toolchains_overlay_tarballs and
814 not options.toolchains_overlay_upload_path):
815 parser.error('--toolchains-overlay-tarball requires '
816 '--toolchains-overlay-upload-path')
Gilad Arnoldad333182015-05-27 15:50:41 -0700817
Chris Sosa6a5dceb2012-05-14 13:48:56 -0700818 return options, target
David Jamesc0f158a2011-02-22 16:07:29 -0800819
Mike Frysingercc838832014-05-24 13:10:30 -0400820
Mike Frysinger86509232014-05-24 13:18:37 -0400821def main(argv):
David Jamesdb401072011-06-10 12:17:16 -0700822 # Set umask to a sane value so that files created as root are readable.
Mike Frysinger60ec1012013-10-21 00:11:10 -0400823 os.umask(0o22)
David Jamesdb401072011-06-10 12:17:16 -0700824
Mike Frysinger86509232014-05-24 13:18:37 -0400825 options, target = ParseOptions(argv)
David Jamesc0f158a2011-02-22 16:07:29 -0800826
David James05bcb2b2011-02-09 09:25:47 -0800827 # Calculate a list of Packages index files to compare against. Whenever we
828 # upload a package, we check to make sure it's not already stored in one of
829 # the packages files we uploaded. This list of packages files might contain
830 # both board and host packages.
David Jamesce093af2011-02-23 15:21:58 -0800831 pkg_indexes = _GrabAllRemotePackageIndexes(options.previous_binhost_url)
David James8c846492011-01-25 17:07:29 -0800832
David James8ece7ee2011-06-29 16:02:30 -0700833 if options.set_version:
834 version = options.set_version
835 else:
836 version = GetVersion()
Matt Tennante8179042013-10-01 15:47:32 -0700837
David Jamesc0f158a2011-02-22 16:07:29 -0800838 if options.prepend_version:
839 version = '%s-%s' % (options.prepend_version, version)
840
Scott Zawalskiab1bed32011-03-16 15:24:24 -0700841 acl = 'public-read'
842 binhost_base_url = options.binhost_base_url
843
David Jamesadd21432013-05-21 10:04:07 -0700844 if options.private:
Scott Zawalskiab1bed32011-03-16 15:24:24 -0700845 binhost_base_url = options.upload
David Jamesadd21432013-05-21 10:04:07 -0700846 if target:
Prathmesh Prabhu421eef22014-10-16 17:13:19 -0700847 acl = portage_util.FindOverlayFile(_GOOGLESTORAGE_GSUTIL_FILE,
848 board=target.board_variant,
849 buildroot=options.build_path)
Ben Chan067de492015-01-06 17:19:13 -0800850 if acl is None:
851 cros_build_lib.Die('No Google Storage ACL file %s found in %s overlay.',
852 _GOOGLESTORAGE_GSUTIL_FILE, target.board_variant)
Scott Zawalskiab1bed32011-03-16 15:24:24 -0700853
David Jamesb26b9312014-12-15 11:26:46 -0800854 binhost_conf_dir = None
855 if options.binhost_conf_dir:
856 binhost_conf_dir = os.path.join(options.build_path,
857 options.binhost_conf_dir)
858
Scott Zawalskiab1bed32011-03-16 15:24:24 -0700859 uploader = PrebuiltUploader(options.upload, acl, binhost_base_url,
David James615e5b52011-06-03 11:10:15 -0700860 pkg_indexes, options.build_path,
David James27fa7d12011-06-29 17:24:14 -0700861 options.packages, options.skip_upload,
David Jamesb26b9312014-12-15 11:26:46 -0800862 binhost_conf_dir, options.dryrun,
Mike Frysinger8092a632014-05-24 13:25:46 -0400863 target, options.slave_targets, version)
David Jamesc0f158a2011-02-22 16:07:29 -0800864
David James8c846492011-01-25 17:07:29 -0800865 if options.sync_host:
Mike Frysinger8092a632014-05-24 13:25:46 -0400866 uploader.SyncHostPrebuilts(options.key, options.git_sync,
Chris Sosa6a5dceb2012-05-14 13:48:56 -0700867 options.sync_binhost_conf)
David James8c846492011-01-25 17:07:29 -0800868
Chris Sosa62c8ff52012-06-04 15:03:12 -0700869 if options.board or options.slave_targets:
Mike Frysinger8092a632014-05-24 13:25:46 -0400870 uploader.SyncBoardPrebuilts(options.key, options.git_sync,
Chris Sosa6a5dceb2012-05-14 13:48:56 -0700871 options.sync_binhost_conf,
Zdenek Behan62a57792012-08-31 15:09:08 +0200872 options.upload_board_tarball,
Mike Frysinger9e979b92012-11-29 02:55:09 -0500873 options.prepackaged_tarball,
Gilad Arnold2b79e2d2015-06-02 11:26:07 -0700874 options.toolchains_overlay_tarballs,
875 options.toolchains_overlay_upload_path,
Mike Frysinger9e979b92012-11-29 02:55:09 -0500876 options.toolchain_tarballs,
877 options.toolchain_upload_path)