blob: b2118478b22cffbb195f946e636d337588107d32 [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
David James14e97772014-06-04 18:44:49 -070031from chromite.cbuildbot import 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'
Gabe Black40169e62014-06-17 15:23:47 -070060_GOOGLESTORAGE_GSUTIL_FILE = 'googlestorage_acl.txt'
David James3753d942014-04-23 10:55:48 -070061_BINHOST_BASE_URL = 'gs://chromeos-prebuilt'
David James8c846492011-01-25 17:07:29 -080062_PREBUILT_BASE_DIR = 'src/third_party/chromiumos-overlay/chromeos/config/'
63# Created in the event of new host targets becoming available
64_PREBUILT_MAKE_CONF = {'amd64': os.path.join(_PREBUILT_BASE_DIR,
65 'make.conf.amd64-host')}
David James8c846492011-01-25 17:07:29 -080066
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')
Gabe Black40169e62014-06-17 15:23:47 -0700189 if acl.endswith('.xml'):
190 # Apply the passed in ACL xml file to the uploaded object.
191 gs_context.SetACL(remote_file, acl=acl)
192 else:
193 gs_context.ChangeACL(remote_file, acl_args_file=acl)
Scott Zawalskiab1bed32011-03-16 15:24:24 -0700194
Mike Frysingercc838832014-05-24 13:10:30 -0400195
Mike Frysinger540883b2014-05-24 13:46:16 -0400196def RemoteUpload(gs_context, acl, files, pool=10):
David James8c846492011-01-25 17:07:29 -0800197 """Upload to google storage.
198
199 Create a pool of process and call _GsUpload with the proper arguments.
200
201 Args:
Mike Frysinger540883b2014-05-24 13:46:16 -0400202 gs_context: A lib.gs.GSContext instance.
David Jamesfd0b0852011-02-23 11:15:36 -0800203 acl: The canned acl used for uploading. acl can be one of: "public-read",
204 "public-read-write", "authenticated-read", "bucket-owner-read",
205 "bucket-owner-full-control", or "private".
David James8c846492011-01-25 17:07:29 -0800206 files: dictionary with keys to local files and values to remote path.
207 pool: integer of maximum proesses to have at the same time.
208
209 Returns:
210 Return a set of tuple arguments of the failed uploads
211 """
Mike Frysinger540883b2014-05-24 13:46:16 -0400212 upload = functools.partial(_GsUpload, gs_context, acl)
213 tasks = [[key, value] for key, value in files.iteritems()]
214 parallel.RunTasksInProcessPool(upload, tasks, pool)
David James8c846492011-01-25 17:07:29 -0800215
216
217def GenerateUploadDict(base_local_path, base_remote_path, pkgs):
218 """Build a dictionary of local remote file key pairs to upload.
219
220 Args:
221 base_local_path: The base path to the files on the local hard drive.
Matt Tennante8179042013-10-01 15:47:32 -0700222 base_remote_path: The base path to the remote paths.
David James8c846492011-01-25 17:07:29 -0800223 pkgs: The packages to upload.
224
225 Returns:
226 Returns a dictionary of local_path/remote_path pairs
227 """
228 upload_files = {}
229 for pkg in pkgs:
230 suffix = pkg['CPV'] + '.tbz2'
231 local_path = os.path.join(base_local_path, suffix)
232 assert os.path.exists(local_path)
233 remote_path = '%s/%s' % (base_remote_path.rstrip('/'), suffix)
234 upload_files[local_path] = remote_path
235
236 return upload_files
237
Mike Frysingercc838832014-05-24 13:10:30 -0400238
Peter Mayo950e41a2014-02-06 21:07:33 +0000239def GetBoardOverlay(build_path, target):
David Jamese5867812012-10-19 12:02:20 -0700240 """Get the path to the board variant.
Mike Frysinger1a736a82013-12-12 01:50:59 -0500241
David James8c846492011-01-25 17:07:29 -0800242 Args:
243 build_path: The path to the root of the build directory
David Jamese5867812012-10-19 12:02:20 -0700244 target: The target board as a BuildTarget object.
Mike Frysinger1a736a82013-12-12 01:50:59 -0500245
David James8c846492011-01-25 17:07:29 -0800246 Returns:
David Jamese5867812012-10-19 12:02:20 -0700247 The last overlay configured for the given board as a string.
David James8c846492011-01-25 17:07:29 -0800248 """
David Jamese5867812012-10-19 12:02:20 -0700249 board = target.board_variant
250 overlays = portage_utilities.FindOverlays(constants.BOTH_OVERLAYS, board,
251 buildroot=build_path)
252 # We only care about the last entry.
253 return overlays[-1]
David James8c846492011-01-25 17:07:29 -0800254
255
256def DeterminePrebuiltConfFile(build_path, target):
257 """Determine the prebuilt.conf file that needs to be updated for prebuilts.
258
Mike Frysinger1a736a82013-12-12 01:50:59 -0500259 Args:
260 build_path: The path to the root of the build directory
261 target: String representation of the board. This includes host and board
262 targets
David James8c846492011-01-25 17:07:29 -0800263
Mike Frysinger1a736a82013-12-12 01:50:59 -0500264 Returns:
265 A string path to a prebuilt.conf file to be updated.
David James8c846492011-01-25 17:07:29 -0800266 """
David James4058b0d2011-12-08 21:24:50 -0800267 if _HOST_ARCH == target:
David James8c846492011-01-25 17:07:29 -0800268 # We are host.
269 # Without more examples of hosts this is a kludge for now.
270 # TODO(Scottz): as new host targets come online expand this to
271 # work more like boards.
Chris Sosa471532a2011-02-01 15:10:06 -0800272 make_path = _PREBUILT_MAKE_CONF[target]
David James8c846492011-01-25 17:07:29 -0800273 else:
274 # We are a board
Peter Mayo950e41a2014-02-06 21:07:33 +0000275 board = GetBoardOverlay(build_path, target)
David James8c846492011-01-25 17:07:29 -0800276 make_path = os.path.join(board, 'prebuilt.conf')
277
278 return make_path
279
280
281def UpdateBinhostConfFile(path, key, value):
282 """Update binhost config file file with key=value.
283
284 Args:
285 path: Filename to update.
286 key: Key to update.
287 value: New value for key.
288 """
289 cwd = os.path.dirname(os.path.abspath(path))
290 filename = os.path.basename(path)
Brian Harringaf019fb2012-05-10 15:06:13 -0700291 osutils.SafeMakedirs(cwd)
David Jamesf6e8fb72013-05-10 08:58:43 -0700292 if not git.GetCurrentBranch(cwd):
293 git.CreatePushBranch(constants.STABLE_EBUILD_BRANCH, cwd, sync=False)
Brian Harring22edb442012-05-11 23:55:18 -0700294 osutils.WriteFile(path, '', mode='a')
David James8c846492011-01-25 17:07:29 -0800295 UpdateLocalFile(path, value, key)
David James67d73252013-09-19 17:33:12 -0700296 git.RunGit(cwd, ['add', filename])
Mike Frysinger109cada2013-01-17 15:50:44 -0500297 description = '%s: updating %s' % (os.path.basename(filename), key)
David James67d73252013-09-19 17:33:12 -0700298 git.RunGit(cwd, ['commit', '-m', description])
David James8c846492011-01-25 17:07:29 -0800299
300
Mike Frysinger212e4292014-05-24 15:15:44 -0400301def GenerateHtmlIndex(files, index, board, version):
302 """Given the list of |files|, generate an index.html at |index|.
303
304 Args:
305 files: The list of files to link to.
306 index: The path to the html index.
307 board: Name of the board this index is for.
308 version: Build version this index is for.
309 """
310 head = """<html>
311<head>
312 <title>Package Prebuilt Index: %(board)s / %(version)s</title>
313</head>
314<body>
315<h2>Package Prebuilt Index: %(board)s / %(version)s</h2>"""
316 head %= {
317 'board': board,
318 'version': version,
319 }
320
321 files = files + [
322 '.|Google Storage Index',
323 '..|',
324 ]
325 commands.GenerateHtmlIndex(index, files, head=head)
326
327
David Jamesce093af2011-02-23 15:21:58 -0800328def _GrabAllRemotePackageIndexes(binhost_urls):
David James05bcb2b2011-02-09 09:25:47 -0800329 """Grab all of the packages files associated with a list of binhost_urls.
330
David James05bcb2b2011-02-09 09:25:47 -0800331 Args:
332 binhost_urls: The URLs for the directories containing the Packages files we
333 want to grab.
David James05bcb2b2011-02-09 09:25:47 -0800334
335 Returns:
336 A list of PackageIndex objects.
337 """
338 pkg_indexes = []
339 for url in binhost_urls:
David James32faafe2012-06-08 14:25:03 -0700340 pkg_index = binpkg.GrabRemotePackageIndex(url)
David James05bcb2b2011-02-09 09:25:47 -0800341 if pkg_index:
342 pkg_indexes.append(pkg_index)
David James05bcb2b2011-02-09 09:25:47 -0800343 return pkg_indexes
344
345
David Jamesc0f158a2011-02-22 16:07:29 -0800346class PrebuiltUploader(object):
347 """Synchronize host and board prebuilts."""
David James8c846492011-01-25 17:07:29 -0800348
Mike Frysinger86509232014-05-24 13:18:37 -0400349 def __init__(self, upload_location, acl, binhost_base_url, pkg_indexes,
350 build_path, packages, skip_upload, binhost_conf_dir, dryrun,
Mike Frysinger8092a632014-05-24 13:25:46 -0400351 target, slave_targets, version):
David Jamesc0f158a2011-02-22 16:07:29 -0800352 """Constructor for prebuilt uploader object.
David James8c846492011-01-25 17:07:29 -0800353
David Jamesc0f158a2011-02-22 16:07:29 -0800354 This object can upload host or prebuilt files to Google Storage.
David James8c846492011-01-25 17:07:29 -0800355
David Jamesc0f158a2011-02-22 16:07:29 -0800356 Args:
357 upload_location: The upload location.
David Jamesfd0b0852011-02-23 11:15:36 -0800358 acl: The canned acl used for uploading to Google Storage. acl can be one
359 of: "public-read", "public-read-write", "authenticated-read",
Matt Tennante8179042013-10-01 15:47:32 -0700360 "bucket-owner-read", "bucket-owner-full-control", "project-private",
361 or "private" (see "gsutil help acls"). If we are not uploading to
362 Google Storage, this parameter is unused.
David Jamesfd0b0852011-02-23 11:15:36 -0800363 binhost_base_url: The URL used for downloading the prebuilts.
David Jamesc0f158a2011-02-22 16:07:29 -0800364 pkg_indexes: Old uploaded prebuilts to compare against. Instead of
365 uploading duplicate files, we just link to the old files.
David James615e5b52011-06-03 11:10:15 -0700366 build_path: The path to the directory containing the chroot.
367 packages: Packages to upload.
David James32b0b2f2011-07-13 20:56:50 -0700368 skip_upload: Don't actually upload the tarballs.
369 binhost_conf_dir: Directory where to store binhost.conf files.
Mike Frysinger86509232014-05-24 13:18:37 -0400370 dryrun: Don't push or upload prebuilts.
David James4058b0d2011-12-08 21:24:50 -0800371 target: BuildTarget managed by this builder.
372 slave_targets: List of BuildTargets managed by slave builders.
Mike Frysinger8092a632014-05-24 13:25:46 -0400373 version: A unique string, intended to be included in the upload path,
374 which identifies the version number of the uploaded prebuilts.
David Jamesc0f158a2011-02-22 16:07:29 -0800375 """
376 self._upload_location = upload_location
David Jamesfd0b0852011-02-23 11:15:36 -0800377 self._acl = acl
David Jamesc0f158a2011-02-22 16:07:29 -0800378 self._binhost_base_url = binhost_base_url
379 self._pkg_indexes = pkg_indexes
David James615e5b52011-06-03 11:10:15 -0700380 self._build_path = build_path
381 self._packages = set(packages)
Mike Frysingerf5f809a2013-02-12 13:47:37 -0500382 self._found_packages = set()
David James8ece7ee2011-06-29 16:02:30 -0700383 self._skip_upload = skip_upload
David James32b0b2f2011-07-13 20:56:50 -0700384 self._binhost_conf_dir = binhost_conf_dir
Mike Frysinger86509232014-05-24 13:18:37 -0400385 self._dryrun = dryrun
David James4058b0d2011-12-08 21:24:50 -0800386 self._target = target
387 self._slave_targets = slave_targets
Mike Frysinger8092a632014-05-24 13:25:46 -0400388 self._version = version
Mike Frysinger540883b2014-05-24 13:46:16 -0400389 self._gs_context = gs.GSContext(retries=_RETRIES, sleep=_SLEEP_TIME,
390 dry_run=self._dryrun)
391
392 def _Upload(self, local_file, remote_file):
393 """Wrapper around _GsUpload"""
394 _GsUpload(self._gs_context, self._acl, local_file, remote_file)
David James615e5b52011-06-03 11:10:15 -0700395
396 def _ShouldFilterPackage(self, pkg):
397 if not self._packages:
398 return False
399 pym_path = os.path.abspath(os.path.join(self._build_path, _PYM_PATH))
David James710b7dc2012-02-07 16:49:59 -0800400 sys.path.insert(0, pym_path)
Don Garrett25f309a2014-03-19 14:02:12 -0700401 # pylint: disable=F0401
David James615e5b52011-06-03 11:10:15 -0700402 import portage.versions
403 cat, pkgname = portage.versions.catpkgsplit(pkg['CPV'])[0:2]
404 cp = '%s/%s' % (cat, pkgname)
Mike Frysingerf5f809a2013-02-12 13:47:37 -0500405 self._found_packages.add(cp)
David James615e5b52011-06-03 11:10:15 -0700406 return pkgname not in self._packages and cp not in self._packages
David James8c846492011-01-25 17:07:29 -0800407
David Jamesc0f158a2011-02-22 16:07:29 -0800408 def _UploadPrebuilt(self, package_path, url_suffix):
409 """Upload host or board prebuilt files to Google Storage space.
David James8c846492011-01-25 17:07:29 -0800410
David Jamesc0f158a2011-02-22 16:07:29 -0800411 Args:
412 package_path: The path to the packages dir.
David Jamesce093af2011-02-23 15:21:58 -0800413 url_suffix: The remote subdirectory where we should upload the packages.
David Jamesc0f158a2011-02-22 16:07:29 -0800414 """
David Jamesc0f158a2011-02-22 16:07:29 -0800415 # Process Packages file, removing duplicates and filtered packages.
David James32faafe2012-06-08 14:25:03 -0700416 pkg_index = binpkg.GrabLocalPackageIndex(package_path)
David Jamesc0f158a2011-02-22 16:07:29 -0800417 pkg_index.SetUploadLocation(self._binhost_base_url, url_suffix)
David James615e5b52011-06-03 11:10:15 -0700418 pkg_index.RemoveFilteredPackages(self._ShouldFilterPackage)
David Jamesc0f158a2011-02-22 16:07:29 -0800419 uploads = pkg_index.ResolveDuplicateUploads(self._pkg_indexes)
Mike Frysingerf5f809a2013-02-12 13:47:37 -0500420 unmatched_pkgs = self._packages - self._found_packages
421 if unmatched_pkgs:
422 cros_build_lib.Warning('unable to match packages: %r' % unmatched_pkgs)
David James05bcb2b2011-02-09 09:25:47 -0800423
David Jamesc0f158a2011-02-22 16:07:29 -0800424 # Write Packages file.
425 tmp_packages_file = pkg_index.WriteToNamedTemporaryFile()
David James05bcb2b2011-02-09 09:25:47 -0800426
David Jamesc0f158a2011-02-22 16:07:29 -0800427 remote_location = '%s/%s' % (self._upload_location.rstrip('/'), url_suffix)
David James015af872012-06-19 15:24:36 -0700428 assert remote_location.startswith('gs://')
David James05bcb2b2011-02-09 09:25:47 -0800429
David James015af872012-06-19 15:24:36 -0700430 # Build list of files to upload.
431 upload_files = GenerateUploadDict(package_path, remote_location, uploads)
432 remote_file = '%s/Packages' % remote_location.rstrip('/')
433 upload_files[tmp_packages_file.name] = remote_file
434
Mike Frysinger540883b2014-05-24 13:46:16 -0400435 RemoteUpload(self._gs_context, self._acl, upload_files)
David James8c846492011-01-25 17:07:29 -0800436
Mike Frysinger212e4292014-05-24 15:15:44 -0400437 with tempfile.NamedTemporaryFile(
438 prefix='chromite.upload_prebuilts.index.') as index:
439 GenerateHtmlIndex(
440 [x[len(remote_location) + 1:] for x in upload_files.values()],
441 index.name, self._target, self._version)
442 self._Upload(index.name, '%s/index.html' % remote_location.rstrip('/'))
443
444 link_name = 'Prebuilts[%s]: %s' % (self._target, self._version)
445 url = '%s%s/index.html' % (gs.PUBLIC_BASE_HTTPS_URL,
446 remote_location[len(gs.BASE_GS_URL):])
447 cros_build_lib.PrintBuildbotLink(link_name, url)
448
Mike Frysinger8092a632014-05-24 13:25:46 -0400449 def _UploadSdkTarball(self, board_path, url_suffix, prepackaged,
Mike Frysinger9e979b92012-11-29 02:55:09 -0500450 toolchain_tarballs, toolchain_upload_path):
451 """Upload a tarball of the sdk at the specified path to Google Storage.
David James8fa34ea2011-04-15 13:00:20 -0700452
453 Args:
454 board_path: The path to the board dir.
455 url_suffix: The remote subdirectory where we should upload the packages.
Zdenek Behan62a57792012-08-31 15:09:08 +0200456 prepackaged: If given, a tarball that has been packaged outside of this
457 script and should be used.
Mike Frysinger9e979b92012-11-29 02:55:09 -0500458 toolchain_tarballs: List of toolchain tarballs to upload.
459 toolchain_upload_path: Path under the bucket to place toolchain tarballs.
David James8fa34ea2011-04-15 13:00:20 -0700460 """
461 remote_location = '%s/%s' % (self._upload_location.rstrip('/'), url_suffix)
462 assert remote_location.startswith('gs://')
Zdenek Behan86c15e92012-10-13 00:55:47 +0200463 boardname = os.path.basename(board_path.rstrip('/'))
464 # We do not upload non SDK board tarballs,
465 assert boardname == constants.CHROOT_BUILDER_BOARD
466 assert prepackaged is not None
Zdenek Behan62a57792012-08-31 15:09:08 +0200467
Mike Frysinger8092a632014-05-24 13:25:46 -0400468 version_str = self._version[len('chroot-'):]
Mike Frysinger8e727a32013-01-16 16:57:53 -0500469 remote_tarfile = toolchain.GetSdkURL(
470 for_gsutil=True, suburl='cros-sdk-%s.tar.xz' % (version_str,))
Zdenek Behan86c15e92012-10-13 00:55:47 +0200471 # For SDK, also upload the manifest which is guaranteed to exist
472 # by the builderstage.
Mike Frysinger540883b2014-05-24 13:46:16 -0400473 self._Upload(prepackaged + '.Manifest', remote_tarfile + '.Manifest')
474 self._Upload(prepackaged, remote_tarfile)
Zdenek Behan86c15e92012-10-13 00:55:47 +0200475
Mike Frysinger9e979b92012-11-29 02:55:09 -0500476 # Post the toolchain tarballs too.
477 for tarball in toolchain_tarballs:
478 target, local_path = tarball.split(':')
479 suburl = toolchain_upload_path % {'target': target}
480 remote_path = toolchain.GetSdkURL(for_gsutil=True, suburl=suburl)
Mike Frysinger540883b2014-05-24 13:46:16 -0400481 self._Upload(local_path, remote_path)
Mike Frysinger9e979b92012-11-29 02:55:09 -0500482
Zdenek Behan86c15e92012-10-13 00:55:47 +0200483 # Finally, also update the pointer to the latest SDK on which polling
484 # scripts rely.
David James4bc13702013-03-26 08:08:04 -0700485 with osutils.TempDir() as tmpdir:
Zdenek Behan86c15e92012-10-13 00:55:47 +0200486 pointerfile = os.path.join(tmpdir, 'cros-sdk-latest.conf')
Mike Frysinger8e727a32013-01-16 16:57:53 -0500487 remote_pointerfile = toolchain.GetSdkURL(for_gsutil=True,
488 suburl='cros-sdk-latest.conf')
Zdenek Behan86c15e92012-10-13 00:55:47 +0200489 osutils.WriteFile(pointerfile, 'LATEST_SDK="%s"' % version_str)
Mike Frysinger540883b2014-05-24 13:46:16 -0400490 self._Upload(pointerfile, remote_pointerfile)
Zdenek Behan33a34112012-09-10 21:07:51 +0200491
Chris Sosa6a5dceb2012-05-14 13:48:56 -0700492 def _GetTargets(self):
493 """Retuns the list of targets to use."""
494 targets = self._slave_targets[:]
495 if self._target:
496 targets.append(self._target)
497
498 return targets
499
Mike Frysinger8092a632014-05-24 13:25:46 -0400500 def SyncHostPrebuilts(self, key, git_sync, sync_binhost_conf):
David Jamesc0f158a2011-02-22 16:07:29 -0800501 """Synchronize host prebuilt files.
David James05bcb2b2011-02-09 09:25:47 -0800502
David Jamesc0f158a2011-02-22 16:07:29 -0800503 This function will sync both the standard host packages, plus the host
504 packages associated with all targets that have been "setup" with the
505 current host's chroot. For instance, if this host has been used to build
506 x86-generic, it will sync the host packages associated with
507 'i686-pc-linux-gnu'. If this host has also been used to build arm-generic,
508 it will also sync the host packages associated with
509 'armv7a-cros-linux-gnueabi'.
David James05bcb2b2011-02-09 09:25:47 -0800510
David Jamesc0f158a2011-02-22 16:07:29 -0800511 Args:
David Jamesc0f158a2011-02-22 16:07:29 -0800512 key: The variable key to update in the git file.
513 git_sync: If set, update make.conf of target to reference the latest
514 prebuilt packages generated here.
515 sync_binhost_conf: If set, update binhost config file in
516 chromiumos-overlay for the host.
517 """
David Jamese2488642011-11-14 16:15:20 -0800518 # Slave boards are listed before the master board so that the master board
519 # takes priority (i.e. x86-generic preflight host prebuilts takes priority
520 # over preflight host prebuilts from other builders.)
521 binhost_urls = []
Chris Sosa6a5dceb2012-05-14 13:48:56 -0700522 for target in self._GetTargets():
Mike Frysinger8092a632014-05-24 13:25:46 -0400523 url_suffix = _REL_HOST_PATH % {'version': self._version,
David James4058b0d2011-12-08 21:24:50 -0800524 'host_arch': _HOST_ARCH,
525 'target': target}
David Jamese2488642011-11-14 16:15:20 -0800526 packages_url_suffix = '%s/packages' % url_suffix.rstrip('/')
David James05bcb2b2011-02-09 09:25:47 -0800527
Mike Frysinger540883b2014-05-24 13:46:16 -0400528 if self._target == target and not self._skip_upload:
David Jamese2488642011-11-14 16:15:20 -0800529 # Upload prebuilts.
530 package_path = os.path.join(self._build_path, _HOST_PACKAGES_PATH)
531 self._UploadPrebuilt(package_path, packages_url_suffix)
David James8ece7ee2011-06-29 16:02:30 -0700532
David Jamese2488642011-11-14 16:15:20 -0800533 # Record URL where prebuilts were uploaded.
534 binhost_urls.append('%s/%s/' % (self._binhost_base_url.rstrip('/'),
535 packages_url_suffix.rstrip('/')))
536
David James20b2b6f2011-11-18 15:11:58 -0800537 binhost = ' '.join(binhost_urls)
David James8ece7ee2011-06-29 16:02:30 -0700538 if git_sync:
539 git_file = os.path.join(self._build_path,
David James4058b0d2011-12-08 21:24:50 -0800540 _PREBUILT_MAKE_CONF[_HOST_ARCH])
Mike Frysinger86509232014-05-24 13:18:37 -0400541 RevGitFile(git_file, {key: binhost}, dryrun=self._dryrun)
David James8ece7ee2011-06-29 16:02:30 -0700542 if sync_binhost_conf:
David James32b0b2f2011-07-13 20:56:50 -0700543 binhost_conf = os.path.join(self._build_path, self._binhost_conf_dir,
David James4058b0d2011-12-08 21:24:50 -0800544 'host', '%s-%s.conf' % (_HOST_ARCH, key))
David Jamese2488642011-11-14 16:15:20 -0800545 UpdateBinhostConfFile(binhost_conf, key, binhost)
David Jamesc0f158a2011-02-22 16:07:29 -0800546
Mike Frysinger8092a632014-05-24 13:25:46 -0400547 def SyncBoardPrebuilts(self, key, git_sync, sync_binhost_conf,
Mike Frysinger9e979b92012-11-29 02:55:09 -0500548 upload_board_tarball, prepackaged_board,
549 toolchain_tarballs, toolchain_upload_path):
David Jamesc0f158a2011-02-22 16:07:29 -0800550 """Synchronize board prebuilt files.
551
552 Args:
David Jamesc0f158a2011-02-22 16:07:29 -0800553 key: The variable key to update in the git file.
554 git_sync: If set, update make.conf of target to reference the latest
555 prebuilt packages generated here.
556 sync_binhost_conf: If set, update binhost config file in
557 chromiumos-overlay for the current board.
David James8fa34ea2011-04-15 13:00:20 -0700558 upload_board_tarball: Include a tarball of the board in our upload.
Zdenek Behan62a57792012-08-31 15:09:08 +0200559 prepackaged_board: A tarball of the board built outside of this script.
Mike Frysinger9e979b92012-11-29 02:55:09 -0500560 toolchain_tarballs: A list of toolchain tarballs to upload.
561 toolchain_upload_path: Path under the bucket to place toolchain tarballs.
David Jamesc0f158a2011-02-22 16:07:29 -0800562 """
Chris Sosa6a5dceb2012-05-14 13:48:56 -0700563 for target in self._GetTargets():
David Jamese2488642011-11-14 16:15:20 -0800564 board_path = os.path.join(self._build_path,
David James4058b0d2011-12-08 21:24:50 -0800565 _BOARD_PATH % {'board': target.board_variant})
David Jamese2488642011-11-14 16:15:20 -0800566 package_path = os.path.join(board_path, 'packages')
Mike Frysinger8092a632014-05-24 13:25:46 -0400567 url_suffix = _REL_BOARD_PATH % {'target': target,
568 'version': self._version}
David Jamese2488642011-11-14 16:15:20 -0800569 packages_url_suffix = '%s/packages' % url_suffix.rstrip('/')
David James8fa34ea2011-04-15 13:00:20 -0700570
Matt Tennante8179042013-10-01 15:47:32 -0700571 # Process the target board differently if it is the main --board.
Mike Frysinger540883b2014-05-24 13:46:16 -0400572 if self._target == target and not self._skip_upload:
Matt Tennante8179042013-10-01 15:47:32 -0700573 # This strips "chroot" prefix because that is sometimes added as the
574 # --prepend-version argument (e.g. by chromiumos-sdk bot).
575 # TODO(build): Clean it up to be less hard-coded.
Mike Frysinger8092a632014-05-24 13:25:46 -0400576 version_str = self._version[len('chroot-'):]
Mike Frysinger9e979b92012-11-29 02:55:09 -0500577
David Jamese2488642011-11-14 16:15:20 -0800578 # Upload board tarballs in the background.
579 if upload_board_tarball:
Mike Frysinger9e979b92012-11-29 02:55:09 -0500580 if toolchain_upload_path:
581 toolchain_upload_path %= {'version': version_str}
582 tar_process = multiprocessing.Process(
583 target=self._UploadSdkTarball,
Mike Frysinger8092a632014-05-24 13:25:46 -0400584 args=(board_path, url_suffix, prepackaged_board,
Mike Frysinger9e979b92012-11-29 02:55:09 -0500585 toolchain_tarballs, toolchain_upload_path))
David Jamese2488642011-11-14 16:15:20 -0800586 tar_process.start()
David James8fa34ea2011-04-15 13:00:20 -0700587
David Jamese2488642011-11-14 16:15:20 -0800588 # Upload prebuilts.
589 self._UploadPrebuilt(package_path, packages_url_suffix)
David James8fa34ea2011-04-15 13:00:20 -0700590
David Jamese2488642011-11-14 16:15:20 -0800591 # Make sure we finished uploading the board tarballs.
592 if upload_board_tarball:
593 tar_process.join()
594 assert tar_process.exitcode == 0
595 # TODO(zbehan): This should be done cleaner.
Zdenek Behan33a34112012-09-10 21:07:51 +0200596 if target.board == constants.CHROOT_BUILDER_BOARD:
David Jamese2488642011-11-14 16:15:20 -0800597 sdk_conf = os.path.join(self._build_path, self._binhost_conf_dir,
Mike Frysinger5b34d732013-01-17 15:11:58 -0500598 'host/sdk_version.conf')
599 sdk_settings = {
Mike Frysinger9e979b92012-11-29 02:55:09 -0500600 'SDK_LATEST_VERSION': version_str,
601 'TC_PATH': toolchain_upload_path,
Mike Frysinger5b34d732013-01-17 15:11:58 -0500602 }
Mike Frysinger86509232014-05-24 13:18:37 -0400603 RevGitFile(sdk_conf, sdk_settings, dryrun=self._dryrun)
David Jamesc0f158a2011-02-22 16:07:29 -0800604
David Jamese2488642011-11-14 16:15:20 -0800605 # Record URL where prebuilts were uploaded.
606 url_value = '%s/%s/' % (self._binhost_base_url.rstrip('/'),
607 packages_url_suffix.rstrip('/'))
608
609 if git_sync:
David James4058b0d2011-12-08 21:24:50 -0800610 git_file = DeterminePrebuiltConfFile(self._build_path, target)
Mike Frysinger86509232014-05-24 13:18:37 -0400611 RevGitFile(git_file, {key: url_value}, dryrun=self._dryrun)
Matt Tennante8179042013-10-01 15:47:32 -0700612
David Jamese2488642011-11-14 16:15:20 -0800613 if sync_binhost_conf:
Matt Tennante8179042013-10-01 15:47:32 -0700614 # Update the binhost configuration file in git.
David Jamese2488642011-11-14 16:15:20 -0800615 binhost_conf = os.path.join(self._build_path, self._binhost_conf_dir,
David James4058b0d2011-12-08 21:24:50 -0800616 'target', '%s-%s.conf' % (target, key))
David Jamese2488642011-11-14 16:15:20 -0800617 UpdateBinhostConfFile(binhost_conf, key, url_value)
David James05bcb2b2011-02-09 09:25:47 -0800618
619
Chris Sosa6a5dceb2012-05-14 13:48:56 -0700620def _AddSlaveBoard(_option, _opt_str, value, parser):
621 """Callback that adds a slave board to the list of slave targets."""
David James4058b0d2011-12-08 21:24:50 -0800622 parser.values.slave_targets.append(BuildTarget(value))
623
624
Chris Sosa6a5dceb2012-05-14 13:48:56 -0700625def _AddSlaveProfile(_option, _opt_str, value, parser):
626 """Callback that adds a slave profile to the list of slave targets."""
David James4058b0d2011-12-08 21:24:50 -0800627 if not parser.values.slave_targets:
Mike Frysinger86509232014-05-24 13:18:37 -0400628 parser.error('Must specify --slave-board before --slave-profile')
David James4058b0d2011-12-08 21:24:50 -0800629 if parser.values.slave_targets[-1].profile is not None:
Mike Frysinger86509232014-05-24 13:18:37 -0400630 parser.error('Cannot specify --slave-profile twice for same board')
David James4058b0d2011-12-08 21:24:50 -0800631 parser.values.slave_targets[-1].profile = value
632
633
Mike Frysinger86509232014-05-24 13:18:37 -0400634def ParseOptions(argv):
Chris Sosa6a5dceb2012-05-14 13:48:56 -0700635 """Returns options given by the user and the target specified.
636
Mike Frysinger86509232014-05-24 13:18:37 -0400637 Args:
638 argv: The args to parse.
639
Mike Frysinger1a736a82013-12-12 01:50:59 -0500640 Returns:
641 A tuple containing a parsed options object and BuildTarget.
642 The target instance is None if no board is specified.
Chris Sosa6a5dceb2012-05-14 13:48:56 -0700643 """
Mike Frysinger86509232014-05-24 13:18:37 -0400644 parser = commandline.OptionParser()
David James8c846492011-01-25 17:07:29 -0800645 parser.add_option('-H', '--binhost-base-url', dest='binhost_base_url',
646 default=_BINHOST_BASE_URL,
647 help='Base URL to use for binhost in make.conf updates')
648 parser.add_option('', '--previous-binhost-url', action='append',
649 default=[], dest='previous_binhost_url',
650 help='Previous binhost URL')
651 parser.add_option('-b', '--board', dest='board', default=None,
652 help='Board type that was built on this machine')
Zdenek Behan62a57792012-08-31 15:09:08 +0200653 parser.add_option('-B', '--prepackaged-tarball', dest='prepackaged_tarball',
654 default=None,
655 help='Board tarball prebuilt outside of this script.')
Mike Frysinger9e979b92012-11-29 02:55:09 -0500656 parser.add_option('--toolchain-tarball', dest='toolchain_tarballs',
657 action='append', default=[],
658 help='Redistributable toolchain tarball.')
659 parser.add_option('--toolchain-upload-path', default='',
660 help='Path to place toolchain tarballs in the sdk tree.')
David James4058b0d2011-12-08 21:24:50 -0800661 parser.add_option('', '--profile', dest='profile', default=None,
662 help='Profile that was built on this machine')
663 parser.add_option('', '--slave-board', default=[], action='callback',
664 dest='slave_targets', type='string',
Chris Sosa6a5dceb2012-05-14 13:48:56 -0700665 callback=_AddSlaveBoard,
David James4058b0d2011-12-08 21:24:50 -0800666 help='Board type that was built on a slave machine. To '
667 'add a profile to this board, use --slave-profile.')
668 parser.add_option('', '--slave-profile', action='callback', type='string',
Chris Sosa6a5dceb2012-05-14 13:48:56 -0700669 callback=_AddSlaveProfile,
David James4058b0d2011-12-08 21:24:50 -0800670 help='Board profile that was built on a slave machine. '
671 'Applies to previous slave board.')
David James8c846492011-01-25 17:07:29 -0800672 parser.add_option('-p', '--build-path', dest='build_path',
David James05bcb2b2011-02-09 09:25:47 -0800673 help='Path to the directory containing the chroot')
David James615e5b52011-06-03 11:10:15 -0700674 parser.add_option('', '--packages', action='append',
675 default=[], dest='packages',
676 help='Only include the specified packages. '
677 '(Default is to include all packages.)')
David James8c846492011-01-25 17:07:29 -0800678 parser.add_option('-s', '--sync-host', dest='sync_host',
679 default=False, action='store_true',
680 help='Sync host prebuilts')
681 parser.add_option('-g', '--git-sync', dest='git_sync',
682 default=False, action='store_true',
David Jamese2488642011-11-14 16:15:20 -0800683 help='Enable git version sync (This commits to a repo.) '
684 'This is used by full builders to commit directly '
685 'to board overlays.')
David James8c846492011-01-25 17:07:29 -0800686 parser.add_option('-u', '--upload', dest='upload',
687 default=None,
688 help='Upload location')
689 parser.add_option('-V', '--prepend-version', dest='prepend_version',
690 default=None,
691 help='Add an identifier to the front of the version')
692 parser.add_option('-f', '--filters', dest='filters', action='store_true',
693 default=False,
694 help='Turn on filtering of private ebuild packages')
695 parser.add_option('-k', '--key', dest='key',
696 default='PORTAGE_BINHOST',
697 help='Key to update in make.conf / binhost.conf')
David James8ece7ee2011-06-29 16:02:30 -0700698 parser.add_option('', '--set-version', dest='set_version',
699 default=None,
700 help='Specify the version string')
David James8c846492011-01-25 17:07:29 -0800701 parser.add_option('', '--sync-binhost-conf', dest='sync_binhost_conf',
702 default=False, action='store_true',
David Jamese2488642011-11-14 16:15:20 -0800703 help='Update binhost.conf in chromiumos-overlay or '
704 'chromeos-overlay. Commit the changes, but don\'t '
705 'push them. This is used for preflight binhosts.')
David James32b0b2f2011-07-13 20:56:50 -0700706 parser.add_option('', '--binhost-conf-dir', dest='binhost_conf_dir',
David James32b0b2f2011-07-13 20:56:50 -0700707 help='Directory to commit binhost config with '
708 '--sync-binhost-conf.')
David Jamesfd0b0852011-02-23 11:15:36 -0800709 parser.add_option('-P', '--private', dest='private', action='store_true',
710 default=False, help='Mark gs:// uploads as private.')
David James8ece7ee2011-06-29 16:02:30 -0700711 parser.add_option('', '--skip-upload', dest='skip_upload',
712 action='store_true', default=False,
713 help='Skip upload step.')
David James8fa34ea2011-04-15 13:00:20 -0700714 parser.add_option('', '--upload-board-tarball', dest='upload_board_tarball',
715 action='store_true', default=False,
716 help='Upload board tarball to Google Storage.')
Mike Frysinger86509232014-05-24 13:18:37 -0400717 parser.add_option('-n', '--dry-run', dest='dryrun',
David James27fa7d12011-06-29 17:24:14 -0700718 action='store_true', default=False,
719 help='Don\'t push or upload prebuilts.')
David James8c846492011-01-25 17:07:29 -0800720
Mike Frysinger86509232014-05-24 13:18:37 -0400721 options, args = parser.parse_args(argv)
David James8c846492011-01-25 17:07:29 -0800722 if not options.build_path:
Mike Frysinger86509232014-05-24 13:18:37 -0400723 parser.error('you need provide a chroot path')
David James8ece7ee2011-06-29 16:02:30 -0700724 if not options.upload and not options.skip_upload:
Mike Frysinger86509232014-05-24 13:18:37 -0400725 parser.error('you need to provide an upload location using -u')
David James8ece7ee2011-06-29 16:02:30 -0700726 if not options.set_version and options.skip_upload:
Mike Frysinger86509232014-05-24 13:18:37 -0400727 parser.error('If you are using --skip-upload, you must specify a '
728 'version number using --set-version.')
David James9417f272011-05-26 13:24:47 -0700729 if args:
Mike Frysinger86509232014-05-24 13:18:37 -0400730 parser.error('invalid arguments passed to upload_prebuilts: %r' % args)
Scott Zawalskiab1bed32011-03-16 15:24:24 -0700731
Chris Sosa6a5dceb2012-05-14 13:48:56 -0700732 target = None
733 if options.board:
734 target = BuildTarget(options.board, options.profile)
735
736 if target in options.slave_targets:
Mike Frysinger86509232014-05-24 13:18:37 -0400737 parser.error('--board/--profile must not also be a slave target.')
David Jamese2488642011-11-14 16:15:20 -0800738
David James4058b0d2011-12-08 21:24:50 -0800739 if len(set(options.slave_targets)) != len(options.slave_targets):
Mike Frysinger86509232014-05-24 13:18:37 -0400740 parser.error('--slave-boards must not have duplicates.')
David Jamese2488642011-11-14 16:15:20 -0800741
David James4058b0d2011-12-08 21:24:50 -0800742 if options.slave_targets and options.git_sync:
Mike Frysinger86509232014-05-24 13:18:37 -0400743 parser.error('--slave-boards is not compatible with --git-sync')
David Jamese2488642011-11-14 16:15:20 -0800744
David James8ece7ee2011-06-29 16:02:30 -0700745 if (options.upload_board_tarball and options.skip_upload and
746 options.board == 'amd64-host'):
Mike Frysinger86509232014-05-24 13:18:37 -0400747 parser.error('--skip-upload is not compatible with '
748 '--upload-board-tarball and --board=amd64-host')
David James8fa34ea2011-04-15 13:00:20 -0700749
David James8ece7ee2011-06-29 16:02:30 -0700750 if (options.upload_board_tarball and not options.skip_upload and
751 not options.upload.startswith('gs://')):
Mike Frysinger86509232014-05-24 13:18:37 -0400752 parser.error('--upload-board-tarball only works with gs:// URLs.\n'
753 '--upload must be a gs:// URL.')
David James8fa34ea2011-04-15 13:00:20 -0700754
Zdenek Behan86c15e92012-10-13 00:55:47 +0200755 if options.upload_board_tarball and options.prepackaged_tarball is None:
Mike Frysinger86509232014-05-24 13:18:37 -0400756 parser.error('--upload-board-tarball requires --prepackaged-tarball')
Zdenek Behan86c15e92012-10-13 00:55:47 +0200757
Scott Zawalskiab1bed32011-03-16 15:24:24 -0700758 if options.private:
759 if options.sync_host:
Mike Frysinger86509232014-05-24 13:18:37 -0400760 parser.error('--private and --sync-host/-s cannot be specified '
761 'together; we do not support private host prebuilts')
Scott Zawalskiab1bed32011-03-16 15:24:24 -0700762
David James8ece7ee2011-06-29 16:02:30 -0700763 if not options.upload or not options.upload.startswith('gs://'):
Mike Frysinger86509232014-05-24 13:18:37 -0400764 parser.error('--private is only valid for gs:// URLs; '
765 '--upload must be a gs:// URL.')
Scott Zawalskiab1bed32011-03-16 15:24:24 -0700766
767 if options.binhost_base_url != _BINHOST_BASE_URL:
Mike Frysinger86509232014-05-24 13:18:37 -0400768 parser.error('when using --private the --binhost-base-url '
769 'is automatically derived.')
David James27fa7d12011-06-29 17:24:14 -0700770
David Jamesc31168e2014-06-05 14:40:05 -0700771 if options.sync_binhost_conf and not options.binhost_conf_dir:
772 parser.error('--sync-binhost-conf requires --binhost-conf-dir')
773
Chris Sosa6a5dceb2012-05-14 13:48:56 -0700774 return options, target
David Jamesc0f158a2011-02-22 16:07:29 -0800775
Mike Frysingercc838832014-05-24 13:10:30 -0400776
Mike Frysinger86509232014-05-24 13:18:37 -0400777def main(argv):
David Jamesdb401072011-06-10 12:17:16 -0700778 # Set umask to a sane value so that files created as root are readable.
Mike Frysinger60ec1012013-10-21 00:11:10 -0400779 os.umask(0o22)
David Jamesdb401072011-06-10 12:17:16 -0700780
Mike Frysinger86509232014-05-24 13:18:37 -0400781 options, target = ParseOptions(argv)
David Jamesc0f158a2011-02-22 16:07:29 -0800782
David James05bcb2b2011-02-09 09:25:47 -0800783 # Calculate a list of Packages index files to compare against. Whenever we
784 # upload a package, we check to make sure it's not already stored in one of
785 # the packages files we uploaded. This list of packages files might contain
786 # both board and host packages.
David Jamesce093af2011-02-23 15:21:58 -0800787 pkg_indexes = _GrabAllRemotePackageIndexes(options.previous_binhost_url)
David James8c846492011-01-25 17:07:29 -0800788
David James8ece7ee2011-06-29 16:02:30 -0700789 if options.set_version:
790 version = options.set_version
791 else:
792 version = GetVersion()
Matt Tennante8179042013-10-01 15:47:32 -0700793
David Jamesc0f158a2011-02-22 16:07:29 -0800794 if options.prepend_version:
795 version = '%s-%s' % (options.prepend_version, version)
796
Scott Zawalskiab1bed32011-03-16 15:24:24 -0700797 acl = 'public-read'
798 binhost_base_url = options.binhost_base_url
799
David Jamesadd21432013-05-21 10:04:07 -0700800 if options.private:
Scott Zawalskiab1bed32011-03-16 15:24:24 -0700801 binhost_base_url = options.upload
David Jamesadd21432013-05-21 10:04:07 -0700802 if target:
Peter Mayo950e41a2014-02-06 21:07:33 +0000803 board_path = GetBoardOverlay(options.build_path, target)
Gabe Black40169e62014-06-17 15:23:47 -0700804 # Use the gsutil acl ch argument file if it exists, or fall back to the
805 # XML acl file.
806 acl = os.path.join(board_path, _GOOGLESTORAGE_GSUTIL_FILE)
807 if not os.path.isfile(acl):
808 acl = os.path.join(board_path, _GOOGLESTORAGE_ACL_FILE)
Scott Zawalskiab1bed32011-03-16 15:24:24 -0700809
810 uploader = PrebuiltUploader(options.upload, acl, binhost_base_url,
David James615e5b52011-06-03 11:10:15 -0700811 pkg_indexes, options.build_path,
David James27fa7d12011-06-29 17:24:14 -0700812 options.packages, options.skip_upload,
Mike Frysinger86509232014-05-24 13:18:37 -0400813 options.binhost_conf_dir, options.dryrun,
Mike Frysinger8092a632014-05-24 13:25:46 -0400814 target, options.slave_targets, version)
David Jamesc0f158a2011-02-22 16:07:29 -0800815
David James8c846492011-01-25 17:07:29 -0800816 if options.sync_host:
Mike Frysinger8092a632014-05-24 13:25:46 -0400817 uploader.SyncHostPrebuilts(options.key, options.git_sync,
Chris Sosa6a5dceb2012-05-14 13:48:56 -0700818 options.sync_binhost_conf)
David James8c846492011-01-25 17:07:29 -0800819
Chris Sosa62c8ff52012-06-04 15:03:12 -0700820 if options.board or options.slave_targets:
Mike Frysinger8092a632014-05-24 13:25:46 -0400821 uploader.SyncBoardPrebuilts(options.key, options.git_sync,
Chris Sosa6a5dceb2012-05-14 13:48:56 -0700822 options.sync_binhost_conf,
Zdenek Behan62a57792012-08-31 15:09:08 +0200823 options.upload_board_tarball,
Mike Frysinger9e979b92012-11-29 02:55:09 -0500824 options.prepackaged_tarball,
825 options.toolchain_tarballs,
826 options.toolchain_upload_path)