blob: 7240e97a8b291ffd9c8829deb42072f420ae0600 [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:
Mike Nicholsd0acc7f2021-05-21 17:18:24 +000015upload_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:
Mike Nicholsd0acc7f2021-05-21 17:18:24 +000018upload_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
Alex Klein18a60af2020-06-11 12:08:47 -060044from chromite.lib.parser import package_info
Chris Sosa1dc96132012-05-11 15:40:50 -070045
Mike Frysinger72b7cf92020-04-19 06:00:51 -040046
47assert sys.version_info >= (3, 6), 'This module requires Python 3.6+'
48
49
David James015af872012-06-19 15:24:36 -070050# How many times to retry uploads.
51_RETRIES = 10
52
53# Multiplier for how long to sleep (in seconds) between retries; will delay
54# (1*sleep) the first time, then (2*sleep), continuing via attempt * sleep.
55_SLEEP_TIME = 60
56
David James5ab67e32014-10-24 08:19:59 -070057# The length of time (in seconds) that Portage should wait before refetching
58# binpkgs from the same binhost. We don't ever modify binhosts, so this should
59# be something big.
60_BINPKG_TTL = 60 * 60 * 24 * 365
61
David James8c846492011-01-25 17:07:29 -080062_HOST_PACKAGES_PATH = 'chroot/var/lib/portage/pkgs'
David James05bcb2b2011-02-09 09:25:47 -080063_CATEGORIES_PATH = 'chroot/etc/portage/categories'
David James615e5b52011-06-03 11:10:15 -070064_PYM_PATH = 'chroot/usr/lib/portage/pym'
David James4058b0d2011-12-08 21:24:50 -080065_HOST_ARCH = 'amd64'
David James8c846492011-01-25 17:07:29 -080066_BOARD_PATH = 'chroot/build/%(board)s'
David James4058b0d2011-12-08 21:24:50 -080067_REL_BOARD_PATH = 'board/%(target)s/%(version)s'
68_REL_HOST_PATH = 'host/%(host_arch)s/%(target)s/%(version)s'
David James8c846492011-01-25 17:07:29 -080069# Private overlays to look at for builds to filter
70# relative to build path
71_PRIVATE_OVERLAY_DIR = 'src/private-overlays'
Gabe Black40169e62014-06-17 15:23:47 -070072_GOOGLESTORAGE_GSUTIL_FILE = 'googlestorage_acl.txt'
David James3753d942014-04-23 10:55:48 -070073_BINHOST_BASE_URL = 'gs://chromeos-prebuilt'
David James8c846492011-01-25 17:07:29 -080074_PREBUILT_BASE_DIR = 'src/third_party/chromiumos-overlay/chromeos/config/'
75# Created in the event of new host targets becoming available
76_PREBUILT_MAKE_CONF = {'amd64': os.path.join(_PREBUILT_BASE_DIR,
77 'make.conf.amd64-host')}
David James8c846492011-01-25 17:07:29 -080078
79
David James4058b0d2011-12-08 21:24:50 -080080class BuildTarget(object):
81 """A board/variant/profile tuple."""
82
83 def __init__(self, board_variant, profile=None):
84 self.board_variant = board_variant
85 self.board, _, self.variant = board_variant.partition('_')
86 self.profile = profile
87
88 def __str__(self):
89 if self.profile:
90 return '%s_%s' % (self.board_variant, self.profile)
91 else:
92 return self.board_variant
93
94 def __eq__(self, other):
95 return str(other) == str(self)
96
97 def __hash__(self):
98 return hash(str(self))
99
100
David James8c846492011-01-25 17:07:29 -0800101def UpdateLocalFile(filename, value, key='PORTAGE_BINHOST'):
102 """Update the key in file with the value passed.
Mike Frysinger1a736a82013-12-12 01:50:59 -0500103
David James8c846492011-01-25 17:07:29 -0800104 File format:
105 key="value"
106 Note quotes are added automatically
107
108 Args:
109 filename: Name of file to modify.
110 value: Value to write with the key.
111 key: The variable key to update. (Default: PORTAGE_BINHOST)
David Jamesb26b9312014-12-15 11:26:46 -0800112
113 Returns:
114 True if changes were made to the file.
David James8c846492011-01-25 17:07:29 -0800115 """
116 if os.path.exists(filename):
117 file_fh = open(filename)
118 else:
119 file_fh = open(filename, 'w+')
120 file_lines = []
121 found = False
David Jamesb26b9312014-12-15 11:26:46 -0800122 made_changes = False
David James8c846492011-01-25 17:07:29 -0800123 keyval_str = '%(key)s=%(value)s'
124 for line in file_fh:
125 # Strip newlines from end of line. We already add newlines below.
Mike Frysinger80de5012019-08-01 14:10:53 -0400126 line = line.rstrip('\n')
David James8c846492011-01-25 17:07:29 -0800127
128 if len(line.split('=')) != 2:
129 # Skip any line that doesn't fit key=val.
130 file_lines.append(line)
131 continue
132
133 file_var, file_val = line.split('=')
134 if file_var == key:
135 found = True
Mike Frysingerff441bf2014-05-24 13:47:21 -0400136 print('Updating %s=%s to %s="%s"' % (file_var, file_val, key, value))
David James8c846492011-01-25 17:07:29 -0800137 value = '"%s"' % value
David Jamesb26b9312014-12-15 11:26:46 -0800138 made_changes |= (file_val != value)
David James8c846492011-01-25 17:07:29 -0800139 file_lines.append(keyval_str % {'key': key, 'value': value})
140 else:
141 file_lines.append(keyval_str % {'key': file_var, 'value': file_val})
142
143 if not found:
Brian Harring2a014302012-05-12 00:53:33 -0700144 value = '"%s"' % value
David Jamesb26b9312014-12-15 11:26:46 -0800145 made_changes = True
David James8c846492011-01-25 17:07:29 -0800146 file_lines.append(keyval_str % {'key': key, 'value': value})
147
148 file_fh.close()
149 # write out new file
Brian Harringaf019fb2012-05-10 15:06:13 -0700150 osutils.WriteFile(filename, '\n'.join(file_lines) + '\n')
David Jamesb26b9312014-12-15 11:26:46 -0800151 return made_changes
David James8c846492011-01-25 17:07:29 -0800152
153
Mike Nicholsa6818c52018-04-09 11:05:42 -0600154def RevGitFile(filename, data, dryrun=False):
David James8c846492011-01-25 17:07:29 -0800155 """Update and push the git file.
156
Mike Frysinger5b34d732013-01-17 15:11:58 -0500157 Args:
158 filename: file to modify that is in a git repo already
159 data: A dict of key/values to update in |filename|
Matt Tennante8179042013-10-01 15:47:32 -0700160 dryrun: If True, do not actually commit the change.
David James8c846492011-01-25 17:07:29 -0800161 """
162 prebuilt_branch = 'prebuilt_branch'
David James1b6e67a2011-05-19 21:32:38 -0700163 cwd = os.path.abspath(os.path.dirname(filename))
Julio Hurtado180a42f2021-05-13 21:42:08 +0000164 commit = git.RunGit(cwd, ['rev-parse', 'HEAD']).output.rstrip()
Mike Frysinger5b34d732013-01-17 15:11:58 -0500165 description = '%s: updating %s' % (os.path.basename(filename),
166 ', '.join(data.keys()))
167 # UpdateLocalFile will print out the keys/values for us.
Mike Frysingerff441bf2014-05-24 13:47:21 -0400168 print('Revving git file %s' % filename)
Julio Hurtado2d4817d2021-04-29 16:03:58 +0000169
Julio Hurtado180a42f2021-05-13 21:42:08 +0000170 try:
171 git.CreatePushBranch(prebuilt_branch, cwd)
172 for key, value in data.items():
173 UpdateLocalFile(filename, value, key)
174 git.RunGit(cwd, ['add', filename])
175 git.RunGit(cwd, ['commit', '-m', description])
176 git.PushBranch(prebuilt_branch, cwd, dryrun=dryrun, auto_merge=True)
177 finally:
178 # We reset the index and the working tree state in case there are any
179 # uncommitted or pending changes, but we don't change any existing commits.
180 git.RunGit(cwd, ['reset', '--hard'])
181
182 # Check out the last good commit as a sanity fallback.
183 git.RunGit(cwd, ['checkout', commit])
David James8c846492011-01-25 17:07:29 -0800184
185
186def GetVersion():
187 """Get the version to put in LATEST and update the git version with."""
Mike Frysinger0b92cfe2012-12-13 02:13:45 -0500188 return datetime.datetime.now().strftime('%Y.%m.%d.%H%M%S')
David James8c846492011-01-25 17:07:29 -0800189
190
Mike Frysinger540883b2014-05-24 13:46:16 -0400191def _GsUpload(gs_context, acl, local_file, remote_file):
David James8c846492011-01-25 17:07:29 -0800192 """Upload to GS bucket.
193
194 Args:
Mike Frysinger540883b2014-05-24 13:46:16 -0400195 gs_context: A lib.gs.GSContext instance.
196 acl: The ACL to use for uploading the file.
Matt Tennante8179042013-10-01 15:47:32 -0700197 local_file: The local file to be uploaded.
198 remote_file: The remote location to upload to.
David James8c846492011-01-25 17:07:29 -0800199 """
Scott Zawalskiab1bed32011-03-16 15:24:24 -0700200 CANNED_ACLS = ['public-read', 'private', 'bucket-owner-read',
201 'authenticated-read', 'bucket-owner-full-control',
202 'public-read-write']
Scott Zawalskiab1bed32011-03-16 15:24:24 -0700203 if acl in CANNED_ACLS:
David James9374aac2013-10-08 16:00:17 -0700204 gs_context.Copy(local_file, remote_file, acl=acl)
Scott Zawalskiab1bed32011-03-16 15:24:24 -0700205 else:
206 # For private uploads we assume that the overlay board is set up properly
David James015af872012-06-19 15:24:36 -0700207 # and a googlestore_acl.xml is present. Otherwise, this script errors.
David James7b7d7c32015-04-02 13:48:17 -0700208 # We set version=0 here to ensure that the ACL is set only once (see
209 # http://b/15883752#comment54).
210 try:
211 gs_context.Copy(local_file, remote_file, version=0)
212 except gs.GSContextPreconditionFailed as ex:
213 # If we received a GSContextPreconditionFailed error, we know that the
214 # file exists now, but we don't know whether our specific update
215 # succeeded. See http://b/15883752#comment62
216 logging.warning(
217 'Assuming upload succeeded despite PreconditionFailed errors: %s', ex)
218
Gabe Black40169e62014-06-17 15:23:47 -0700219 if acl.endswith('.xml'):
220 # Apply the passed in ACL xml file to the uploaded object.
221 gs_context.SetACL(remote_file, acl=acl)
222 else:
Mike Frysinger5186f262017-09-13 10:26:19 -0400223 gs_context.ChangeACL(remote_file, acl_args_file=acl)
Scott Zawalskiab1bed32011-03-16 15:24:24 -0700224
Mike Frysingercc838832014-05-24 13:10:30 -0400225
Mike Frysinger540883b2014-05-24 13:46:16 -0400226def RemoteUpload(gs_context, acl, files, pool=10):
David James8c846492011-01-25 17:07:29 -0800227 """Upload to google storage.
228
229 Create a pool of process and call _GsUpload with the proper arguments.
230
231 Args:
Mike Frysinger540883b2014-05-24 13:46:16 -0400232 gs_context: A lib.gs.GSContext instance.
David Jamesfd0b0852011-02-23 11:15:36 -0800233 acl: The canned acl used for uploading. acl can be one of: "public-read",
234 "public-read-write", "authenticated-read", "bucket-owner-read",
235 "bucket-owner-full-control", or "private".
David James8c846492011-01-25 17:07:29 -0800236 files: dictionary with keys to local files and values to remote path.
237 pool: integer of maximum proesses to have at the same time.
238
239 Returns:
240 Return a set of tuple arguments of the failed uploads
241 """
Mike Frysinger540883b2014-05-24 13:46:16 -0400242 upload = functools.partial(_GsUpload, gs_context, acl)
Mike Frysinger0bdbc102019-06-13 15:27:29 -0400243 tasks = [[key, value] for key, value in files.items()]
Mike Frysinger540883b2014-05-24 13:46:16 -0400244 parallel.RunTasksInProcessPool(upload, tasks, pool)
David James8c846492011-01-25 17:07:29 -0800245
246
247def GenerateUploadDict(base_local_path, base_remote_path, pkgs):
248 """Build a dictionary of local remote file key pairs to upload.
249
250 Args:
251 base_local_path: The base path to the files on the local hard drive.
Matt Tennante8179042013-10-01 15:47:32 -0700252 base_remote_path: The base path to the remote paths.
David James8c846492011-01-25 17:07:29 -0800253 pkgs: The packages to upload.
254
255 Returns:
256 Returns a dictionary of local_path/remote_path pairs
257 """
258 upload_files = {}
259 for pkg in pkgs:
260 suffix = pkg['CPV'] + '.tbz2'
261 local_path = os.path.join(base_local_path, suffix)
David James7b7d7c32015-04-02 13:48:17 -0700262 assert os.path.exists(local_path), '%s does not exist' % local_path
Bertrand SIMONNET811bcde2014-11-20 15:21:25 -0800263 upload_files[local_path] = os.path.join(base_remote_path, suffix)
David James8c846492011-01-25 17:07:29 -0800264
Bertrand SIMONNET811bcde2014-11-20 15:21:25 -0800265 if pkg.get('DEBUG_SYMBOLS') == 'yes':
266 debugsuffix = pkg['CPV'] + '.debug.tbz2'
267 local_path = os.path.join(base_local_path, debugsuffix)
268 assert os.path.exists(local_path)
269 upload_files[local_path] = os.path.join(base_remote_path, debugsuffix)
Bertrand SIMONNET22e828b2014-11-11 16:27:06 -0800270
David James8c846492011-01-25 17:07:29 -0800271 return upload_files
272
Mike Frysingercc838832014-05-24 13:10:30 -0400273
Peter Mayo950e41a2014-02-06 21:07:33 +0000274def GetBoardOverlay(build_path, target):
David Jamese5867812012-10-19 12:02:20 -0700275 """Get the path to the board variant.
Mike Frysinger1a736a82013-12-12 01:50:59 -0500276
Mike Frysinger6f3c48e2015-05-06 02:38:51 -0400277 Args:
278 build_path: The path to the root of the build directory
279 target: The target board as a BuildTarget object.
Mike Frysinger1a736a82013-12-12 01:50:59 -0500280
Mike Frysinger6f3c48e2015-05-06 02:38:51 -0400281 Returns:
282 The last overlay configured for the given board as a string.
David James8c846492011-01-25 17:07:29 -0800283 """
David Jamese5867812012-10-19 12:02:20 -0700284 board = target.board_variant
Alex Deymo075c2292014-09-04 18:31:50 -0700285 overlays = portage_util.FindOverlays(constants.BOTH_OVERLAYS, board,
286 buildroot=build_path)
David Jamese5867812012-10-19 12:02:20 -0700287 # We only care about the last entry.
288 return overlays[-1]
David James8c846492011-01-25 17:07:29 -0800289
290
291def DeterminePrebuiltConfFile(build_path, target):
292 """Determine the prebuilt.conf file that needs to be updated for prebuilts.
293
Mike Frysinger1a736a82013-12-12 01:50:59 -0500294 Args:
295 build_path: The path to the root of the build directory
296 target: String representation of the board. This includes host and board
297 targets
David James8c846492011-01-25 17:07:29 -0800298
Mike Frysinger1a736a82013-12-12 01:50:59 -0500299 Returns:
300 A string path to a prebuilt.conf file to be updated.
David James8c846492011-01-25 17:07:29 -0800301 """
David James4058b0d2011-12-08 21:24:50 -0800302 if _HOST_ARCH == target:
David James8c846492011-01-25 17:07:29 -0800303 # We are host.
304 # Without more examples of hosts this is a kludge for now.
305 # TODO(Scottz): as new host targets come online expand this to
306 # work more like boards.
Chris Sosa471532a2011-02-01 15:10:06 -0800307 make_path = _PREBUILT_MAKE_CONF[target]
David James8c846492011-01-25 17:07:29 -0800308 else:
309 # We are a board
Peter Mayo950e41a2014-02-06 21:07:33 +0000310 board = GetBoardOverlay(build_path, target)
David James8c846492011-01-25 17:07:29 -0800311 make_path = os.path.join(board, 'prebuilt.conf')
312
313 return make_path
314
315
316def UpdateBinhostConfFile(path, key, value):
317 """Update binhost config file file with key=value.
318
319 Args:
320 path: Filename to update.
321 key: Key to update.
322 value: New value for key.
323 """
David Jamesb26b9312014-12-15 11:26:46 -0800324 cwd, filename = os.path.split(os.path.abspath(path))
Brian Harringaf019fb2012-05-10 15:06:13 -0700325 osutils.SafeMakedirs(cwd)
David Jamesf6e8fb72013-05-10 08:58:43 -0700326 if not git.GetCurrentBranch(cwd):
327 git.CreatePushBranch(constants.STABLE_EBUILD_BRANCH, cwd, sync=False)
Brian Harring22edb442012-05-11 23:55:18 -0700328 osutils.WriteFile(path, '', mode='a')
David Jamesb26b9312014-12-15 11:26:46 -0800329 if UpdateLocalFile(path, value, key):
330 desc = '%s: %s %s' % (filename, 'updating' if value else 'clearing', key)
331 git.AddPath(path)
332 git.Commit(cwd, desc)
David James8c846492011-01-25 17:07:29 -0800333
Achuith Bhandarkar03d924a2018-01-02 10:50:44 -0800334def GenerateHtmlIndex(files, index, board, version, remote_location):
Mike Frysinger212e4292014-05-24 15:15:44 -0400335 """Given the list of |files|, generate an index.html at |index|.
336
337 Args:
338 files: The list of files to link to.
339 index: The path to the html index.
340 board: Name of the board this index is for.
341 version: Build version this index is for.
Achuith Bhandarkar03d924a2018-01-02 10:50:44 -0800342 remote_location: Remote gs location prebuilts are uploaded to.
Mike Frysinger212e4292014-05-24 15:15:44 -0400343 """
Don Garrett13cbbff2016-08-09 14:18:38 -0700344 title = 'Package Prebuilt Index: %s / %s' % (board, version)
Mike Frysinger212e4292014-05-24 15:15:44 -0400345
346 files = files + [
347 '.|Google Storage Index',
348 '..|',
349 ]
Achuith Bhandarkar03d924a2018-01-02 10:50:44 -0800350 commands.GenerateHtmlIndex(index, files, title=title,
351 url_base=gs.GsUrlToHttp(remote_location))
Mike Frysinger212e4292014-05-24 15:15:44 -0400352
353
David Jamesce093af2011-02-23 15:21:58 -0800354def _GrabAllRemotePackageIndexes(binhost_urls):
David James05bcb2b2011-02-09 09:25:47 -0800355 """Grab all of the packages files associated with a list of binhost_urls.
356
David James05bcb2b2011-02-09 09:25:47 -0800357 Args:
358 binhost_urls: The URLs for the directories containing the Packages files we
359 want to grab.
David James05bcb2b2011-02-09 09:25:47 -0800360
361 Returns:
362 A list of PackageIndex objects.
363 """
364 pkg_indexes = []
365 for url in binhost_urls:
David James32faafe2012-06-08 14:25:03 -0700366 pkg_index = binpkg.GrabRemotePackageIndex(url)
David James05bcb2b2011-02-09 09:25:47 -0800367 if pkg_index:
368 pkg_indexes.append(pkg_index)
David James05bcb2b2011-02-09 09:25:47 -0800369 return pkg_indexes
370
371
David Jamesc0f158a2011-02-22 16:07:29 -0800372class PrebuiltUploader(object):
373 """Synchronize host and board prebuilts."""
David James8c846492011-01-25 17:07:29 -0800374
Mike Frysinger86509232014-05-24 13:18:37 -0400375 def __init__(self, upload_location, acl, binhost_base_url, pkg_indexes,
376 build_path, packages, skip_upload, binhost_conf_dir, dryrun,
Mike Frysinger8092a632014-05-24 13:25:46 -0400377 target, slave_targets, version):
David Jamesc0f158a2011-02-22 16:07:29 -0800378 """Constructor for prebuilt uploader object.
David James8c846492011-01-25 17:07:29 -0800379
David Jamesc0f158a2011-02-22 16:07:29 -0800380 This object can upload host or prebuilt files to Google Storage.
David James8c846492011-01-25 17:07:29 -0800381
David Jamesc0f158a2011-02-22 16:07:29 -0800382 Args:
383 upload_location: The upload location.
David Jamesfd0b0852011-02-23 11:15:36 -0800384 acl: The canned acl used for uploading to Google Storage. acl can be one
385 of: "public-read", "public-read-write", "authenticated-read",
Matt Tennante8179042013-10-01 15:47:32 -0700386 "bucket-owner-read", "bucket-owner-full-control", "project-private",
387 or "private" (see "gsutil help acls"). If we are not uploading to
388 Google Storage, this parameter is unused.
David Jamesfd0b0852011-02-23 11:15:36 -0800389 binhost_base_url: The URL used for downloading the prebuilts.
David Jamesc0f158a2011-02-22 16:07:29 -0800390 pkg_indexes: Old uploaded prebuilts to compare against. Instead of
391 uploading duplicate files, we just link to the old files.
David James615e5b52011-06-03 11:10:15 -0700392 build_path: The path to the directory containing the chroot.
393 packages: Packages to upload.
David James32b0b2f2011-07-13 20:56:50 -0700394 skip_upload: Don't actually upload the tarballs.
395 binhost_conf_dir: Directory where to store binhost.conf files.
Mike Frysinger86509232014-05-24 13:18:37 -0400396 dryrun: Don't push or upload prebuilts.
David James4058b0d2011-12-08 21:24:50 -0800397 target: BuildTarget managed by this builder.
398 slave_targets: List of BuildTargets managed by slave builders.
Mike Frysinger8092a632014-05-24 13:25:46 -0400399 version: A unique string, intended to be included in the upload path,
400 which identifies the version number of the uploaded prebuilts.
David Jamesc0f158a2011-02-22 16:07:29 -0800401 """
402 self._upload_location = upload_location
David Jamesfd0b0852011-02-23 11:15:36 -0800403 self._acl = acl
David Jamesc0f158a2011-02-22 16:07:29 -0800404 self._binhost_base_url = binhost_base_url
405 self._pkg_indexes = pkg_indexes
David James615e5b52011-06-03 11:10:15 -0700406 self._build_path = build_path
407 self._packages = set(packages)
Mike Frysingerf5f809a2013-02-12 13:47:37 -0500408 self._found_packages = set()
David James8ece7ee2011-06-29 16:02:30 -0700409 self._skip_upload = skip_upload
David James32b0b2f2011-07-13 20:56:50 -0700410 self._binhost_conf_dir = binhost_conf_dir
Mike Frysinger86509232014-05-24 13:18:37 -0400411 self._dryrun = dryrun
David James4058b0d2011-12-08 21:24:50 -0800412 self._target = target
413 self._slave_targets = slave_targets
Mike Frysinger8092a632014-05-24 13:25:46 -0400414 self._version = version
Mike Frysinger540883b2014-05-24 13:46:16 -0400415 self._gs_context = gs.GSContext(retries=_RETRIES, sleep=_SLEEP_TIME,
416 dry_run=self._dryrun)
417
418 def _Upload(self, local_file, remote_file):
419 """Wrapper around _GsUpload"""
420 _GsUpload(self._gs_context, self._acl, local_file, remote_file)
David James615e5b52011-06-03 11:10:15 -0700421
422 def _ShouldFilterPackage(self, pkg):
423 if not self._packages:
424 return False
Alex Klein18a60af2020-06-11 12:08:47 -0600425 cpv = package_info.SplitCPV(pkg['CPV'])
Alex Klein9f93b482018-10-01 09:26:51 -0600426 self._found_packages.add(cpv.cp)
427 return cpv.package not in self._packages and cpv.cp not in self._packages
David James8c846492011-01-25 17:07:29 -0800428
David Jamesc0f158a2011-02-22 16:07:29 -0800429 def _UploadPrebuilt(self, package_path, url_suffix):
430 """Upload host or board prebuilt files to Google Storage space.
David James8c846492011-01-25 17:07:29 -0800431
David Jamesc0f158a2011-02-22 16:07:29 -0800432 Args:
433 package_path: The path to the packages dir.
David Jamesce093af2011-02-23 15:21:58 -0800434 url_suffix: The remote subdirectory where we should upload the packages.
David Jamesc0f158a2011-02-22 16:07:29 -0800435 """
David Jamesc0f158a2011-02-22 16:07:29 -0800436 # Process Packages file, removing duplicates and filtered packages.
David James32faafe2012-06-08 14:25:03 -0700437 pkg_index = binpkg.GrabLocalPackageIndex(package_path)
David Jamesc0f158a2011-02-22 16:07:29 -0800438 pkg_index.SetUploadLocation(self._binhost_base_url, url_suffix)
David James615e5b52011-06-03 11:10:15 -0700439 pkg_index.RemoveFilteredPackages(self._ShouldFilterPackage)
David Jamesc0f158a2011-02-22 16:07:29 -0800440 uploads = pkg_index.ResolveDuplicateUploads(self._pkg_indexes)
Mike Frysingerf5f809a2013-02-12 13:47:37 -0500441 unmatched_pkgs = self._packages - self._found_packages
442 if unmatched_pkgs:
Lann Martinffb95162018-08-28 12:02:54 -0600443 logging.warning('unable to match packages: %r', unmatched_pkgs)
David James05bcb2b2011-02-09 09:25:47 -0800444
David Jamesc0f158a2011-02-22 16:07:29 -0800445 # Write Packages file.
David James5ab67e32014-10-24 08:19:59 -0700446 pkg_index.header['TTL'] = _BINPKG_TTL
David Jamesc0f158a2011-02-22 16:07:29 -0800447 tmp_packages_file = pkg_index.WriteToNamedTemporaryFile()
David James05bcb2b2011-02-09 09:25:47 -0800448
David Jamesc0f158a2011-02-22 16:07:29 -0800449 remote_location = '%s/%s' % (self._upload_location.rstrip('/'), url_suffix)
David James015af872012-06-19 15:24:36 -0700450 assert remote_location.startswith('gs://')
David James05bcb2b2011-02-09 09:25:47 -0800451
David James015af872012-06-19 15:24:36 -0700452 upload_files = GenerateUploadDict(package_path, remote_location, uploads)
453 remote_file = '%s/Packages' % remote_location.rstrip('/')
454 upload_files[tmp_packages_file.name] = remote_file
455
Mike Frysinger9bb6cd82020-08-20 03:02:23 -0400456 # Build list of files to upload. Manually include the dev-only files but
457 # skip them if not present.
458 dev_only = os.path.join(package_path, 'dev-only-extras.tar.xz')
459 if os.path.exists(dev_only):
460 upload_files[dev_only] = '%s/%s' % (
461 remote_location.rstrip('/'), os.path.basename(dev_only))
462
Mike Frysinger540883b2014-05-24 13:46:16 -0400463 RemoteUpload(self._gs_context, self._acl, upload_files)
David James8c846492011-01-25 17:07:29 -0800464
Mike Frysinger212e4292014-05-24 15:15:44 -0400465 with tempfile.NamedTemporaryFile(
466 prefix='chromite.upload_prebuilts.index.') as index:
467 GenerateHtmlIndex(
468 [x[len(remote_location) + 1:] for x in upload_files.values()],
Achuith Bhandarkar03d924a2018-01-02 10:50:44 -0800469 index.name, self._target, self._version, remote_location)
Mike Frysinger212e4292014-05-24 15:15:44 -0400470 self._Upload(index.name, '%s/index.html' % remote_location.rstrip('/'))
471
472 link_name = 'Prebuilts[%s]: %s' % (self._target, self._version)
473 url = '%s%s/index.html' % (gs.PUBLIC_BASE_HTTPS_URL,
474 remote_location[len(gs.BASE_GS_URL):])
Prathmesh Prabhu17f07422015-07-17 11:40:40 -0700475 logging.PrintBuildbotLink(link_name, url)
Mike Frysinger212e4292014-05-24 15:15:44 -0400476
Mike Frysinger8092a632014-05-24 13:25:46 -0400477 def _UploadSdkTarball(self, board_path, url_suffix, prepackaged,
Gilad Arnold2b79e2d2015-06-02 11:26:07 -0700478 toolchains_overlay_tarballs,
479 toolchains_overlay_upload_path,
Mike Frysinger9e979b92012-11-29 02:55:09 -0500480 toolchain_tarballs, toolchain_upload_path):
481 """Upload a tarball of the sdk at the specified path to Google Storage.
David James8fa34ea2011-04-15 13:00:20 -0700482
483 Args:
484 board_path: The path to the board dir.
485 url_suffix: The remote subdirectory where we should upload the packages.
Zdenek Behan62a57792012-08-31 15:09:08 +0200486 prepackaged: If given, a tarball that has been packaged outside of this
487 script and should be used.
Gilad Arnold2b79e2d2015-06-02 11:26:07 -0700488 toolchains_overlay_tarballs: List of toolchains overlay tarball
489 specifications to upload. Items take the form
490 "toolchains_spec:/path/to/tarball".
491 toolchains_overlay_upload_path: Path template under the bucket to place
492 toolchains overlay tarballs.
Mike Frysinger9e979b92012-11-29 02:55:09 -0500493 toolchain_tarballs: List of toolchain tarballs to upload.
494 toolchain_upload_path: Path under the bucket to place toolchain tarballs.
David James8fa34ea2011-04-15 13:00:20 -0700495 """
496 remote_location = '%s/%s' % (self._upload_location.rstrip('/'), url_suffix)
497 assert remote_location.startswith('gs://')
Zdenek Behan86c15e92012-10-13 00:55:47 +0200498 boardname = os.path.basename(board_path.rstrip('/'))
499 # We do not upload non SDK board tarballs,
500 assert boardname == constants.CHROOT_BUILDER_BOARD
501 assert prepackaged is not None
Zdenek Behan62a57792012-08-31 15:09:08 +0200502
Mike Frysinger8092a632014-05-24 13:25:46 -0400503 version_str = self._version[len('chroot-'):]
Mike Frysinger8e727a32013-01-16 16:57:53 -0500504 remote_tarfile = toolchain.GetSdkURL(
505 for_gsutil=True, suburl='cros-sdk-%s.tar.xz' % (version_str,))
Zdenek Behan86c15e92012-10-13 00:55:47 +0200506 # For SDK, also upload the manifest which is guaranteed to exist
507 # by the builderstage.
Mike Frysinger540883b2014-05-24 13:46:16 -0400508 self._Upload(prepackaged + '.Manifest', remote_tarfile + '.Manifest')
509 self._Upload(prepackaged, remote_tarfile)
Zdenek Behan86c15e92012-10-13 00:55:47 +0200510
Gilad Arnold2b79e2d2015-06-02 11:26:07 -0700511 # Upload SDK toolchains overlays and toolchain tarballs, if given.
Gilad Arnoldad333182015-05-27 15:50:41 -0700512 for tarball_list, upload_path, qualifier_name in (
Gilad Arnold2b79e2d2015-06-02 11:26:07 -0700513 (toolchains_overlay_tarballs, toolchains_overlay_upload_path,
514 'toolchains'),
Gilad Arnoldad333182015-05-27 15:50:41 -0700515 (toolchain_tarballs, toolchain_upload_path, 'target')):
Gilad Arnold2b79e2d2015-06-02 11:26:07 -0700516 for tarball_spec in tarball_list:
517 qualifier_val, local_path = tarball_spec.split(':')
Gilad Arnoldad333182015-05-27 15:50:41 -0700518 suburl = upload_path % {qualifier_name: qualifier_val}
519 remote_path = toolchain.GetSdkURL(for_gsutil=True, suburl=suburl)
520 self._Upload(local_path, remote_path)
Mike Frysinger9e979b92012-11-29 02:55:09 -0500521
Zdenek Behan86c15e92012-10-13 00:55:47 +0200522 # Finally, also update the pointer to the latest SDK on which polling
523 # scripts rely.
David James4bc13702013-03-26 08:08:04 -0700524 with osutils.TempDir() as tmpdir:
Zdenek Behan86c15e92012-10-13 00:55:47 +0200525 pointerfile = os.path.join(tmpdir, 'cros-sdk-latest.conf')
Mike Frysinger8e727a32013-01-16 16:57:53 -0500526 remote_pointerfile = toolchain.GetSdkURL(for_gsutil=True,
527 suburl='cros-sdk-latest.conf')
Zdenek Behan86c15e92012-10-13 00:55:47 +0200528 osutils.WriteFile(pointerfile, 'LATEST_SDK="%s"' % version_str)
Mike Frysinger540883b2014-05-24 13:46:16 -0400529 self._Upload(pointerfile, remote_pointerfile)
Zdenek Behan33a34112012-09-10 21:07:51 +0200530
Chris Sosa6a5dceb2012-05-14 13:48:56 -0700531 def _GetTargets(self):
532 """Retuns the list of targets to use."""
533 targets = self._slave_targets[:]
534 if self._target:
535 targets.append(self._target)
536
537 return targets
538
Mike Frysinger8092a632014-05-24 13:25:46 -0400539 def SyncHostPrebuilts(self, key, git_sync, sync_binhost_conf):
David Jamesc0f158a2011-02-22 16:07:29 -0800540 """Synchronize host prebuilt files.
David James05bcb2b2011-02-09 09:25:47 -0800541
David Jamesc0f158a2011-02-22 16:07:29 -0800542 This function will sync both the standard host packages, plus the host
543 packages associated with all targets that have been "setup" with the
544 current host's chroot. For instance, if this host has been used to build
545 x86-generic, it will sync the host packages associated with
546 'i686-pc-linux-gnu'. If this host has also been used to build arm-generic,
547 it will also sync the host packages associated with
548 'armv7a-cros-linux-gnueabi'.
David James05bcb2b2011-02-09 09:25:47 -0800549
David Jamesc0f158a2011-02-22 16:07:29 -0800550 Args:
David Jamesc0f158a2011-02-22 16:07:29 -0800551 key: The variable key to update in the git file.
552 git_sync: If set, update make.conf of target to reference the latest
553 prebuilt packages generated here.
554 sync_binhost_conf: If set, update binhost config file in
555 chromiumos-overlay for the host.
556 """
Mike Nicholsa1414162021-04-22 20:07:22 +0000557 # Slave boards are listed before the master board so that the master board
David Jamese2488642011-11-14 16:15:20 -0800558 # takes priority (i.e. x86-generic preflight host prebuilts takes priority
559 # over preflight host prebuilts from other builders.)
560 binhost_urls = []
Chris Sosa6a5dceb2012-05-14 13:48:56 -0700561 for target in self._GetTargets():
Mike Frysinger8092a632014-05-24 13:25:46 -0400562 url_suffix = _REL_HOST_PATH % {'version': self._version,
David James4058b0d2011-12-08 21:24:50 -0800563 'host_arch': _HOST_ARCH,
564 'target': target}
David Jamese2488642011-11-14 16:15:20 -0800565 packages_url_suffix = '%s/packages' % url_suffix.rstrip('/')
David James05bcb2b2011-02-09 09:25:47 -0800566
Mike Frysinger540883b2014-05-24 13:46:16 -0400567 if self._target == target and not self._skip_upload:
David Jamese2488642011-11-14 16:15:20 -0800568 # Upload prebuilts.
569 package_path = os.path.join(self._build_path, _HOST_PACKAGES_PATH)
570 self._UploadPrebuilt(package_path, packages_url_suffix)
David James8ece7ee2011-06-29 16:02:30 -0700571
David Jamese2488642011-11-14 16:15:20 -0800572 # Record URL where prebuilts were uploaded.
573 binhost_urls.append('%s/%s/' % (self._binhost_base_url.rstrip('/'),
574 packages_url_suffix.rstrip('/')))
575
David James20b2b6f2011-11-18 15:11:58 -0800576 binhost = ' '.join(binhost_urls)
David James8ece7ee2011-06-29 16:02:30 -0700577 if git_sync:
David Jamesb26b9312014-12-15 11:26:46 -0800578 git_file = os.path.join(self._build_path, _PREBUILT_MAKE_CONF[_HOST_ARCH])
Mike Frysinger86509232014-05-24 13:18:37 -0400579 RevGitFile(git_file, {key: binhost}, dryrun=self._dryrun)
David James8ece7ee2011-06-29 16:02:30 -0700580 if sync_binhost_conf:
David Jamesb26b9312014-12-15 11:26:46 -0800581 binhost_conf = os.path.join(
582 self._binhost_conf_dir, 'host', '%s-%s.conf' % (_HOST_ARCH, key))
David Jamese2488642011-11-14 16:15:20 -0800583 UpdateBinhostConfFile(binhost_conf, key, binhost)
David Jamesc0f158a2011-02-22 16:07:29 -0800584
Mike Frysinger8092a632014-05-24 13:25:46 -0400585 def SyncBoardPrebuilts(self, key, git_sync, sync_binhost_conf,
Mike Frysinger9e979b92012-11-29 02:55:09 -0500586 upload_board_tarball, prepackaged_board,
Gilad Arnold2b79e2d2015-06-02 11:26:07 -0700587 toolchains_overlay_tarballs,
588 toolchains_overlay_upload_path,
Mike Frysinger9e979b92012-11-29 02:55:09 -0500589 toolchain_tarballs, toolchain_upload_path):
David Jamesc0f158a2011-02-22 16:07:29 -0800590 """Synchronize board prebuilt files.
591
592 Args:
David Jamesc0f158a2011-02-22 16:07:29 -0800593 key: The variable key to update in the git file.
594 git_sync: If set, update make.conf of target to reference the latest
595 prebuilt packages generated here.
596 sync_binhost_conf: If set, update binhost config file in
597 chromiumos-overlay for the current board.
David James8fa34ea2011-04-15 13:00:20 -0700598 upload_board_tarball: Include a tarball of the board in our upload.
Zdenek Behan62a57792012-08-31 15:09:08 +0200599 prepackaged_board: A tarball of the board built outside of this script.
Gilad Arnold2b79e2d2015-06-02 11:26:07 -0700600 toolchains_overlay_tarballs: List of toolchains overlay tarball
601 specifications to upload. Items take the form
602 "toolchains_spec:/path/to/tarball".
603 toolchains_overlay_upload_path: Path template under the bucket to place
604 toolchains overlay tarballs.
Mike Frysinger9e979b92012-11-29 02:55:09 -0500605 toolchain_tarballs: A list of toolchain tarballs to upload.
606 toolchain_upload_path: Path under the bucket to place toolchain tarballs.
David Jamesc0f158a2011-02-22 16:07:29 -0800607 """
David Jamesb26b9312014-12-15 11:26:46 -0800608 updated_binhosts = set()
Chris Sosa6a5dceb2012-05-14 13:48:56 -0700609 for target in self._GetTargets():
David Jamese2488642011-11-14 16:15:20 -0800610 board_path = os.path.join(self._build_path,
David James4058b0d2011-12-08 21:24:50 -0800611 _BOARD_PATH % {'board': target.board_variant})
David Jamese2488642011-11-14 16:15:20 -0800612 package_path = os.path.join(board_path, 'packages')
Mike Frysinger8092a632014-05-24 13:25:46 -0400613 url_suffix = _REL_BOARD_PATH % {'target': target,
614 'version': self._version}
David Jamese2488642011-11-14 16:15:20 -0800615 packages_url_suffix = '%s/packages' % url_suffix.rstrip('/')
David James8fa34ea2011-04-15 13:00:20 -0700616
Matt Tennante8179042013-10-01 15:47:32 -0700617 # Process the target board differently if it is the main --board.
Mike Frysinger540883b2014-05-24 13:46:16 -0400618 if self._target == target and not self._skip_upload:
Matt Tennante8179042013-10-01 15:47:32 -0700619 # This strips "chroot" prefix because that is sometimes added as the
620 # --prepend-version argument (e.g. by chromiumos-sdk bot).
621 # TODO(build): Clean it up to be less hard-coded.
Mike Frysinger8092a632014-05-24 13:25:46 -0400622 version_str = self._version[len('chroot-'):]
Mike Frysinger9e979b92012-11-29 02:55:09 -0500623
David Jamese2488642011-11-14 16:15:20 -0800624 # Upload board tarballs in the background.
625 if upload_board_tarball:
Mike Frysinger9e979b92012-11-29 02:55:09 -0500626 if toolchain_upload_path:
627 toolchain_upload_path %= {'version': version_str}
Gilad Arnold2b79e2d2015-06-02 11:26:07 -0700628 if toolchains_overlay_upload_path:
629 toolchains_overlay_upload_path %= {'version': version_str}
Mike Frysinger9e979b92012-11-29 02:55:09 -0500630 tar_process = multiprocessing.Process(
631 target=self._UploadSdkTarball,
Mike Frysinger8092a632014-05-24 13:25:46 -0400632 args=(board_path, url_suffix, prepackaged_board,
Gilad Arnold2b79e2d2015-06-02 11:26:07 -0700633 toolchains_overlay_tarballs,
634 toolchains_overlay_upload_path, toolchain_tarballs,
635 toolchain_upload_path))
David Jamese2488642011-11-14 16:15:20 -0800636 tar_process.start()
David James8fa34ea2011-04-15 13:00:20 -0700637
David Jamese2488642011-11-14 16:15:20 -0800638 # Upload prebuilts.
639 self._UploadPrebuilt(package_path, packages_url_suffix)
David James8fa34ea2011-04-15 13:00:20 -0700640
David Jamese2488642011-11-14 16:15:20 -0800641 # Make sure we finished uploading the board tarballs.
642 if upload_board_tarball:
643 tar_process.join()
644 assert tar_process.exitcode == 0
David Jamesc0f158a2011-02-22 16:07:29 -0800645
David Jamese2488642011-11-14 16:15:20 -0800646 # Record URL where prebuilts were uploaded.
647 url_value = '%s/%s/' % (self._binhost_base_url.rstrip('/'),
648 packages_url_suffix.rstrip('/'))
649
650 if git_sync:
David James4058b0d2011-12-08 21:24:50 -0800651 git_file = DeterminePrebuiltConfFile(self._build_path, target)
Mike Frysinger86509232014-05-24 13:18:37 -0400652 RevGitFile(git_file, {key: url_value}, dryrun=self._dryrun)
Matt Tennante8179042013-10-01 15:47:32 -0700653
David Jamese2488642011-11-14 16:15:20 -0800654 if sync_binhost_conf:
Matt Tennante8179042013-10-01 15:47:32 -0700655 # Update the binhost configuration file in git.
David Jamesb26b9312014-12-15 11:26:46 -0800656 binhost_conf = os.path.join(
657 self._binhost_conf_dir, 'target', '%s-%s.conf' % (target, key))
658 updated_binhosts.add(binhost_conf)
David Jamese2488642011-11-14 16:15:20 -0800659 UpdateBinhostConfFile(binhost_conf, key, url_value)
David James05bcb2b2011-02-09 09:25:47 -0800660
David Jamesb26b9312014-12-15 11:26:46 -0800661 if sync_binhost_conf:
662 # Clear all old binhosts. The files must be left empty in case anybody
663 # is referring to them.
664 all_binhosts = set(glob.glob(os.path.join(
665 self._binhost_conf_dir, 'target', '*-%s.conf' % key)))
666 for binhost_conf in all_binhosts - updated_binhosts:
667 UpdateBinhostConfFile(binhost_conf, key, '')
668
David James05bcb2b2011-02-09 09:25:47 -0800669
Mike Nicholsa1414162021-04-22 20:07:22 +0000670class _AddSlaveBoardAction(argparse.Action):
671 """Callback that adds a slave board to the list of slave targets."""
Mike Frysingerb87bb782015-06-04 02:46:50 -0400672 def __call__(self, parser, namespace, values, option_string=None):
673 getattr(namespace, self.dest).append(BuildTarget(values))
David James4058b0d2011-12-08 21:24:50 -0800674
675
Mike Nicholsa1414162021-04-22 20:07:22 +0000676class _AddSlaveProfileAction(argparse.Action):
677 """Callback that adds a slave profile to the list of slave targets."""
Mike Frysingerb87bb782015-06-04 02:46:50 -0400678 def __call__(self, parser, namespace, values, option_string=None):
679 if not namespace.slave_targets:
680 parser.error('Must specify --slave-board before --slave-profile')
681 if namespace.slave_targets[-1].profile is not None:
682 parser.error('Cannot specify --slave-profile twice for same board')
683 namespace.slave_targets[-1].profile = values
David James4058b0d2011-12-08 21:24:50 -0800684
685
Mike Frysinger86509232014-05-24 13:18:37 -0400686def ParseOptions(argv):
Chris Sosa6a5dceb2012-05-14 13:48:56 -0700687 """Returns options given by the user and the target specified.
688
Mike Frysinger86509232014-05-24 13:18:37 -0400689 Args:
690 argv: The args to parse.
691
Mike Frysinger1a736a82013-12-12 01:50:59 -0500692 Returns:
693 A tuple containing a parsed options object and BuildTarget.
694 The target instance is None if no board is specified.
Chris Sosa6a5dceb2012-05-14 13:48:56 -0700695 """
Mike Frysingerb87bb782015-06-04 02:46:50 -0400696 parser = commandline.ArgumentParser()
697 parser.add_argument('-H', '--binhost-base-url', default=_BINHOST_BASE_URL,
698 help='Base URL to use for binhost in make.conf updates')
699 parser.add_argument('--previous-binhost-url', action='append', default=[],
700 help='Previous binhost URL')
701 parser.add_argument('-b', '--board',
702 help='Board type that was built on this machine')
703 parser.add_argument('-B', '--prepackaged-tarball', type='path',
704 help='Board tarball prebuilt outside of this script.')
Gilad Arnold2b79e2d2015-06-02 11:26:07 -0700705 parser.add_argument('--toolchains-overlay-tarball',
706 dest='toolchains_overlay_tarballs',
Mike Frysingerb87bb782015-06-04 02:46:50 -0400707 action='append', default=[],
Gilad Arnold2b79e2d2015-06-02 11:26:07 -0700708 help='Toolchains overlay tarball specification to '
709 'upload. Takes the form '
710 '"toolchains_spec:/path/to/tarball".')
711 parser.add_argument('--toolchains-overlay-upload-path', default='',
712 help='Path template for uploading toolchains overlays.')
Mike Frysingerb87bb782015-06-04 02:46:50 -0400713 parser.add_argument('--toolchain-tarball', dest='toolchain_tarballs',
714 action='append', default=[],
715 help='Redistributable toolchain tarball.')
Gilad Arnold2b79e2d2015-06-02 11:26:07 -0700716 parser.add_argument('--toolchain-upload-path', default='',
Mike Frysingerb87bb782015-06-04 02:46:50 -0400717 help='Path to place toolchain tarballs in the sdk tree.')
718 parser.add_argument('--profile',
719 help='Profile that was built on this machine')
Mike Nicholsa1414162021-04-22 20:07:22 +0000720 parser.add_argument('--slave-board', default=[], action=_AddSlaveBoardAction,
Mike Frysingerb87bb782015-06-04 02:46:50 -0400721 dest='slave_targets',
722 help='Board type that was built on a slave machine. To '
723 'add a profile to this board, use --slave-profile.')
Mike Nicholsa1414162021-04-22 20:07:22 +0000724 parser.add_argument('--slave-profile', action=_AddSlaveProfileAction,
Mike Frysingerb87bb782015-06-04 02:46:50 -0400725 help='Board profile that was built on a slave machine. '
726 'Applies to previous slave board.')
727 parser.add_argument('-p', '--build-path', required=True,
728 help='Path to the directory containing the chroot')
729 parser.add_argument('--packages', action='append', default=[],
730 help='Only include the specified packages. '
731 '(Default is to include all packages.)')
732 parser.add_argument('-s', '--sync-host', default=False, action='store_true',
733 help='Sync host prebuilts')
734 parser.add_argument('-g', '--git-sync', default=False, action='store_true',
735 help='Enable git version sync (This commits to a repo.) '
736 'This is used by full builders to commit directly '
737 'to board overlays.')
738 parser.add_argument('-u', '--upload',
739 help='Upload location')
740 parser.add_argument('-V', '--prepend-version',
741 help='Add an identifier to the front of the version')
742 parser.add_argument('-f', '--filters', action='store_true', default=False,
743 help='Turn on filtering of private ebuild packages')
744 parser.add_argument('-k', '--key', default='PORTAGE_BINHOST',
745 help='Key to update in make.conf / binhost.conf')
746 parser.add_argument('--set-version',
747 help='Specify the version string')
748 parser.add_argument('--sync-binhost-conf', default=False, action='store_true',
749 help='Update binhost.conf in chromiumos-overlay or '
Mike Frysinger80de5012019-08-01 14:10:53 -0400750 "chromeos-overlay. Commit the changes, but don't "
Mike Frysingerb87bb782015-06-04 02:46:50 -0400751 'push them. This is used for preflight binhosts.')
752 parser.add_argument('--binhost-conf-dir',
753 help='Directory to commit binhost config with '
754 '--sync-binhost-conf.')
755 parser.add_argument('-P', '--private', action='store_true', default=False,
756 help='Mark gs:// uploads as private.')
757 parser.add_argument('--skip-upload', action='store_true', default=False,
758 help='Skip upload step.')
759 parser.add_argument('--upload-board-tarball', action='store_true',
760 default=False,
761 help='Upload board tarball to Google Storage.')
762 parser.add_argument('-n', '--dry-run', dest='dryrun',
763 action='store_true', default=False,
Mike Frysinger80de5012019-08-01 14:10:53 -0400764 help="Don't push or upload prebuilts.")
David James8c846492011-01-25 17:07:29 -0800765
Mike Frysingerb87bb782015-06-04 02:46:50 -0400766 options = parser.parse_args(argv)
David James8ece7ee2011-06-29 16:02:30 -0700767 if not options.upload and not options.skip_upload:
Mike Frysinger86509232014-05-24 13:18:37 -0400768 parser.error('you need to provide an upload location using -u')
David James8ece7ee2011-06-29 16:02:30 -0700769 if not options.set_version and options.skip_upload:
Mike Frysinger86509232014-05-24 13:18:37 -0400770 parser.error('If you are using --skip-upload, you must specify a '
771 'version number using --set-version.')
Scott Zawalskiab1bed32011-03-16 15:24:24 -0700772
Chris Sosa6a5dceb2012-05-14 13:48:56 -0700773 target = None
774 if options.board:
775 target = BuildTarget(options.board, options.profile)
776
777 if target in options.slave_targets:
Mike Frysinger86509232014-05-24 13:18:37 -0400778 parser.error('--board/--profile must not also be a slave target.')
David Jamese2488642011-11-14 16:15:20 -0800779
David James4058b0d2011-12-08 21:24:50 -0800780 if len(set(options.slave_targets)) != len(options.slave_targets):
Mike Frysinger86509232014-05-24 13:18:37 -0400781 parser.error('--slave-boards must not have duplicates.')
David Jamese2488642011-11-14 16:15:20 -0800782
David James4058b0d2011-12-08 21:24:50 -0800783 if options.slave_targets and options.git_sync:
Mike Frysinger86509232014-05-24 13:18:37 -0400784 parser.error('--slave-boards is not compatible with --git-sync')
David Jamese2488642011-11-14 16:15:20 -0800785
David James8ece7ee2011-06-29 16:02:30 -0700786 if (options.upload_board_tarball and options.skip_upload and
787 options.board == 'amd64-host'):
Mike Frysinger86509232014-05-24 13:18:37 -0400788 parser.error('--skip-upload is not compatible with '
789 '--upload-board-tarball and --board=amd64-host')
David James8fa34ea2011-04-15 13:00:20 -0700790
David James8ece7ee2011-06-29 16:02:30 -0700791 if (options.upload_board_tarball and not options.skip_upload and
792 not options.upload.startswith('gs://')):
Mike Frysinger86509232014-05-24 13:18:37 -0400793 parser.error('--upload-board-tarball only works with gs:// URLs.\n'
794 '--upload must be a gs:// URL.')
David James8fa34ea2011-04-15 13:00:20 -0700795
Zdenek Behan86c15e92012-10-13 00:55:47 +0200796 if options.upload_board_tarball and options.prepackaged_tarball is None:
Mike Frysinger86509232014-05-24 13:18:37 -0400797 parser.error('--upload-board-tarball requires --prepackaged-tarball')
Zdenek Behan86c15e92012-10-13 00:55:47 +0200798
Scott Zawalskiab1bed32011-03-16 15:24:24 -0700799 if options.private:
800 if options.sync_host:
Mike Frysinger86509232014-05-24 13:18:37 -0400801 parser.error('--private and --sync-host/-s cannot be specified '
802 'together; we do not support private host prebuilts')
Scott Zawalskiab1bed32011-03-16 15:24:24 -0700803
David James8ece7ee2011-06-29 16:02:30 -0700804 if not options.upload or not options.upload.startswith('gs://'):
Mike Frysinger86509232014-05-24 13:18:37 -0400805 parser.error('--private is only valid for gs:// URLs; '
806 '--upload must be a gs:// URL.')
Scott Zawalskiab1bed32011-03-16 15:24:24 -0700807
808 if options.binhost_base_url != _BINHOST_BASE_URL:
Mike Frysinger86509232014-05-24 13:18:37 -0400809 parser.error('when using --private the --binhost-base-url '
810 'is automatically derived.')
David James27fa7d12011-06-29 17:24:14 -0700811
David Jamesc31168e2014-06-05 14:40:05 -0700812 if options.sync_binhost_conf and not options.binhost_conf_dir:
813 parser.error('--sync-binhost-conf requires --binhost-conf-dir')
814
Gilad Arnold2b79e2d2015-06-02 11:26:07 -0700815 if (options.toolchains_overlay_tarballs and
816 not options.toolchains_overlay_upload_path):
817 parser.error('--toolchains-overlay-tarball requires '
818 '--toolchains-overlay-upload-path')
Gilad Arnoldad333182015-05-27 15:50:41 -0700819
Chris Sosa6a5dceb2012-05-14 13:48:56 -0700820 return options, target
David Jamesc0f158a2011-02-22 16:07:29 -0800821
Mike Frysingercc838832014-05-24 13:10:30 -0400822
Mike Frysinger86509232014-05-24 13:18:37 -0400823def main(argv):
David Jamesdb401072011-06-10 12:17:16 -0700824 # Set umask to a sane value so that files created as root are readable.
Mike Frysinger60ec1012013-10-21 00:11:10 -0400825 os.umask(0o22)
David Jamesdb401072011-06-10 12:17:16 -0700826
Mike Frysinger86509232014-05-24 13:18:37 -0400827 options, target = ParseOptions(argv)
David Jamesc0f158a2011-02-22 16:07:29 -0800828
David James05bcb2b2011-02-09 09:25:47 -0800829 # Calculate a list of Packages index files to compare against. Whenever we
830 # upload a package, we check to make sure it's not already stored in one of
831 # the packages files we uploaded. This list of packages files might contain
832 # both board and host packages.
David Jamesce093af2011-02-23 15:21:58 -0800833 pkg_indexes = _GrabAllRemotePackageIndexes(options.previous_binhost_url)
David James8c846492011-01-25 17:07:29 -0800834
David James8ece7ee2011-06-29 16:02:30 -0700835 if options.set_version:
836 version = options.set_version
837 else:
838 version = GetVersion()
Matt Tennante8179042013-10-01 15:47:32 -0700839
David Jamesc0f158a2011-02-22 16:07:29 -0800840 if options.prepend_version:
841 version = '%s-%s' % (options.prepend_version, version)
842
Scott Zawalskiab1bed32011-03-16 15:24:24 -0700843 acl = 'public-read'
844 binhost_base_url = options.binhost_base_url
845
David Jamesadd21432013-05-21 10:04:07 -0700846 if options.private:
Scott Zawalskiab1bed32011-03-16 15:24:24 -0700847 binhost_base_url = options.upload
David Jamesadd21432013-05-21 10:04:07 -0700848 if target:
Prathmesh Prabhu421eef22014-10-16 17:13:19 -0700849 acl = portage_util.FindOverlayFile(_GOOGLESTORAGE_GSUTIL_FILE,
850 board=target.board_variant,
851 buildroot=options.build_path)
Ben Chan067de492015-01-06 17:19:13 -0800852 if acl is None:
853 cros_build_lib.Die('No Google Storage ACL file %s found in %s overlay.',
854 _GOOGLESTORAGE_GSUTIL_FILE, target.board_variant)
Scott Zawalskiab1bed32011-03-16 15:24:24 -0700855
David Jamesb26b9312014-12-15 11:26:46 -0800856 binhost_conf_dir = None
857 if options.binhost_conf_dir:
858 binhost_conf_dir = os.path.join(options.build_path,
859 options.binhost_conf_dir)
860
Scott Zawalskiab1bed32011-03-16 15:24:24 -0700861 uploader = PrebuiltUploader(options.upload, acl, binhost_base_url,
David James615e5b52011-06-03 11:10:15 -0700862 pkg_indexes, options.build_path,
David James27fa7d12011-06-29 17:24:14 -0700863 options.packages, options.skip_upload,
David Jamesb26b9312014-12-15 11:26:46 -0800864 binhost_conf_dir, options.dryrun,
Mike Frysinger8092a632014-05-24 13:25:46 -0400865 target, options.slave_targets, version)
David Jamesc0f158a2011-02-22 16:07:29 -0800866
David James8c846492011-01-25 17:07:29 -0800867 if options.sync_host:
Mike Frysinger8092a632014-05-24 13:25:46 -0400868 uploader.SyncHostPrebuilts(options.key, options.git_sync,
Chris Sosa6a5dceb2012-05-14 13:48:56 -0700869 options.sync_binhost_conf)
David James8c846492011-01-25 17:07:29 -0800870
Chris Sosa62c8ff52012-06-04 15:03:12 -0700871 if options.board or options.slave_targets:
Mike Frysinger8092a632014-05-24 13:25:46 -0400872 uploader.SyncBoardPrebuilts(options.key, options.git_sync,
Chris Sosa6a5dceb2012-05-14 13:48:56 -0700873 options.sync_binhost_conf,
Zdenek Behan62a57792012-08-31 15:09:08 +0200874 options.upload_board_tarball,
Mike Frysinger9e979b92012-11-29 02:55:09 -0500875 options.prepackaged_tarball,
Gilad Arnold2b79e2d2015-06-02 11:26:07 -0700876 options.toolchains_overlay_tarballs,
877 options.toolchains_overlay_upload_path,
Mike Frysinger9e979b92012-11-29 02:55:09 -0500878 options.toolchain_tarballs,
879 options.toolchain_upload_path)