blob: edd6b40d5dd7bcb031f8169cac6418f1d5583133 [file] [log] [blame]
David Jamesb619a782012-07-25 19:37:57 -07001# Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
David James8c846492011-01-25 17:07:29 -08002# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
Brian Harringaf019fb2012-05-10 15:06:13 -07005"""This script is used to upload host prebuilts as well as board BINHOSTS.
David James8c846492011-01-25 17:07:29 -08006
David James015af872012-06-19 15:24:36 -07007Prebuilts are uploaded using gsutil to Google Storage. After these prebuilts
8are successfully uploaded, a file is updated with the proper BINHOST version.
David James8c846492011-01-25 17:07:29 -08009
10To read more about prebuilts/binhost binary packages please refer to:
David James015af872012-06-19 15:24:36 -070011http://goto/chromeos-prebuilts
David James8c846492011-01-25 17:07:29 -080012
13Example of uploading prebuilt amd64 host files to Google Storage:
David Jamesc5cbd472012-06-19 16:25:45 -070014upload_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:
David Jamesc5cbd472012-06-19 16:25:45 -070017upload_prebuilts -b x86-dogfood -p /b/cbuild/build/ -u gs://chromeos-prebuilt -g
David James8c846492011-01-25 17:07:29 -080018"""
19
Mike Frysingerff441bf2014-05-24 13:47:21 -040020from __future__ import print_function
21
Chris Sosa1dc96132012-05-11 15:40:50 -070022import datetime
Mike Frysinger540883b2014-05-24 13:46:16 -040023import functools
Chris Sosa1dc96132012-05-11 15:40:50 -070024import multiprocessing
Chris Sosa1dc96132012-05-11 15:40:50 -070025import os
26import sys
Mike Frysinger212e4292014-05-24 15:15:44 -040027import tempfile
Chris Sosa1dc96132012-05-11 15:40:50 -070028
Don Garrett88b8d782014-05-13 17:30:55 -070029from chromite.cbuildbot import constants
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 Sosa1dc96132012-05-11 15:40:50 -070033from chromite.lib import cros_build_lib
David James97d95872012-11-16 15:09:56 -080034from chromite.lib import git
Brian Harring7904b482012-08-08 02:54:12 -070035from chromite.lib import gs
Brian Harringaf019fb2012-05-10 15:06:13 -070036from chromite.lib import osutils
David James6450a0a2012-12-04 07:59:53 -080037from chromite.lib import parallel
Alex Deymo075c2292014-09-04 18:31:50 -070038from chromite.lib import portage_util
Mike Frysinger8e727a32013-01-16 16:57:53 -050039from chromite.lib import toolchain
Chris Sosa1dc96132012-05-11 15:40:50 -070040
David James015af872012-06-19 15:24:36 -070041# How many times to retry uploads.
42_RETRIES = 10
43
44# Multiplier for how long to sleep (in seconds) between retries; will delay
45# (1*sleep) the first time, then (2*sleep), continuing via attempt * sleep.
46_SLEEP_TIME = 60
47
David James5ab67e32014-10-24 08:19:59 -070048# The length of time (in seconds) that Portage should wait before refetching
49# binpkgs from the same binhost. We don't ever modify binhosts, so this should
50# be something big.
51_BINPKG_TTL = 60 * 60 * 24 * 365
52
David James8c846492011-01-25 17:07:29 -080053_HOST_PACKAGES_PATH = 'chroot/var/lib/portage/pkgs'
David James05bcb2b2011-02-09 09:25:47 -080054_CATEGORIES_PATH = 'chroot/etc/portage/categories'
David James615e5b52011-06-03 11:10:15 -070055_PYM_PATH = 'chroot/usr/lib/portage/pym'
David James4058b0d2011-12-08 21:24:50 -080056_HOST_ARCH = 'amd64'
David James8c846492011-01-25 17:07:29 -080057_BOARD_PATH = 'chroot/build/%(board)s'
David James4058b0d2011-12-08 21:24:50 -080058_REL_BOARD_PATH = 'board/%(target)s/%(version)s'
59_REL_HOST_PATH = 'host/%(host_arch)s/%(target)s/%(version)s'
David James8c846492011-01-25 17:07:29 -080060# Private overlays to look at for builds to filter
61# relative to build path
62_PRIVATE_OVERLAY_DIR = 'src/private-overlays'
Gabe Black40169e62014-06-17 15:23:47 -070063_GOOGLESTORAGE_GSUTIL_FILE = 'googlestorage_acl.txt'
David James3753d942014-04-23 10:55:48 -070064_BINHOST_BASE_URL = 'gs://chromeos-prebuilt'
David James8c846492011-01-25 17:07:29 -080065_PREBUILT_BASE_DIR = 'src/third_party/chromiumos-overlay/chromeos/config/'
66# Created in the event of new host targets becoming available
67_PREBUILT_MAKE_CONF = {'amd64': os.path.join(_PREBUILT_BASE_DIR,
68 'make.conf.amd64-host')}
David James8c846492011-01-25 17:07:29 -080069
70
David James4058b0d2011-12-08 21:24:50 -080071class BuildTarget(object):
72 """A board/variant/profile tuple."""
73
74 def __init__(self, board_variant, profile=None):
75 self.board_variant = board_variant
76 self.board, _, self.variant = board_variant.partition('_')
77 self.profile = profile
78
79 def __str__(self):
80 if self.profile:
81 return '%s_%s' % (self.board_variant, self.profile)
82 else:
83 return self.board_variant
84
85 def __eq__(self, other):
86 return str(other) == str(self)
87
88 def __hash__(self):
89 return hash(str(self))
90
91
David James8c846492011-01-25 17:07:29 -080092def UpdateLocalFile(filename, value, key='PORTAGE_BINHOST'):
93 """Update the key in file with the value passed.
Mike Frysinger1a736a82013-12-12 01:50:59 -050094
David James8c846492011-01-25 17:07:29 -080095 File format:
96 key="value"
97 Note quotes are added automatically
98
99 Args:
100 filename: Name of file to modify.
101 value: Value to write with the key.
102 key: The variable key to update. (Default: PORTAGE_BINHOST)
103 """
104 if os.path.exists(filename):
105 file_fh = open(filename)
106 else:
107 file_fh = open(filename, 'w+')
108 file_lines = []
109 found = False
110 keyval_str = '%(key)s=%(value)s'
111 for line in file_fh:
112 # Strip newlines from end of line. We already add newlines below.
113 line = line.rstrip("\n")
114
115 if len(line.split('=')) != 2:
116 # Skip any line that doesn't fit key=val.
117 file_lines.append(line)
118 continue
119
120 file_var, file_val = line.split('=')
121 if file_var == key:
122 found = True
Mike Frysingerff441bf2014-05-24 13:47:21 -0400123 print('Updating %s=%s to %s="%s"' % (file_var, file_val, key, value))
David James8c846492011-01-25 17:07:29 -0800124 value = '"%s"' % value
125 file_lines.append(keyval_str % {'key': key, 'value': value})
126 else:
127 file_lines.append(keyval_str % {'key': file_var, 'value': file_val})
128
129 if not found:
Brian Harring2a014302012-05-12 00:53:33 -0700130 value = '"%s"' % value
David James8c846492011-01-25 17:07:29 -0800131 file_lines.append(keyval_str % {'key': key, 'value': value})
132
133 file_fh.close()
134 # write out new file
Brian Harringaf019fb2012-05-10 15:06:13 -0700135 osutils.WriteFile(filename, '\n'.join(file_lines) + '\n')
David James8c846492011-01-25 17:07:29 -0800136
137
Mike Frysinger5b34d732013-01-17 15:11:58 -0500138def RevGitFile(filename, data, retries=5, dryrun=False):
David James8c846492011-01-25 17:07:29 -0800139 """Update and push the git file.
140
Mike Frysinger5b34d732013-01-17 15:11:58 -0500141 Args:
142 filename: file to modify that is in a git repo already
143 data: A dict of key/values to update in |filename|
144 retries: The number of times to retry before giving up, default: 5
Matt Tennante8179042013-10-01 15:47:32 -0700145 dryrun: If True, do not actually commit the change.
David James8c846492011-01-25 17:07:29 -0800146 """
147 prebuilt_branch = 'prebuilt_branch'
David James1b6e67a2011-05-19 21:32:38 -0700148 cwd = os.path.abspath(os.path.dirname(filename))
David James97d95872012-11-16 15:09:56 -0800149 commit = git.RunGit(cwd, ['rev-parse', 'HEAD']).output.rstrip()
Mike Frysinger5b34d732013-01-17 15:11:58 -0500150 description = '%s: updating %s' % (os.path.basename(filename),
151 ', '.join(data.keys()))
152 # UpdateLocalFile will print out the keys/values for us.
Mike Frysingerff441bf2014-05-24 13:47:21 -0400153 print('Revving git file %s' % filename)
David James66009462012-03-25 10:08:38 -0700154
David James8c846492011-01-25 17:07:29 -0800155 try:
David James97d95872012-11-16 15:09:56 -0800156 git.CreatePushBranch(prebuilt_branch, cwd)
Mike Frysinger5b34d732013-01-17 15:11:58 -0500157 for key, value in data.iteritems():
158 UpdateLocalFile(filename, value, key)
David James97d95872012-11-16 15:09:56 -0800159 git.RunGit(cwd, ['add', filename])
160 git.RunGit(cwd, ['commit', '-m', description])
161 git.PushWithRetry(prebuilt_branch, cwd, dryrun=dryrun, retries=retries)
David James8c846492011-01-25 17:07:29 -0800162 finally:
David James67d73252013-09-19 17:33:12 -0700163 git.RunGit(cwd, ['checkout', commit])
David James8c846492011-01-25 17:07:29 -0800164
165
166def GetVersion():
167 """Get the version to put in LATEST and update the git version with."""
Mike Frysinger0b92cfe2012-12-13 02:13:45 -0500168 return datetime.datetime.now().strftime('%Y.%m.%d.%H%M%S')
David James8c846492011-01-25 17:07:29 -0800169
170
Mike Frysinger540883b2014-05-24 13:46:16 -0400171def _GsUpload(gs_context, acl, local_file, remote_file):
David James8c846492011-01-25 17:07:29 -0800172 """Upload to GS bucket.
173
174 Args:
Mike Frysinger540883b2014-05-24 13:46:16 -0400175 gs_context: A lib.gs.GSContext instance.
176 acl: The ACL to use for uploading the file.
Matt Tennante8179042013-10-01 15:47:32 -0700177 local_file: The local file to be uploaded.
178 remote_file: The remote location to upload to.
David James8c846492011-01-25 17:07:29 -0800179
180 Returns:
181 Return the arg tuple of two if the upload failed
182 """
Scott Zawalskiab1bed32011-03-16 15:24:24 -0700183 CANNED_ACLS = ['public-read', 'private', 'bucket-owner-read',
184 'authenticated-read', 'bucket-owner-full-control',
185 'public-read-write']
Scott Zawalskiab1bed32011-03-16 15:24:24 -0700186 if acl in CANNED_ACLS:
David James9374aac2013-10-08 16:00:17 -0700187 gs_context.Copy(local_file, remote_file, acl=acl)
Scott Zawalskiab1bed32011-03-16 15:24:24 -0700188 else:
189 # For private uploads we assume that the overlay board is set up properly
David James015af872012-06-19 15:24:36 -0700190 # and a googlestore_acl.xml is present. Otherwise, this script errors.
David James9374aac2013-10-08 16:00:17 -0700191 gs_context.Copy(local_file, remote_file, acl='private')
Gabe Black40169e62014-06-17 15:23:47 -0700192 if acl.endswith('.xml'):
193 # Apply the passed in ACL xml file to the uploaded object.
194 gs_context.SetACL(remote_file, acl=acl)
195 else:
196 gs_context.ChangeACL(remote_file, acl_args_file=acl)
Scott Zawalskiab1bed32011-03-16 15:24:24 -0700197
Mike Frysingercc838832014-05-24 13:10:30 -0400198
Mike Frysinger540883b2014-05-24 13:46:16 -0400199def RemoteUpload(gs_context, acl, files, pool=10):
David James8c846492011-01-25 17:07:29 -0800200 """Upload to google storage.
201
202 Create a pool of process and call _GsUpload with the proper arguments.
203
204 Args:
Mike Frysinger540883b2014-05-24 13:46:16 -0400205 gs_context: A lib.gs.GSContext instance.
David Jamesfd0b0852011-02-23 11:15:36 -0800206 acl: The canned acl used for uploading. acl can be one of: "public-read",
207 "public-read-write", "authenticated-read", "bucket-owner-read",
208 "bucket-owner-full-control", or "private".
David James8c846492011-01-25 17:07:29 -0800209 files: dictionary with keys to local files and values to remote path.
210 pool: integer of maximum proesses to have at the same time.
211
212 Returns:
213 Return a set of tuple arguments of the failed uploads
214 """
Mike Frysinger540883b2014-05-24 13:46:16 -0400215 upload = functools.partial(_GsUpload, gs_context, acl)
216 tasks = [[key, value] for key, value in files.iteritems()]
217 parallel.RunTasksInProcessPool(upload, tasks, pool)
David James8c846492011-01-25 17:07:29 -0800218
219
220def GenerateUploadDict(base_local_path, base_remote_path, pkgs):
221 """Build a dictionary of local remote file key pairs to upload.
222
223 Args:
224 base_local_path: The base path to the files on the local hard drive.
Matt Tennante8179042013-10-01 15:47:32 -0700225 base_remote_path: The base path to the remote paths.
David James8c846492011-01-25 17:07:29 -0800226 pkgs: The packages to upload.
227
228 Returns:
229 Returns a dictionary of local_path/remote_path pairs
230 """
231 upload_files = {}
232 for pkg in pkgs:
233 suffix = pkg['CPV'] + '.tbz2'
234 local_path = os.path.join(base_local_path, suffix)
235 assert os.path.exists(local_path)
236 remote_path = '%s/%s' % (base_remote_path.rstrip('/'), suffix)
237 upload_files[local_path] = remote_path
238
239 return upload_files
240
Mike Frysingercc838832014-05-24 13:10:30 -0400241
Peter Mayo950e41a2014-02-06 21:07:33 +0000242def GetBoardOverlay(build_path, target):
David Jamese5867812012-10-19 12:02:20 -0700243 """Get the path to the board variant.
Mike Frysinger1a736a82013-12-12 01:50:59 -0500244
David James8c846492011-01-25 17:07:29 -0800245 Args:
246 build_path: The path to the root of the build directory
David Jamese5867812012-10-19 12:02:20 -0700247 target: The target board as a BuildTarget object.
Mike Frysinger1a736a82013-12-12 01:50:59 -0500248
David James8c846492011-01-25 17:07:29 -0800249 Returns:
David Jamese5867812012-10-19 12:02:20 -0700250 The last overlay configured for the given board as a string.
David James8c846492011-01-25 17:07:29 -0800251 """
David Jamese5867812012-10-19 12:02:20 -0700252 board = target.board_variant
Alex Deymo075c2292014-09-04 18:31:50 -0700253 overlays = portage_util.FindOverlays(constants.BOTH_OVERLAYS, board,
254 buildroot=build_path)
David Jamese5867812012-10-19 12:02:20 -0700255 # We only care about the last entry.
256 return overlays[-1]
David James8c846492011-01-25 17:07:29 -0800257
258
259def DeterminePrebuiltConfFile(build_path, target):
260 """Determine the prebuilt.conf file that needs to be updated for prebuilts.
261
Mike Frysinger1a736a82013-12-12 01:50:59 -0500262 Args:
263 build_path: The path to the root of the build directory
264 target: String representation of the board. This includes host and board
265 targets
David James8c846492011-01-25 17:07:29 -0800266
Mike Frysinger1a736a82013-12-12 01:50:59 -0500267 Returns:
268 A string path to a prebuilt.conf file to be updated.
David James8c846492011-01-25 17:07:29 -0800269 """
David James4058b0d2011-12-08 21:24:50 -0800270 if _HOST_ARCH == target:
David James8c846492011-01-25 17:07:29 -0800271 # We are host.
272 # Without more examples of hosts this is a kludge for now.
273 # TODO(Scottz): as new host targets come online expand this to
274 # work more like boards.
Chris Sosa471532a2011-02-01 15:10:06 -0800275 make_path = _PREBUILT_MAKE_CONF[target]
David James8c846492011-01-25 17:07:29 -0800276 else:
277 # We are a board
Peter Mayo950e41a2014-02-06 21:07:33 +0000278 board = GetBoardOverlay(build_path, target)
David James8c846492011-01-25 17:07:29 -0800279 make_path = os.path.join(board, 'prebuilt.conf')
280
281 return make_path
282
283
284def UpdateBinhostConfFile(path, key, value):
285 """Update binhost config file file with key=value.
286
287 Args:
288 path: Filename to update.
289 key: Key to update.
290 value: New value for key.
291 """
292 cwd = os.path.dirname(os.path.abspath(path))
293 filename = os.path.basename(path)
Brian Harringaf019fb2012-05-10 15:06:13 -0700294 osutils.SafeMakedirs(cwd)
David Jamesf6e8fb72013-05-10 08:58:43 -0700295 if not git.GetCurrentBranch(cwd):
296 git.CreatePushBranch(constants.STABLE_EBUILD_BRANCH, cwd, sync=False)
Brian Harring22edb442012-05-11 23:55:18 -0700297 osutils.WriteFile(path, '', mode='a')
David James8c846492011-01-25 17:07:29 -0800298 UpdateLocalFile(path, value, key)
David James67d73252013-09-19 17:33:12 -0700299 git.RunGit(cwd, ['add', filename])
Mike Frysinger109cada2013-01-17 15:50:44 -0500300 description = '%s: updating %s' % (os.path.basename(filename), key)
David James67d73252013-09-19 17:33:12 -0700301 git.RunGit(cwd, ['commit', '-m', description])
David James8c846492011-01-25 17:07:29 -0800302
303
Mike Frysinger212e4292014-05-24 15:15:44 -0400304def GenerateHtmlIndex(files, index, board, version):
305 """Given the list of |files|, generate an index.html at |index|.
306
307 Args:
308 files: The list of files to link to.
309 index: The path to the html index.
310 board: Name of the board this index is for.
311 version: Build version this index is for.
312 """
313 head = """<html>
314<head>
315 <title>Package Prebuilt Index: %(board)s / %(version)s</title>
316</head>
317<body>
318<h2>Package Prebuilt Index: %(board)s / %(version)s</h2>"""
319 head %= {
320 'board': board,
321 'version': version,
322 }
323
324 files = files + [
325 '.|Google Storage Index',
326 '..|',
327 ]
328 commands.GenerateHtmlIndex(index, files, head=head)
329
330
David Jamesce093af2011-02-23 15:21:58 -0800331def _GrabAllRemotePackageIndexes(binhost_urls):
David James05bcb2b2011-02-09 09:25:47 -0800332 """Grab all of the packages files associated with a list of binhost_urls.
333
David James05bcb2b2011-02-09 09:25:47 -0800334 Args:
335 binhost_urls: The URLs for the directories containing the Packages files we
336 want to grab.
David James05bcb2b2011-02-09 09:25:47 -0800337
338 Returns:
339 A list of PackageIndex objects.
340 """
341 pkg_indexes = []
342 for url in binhost_urls:
David James32faafe2012-06-08 14:25:03 -0700343 pkg_index = binpkg.GrabRemotePackageIndex(url)
David James05bcb2b2011-02-09 09:25:47 -0800344 if pkg_index:
345 pkg_indexes.append(pkg_index)
David James05bcb2b2011-02-09 09:25:47 -0800346 return pkg_indexes
347
348
David Jamesc0f158a2011-02-22 16:07:29 -0800349class PrebuiltUploader(object):
350 """Synchronize host and board prebuilts."""
David James8c846492011-01-25 17:07:29 -0800351
Mike Frysinger86509232014-05-24 13:18:37 -0400352 def __init__(self, upload_location, acl, binhost_base_url, pkg_indexes,
353 build_path, packages, skip_upload, binhost_conf_dir, dryrun,
Mike Frysinger8092a632014-05-24 13:25:46 -0400354 target, slave_targets, version):
David Jamesc0f158a2011-02-22 16:07:29 -0800355 """Constructor for prebuilt uploader object.
David James8c846492011-01-25 17:07:29 -0800356
David Jamesc0f158a2011-02-22 16:07:29 -0800357 This object can upload host or prebuilt files to Google Storage.
David James8c846492011-01-25 17:07:29 -0800358
David Jamesc0f158a2011-02-22 16:07:29 -0800359 Args:
360 upload_location: The upload location.
David Jamesfd0b0852011-02-23 11:15:36 -0800361 acl: The canned acl used for uploading to Google Storage. acl can be one
362 of: "public-read", "public-read-write", "authenticated-read",
Matt Tennante8179042013-10-01 15:47:32 -0700363 "bucket-owner-read", "bucket-owner-full-control", "project-private",
364 or "private" (see "gsutil help acls"). If we are not uploading to
365 Google Storage, this parameter is unused.
David Jamesfd0b0852011-02-23 11:15:36 -0800366 binhost_base_url: The URL used for downloading the prebuilts.
David Jamesc0f158a2011-02-22 16:07:29 -0800367 pkg_indexes: Old uploaded prebuilts to compare against. Instead of
368 uploading duplicate files, we just link to the old files.
David James615e5b52011-06-03 11:10:15 -0700369 build_path: The path to the directory containing the chroot.
370 packages: Packages to upload.
David James32b0b2f2011-07-13 20:56:50 -0700371 skip_upload: Don't actually upload the tarballs.
372 binhost_conf_dir: Directory where to store binhost.conf files.
Mike Frysinger86509232014-05-24 13:18:37 -0400373 dryrun: Don't push or upload prebuilts.
David James4058b0d2011-12-08 21:24:50 -0800374 target: BuildTarget managed by this builder.
375 slave_targets: List of BuildTargets managed by slave builders.
Mike Frysinger8092a632014-05-24 13:25:46 -0400376 version: A unique string, intended to be included in the upload path,
377 which identifies the version number of the uploaded prebuilts.
David Jamesc0f158a2011-02-22 16:07:29 -0800378 """
379 self._upload_location = upload_location
David Jamesfd0b0852011-02-23 11:15:36 -0800380 self._acl = acl
David Jamesc0f158a2011-02-22 16:07:29 -0800381 self._binhost_base_url = binhost_base_url
382 self._pkg_indexes = pkg_indexes
David James615e5b52011-06-03 11:10:15 -0700383 self._build_path = build_path
384 self._packages = set(packages)
Mike Frysingerf5f809a2013-02-12 13:47:37 -0500385 self._found_packages = set()
David James8ece7ee2011-06-29 16:02:30 -0700386 self._skip_upload = skip_upload
David James32b0b2f2011-07-13 20:56:50 -0700387 self._binhost_conf_dir = binhost_conf_dir
Mike Frysinger86509232014-05-24 13:18:37 -0400388 self._dryrun = dryrun
David James4058b0d2011-12-08 21:24:50 -0800389 self._target = target
390 self._slave_targets = slave_targets
Mike Frysinger8092a632014-05-24 13:25:46 -0400391 self._version = version
Mike Frysinger540883b2014-05-24 13:46:16 -0400392 self._gs_context = gs.GSContext(retries=_RETRIES, sleep=_SLEEP_TIME,
393 dry_run=self._dryrun)
394
395 def _Upload(self, local_file, remote_file):
396 """Wrapper around _GsUpload"""
397 _GsUpload(self._gs_context, self._acl, local_file, remote_file)
David James615e5b52011-06-03 11:10:15 -0700398
399 def _ShouldFilterPackage(self, pkg):
400 if not self._packages:
401 return False
402 pym_path = os.path.abspath(os.path.join(self._build_path, _PYM_PATH))
David James710b7dc2012-02-07 16:49:59 -0800403 sys.path.insert(0, pym_path)
Don Garrett25f309a2014-03-19 14:02:12 -0700404 # pylint: disable=F0401
David James615e5b52011-06-03 11:10:15 -0700405 import portage.versions
406 cat, pkgname = portage.versions.catpkgsplit(pkg['CPV'])[0:2]
407 cp = '%s/%s' % (cat, pkgname)
Mike Frysingerf5f809a2013-02-12 13:47:37 -0500408 self._found_packages.add(cp)
David James615e5b52011-06-03 11:10:15 -0700409 return pkgname not in self._packages and cp not in self._packages
David James8c846492011-01-25 17:07:29 -0800410
David Jamesc0f158a2011-02-22 16:07:29 -0800411 def _UploadPrebuilt(self, package_path, url_suffix):
412 """Upload host or board prebuilt files to Google Storage space.
David James8c846492011-01-25 17:07:29 -0800413
David Jamesc0f158a2011-02-22 16:07:29 -0800414 Args:
415 package_path: The path to the packages dir.
David Jamesce093af2011-02-23 15:21:58 -0800416 url_suffix: The remote subdirectory where we should upload the packages.
David Jamesc0f158a2011-02-22 16:07:29 -0800417 """
David Jamesc0f158a2011-02-22 16:07:29 -0800418 # Process Packages file, removing duplicates and filtered packages.
David James32faafe2012-06-08 14:25:03 -0700419 pkg_index = binpkg.GrabLocalPackageIndex(package_path)
David Jamesc0f158a2011-02-22 16:07:29 -0800420 pkg_index.SetUploadLocation(self._binhost_base_url, url_suffix)
David James615e5b52011-06-03 11:10:15 -0700421 pkg_index.RemoveFilteredPackages(self._ShouldFilterPackage)
David Jamesc0f158a2011-02-22 16:07:29 -0800422 uploads = pkg_index.ResolveDuplicateUploads(self._pkg_indexes)
Mike Frysingerf5f809a2013-02-12 13:47:37 -0500423 unmatched_pkgs = self._packages - self._found_packages
424 if unmatched_pkgs:
425 cros_build_lib.Warning('unable to match packages: %r' % unmatched_pkgs)
David James05bcb2b2011-02-09 09:25:47 -0800426
David Jamesc0f158a2011-02-22 16:07:29 -0800427 # Write Packages file.
David James5ab67e32014-10-24 08:19:59 -0700428 pkg_index.header['TTL'] = _BINPKG_TTL
David Jamesc0f158a2011-02-22 16:07:29 -0800429 tmp_packages_file = pkg_index.WriteToNamedTemporaryFile()
David James05bcb2b2011-02-09 09:25:47 -0800430
David Jamesc0f158a2011-02-22 16:07:29 -0800431 remote_location = '%s/%s' % (self._upload_location.rstrip('/'), url_suffix)
David James015af872012-06-19 15:24:36 -0700432 assert remote_location.startswith('gs://')
David James05bcb2b2011-02-09 09:25:47 -0800433
David James015af872012-06-19 15:24:36 -0700434 # Build list of files to upload.
435 upload_files = GenerateUploadDict(package_path, remote_location, uploads)
436 remote_file = '%s/Packages' % remote_location.rstrip('/')
437 upload_files[tmp_packages_file.name] = remote_file
438
Mike Frysinger540883b2014-05-24 13:46:16 -0400439 RemoteUpload(self._gs_context, self._acl, upload_files)
David James8c846492011-01-25 17:07:29 -0800440
Mike Frysinger212e4292014-05-24 15:15:44 -0400441 with tempfile.NamedTemporaryFile(
442 prefix='chromite.upload_prebuilts.index.') as index:
443 GenerateHtmlIndex(
444 [x[len(remote_location) + 1:] for x in upload_files.values()],
445 index.name, self._target, self._version)
446 self._Upload(index.name, '%s/index.html' % remote_location.rstrip('/'))
447
448 link_name = 'Prebuilts[%s]: %s' % (self._target, self._version)
449 url = '%s%s/index.html' % (gs.PUBLIC_BASE_HTTPS_URL,
450 remote_location[len(gs.BASE_GS_URL):])
451 cros_build_lib.PrintBuildbotLink(link_name, url)
452
Mike Frysinger8092a632014-05-24 13:25:46 -0400453 def _UploadSdkTarball(self, board_path, url_suffix, prepackaged,
Mike Frysinger9e979b92012-11-29 02:55:09 -0500454 toolchain_tarballs, toolchain_upload_path):
455 """Upload a tarball of the sdk at the specified path to Google Storage.
David James8fa34ea2011-04-15 13:00:20 -0700456
457 Args:
458 board_path: The path to the board dir.
459 url_suffix: The remote subdirectory where we should upload the packages.
Zdenek Behan62a57792012-08-31 15:09:08 +0200460 prepackaged: If given, a tarball that has been packaged outside of this
461 script and should be used.
Mike Frysinger9e979b92012-11-29 02:55:09 -0500462 toolchain_tarballs: List of toolchain tarballs to upload.
463 toolchain_upload_path: Path under the bucket to place toolchain tarballs.
David James8fa34ea2011-04-15 13:00:20 -0700464 """
465 remote_location = '%s/%s' % (self._upload_location.rstrip('/'), url_suffix)
466 assert remote_location.startswith('gs://')
Zdenek Behan86c15e92012-10-13 00:55:47 +0200467 boardname = os.path.basename(board_path.rstrip('/'))
468 # We do not upload non SDK board tarballs,
469 assert boardname == constants.CHROOT_BUILDER_BOARD
470 assert prepackaged is not None
Zdenek Behan62a57792012-08-31 15:09:08 +0200471
Mike Frysinger8092a632014-05-24 13:25:46 -0400472 version_str = self._version[len('chroot-'):]
Mike Frysinger8e727a32013-01-16 16:57:53 -0500473 remote_tarfile = toolchain.GetSdkURL(
474 for_gsutil=True, suburl='cros-sdk-%s.tar.xz' % (version_str,))
Zdenek Behan86c15e92012-10-13 00:55:47 +0200475 # For SDK, also upload the manifest which is guaranteed to exist
476 # by the builderstage.
Mike Frysinger540883b2014-05-24 13:46:16 -0400477 self._Upload(prepackaged + '.Manifest', remote_tarfile + '.Manifest')
478 self._Upload(prepackaged, remote_tarfile)
Zdenek Behan86c15e92012-10-13 00:55:47 +0200479
Mike Frysinger9e979b92012-11-29 02:55:09 -0500480 # Post the toolchain tarballs too.
481 for tarball in toolchain_tarballs:
482 target, local_path = tarball.split(':')
483 suburl = toolchain_upload_path % {'target': target}
484 remote_path = toolchain.GetSdkURL(for_gsutil=True, suburl=suburl)
Mike Frysinger540883b2014-05-24 13:46:16 -0400485 self._Upload(local_path, remote_path)
Mike Frysinger9e979b92012-11-29 02:55:09 -0500486
Zdenek Behan86c15e92012-10-13 00:55:47 +0200487 # Finally, also update the pointer to the latest SDK on which polling
488 # scripts rely.
David James4bc13702013-03-26 08:08:04 -0700489 with osutils.TempDir() as tmpdir:
Zdenek Behan86c15e92012-10-13 00:55:47 +0200490 pointerfile = os.path.join(tmpdir, 'cros-sdk-latest.conf')
Mike Frysinger8e727a32013-01-16 16:57:53 -0500491 remote_pointerfile = toolchain.GetSdkURL(for_gsutil=True,
492 suburl='cros-sdk-latest.conf')
Zdenek Behan86c15e92012-10-13 00:55:47 +0200493 osutils.WriteFile(pointerfile, 'LATEST_SDK="%s"' % version_str)
Mike Frysinger540883b2014-05-24 13:46:16 -0400494 self._Upload(pointerfile, remote_pointerfile)
Zdenek Behan33a34112012-09-10 21:07:51 +0200495
Chris Sosa6a5dceb2012-05-14 13:48:56 -0700496 def _GetTargets(self):
497 """Retuns the list of targets to use."""
498 targets = self._slave_targets[:]
499 if self._target:
500 targets.append(self._target)
501
502 return targets
503
Mike Frysinger8092a632014-05-24 13:25:46 -0400504 def SyncHostPrebuilts(self, key, git_sync, sync_binhost_conf):
David Jamesc0f158a2011-02-22 16:07:29 -0800505 """Synchronize host prebuilt files.
David James05bcb2b2011-02-09 09:25:47 -0800506
David Jamesc0f158a2011-02-22 16:07:29 -0800507 This function will sync both the standard host packages, plus the host
508 packages associated with all targets that have been "setup" with the
509 current host's chroot. For instance, if this host has been used to build
510 x86-generic, it will sync the host packages associated with
511 'i686-pc-linux-gnu'. If this host has also been used to build arm-generic,
512 it will also sync the host packages associated with
513 'armv7a-cros-linux-gnueabi'.
David James05bcb2b2011-02-09 09:25:47 -0800514
David Jamesc0f158a2011-02-22 16:07:29 -0800515 Args:
David Jamesc0f158a2011-02-22 16:07:29 -0800516 key: The variable key to update in the git file.
517 git_sync: If set, update make.conf of target to reference the latest
518 prebuilt packages generated here.
519 sync_binhost_conf: If set, update binhost config file in
520 chromiumos-overlay for the host.
521 """
David Jamese2488642011-11-14 16:15:20 -0800522 # Slave boards are listed before the master board so that the master board
523 # takes priority (i.e. x86-generic preflight host prebuilts takes priority
524 # over preflight host prebuilts from other builders.)
525 binhost_urls = []
Chris Sosa6a5dceb2012-05-14 13:48:56 -0700526 for target in self._GetTargets():
Mike Frysinger8092a632014-05-24 13:25:46 -0400527 url_suffix = _REL_HOST_PATH % {'version': self._version,
David James4058b0d2011-12-08 21:24:50 -0800528 'host_arch': _HOST_ARCH,
529 'target': target}
David Jamese2488642011-11-14 16:15:20 -0800530 packages_url_suffix = '%s/packages' % url_suffix.rstrip('/')
David James05bcb2b2011-02-09 09:25:47 -0800531
Mike Frysinger540883b2014-05-24 13:46:16 -0400532 if self._target == target and not self._skip_upload:
David Jamese2488642011-11-14 16:15:20 -0800533 # Upload prebuilts.
534 package_path = os.path.join(self._build_path, _HOST_PACKAGES_PATH)
535 self._UploadPrebuilt(package_path, packages_url_suffix)
David James8ece7ee2011-06-29 16:02:30 -0700536
David Jamese2488642011-11-14 16:15:20 -0800537 # Record URL where prebuilts were uploaded.
538 binhost_urls.append('%s/%s/' % (self._binhost_base_url.rstrip('/'),
539 packages_url_suffix.rstrip('/')))
540
David James20b2b6f2011-11-18 15:11:58 -0800541 binhost = ' '.join(binhost_urls)
David James8ece7ee2011-06-29 16:02:30 -0700542 if git_sync:
543 git_file = os.path.join(self._build_path,
David James4058b0d2011-12-08 21:24:50 -0800544 _PREBUILT_MAKE_CONF[_HOST_ARCH])
Mike Frysinger86509232014-05-24 13:18:37 -0400545 RevGitFile(git_file, {key: binhost}, dryrun=self._dryrun)
David James8ece7ee2011-06-29 16:02:30 -0700546 if sync_binhost_conf:
David James32b0b2f2011-07-13 20:56:50 -0700547 binhost_conf = os.path.join(self._build_path, self._binhost_conf_dir,
David James4058b0d2011-12-08 21:24:50 -0800548 'host', '%s-%s.conf' % (_HOST_ARCH, key))
David Jamese2488642011-11-14 16:15:20 -0800549 UpdateBinhostConfFile(binhost_conf, key, binhost)
David Jamesc0f158a2011-02-22 16:07:29 -0800550
Mike Frysinger8092a632014-05-24 13:25:46 -0400551 def SyncBoardPrebuilts(self, key, git_sync, sync_binhost_conf,
Mike Frysinger9e979b92012-11-29 02:55:09 -0500552 upload_board_tarball, prepackaged_board,
553 toolchain_tarballs, toolchain_upload_path):
David Jamesc0f158a2011-02-22 16:07:29 -0800554 """Synchronize board prebuilt files.
555
556 Args:
David Jamesc0f158a2011-02-22 16:07:29 -0800557 key: The variable key to update in the git file.
558 git_sync: If set, update make.conf of target to reference the latest
559 prebuilt packages generated here.
560 sync_binhost_conf: If set, update binhost config file in
561 chromiumos-overlay for the current board.
David James8fa34ea2011-04-15 13:00:20 -0700562 upload_board_tarball: Include a tarball of the board in our upload.
Zdenek Behan62a57792012-08-31 15:09:08 +0200563 prepackaged_board: A tarball of the board built outside of this script.
Mike Frysinger9e979b92012-11-29 02:55:09 -0500564 toolchain_tarballs: A list of toolchain tarballs to upload.
565 toolchain_upload_path: Path under the bucket to place toolchain tarballs.
David Jamesc0f158a2011-02-22 16:07:29 -0800566 """
Chris Sosa6a5dceb2012-05-14 13:48:56 -0700567 for target in self._GetTargets():
David Jamese2488642011-11-14 16:15:20 -0800568 board_path = os.path.join(self._build_path,
David James4058b0d2011-12-08 21:24:50 -0800569 _BOARD_PATH % {'board': target.board_variant})
David Jamese2488642011-11-14 16:15:20 -0800570 package_path = os.path.join(board_path, 'packages')
Mike Frysinger8092a632014-05-24 13:25:46 -0400571 url_suffix = _REL_BOARD_PATH % {'target': target,
572 'version': self._version}
David Jamese2488642011-11-14 16:15:20 -0800573 packages_url_suffix = '%s/packages' % url_suffix.rstrip('/')
David James8fa34ea2011-04-15 13:00:20 -0700574
Matt Tennante8179042013-10-01 15:47:32 -0700575 # Process the target board differently if it is the main --board.
Mike Frysinger540883b2014-05-24 13:46:16 -0400576 if self._target == target and not self._skip_upload:
Matt Tennante8179042013-10-01 15:47:32 -0700577 # This strips "chroot" prefix because that is sometimes added as the
578 # --prepend-version argument (e.g. by chromiumos-sdk bot).
579 # TODO(build): Clean it up to be less hard-coded.
Mike Frysinger8092a632014-05-24 13:25:46 -0400580 version_str = self._version[len('chroot-'):]
Mike Frysinger9e979b92012-11-29 02:55:09 -0500581
David Jamese2488642011-11-14 16:15:20 -0800582 # Upload board tarballs in the background.
583 if upload_board_tarball:
Mike Frysinger9e979b92012-11-29 02:55:09 -0500584 if toolchain_upload_path:
585 toolchain_upload_path %= {'version': version_str}
586 tar_process = multiprocessing.Process(
587 target=self._UploadSdkTarball,
Mike Frysinger8092a632014-05-24 13:25:46 -0400588 args=(board_path, url_suffix, prepackaged_board,
Mike Frysinger9e979b92012-11-29 02:55:09 -0500589 toolchain_tarballs, toolchain_upload_path))
David Jamese2488642011-11-14 16:15:20 -0800590 tar_process.start()
David James8fa34ea2011-04-15 13:00:20 -0700591
David Jamese2488642011-11-14 16:15:20 -0800592 # Upload prebuilts.
593 self._UploadPrebuilt(package_path, packages_url_suffix)
David James8fa34ea2011-04-15 13:00:20 -0700594
David Jamese2488642011-11-14 16:15:20 -0800595 # Make sure we finished uploading the board tarballs.
596 if upload_board_tarball:
597 tar_process.join()
598 assert tar_process.exitcode == 0
599 # TODO(zbehan): This should be done cleaner.
Zdenek Behan33a34112012-09-10 21:07:51 +0200600 if target.board == constants.CHROOT_BUILDER_BOARD:
David Jamese2488642011-11-14 16:15:20 -0800601 sdk_conf = os.path.join(self._build_path, self._binhost_conf_dir,
Mike Frysinger5b34d732013-01-17 15:11:58 -0500602 'host/sdk_version.conf')
603 sdk_settings = {
Mike Frysinger9e979b92012-11-29 02:55:09 -0500604 'SDK_LATEST_VERSION': version_str,
605 'TC_PATH': toolchain_upload_path,
Mike Frysinger5b34d732013-01-17 15:11:58 -0500606 }
Mike Frysinger86509232014-05-24 13:18:37 -0400607 RevGitFile(sdk_conf, sdk_settings, dryrun=self._dryrun)
David Jamesc0f158a2011-02-22 16:07:29 -0800608
David Jamese2488642011-11-14 16:15:20 -0800609 # Record URL where prebuilts were uploaded.
610 url_value = '%s/%s/' % (self._binhost_base_url.rstrip('/'),
611 packages_url_suffix.rstrip('/'))
612
613 if git_sync:
David James4058b0d2011-12-08 21:24:50 -0800614 git_file = DeterminePrebuiltConfFile(self._build_path, target)
Mike Frysinger86509232014-05-24 13:18:37 -0400615 RevGitFile(git_file, {key: url_value}, dryrun=self._dryrun)
Matt Tennante8179042013-10-01 15:47:32 -0700616
David Jamese2488642011-11-14 16:15:20 -0800617 if sync_binhost_conf:
Matt Tennante8179042013-10-01 15:47:32 -0700618 # Update the binhost configuration file in git.
David Jamese2488642011-11-14 16:15:20 -0800619 binhost_conf = os.path.join(self._build_path, self._binhost_conf_dir,
David James4058b0d2011-12-08 21:24:50 -0800620 'target', '%s-%s.conf' % (target, key))
David Jamese2488642011-11-14 16:15:20 -0800621 UpdateBinhostConfFile(binhost_conf, key, url_value)
David James05bcb2b2011-02-09 09:25:47 -0800622
623
Chris Sosa6a5dceb2012-05-14 13:48:56 -0700624def _AddSlaveBoard(_option, _opt_str, value, parser):
625 """Callback that adds a slave board to the list of slave targets."""
David James4058b0d2011-12-08 21:24:50 -0800626 parser.values.slave_targets.append(BuildTarget(value))
627
628
Chris Sosa6a5dceb2012-05-14 13:48:56 -0700629def _AddSlaveProfile(_option, _opt_str, value, parser):
630 """Callback that adds a slave profile to the list of slave targets."""
David James4058b0d2011-12-08 21:24:50 -0800631 if not parser.values.slave_targets:
Mike Frysinger86509232014-05-24 13:18:37 -0400632 parser.error('Must specify --slave-board before --slave-profile')
David James4058b0d2011-12-08 21:24:50 -0800633 if parser.values.slave_targets[-1].profile is not None:
Mike Frysinger86509232014-05-24 13:18:37 -0400634 parser.error('Cannot specify --slave-profile twice for same board')
David James4058b0d2011-12-08 21:24:50 -0800635 parser.values.slave_targets[-1].profile = value
636
637
Mike Frysinger86509232014-05-24 13:18:37 -0400638def ParseOptions(argv):
Chris Sosa6a5dceb2012-05-14 13:48:56 -0700639 """Returns options given by the user and the target specified.
640
Mike Frysinger86509232014-05-24 13:18:37 -0400641 Args:
642 argv: The args to parse.
643
Mike Frysinger1a736a82013-12-12 01:50:59 -0500644 Returns:
645 A tuple containing a parsed options object and BuildTarget.
646 The target instance is None if no board is specified.
Chris Sosa6a5dceb2012-05-14 13:48:56 -0700647 """
Mike Frysinger86509232014-05-24 13:18:37 -0400648 parser = commandline.OptionParser()
David James8c846492011-01-25 17:07:29 -0800649 parser.add_option('-H', '--binhost-base-url', dest='binhost_base_url',
650 default=_BINHOST_BASE_URL,
651 help='Base URL to use for binhost in make.conf updates')
652 parser.add_option('', '--previous-binhost-url', action='append',
653 default=[], dest='previous_binhost_url',
654 help='Previous binhost URL')
655 parser.add_option('-b', '--board', dest='board', default=None,
656 help='Board type that was built on this machine')
Zdenek Behan62a57792012-08-31 15:09:08 +0200657 parser.add_option('-B', '--prepackaged-tarball', dest='prepackaged_tarball',
658 default=None,
659 help='Board tarball prebuilt outside of this script.')
Mike Frysinger9e979b92012-11-29 02:55:09 -0500660 parser.add_option('--toolchain-tarball', dest='toolchain_tarballs',
661 action='append', default=[],
662 help='Redistributable toolchain tarball.')
663 parser.add_option('--toolchain-upload-path', default='',
664 help='Path to place toolchain tarballs in the sdk tree.')
David James4058b0d2011-12-08 21:24:50 -0800665 parser.add_option('', '--profile', dest='profile', default=None,
666 help='Profile that was built on this machine')
667 parser.add_option('', '--slave-board', default=[], action='callback',
668 dest='slave_targets', type='string',
Chris Sosa6a5dceb2012-05-14 13:48:56 -0700669 callback=_AddSlaveBoard,
David James4058b0d2011-12-08 21:24:50 -0800670 help='Board type that was built on a slave machine. To '
671 'add a profile to this board, use --slave-profile.')
672 parser.add_option('', '--slave-profile', action='callback', type='string',
Chris Sosa6a5dceb2012-05-14 13:48:56 -0700673 callback=_AddSlaveProfile,
David James4058b0d2011-12-08 21:24:50 -0800674 help='Board profile that was built on a slave machine. '
675 'Applies to previous slave board.')
David James8c846492011-01-25 17:07:29 -0800676 parser.add_option('-p', '--build-path', dest='build_path',
David James05bcb2b2011-02-09 09:25:47 -0800677 help='Path to the directory containing the chroot')
David James615e5b52011-06-03 11:10:15 -0700678 parser.add_option('', '--packages', action='append',
679 default=[], dest='packages',
680 help='Only include the specified packages. '
681 '(Default is to include all packages.)')
David James8c846492011-01-25 17:07:29 -0800682 parser.add_option('-s', '--sync-host', dest='sync_host',
683 default=False, action='store_true',
684 help='Sync host prebuilts')
685 parser.add_option('-g', '--git-sync', dest='git_sync',
686 default=False, action='store_true',
David Jamese2488642011-11-14 16:15:20 -0800687 help='Enable git version sync (This commits to a repo.) '
688 'This is used by full builders to commit directly '
689 'to board overlays.')
David James8c846492011-01-25 17:07:29 -0800690 parser.add_option('-u', '--upload', dest='upload',
691 default=None,
692 help='Upload location')
693 parser.add_option('-V', '--prepend-version', dest='prepend_version',
694 default=None,
695 help='Add an identifier to the front of the version')
696 parser.add_option('-f', '--filters', dest='filters', action='store_true',
697 default=False,
698 help='Turn on filtering of private ebuild packages')
699 parser.add_option('-k', '--key', dest='key',
700 default='PORTAGE_BINHOST',
701 help='Key to update in make.conf / binhost.conf')
David James8ece7ee2011-06-29 16:02:30 -0700702 parser.add_option('', '--set-version', dest='set_version',
703 default=None,
704 help='Specify the version string')
David James8c846492011-01-25 17:07:29 -0800705 parser.add_option('', '--sync-binhost-conf', dest='sync_binhost_conf',
706 default=False, action='store_true',
David Jamese2488642011-11-14 16:15:20 -0800707 help='Update binhost.conf in chromiumos-overlay or '
708 'chromeos-overlay. Commit the changes, but don\'t '
709 'push them. This is used for preflight binhosts.')
David James32b0b2f2011-07-13 20:56:50 -0700710 parser.add_option('', '--binhost-conf-dir', dest='binhost_conf_dir',
David James32b0b2f2011-07-13 20:56:50 -0700711 help='Directory to commit binhost config with '
712 '--sync-binhost-conf.')
David Jamesfd0b0852011-02-23 11:15:36 -0800713 parser.add_option('-P', '--private', dest='private', action='store_true',
714 default=False, help='Mark gs:// uploads as private.')
David James8ece7ee2011-06-29 16:02:30 -0700715 parser.add_option('', '--skip-upload', dest='skip_upload',
716 action='store_true', default=False,
717 help='Skip upload step.')
David James8fa34ea2011-04-15 13:00:20 -0700718 parser.add_option('', '--upload-board-tarball', dest='upload_board_tarball',
719 action='store_true', default=False,
720 help='Upload board tarball to Google Storage.')
Mike Frysinger86509232014-05-24 13:18:37 -0400721 parser.add_option('-n', '--dry-run', dest='dryrun',
David James27fa7d12011-06-29 17:24:14 -0700722 action='store_true', default=False,
723 help='Don\'t push or upload prebuilts.')
David James8c846492011-01-25 17:07:29 -0800724
Mike Frysinger86509232014-05-24 13:18:37 -0400725 options, args = parser.parse_args(argv)
David James8c846492011-01-25 17:07:29 -0800726 if not options.build_path:
Mike Frysinger86509232014-05-24 13:18:37 -0400727 parser.error('you need provide a chroot path')
David James8ece7ee2011-06-29 16:02:30 -0700728 if not options.upload and not options.skip_upload:
Mike Frysinger86509232014-05-24 13:18:37 -0400729 parser.error('you need to provide an upload location using -u')
David James8ece7ee2011-06-29 16:02:30 -0700730 if not options.set_version and options.skip_upload:
Mike Frysinger86509232014-05-24 13:18:37 -0400731 parser.error('If you are using --skip-upload, you must specify a '
732 'version number using --set-version.')
David James9417f272011-05-26 13:24:47 -0700733 if args:
Mike Frysinger86509232014-05-24 13:18:37 -0400734 parser.error('invalid arguments passed to upload_prebuilts: %r' % args)
Scott Zawalskiab1bed32011-03-16 15:24:24 -0700735
Chris Sosa6a5dceb2012-05-14 13:48:56 -0700736 target = None
737 if options.board:
738 target = BuildTarget(options.board, options.profile)
739
740 if target in options.slave_targets:
Mike Frysinger86509232014-05-24 13:18:37 -0400741 parser.error('--board/--profile must not also be a slave target.')
David Jamese2488642011-11-14 16:15:20 -0800742
David James4058b0d2011-12-08 21:24:50 -0800743 if len(set(options.slave_targets)) != len(options.slave_targets):
Mike Frysinger86509232014-05-24 13:18:37 -0400744 parser.error('--slave-boards must not have duplicates.')
David Jamese2488642011-11-14 16:15:20 -0800745
David James4058b0d2011-12-08 21:24:50 -0800746 if options.slave_targets and options.git_sync:
Mike Frysinger86509232014-05-24 13:18:37 -0400747 parser.error('--slave-boards is not compatible with --git-sync')
David Jamese2488642011-11-14 16:15:20 -0800748
David James8ece7ee2011-06-29 16:02:30 -0700749 if (options.upload_board_tarball and options.skip_upload and
750 options.board == 'amd64-host'):
Mike Frysinger86509232014-05-24 13:18:37 -0400751 parser.error('--skip-upload is not compatible with '
752 '--upload-board-tarball and --board=amd64-host')
David James8fa34ea2011-04-15 13:00:20 -0700753
David James8ece7ee2011-06-29 16:02:30 -0700754 if (options.upload_board_tarball and not options.skip_upload and
755 not options.upload.startswith('gs://')):
Mike Frysinger86509232014-05-24 13:18:37 -0400756 parser.error('--upload-board-tarball only works with gs:// URLs.\n'
757 '--upload must be a gs:// URL.')
David James8fa34ea2011-04-15 13:00:20 -0700758
Zdenek Behan86c15e92012-10-13 00:55:47 +0200759 if options.upload_board_tarball and options.prepackaged_tarball is None:
Mike Frysinger86509232014-05-24 13:18:37 -0400760 parser.error('--upload-board-tarball requires --prepackaged-tarball')
Zdenek Behan86c15e92012-10-13 00:55:47 +0200761
Scott Zawalskiab1bed32011-03-16 15:24:24 -0700762 if options.private:
763 if options.sync_host:
Mike Frysinger86509232014-05-24 13:18:37 -0400764 parser.error('--private and --sync-host/-s cannot be specified '
765 'together; we do not support private host prebuilts')
Scott Zawalskiab1bed32011-03-16 15:24:24 -0700766
David James8ece7ee2011-06-29 16:02:30 -0700767 if not options.upload or not options.upload.startswith('gs://'):
Mike Frysinger86509232014-05-24 13:18:37 -0400768 parser.error('--private is only valid for gs:// URLs; '
769 '--upload must be a gs:// URL.')
Scott Zawalskiab1bed32011-03-16 15:24:24 -0700770
771 if options.binhost_base_url != _BINHOST_BASE_URL:
Mike Frysinger86509232014-05-24 13:18:37 -0400772 parser.error('when using --private the --binhost-base-url '
773 'is automatically derived.')
David James27fa7d12011-06-29 17:24:14 -0700774
David Jamesc31168e2014-06-05 14:40:05 -0700775 if options.sync_binhost_conf and not options.binhost_conf_dir:
776 parser.error('--sync-binhost-conf requires --binhost-conf-dir')
777
Chris Sosa6a5dceb2012-05-14 13:48:56 -0700778 return options, target
David Jamesc0f158a2011-02-22 16:07:29 -0800779
Mike Frysingercc838832014-05-24 13:10:30 -0400780
Mike Frysinger86509232014-05-24 13:18:37 -0400781def main(argv):
David Jamesdb401072011-06-10 12:17:16 -0700782 # Set umask to a sane value so that files created as root are readable.
Mike Frysinger60ec1012013-10-21 00:11:10 -0400783 os.umask(0o22)
David Jamesdb401072011-06-10 12:17:16 -0700784
Mike Frysinger86509232014-05-24 13:18:37 -0400785 options, target = ParseOptions(argv)
David Jamesc0f158a2011-02-22 16:07:29 -0800786
David James05bcb2b2011-02-09 09:25:47 -0800787 # Calculate a list of Packages index files to compare against. Whenever we
788 # upload a package, we check to make sure it's not already stored in one of
789 # the packages files we uploaded. This list of packages files might contain
790 # both board and host packages.
David Jamesce093af2011-02-23 15:21:58 -0800791 pkg_indexes = _GrabAllRemotePackageIndexes(options.previous_binhost_url)
David James8c846492011-01-25 17:07:29 -0800792
David James8ece7ee2011-06-29 16:02:30 -0700793 if options.set_version:
794 version = options.set_version
795 else:
796 version = GetVersion()
Matt Tennante8179042013-10-01 15:47:32 -0700797
David Jamesc0f158a2011-02-22 16:07:29 -0800798 if options.prepend_version:
799 version = '%s-%s' % (options.prepend_version, version)
800
Scott Zawalskiab1bed32011-03-16 15:24:24 -0700801 acl = 'public-read'
802 binhost_base_url = options.binhost_base_url
803
David Jamesadd21432013-05-21 10:04:07 -0700804 if options.private:
Scott Zawalskiab1bed32011-03-16 15:24:24 -0700805 binhost_base_url = options.upload
David Jamesadd21432013-05-21 10:04:07 -0700806 if target:
Prathmesh Prabhu421eef22014-10-16 17:13:19 -0700807 acl = portage_util.FindOverlayFile(_GOOGLESTORAGE_GSUTIL_FILE,
808 board=target.board_variant,
809 buildroot=options.build_path)
Scott Zawalskiab1bed32011-03-16 15:24:24 -0700810
811 uploader = PrebuiltUploader(options.upload, acl, binhost_base_url,
David James615e5b52011-06-03 11:10:15 -0700812 pkg_indexes, options.build_path,
David James27fa7d12011-06-29 17:24:14 -0700813 options.packages, options.skip_upload,
Mike Frysinger86509232014-05-24 13:18:37 -0400814 options.binhost_conf_dir, options.dryrun,
Mike Frysinger8092a632014-05-24 13:25:46 -0400815 target, options.slave_targets, version)
David Jamesc0f158a2011-02-22 16:07:29 -0800816
David James8c846492011-01-25 17:07:29 -0800817 if options.sync_host:
Mike Frysinger8092a632014-05-24 13:25:46 -0400818 uploader.SyncHostPrebuilts(options.key, options.git_sync,
Chris Sosa6a5dceb2012-05-14 13:48:56 -0700819 options.sync_binhost_conf)
David James8c846492011-01-25 17:07:29 -0800820
Chris Sosa62c8ff52012-06-04 15:03:12 -0700821 if options.board or options.slave_targets:
Mike Frysinger8092a632014-05-24 13:25:46 -0400822 uploader.SyncBoardPrebuilts(options.key, options.git_sync,
Chris Sosa6a5dceb2012-05-14 13:48:56 -0700823 options.sync_binhost_conf,
Zdenek Behan62a57792012-08-31 15:09:08 +0200824 options.upload_board_tarball,
Mike Frysinger9e979b92012-11-29 02:55:09 -0500825 options.prepackaged_tarball,
826 options.toolchain_tarballs,
827 options.toolchain_upload_path)