blob: 5c0a11eba678651f79070f2ad7e3cec859391a9d [file] [log] [blame]
David James8c846492011-01-25 17:07:29 -08001#!/usr/bin/python
David Jamesb619a782012-07-25 19:37:57 -07002# Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
David James8c846492011-01-25 17:07:29 -08003# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
5
Brian Harringaf019fb2012-05-10 15:06:13 -07006"""This script is used to upload host prebuilts as well as board BINHOSTS.
David James8c846492011-01-25 17:07:29 -08007
David James015af872012-06-19 15:24:36 -07008Prebuilts are uploaded using gsutil to Google Storage. After these prebuilts
9are successfully uploaded, a file is updated with the proper BINHOST version.
David James8c846492011-01-25 17:07:29 -080010
11To read more about prebuilts/binhost binary packages please refer to:
David James015af872012-06-19 15:24:36 -070012http://goto/chromeos-prebuilts
David James8c846492011-01-25 17:07:29 -080013
14Example of uploading prebuilt amd64 host files to Google Storage:
David Jamesc5cbd472012-06-19 16:25:45 -070015upload_prebuilts -p /b/cbuild/build -s -u gs://chromeos-prebuilt
David James8c846492011-01-25 17:07:29 -080016
17Example of uploading x86-dogfood binhosts to Google Storage:
David Jamesc5cbd472012-06-19 16:25:45 -070018upload_prebuilts -b x86-dogfood -p /b/cbuild/build/ -u gs://chromeos-prebuilt -g
David James8c846492011-01-25 17:07:29 -080019"""
20
Mike Frysingerff441bf2014-05-24 13:47:21 -040021from __future__ import print_function
22
Chris Sosa1dc96132012-05-11 15:40:50 -070023import datetime
Mike Frysinger540883b2014-05-24 13:46:16 -040024import functools
Chris Sosa1dc96132012-05-11 15:40:50 -070025import multiprocessing
Chris Sosa1dc96132012-05-11 15:40:50 -070026import os
27import sys
Mike Frysinger212e4292014-05-24 15:15:44 -040028import tempfile
Chris Sosa1dc96132012-05-11 15:40:50 -070029
Don Garrett88b8d782014-05-13 17:30:55 -070030from chromite.cbuildbot import constants
Mike Frysinger212e4292014-05-24 15:15:44 -040031from chromite.cbuildbot import cbuildbot_commands as commands
Don Garrett88b8d782014-05-13 17:30:55 -070032from chromite.cbuildbot import portage_utilities
David James6450a0a2012-12-04 07:59:53 -080033from chromite.lib import binpkg
Mike Frysinger86509232014-05-24 13:18:37 -040034from chromite.lib import commandline
Chris Sosa1dc96132012-05-11 15:40:50 -070035from chromite.lib import cros_build_lib
David James97d95872012-11-16 15:09:56 -080036from 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
Mike Frysinger8e727a32013-01-16 16:57:53 -050040from chromite.lib import toolchain
Chris Sosa1dc96132012-05-11 15:40:50 -070041
David James015af872012-06-19 15:24:36 -070042# How many times to retry uploads.
43_RETRIES = 10
44
45# Multiplier for how long to sleep (in seconds) between retries; will delay
46# (1*sleep) the first time, then (2*sleep), continuing via attempt * sleep.
47_SLEEP_TIME = 60
48
David James8c846492011-01-25 17:07:29 -080049_HOST_PACKAGES_PATH = 'chroot/var/lib/portage/pkgs'
David James05bcb2b2011-02-09 09:25:47 -080050_CATEGORIES_PATH = 'chroot/etc/portage/categories'
David James615e5b52011-06-03 11:10:15 -070051_PYM_PATH = 'chroot/usr/lib/portage/pym'
David James4058b0d2011-12-08 21:24:50 -080052_HOST_ARCH = 'amd64'
David James8c846492011-01-25 17:07:29 -080053_BOARD_PATH = 'chroot/build/%(board)s'
David James4058b0d2011-12-08 21:24:50 -080054_REL_BOARD_PATH = 'board/%(target)s/%(version)s'
55_REL_HOST_PATH = 'host/%(host_arch)s/%(target)s/%(version)s'
David James8c846492011-01-25 17:07:29 -080056# Private overlays to look at for builds to filter
57# relative to build path
58_PRIVATE_OVERLAY_DIR = 'src/private-overlays'
Scott Zawalskiab1bed32011-03-16 15:24:24 -070059_GOOGLESTORAGE_ACL_FILE = 'googlestorage_acl.xml'
David James3753d942014-04-23 10:55:48 -070060_BINHOST_BASE_URL = 'gs://chromeos-prebuilt'
David James8c846492011-01-25 17:07:29 -080061_PREBUILT_BASE_DIR = 'src/third_party/chromiumos-overlay/chromeos/config/'
62# Created in the event of new host targets becoming available
63_PREBUILT_MAKE_CONF = {'amd64': os.path.join(_PREBUILT_BASE_DIR,
64 'make.conf.amd64-host')}
65_BINHOST_CONF_DIR = 'src/third_party/chromiumos-overlay/chromeos/binhost'
66
67
David James4058b0d2011-12-08 21:24:50 -080068class BuildTarget(object):
69 """A board/variant/profile tuple."""
70
71 def __init__(self, board_variant, profile=None):
72 self.board_variant = board_variant
73 self.board, _, self.variant = board_variant.partition('_')
74 self.profile = profile
75
76 def __str__(self):
77 if self.profile:
78 return '%s_%s' % (self.board_variant, self.profile)
79 else:
80 return self.board_variant
81
82 def __eq__(self, other):
83 return str(other) == str(self)
84
85 def __hash__(self):
86 return hash(str(self))
87
88
David James8c846492011-01-25 17:07:29 -080089def UpdateLocalFile(filename, value, key='PORTAGE_BINHOST'):
90 """Update the key in file with the value passed.
Mike Frysinger1a736a82013-12-12 01:50:59 -050091
David James8c846492011-01-25 17:07:29 -080092 File format:
93 key="value"
94 Note quotes are added automatically
95
96 Args:
97 filename: Name of file to modify.
98 value: Value to write with the key.
99 key: The variable key to update. (Default: PORTAGE_BINHOST)
100 """
101 if os.path.exists(filename):
102 file_fh = open(filename)
103 else:
104 file_fh = open(filename, 'w+')
105 file_lines = []
106 found = False
107 keyval_str = '%(key)s=%(value)s'
108 for line in file_fh:
109 # Strip newlines from end of line. We already add newlines below.
110 line = line.rstrip("\n")
111
112 if len(line.split('=')) != 2:
113 # Skip any line that doesn't fit key=val.
114 file_lines.append(line)
115 continue
116
117 file_var, file_val = line.split('=')
118 if file_var == key:
119 found = True
Mike Frysingerff441bf2014-05-24 13:47:21 -0400120 print('Updating %s=%s to %s="%s"' % (file_var, file_val, key, value))
David James8c846492011-01-25 17:07:29 -0800121 value = '"%s"' % value
122 file_lines.append(keyval_str % {'key': key, 'value': value})
123 else:
124 file_lines.append(keyval_str % {'key': file_var, 'value': file_val})
125
126 if not found:
Brian Harring2a014302012-05-12 00:53:33 -0700127 value = '"%s"' % value
David James8c846492011-01-25 17:07:29 -0800128 file_lines.append(keyval_str % {'key': key, 'value': value})
129
130 file_fh.close()
131 # write out new file
Brian Harringaf019fb2012-05-10 15:06:13 -0700132 osutils.WriteFile(filename, '\n'.join(file_lines) + '\n')
David James8c846492011-01-25 17:07:29 -0800133
134
Mike Frysinger5b34d732013-01-17 15:11:58 -0500135def RevGitFile(filename, data, retries=5, dryrun=False):
David James8c846492011-01-25 17:07:29 -0800136 """Update and push the git file.
137
Mike Frysinger5b34d732013-01-17 15:11:58 -0500138 Args:
139 filename: file to modify that is in a git repo already
140 data: A dict of key/values to update in |filename|
141 retries: The number of times to retry before giving up, default: 5
Matt Tennante8179042013-10-01 15:47:32 -0700142 dryrun: If True, do not actually commit the change.
David James8c846492011-01-25 17:07:29 -0800143 """
144 prebuilt_branch = 'prebuilt_branch'
David James1b6e67a2011-05-19 21:32:38 -0700145 cwd = os.path.abspath(os.path.dirname(filename))
David James97d95872012-11-16 15:09:56 -0800146 commit = git.RunGit(cwd, ['rev-parse', 'HEAD']).output.rstrip()
Mike Frysinger5b34d732013-01-17 15:11:58 -0500147 description = '%s: updating %s' % (os.path.basename(filename),
148 ', '.join(data.keys()))
149 # UpdateLocalFile will print out the keys/values for us.
Mike Frysingerff441bf2014-05-24 13:47:21 -0400150 print('Revving git file %s' % filename)
David James66009462012-03-25 10:08:38 -0700151
David James8c846492011-01-25 17:07:29 -0800152 try:
David James97d95872012-11-16 15:09:56 -0800153 git.CreatePushBranch(prebuilt_branch, cwd)
Mike Frysinger5b34d732013-01-17 15:11:58 -0500154 for key, value in data.iteritems():
155 UpdateLocalFile(filename, value, key)
David James97d95872012-11-16 15:09:56 -0800156 git.RunGit(cwd, ['add', filename])
157 git.RunGit(cwd, ['commit', '-m', description])
158 git.PushWithRetry(prebuilt_branch, cwd, dryrun=dryrun, retries=retries)
David James8c846492011-01-25 17:07:29 -0800159 finally:
David James67d73252013-09-19 17:33:12 -0700160 git.RunGit(cwd, ['checkout', commit])
David James8c846492011-01-25 17:07:29 -0800161
162
163def GetVersion():
164 """Get the version to put in LATEST and update the git version with."""
Mike Frysinger0b92cfe2012-12-13 02:13:45 -0500165 return datetime.datetime.now().strftime('%Y.%m.%d.%H%M%S')
David James8c846492011-01-25 17:07:29 -0800166
167
Mike Frysinger540883b2014-05-24 13:46:16 -0400168def _GsUpload(gs_context, acl, local_file, remote_file):
David James8c846492011-01-25 17:07:29 -0800169 """Upload to GS bucket.
170
171 Args:
Mike Frysinger540883b2014-05-24 13:46:16 -0400172 gs_context: A lib.gs.GSContext instance.
173 acl: The ACL to use for uploading the file.
Matt Tennante8179042013-10-01 15:47:32 -0700174 local_file: The local file to be uploaded.
175 remote_file: The remote location to upload to.
David James8c846492011-01-25 17:07:29 -0800176
177 Returns:
178 Return the arg tuple of two if the upload failed
179 """
Scott Zawalskiab1bed32011-03-16 15:24:24 -0700180 CANNED_ACLS = ['public-read', 'private', 'bucket-owner-read',
181 'authenticated-read', 'bucket-owner-full-control',
182 'public-read-write']
Scott Zawalskiab1bed32011-03-16 15:24:24 -0700183 if acl in CANNED_ACLS:
David James9374aac2013-10-08 16:00:17 -0700184 gs_context.Copy(local_file, remote_file, acl=acl)
Scott Zawalskiab1bed32011-03-16 15:24:24 -0700185 else:
186 # For private uploads we assume that the overlay board is set up properly
David James015af872012-06-19 15:24:36 -0700187 # and a googlestore_acl.xml is present. Otherwise, this script errors.
David James9374aac2013-10-08 16:00:17 -0700188 gs_context.Copy(local_file, remote_file, acl='private')
Scott Zawalskiab1bed32011-03-16 15:24:24 -0700189 # Apply the passed in ACL xml file to the uploaded object.
David James9374aac2013-10-08 16:00:17 -0700190 gs_context.SetACL(remote_file, acl=acl)
Scott Zawalskiab1bed32011-03-16 15:24:24 -0700191
Mike Frysingercc838832014-05-24 13:10:30 -0400192
Mike Frysinger540883b2014-05-24 13:46:16 -0400193def RemoteUpload(gs_context, acl, files, pool=10):
David James8c846492011-01-25 17:07:29 -0800194 """Upload to google storage.
195
196 Create a pool of process and call _GsUpload with the proper arguments.
197
198 Args:
Mike Frysinger540883b2014-05-24 13:46:16 -0400199 gs_context: A lib.gs.GSContext instance.
David Jamesfd0b0852011-02-23 11:15:36 -0800200 acl: The canned acl used for uploading. acl can be one of: "public-read",
201 "public-read-write", "authenticated-read", "bucket-owner-read",
202 "bucket-owner-full-control", or "private".
David James8c846492011-01-25 17:07:29 -0800203 files: dictionary with keys to local files and values to remote path.
204 pool: integer of maximum proesses to have at the same time.
205
206 Returns:
207 Return a set of tuple arguments of the failed uploads
208 """
Mike Frysinger540883b2014-05-24 13:46:16 -0400209 upload = functools.partial(_GsUpload, gs_context, acl)
210 tasks = [[key, value] for key, value in files.iteritems()]
211 parallel.RunTasksInProcessPool(upload, tasks, pool)
David James8c846492011-01-25 17:07:29 -0800212
213
214def GenerateUploadDict(base_local_path, base_remote_path, pkgs):
215 """Build a dictionary of local remote file key pairs to upload.
216
217 Args:
218 base_local_path: The base path to the files on the local hard drive.
Matt Tennante8179042013-10-01 15:47:32 -0700219 base_remote_path: The base path to the remote paths.
David James8c846492011-01-25 17:07:29 -0800220 pkgs: The packages to upload.
221
222 Returns:
223 Returns a dictionary of local_path/remote_path pairs
224 """
225 upload_files = {}
226 for pkg in pkgs:
227 suffix = pkg['CPV'] + '.tbz2'
228 local_path = os.path.join(base_local_path, suffix)
229 assert os.path.exists(local_path)
230 remote_path = '%s/%s' % (base_remote_path.rstrip('/'), suffix)
231 upload_files[local_path] = remote_path
232
233 return upload_files
234
Mike Frysingercc838832014-05-24 13:10:30 -0400235
Peter Mayo950e41a2014-02-06 21:07:33 +0000236def GetBoardOverlay(build_path, target):
David Jamese5867812012-10-19 12:02:20 -0700237 """Get the path to the board variant.
Mike Frysinger1a736a82013-12-12 01:50:59 -0500238
David James8c846492011-01-25 17:07:29 -0800239 Args:
240 build_path: The path to the root of the build directory
David Jamese5867812012-10-19 12:02:20 -0700241 target: The target board as a BuildTarget object.
Mike Frysinger1a736a82013-12-12 01:50:59 -0500242
David James8c846492011-01-25 17:07:29 -0800243 Returns:
David Jamese5867812012-10-19 12:02:20 -0700244 The last overlay configured for the given board as a string.
David James8c846492011-01-25 17:07:29 -0800245 """
David Jamese5867812012-10-19 12:02:20 -0700246 board = target.board_variant
247 overlays = portage_utilities.FindOverlays(constants.BOTH_OVERLAYS, board,
248 buildroot=build_path)
249 # We only care about the last entry.
250 return overlays[-1]
David James8c846492011-01-25 17:07:29 -0800251
252
253def DeterminePrebuiltConfFile(build_path, target):
254 """Determine the prebuilt.conf file that needs to be updated for prebuilts.
255
Mike Frysinger1a736a82013-12-12 01:50:59 -0500256 Args:
257 build_path: The path to the root of the build directory
258 target: String representation of the board. This includes host and board
259 targets
David James8c846492011-01-25 17:07:29 -0800260
Mike Frysinger1a736a82013-12-12 01:50:59 -0500261 Returns:
262 A string path to a prebuilt.conf file to be updated.
David James8c846492011-01-25 17:07:29 -0800263 """
David James4058b0d2011-12-08 21:24:50 -0800264 if _HOST_ARCH == target:
David James8c846492011-01-25 17:07:29 -0800265 # We are host.
266 # Without more examples of hosts this is a kludge for now.
267 # TODO(Scottz): as new host targets come online expand this to
268 # work more like boards.
Chris Sosa471532a2011-02-01 15:10:06 -0800269 make_path = _PREBUILT_MAKE_CONF[target]
David James8c846492011-01-25 17:07:29 -0800270 else:
271 # We are a board
Peter Mayo950e41a2014-02-06 21:07:33 +0000272 board = GetBoardOverlay(build_path, target)
David James8c846492011-01-25 17:07:29 -0800273 make_path = os.path.join(board, 'prebuilt.conf')
274
275 return make_path
276
277
278def UpdateBinhostConfFile(path, key, value):
279 """Update binhost config file file with key=value.
280
281 Args:
282 path: Filename to update.
283 key: Key to update.
284 value: New value for key.
285 """
286 cwd = os.path.dirname(os.path.abspath(path))
287 filename = os.path.basename(path)
Brian Harringaf019fb2012-05-10 15:06:13 -0700288 osutils.SafeMakedirs(cwd)
David Jamesf6e8fb72013-05-10 08:58:43 -0700289 if not git.GetCurrentBranch(cwd):
290 git.CreatePushBranch(constants.STABLE_EBUILD_BRANCH, cwd, sync=False)
Brian Harring22edb442012-05-11 23:55:18 -0700291 osutils.WriteFile(path, '', mode='a')
David James8c846492011-01-25 17:07:29 -0800292 UpdateLocalFile(path, value, key)
David James67d73252013-09-19 17:33:12 -0700293 git.RunGit(cwd, ['add', filename])
Mike Frysinger109cada2013-01-17 15:50:44 -0500294 description = '%s: updating %s' % (os.path.basename(filename), key)
David James67d73252013-09-19 17:33:12 -0700295 git.RunGit(cwd, ['commit', '-m', description])
David James8c846492011-01-25 17:07:29 -0800296
297
Mike Frysinger212e4292014-05-24 15:15:44 -0400298def GenerateHtmlIndex(files, index, board, version):
299 """Given the list of |files|, generate an index.html at |index|.
300
301 Args:
302 files: The list of files to link to.
303 index: The path to the html index.
304 board: Name of the board this index is for.
305 version: Build version this index is for.
306 """
307 head = """<html>
308<head>
309 <title>Package Prebuilt Index: %(board)s / %(version)s</title>
310</head>
311<body>
312<h2>Package Prebuilt Index: %(board)s / %(version)s</h2>"""
313 head %= {
314 'board': board,
315 'version': version,
316 }
317
318 files = files + [
319 '.|Google Storage Index',
320 '..|',
321 ]
322 commands.GenerateHtmlIndex(index, files, head=head)
323
324
David Jamesce093af2011-02-23 15:21:58 -0800325def _GrabAllRemotePackageIndexes(binhost_urls):
David James05bcb2b2011-02-09 09:25:47 -0800326 """Grab all of the packages files associated with a list of binhost_urls.
327
David James05bcb2b2011-02-09 09:25:47 -0800328 Args:
329 binhost_urls: The URLs for the directories containing the Packages files we
330 want to grab.
David James05bcb2b2011-02-09 09:25:47 -0800331
332 Returns:
333 A list of PackageIndex objects.
334 """
335 pkg_indexes = []
336 for url in binhost_urls:
David James32faafe2012-06-08 14:25:03 -0700337 pkg_index = binpkg.GrabRemotePackageIndex(url)
David James05bcb2b2011-02-09 09:25:47 -0800338 if pkg_index:
339 pkg_indexes.append(pkg_index)
David James05bcb2b2011-02-09 09:25:47 -0800340 return pkg_indexes
341
342
David Jamesc0f158a2011-02-22 16:07:29 -0800343class PrebuiltUploader(object):
344 """Synchronize host and board prebuilts."""
David James8c846492011-01-25 17:07:29 -0800345
Mike Frysinger86509232014-05-24 13:18:37 -0400346 def __init__(self, upload_location, acl, binhost_base_url, pkg_indexes,
347 build_path, packages, skip_upload, binhost_conf_dir, dryrun,
Mike Frysinger8092a632014-05-24 13:25:46 -0400348 target, slave_targets, version):
David Jamesc0f158a2011-02-22 16:07:29 -0800349 """Constructor for prebuilt uploader object.
David James8c846492011-01-25 17:07:29 -0800350
David Jamesc0f158a2011-02-22 16:07:29 -0800351 This object can upload host or prebuilt files to Google Storage.
David James8c846492011-01-25 17:07:29 -0800352
David Jamesc0f158a2011-02-22 16:07:29 -0800353 Args:
354 upload_location: The upload location.
David Jamesfd0b0852011-02-23 11:15:36 -0800355 acl: The canned acl used for uploading to Google Storage. acl can be one
356 of: "public-read", "public-read-write", "authenticated-read",
Matt Tennante8179042013-10-01 15:47:32 -0700357 "bucket-owner-read", "bucket-owner-full-control", "project-private",
358 or "private" (see "gsutil help acls"). If we are not uploading to
359 Google Storage, this parameter is unused.
David Jamesfd0b0852011-02-23 11:15:36 -0800360 binhost_base_url: The URL used for downloading the prebuilts.
David Jamesc0f158a2011-02-22 16:07:29 -0800361 pkg_indexes: Old uploaded prebuilts to compare against. Instead of
362 uploading duplicate files, we just link to the old files.
David James615e5b52011-06-03 11:10:15 -0700363 build_path: The path to the directory containing the chroot.
364 packages: Packages to upload.
David James32b0b2f2011-07-13 20:56:50 -0700365 skip_upload: Don't actually upload the tarballs.
366 binhost_conf_dir: Directory where to store binhost.conf files.
Mike Frysinger86509232014-05-24 13:18:37 -0400367 dryrun: Don't push or upload prebuilts.
David James4058b0d2011-12-08 21:24:50 -0800368 target: BuildTarget managed by this builder.
369 slave_targets: List of BuildTargets managed by slave builders.
Mike Frysinger8092a632014-05-24 13:25:46 -0400370 version: A unique string, intended to be included in the upload path,
371 which identifies the version number of the uploaded prebuilts.
David Jamesc0f158a2011-02-22 16:07:29 -0800372 """
373 self._upload_location = upload_location
David Jamesfd0b0852011-02-23 11:15:36 -0800374 self._acl = acl
David Jamesc0f158a2011-02-22 16:07:29 -0800375 self._binhost_base_url = binhost_base_url
376 self._pkg_indexes = pkg_indexes
David James615e5b52011-06-03 11:10:15 -0700377 self._build_path = build_path
378 self._packages = set(packages)
Mike Frysingerf5f809a2013-02-12 13:47:37 -0500379 self._found_packages = set()
David James8ece7ee2011-06-29 16:02:30 -0700380 self._skip_upload = skip_upload
David James32b0b2f2011-07-13 20:56:50 -0700381 self._binhost_conf_dir = binhost_conf_dir
Mike Frysinger86509232014-05-24 13:18:37 -0400382 self._dryrun = dryrun
David James4058b0d2011-12-08 21:24:50 -0800383 self._target = target
384 self._slave_targets = slave_targets
Mike Frysinger8092a632014-05-24 13:25:46 -0400385 self._version = version
Mike Frysinger540883b2014-05-24 13:46:16 -0400386 self._gs_context = gs.GSContext(retries=_RETRIES, sleep=_SLEEP_TIME,
387 dry_run=self._dryrun)
388
389 def _Upload(self, local_file, remote_file):
390 """Wrapper around _GsUpload"""
391 _GsUpload(self._gs_context, self._acl, local_file, remote_file)
David James615e5b52011-06-03 11:10:15 -0700392
393 def _ShouldFilterPackage(self, pkg):
394 if not self._packages:
395 return False
396 pym_path = os.path.abspath(os.path.join(self._build_path, _PYM_PATH))
David James710b7dc2012-02-07 16:49:59 -0800397 sys.path.insert(0, pym_path)
Don Garrett25f309a2014-03-19 14:02:12 -0700398 # pylint: disable=F0401
David James615e5b52011-06-03 11:10:15 -0700399 import portage.versions
400 cat, pkgname = portage.versions.catpkgsplit(pkg['CPV'])[0:2]
401 cp = '%s/%s' % (cat, pkgname)
Mike Frysingerf5f809a2013-02-12 13:47:37 -0500402 self._found_packages.add(cp)
David James615e5b52011-06-03 11:10:15 -0700403 return pkgname not in self._packages and cp not in self._packages
David James8c846492011-01-25 17:07:29 -0800404
David Jamesc0f158a2011-02-22 16:07:29 -0800405 def _UploadPrebuilt(self, package_path, url_suffix):
406 """Upload host or board prebuilt files to Google Storage space.
David James8c846492011-01-25 17:07:29 -0800407
David Jamesc0f158a2011-02-22 16:07:29 -0800408 Args:
409 package_path: The path to the packages dir.
David Jamesce093af2011-02-23 15:21:58 -0800410 url_suffix: The remote subdirectory where we should upload the packages.
David Jamesc0f158a2011-02-22 16:07:29 -0800411 """
David Jamesc0f158a2011-02-22 16:07:29 -0800412 # Process Packages file, removing duplicates and filtered packages.
David James32faafe2012-06-08 14:25:03 -0700413 pkg_index = binpkg.GrabLocalPackageIndex(package_path)
David Jamesc0f158a2011-02-22 16:07:29 -0800414 pkg_index.SetUploadLocation(self._binhost_base_url, url_suffix)
David James615e5b52011-06-03 11:10:15 -0700415 pkg_index.RemoveFilteredPackages(self._ShouldFilterPackage)
David Jamesc0f158a2011-02-22 16:07:29 -0800416 uploads = pkg_index.ResolveDuplicateUploads(self._pkg_indexes)
Mike Frysingerf5f809a2013-02-12 13:47:37 -0500417 unmatched_pkgs = self._packages - self._found_packages
418 if unmatched_pkgs:
419 cros_build_lib.Warning('unable to match packages: %r' % unmatched_pkgs)
David James05bcb2b2011-02-09 09:25:47 -0800420
David Jamesc0f158a2011-02-22 16:07:29 -0800421 # Write Packages file.
422 tmp_packages_file = pkg_index.WriteToNamedTemporaryFile()
David James05bcb2b2011-02-09 09:25:47 -0800423
David Jamesc0f158a2011-02-22 16:07:29 -0800424 remote_location = '%s/%s' % (self._upload_location.rstrip('/'), url_suffix)
David James015af872012-06-19 15:24:36 -0700425 assert remote_location.startswith('gs://')
David James05bcb2b2011-02-09 09:25:47 -0800426
David James015af872012-06-19 15:24:36 -0700427 # Build list of files to upload.
428 upload_files = GenerateUploadDict(package_path, remote_location, uploads)
429 remote_file = '%s/Packages' % remote_location.rstrip('/')
430 upload_files[tmp_packages_file.name] = remote_file
431
Mike Frysinger540883b2014-05-24 13:46:16 -0400432 RemoteUpload(self._gs_context, self._acl, upload_files)
David James8c846492011-01-25 17:07:29 -0800433
Mike Frysinger212e4292014-05-24 15:15:44 -0400434 with tempfile.NamedTemporaryFile(
435 prefix='chromite.upload_prebuilts.index.') as index:
436 GenerateHtmlIndex(
437 [x[len(remote_location) + 1:] for x in upload_files.values()],
438 index.name, self._target, self._version)
439 self._Upload(index.name, '%s/index.html' % remote_location.rstrip('/'))
440
441 link_name = 'Prebuilts[%s]: %s' % (self._target, self._version)
442 url = '%s%s/index.html' % (gs.PUBLIC_BASE_HTTPS_URL,
443 remote_location[len(gs.BASE_GS_URL):])
444 cros_build_lib.PrintBuildbotLink(link_name, url)
445
Mike Frysinger8092a632014-05-24 13:25:46 -0400446 def _UploadSdkTarball(self, board_path, url_suffix, prepackaged,
Mike Frysinger9e979b92012-11-29 02:55:09 -0500447 toolchain_tarballs, toolchain_upload_path):
448 """Upload a tarball of the sdk at the specified path to Google Storage.
David James8fa34ea2011-04-15 13:00:20 -0700449
450 Args:
451 board_path: The path to the board dir.
452 url_suffix: The remote subdirectory where we should upload the packages.
Zdenek Behan62a57792012-08-31 15:09:08 +0200453 prepackaged: If given, a tarball that has been packaged outside of this
454 script and should be used.
Mike Frysinger9e979b92012-11-29 02:55:09 -0500455 toolchain_tarballs: List of toolchain tarballs to upload.
456 toolchain_upload_path: Path under the bucket to place toolchain tarballs.
David James8fa34ea2011-04-15 13:00:20 -0700457 """
458 remote_location = '%s/%s' % (self._upload_location.rstrip('/'), url_suffix)
459 assert remote_location.startswith('gs://')
Zdenek Behan86c15e92012-10-13 00:55:47 +0200460 boardname = os.path.basename(board_path.rstrip('/'))
461 # We do not upload non SDK board tarballs,
462 assert boardname == constants.CHROOT_BUILDER_BOARD
463 assert prepackaged is not None
Zdenek Behan62a57792012-08-31 15:09:08 +0200464
Mike Frysinger8092a632014-05-24 13:25:46 -0400465 version_str = self._version[len('chroot-'):]
Mike Frysinger8e727a32013-01-16 16:57:53 -0500466 remote_tarfile = toolchain.GetSdkURL(
467 for_gsutil=True, suburl='cros-sdk-%s.tar.xz' % (version_str,))
Zdenek Behan86c15e92012-10-13 00:55:47 +0200468 # For SDK, also upload the manifest which is guaranteed to exist
469 # by the builderstage.
Mike Frysinger540883b2014-05-24 13:46:16 -0400470 self._Upload(prepackaged + '.Manifest', remote_tarfile + '.Manifest')
471 self._Upload(prepackaged, remote_tarfile)
Zdenek Behan86c15e92012-10-13 00:55:47 +0200472
Mike Frysinger9e979b92012-11-29 02:55:09 -0500473 # Post the toolchain tarballs too.
474 for tarball in toolchain_tarballs:
475 target, local_path = tarball.split(':')
476 suburl = toolchain_upload_path % {'target': target}
477 remote_path = toolchain.GetSdkURL(for_gsutil=True, suburl=suburl)
Mike Frysinger540883b2014-05-24 13:46:16 -0400478 self._Upload(local_path, remote_path)
Mike Frysinger9e979b92012-11-29 02:55:09 -0500479
Zdenek Behan86c15e92012-10-13 00:55:47 +0200480 # Finally, also update the pointer to the latest SDK on which polling
481 # scripts rely.
David James4bc13702013-03-26 08:08:04 -0700482 with osutils.TempDir() as tmpdir:
Zdenek Behan86c15e92012-10-13 00:55:47 +0200483 pointerfile = os.path.join(tmpdir, 'cros-sdk-latest.conf')
Mike Frysinger8e727a32013-01-16 16:57:53 -0500484 remote_pointerfile = toolchain.GetSdkURL(for_gsutil=True,
485 suburl='cros-sdk-latest.conf')
Zdenek Behan86c15e92012-10-13 00:55:47 +0200486 osutils.WriteFile(pointerfile, 'LATEST_SDK="%s"' % version_str)
Mike Frysinger540883b2014-05-24 13:46:16 -0400487 self._Upload(pointerfile, remote_pointerfile)
Zdenek Behan33a34112012-09-10 21:07:51 +0200488
Chris Sosa6a5dceb2012-05-14 13:48:56 -0700489 def _GetTargets(self):
490 """Retuns the list of targets to use."""
491 targets = self._slave_targets[:]
492 if self._target:
493 targets.append(self._target)
494
495 return targets
496
Mike Frysinger8092a632014-05-24 13:25:46 -0400497 def SyncHostPrebuilts(self, key, git_sync, sync_binhost_conf):
David Jamesc0f158a2011-02-22 16:07:29 -0800498 """Synchronize host prebuilt files.
David James05bcb2b2011-02-09 09:25:47 -0800499
David Jamesc0f158a2011-02-22 16:07:29 -0800500 This function will sync both the standard host packages, plus the host
501 packages associated with all targets that have been "setup" with the
502 current host's chroot. For instance, if this host has been used to build
503 x86-generic, it will sync the host packages associated with
504 'i686-pc-linux-gnu'. If this host has also been used to build arm-generic,
505 it will also sync the host packages associated with
506 'armv7a-cros-linux-gnueabi'.
David James05bcb2b2011-02-09 09:25:47 -0800507
David Jamesc0f158a2011-02-22 16:07:29 -0800508 Args:
David Jamesc0f158a2011-02-22 16:07:29 -0800509 key: The variable key to update in the git file.
510 git_sync: If set, update make.conf of target to reference the latest
511 prebuilt packages generated here.
512 sync_binhost_conf: If set, update binhost config file in
513 chromiumos-overlay for the host.
514 """
David Jamese2488642011-11-14 16:15:20 -0800515 # Slave boards are listed before the master board so that the master board
516 # takes priority (i.e. x86-generic preflight host prebuilts takes priority
517 # over preflight host prebuilts from other builders.)
518 binhost_urls = []
Chris Sosa6a5dceb2012-05-14 13:48:56 -0700519 for target in self._GetTargets():
Mike Frysinger8092a632014-05-24 13:25:46 -0400520 url_suffix = _REL_HOST_PATH % {'version': self._version,
David James4058b0d2011-12-08 21:24:50 -0800521 'host_arch': _HOST_ARCH,
522 'target': target}
David Jamese2488642011-11-14 16:15:20 -0800523 packages_url_suffix = '%s/packages' % url_suffix.rstrip('/')
David James05bcb2b2011-02-09 09:25:47 -0800524
Mike Frysinger540883b2014-05-24 13:46:16 -0400525 if self._target == target and not self._skip_upload:
David Jamese2488642011-11-14 16:15:20 -0800526 # Upload prebuilts.
527 package_path = os.path.join(self._build_path, _HOST_PACKAGES_PATH)
528 self._UploadPrebuilt(package_path, packages_url_suffix)
David James8ece7ee2011-06-29 16:02:30 -0700529
David Jamese2488642011-11-14 16:15:20 -0800530 # Record URL where prebuilts were uploaded.
531 binhost_urls.append('%s/%s/' % (self._binhost_base_url.rstrip('/'),
532 packages_url_suffix.rstrip('/')))
533
David James20b2b6f2011-11-18 15:11:58 -0800534 binhost = ' '.join(binhost_urls)
David James8ece7ee2011-06-29 16:02:30 -0700535 if git_sync:
536 git_file = os.path.join(self._build_path,
David James4058b0d2011-12-08 21:24:50 -0800537 _PREBUILT_MAKE_CONF[_HOST_ARCH])
Mike Frysinger86509232014-05-24 13:18:37 -0400538 RevGitFile(git_file, {key: binhost}, dryrun=self._dryrun)
David James8ece7ee2011-06-29 16:02:30 -0700539 if sync_binhost_conf:
David James32b0b2f2011-07-13 20:56:50 -0700540 binhost_conf = os.path.join(self._build_path, self._binhost_conf_dir,
David James4058b0d2011-12-08 21:24:50 -0800541 'host', '%s-%s.conf' % (_HOST_ARCH, key))
David Jamese2488642011-11-14 16:15:20 -0800542 UpdateBinhostConfFile(binhost_conf, key, binhost)
David Jamesc0f158a2011-02-22 16:07:29 -0800543
Mike Frysinger8092a632014-05-24 13:25:46 -0400544 def SyncBoardPrebuilts(self, key, git_sync, sync_binhost_conf,
Mike Frysinger9e979b92012-11-29 02:55:09 -0500545 upload_board_tarball, prepackaged_board,
546 toolchain_tarballs, toolchain_upload_path):
David Jamesc0f158a2011-02-22 16:07:29 -0800547 """Synchronize board prebuilt files.
548
549 Args:
David Jamesc0f158a2011-02-22 16:07:29 -0800550 key: The variable key to update in the git file.
551 git_sync: If set, update make.conf of target to reference the latest
552 prebuilt packages generated here.
553 sync_binhost_conf: If set, update binhost config file in
554 chromiumos-overlay for the current board.
David James8fa34ea2011-04-15 13:00:20 -0700555 upload_board_tarball: Include a tarball of the board in our upload.
Zdenek Behan62a57792012-08-31 15:09:08 +0200556 prepackaged_board: A tarball of the board built outside of this script.
Mike Frysinger9e979b92012-11-29 02:55:09 -0500557 toolchain_tarballs: A list of toolchain tarballs to upload.
558 toolchain_upload_path: Path under the bucket to place toolchain tarballs.
David Jamesc0f158a2011-02-22 16:07:29 -0800559 """
Chris Sosa6a5dceb2012-05-14 13:48:56 -0700560 for target in self._GetTargets():
David Jamese2488642011-11-14 16:15:20 -0800561 board_path = os.path.join(self._build_path,
David James4058b0d2011-12-08 21:24:50 -0800562 _BOARD_PATH % {'board': target.board_variant})
David Jamese2488642011-11-14 16:15:20 -0800563 package_path = os.path.join(board_path, 'packages')
Mike Frysinger8092a632014-05-24 13:25:46 -0400564 url_suffix = _REL_BOARD_PATH % {'target': target,
565 'version': self._version}
David Jamese2488642011-11-14 16:15:20 -0800566 packages_url_suffix = '%s/packages' % url_suffix.rstrip('/')
David James8fa34ea2011-04-15 13:00:20 -0700567
Matt Tennante8179042013-10-01 15:47:32 -0700568 # Process the target board differently if it is the main --board.
Mike Frysinger540883b2014-05-24 13:46:16 -0400569 if self._target == target and not self._skip_upload:
Matt Tennante8179042013-10-01 15:47:32 -0700570 # This strips "chroot" prefix because that is sometimes added as the
571 # --prepend-version argument (e.g. by chromiumos-sdk bot).
572 # TODO(build): Clean it up to be less hard-coded.
Mike Frysinger8092a632014-05-24 13:25:46 -0400573 version_str = self._version[len('chroot-'):]
Mike Frysinger9e979b92012-11-29 02:55:09 -0500574
David Jamese2488642011-11-14 16:15:20 -0800575 # Upload board tarballs in the background.
576 if upload_board_tarball:
Mike Frysinger9e979b92012-11-29 02:55:09 -0500577 if toolchain_upload_path:
578 toolchain_upload_path %= {'version': version_str}
579 tar_process = multiprocessing.Process(
580 target=self._UploadSdkTarball,
Mike Frysinger8092a632014-05-24 13:25:46 -0400581 args=(board_path, url_suffix, prepackaged_board,
Mike Frysinger9e979b92012-11-29 02:55:09 -0500582 toolchain_tarballs, toolchain_upload_path))
David Jamese2488642011-11-14 16:15:20 -0800583 tar_process.start()
David James8fa34ea2011-04-15 13:00:20 -0700584
David Jamese2488642011-11-14 16:15:20 -0800585 # Upload prebuilts.
586 self._UploadPrebuilt(package_path, packages_url_suffix)
David James8fa34ea2011-04-15 13:00:20 -0700587
David Jamese2488642011-11-14 16:15:20 -0800588 # Make sure we finished uploading the board tarballs.
589 if upload_board_tarball:
590 tar_process.join()
591 assert tar_process.exitcode == 0
592 # TODO(zbehan): This should be done cleaner.
Zdenek Behan33a34112012-09-10 21:07:51 +0200593 if target.board == constants.CHROOT_BUILDER_BOARD:
David Jamese2488642011-11-14 16:15:20 -0800594 sdk_conf = os.path.join(self._build_path, self._binhost_conf_dir,
Mike Frysinger5b34d732013-01-17 15:11:58 -0500595 'host/sdk_version.conf')
596 sdk_settings = {
Mike Frysinger9e979b92012-11-29 02:55:09 -0500597 'SDK_LATEST_VERSION': version_str,
598 'TC_PATH': toolchain_upload_path,
Mike Frysinger5b34d732013-01-17 15:11:58 -0500599 }
Mike Frysinger86509232014-05-24 13:18:37 -0400600 RevGitFile(sdk_conf, sdk_settings, dryrun=self._dryrun)
David Jamesc0f158a2011-02-22 16:07:29 -0800601
David Jamese2488642011-11-14 16:15:20 -0800602 # Record URL where prebuilts were uploaded.
603 url_value = '%s/%s/' % (self._binhost_base_url.rstrip('/'),
604 packages_url_suffix.rstrip('/'))
605
606 if git_sync:
David James4058b0d2011-12-08 21:24:50 -0800607 git_file = DeterminePrebuiltConfFile(self._build_path, target)
Mike Frysinger86509232014-05-24 13:18:37 -0400608 RevGitFile(git_file, {key: url_value}, dryrun=self._dryrun)
Matt Tennante8179042013-10-01 15:47:32 -0700609
David Jamese2488642011-11-14 16:15:20 -0800610 if sync_binhost_conf:
Matt Tennante8179042013-10-01 15:47:32 -0700611 # Update the binhost configuration file in git.
David Jamese2488642011-11-14 16:15:20 -0800612 binhost_conf = os.path.join(self._build_path, self._binhost_conf_dir,
David James4058b0d2011-12-08 21:24:50 -0800613 'target', '%s-%s.conf' % (target, key))
David Jamese2488642011-11-14 16:15:20 -0800614 UpdateBinhostConfFile(binhost_conf, key, url_value)
David James05bcb2b2011-02-09 09:25:47 -0800615
616
Chris Sosa6a5dceb2012-05-14 13:48:56 -0700617def _AddSlaveBoard(_option, _opt_str, value, parser):
618 """Callback that adds a slave board to the list of slave targets."""
David James4058b0d2011-12-08 21:24:50 -0800619 parser.values.slave_targets.append(BuildTarget(value))
620
621
Chris Sosa6a5dceb2012-05-14 13:48:56 -0700622def _AddSlaveProfile(_option, _opt_str, value, parser):
623 """Callback that adds a slave profile to the list of slave targets."""
David James4058b0d2011-12-08 21:24:50 -0800624 if not parser.values.slave_targets:
Mike Frysinger86509232014-05-24 13:18:37 -0400625 parser.error('Must specify --slave-board before --slave-profile')
David James4058b0d2011-12-08 21:24:50 -0800626 if parser.values.slave_targets[-1].profile is not None:
Mike Frysinger86509232014-05-24 13:18:37 -0400627 parser.error('Cannot specify --slave-profile twice for same board')
David James4058b0d2011-12-08 21:24:50 -0800628 parser.values.slave_targets[-1].profile = value
629
630
Mike Frysinger86509232014-05-24 13:18:37 -0400631def ParseOptions(argv):
Chris Sosa6a5dceb2012-05-14 13:48:56 -0700632 """Returns options given by the user and the target specified.
633
Mike Frysinger86509232014-05-24 13:18:37 -0400634 Args:
635 argv: The args to parse.
636
Mike Frysinger1a736a82013-12-12 01:50:59 -0500637 Returns:
638 A tuple containing a parsed options object and BuildTarget.
639 The target instance is None if no board is specified.
Chris Sosa6a5dceb2012-05-14 13:48:56 -0700640 """
Mike Frysinger86509232014-05-24 13:18:37 -0400641 parser = commandline.OptionParser()
David James8c846492011-01-25 17:07:29 -0800642 parser.add_option('-H', '--binhost-base-url', dest='binhost_base_url',
643 default=_BINHOST_BASE_URL,
644 help='Base URL to use for binhost in make.conf updates')
645 parser.add_option('', '--previous-binhost-url', action='append',
646 default=[], dest='previous_binhost_url',
647 help='Previous binhost URL')
648 parser.add_option('-b', '--board', dest='board', default=None,
649 help='Board type that was built on this machine')
Zdenek Behan62a57792012-08-31 15:09:08 +0200650 parser.add_option('-B', '--prepackaged-tarball', dest='prepackaged_tarball',
651 default=None,
652 help='Board tarball prebuilt outside of this script.')
Mike Frysinger9e979b92012-11-29 02:55:09 -0500653 parser.add_option('--toolchain-tarball', dest='toolchain_tarballs',
654 action='append', default=[],
655 help='Redistributable toolchain tarball.')
656 parser.add_option('--toolchain-upload-path', default='',
657 help='Path to place toolchain tarballs in the sdk tree.')
David James4058b0d2011-12-08 21:24:50 -0800658 parser.add_option('', '--profile', dest='profile', default=None,
659 help='Profile that was built on this machine')
660 parser.add_option('', '--slave-board', default=[], action='callback',
661 dest='slave_targets', type='string',
Chris Sosa6a5dceb2012-05-14 13:48:56 -0700662 callback=_AddSlaveBoard,
David James4058b0d2011-12-08 21:24:50 -0800663 help='Board type that was built on a slave machine. To '
664 'add a profile to this board, use --slave-profile.')
665 parser.add_option('', '--slave-profile', action='callback', type='string',
Chris Sosa6a5dceb2012-05-14 13:48:56 -0700666 callback=_AddSlaveProfile,
David James4058b0d2011-12-08 21:24:50 -0800667 help='Board profile that was built on a slave machine. '
668 'Applies to previous slave board.')
David James8c846492011-01-25 17:07:29 -0800669 parser.add_option('-p', '--build-path', dest='build_path',
David James05bcb2b2011-02-09 09:25:47 -0800670 help='Path to the directory containing the chroot')
David James615e5b52011-06-03 11:10:15 -0700671 parser.add_option('', '--packages', action='append',
672 default=[], dest='packages',
673 help='Only include the specified packages. '
674 '(Default is to include all packages.)')
David James8c846492011-01-25 17:07:29 -0800675 parser.add_option('-s', '--sync-host', dest='sync_host',
676 default=False, action='store_true',
677 help='Sync host prebuilts')
678 parser.add_option('-g', '--git-sync', dest='git_sync',
679 default=False, action='store_true',
David Jamese2488642011-11-14 16:15:20 -0800680 help='Enable git version sync (This commits to a repo.) '
681 'This is used by full builders to commit directly '
682 'to board overlays.')
David James8c846492011-01-25 17:07:29 -0800683 parser.add_option('-u', '--upload', dest='upload',
684 default=None,
685 help='Upload location')
686 parser.add_option('-V', '--prepend-version', dest='prepend_version',
687 default=None,
688 help='Add an identifier to the front of the version')
689 parser.add_option('-f', '--filters', dest='filters', action='store_true',
690 default=False,
691 help='Turn on filtering of private ebuild packages')
692 parser.add_option('-k', '--key', dest='key',
693 default='PORTAGE_BINHOST',
694 help='Key to update in make.conf / binhost.conf')
David James8ece7ee2011-06-29 16:02:30 -0700695 parser.add_option('', '--set-version', dest='set_version',
696 default=None,
697 help='Specify the version string')
David James8c846492011-01-25 17:07:29 -0800698 parser.add_option('', '--sync-binhost-conf', dest='sync_binhost_conf',
699 default=False, action='store_true',
David Jamese2488642011-11-14 16:15:20 -0800700 help='Update binhost.conf in chromiumos-overlay or '
701 'chromeos-overlay. Commit the changes, but don\'t '
702 'push them. This is used for preflight binhosts.')
David James32b0b2f2011-07-13 20:56:50 -0700703 parser.add_option('', '--binhost-conf-dir', dest='binhost_conf_dir',
704 default=_BINHOST_CONF_DIR,
705 help='Directory to commit binhost config with '
706 '--sync-binhost-conf.')
David Jamesfd0b0852011-02-23 11:15:36 -0800707 parser.add_option('-P', '--private', dest='private', action='store_true',
708 default=False, help='Mark gs:// uploads as private.')
David James8ece7ee2011-06-29 16:02:30 -0700709 parser.add_option('', '--skip-upload', dest='skip_upload',
710 action='store_true', default=False,
711 help='Skip upload step.')
David James8fa34ea2011-04-15 13:00:20 -0700712 parser.add_option('', '--upload-board-tarball', dest='upload_board_tarball',
713 action='store_true', default=False,
714 help='Upload board tarball to Google Storage.')
Mike Frysinger86509232014-05-24 13:18:37 -0400715 parser.add_option('-n', '--dry-run', dest='dryrun',
David James27fa7d12011-06-29 17:24:14 -0700716 action='store_true', default=False,
717 help='Don\'t push or upload prebuilts.')
David James8c846492011-01-25 17:07:29 -0800718
Mike Frysinger86509232014-05-24 13:18:37 -0400719 options, args = parser.parse_args(argv)
David James8c846492011-01-25 17:07:29 -0800720 if not options.build_path:
Mike Frysinger86509232014-05-24 13:18:37 -0400721 parser.error('you need provide a chroot path')
David James8ece7ee2011-06-29 16:02:30 -0700722 if not options.upload and not options.skip_upload:
Mike Frysinger86509232014-05-24 13:18:37 -0400723 parser.error('you need to provide an upload location using -u')
David James8ece7ee2011-06-29 16:02:30 -0700724 if not options.set_version and options.skip_upload:
Mike Frysinger86509232014-05-24 13:18:37 -0400725 parser.error('If you are using --skip-upload, you must specify a '
726 'version number using --set-version.')
David James9417f272011-05-26 13:24:47 -0700727 if args:
Mike Frysinger86509232014-05-24 13:18:37 -0400728 parser.error('invalid arguments passed to upload_prebuilts: %r' % args)
Scott Zawalskiab1bed32011-03-16 15:24:24 -0700729
Chris Sosa6a5dceb2012-05-14 13:48:56 -0700730 target = None
731 if options.board:
732 target = BuildTarget(options.board, options.profile)
733
734 if target in options.slave_targets:
Mike Frysinger86509232014-05-24 13:18:37 -0400735 parser.error('--board/--profile must not also be a slave target.')
David Jamese2488642011-11-14 16:15:20 -0800736
David James4058b0d2011-12-08 21:24:50 -0800737 if len(set(options.slave_targets)) != len(options.slave_targets):
Mike Frysinger86509232014-05-24 13:18:37 -0400738 parser.error('--slave-boards must not have duplicates.')
David Jamese2488642011-11-14 16:15:20 -0800739
David James4058b0d2011-12-08 21:24:50 -0800740 if options.slave_targets and options.git_sync:
Mike Frysinger86509232014-05-24 13:18:37 -0400741 parser.error('--slave-boards is not compatible with --git-sync')
David Jamese2488642011-11-14 16:15:20 -0800742
David James8ece7ee2011-06-29 16:02:30 -0700743 if (options.upload_board_tarball and options.skip_upload and
744 options.board == 'amd64-host'):
Mike Frysinger86509232014-05-24 13:18:37 -0400745 parser.error('--skip-upload is not compatible with '
746 '--upload-board-tarball and --board=amd64-host')
David James8fa34ea2011-04-15 13:00:20 -0700747
David James8ece7ee2011-06-29 16:02:30 -0700748 if (options.upload_board_tarball and not options.skip_upload and
749 not options.upload.startswith('gs://')):
Mike Frysinger86509232014-05-24 13:18:37 -0400750 parser.error('--upload-board-tarball only works with gs:// URLs.\n'
751 '--upload must be a gs:// URL.')
David James8fa34ea2011-04-15 13:00:20 -0700752
Zdenek Behan86c15e92012-10-13 00:55:47 +0200753 if options.upload_board_tarball and options.prepackaged_tarball is None:
Mike Frysinger86509232014-05-24 13:18:37 -0400754 parser.error('--upload-board-tarball requires --prepackaged-tarball')
Zdenek Behan86c15e92012-10-13 00:55:47 +0200755
Scott Zawalskiab1bed32011-03-16 15:24:24 -0700756 if options.private:
757 if options.sync_host:
Mike Frysinger86509232014-05-24 13:18:37 -0400758 parser.error('--private and --sync-host/-s cannot be specified '
759 'together; we do not support private host prebuilts')
Scott Zawalskiab1bed32011-03-16 15:24:24 -0700760
David James8ece7ee2011-06-29 16:02:30 -0700761 if not options.upload or not options.upload.startswith('gs://'):
Mike Frysinger86509232014-05-24 13:18:37 -0400762 parser.error('--private is only valid for gs:// URLs; '
763 '--upload must be a gs:// URL.')
Scott Zawalskiab1bed32011-03-16 15:24:24 -0700764
765 if options.binhost_base_url != _BINHOST_BASE_URL:
Mike Frysinger86509232014-05-24 13:18:37 -0400766 parser.error('when using --private the --binhost-base-url '
767 'is automatically derived.')
David James27fa7d12011-06-29 17:24:14 -0700768
Chris Sosa6a5dceb2012-05-14 13:48:56 -0700769 return options, target
David Jamesc0f158a2011-02-22 16:07:29 -0800770
Mike Frysingercc838832014-05-24 13:10:30 -0400771
Mike Frysinger86509232014-05-24 13:18:37 -0400772def main(argv):
David Jamesdb401072011-06-10 12:17:16 -0700773 # Set umask to a sane value so that files created as root are readable.
Mike Frysinger60ec1012013-10-21 00:11:10 -0400774 os.umask(0o22)
David Jamesdb401072011-06-10 12:17:16 -0700775
Mike Frysinger86509232014-05-24 13:18:37 -0400776 options, target = ParseOptions(argv)
David Jamesc0f158a2011-02-22 16:07:29 -0800777
David James05bcb2b2011-02-09 09:25:47 -0800778 # Calculate a list of Packages index files to compare against. Whenever we
779 # upload a package, we check to make sure it's not already stored in one of
780 # the packages files we uploaded. This list of packages files might contain
781 # both board and host packages.
David Jamesce093af2011-02-23 15:21:58 -0800782 pkg_indexes = _GrabAllRemotePackageIndexes(options.previous_binhost_url)
David James8c846492011-01-25 17:07:29 -0800783
David James8ece7ee2011-06-29 16:02:30 -0700784 if options.set_version:
785 version = options.set_version
786 else:
787 version = GetVersion()
Matt Tennante8179042013-10-01 15:47:32 -0700788
David Jamesc0f158a2011-02-22 16:07:29 -0800789 if options.prepend_version:
790 version = '%s-%s' % (options.prepend_version, version)
791
Scott Zawalskiab1bed32011-03-16 15:24:24 -0700792 acl = 'public-read'
793 binhost_base_url = options.binhost_base_url
794
David Jamesadd21432013-05-21 10:04:07 -0700795 if options.private:
Scott Zawalskiab1bed32011-03-16 15:24:24 -0700796 binhost_base_url = options.upload
David Jamesadd21432013-05-21 10:04:07 -0700797 if target:
Peter Mayo950e41a2014-02-06 21:07:33 +0000798 board_path = GetBoardOverlay(options.build_path, target)
David Jamesadd21432013-05-21 10:04:07 -0700799 acl = os.path.join(board_path, _GOOGLESTORAGE_ACL_FILE)
Scott Zawalskiab1bed32011-03-16 15:24:24 -0700800
801 uploader = PrebuiltUploader(options.upload, acl, binhost_base_url,
David James615e5b52011-06-03 11:10:15 -0700802 pkg_indexes, options.build_path,
David James27fa7d12011-06-29 17:24:14 -0700803 options.packages, options.skip_upload,
Mike Frysinger86509232014-05-24 13:18:37 -0400804 options.binhost_conf_dir, options.dryrun,
Mike Frysinger8092a632014-05-24 13:25:46 -0400805 target, options.slave_targets, version)
David Jamesc0f158a2011-02-22 16:07:29 -0800806
David James8c846492011-01-25 17:07:29 -0800807 if options.sync_host:
Mike Frysinger8092a632014-05-24 13:25:46 -0400808 uploader.SyncHostPrebuilts(options.key, options.git_sync,
Chris Sosa6a5dceb2012-05-14 13:48:56 -0700809 options.sync_binhost_conf)
David James8c846492011-01-25 17:07:29 -0800810
Chris Sosa62c8ff52012-06-04 15:03:12 -0700811 if options.board or options.slave_targets:
Mike Frysinger8092a632014-05-24 13:25:46 -0400812 uploader.SyncBoardPrebuilts(options.key, options.git_sync,
Chris Sosa6a5dceb2012-05-14 13:48:56 -0700813 options.sync_binhost_conf,
Zdenek Behan62a57792012-08-31 15:09:08 +0200814 options.upload_board_tarball,
Mike Frysinger9e979b92012-11-29 02:55:09 -0500815 options.prepackaged_tarball,
816 options.toolchain_tarballs,
817 options.toolchain_upload_path)