blob: e998d112cf631b1b7aaa713ef789a5298a942ea2 [file] [log] [blame]
Mike Frysingerf1ba7ad2022-09-12 05:42:57 -04001# Copyright 2012 The ChromiumOS Authors
David James8c846492011-01-25 17:07:29 -08002# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
Brian Harringaf019fb2012-05-10 15:06:13 -07005"""This script is used to upload host prebuilts as well as board BINHOSTS.
David James8c846492011-01-25 17:07:29 -08006
David James015af872012-06-19 15:24:36 -07007Prebuilts are uploaded using gsutil to Google Storage. After these prebuilts
8are successfully uploaded, a file is updated with the proper BINHOST version.
David James8c846492011-01-25 17:07:29 -08009
10To read more about prebuilts/binhost binary packages please refer to:
David James015af872012-06-19 15:24:36 -070011http://goto/chromeos-prebuilts
David James8c846492011-01-25 17:07:29 -080012
13Example of uploading prebuilt amd64 host files to Google Storage:
Mike Nicholsd0acc7f2021-05-21 17:18:24 +000014upload_prebuilts -p /b/cbuild/build -s -u gs://chromeos-prebuilt
David James8c846492011-01-25 17:07:29 -080015
16Example of uploading x86-dogfood binhosts to Google Storage:
Mike Nicholsd0acc7f2021-05-21 17:18:24 +000017upload_prebuilts -b x86-dogfood -p /b/cbuild/build/ -u gs://chromeos-prebuilt -g
David James8c846492011-01-25 17:07:29 -080018"""
19
Mike Frysingerb87bb782015-06-04 02:46:50 -040020import argparse
Chris Sosa1dc96132012-05-11 15:40:50 -070021import datetime
Mike Frysinger540883b2014-05-24 13:46:16 -040022import functools
David Jamesb26b9312014-12-15 11:26:46 -080023import glob
Chris McDonaldb55b7032021-06-17 16:41:32 -060024import logging
Chris Sosa1dc96132012-05-11 15:40:50 -070025import multiprocessing
Chris Sosa1dc96132012-05-11 15:40:50 -070026import os
Mike Frysinger212e4292014-05-24 15:15:44 -040027import tempfile
Chris Sosa1dc96132012-05-11 15:40:50 -070028
Chris McDonaldb55b7032021-06-17 16:41:32 -060029from chromite.cbuildbot import cbuildbot_alerts
David James14e97772014-06-04 18:44:49 -070030from chromite.cbuildbot import commands
David James6450a0a2012-12-04 07:59:53 -080031from chromite.lib import binpkg
Mike Frysinger86509232014-05-24 13:18:37 -040032from chromite.lib import commandline
Chris McDonaldb55b7032021-06-17 16:41:32 -060033from chromite.lib import constants
Chris Sosa1dc96132012-05-11 15:40:50 -070034from chromite.lib import cros_build_lib
Julio Hurtadofad17992021-05-20 21:24:24 +000035from chromite.lib import gerrit
Mike Frysinger807d8282022-04-28 22:45:17 -040036from chromite.lib import git
Brian Harring7904b482012-08-08 02:54:12 -070037from chromite.lib import gs
Brian Harringaf019fb2012-05-10 15:06:13 -070038from chromite.lib import osutils
David James6450a0a2012-12-04 07:59:53 -080039from chromite.lib import parallel
Alex Deymo075c2292014-09-04 18:31:50 -070040from chromite.lib import portage_util
Mike Frysinger8e727a32013-01-16 16:57:53 -050041from chromite.lib import toolchain
Alex Klein18a60af2020-06-11 12:08:47 -060042from chromite.lib.parser import package_info
Chris Sosa1dc96132012-05-11 15:40:50 -070043
Mike Frysinger72b7cf92020-04-19 06:00:51 -040044
David James015af872012-06-19 15:24:36 -070045# How many times to retry uploads.
46_RETRIES = 10
47
48# Multiplier for how long to sleep (in seconds) between retries; will delay
49# (1*sleep) the first time, then (2*sleep), continuing via attempt * sleep.
50_SLEEP_TIME = 60
51
David James5ab67e32014-10-24 08:19:59 -070052# The length of time (in seconds) that Portage should wait before refetching
53# binpkgs from the same binhost. We don't ever modify binhosts, so this should
54# be something big.
55_BINPKG_TTL = 60 * 60 * 24 * 365
56
Alex Klein1699fab2022-09-08 08:46:06 -060057_HOST_PACKAGES_PATH = "var/lib/portage/pkgs"
58_CATEGORIES_PATH = "chroot/etc/portage/categories"
59_PYM_PATH = "chroot/usr/lib/portage/pym"
60_HOST_ARCH = "amd64"
61_BOARD_PATH = "chroot/build/%(board)s"
62_REL_BOARD_PATH = "board/%(target)s/%(version)s"
63_REL_HOST_PATH = "host/%(host_arch)s/%(target)s/%(version)s"
David James8c846492011-01-25 17:07:29 -080064# Private overlays to look at for builds to filter
65# relative to build path
Alex Klein1699fab2022-09-08 08:46:06 -060066_PRIVATE_OVERLAY_DIR = "src/private-overlays"
67_GOOGLESTORAGE_GSUTIL_FILE = "googlestorage_acl.txt"
68_BINHOST_BASE_URL = "gs://chromeos-prebuilt"
69_PREBUILT_BASE_DIR = "src/third_party/chromiumos-overlay/chromeos/config/"
David James8c846492011-01-25 17:07:29 -080070# Created in the event of new host targets becoming available
Alex Klein1699fab2022-09-08 08:46:06 -060071_PREBUILT_MAKE_CONF = {
72 "amd64": os.path.join(_PREBUILT_BASE_DIR, "make.conf.amd64-host")
73}
David James8c846492011-01-25 17:07:29 -080074
75
David James4058b0d2011-12-08 21:24:50 -080076class BuildTarget(object):
Alex Klein1699fab2022-09-08 08:46:06 -060077 """A board/variant/profile tuple."""
David James4058b0d2011-12-08 21:24:50 -080078
Alex Klein1699fab2022-09-08 08:46:06 -060079 def __init__(self, board_variant, profile=None):
80 self.board_variant = board_variant
81 self.board, _, self.variant = board_variant.partition("_")
82 self.profile = profile
David James4058b0d2011-12-08 21:24:50 -080083
Alex Klein1699fab2022-09-08 08:46:06 -060084 def __str__(self):
85 if self.profile:
86 return "%s_%s" % (self.board_variant, self.profile)
87 else:
88 return self.board_variant
David James4058b0d2011-12-08 21:24:50 -080089
Alex Klein1699fab2022-09-08 08:46:06 -060090 def __eq__(self, other):
91 return str(other) == str(self)
David James4058b0d2011-12-08 21:24:50 -080092
Alex Klein1699fab2022-09-08 08:46:06 -060093 def __hash__(self):
94 return hash(str(self))
David James4058b0d2011-12-08 21:24:50 -080095
96
Alex Klein1699fab2022-09-08 08:46:06 -060097def UpdateLocalFile(filename, value, key="PORTAGE_BINHOST"):
98 """Update the key in file with the value passed.
Mike Frysinger1a736a82013-12-12 01:50:59 -050099
Alex Klein1699fab2022-09-08 08:46:06 -0600100 File format:
101 key="value"
102 Note quotes are added automatically
David James8c846492011-01-25 17:07:29 -0800103
Alex Klein1699fab2022-09-08 08:46:06 -0600104 Args:
105 filename: Name of file to modify.
106 value: Value to write with the key.
107 key: The variable key to update. (Default: PORTAGE_BINHOST)
David Jamesb26b9312014-12-15 11:26:46 -0800108
Alex Klein1699fab2022-09-08 08:46:06 -0600109 Returns:
110 True if changes were made to the file.
111 """
Sergey Frolov09280f12022-06-06 17:47:32 -0600112
Alex Klein1699fab2022-09-08 08:46:06 -0600113 keyval_str = "%(key)s=%(value)s"
Sergey Frolov09280f12022-06-06 17:47:32 -0600114
Alex Klein1699fab2022-09-08 08:46:06 -0600115 # Add quotes around the value, if missing.
116 if not value or value[0] != '"' or value[-1] != '"':
117 value = f'"{value}"'
Sergey Frolov09280f12022-06-06 17:47:32 -0600118
Alex Klein1699fab2022-09-08 08:46:06 -0600119 # new_lines is the content to be used to overwrite/create the config file
120 # at the end of this function.
121 made_changes = False
122 new_lines = []
Sergey Frolov09280f12022-06-06 17:47:32 -0600123
Alex Klein1699fab2022-09-08 08:46:06 -0600124 # Read current lines.
125 try:
126 current_lines = osutils.ReadFile(filename).splitlines()
127 except FileNotFoundError:
128 current_lines = []
129 print(f"Creating new file {filename}")
Sergey Frolov09280f12022-06-06 17:47:32 -0600130
Alex Klein1699fab2022-09-08 08:46:06 -0600131 # Scan current lines, copy all vars to new_lines, change the line with |key|.
132 found = False
133 for line in current_lines:
134 # Strip newlines from end of line. We already add newlines below.
135 line = line.rstrip("\n")
136 if len(line.split("=")) != 2:
137 # Skip any line that doesn't fit key=val.
138 new_lines.append(line)
139 continue
140 file_var, file_val = line.split("=")
141 if file_var == key:
142 found = True
143 print(f"Updating {file_var}={file_val} to {key}={value}")
144 made_changes |= file_val != value
145 new_lines.append(keyval_str % {"key": key, "value": value})
146 else:
147 new_lines.append(keyval_str % {"key": file_var, "value": file_val})
148 if not found:
149 print(f"Adding new variable {key}={value}")
150 made_changes = True
151 new_lines.append(keyval_str % {"key": key, "value": value})
Jack Neusf30f6722022-06-09 16:23:49 +0000152
Alex Klein1699fab2022-09-08 08:46:06 -0600153 # Write out new file.
154 osutils.WriteFile(filename, "\n".join(new_lines) + "\n")
155 return made_changes
David James8c846492011-01-25 17:07:29 -0800156
157
Mike Nicholsa6818c52018-04-09 11:05:42 -0600158def RevGitFile(filename, data, dryrun=False):
Alex Klein1699fab2022-09-08 08:46:06 -0600159 """Update and push the git file.
David James8c846492011-01-25 17:07:29 -0800160
Alex Klein1699fab2022-09-08 08:46:06 -0600161 Args:
162 filename: file to modify that is in a git repo already
163 data: A dict of key/values to update in |filename|
164 dryrun: If True, do not actually commit the change.
165 """
166 prebuilt_branch = "prebuilt_branch"
167 cwd = os.path.abspath(os.path.dirname(filename))
168 remote_name = git.RunGit(cwd, ["remote"]).stdout.strip()
169 gerrit_helper = gerrit.GetGerritHelper(remote_name)
170 remote_url = git.RunGit(
171 cwd, ["config", "--get", f"remote.{remote_name}.url"]
172 ).stdout.strip()
173 description = "%s: updating %s" % (
174 os.path.basename(filename),
175 ", ".join(data.keys()),
176 )
177 # UpdateLocalFile will print out the keys/values for us.
178 print("Revving git file %s" % filename)
179 git.CreatePushBranch(prebuilt_branch, cwd)
180 for key, value in data.items():
181 UpdateLocalFile(filename, value, key)
182 git.RunGit(cwd, ["add", filename])
183 git.RunGit(cwd, ["commit", "-m", description])
Julio Hurtado2d4817d2021-04-29 16:03:58 +0000184
Alex Klein1699fab2022-09-08 08:46:06 -0600185 tracking_info = git.GetTrackingBranch(
186 cwd, prebuilt_branch, for_push=True, for_checkout=False
187 )
188 gpatch = gerrit_helper.CreateGerritPatch(
189 cwd, remote_url, ref=tracking_info.ref, notify="NONE"
190 )
191 gerrit_helper.SetReview(
192 gpatch, labels={"Bot-Commit": 1}, dryrun=dryrun, notify="NONE"
193 )
194 gerrit_helper.SubmitChange(gpatch, dryrun=dryrun, notify="NONE")
David James8c846492011-01-25 17:07:29 -0800195
196
197def GetVersion():
Alex Klein1699fab2022-09-08 08:46:06 -0600198 """Get the version to put in LATEST and update the git version with."""
199 return datetime.datetime.now().strftime("%Y.%m.%d.%H%M%S")
David James8c846492011-01-25 17:07:29 -0800200
201
Mike Frysinger540883b2014-05-24 13:46:16 -0400202def _GsUpload(gs_context, acl, local_file, remote_file):
Alex Klein1699fab2022-09-08 08:46:06 -0600203 """Upload to GS bucket.
David James8c846492011-01-25 17:07:29 -0800204
Alex Klein1699fab2022-09-08 08:46:06 -0600205 Args:
206 gs_context: A lib.gs.GSContext instance.
207 acl: The ACL to use for uploading the file.
208 local_file: The local file to be uploaded.
209 remote_file: The remote location to upload to.
210 """
211 CANNED_ACLS = [
212 "public-read",
213 "private",
214 "bucket-owner-read",
215 "authenticated-read",
216 "bucket-owner-full-control",
217 "public-read-write",
218 ]
219 if acl in CANNED_ACLS:
220 gs_context.Copy(local_file, remote_file, acl=acl)
Gabe Black40169e62014-06-17 15:23:47 -0700221 else:
Alex Klein1699fab2022-09-08 08:46:06 -0600222 # For private uploads we assume that the overlay board is set up properly
223 # and a googlestore_acl.xml is present. Otherwise, this script errors.
224 # We set version=0 here to ensure that the ACL is set only once (see
225 # http://b/15883752#comment54).
226 try:
227 gs_context.Copy(local_file, remote_file, version=0)
228 except gs.GSContextPreconditionFailed as ex:
229 # If we received a GSContextPreconditionFailed error, we know that the
230 # file exists now, but we don't know whether our specific update
231 # succeeded. See http://b/15883752#comment62
232 logging.warning(
233 "Assuming upload succeeded despite PreconditionFailed errors: %s",
234 ex,
235 )
236
237 if acl.endswith(".xml"):
238 # Apply the passed in ACL xml file to the uploaded object.
239 gs_context.SetACL(remote_file, acl=acl)
240 else:
241 gs_context.ChangeACL(remote_file, acl_args_file=acl)
Scott Zawalskiab1bed32011-03-16 15:24:24 -0700242
Mike Frysingercc838832014-05-24 13:10:30 -0400243
Mike Frysinger540883b2014-05-24 13:46:16 -0400244def RemoteUpload(gs_context, acl, files, pool=10):
Alex Klein1699fab2022-09-08 08:46:06 -0600245 """Upload to google storage.
David James8c846492011-01-25 17:07:29 -0800246
Alex Klein1699fab2022-09-08 08:46:06 -0600247 Create a pool of process and call _GsUpload with the proper arguments.
David James8c846492011-01-25 17:07:29 -0800248
Alex Klein1699fab2022-09-08 08:46:06 -0600249 Args:
250 gs_context: A lib.gs.GSContext instance.
251 acl: The canned acl used for uploading. acl can be one of: "public-read",
252 "public-read-write", "authenticated-read", "bucket-owner-read",
253 "bucket-owner-full-control", or "private".
254 files: dictionary with keys to local files and values to remote path.
255 pool: integer of maximum proesses to have at the same time.
David James8c846492011-01-25 17:07:29 -0800256
Alex Klein1699fab2022-09-08 08:46:06 -0600257 Returns:
258 Return a set of tuple arguments of the failed uploads
259 """
260 upload = functools.partial(_GsUpload, gs_context, acl)
261 tasks = [[key, value] for key, value in files.items()]
262 parallel.RunTasksInProcessPool(upload, tasks, pool)
David James8c846492011-01-25 17:07:29 -0800263
264
265def GenerateUploadDict(base_local_path, base_remote_path, pkgs):
Alex Klein1699fab2022-09-08 08:46:06 -0600266 """Build a dictionary of local remote file key pairs to upload.
David James8c846492011-01-25 17:07:29 -0800267
Alex Klein1699fab2022-09-08 08:46:06 -0600268 Args:
269 base_local_path: The base path to the files on the local hard drive.
270 base_remote_path: The base path to the remote paths.
271 pkgs: The packages to upload.
David James8c846492011-01-25 17:07:29 -0800272
Alex Klein1699fab2022-09-08 08:46:06 -0600273 Returns:
274 Returns a dictionary of local_path/remote_path pairs
275 """
276 upload_files = {}
277 for pkg in pkgs:
278 suffix = pkg["CPV"] + ".tbz2"
279 local_path = os.path.join(base_local_path, suffix)
280 assert os.path.exists(local_path), "%s does not exist" % local_path
281 upload_files[local_path] = os.path.join(base_remote_path, suffix)
David James8c846492011-01-25 17:07:29 -0800282
Alex Klein1699fab2022-09-08 08:46:06 -0600283 if pkg.get("DEBUG_SYMBOLS") == "yes":
284 debugsuffix = pkg["CPV"] + ".debug.tbz2"
285 local_path = os.path.join(base_local_path, debugsuffix)
286 assert os.path.exists(local_path)
287 upload_files[local_path] = os.path.join(
288 base_remote_path, debugsuffix
289 )
Bertrand SIMONNET22e828b2014-11-11 16:27:06 -0800290
Alex Klein1699fab2022-09-08 08:46:06 -0600291 return upload_files
David James8c846492011-01-25 17:07:29 -0800292
Mike Frysingercc838832014-05-24 13:10:30 -0400293
Peter Mayo950e41a2014-02-06 21:07:33 +0000294def GetBoardOverlay(build_path, target):
Alex Klein1699fab2022-09-08 08:46:06 -0600295 """Get the path to the board variant.
Mike Frysinger1a736a82013-12-12 01:50:59 -0500296
Alex Klein1699fab2022-09-08 08:46:06 -0600297 Args:
298 build_path: The path to the root of the build directory
299 target: The target board as a BuildTarget object.
Mike Frysinger1a736a82013-12-12 01:50:59 -0500300
Alex Klein1699fab2022-09-08 08:46:06 -0600301 Returns:
302 The last overlay configured for the given board as a string.
303 """
304 board = target.board_variant
305 overlays = portage_util.FindOverlays(
306 constants.BOTH_OVERLAYS, board, buildroot=build_path
307 )
308 # We only care about the last entry.
309 return overlays[-1]
David James8c846492011-01-25 17:07:29 -0800310
311
312def DeterminePrebuiltConfFile(build_path, target):
Alex Klein1699fab2022-09-08 08:46:06 -0600313 """Determine the prebuilt.conf file that needs to be updated for prebuilts.
David James8c846492011-01-25 17:07:29 -0800314
Alex Klein1699fab2022-09-08 08:46:06 -0600315 Args:
316 build_path: The path to the root of the build directory
317 target: String representation of the board. This includes host and board
318 targets
David James8c846492011-01-25 17:07:29 -0800319
Alex Klein1699fab2022-09-08 08:46:06 -0600320 Returns:
321 A string path to a prebuilt.conf file to be updated.
322 """
323 if _HOST_ARCH == target:
324 # We are host.
325 # Without more examples of hosts this is a kludge for now.
326 # TODO(Scottz): as new host targets come online expand this to
327 # work more like boards.
328 make_path = _PREBUILT_MAKE_CONF[target]
329 else:
330 # We are a board
331 board = GetBoardOverlay(build_path, target)
332 make_path = os.path.join(board, "prebuilt.conf")
David James8c846492011-01-25 17:07:29 -0800333
Alex Klein1699fab2022-09-08 08:46:06 -0600334 return make_path
David James8c846492011-01-25 17:07:29 -0800335
336
337def UpdateBinhostConfFile(path, key, value):
Alex Klein1699fab2022-09-08 08:46:06 -0600338 """Update binhost config file file with key=value.
David James8c846492011-01-25 17:07:29 -0800339
Alex Klein1699fab2022-09-08 08:46:06 -0600340 Args:
341 path: Filename to update.
342 key: Key to update.
343 value: New value for key.
344 """
345 cwd, filename = os.path.split(os.path.abspath(path))
346 osutils.SafeMakedirs(cwd)
347 if not git.GetCurrentBranch(cwd):
348 git.CreatePushBranch(constants.STABLE_EBUILD_BRANCH, cwd, sync=False)
349 osutils.WriteFile(path, "", mode="a")
350 if UpdateLocalFile(path, value, key):
351 desc = "%s: %s %s" % (
352 filename,
353 "updating" if value else "clearing",
354 key,
355 )
356 git.AddPath(path)
357 git.Commit(cwd, desc)
358
David James8c846492011-01-25 17:07:29 -0800359
Achuith Bhandarkar03d924a2018-01-02 10:50:44 -0800360def GenerateHtmlIndex(files, index, board, version, remote_location):
Alex Klein1699fab2022-09-08 08:46:06 -0600361 """Given the list of |files|, generate an index.html at |index|.
Mike Frysinger212e4292014-05-24 15:15:44 -0400362
Alex Klein1699fab2022-09-08 08:46:06 -0600363 Args:
364 files: The list of files to link to.
365 index: The path to the html index.
366 board: Name of the board this index is for.
367 version: Build version this index is for.
368 remote_location: Remote gs location prebuilts are uploaded to.
369 """
370 title = "Package Prebuilt Index: %s / %s" % (board, version)
Mike Frysinger212e4292014-05-24 15:15:44 -0400371
Alex Klein1699fab2022-09-08 08:46:06 -0600372 files = files + [
373 ".|Google Storage Index",
374 "..|",
375 ]
376 commands.GenerateHtmlIndex(
377 index, files, title=title, url_base=gs.GsUrlToHttp(remote_location)
378 )
Mike Frysinger212e4292014-05-24 15:15:44 -0400379
380
David Jamesce093af2011-02-23 15:21:58 -0800381def _GrabAllRemotePackageIndexes(binhost_urls):
Alex Klein1699fab2022-09-08 08:46:06 -0600382 """Grab all of the packages files associated with a list of binhost_urls.
David James05bcb2b2011-02-09 09:25:47 -0800383
Alex Klein1699fab2022-09-08 08:46:06 -0600384 Args:
385 binhost_urls: The URLs for the directories containing the Packages files we
386 want to grab.
David James05bcb2b2011-02-09 09:25:47 -0800387
Alex Klein1699fab2022-09-08 08:46:06 -0600388 Returns:
389 A list of PackageIndex objects.
390 """
391 pkg_indexes = []
392 for url in binhost_urls:
393 pkg_index = binpkg.GrabRemotePackageIndex(url)
394 if pkg_index:
395 pkg_indexes.append(pkg_index)
396 return pkg_indexes
David James05bcb2b2011-02-09 09:25:47 -0800397
398
David Jamesc0f158a2011-02-22 16:07:29 -0800399class PrebuiltUploader(object):
Alex Klein1699fab2022-09-08 08:46:06 -0600400 """Synchronize host and board prebuilts."""
David James8c846492011-01-25 17:07:29 -0800401
Alex Klein1699fab2022-09-08 08:46:06 -0600402 def __init__(
403 self,
404 upload_location,
405 acl,
406 binhost_base_url,
407 pkg_indexes,
408 build_path,
409 packages,
410 skip_upload,
411 binhost_conf_dir,
412 dryrun,
413 target,
414 slave_targets,
415 version,
416 chroot=None,
417 ):
418 """Constructor for prebuilt uploader object.
David James8c846492011-01-25 17:07:29 -0800419
Alex Klein1699fab2022-09-08 08:46:06 -0600420 This object can upload host or prebuilt files to Google Storage.
David James8c846492011-01-25 17:07:29 -0800421
Alex Klein1699fab2022-09-08 08:46:06 -0600422 Args:
423 upload_location: The upload location.
424 acl: The canned acl used for uploading to Google Storage. acl can be one
425 of: "public-read", "public-read-write", "authenticated-read",
426 "bucket-owner-read", "bucket-owner-full-control", "project-private",
427 or "private" (see "gsutil help acls"). If we are not uploading to
428 Google Storage, this parameter is unused.
429 binhost_base_url: The URL used for downloading the prebuilts.
430 pkg_indexes: Old uploaded prebuilts to compare against. Instead of
431 uploading duplicate files, we just link to the old files.
432 build_path: The path to the directory containing the chroot.
433 packages: Packages to upload.
434 skip_upload: Don't actually upload the tarballs.
435 binhost_conf_dir: Directory where to store binhost.conf files.
436 dryrun: Don't push or upload prebuilts.
437 target: BuildTarget managed by this builder.
438 slave_targets: List of BuildTargets managed by slave builders.
439 version: A unique string, intended to be included in the upload path,
440 which identifies the version number of the uploaded prebuilts.
441 chroot: Path to the chroot containing the prebuilts.
442 """
443 self._upload_location = upload_location
444 self._acl = acl
445 self._binhost_base_url = binhost_base_url
446 self._pkg_indexes = pkg_indexes
447 self._build_path = build_path
448 self._packages = set(packages)
449 self._found_packages = set()
450 self._skip_upload = skip_upload
451 self._binhost_conf_dir = binhost_conf_dir
452 self._dryrun = dryrun
453 self._target = target
454 self._slave_targets = slave_targets
455 self._version = version
456 self._chroot = chroot or os.path.join(
457 build_path, constants.DEFAULT_CHROOT_DIR
458 )
459 self._gs_context = gs.GSContext(
460 retries=_RETRIES, sleep=_SLEEP_TIME, dry_run=self._dryrun
461 )
Mike Frysinger540883b2014-05-24 13:46:16 -0400462
Alex Klein1699fab2022-09-08 08:46:06 -0600463 def _Upload(self, local_file, remote_file):
464 """Wrapper around _GsUpload"""
465 _GsUpload(self._gs_context, self._acl, local_file, remote_file)
David James615e5b52011-06-03 11:10:15 -0700466
Alex Klein1699fab2022-09-08 08:46:06 -0600467 def _ShouldFilterPackage(self, pkg):
468 if not self._packages:
469 return False
470 cpv = package_info.SplitCPV(pkg["CPV"])
471 self._found_packages.add(cpv.cp)
472 return (
473 cpv.package not in self._packages and cpv.cp not in self._packages
474 )
David James8c846492011-01-25 17:07:29 -0800475
Alex Klein1699fab2022-09-08 08:46:06 -0600476 def _UploadPrebuilt(self, package_path, url_suffix):
477 """Upload host or board prebuilt files to Google Storage space.
David James8c846492011-01-25 17:07:29 -0800478
Alex Klein1699fab2022-09-08 08:46:06 -0600479 Args:
480 package_path: The path to the packages dir.
481 url_suffix: The remote subdirectory where we should upload the packages.
482 """
483 # Process Packages file, removing duplicates and filtered packages.
484 pkg_index = binpkg.GrabLocalPackageIndex(package_path)
485 pkg_index.SetUploadLocation(self._binhost_base_url, url_suffix)
486 pkg_index.RemoveFilteredPackages(self._ShouldFilterPackage)
487 uploads = pkg_index.ResolveDuplicateUploads(self._pkg_indexes)
488 unmatched_pkgs = self._packages - self._found_packages
489 if unmatched_pkgs:
490 logging.warning("unable to match packages: %r", unmatched_pkgs)
David James05bcb2b2011-02-09 09:25:47 -0800491
Alex Klein1699fab2022-09-08 08:46:06 -0600492 # Write Packages file.
493 pkg_index.header["TTL"] = _BINPKG_TTL
494 tmp_packages_file = pkg_index.WriteToNamedTemporaryFile()
David James05bcb2b2011-02-09 09:25:47 -0800495
Alex Klein1699fab2022-09-08 08:46:06 -0600496 remote_location = "%s/%s" % (
497 self._upload_location.rstrip("/"),
498 url_suffix,
499 )
500 assert remote_location.startswith("gs://")
David James05bcb2b2011-02-09 09:25:47 -0800501
Alex Klein1699fab2022-09-08 08:46:06 -0600502 upload_files = GenerateUploadDict(
503 package_path, remote_location, uploads
504 )
505 remote_file = "%s/Packages" % remote_location.rstrip("/")
506 upload_files[tmp_packages_file.name] = remote_file
David James015af872012-06-19 15:24:36 -0700507
Alex Klein1699fab2022-09-08 08:46:06 -0600508 # Build list of files to upload. Manually include the dev-only files but
509 # skip them if not present.
510 dev_only = os.path.join(package_path, "dev-only-extras.tar.xz")
511 if os.path.exists(dev_only):
512 upload_files[dev_only] = "%s/%s" % (
513 remote_location.rstrip("/"),
514 os.path.basename(dev_only),
515 )
Mike Frysinger9bb6cd82020-08-20 03:02:23 -0400516
Alex Klein1699fab2022-09-08 08:46:06 -0600517 RemoteUpload(self._gs_context, self._acl, upload_files)
David James8c846492011-01-25 17:07:29 -0800518
Alex Klein1699fab2022-09-08 08:46:06 -0600519 with tempfile.NamedTemporaryFile(
520 prefix="chromite.upload_prebuilts.index."
521 ) as index:
522 GenerateHtmlIndex(
523 [x[len(remote_location) + 1 :] for x in upload_files.values()],
524 index.name,
525 self._target,
526 self._version,
527 remote_location,
528 )
529 self._Upload(
530 index.name, "%s/index.html" % remote_location.rstrip("/")
531 )
Mike Frysinger212e4292014-05-24 15:15:44 -0400532
Alex Klein1699fab2022-09-08 08:46:06 -0600533 link_name = "Prebuilts[%s]: %s" % (self._target, self._version)
534 url = "%s%s/index.html" % (
535 gs.PUBLIC_BASE_HTTPS_URL,
536 remote_location[len(gs.BASE_GS_URL) :],
537 )
538 cbuildbot_alerts.PrintBuildbotLink(link_name, url)
Mike Frysinger212e4292014-05-24 15:15:44 -0400539
Alex Klein1699fab2022-09-08 08:46:06 -0600540 def _UploadSdkTarball(
541 self,
542 board_path,
543 url_suffix,
544 prepackaged,
545 toolchains_overlay_tarballs,
546 toolchains_overlay_upload_path,
547 toolchain_tarballs,
548 toolchain_upload_path,
549 ):
550 """Upload a tarball of the sdk at the specified path to Google Storage.
David James8fa34ea2011-04-15 13:00:20 -0700551
Alex Klein1699fab2022-09-08 08:46:06 -0600552 Args:
553 board_path: The path to the board dir.
554 url_suffix: The remote subdirectory where we should upload the packages.
555 prepackaged: If given, a tarball that has been packaged outside of this
556 script and should be used.
557 toolchains_overlay_tarballs: List of toolchains overlay tarball
558 specifications to upload. Items take the form
559 "toolchains_spec:/path/to/tarball".
560 toolchains_overlay_upload_path: Path template under the bucket to place
561 toolchains overlay tarballs.
562 toolchain_tarballs: List of toolchain tarballs to upload.
563 toolchain_upload_path: Path under the bucket to place toolchain tarballs.
564 """
565 remote_location = "%s/%s" % (
566 self._upload_location.rstrip("/"),
567 url_suffix,
568 )
569 assert remote_location.startswith("gs://")
570 boardname = os.path.basename(board_path.rstrip("/"))
571 # We do not upload non SDK board tarballs,
572 assert boardname == constants.CHROOT_BUILDER_BOARD
573 assert prepackaged is not None
Zdenek Behan62a57792012-08-31 15:09:08 +0200574
Alex Klein1699fab2022-09-08 08:46:06 -0600575 version_str = self._version[len("chroot-") :]
576 remote_tarfile = toolchain.GetSdkURL(
577 for_gsutil=True, suburl="cros-sdk-%s.tar.xz" % (version_str,)
578 )
579 # For SDK, also upload the manifest which is guaranteed to exist
580 # by the builderstage.
581 self._Upload(prepackaged + ".Manifest", remote_tarfile + ".Manifest")
582 self._Upload(prepackaged, remote_tarfile)
Zdenek Behan86c15e92012-10-13 00:55:47 +0200583
Alex Klein1699fab2022-09-08 08:46:06 -0600584 # Upload SDK toolchains overlays and toolchain tarballs, if given.
585 for tarball_list, upload_path, qualifier_name in (
586 (
587 toolchains_overlay_tarballs,
588 toolchains_overlay_upload_path,
589 "toolchains",
590 ),
591 (toolchain_tarballs, toolchain_upload_path, "target"),
592 ):
593 for tarball_spec in tarball_list:
594 qualifier_val, local_path = tarball_spec.split(":")
595 suburl = upload_path % {qualifier_name: qualifier_val}
596 remote_path = toolchain.GetSdkURL(
597 for_gsutil=True, suburl=suburl
598 )
599 self._Upload(local_path, remote_path)
Mike Frysinger9e979b92012-11-29 02:55:09 -0500600
Alex Klein1699fab2022-09-08 08:46:06 -0600601 # Finally, also update the pointer to the latest SDK on which polling
602 # scripts rely.
603 with osutils.TempDir() as tmpdir:
604 pointerfile = os.path.join(tmpdir, "cros-sdk-latest.conf")
605 remote_pointerfile = toolchain.GetSdkURL(
606 for_gsutil=True, suburl="cros-sdk-latest.conf"
607 )
608 osutils.WriteFile(pointerfile, 'LATEST_SDK="%s"' % version_str)
609 self._Upload(pointerfile, remote_pointerfile)
Zdenek Behan33a34112012-09-10 21:07:51 +0200610
Alex Klein1699fab2022-09-08 08:46:06 -0600611 def _GetTargets(self):
612 """Retuns the list of targets to use."""
613 targets = self._slave_targets[:]
614 if self._target:
615 targets.append(self._target)
Chris Sosa6a5dceb2012-05-14 13:48:56 -0700616
Alex Klein1699fab2022-09-08 08:46:06 -0600617 return targets
Chris Sosa6a5dceb2012-05-14 13:48:56 -0700618
Alex Klein1699fab2022-09-08 08:46:06 -0600619 def SyncHostPrebuilts(self, key, git_sync, sync_binhost_conf):
620 """Synchronize host prebuilt files.
David James05bcb2b2011-02-09 09:25:47 -0800621
Alex Klein1699fab2022-09-08 08:46:06 -0600622 This function will sync both the standard host packages, plus the host
623 packages associated with all targets that have been "setup" with the
624 current host's chroot. For instance, if this host has been used to build
625 x86-generic, it will sync the host packages associated with
626 'i686-pc-linux-gnu'. If this host has also been used to build arm-generic,
627 it will also sync the host packages associated with
628 'armv7a-cros-linux-gnueabi'.
David James05bcb2b2011-02-09 09:25:47 -0800629
Alex Klein1699fab2022-09-08 08:46:06 -0600630 Args:
631 key: The variable key to update in the git file.
632 git_sync: If set, update make.conf of target to reference the latest
633 prebuilt packages generated here.
634 sync_binhost_conf: If set, update binhost config file in
635 chromiumos-overlay for the host.
636 """
637 # Slave boards are listed before the master board so that the master board
638 # takes priority (i.e. x86-generic preflight host prebuilts takes priority
639 # over preflight host prebuilts from other builders.)
640 binhost_urls = []
641 for target in self._GetTargets():
642 url_suffix = _REL_HOST_PATH % {
643 "version": self._version,
644 "host_arch": _HOST_ARCH,
645 "target": target,
646 }
647 packages_url_suffix = "%s/packages" % url_suffix.rstrip("/")
David James05bcb2b2011-02-09 09:25:47 -0800648
Alex Klein1699fab2022-09-08 08:46:06 -0600649 if self._target == target and not self._skip_upload:
650 # Upload prebuilts.
651 package_path = os.path.join(self._chroot, _HOST_PACKAGES_PATH)
652 self._UploadPrebuilt(package_path, packages_url_suffix)
David James8ece7ee2011-06-29 16:02:30 -0700653
Alex Klein1699fab2022-09-08 08:46:06 -0600654 # Record URL where prebuilts were uploaded.
655 binhost_urls.append(
656 "%s/%s/"
657 % (
658 self._binhost_base_url.rstrip("/"),
659 packages_url_suffix.rstrip("/"),
660 )
661 )
David Jamese2488642011-11-14 16:15:20 -0800662
Alex Klein1699fab2022-09-08 08:46:06 -0600663 binhost = " ".join(binhost_urls)
664 if git_sync:
665 git_file = os.path.join(
666 self._build_path, _PREBUILT_MAKE_CONF[_HOST_ARCH]
667 )
668 RevGitFile(git_file, {key: binhost}, dryrun=self._dryrun)
669 if sync_binhost_conf:
670 binhost_conf = os.path.join(
671 self._binhost_conf_dir, "host", "%s-%s.conf" % (_HOST_ARCH, key)
672 )
673 UpdateBinhostConfFile(binhost_conf, key, binhost)
David Jamesc0f158a2011-02-22 16:07:29 -0800674
Alex Klein1699fab2022-09-08 08:46:06 -0600675 def SyncBoardPrebuilts(
676 self,
677 key,
678 git_sync,
679 sync_binhost_conf,
680 upload_board_tarball,
681 prepackaged_board,
682 toolchains_overlay_tarballs,
683 toolchains_overlay_upload_path,
684 toolchain_tarballs,
685 toolchain_upload_path,
686 ):
687 """Synchronize board prebuilt files.
David Jamesc0f158a2011-02-22 16:07:29 -0800688
Alex Klein1699fab2022-09-08 08:46:06 -0600689 Args:
690 key: The variable key to update in the git file.
691 git_sync: If set, update make.conf of target to reference the latest
692 prebuilt packages generated here.
693 sync_binhost_conf: If set, update binhost config file in
694 chromiumos-overlay for the current board.
695 upload_board_tarball: Include a tarball of the board in our upload.
696 prepackaged_board: A tarball of the board built outside of this script.
697 toolchains_overlay_tarballs: List of toolchains overlay tarball
698 specifications to upload. Items take the form
699 "toolchains_spec:/path/to/tarball".
700 toolchains_overlay_upload_path: Path template under the bucket to place
701 toolchains overlay tarballs.
702 toolchain_tarballs: A list of toolchain tarballs to upload.
703 toolchain_upload_path: Path under the bucket to place toolchain tarballs.
704 """
705 updated_binhosts = set()
706 for target in self._GetTargets():
707 board_path = os.path.join(
708 self._build_path, _BOARD_PATH % {"board": target.board_variant}
709 )
710 package_path = os.path.join(board_path, "packages")
711 url_suffix = _REL_BOARD_PATH % {
712 "target": target,
713 "version": self._version,
714 }
715 packages_url_suffix = "%s/packages" % url_suffix.rstrip("/")
David James8fa34ea2011-04-15 13:00:20 -0700716
Alex Klein1699fab2022-09-08 08:46:06 -0600717 # Process the target board differently if it is the main --board.
718 if self._target == target and not self._skip_upload:
719 # This strips "chroot" prefix because that is sometimes added as the
720 # --prepend-version argument (e.g. by chromiumos-sdk bot).
721 # TODO(build): Clean it up to be less hard-coded.
722 version_str = self._version[len("chroot-") :]
Mike Frysinger9e979b92012-11-29 02:55:09 -0500723
Alex Klein1699fab2022-09-08 08:46:06 -0600724 # Upload board tarballs in the background.
725 if upload_board_tarball:
726 if toolchain_upload_path:
727 toolchain_upload_path %= {"version": version_str}
728 if toolchains_overlay_upload_path:
729 toolchains_overlay_upload_path %= {
730 "version": version_str
731 }
732 tar_process = multiprocessing.Process(
733 target=self._UploadSdkTarball,
734 args=(
735 board_path,
736 url_suffix,
737 prepackaged_board,
738 toolchains_overlay_tarballs,
739 toolchains_overlay_upload_path,
740 toolchain_tarballs,
741 toolchain_upload_path,
742 ),
743 )
744 tar_process.start()
David James8fa34ea2011-04-15 13:00:20 -0700745
Alex Klein1699fab2022-09-08 08:46:06 -0600746 # Upload prebuilts.
747 self._UploadPrebuilt(package_path, packages_url_suffix)
David James8fa34ea2011-04-15 13:00:20 -0700748
Alex Klein1699fab2022-09-08 08:46:06 -0600749 # Make sure we finished uploading the board tarballs.
750 if upload_board_tarball:
751 tar_process.join()
752 assert tar_process.exitcode == 0
David Jamesc0f158a2011-02-22 16:07:29 -0800753
Alex Klein1699fab2022-09-08 08:46:06 -0600754 # Record URL where prebuilts were uploaded.
755 url_value = "%s/%s/" % (
756 self._binhost_base_url.rstrip("/"),
757 packages_url_suffix.rstrip("/"),
758 )
David Jamese2488642011-11-14 16:15:20 -0800759
Alex Klein1699fab2022-09-08 08:46:06 -0600760 if git_sync:
761 git_file = DeterminePrebuiltConfFile(self._build_path, target)
762 RevGitFile(git_file, {key: url_value}, dryrun=self._dryrun)
Matt Tennante8179042013-10-01 15:47:32 -0700763
Alex Klein1699fab2022-09-08 08:46:06 -0600764 if sync_binhost_conf:
765 # Update the binhost configuration file in git.
766 binhost_conf = os.path.join(
767 self._binhost_conf_dir,
768 "target",
769 "%s-%s.conf" % (target, key),
770 )
771 updated_binhosts.add(binhost_conf)
772 UpdateBinhostConfFile(binhost_conf, key, url_value)
David James05bcb2b2011-02-09 09:25:47 -0800773
Alex Klein1699fab2022-09-08 08:46:06 -0600774 if sync_binhost_conf:
775 # Clear all old binhosts. The files must be left empty in case anybody
776 # is referring to them.
777 all_binhosts = set(
778 glob.glob(
779 os.path.join(
780 self._binhost_conf_dir, "target", "*-%s.conf" % key
781 )
782 )
783 )
784 for binhost_conf in all_binhosts - updated_binhosts:
785 UpdateBinhostConfFile(binhost_conf, key, "")
David Jamesb26b9312014-12-15 11:26:46 -0800786
David James05bcb2b2011-02-09 09:25:47 -0800787
Mike Nicholsa1414162021-04-22 20:07:22 +0000788class _AddSlaveBoardAction(argparse.Action):
Alex Klein1699fab2022-09-08 08:46:06 -0600789 """Callback that adds a slave board to the list of slave targets."""
790
791 def __call__(self, parser, namespace, values, option_string=None):
792 getattr(namespace, self.dest).append(BuildTarget(values))
David James4058b0d2011-12-08 21:24:50 -0800793
794
Mike Nicholsa1414162021-04-22 20:07:22 +0000795class _AddSlaveProfileAction(argparse.Action):
Alex Klein1699fab2022-09-08 08:46:06 -0600796 """Callback that adds a slave profile to the list of slave targets."""
797
798 def __call__(self, parser, namespace, values, option_string=None):
799 if not namespace.slave_targets:
800 parser.error("Must specify --slave-board before --slave-profile")
801 if namespace.slave_targets[-1].profile is not None:
802 parser.error("Cannot specify --slave-profile twice for same board")
803 namespace.slave_targets[-1].profile = values
David James4058b0d2011-12-08 21:24:50 -0800804
805
Mike Frysinger86509232014-05-24 13:18:37 -0400806def ParseOptions(argv):
Alex Klein1699fab2022-09-08 08:46:06 -0600807 """Returns options given by the user and the target specified.
Chris Sosa6a5dceb2012-05-14 13:48:56 -0700808
Alex Klein1699fab2022-09-08 08:46:06 -0600809 Args:
810 argv: The args to parse.
Mike Frysinger86509232014-05-24 13:18:37 -0400811
Alex Klein1699fab2022-09-08 08:46:06 -0600812 Returns:
813 A tuple containing a parsed options object and BuildTarget.
814 The target instance is None if no board is specified.
815 """
816 parser = commandline.ArgumentParser()
817 parser.add_argument(
818 "-H",
819 "--binhost-base-url",
820 default=_BINHOST_BASE_URL,
821 help="Base URL to use for binhost in make.conf updates",
822 )
823 parser.add_argument(
824 "--previous-binhost-url",
825 action="append",
826 default=[],
827 help="Previous binhost URL",
828 )
829 parser.add_argument(
830 "-b", "--board", help="Board type that was built on this machine"
831 )
832 parser.add_argument(
833 "-B",
834 "--prepackaged-tarball",
835 type="path",
836 help="Board tarball prebuilt outside of this script.",
837 )
838 parser.add_argument(
839 "--toolchains-overlay-tarball",
840 dest="toolchains_overlay_tarballs",
841 action="append",
842 default=[],
843 help="Toolchains overlay tarball specification to "
844 "upload. Takes the form "
845 '"toolchains_spec:/path/to/tarball".',
846 )
847 parser.add_argument(
848 "--toolchains-overlay-upload-path",
849 default="",
850 help="Path template for uploading toolchains overlays.",
851 )
852 parser.add_argument(
853 "--toolchain-tarball",
854 dest="toolchain_tarballs",
855 action="append",
856 default=[],
857 help="Redistributable toolchain tarball.",
858 )
859 parser.add_argument(
860 "--toolchain-upload-path",
861 default="",
862 help="Path to place toolchain tarballs in the sdk tree.",
863 )
864 parser.add_argument(
865 "--profile", help="Profile that was built on this machine"
866 )
867 parser.add_argument(
868 "--slave-board",
869 default=[],
870 action=_AddSlaveBoardAction,
871 dest="slave_targets",
872 help="Board type that was built on a slave machine. To "
873 "add a profile to this board, use --slave-profile.",
874 )
875 parser.add_argument(
876 "--slave-profile",
877 action=_AddSlaveProfileAction,
878 help="Board profile that was built on a slave machine. "
879 "Applies to previous slave board.",
880 )
881 parser.add_argument(
882 "-p",
883 "--build-path",
884 required=True,
885 help="Path to the directory containing the chroot",
886 )
887 parser.add_argument(
888 "--chroot",
889 help="Path where the chroot is located. "
890 "(Default: {build_path}/chroot)",
891 )
892 parser.add_argument(
893 "--packages",
894 action="append",
895 default=[],
896 help="Only include the specified packages. "
897 "(Default is to include all packages.)",
898 )
899 parser.add_argument(
900 "-s",
901 "--sync-host",
902 default=False,
903 action="store_true",
904 help="Sync host prebuilts",
905 )
906 parser.add_argument(
907 "-g",
908 "--git-sync",
909 default=False,
910 action="store_true",
911 help="Enable git version sync (This commits to a repo.) "
912 "This is used by full builders to commit directly "
913 "to board overlays.",
914 )
915 parser.add_argument("-u", "--upload", help="Upload location")
916 parser.add_argument(
917 "-V",
918 "--prepend-version",
919 help="Add an identifier to the front of the version",
920 )
921 parser.add_argument(
922 "-f",
923 "--filters",
924 action="store_true",
925 default=False,
926 help="Turn on filtering of private ebuild packages",
927 )
928 parser.add_argument(
929 "-k",
930 "--key",
931 default="PORTAGE_BINHOST",
932 help="Key to update in make.conf / binhost.conf",
933 )
934 parser.add_argument("--set-version", help="Specify the version string")
935 parser.add_argument(
936 "--sync-binhost-conf",
937 default=False,
938 action="store_true",
939 help="Update binhost.conf in chromiumos-overlay or "
940 "chromeos-overlay. Commit the changes, but don't "
941 "push them. This is used for preflight binhosts.",
942 )
943 parser.add_argument(
944 "--binhost-conf-dir",
945 help="Directory to commit binhost config with " "--sync-binhost-conf.",
946 )
947 parser.add_argument(
948 "-P",
949 "--private",
950 action="store_true",
951 default=False,
952 help="Mark gs:// uploads as private.",
953 )
954 parser.add_argument(
955 "--skip-upload",
956 action="store_true",
957 default=False,
958 help="Skip upload step.",
959 )
960 parser.add_argument(
961 "--upload-board-tarball",
962 action="store_true",
963 default=False,
964 help="Upload board tarball to Google Storage.",
965 )
966 parser.add_argument(
967 "-n",
968 "--dry-run",
969 dest="dryrun",
970 action="store_true",
971 default=False,
972 help="Don't push or upload prebuilts.",
973 )
David James8c846492011-01-25 17:07:29 -0800974
Alex Klein1699fab2022-09-08 08:46:06 -0600975 options = parser.parse_args(argv)
976 if not options.upload and not options.skip_upload:
977 parser.error("you need to provide an upload location using -u")
978 if not options.set_version and options.skip_upload:
979 parser.error(
980 "If you are using --skip-upload, you must specify a "
981 "version number using --set-version."
982 )
Scott Zawalskiab1bed32011-03-16 15:24:24 -0700983
Alex Klein1699fab2022-09-08 08:46:06 -0600984 target = None
985 if options.board:
986 target = BuildTarget(options.board, options.profile)
Chris Sosa6a5dceb2012-05-14 13:48:56 -0700987
Alex Klein1699fab2022-09-08 08:46:06 -0600988 if target in options.slave_targets:
989 parser.error("--board/--profile must not also be a slave target.")
David Jamese2488642011-11-14 16:15:20 -0800990
Alex Klein1699fab2022-09-08 08:46:06 -0600991 if len(set(options.slave_targets)) != len(options.slave_targets):
992 parser.error("--slave-boards must not have duplicates.")
David Jamese2488642011-11-14 16:15:20 -0800993
Alex Klein1699fab2022-09-08 08:46:06 -0600994 if options.slave_targets and options.git_sync:
995 parser.error("--slave-boards is not compatible with --git-sync")
David Jamese2488642011-11-14 16:15:20 -0800996
Alex Klein1699fab2022-09-08 08:46:06 -0600997 if (
998 options.upload_board_tarball
999 and options.skip_upload
1000 and options.board == "amd64-host"
1001 ):
1002 parser.error(
1003 "--skip-upload is not compatible with "
1004 "--upload-board-tarball and --board=amd64-host"
1005 )
David James8fa34ea2011-04-15 13:00:20 -07001006
Alex Klein1699fab2022-09-08 08:46:06 -06001007 if (
1008 options.upload_board_tarball
1009 and not options.skip_upload
1010 and not options.upload.startswith("gs://")
1011 ):
1012 parser.error(
1013 "--upload-board-tarball only works with gs:// URLs.\n"
1014 "--upload must be a gs:// URL."
1015 )
David James8fa34ea2011-04-15 13:00:20 -07001016
Alex Klein1699fab2022-09-08 08:46:06 -06001017 if options.upload_board_tarball and options.prepackaged_tarball is None:
1018 parser.error("--upload-board-tarball requires --prepackaged-tarball")
Zdenek Behan86c15e92012-10-13 00:55:47 +02001019
Alex Klein1699fab2022-09-08 08:46:06 -06001020 if options.private:
1021 if options.sync_host:
1022 parser.error(
1023 "--private and --sync-host/-s cannot be specified "
1024 "together; we do not support private host prebuilts"
1025 )
Scott Zawalskiab1bed32011-03-16 15:24:24 -07001026
Alex Klein1699fab2022-09-08 08:46:06 -06001027 if not options.upload or not options.upload.startswith("gs://"):
1028 parser.error(
1029 "--private is only valid for gs:// URLs; "
1030 "--upload must be a gs:// URL."
1031 )
Scott Zawalskiab1bed32011-03-16 15:24:24 -07001032
Alex Klein1699fab2022-09-08 08:46:06 -06001033 if options.binhost_base_url != _BINHOST_BASE_URL:
1034 parser.error(
1035 "when using --private the --binhost-base-url "
1036 "is automatically derived."
1037 )
David James27fa7d12011-06-29 17:24:14 -07001038
Alex Klein1699fab2022-09-08 08:46:06 -06001039 if options.sync_binhost_conf and not options.binhost_conf_dir:
1040 parser.error("--sync-binhost-conf requires --binhost-conf-dir")
David Jamesc31168e2014-06-05 14:40:05 -07001041
Alex Klein1699fab2022-09-08 08:46:06 -06001042 if (
1043 options.toolchains_overlay_tarballs
1044 and not options.toolchains_overlay_upload_path
1045 ):
1046 parser.error(
1047 "--toolchains-overlay-tarball requires "
1048 "--toolchains-overlay-upload-path"
1049 )
Gilad Arnoldad333182015-05-27 15:50:41 -07001050
Alex Klein1699fab2022-09-08 08:46:06 -06001051 return options, target
David Jamesc0f158a2011-02-22 16:07:29 -08001052
Mike Frysingercc838832014-05-24 13:10:30 -04001053
Mike Frysinger86509232014-05-24 13:18:37 -04001054def main(argv):
Alex Klein1699fab2022-09-08 08:46:06 -06001055 # Set umask so that files created as root are readable.
1056 os.umask(0o22)
David Jamesdb401072011-06-10 12:17:16 -07001057
Alex Klein1699fab2022-09-08 08:46:06 -06001058 options, target = ParseOptions(argv)
David Jamesc0f158a2011-02-22 16:07:29 -08001059
Alex Klein1699fab2022-09-08 08:46:06 -06001060 # Calculate a list of Packages index files to compare against. Whenever we
1061 # upload a package, we check to make sure it's not already stored in one of
1062 # the packages files we uploaded. This list of packages files might contain
1063 # both board and host packages.
1064 pkg_indexes = _GrabAllRemotePackageIndexes(options.previous_binhost_url)
David James8c846492011-01-25 17:07:29 -08001065
Alex Klein1699fab2022-09-08 08:46:06 -06001066 if options.set_version:
1067 version = options.set_version
1068 else:
1069 version = GetVersion()
Matt Tennante8179042013-10-01 15:47:32 -07001070
Alex Klein1699fab2022-09-08 08:46:06 -06001071 if options.prepend_version:
1072 version = "%s-%s" % (options.prepend_version, version)
David Jamesc0f158a2011-02-22 16:07:29 -08001073
Alex Klein1699fab2022-09-08 08:46:06 -06001074 acl = "public-read"
1075 binhost_base_url = options.binhost_base_url
Scott Zawalskiab1bed32011-03-16 15:24:24 -07001076
Alex Klein1699fab2022-09-08 08:46:06 -06001077 if options.private:
1078 binhost_base_url = options.upload
1079 if target:
1080 acl = portage_util.FindOverlayFile(
1081 _GOOGLESTORAGE_GSUTIL_FILE,
1082 board=target.board_variant,
1083 buildroot=options.build_path,
1084 )
1085 if acl is None:
1086 cros_build_lib.Die(
1087 "No Google Storage ACL file %s found in %s overlay.",
1088 _GOOGLESTORAGE_GSUTIL_FILE,
1089 target.board_variant,
1090 )
Scott Zawalskiab1bed32011-03-16 15:24:24 -07001091
Alex Klein1699fab2022-09-08 08:46:06 -06001092 binhost_conf_dir = None
1093 if options.binhost_conf_dir:
1094 binhost_conf_dir = os.path.join(
1095 options.build_path, options.binhost_conf_dir
1096 )
David Jamesb26b9312014-12-15 11:26:46 -08001097
Alex Klein1699fab2022-09-08 08:46:06 -06001098 uploader = PrebuiltUploader(
1099 options.upload,
1100 acl,
1101 binhost_base_url,
1102 pkg_indexes,
1103 options.build_path,
1104 options.packages,
1105 options.skip_upload,
1106 binhost_conf_dir,
1107 options.dryrun,
1108 target,
1109 options.slave_targets,
1110 version,
1111 options.chroot,
1112 )
David Jamesc0f158a2011-02-22 16:07:29 -08001113
Alex Klein1699fab2022-09-08 08:46:06 -06001114 if options.sync_host:
1115 uploader.SyncHostPrebuilts(
1116 options.key, options.git_sync, options.sync_binhost_conf
1117 )
David James8c846492011-01-25 17:07:29 -08001118
Alex Klein1699fab2022-09-08 08:46:06 -06001119 if options.board or options.slave_targets:
1120 uploader.SyncBoardPrebuilts(
1121 options.key,
1122 options.git_sync,
1123 options.sync_binhost_conf,
1124 options.upload_board_tarball,
1125 options.prepackaged_tarball,
1126 options.toolchains_overlay_tarballs,
1127 options.toolchains_overlay_upload_path,
1128 options.toolchain_tarballs,
1129 options.toolchain_upload_path,
1130 )