blob: 0896860a8e3d13a3ffa8506bd68e8d04da0ae4eb [file] [log] [blame]
David Jamesb619a782012-07-25 19:37:57 -07001# Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
David James8c846492011-01-25 17:07:29 -08002# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
Brian Harringaf019fb2012-05-10 15:06:13 -07005"""This script is used to upload host prebuilts as well as board BINHOSTS.
David James8c846492011-01-25 17:07:29 -08006
David James015af872012-06-19 15:24:36 -07007Prebuilts are uploaded using gsutil to Google Storage. After these prebuilts
8are successfully uploaded, a file is updated with the proper BINHOST version.
David James8c846492011-01-25 17:07:29 -08009
10To read more about prebuilts/binhost binary packages please refer to:
David James015af872012-06-19 15:24:36 -070011http://goto/chromeos-prebuilts
David James8c846492011-01-25 17:07:29 -080012
13Example of uploading prebuilt amd64 host files to Google Storage:
David Jamesc5cbd472012-06-19 16:25:45 -070014upload_prebuilts -p /b/cbuild/build -s -u gs://chromeos-prebuilt
David James8c846492011-01-25 17:07:29 -080015
16Example of uploading x86-dogfood binhosts to Google Storage:
David Jamesc5cbd472012-06-19 16:25:45 -070017upload_prebuilts -b x86-dogfood -p /b/cbuild/build/ -u gs://chromeos-prebuilt -g
David James8c846492011-01-25 17:07:29 -080018"""
19
Mike Frysingerff441bf2014-05-24 13:47:21 -040020from __future__ import print_function
21
Chris Sosa1dc96132012-05-11 15:40:50 -070022import datetime
Mike Frysinger540883b2014-05-24 13:46:16 -040023import functools
David Jamesb26b9312014-12-15 11:26:46 -080024import glob
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
David James6450a0a2012-12-04 07:59:53 -080032from chromite.lib import binpkg
Mike Frysinger86509232014-05-24 13:18:37 -040033from chromite.lib import commandline
Chris Sosa1dc96132012-05-11 15:40:50 -070034from chromite.lib import cros_build_lib
David James97d95872012-11-16 15:09:56 -080035from chromite.lib import git
Brian Harring7904b482012-08-08 02:54:12 -070036from chromite.lib import gs
Brian Harringaf019fb2012-05-10 15:06:13 -070037from chromite.lib import osutils
David James6450a0a2012-12-04 07:59:53 -080038from chromite.lib import parallel
Alex Deymo075c2292014-09-04 18:31:50 -070039from chromite.lib import portage_util
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 James5ab67e32014-10-24 08:19:59 -070049# The length of time (in seconds) that Portage should wait before refetching
50# binpkgs from the same binhost. We don't ever modify binhosts, so this should
51# be something big.
52_BINPKG_TTL = 60 * 60 * 24 * 365
53
David James8c846492011-01-25 17:07:29 -080054_HOST_PACKAGES_PATH = 'chroot/var/lib/portage/pkgs'
David James05bcb2b2011-02-09 09:25:47 -080055_CATEGORIES_PATH = 'chroot/etc/portage/categories'
David James615e5b52011-06-03 11:10:15 -070056_PYM_PATH = 'chroot/usr/lib/portage/pym'
David James4058b0d2011-12-08 21:24:50 -080057_HOST_ARCH = 'amd64'
David James8c846492011-01-25 17:07:29 -080058_BOARD_PATH = 'chroot/build/%(board)s'
David James4058b0d2011-12-08 21:24:50 -080059_REL_BOARD_PATH = 'board/%(target)s/%(version)s'
60_REL_HOST_PATH = 'host/%(host_arch)s/%(target)s/%(version)s'
David James8c846492011-01-25 17:07:29 -080061# Private overlays to look at for builds to filter
62# relative to build path
63_PRIVATE_OVERLAY_DIR = 'src/private-overlays'
Gabe Black40169e62014-06-17 15:23:47 -070064_GOOGLESTORAGE_GSUTIL_FILE = 'googlestorage_acl.txt'
David James3753d942014-04-23 10:55:48 -070065_BINHOST_BASE_URL = 'gs://chromeos-prebuilt'
David James8c846492011-01-25 17:07:29 -080066_PREBUILT_BASE_DIR = 'src/third_party/chromiumos-overlay/chromeos/config/'
67# Created in the event of new host targets becoming available
68_PREBUILT_MAKE_CONF = {'amd64': os.path.join(_PREBUILT_BASE_DIR,
69 'make.conf.amd64-host')}
David James8c846492011-01-25 17:07:29 -080070
71
David James4058b0d2011-12-08 21:24:50 -080072class BuildTarget(object):
73 """A board/variant/profile tuple."""
74
75 def __init__(self, board_variant, profile=None):
76 self.board_variant = board_variant
77 self.board, _, self.variant = board_variant.partition('_')
78 self.profile = profile
79
80 def __str__(self):
81 if self.profile:
82 return '%s_%s' % (self.board_variant, self.profile)
83 else:
84 return self.board_variant
85
86 def __eq__(self, other):
87 return str(other) == str(self)
88
89 def __hash__(self):
90 return hash(str(self))
91
92
David James8c846492011-01-25 17:07:29 -080093def UpdateLocalFile(filename, value, key='PORTAGE_BINHOST'):
94 """Update the key in file with the value passed.
Mike Frysinger1a736a82013-12-12 01:50:59 -050095
David James8c846492011-01-25 17:07:29 -080096 File format:
97 key="value"
98 Note quotes are added automatically
99
100 Args:
101 filename: Name of file to modify.
102 value: Value to write with the key.
103 key: The variable key to update. (Default: PORTAGE_BINHOST)
David Jamesb26b9312014-12-15 11:26:46 -0800104
105 Returns:
106 True if changes were made to the file.
David James8c846492011-01-25 17:07:29 -0800107 """
108 if os.path.exists(filename):
109 file_fh = open(filename)
110 else:
111 file_fh = open(filename, 'w+')
112 file_lines = []
113 found = False
David Jamesb26b9312014-12-15 11:26:46 -0800114 made_changes = False
David James8c846492011-01-25 17:07:29 -0800115 keyval_str = '%(key)s=%(value)s'
116 for line in file_fh:
117 # Strip newlines from end of line. We already add newlines below.
118 line = line.rstrip("\n")
119
120 if len(line.split('=')) != 2:
121 # Skip any line that doesn't fit key=val.
122 file_lines.append(line)
123 continue
124
125 file_var, file_val = line.split('=')
126 if file_var == key:
127 found = True
Mike Frysingerff441bf2014-05-24 13:47:21 -0400128 print('Updating %s=%s to %s="%s"' % (file_var, file_val, key, value))
David James8c846492011-01-25 17:07:29 -0800129 value = '"%s"' % value
David Jamesb26b9312014-12-15 11:26:46 -0800130 made_changes |= (file_val != value)
David James8c846492011-01-25 17:07:29 -0800131 file_lines.append(keyval_str % {'key': key, 'value': value})
132 else:
133 file_lines.append(keyval_str % {'key': file_var, 'value': file_val})
134
135 if not found:
Brian Harring2a014302012-05-12 00:53:33 -0700136 value = '"%s"' % value
David Jamesb26b9312014-12-15 11:26:46 -0800137 made_changes = True
David James8c846492011-01-25 17:07:29 -0800138 file_lines.append(keyval_str % {'key': key, 'value': value})
139
140 file_fh.close()
141 # write out new file
Brian Harringaf019fb2012-05-10 15:06:13 -0700142 osutils.WriteFile(filename, '\n'.join(file_lines) + '\n')
David Jamesb26b9312014-12-15 11:26:46 -0800143 return made_changes
David James8c846492011-01-25 17:07:29 -0800144
145
Mike Frysinger5b34d732013-01-17 15:11:58 -0500146def RevGitFile(filename, data, retries=5, dryrun=False):
David James8c846492011-01-25 17:07:29 -0800147 """Update and push the git file.
148
Mike Frysinger5b34d732013-01-17 15:11:58 -0500149 Args:
150 filename: file to modify that is in a git repo already
151 data: A dict of key/values to update in |filename|
152 retries: The number of times to retry before giving up, default: 5
Matt Tennante8179042013-10-01 15:47:32 -0700153 dryrun: If True, do not actually commit the change.
David James8c846492011-01-25 17:07:29 -0800154 """
155 prebuilt_branch = 'prebuilt_branch'
David James1b6e67a2011-05-19 21:32:38 -0700156 cwd = os.path.abspath(os.path.dirname(filename))
David James97d95872012-11-16 15:09:56 -0800157 commit = git.RunGit(cwd, ['rev-parse', 'HEAD']).output.rstrip()
Mike Frysinger5b34d732013-01-17 15:11:58 -0500158 description = '%s: updating %s' % (os.path.basename(filename),
159 ', '.join(data.keys()))
160 # UpdateLocalFile will print out the keys/values for us.
Mike Frysingerff441bf2014-05-24 13:47:21 -0400161 print('Revving git file %s' % filename)
David James66009462012-03-25 10:08:38 -0700162
David James8c846492011-01-25 17:07:29 -0800163 try:
David James97d95872012-11-16 15:09:56 -0800164 git.CreatePushBranch(prebuilt_branch, cwd)
Mike Frysinger5b34d732013-01-17 15:11:58 -0500165 for key, value in data.iteritems():
166 UpdateLocalFile(filename, value, key)
David James97d95872012-11-16 15:09:56 -0800167 git.RunGit(cwd, ['add', filename])
168 git.RunGit(cwd, ['commit', '-m', description])
169 git.PushWithRetry(prebuilt_branch, cwd, dryrun=dryrun, retries=retries)
David James8c846492011-01-25 17:07:29 -0800170 finally:
David James67d73252013-09-19 17:33:12 -0700171 git.RunGit(cwd, ['checkout', commit])
David James8c846492011-01-25 17:07:29 -0800172
173
174def GetVersion():
175 """Get the version to put in LATEST and update the git version with."""
Mike Frysinger0b92cfe2012-12-13 02:13:45 -0500176 return datetime.datetime.now().strftime('%Y.%m.%d.%H%M%S')
David James8c846492011-01-25 17:07:29 -0800177
178
Mike Frysinger540883b2014-05-24 13:46:16 -0400179def _GsUpload(gs_context, acl, local_file, remote_file):
David James8c846492011-01-25 17:07:29 -0800180 """Upload to GS bucket.
181
182 Args:
Mike Frysinger540883b2014-05-24 13:46:16 -0400183 gs_context: A lib.gs.GSContext instance.
184 acl: The ACL to use for uploading the file.
Matt Tennante8179042013-10-01 15:47:32 -0700185 local_file: The local file to be uploaded.
186 remote_file: The remote location to upload to.
David James8c846492011-01-25 17:07:29 -0800187
188 Returns:
189 Return the arg tuple of two if the upload failed
190 """
Scott Zawalskiab1bed32011-03-16 15:24:24 -0700191 CANNED_ACLS = ['public-read', 'private', 'bucket-owner-read',
192 'authenticated-read', 'bucket-owner-full-control',
193 'public-read-write']
Scott Zawalskiab1bed32011-03-16 15:24:24 -0700194 if acl in CANNED_ACLS:
David James9374aac2013-10-08 16:00:17 -0700195 gs_context.Copy(local_file, remote_file, acl=acl)
Scott Zawalskiab1bed32011-03-16 15:24:24 -0700196 else:
197 # For private uploads we assume that the overlay board is set up properly
David James015af872012-06-19 15:24:36 -0700198 # and a googlestore_acl.xml is present. Otherwise, this script errors.
David James9374aac2013-10-08 16:00:17 -0700199 gs_context.Copy(local_file, remote_file, acl='private')
Gabe Black40169e62014-06-17 15:23:47 -0700200 if acl.endswith('.xml'):
201 # Apply the passed in ACL xml file to the uploaded object.
202 gs_context.SetACL(remote_file, acl=acl)
203 else:
204 gs_context.ChangeACL(remote_file, acl_args_file=acl)
Scott Zawalskiab1bed32011-03-16 15:24:24 -0700205
Mike Frysingercc838832014-05-24 13:10:30 -0400206
Mike Frysinger540883b2014-05-24 13:46:16 -0400207def RemoteUpload(gs_context, acl, files, pool=10):
David James8c846492011-01-25 17:07:29 -0800208 """Upload to google storage.
209
210 Create a pool of process and call _GsUpload with the proper arguments.
211
212 Args:
Mike Frysinger540883b2014-05-24 13:46:16 -0400213 gs_context: A lib.gs.GSContext instance.
David Jamesfd0b0852011-02-23 11:15:36 -0800214 acl: The canned acl used for uploading. acl can be one of: "public-read",
215 "public-read-write", "authenticated-read", "bucket-owner-read",
216 "bucket-owner-full-control", or "private".
David James8c846492011-01-25 17:07:29 -0800217 files: dictionary with keys to local files and values to remote path.
218 pool: integer of maximum proesses to have at the same time.
219
220 Returns:
221 Return a set of tuple arguments of the failed uploads
222 """
Mike Frysinger540883b2014-05-24 13:46:16 -0400223 upload = functools.partial(_GsUpload, gs_context, acl)
224 tasks = [[key, value] for key, value in files.iteritems()]
225 parallel.RunTasksInProcessPool(upload, tasks, pool)
David James8c846492011-01-25 17:07:29 -0800226
227
228def GenerateUploadDict(base_local_path, base_remote_path, pkgs):
229 """Build a dictionary of local remote file key pairs to upload.
230
231 Args:
232 base_local_path: The base path to the files on the local hard drive.
Matt Tennante8179042013-10-01 15:47:32 -0700233 base_remote_path: The base path to the remote paths.
David James8c846492011-01-25 17:07:29 -0800234 pkgs: The packages to upload.
235
236 Returns:
237 Returns a dictionary of local_path/remote_path pairs
238 """
239 upload_files = {}
240 for pkg in pkgs:
241 suffix = pkg['CPV'] + '.tbz2'
242 local_path = os.path.join(base_local_path, suffix)
243 assert os.path.exists(local_path)
Bertrand SIMONNET811bcde2014-11-20 15:21:25 -0800244 upload_files[local_path] = os.path.join(base_remote_path, suffix)
David James8c846492011-01-25 17:07:29 -0800245
Bertrand SIMONNET811bcde2014-11-20 15:21:25 -0800246 if pkg.get('DEBUG_SYMBOLS') == 'yes':
247 debugsuffix = pkg['CPV'] + '.debug.tbz2'
248 local_path = os.path.join(base_local_path, debugsuffix)
249 assert os.path.exists(local_path)
250 upload_files[local_path] = os.path.join(base_remote_path, debugsuffix)
Bertrand SIMONNET22e828b2014-11-11 16:27:06 -0800251
David James8c846492011-01-25 17:07:29 -0800252 return upload_files
253
Mike Frysingercc838832014-05-24 13:10:30 -0400254
Peter Mayo950e41a2014-02-06 21:07:33 +0000255def GetBoardOverlay(build_path, target):
David Jamese5867812012-10-19 12:02:20 -0700256 """Get the path to the board variant.
Mike Frysinger1a736a82013-12-12 01:50:59 -0500257
David James8c846492011-01-25 17:07:29 -0800258 Args:
259 build_path: The path to the root of the build directory
David Jamese5867812012-10-19 12:02:20 -0700260 target: The target board as a BuildTarget object.
Mike Frysinger1a736a82013-12-12 01:50:59 -0500261
David James8c846492011-01-25 17:07:29 -0800262 Returns:
David Jamese5867812012-10-19 12:02:20 -0700263 The last overlay configured for the given board as a string.
David James8c846492011-01-25 17:07:29 -0800264 """
David Jamese5867812012-10-19 12:02:20 -0700265 board = target.board_variant
Alex Deymo075c2292014-09-04 18:31:50 -0700266 overlays = portage_util.FindOverlays(constants.BOTH_OVERLAYS, board,
267 buildroot=build_path)
David Jamese5867812012-10-19 12:02:20 -0700268 # We only care about the last entry.
269 return overlays[-1]
David James8c846492011-01-25 17:07:29 -0800270
271
272def DeterminePrebuiltConfFile(build_path, target):
273 """Determine the prebuilt.conf file that needs to be updated for prebuilts.
274
Mike Frysinger1a736a82013-12-12 01:50:59 -0500275 Args:
276 build_path: The path to the root of the build directory
277 target: String representation of the board. This includes host and board
278 targets
David James8c846492011-01-25 17:07:29 -0800279
Mike Frysinger1a736a82013-12-12 01:50:59 -0500280 Returns:
281 A string path to a prebuilt.conf file to be updated.
David James8c846492011-01-25 17:07:29 -0800282 """
David James4058b0d2011-12-08 21:24:50 -0800283 if _HOST_ARCH == target:
David James8c846492011-01-25 17:07:29 -0800284 # We are host.
285 # Without more examples of hosts this is a kludge for now.
286 # TODO(Scottz): as new host targets come online expand this to
287 # work more like boards.
Chris Sosa471532a2011-02-01 15:10:06 -0800288 make_path = _PREBUILT_MAKE_CONF[target]
David James8c846492011-01-25 17:07:29 -0800289 else:
290 # We are a board
Peter Mayo950e41a2014-02-06 21:07:33 +0000291 board = GetBoardOverlay(build_path, target)
David James8c846492011-01-25 17:07:29 -0800292 make_path = os.path.join(board, 'prebuilt.conf')
293
294 return make_path
295
296
297def UpdateBinhostConfFile(path, key, value):
298 """Update binhost config file file with key=value.
299
300 Args:
301 path: Filename to update.
302 key: Key to update.
303 value: New value for key.
304 """
David Jamesb26b9312014-12-15 11:26:46 -0800305 cwd, filename = os.path.split(os.path.abspath(path))
Brian Harringaf019fb2012-05-10 15:06:13 -0700306 osutils.SafeMakedirs(cwd)
David Jamesf6e8fb72013-05-10 08:58:43 -0700307 if not git.GetCurrentBranch(cwd):
308 git.CreatePushBranch(constants.STABLE_EBUILD_BRANCH, cwd, sync=False)
Brian Harring22edb442012-05-11 23:55:18 -0700309 osutils.WriteFile(path, '', mode='a')
David Jamesb26b9312014-12-15 11:26:46 -0800310 if UpdateLocalFile(path, value, key):
311 desc = '%s: %s %s' % (filename, 'updating' if value else 'clearing', key)
312 git.AddPath(path)
313 git.Commit(cwd, desc)
David James8c846492011-01-25 17:07:29 -0800314
Mike Frysinger212e4292014-05-24 15:15:44 -0400315def GenerateHtmlIndex(files, index, board, version):
316 """Given the list of |files|, generate an index.html at |index|.
317
318 Args:
319 files: The list of files to link to.
320 index: The path to the html index.
321 board: Name of the board this index is for.
322 version: Build version this index is for.
323 """
324 head = """<html>
325<head>
326 <title>Package Prebuilt Index: %(board)s / %(version)s</title>
327</head>
328<body>
329<h2>Package Prebuilt Index: %(board)s / %(version)s</h2>"""
330 head %= {
331 'board': board,
332 'version': version,
333 }
334
335 files = files + [
336 '.|Google Storage Index',
337 '..|',
338 ]
339 commands.GenerateHtmlIndex(index, files, head=head)
340
341
David Jamesce093af2011-02-23 15:21:58 -0800342def _GrabAllRemotePackageIndexes(binhost_urls):
David James05bcb2b2011-02-09 09:25:47 -0800343 """Grab all of the packages files associated with a list of binhost_urls.
344
David James05bcb2b2011-02-09 09:25:47 -0800345 Args:
346 binhost_urls: The URLs for the directories containing the Packages files we
347 want to grab.
David James05bcb2b2011-02-09 09:25:47 -0800348
349 Returns:
350 A list of PackageIndex objects.
351 """
352 pkg_indexes = []
353 for url in binhost_urls:
David James32faafe2012-06-08 14:25:03 -0700354 pkg_index = binpkg.GrabRemotePackageIndex(url)
David James05bcb2b2011-02-09 09:25:47 -0800355 if pkg_index:
356 pkg_indexes.append(pkg_index)
David James05bcb2b2011-02-09 09:25:47 -0800357 return pkg_indexes
358
359
David Jamesc0f158a2011-02-22 16:07:29 -0800360class PrebuiltUploader(object):
361 """Synchronize host and board prebuilts."""
David James8c846492011-01-25 17:07:29 -0800362
Mike Frysinger86509232014-05-24 13:18:37 -0400363 def __init__(self, upload_location, acl, binhost_base_url, pkg_indexes,
364 build_path, packages, skip_upload, binhost_conf_dir, dryrun,
Mike Frysinger8092a632014-05-24 13:25:46 -0400365 target, slave_targets, version):
David Jamesc0f158a2011-02-22 16:07:29 -0800366 """Constructor for prebuilt uploader object.
David James8c846492011-01-25 17:07:29 -0800367
David Jamesc0f158a2011-02-22 16:07:29 -0800368 This object can upload host or prebuilt files to Google Storage.
David James8c846492011-01-25 17:07:29 -0800369
David Jamesc0f158a2011-02-22 16:07:29 -0800370 Args:
371 upload_location: The upload location.
David Jamesfd0b0852011-02-23 11:15:36 -0800372 acl: The canned acl used for uploading to Google Storage. acl can be one
373 of: "public-read", "public-read-write", "authenticated-read",
Matt Tennante8179042013-10-01 15:47:32 -0700374 "bucket-owner-read", "bucket-owner-full-control", "project-private",
375 or "private" (see "gsutil help acls"). If we are not uploading to
376 Google Storage, this parameter is unused.
David Jamesfd0b0852011-02-23 11:15:36 -0800377 binhost_base_url: The URL used for downloading the prebuilts.
David Jamesc0f158a2011-02-22 16:07:29 -0800378 pkg_indexes: Old uploaded prebuilts to compare against. Instead of
379 uploading duplicate files, we just link to the old files.
David James615e5b52011-06-03 11:10:15 -0700380 build_path: The path to the directory containing the chroot.
381 packages: Packages to upload.
David James32b0b2f2011-07-13 20:56:50 -0700382 skip_upload: Don't actually upload the tarballs.
383 binhost_conf_dir: Directory where to store binhost.conf files.
Mike Frysinger86509232014-05-24 13:18:37 -0400384 dryrun: Don't push or upload prebuilts.
David James4058b0d2011-12-08 21:24:50 -0800385 target: BuildTarget managed by this builder.
386 slave_targets: List of BuildTargets managed by slave builders.
Mike Frysinger8092a632014-05-24 13:25:46 -0400387 version: A unique string, intended to be included in the upload path,
388 which identifies the version number of the uploaded prebuilts.
David Jamesc0f158a2011-02-22 16:07:29 -0800389 """
390 self._upload_location = upload_location
David Jamesfd0b0852011-02-23 11:15:36 -0800391 self._acl = acl
David Jamesc0f158a2011-02-22 16:07:29 -0800392 self._binhost_base_url = binhost_base_url
393 self._pkg_indexes = pkg_indexes
David James615e5b52011-06-03 11:10:15 -0700394 self._build_path = build_path
395 self._packages = set(packages)
Mike Frysingerf5f809a2013-02-12 13:47:37 -0500396 self._found_packages = set()
David James8ece7ee2011-06-29 16:02:30 -0700397 self._skip_upload = skip_upload
David James32b0b2f2011-07-13 20:56:50 -0700398 self._binhost_conf_dir = binhost_conf_dir
Mike Frysinger86509232014-05-24 13:18:37 -0400399 self._dryrun = dryrun
David James4058b0d2011-12-08 21:24:50 -0800400 self._target = target
401 self._slave_targets = slave_targets
Mike Frysinger8092a632014-05-24 13:25:46 -0400402 self._version = version
Mike Frysinger540883b2014-05-24 13:46:16 -0400403 self._gs_context = gs.GSContext(retries=_RETRIES, sleep=_SLEEP_TIME,
404 dry_run=self._dryrun)
405
406 def _Upload(self, local_file, remote_file):
407 """Wrapper around _GsUpload"""
408 _GsUpload(self._gs_context, self._acl, local_file, remote_file)
David James615e5b52011-06-03 11:10:15 -0700409
410 def _ShouldFilterPackage(self, pkg):
411 if not self._packages:
412 return False
413 pym_path = os.path.abspath(os.path.join(self._build_path, _PYM_PATH))
David James710b7dc2012-02-07 16:49:59 -0800414 sys.path.insert(0, pym_path)
Don Garrett25f309a2014-03-19 14:02:12 -0700415 # pylint: disable=F0401
David James615e5b52011-06-03 11:10:15 -0700416 import portage.versions
417 cat, pkgname = portage.versions.catpkgsplit(pkg['CPV'])[0:2]
418 cp = '%s/%s' % (cat, pkgname)
Mike Frysingerf5f809a2013-02-12 13:47:37 -0500419 self._found_packages.add(cp)
David James615e5b52011-06-03 11:10:15 -0700420 return pkgname not in self._packages and cp not in self._packages
David James8c846492011-01-25 17:07:29 -0800421
David Jamesc0f158a2011-02-22 16:07:29 -0800422 def _UploadPrebuilt(self, package_path, url_suffix):
423 """Upload host or board prebuilt files to Google Storage space.
David James8c846492011-01-25 17:07:29 -0800424
David Jamesc0f158a2011-02-22 16:07:29 -0800425 Args:
426 package_path: The path to the packages dir.
David Jamesce093af2011-02-23 15:21:58 -0800427 url_suffix: The remote subdirectory where we should upload the packages.
David Jamesc0f158a2011-02-22 16:07:29 -0800428 """
David Jamesc0f158a2011-02-22 16:07:29 -0800429 # Process Packages file, removing duplicates and filtered packages.
David James32faafe2012-06-08 14:25:03 -0700430 pkg_index = binpkg.GrabLocalPackageIndex(package_path)
David Jamesc0f158a2011-02-22 16:07:29 -0800431 pkg_index.SetUploadLocation(self._binhost_base_url, url_suffix)
David James615e5b52011-06-03 11:10:15 -0700432 pkg_index.RemoveFilteredPackages(self._ShouldFilterPackage)
David Jamesc0f158a2011-02-22 16:07:29 -0800433 uploads = pkg_index.ResolveDuplicateUploads(self._pkg_indexes)
Mike Frysingerf5f809a2013-02-12 13:47:37 -0500434 unmatched_pkgs = self._packages - self._found_packages
435 if unmatched_pkgs:
436 cros_build_lib.Warning('unable to match packages: %r' % unmatched_pkgs)
David James05bcb2b2011-02-09 09:25:47 -0800437
David Jamesc0f158a2011-02-22 16:07:29 -0800438 # Write Packages file.
David James5ab67e32014-10-24 08:19:59 -0700439 pkg_index.header['TTL'] = _BINPKG_TTL
David Jamesc0f158a2011-02-22 16:07:29 -0800440 tmp_packages_file = pkg_index.WriteToNamedTemporaryFile()
David James05bcb2b2011-02-09 09:25:47 -0800441
David Jamesc0f158a2011-02-22 16:07:29 -0800442 remote_location = '%s/%s' % (self._upload_location.rstrip('/'), url_suffix)
David James015af872012-06-19 15:24:36 -0700443 assert remote_location.startswith('gs://')
David James05bcb2b2011-02-09 09:25:47 -0800444
Alex Deymo541ea6f2014-12-23 01:18:14 -0800445 # Build list of files to upload. Manually include the dev-only files but
446 # skip them if not present.
447 # TODO(deymo): Upload dev-only-extras.tbz2 as dev-only-extras.tar.bz2
448 # outside packages/ directory. See crbug.com/448178 for details.
449 if os.path.exists(os.path.join(package_path, 'dev-only-extras.tbz2')):
450 uploads.append({'CPV': 'dev-only-extras'})
David James015af872012-06-19 15:24:36 -0700451 upload_files = GenerateUploadDict(package_path, remote_location, uploads)
452 remote_file = '%s/Packages' % remote_location.rstrip('/')
453 upload_files[tmp_packages_file.name] = remote_file
454
Mike Frysinger540883b2014-05-24 13:46:16 -0400455 RemoteUpload(self._gs_context, self._acl, upload_files)
David James8c846492011-01-25 17:07:29 -0800456
Mike Frysinger212e4292014-05-24 15:15:44 -0400457 with tempfile.NamedTemporaryFile(
458 prefix='chromite.upload_prebuilts.index.') as index:
459 GenerateHtmlIndex(
460 [x[len(remote_location) + 1:] for x in upload_files.values()],
461 index.name, self._target, self._version)
462 self._Upload(index.name, '%s/index.html' % remote_location.rstrip('/'))
463
464 link_name = 'Prebuilts[%s]: %s' % (self._target, self._version)
465 url = '%s%s/index.html' % (gs.PUBLIC_BASE_HTTPS_URL,
466 remote_location[len(gs.BASE_GS_URL):])
467 cros_build_lib.PrintBuildbotLink(link_name, url)
468
Mike Frysinger8092a632014-05-24 13:25:46 -0400469 def _UploadSdkTarball(self, board_path, url_suffix, prepackaged,
Mike Frysinger9e979b92012-11-29 02:55:09 -0500470 toolchain_tarballs, toolchain_upload_path):
471 """Upload a tarball of the sdk at the specified path to Google Storage.
David James8fa34ea2011-04-15 13:00:20 -0700472
473 Args:
474 board_path: The path to the board dir.
475 url_suffix: The remote subdirectory where we should upload the packages.
Zdenek Behan62a57792012-08-31 15:09:08 +0200476 prepackaged: If given, a tarball that has been packaged outside of this
477 script and should be used.
Mike Frysinger9e979b92012-11-29 02:55:09 -0500478 toolchain_tarballs: List of toolchain tarballs to upload.
479 toolchain_upload_path: Path under the bucket to place toolchain tarballs.
David James8fa34ea2011-04-15 13:00:20 -0700480 """
481 remote_location = '%s/%s' % (self._upload_location.rstrip('/'), url_suffix)
482 assert remote_location.startswith('gs://')
Zdenek Behan86c15e92012-10-13 00:55:47 +0200483 boardname = os.path.basename(board_path.rstrip('/'))
484 # We do not upload non SDK board tarballs,
485 assert boardname == constants.CHROOT_BUILDER_BOARD
486 assert prepackaged is not None
Zdenek Behan62a57792012-08-31 15:09:08 +0200487
Mike Frysinger8092a632014-05-24 13:25:46 -0400488 version_str = self._version[len('chroot-'):]
Mike Frysinger8e727a32013-01-16 16:57:53 -0500489 remote_tarfile = toolchain.GetSdkURL(
490 for_gsutil=True, suburl='cros-sdk-%s.tar.xz' % (version_str,))
Zdenek Behan86c15e92012-10-13 00:55:47 +0200491 # For SDK, also upload the manifest which is guaranteed to exist
492 # by the builderstage.
Mike Frysinger540883b2014-05-24 13:46:16 -0400493 self._Upload(prepackaged + '.Manifest', remote_tarfile + '.Manifest')
494 self._Upload(prepackaged, remote_tarfile)
Zdenek Behan86c15e92012-10-13 00:55:47 +0200495
Mike Frysinger9e979b92012-11-29 02:55:09 -0500496 # Post the toolchain tarballs too.
497 for tarball in toolchain_tarballs:
498 target, local_path = tarball.split(':')
499 suburl = toolchain_upload_path % {'target': target}
500 remote_path = toolchain.GetSdkURL(for_gsutil=True, suburl=suburl)
Mike Frysinger540883b2014-05-24 13:46:16 -0400501 self._Upload(local_path, remote_path)
Mike Frysinger9e979b92012-11-29 02:55:09 -0500502
Zdenek Behan86c15e92012-10-13 00:55:47 +0200503 # Finally, also update the pointer to the latest SDK on which polling
504 # scripts rely.
David James4bc13702013-03-26 08:08:04 -0700505 with osutils.TempDir() as tmpdir:
Zdenek Behan86c15e92012-10-13 00:55:47 +0200506 pointerfile = os.path.join(tmpdir, 'cros-sdk-latest.conf')
Mike Frysinger8e727a32013-01-16 16:57:53 -0500507 remote_pointerfile = toolchain.GetSdkURL(for_gsutil=True,
508 suburl='cros-sdk-latest.conf')
Zdenek Behan86c15e92012-10-13 00:55:47 +0200509 osutils.WriteFile(pointerfile, 'LATEST_SDK="%s"' % version_str)
Mike Frysinger540883b2014-05-24 13:46:16 -0400510 self._Upload(pointerfile, remote_pointerfile)
Zdenek Behan33a34112012-09-10 21:07:51 +0200511
Chris Sosa6a5dceb2012-05-14 13:48:56 -0700512 def _GetTargets(self):
513 """Retuns the list of targets to use."""
514 targets = self._slave_targets[:]
515 if self._target:
516 targets.append(self._target)
517
518 return targets
519
Mike Frysinger8092a632014-05-24 13:25:46 -0400520 def SyncHostPrebuilts(self, key, git_sync, sync_binhost_conf):
David Jamesc0f158a2011-02-22 16:07:29 -0800521 """Synchronize host prebuilt files.
David James05bcb2b2011-02-09 09:25:47 -0800522
David Jamesc0f158a2011-02-22 16:07:29 -0800523 This function will sync both the standard host packages, plus the host
524 packages associated with all targets that have been "setup" with the
525 current host's chroot. For instance, if this host has been used to build
526 x86-generic, it will sync the host packages associated with
527 'i686-pc-linux-gnu'. If this host has also been used to build arm-generic,
528 it will also sync the host packages associated with
529 'armv7a-cros-linux-gnueabi'.
David James05bcb2b2011-02-09 09:25:47 -0800530
David Jamesc0f158a2011-02-22 16:07:29 -0800531 Args:
David Jamesc0f158a2011-02-22 16:07:29 -0800532 key: The variable key to update in the git file.
533 git_sync: If set, update make.conf of target to reference the latest
534 prebuilt packages generated here.
535 sync_binhost_conf: If set, update binhost config file in
536 chromiumos-overlay for the host.
537 """
David Jamese2488642011-11-14 16:15:20 -0800538 # Slave boards are listed before the master board so that the master board
539 # takes priority (i.e. x86-generic preflight host prebuilts takes priority
540 # over preflight host prebuilts from other builders.)
541 binhost_urls = []
Chris Sosa6a5dceb2012-05-14 13:48:56 -0700542 for target in self._GetTargets():
Mike Frysinger8092a632014-05-24 13:25:46 -0400543 url_suffix = _REL_HOST_PATH % {'version': self._version,
David James4058b0d2011-12-08 21:24:50 -0800544 'host_arch': _HOST_ARCH,
545 'target': target}
David Jamese2488642011-11-14 16:15:20 -0800546 packages_url_suffix = '%s/packages' % url_suffix.rstrip('/')
David James05bcb2b2011-02-09 09:25:47 -0800547
Mike Frysinger540883b2014-05-24 13:46:16 -0400548 if self._target == target and not self._skip_upload:
David Jamese2488642011-11-14 16:15:20 -0800549 # Upload prebuilts.
550 package_path = os.path.join(self._build_path, _HOST_PACKAGES_PATH)
551 self._UploadPrebuilt(package_path, packages_url_suffix)
David James8ece7ee2011-06-29 16:02:30 -0700552
David Jamese2488642011-11-14 16:15:20 -0800553 # Record URL where prebuilts were uploaded.
554 binhost_urls.append('%s/%s/' % (self._binhost_base_url.rstrip('/'),
555 packages_url_suffix.rstrip('/')))
556
David James20b2b6f2011-11-18 15:11:58 -0800557 binhost = ' '.join(binhost_urls)
David James8ece7ee2011-06-29 16:02:30 -0700558 if git_sync:
David Jamesb26b9312014-12-15 11:26:46 -0800559 git_file = os.path.join(self._build_path, _PREBUILT_MAKE_CONF[_HOST_ARCH])
Mike Frysinger86509232014-05-24 13:18:37 -0400560 RevGitFile(git_file, {key: binhost}, dryrun=self._dryrun)
David James8ece7ee2011-06-29 16:02:30 -0700561 if sync_binhost_conf:
David Jamesb26b9312014-12-15 11:26:46 -0800562 binhost_conf = os.path.join(
563 self._binhost_conf_dir, 'host', '%s-%s.conf' % (_HOST_ARCH, key))
David Jamese2488642011-11-14 16:15:20 -0800564 UpdateBinhostConfFile(binhost_conf, key, binhost)
David Jamesc0f158a2011-02-22 16:07:29 -0800565
Mike Frysinger8092a632014-05-24 13:25:46 -0400566 def SyncBoardPrebuilts(self, key, git_sync, sync_binhost_conf,
Mike Frysinger9e979b92012-11-29 02:55:09 -0500567 upload_board_tarball, prepackaged_board,
568 toolchain_tarballs, toolchain_upload_path):
David Jamesc0f158a2011-02-22 16:07:29 -0800569 """Synchronize board prebuilt files.
570
571 Args:
David Jamesc0f158a2011-02-22 16:07:29 -0800572 key: The variable key to update in the git file.
573 git_sync: If set, update make.conf of target to reference the latest
574 prebuilt packages generated here.
575 sync_binhost_conf: If set, update binhost config file in
576 chromiumos-overlay for the current board.
David James8fa34ea2011-04-15 13:00:20 -0700577 upload_board_tarball: Include a tarball of the board in our upload.
Zdenek Behan62a57792012-08-31 15:09:08 +0200578 prepackaged_board: A tarball of the board built outside of this script.
Mike Frysinger9e979b92012-11-29 02:55:09 -0500579 toolchain_tarballs: A list of toolchain tarballs to upload.
580 toolchain_upload_path: Path under the bucket to place toolchain tarballs.
David Jamesc0f158a2011-02-22 16:07:29 -0800581 """
David Jamesb26b9312014-12-15 11:26:46 -0800582 updated_binhosts = set()
Chris Sosa6a5dceb2012-05-14 13:48:56 -0700583 for target in self._GetTargets():
David Jamese2488642011-11-14 16:15:20 -0800584 board_path = os.path.join(self._build_path,
David James4058b0d2011-12-08 21:24:50 -0800585 _BOARD_PATH % {'board': target.board_variant})
David Jamese2488642011-11-14 16:15:20 -0800586 package_path = os.path.join(board_path, 'packages')
Mike Frysinger8092a632014-05-24 13:25:46 -0400587 url_suffix = _REL_BOARD_PATH % {'target': target,
588 'version': self._version}
David Jamese2488642011-11-14 16:15:20 -0800589 packages_url_suffix = '%s/packages' % url_suffix.rstrip('/')
David James8fa34ea2011-04-15 13:00:20 -0700590
Matt Tennante8179042013-10-01 15:47:32 -0700591 # Process the target board differently if it is the main --board.
Mike Frysinger540883b2014-05-24 13:46:16 -0400592 if self._target == target and not self._skip_upload:
Matt Tennante8179042013-10-01 15:47:32 -0700593 # This strips "chroot" prefix because that is sometimes added as the
594 # --prepend-version argument (e.g. by chromiumos-sdk bot).
595 # TODO(build): Clean it up to be less hard-coded.
Mike Frysinger8092a632014-05-24 13:25:46 -0400596 version_str = self._version[len('chroot-'):]
Mike Frysinger9e979b92012-11-29 02:55:09 -0500597
David Jamese2488642011-11-14 16:15:20 -0800598 # Upload board tarballs in the background.
599 if upload_board_tarball:
Mike Frysinger9e979b92012-11-29 02:55:09 -0500600 if toolchain_upload_path:
601 toolchain_upload_path %= {'version': version_str}
602 tar_process = multiprocessing.Process(
603 target=self._UploadSdkTarball,
Mike Frysinger8092a632014-05-24 13:25:46 -0400604 args=(board_path, url_suffix, prepackaged_board,
Mike Frysinger9e979b92012-11-29 02:55:09 -0500605 toolchain_tarballs, toolchain_upload_path))
David Jamese2488642011-11-14 16:15:20 -0800606 tar_process.start()
David James8fa34ea2011-04-15 13:00:20 -0700607
David Jamese2488642011-11-14 16:15:20 -0800608 # Upload prebuilts.
609 self._UploadPrebuilt(package_path, packages_url_suffix)
David James8fa34ea2011-04-15 13:00:20 -0700610
David Jamese2488642011-11-14 16:15:20 -0800611 # Make sure we finished uploading the board tarballs.
612 if upload_board_tarball:
613 tar_process.join()
614 assert tar_process.exitcode == 0
615 # TODO(zbehan): This should be done cleaner.
Zdenek Behan33a34112012-09-10 21:07:51 +0200616 if target.board == constants.CHROOT_BUILDER_BOARD:
David Jamesb26b9312014-12-15 11:26:46 -0800617 sdk_conf = os.path.join(self._binhost_conf_dir,
Mike Frysinger5b34d732013-01-17 15:11:58 -0500618 'host/sdk_version.conf')
619 sdk_settings = {
Mike Frysinger9e979b92012-11-29 02:55:09 -0500620 'SDK_LATEST_VERSION': version_str,
621 'TC_PATH': toolchain_upload_path,
Mike Frysinger5b34d732013-01-17 15:11:58 -0500622 }
Mike Frysinger86509232014-05-24 13:18:37 -0400623 RevGitFile(sdk_conf, sdk_settings, dryrun=self._dryrun)
David Jamesc0f158a2011-02-22 16:07:29 -0800624
David Jamese2488642011-11-14 16:15:20 -0800625 # Record URL where prebuilts were uploaded.
626 url_value = '%s/%s/' % (self._binhost_base_url.rstrip('/'),
627 packages_url_suffix.rstrip('/'))
628
629 if git_sync:
David James4058b0d2011-12-08 21:24:50 -0800630 git_file = DeterminePrebuiltConfFile(self._build_path, target)
Mike Frysinger86509232014-05-24 13:18:37 -0400631 RevGitFile(git_file, {key: url_value}, dryrun=self._dryrun)
Matt Tennante8179042013-10-01 15:47:32 -0700632
David Jamese2488642011-11-14 16:15:20 -0800633 if sync_binhost_conf:
Matt Tennante8179042013-10-01 15:47:32 -0700634 # Update the binhost configuration file in git.
David Jamesb26b9312014-12-15 11:26:46 -0800635 binhost_conf = os.path.join(
636 self._binhost_conf_dir, 'target', '%s-%s.conf' % (target, key))
637 updated_binhosts.add(binhost_conf)
David Jamese2488642011-11-14 16:15:20 -0800638 UpdateBinhostConfFile(binhost_conf, key, url_value)
David James05bcb2b2011-02-09 09:25:47 -0800639
David Jamesb26b9312014-12-15 11:26:46 -0800640 if sync_binhost_conf:
641 # Clear all old binhosts. The files must be left empty in case anybody
642 # is referring to them.
643 all_binhosts = set(glob.glob(os.path.join(
644 self._binhost_conf_dir, 'target', '*-%s.conf' % key)))
645 for binhost_conf in all_binhosts - updated_binhosts:
646 UpdateBinhostConfFile(binhost_conf, key, '')
647
David James05bcb2b2011-02-09 09:25:47 -0800648
Chris Sosa6a5dceb2012-05-14 13:48:56 -0700649def _AddSlaveBoard(_option, _opt_str, value, parser):
650 """Callback that adds a slave board to the list of slave targets."""
David James4058b0d2011-12-08 21:24:50 -0800651 parser.values.slave_targets.append(BuildTarget(value))
652
653
Chris Sosa6a5dceb2012-05-14 13:48:56 -0700654def _AddSlaveProfile(_option, _opt_str, value, parser):
655 """Callback that adds a slave profile to the list of slave targets."""
David James4058b0d2011-12-08 21:24:50 -0800656 if not parser.values.slave_targets:
Mike Frysinger86509232014-05-24 13:18:37 -0400657 parser.error('Must specify --slave-board before --slave-profile')
David James4058b0d2011-12-08 21:24:50 -0800658 if parser.values.slave_targets[-1].profile is not None:
Mike Frysinger86509232014-05-24 13:18:37 -0400659 parser.error('Cannot specify --slave-profile twice for same board')
David James4058b0d2011-12-08 21:24:50 -0800660 parser.values.slave_targets[-1].profile = value
661
662
Mike Frysinger86509232014-05-24 13:18:37 -0400663def ParseOptions(argv):
Chris Sosa6a5dceb2012-05-14 13:48:56 -0700664 """Returns options given by the user and the target specified.
665
Mike Frysinger86509232014-05-24 13:18:37 -0400666 Args:
667 argv: The args to parse.
668
Mike Frysinger1a736a82013-12-12 01:50:59 -0500669 Returns:
670 A tuple containing a parsed options object and BuildTarget.
671 The target instance is None if no board is specified.
Chris Sosa6a5dceb2012-05-14 13:48:56 -0700672 """
Mike Frysinger86509232014-05-24 13:18:37 -0400673 parser = commandline.OptionParser()
David James8c846492011-01-25 17:07:29 -0800674 parser.add_option('-H', '--binhost-base-url', dest='binhost_base_url',
675 default=_BINHOST_BASE_URL,
676 help='Base URL to use for binhost in make.conf updates')
677 parser.add_option('', '--previous-binhost-url', action='append',
678 default=[], dest='previous_binhost_url',
679 help='Previous binhost URL')
680 parser.add_option('-b', '--board', dest='board', default=None,
681 help='Board type that was built on this machine')
Zdenek Behan62a57792012-08-31 15:09:08 +0200682 parser.add_option('-B', '--prepackaged-tarball', dest='prepackaged_tarball',
683 default=None,
684 help='Board tarball prebuilt outside of this script.')
Mike Frysinger9e979b92012-11-29 02:55:09 -0500685 parser.add_option('--toolchain-tarball', dest='toolchain_tarballs',
686 action='append', default=[],
687 help='Redistributable toolchain tarball.')
688 parser.add_option('--toolchain-upload-path', default='',
689 help='Path to place toolchain tarballs in the sdk tree.')
David James4058b0d2011-12-08 21:24:50 -0800690 parser.add_option('', '--profile', dest='profile', default=None,
691 help='Profile that was built on this machine')
692 parser.add_option('', '--slave-board', default=[], action='callback',
693 dest='slave_targets', type='string',
Chris Sosa6a5dceb2012-05-14 13:48:56 -0700694 callback=_AddSlaveBoard,
David James4058b0d2011-12-08 21:24:50 -0800695 help='Board type that was built on a slave machine. To '
696 'add a profile to this board, use --slave-profile.')
697 parser.add_option('', '--slave-profile', action='callback', type='string',
Chris Sosa6a5dceb2012-05-14 13:48:56 -0700698 callback=_AddSlaveProfile,
David James4058b0d2011-12-08 21:24:50 -0800699 help='Board profile that was built on a slave machine. '
700 'Applies to previous slave board.')
David James8c846492011-01-25 17:07:29 -0800701 parser.add_option('-p', '--build-path', dest='build_path',
David James05bcb2b2011-02-09 09:25:47 -0800702 help='Path to the directory containing the chroot')
David James615e5b52011-06-03 11:10:15 -0700703 parser.add_option('', '--packages', action='append',
704 default=[], dest='packages',
705 help='Only include the specified packages. '
706 '(Default is to include all packages.)')
David James8c846492011-01-25 17:07:29 -0800707 parser.add_option('-s', '--sync-host', dest='sync_host',
708 default=False, action='store_true',
709 help='Sync host prebuilts')
710 parser.add_option('-g', '--git-sync', dest='git_sync',
711 default=False, action='store_true',
David Jamese2488642011-11-14 16:15:20 -0800712 help='Enable git version sync (This commits to a repo.) '
713 'This is used by full builders to commit directly '
714 'to board overlays.')
David James8c846492011-01-25 17:07:29 -0800715 parser.add_option('-u', '--upload', dest='upload',
716 default=None,
717 help='Upload location')
718 parser.add_option('-V', '--prepend-version', dest='prepend_version',
719 default=None,
720 help='Add an identifier to the front of the version')
721 parser.add_option('-f', '--filters', dest='filters', action='store_true',
722 default=False,
723 help='Turn on filtering of private ebuild packages')
724 parser.add_option('-k', '--key', dest='key',
725 default='PORTAGE_BINHOST',
726 help='Key to update in make.conf / binhost.conf')
David James8ece7ee2011-06-29 16:02:30 -0700727 parser.add_option('', '--set-version', dest='set_version',
728 default=None,
729 help='Specify the version string')
David James8c846492011-01-25 17:07:29 -0800730 parser.add_option('', '--sync-binhost-conf', dest='sync_binhost_conf',
731 default=False, action='store_true',
David Jamese2488642011-11-14 16:15:20 -0800732 help='Update binhost.conf in chromiumos-overlay or '
733 'chromeos-overlay. Commit the changes, but don\'t '
734 'push them. This is used for preflight binhosts.')
David James32b0b2f2011-07-13 20:56:50 -0700735 parser.add_option('', '--binhost-conf-dir', dest='binhost_conf_dir',
David James32b0b2f2011-07-13 20:56:50 -0700736 help='Directory to commit binhost config with '
737 '--sync-binhost-conf.')
David Jamesfd0b0852011-02-23 11:15:36 -0800738 parser.add_option('-P', '--private', dest='private', action='store_true',
739 default=False, help='Mark gs:// uploads as private.')
David James8ece7ee2011-06-29 16:02:30 -0700740 parser.add_option('', '--skip-upload', dest='skip_upload',
741 action='store_true', default=False,
742 help='Skip upload step.')
David James8fa34ea2011-04-15 13:00:20 -0700743 parser.add_option('', '--upload-board-tarball', dest='upload_board_tarball',
744 action='store_true', default=False,
745 help='Upload board tarball to Google Storage.')
Mike Frysinger86509232014-05-24 13:18:37 -0400746 parser.add_option('-n', '--dry-run', dest='dryrun',
David James27fa7d12011-06-29 17:24:14 -0700747 action='store_true', default=False,
748 help='Don\'t push or upload prebuilts.')
David James8c846492011-01-25 17:07:29 -0800749
Mike Frysinger86509232014-05-24 13:18:37 -0400750 options, args = parser.parse_args(argv)
David James8c846492011-01-25 17:07:29 -0800751 if not options.build_path:
Mike Frysinger86509232014-05-24 13:18:37 -0400752 parser.error('you need provide a chroot path')
David James8ece7ee2011-06-29 16:02:30 -0700753 if not options.upload and not options.skip_upload:
Mike Frysinger86509232014-05-24 13:18:37 -0400754 parser.error('you need to provide an upload location using -u')
David James8ece7ee2011-06-29 16:02:30 -0700755 if not options.set_version and options.skip_upload:
Mike Frysinger86509232014-05-24 13:18:37 -0400756 parser.error('If you are using --skip-upload, you must specify a '
757 'version number using --set-version.')
David James9417f272011-05-26 13:24:47 -0700758 if args:
Mike Frysinger86509232014-05-24 13:18:37 -0400759 parser.error('invalid arguments passed to upload_prebuilts: %r' % args)
Scott Zawalskiab1bed32011-03-16 15:24:24 -0700760
Chris Sosa6a5dceb2012-05-14 13:48:56 -0700761 target = None
762 if options.board:
763 target = BuildTarget(options.board, options.profile)
764
765 if target in options.slave_targets:
Mike Frysinger86509232014-05-24 13:18:37 -0400766 parser.error('--board/--profile must not also be a slave target.')
David Jamese2488642011-11-14 16:15:20 -0800767
David James4058b0d2011-12-08 21:24:50 -0800768 if len(set(options.slave_targets)) != len(options.slave_targets):
Mike Frysinger86509232014-05-24 13:18:37 -0400769 parser.error('--slave-boards must not have duplicates.')
David Jamese2488642011-11-14 16:15:20 -0800770
David James4058b0d2011-12-08 21:24:50 -0800771 if options.slave_targets and options.git_sync:
Mike Frysinger86509232014-05-24 13:18:37 -0400772 parser.error('--slave-boards is not compatible with --git-sync')
David Jamese2488642011-11-14 16:15:20 -0800773
David James8ece7ee2011-06-29 16:02:30 -0700774 if (options.upload_board_tarball and options.skip_upload and
775 options.board == 'amd64-host'):
Mike Frysinger86509232014-05-24 13:18:37 -0400776 parser.error('--skip-upload is not compatible with '
777 '--upload-board-tarball and --board=amd64-host')
David James8fa34ea2011-04-15 13:00:20 -0700778
David James8ece7ee2011-06-29 16:02:30 -0700779 if (options.upload_board_tarball and not options.skip_upload and
780 not options.upload.startswith('gs://')):
Mike Frysinger86509232014-05-24 13:18:37 -0400781 parser.error('--upload-board-tarball only works with gs:// URLs.\n'
782 '--upload must be a gs:// URL.')
David James8fa34ea2011-04-15 13:00:20 -0700783
Zdenek Behan86c15e92012-10-13 00:55:47 +0200784 if options.upload_board_tarball and options.prepackaged_tarball is None:
Mike Frysinger86509232014-05-24 13:18:37 -0400785 parser.error('--upload-board-tarball requires --prepackaged-tarball')
Zdenek Behan86c15e92012-10-13 00:55:47 +0200786
Scott Zawalskiab1bed32011-03-16 15:24:24 -0700787 if options.private:
788 if options.sync_host:
Mike Frysinger86509232014-05-24 13:18:37 -0400789 parser.error('--private and --sync-host/-s cannot be specified '
790 'together; we do not support private host prebuilts')
Scott Zawalskiab1bed32011-03-16 15:24:24 -0700791
David James8ece7ee2011-06-29 16:02:30 -0700792 if not options.upload or not options.upload.startswith('gs://'):
Mike Frysinger86509232014-05-24 13:18:37 -0400793 parser.error('--private is only valid for gs:// URLs; '
794 '--upload must be a gs:// URL.')
Scott Zawalskiab1bed32011-03-16 15:24:24 -0700795
796 if options.binhost_base_url != _BINHOST_BASE_URL:
Mike Frysinger86509232014-05-24 13:18:37 -0400797 parser.error('when using --private the --binhost-base-url '
798 'is automatically derived.')
David James27fa7d12011-06-29 17:24:14 -0700799
David Jamesc31168e2014-06-05 14:40:05 -0700800 if options.sync_binhost_conf and not options.binhost_conf_dir:
801 parser.error('--sync-binhost-conf requires --binhost-conf-dir')
802
Chris Sosa6a5dceb2012-05-14 13:48:56 -0700803 return options, target
David Jamesc0f158a2011-02-22 16:07:29 -0800804
Mike Frysingercc838832014-05-24 13:10:30 -0400805
Mike Frysinger86509232014-05-24 13:18:37 -0400806def main(argv):
David Jamesdb401072011-06-10 12:17:16 -0700807 # Set umask to a sane value so that files created as root are readable.
Mike Frysinger60ec1012013-10-21 00:11:10 -0400808 os.umask(0o22)
David Jamesdb401072011-06-10 12:17:16 -0700809
Mike Frysinger86509232014-05-24 13:18:37 -0400810 options, target = ParseOptions(argv)
David Jamesc0f158a2011-02-22 16:07:29 -0800811
David James05bcb2b2011-02-09 09:25:47 -0800812 # Calculate a list of Packages index files to compare against. Whenever we
813 # upload a package, we check to make sure it's not already stored in one of
814 # the packages files we uploaded. This list of packages files might contain
815 # both board and host packages.
David Jamesce093af2011-02-23 15:21:58 -0800816 pkg_indexes = _GrabAllRemotePackageIndexes(options.previous_binhost_url)
David James8c846492011-01-25 17:07:29 -0800817
David James8ece7ee2011-06-29 16:02:30 -0700818 if options.set_version:
819 version = options.set_version
820 else:
821 version = GetVersion()
Matt Tennante8179042013-10-01 15:47:32 -0700822
David Jamesc0f158a2011-02-22 16:07:29 -0800823 if options.prepend_version:
824 version = '%s-%s' % (options.prepend_version, version)
825
Scott Zawalskiab1bed32011-03-16 15:24:24 -0700826 acl = 'public-read'
827 binhost_base_url = options.binhost_base_url
828
David Jamesadd21432013-05-21 10:04:07 -0700829 if options.private:
Scott Zawalskiab1bed32011-03-16 15:24:24 -0700830 binhost_base_url = options.upload
David Jamesadd21432013-05-21 10:04:07 -0700831 if target:
Prathmesh Prabhu421eef22014-10-16 17:13:19 -0700832 acl = portage_util.FindOverlayFile(_GOOGLESTORAGE_GSUTIL_FILE,
833 board=target.board_variant,
834 buildroot=options.build_path)
Ben Chan067de492015-01-06 17:19:13 -0800835 if acl is None:
836 cros_build_lib.Die('No Google Storage ACL file %s found in %s overlay.',
837 _GOOGLESTORAGE_GSUTIL_FILE, target.board_variant)
Scott Zawalskiab1bed32011-03-16 15:24:24 -0700838
David Jamesb26b9312014-12-15 11:26:46 -0800839 binhost_conf_dir = None
840 if options.binhost_conf_dir:
841 binhost_conf_dir = os.path.join(options.build_path,
842 options.binhost_conf_dir)
843
Scott Zawalskiab1bed32011-03-16 15:24:24 -0700844 uploader = PrebuiltUploader(options.upload, acl, binhost_base_url,
David James615e5b52011-06-03 11:10:15 -0700845 pkg_indexes, options.build_path,
David James27fa7d12011-06-29 17:24:14 -0700846 options.packages, options.skip_upload,
David Jamesb26b9312014-12-15 11:26:46 -0800847 binhost_conf_dir, options.dryrun,
Mike Frysinger8092a632014-05-24 13:25:46 -0400848 target, options.slave_targets, version)
David Jamesc0f158a2011-02-22 16:07:29 -0800849
David James8c846492011-01-25 17:07:29 -0800850 if options.sync_host:
Mike Frysinger8092a632014-05-24 13:25:46 -0400851 uploader.SyncHostPrebuilts(options.key, options.git_sync,
Chris Sosa6a5dceb2012-05-14 13:48:56 -0700852 options.sync_binhost_conf)
David James8c846492011-01-25 17:07:29 -0800853
Chris Sosa62c8ff52012-06-04 15:03:12 -0700854 if options.board or options.slave_targets:
Mike Frysinger8092a632014-05-24 13:25:46 -0400855 uploader.SyncBoardPrebuilts(options.key, options.git_sync,
Chris Sosa6a5dceb2012-05-14 13:48:56 -0700856 options.sync_binhost_conf,
Zdenek Behan62a57792012-08-31 15:09:08 +0200857 options.upload_board_tarball,
Mike Frysinger9e979b92012-11-29 02:55:09 -0500858 options.prepackaged_tarball,
859 options.toolchain_tarballs,
860 options.toolchain_upload_path)