blob: 151cab7efe99394d00271408b65ca6c6049e8d40 [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
Ralph Nathan446aee92015-03-23 14:44:56 -070035from chromite.lib import cros_logging as logging
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
Alex Deymo075c2292014-09-04 18:31:50 -070040from chromite.lib import portage_util
Mike Frysinger8e727a32013-01-16 16:57:53 -050041from chromite.lib import toolchain
Chris Sosa1dc96132012-05-11 15:40:50 -070042
David James015af872012-06-19 15:24:36 -070043# How many times to retry uploads.
44_RETRIES = 10
45
46# Multiplier for how long to sleep (in seconds) between retries; will delay
47# (1*sleep) the first time, then (2*sleep), continuing via attempt * sleep.
48_SLEEP_TIME = 60
49
David James5ab67e32014-10-24 08:19:59 -070050# The length of time (in seconds) that Portage should wait before refetching
51# binpkgs from the same binhost. We don't ever modify binhosts, so this should
52# be something big.
53_BINPKG_TTL = 60 * 60 * 24 * 365
54
David James8c846492011-01-25 17:07:29 -080055_HOST_PACKAGES_PATH = 'chroot/var/lib/portage/pkgs'
David James05bcb2b2011-02-09 09:25:47 -080056_CATEGORIES_PATH = 'chroot/etc/portage/categories'
David James615e5b52011-06-03 11:10:15 -070057_PYM_PATH = 'chroot/usr/lib/portage/pym'
David James4058b0d2011-12-08 21:24:50 -080058_HOST_ARCH = 'amd64'
David James8c846492011-01-25 17:07:29 -080059_BOARD_PATH = 'chroot/build/%(board)s'
David James4058b0d2011-12-08 21:24:50 -080060_REL_BOARD_PATH = 'board/%(target)s/%(version)s'
61_REL_HOST_PATH = 'host/%(host_arch)s/%(target)s/%(version)s'
David James8c846492011-01-25 17:07:29 -080062# Private overlays to look at for builds to filter
63# relative to build path
64_PRIVATE_OVERLAY_DIR = 'src/private-overlays'
Gabe Black40169e62014-06-17 15:23:47 -070065_GOOGLESTORAGE_GSUTIL_FILE = 'googlestorage_acl.txt'
David James3753d942014-04-23 10:55:48 -070066_BINHOST_BASE_URL = 'gs://chromeos-prebuilt'
David James8c846492011-01-25 17:07:29 -080067_PREBUILT_BASE_DIR = 'src/third_party/chromiumos-overlay/chromeos/config/'
68# Created in the event of new host targets becoming available
69_PREBUILT_MAKE_CONF = {'amd64': os.path.join(_PREBUILT_BASE_DIR,
70 'make.conf.amd64-host')}
David James8c846492011-01-25 17:07:29 -080071
72
David James4058b0d2011-12-08 21:24:50 -080073class BuildTarget(object):
74 """A board/variant/profile tuple."""
75
76 def __init__(self, board_variant, profile=None):
77 self.board_variant = board_variant
78 self.board, _, self.variant = board_variant.partition('_')
79 self.profile = profile
80
81 def __str__(self):
82 if self.profile:
83 return '%s_%s' % (self.board_variant, self.profile)
84 else:
85 return self.board_variant
86
87 def __eq__(self, other):
88 return str(other) == str(self)
89
90 def __hash__(self):
91 return hash(str(self))
92
93
David James8c846492011-01-25 17:07:29 -080094def UpdateLocalFile(filename, value, key='PORTAGE_BINHOST'):
95 """Update the key in file with the value passed.
Mike Frysinger1a736a82013-12-12 01:50:59 -050096
David James8c846492011-01-25 17:07:29 -080097 File format:
98 key="value"
99 Note quotes are added automatically
100
101 Args:
102 filename: Name of file to modify.
103 value: Value to write with the key.
104 key: The variable key to update. (Default: PORTAGE_BINHOST)
David Jamesb26b9312014-12-15 11:26:46 -0800105
106 Returns:
107 True if changes were made to the file.
David James8c846492011-01-25 17:07:29 -0800108 """
109 if os.path.exists(filename):
110 file_fh = open(filename)
111 else:
112 file_fh = open(filename, 'w+')
113 file_lines = []
114 found = False
David Jamesb26b9312014-12-15 11:26:46 -0800115 made_changes = False
David James8c846492011-01-25 17:07:29 -0800116 keyval_str = '%(key)s=%(value)s'
117 for line in file_fh:
118 # Strip newlines from end of line. We already add newlines below.
119 line = line.rstrip("\n")
120
121 if len(line.split('=')) != 2:
122 # Skip any line that doesn't fit key=val.
123 file_lines.append(line)
124 continue
125
126 file_var, file_val = line.split('=')
127 if file_var == key:
128 found = True
Mike Frysingerff441bf2014-05-24 13:47:21 -0400129 print('Updating %s=%s to %s="%s"' % (file_var, file_val, key, value))
David James8c846492011-01-25 17:07:29 -0800130 value = '"%s"' % value
David Jamesb26b9312014-12-15 11:26:46 -0800131 made_changes |= (file_val != value)
David James8c846492011-01-25 17:07:29 -0800132 file_lines.append(keyval_str % {'key': key, 'value': value})
133 else:
134 file_lines.append(keyval_str % {'key': file_var, 'value': file_val})
135
136 if not found:
Brian Harring2a014302012-05-12 00:53:33 -0700137 value = '"%s"' % value
David Jamesb26b9312014-12-15 11:26:46 -0800138 made_changes = True
David James8c846492011-01-25 17:07:29 -0800139 file_lines.append(keyval_str % {'key': key, 'value': value})
140
141 file_fh.close()
142 # write out new file
Brian Harringaf019fb2012-05-10 15:06:13 -0700143 osutils.WriteFile(filename, '\n'.join(file_lines) + '\n')
David Jamesb26b9312014-12-15 11:26:46 -0800144 return made_changes
David James8c846492011-01-25 17:07:29 -0800145
146
Mike Frysinger5b34d732013-01-17 15:11:58 -0500147def RevGitFile(filename, data, retries=5, dryrun=False):
David James8c846492011-01-25 17:07:29 -0800148 """Update and push the git file.
149
Mike Frysinger5b34d732013-01-17 15:11:58 -0500150 Args:
151 filename: file to modify that is in a git repo already
152 data: A dict of key/values to update in |filename|
153 retries: The number of times to retry before giving up, default: 5
Matt Tennante8179042013-10-01 15:47:32 -0700154 dryrun: If True, do not actually commit the change.
David James8c846492011-01-25 17:07:29 -0800155 """
156 prebuilt_branch = 'prebuilt_branch'
David James1b6e67a2011-05-19 21:32:38 -0700157 cwd = os.path.abspath(os.path.dirname(filename))
David James97d95872012-11-16 15:09:56 -0800158 commit = git.RunGit(cwd, ['rev-parse', 'HEAD']).output.rstrip()
Mike Frysinger5b34d732013-01-17 15:11:58 -0500159 description = '%s: updating %s' % (os.path.basename(filename),
160 ', '.join(data.keys()))
161 # UpdateLocalFile will print out the keys/values for us.
Mike Frysingerff441bf2014-05-24 13:47:21 -0400162 print('Revving git file %s' % filename)
David James66009462012-03-25 10:08:38 -0700163
David James8c846492011-01-25 17:07:29 -0800164 try:
David James97d95872012-11-16 15:09:56 -0800165 git.CreatePushBranch(prebuilt_branch, cwd)
Mike Frysinger5b34d732013-01-17 15:11:58 -0500166 for key, value in data.iteritems():
167 UpdateLocalFile(filename, value, key)
David James97d95872012-11-16 15:09:56 -0800168 git.RunGit(cwd, ['add', filename])
169 git.RunGit(cwd, ['commit', '-m', description])
170 git.PushWithRetry(prebuilt_branch, cwd, dryrun=dryrun, retries=retries)
David James8c846492011-01-25 17:07:29 -0800171 finally:
David James67d73252013-09-19 17:33:12 -0700172 git.RunGit(cwd, ['checkout', commit])
David James8c846492011-01-25 17:07:29 -0800173
174
175def GetVersion():
176 """Get the version to put in LATEST and update the git version with."""
Mike Frysinger0b92cfe2012-12-13 02:13:45 -0500177 return datetime.datetime.now().strftime('%Y.%m.%d.%H%M%S')
David James8c846492011-01-25 17:07:29 -0800178
179
Mike Frysinger540883b2014-05-24 13:46:16 -0400180def _GsUpload(gs_context, acl, local_file, remote_file):
David James8c846492011-01-25 17:07:29 -0800181 """Upload to GS bucket.
182
183 Args:
Mike Frysinger540883b2014-05-24 13:46:16 -0400184 gs_context: A lib.gs.GSContext instance.
185 acl: The ACL to use for uploading the file.
Matt Tennante8179042013-10-01 15:47:32 -0700186 local_file: The local file to be uploaded.
187 remote_file: The remote location to upload to.
David James8c846492011-01-25 17:07:29 -0800188
189 Returns:
190 Return the arg tuple of two if the upload failed
191 """
Scott Zawalskiab1bed32011-03-16 15:24:24 -0700192 CANNED_ACLS = ['public-read', 'private', 'bucket-owner-read',
193 'authenticated-read', 'bucket-owner-full-control',
194 'public-read-write']
Scott Zawalskiab1bed32011-03-16 15:24:24 -0700195 if acl in CANNED_ACLS:
David James9374aac2013-10-08 16:00:17 -0700196 gs_context.Copy(local_file, remote_file, acl=acl)
Scott Zawalskiab1bed32011-03-16 15:24:24 -0700197 else:
198 # For private uploads we assume that the overlay board is set up properly
David James015af872012-06-19 15:24:36 -0700199 # and a googlestore_acl.xml is present. Otherwise, this script errors.
David James9374aac2013-10-08 16:00:17 -0700200 gs_context.Copy(local_file, remote_file, acl='private')
Gabe Black40169e62014-06-17 15:23:47 -0700201 if acl.endswith('.xml'):
202 # Apply the passed in ACL xml file to the uploaded object.
203 gs_context.SetACL(remote_file, acl=acl)
204 else:
205 gs_context.ChangeACL(remote_file, acl_args_file=acl)
Scott Zawalskiab1bed32011-03-16 15:24:24 -0700206
Mike Frysingercc838832014-05-24 13:10:30 -0400207
Mike Frysinger540883b2014-05-24 13:46:16 -0400208def RemoteUpload(gs_context, acl, files, pool=10):
David James8c846492011-01-25 17:07:29 -0800209 """Upload to google storage.
210
211 Create a pool of process and call _GsUpload with the proper arguments.
212
213 Args:
Mike Frysinger540883b2014-05-24 13:46:16 -0400214 gs_context: A lib.gs.GSContext instance.
David Jamesfd0b0852011-02-23 11:15:36 -0800215 acl: The canned acl used for uploading. acl can be one of: "public-read",
216 "public-read-write", "authenticated-read", "bucket-owner-read",
217 "bucket-owner-full-control", or "private".
David James8c846492011-01-25 17:07:29 -0800218 files: dictionary with keys to local files and values to remote path.
219 pool: integer of maximum proesses to have at the same time.
220
221 Returns:
222 Return a set of tuple arguments of the failed uploads
223 """
Mike Frysinger540883b2014-05-24 13:46:16 -0400224 upload = functools.partial(_GsUpload, gs_context, acl)
225 tasks = [[key, value] for key, value in files.iteritems()]
226 parallel.RunTasksInProcessPool(upload, tasks, pool)
David James8c846492011-01-25 17:07:29 -0800227
228
229def GenerateUploadDict(base_local_path, base_remote_path, pkgs):
230 """Build a dictionary of local remote file key pairs to upload.
231
232 Args:
233 base_local_path: The base path to the files on the local hard drive.
Matt Tennante8179042013-10-01 15:47:32 -0700234 base_remote_path: The base path to the remote paths.
David James8c846492011-01-25 17:07:29 -0800235 pkgs: The packages to upload.
236
237 Returns:
238 Returns a dictionary of local_path/remote_path pairs
239 """
240 upload_files = {}
241 for pkg in pkgs:
242 suffix = pkg['CPV'] + '.tbz2'
243 local_path = os.path.join(base_local_path, suffix)
244 assert os.path.exists(local_path)
Bertrand SIMONNET811bcde2014-11-20 15:21:25 -0800245 upload_files[local_path] = os.path.join(base_remote_path, suffix)
David James8c846492011-01-25 17:07:29 -0800246
Bertrand SIMONNET811bcde2014-11-20 15:21:25 -0800247 if pkg.get('DEBUG_SYMBOLS') == 'yes':
248 debugsuffix = pkg['CPV'] + '.debug.tbz2'
249 local_path = os.path.join(base_local_path, debugsuffix)
250 assert os.path.exists(local_path)
251 upload_files[local_path] = os.path.join(base_remote_path, debugsuffix)
Bertrand SIMONNET22e828b2014-11-11 16:27:06 -0800252
David James8c846492011-01-25 17:07:29 -0800253 return upload_files
254
Mike Frysingercc838832014-05-24 13:10:30 -0400255
Peter Mayo950e41a2014-02-06 21:07:33 +0000256def GetBoardOverlay(build_path, target):
David Jamese5867812012-10-19 12:02:20 -0700257 """Get the path to the board variant.
Mike Frysinger1a736a82013-12-12 01:50:59 -0500258
David James8c846492011-01-25 17:07:29 -0800259 Args:
260 build_path: The path to the root of the build directory
David Jamese5867812012-10-19 12:02:20 -0700261 target: The target board as a BuildTarget object.
Mike Frysinger1a736a82013-12-12 01:50:59 -0500262
David James8c846492011-01-25 17:07:29 -0800263 Returns:
David Jamese5867812012-10-19 12:02:20 -0700264 The last overlay configured for the given board as a string.
David James8c846492011-01-25 17:07:29 -0800265 """
David Jamese5867812012-10-19 12:02:20 -0700266 board = target.board_variant
Alex Deymo075c2292014-09-04 18:31:50 -0700267 overlays = portage_util.FindOverlays(constants.BOTH_OVERLAYS, board,
268 buildroot=build_path)
David Jamese5867812012-10-19 12:02:20 -0700269 # We only care about the last entry.
270 return overlays[-1]
David James8c846492011-01-25 17:07:29 -0800271
272
273def DeterminePrebuiltConfFile(build_path, target):
274 """Determine the prebuilt.conf file that needs to be updated for prebuilts.
275
Mike Frysinger1a736a82013-12-12 01:50:59 -0500276 Args:
277 build_path: The path to the root of the build directory
278 target: String representation of the board. This includes host and board
279 targets
David James8c846492011-01-25 17:07:29 -0800280
Mike Frysinger1a736a82013-12-12 01:50:59 -0500281 Returns:
282 A string path to a prebuilt.conf file to be updated.
David James8c846492011-01-25 17:07:29 -0800283 """
David James4058b0d2011-12-08 21:24:50 -0800284 if _HOST_ARCH == target:
David James8c846492011-01-25 17:07:29 -0800285 # We are host.
286 # Without more examples of hosts this is a kludge for now.
287 # TODO(Scottz): as new host targets come online expand this to
288 # work more like boards.
Chris Sosa471532a2011-02-01 15:10:06 -0800289 make_path = _PREBUILT_MAKE_CONF[target]
David James8c846492011-01-25 17:07:29 -0800290 else:
291 # We are a board
Peter Mayo950e41a2014-02-06 21:07:33 +0000292 board = GetBoardOverlay(build_path, target)
David James8c846492011-01-25 17:07:29 -0800293 make_path = os.path.join(board, 'prebuilt.conf')
294
295 return make_path
296
297
298def UpdateBinhostConfFile(path, key, value):
299 """Update binhost config file file with key=value.
300
301 Args:
302 path: Filename to update.
303 key: Key to update.
304 value: New value for key.
305 """
David Jamesb26b9312014-12-15 11:26:46 -0800306 cwd, filename = os.path.split(os.path.abspath(path))
Brian Harringaf019fb2012-05-10 15:06:13 -0700307 osutils.SafeMakedirs(cwd)
David Jamesf6e8fb72013-05-10 08:58:43 -0700308 if not git.GetCurrentBranch(cwd):
309 git.CreatePushBranch(constants.STABLE_EBUILD_BRANCH, cwd, sync=False)
Brian Harring22edb442012-05-11 23:55:18 -0700310 osutils.WriteFile(path, '', mode='a')
David Jamesb26b9312014-12-15 11:26:46 -0800311 if UpdateLocalFile(path, value, key):
312 desc = '%s: %s %s' % (filename, 'updating' if value else 'clearing', key)
313 git.AddPath(path)
314 git.Commit(cwd, desc)
David James8c846492011-01-25 17:07:29 -0800315
Mike Frysinger212e4292014-05-24 15:15:44 -0400316def GenerateHtmlIndex(files, index, board, version):
317 """Given the list of |files|, generate an index.html at |index|.
318
319 Args:
320 files: The list of files to link to.
321 index: The path to the html index.
322 board: Name of the board this index is for.
323 version: Build version this index is for.
324 """
325 head = """<html>
326<head>
327 <title>Package Prebuilt Index: %(board)s / %(version)s</title>
328</head>
329<body>
330<h2>Package Prebuilt Index: %(board)s / %(version)s</h2>"""
331 head %= {
332 'board': board,
333 'version': version,
334 }
335
336 files = files + [
337 '.|Google Storage Index',
338 '..|',
339 ]
340 commands.GenerateHtmlIndex(index, files, head=head)
341
342
David Jamesce093af2011-02-23 15:21:58 -0800343def _GrabAllRemotePackageIndexes(binhost_urls):
David James05bcb2b2011-02-09 09:25:47 -0800344 """Grab all of the packages files associated with a list of binhost_urls.
345
David James05bcb2b2011-02-09 09:25:47 -0800346 Args:
347 binhost_urls: The URLs for the directories containing the Packages files we
348 want to grab.
David James05bcb2b2011-02-09 09:25:47 -0800349
350 Returns:
351 A list of PackageIndex objects.
352 """
353 pkg_indexes = []
354 for url in binhost_urls:
David James32faafe2012-06-08 14:25:03 -0700355 pkg_index = binpkg.GrabRemotePackageIndex(url)
David James05bcb2b2011-02-09 09:25:47 -0800356 if pkg_index:
357 pkg_indexes.append(pkg_index)
David James05bcb2b2011-02-09 09:25:47 -0800358 return pkg_indexes
359
360
David Jamesc0f158a2011-02-22 16:07:29 -0800361class PrebuiltUploader(object):
362 """Synchronize host and board prebuilts."""
David James8c846492011-01-25 17:07:29 -0800363
Mike Frysinger86509232014-05-24 13:18:37 -0400364 def __init__(self, upload_location, acl, binhost_base_url, pkg_indexes,
365 build_path, packages, skip_upload, binhost_conf_dir, dryrun,
Mike Frysinger8092a632014-05-24 13:25:46 -0400366 target, slave_targets, version):
David Jamesc0f158a2011-02-22 16:07:29 -0800367 """Constructor for prebuilt uploader object.
David James8c846492011-01-25 17:07:29 -0800368
David Jamesc0f158a2011-02-22 16:07:29 -0800369 This object can upload host or prebuilt files to Google Storage.
David James8c846492011-01-25 17:07:29 -0800370
David Jamesc0f158a2011-02-22 16:07:29 -0800371 Args:
372 upload_location: The upload location.
David Jamesfd0b0852011-02-23 11:15:36 -0800373 acl: The canned acl used for uploading to Google Storage. acl can be one
374 of: "public-read", "public-read-write", "authenticated-read",
Matt Tennante8179042013-10-01 15:47:32 -0700375 "bucket-owner-read", "bucket-owner-full-control", "project-private",
376 or "private" (see "gsutil help acls"). If we are not uploading to
377 Google Storage, this parameter is unused.
David Jamesfd0b0852011-02-23 11:15:36 -0800378 binhost_base_url: The URL used for downloading the prebuilts.
David Jamesc0f158a2011-02-22 16:07:29 -0800379 pkg_indexes: Old uploaded prebuilts to compare against. Instead of
380 uploading duplicate files, we just link to the old files.
David James615e5b52011-06-03 11:10:15 -0700381 build_path: The path to the directory containing the chroot.
382 packages: Packages to upload.
David James32b0b2f2011-07-13 20:56:50 -0700383 skip_upload: Don't actually upload the tarballs.
384 binhost_conf_dir: Directory where to store binhost.conf files.
Mike Frysinger86509232014-05-24 13:18:37 -0400385 dryrun: Don't push or upload prebuilts.
David James4058b0d2011-12-08 21:24:50 -0800386 target: BuildTarget managed by this builder.
387 slave_targets: List of BuildTargets managed by slave builders.
Mike Frysinger8092a632014-05-24 13:25:46 -0400388 version: A unique string, intended to be included in the upload path,
389 which identifies the version number of the uploaded prebuilts.
David Jamesc0f158a2011-02-22 16:07:29 -0800390 """
391 self._upload_location = upload_location
David Jamesfd0b0852011-02-23 11:15:36 -0800392 self._acl = acl
David Jamesc0f158a2011-02-22 16:07:29 -0800393 self._binhost_base_url = binhost_base_url
394 self._pkg_indexes = pkg_indexes
David James615e5b52011-06-03 11:10:15 -0700395 self._build_path = build_path
396 self._packages = set(packages)
Mike Frysingerf5f809a2013-02-12 13:47:37 -0500397 self._found_packages = set()
David James8ece7ee2011-06-29 16:02:30 -0700398 self._skip_upload = skip_upload
David James32b0b2f2011-07-13 20:56:50 -0700399 self._binhost_conf_dir = binhost_conf_dir
Mike Frysinger86509232014-05-24 13:18:37 -0400400 self._dryrun = dryrun
David James4058b0d2011-12-08 21:24:50 -0800401 self._target = target
402 self._slave_targets = slave_targets
Mike Frysinger8092a632014-05-24 13:25:46 -0400403 self._version = version
Mike Frysinger540883b2014-05-24 13:46:16 -0400404 self._gs_context = gs.GSContext(retries=_RETRIES, sleep=_SLEEP_TIME,
405 dry_run=self._dryrun)
406
407 def _Upload(self, local_file, remote_file):
408 """Wrapper around _GsUpload"""
409 _GsUpload(self._gs_context, self._acl, local_file, remote_file)
David James615e5b52011-06-03 11:10:15 -0700410
411 def _ShouldFilterPackage(self, pkg):
412 if not self._packages:
413 return False
414 pym_path = os.path.abspath(os.path.join(self._build_path, _PYM_PATH))
David James710b7dc2012-02-07 16:49:59 -0800415 sys.path.insert(0, pym_path)
Don Garrett25f309a2014-03-19 14:02:12 -0700416 # pylint: disable=F0401
David James615e5b52011-06-03 11:10:15 -0700417 import portage.versions
418 cat, pkgname = portage.versions.catpkgsplit(pkg['CPV'])[0:2]
419 cp = '%s/%s' % (cat, pkgname)
Mike Frysingerf5f809a2013-02-12 13:47:37 -0500420 self._found_packages.add(cp)
David James615e5b52011-06-03 11:10:15 -0700421 return pkgname not in self._packages and cp not in self._packages
David James8c846492011-01-25 17:07:29 -0800422
David Jamesc0f158a2011-02-22 16:07:29 -0800423 def _UploadPrebuilt(self, package_path, url_suffix):
424 """Upload host or board prebuilt files to Google Storage space.
David James8c846492011-01-25 17:07:29 -0800425
David Jamesc0f158a2011-02-22 16:07:29 -0800426 Args:
427 package_path: The path to the packages dir.
David Jamesce093af2011-02-23 15:21:58 -0800428 url_suffix: The remote subdirectory where we should upload the packages.
David Jamesc0f158a2011-02-22 16:07:29 -0800429 """
David Jamesc0f158a2011-02-22 16:07:29 -0800430 # Process Packages file, removing duplicates and filtered packages.
David James32faafe2012-06-08 14:25:03 -0700431 pkg_index = binpkg.GrabLocalPackageIndex(package_path)
David Jamesc0f158a2011-02-22 16:07:29 -0800432 pkg_index.SetUploadLocation(self._binhost_base_url, url_suffix)
David James615e5b52011-06-03 11:10:15 -0700433 pkg_index.RemoveFilteredPackages(self._ShouldFilterPackage)
David Jamesc0f158a2011-02-22 16:07:29 -0800434 uploads = pkg_index.ResolveDuplicateUploads(self._pkg_indexes)
Mike Frysingerf5f809a2013-02-12 13:47:37 -0500435 unmatched_pkgs = self._packages - self._found_packages
436 if unmatched_pkgs:
Ralph Nathan446aee92015-03-23 14:44:56 -0700437 logging.warning('unable to match packages: %r' % unmatched_pkgs)
David James05bcb2b2011-02-09 09:25:47 -0800438
David Jamesc0f158a2011-02-22 16:07:29 -0800439 # Write Packages file.
David James5ab67e32014-10-24 08:19:59 -0700440 pkg_index.header['TTL'] = _BINPKG_TTL
David Jamesc0f158a2011-02-22 16:07:29 -0800441 tmp_packages_file = pkg_index.WriteToNamedTemporaryFile()
David James05bcb2b2011-02-09 09:25:47 -0800442
David Jamesc0f158a2011-02-22 16:07:29 -0800443 remote_location = '%s/%s' % (self._upload_location.rstrip('/'), url_suffix)
David James015af872012-06-19 15:24:36 -0700444 assert remote_location.startswith('gs://')
David James05bcb2b2011-02-09 09:25:47 -0800445
Alex Deymo541ea6f2014-12-23 01:18:14 -0800446 # Build list of files to upload. Manually include the dev-only files but
447 # skip them if not present.
448 # TODO(deymo): Upload dev-only-extras.tbz2 as dev-only-extras.tar.bz2
449 # outside packages/ directory. See crbug.com/448178 for details.
450 if os.path.exists(os.path.join(package_path, 'dev-only-extras.tbz2')):
451 uploads.append({'CPV': 'dev-only-extras'})
David James015af872012-06-19 15:24:36 -0700452 upload_files = GenerateUploadDict(package_path, remote_location, uploads)
453 remote_file = '%s/Packages' % remote_location.rstrip('/')
454 upload_files[tmp_packages_file.name] = remote_file
455
Mike Frysinger540883b2014-05-24 13:46:16 -0400456 RemoteUpload(self._gs_context, self._acl, upload_files)
David James8c846492011-01-25 17:07:29 -0800457
Mike Frysinger212e4292014-05-24 15:15:44 -0400458 with tempfile.NamedTemporaryFile(
459 prefix='chromite.upload_prebuilts.index.') as index:
460 GenerateHtmlIndex(
461 [x[len(remote_location) + 1:] for x in upload_files.values()],
462 index.name, self._target, self._version)
463 self._Upload(index.name, '%s/index.html' % remote_location.rstrip('/'))
464
465 link_name = 'Prebuilts[%s]: %s' % (self._target, self._version)
466 url = '%s%s/index.html' % (gs.PUBLIC_BASE_HTTPS_URL,
467 remote_location[len(gs.BASE_GS_URL):])
468 cros_build_lib.PrintBuildbotLink(link_name, url)
469
Mike Frysinger8092a632014-05-24 13:25:46 -0400470 def _UploadSdkTarball(self, board_path, url_suffix, prepackaged,
Mike Frysinger9e979b92012-11-29 02:55:09 -0500471 toolchain_tarballs, toolchain_upload_path):
472 """Upload a tarball of the sdk at the specified path to Google Storage.
David James8fa34ea2011-04-15 13:00:20 -0700473
474 Args:
475 board_path: The path to the board dir.
476 url_suffix: The remote subdirectory where we should upload the packages.
Zdenek Behan62a57792012-08-31 15:09:08 +0200477 prepackaged: If given, a tarball that has been packaged outside of this
478 script and should be used.
Mike Frysinger9e979b92012-11-29 02:55:09 -0500479 toolchain_tarballs: List of toolchain tarballs to upload.
480 toolchain_upload_path: Path under the bucket to place toolchain tarballs.
David James8fa34ea2011-04-15 13:00:20 -0700481 """
482 remote_location = '%s/%s' % (self._upload_location.rstrip('/'), url_suffix)
483 assert remote_location.startswith('gs://')
Zdenek Behan86c15e92012-10-13 00:55:47 +0200484 boardname = os.path.basename(board_path.rstrip('/'))
485 # We do not upload non SDK board tarballs,
486 assert boardname == constants.CHROOT_BUILDER_BOARD
487 assert prepackaged is not None
Zdenek Behan62a57792012-08-31 15:09:08 +0200488
Mike Frysinger8092a632014-05-24 13:25:46 -0400489 version_str = self._version[len('chroot-'):]
Mike Frysinger8e727a32013-01-16 16:57:53 -0500490 remote_tarfile = toolchain.GetSdkURL(
491 for_gsutil=True, suburl='cros-sdk-%s.tar.xz' % (version_str,))
Zdenek Behan86c15e92012-10-13 00:55:47 +0200492 # For SDK, also upload the manifest which is guaranteed to exist
493 # by the builderstage.
Mike Frysinger540883b2014-05-24 13:46:16 -0400494 self._Upload(prepackaged + '.Manifest', remote_tarfile + '.Manifest')
495 self._Upload(prepackaged, remote_tarfile)
Zdenek Behan86c15e92012-10-13 00:55:47 +0200496
Mike Frysinger9e979b92012-11-29 02:55:09 -0500497 # Post the toolchain tarballs too.
498 for tarball in toolchain_tarballs:
499 target, local_path = tarball.split(':')
500 suburl = toolchain_upload_path % {'target': target}
501 remote_path = toolchain.GetSdkURL(for_gsutil=True, suburl=suburl)
Mike Frysinger540883b2014-05-24 13:46:16 -0400502 self._Upload(local_path, remote_path)
Mike Frysinger9e979b92012-11-29 02:55:09 -0500503
Zdenek Behan86c15e92012-10-13 00:55:47 +0200504 # Finally, also update the pointer to the latest SDK on which polling
505 # scripts rely.
David James4bc13702013-03-26 08:08:04 -0700506 with osutils.TempDir() as tmpdir:
Zdenek Behan86c15e92012-10-13 00:55:47 +0200507 pointerfile = os.path.join(tmpdir, 'cros-sdk-latest.conf')
Mike Frysinger8e727a32013-01-16 16:57:53 -0500508 remote_pointerfile = toolchain.GetSdkURL(for_gsutil=True,
509 suburl='cros-sdk-latest.conf')
Zdenek Behan86c15e92012-10-13 00:55:47 +0200510 osutils.WriteFile(pointerfile, 'LATEST_SDK="%s"' % version_str)
Mike Frysinger540883b2014-05-24 13:46:16 -0400511 self._Upload(pointerfile, remote_pointerfile)
Zdenek Behan33a34112012-09-10 21:07:51 +0200512
Chris Sosa6a5dceb2012-05-14 13:48:56 -0700513 def _GetTargets(self):
514 """Retuns the list of targets to use."""
515 targets = self._slave_targets[:]
516 if self._target:
517 targets.append(self._target)
518
519 return targets
520
Mike Frysinger8092a632014-05-24 13:25:46 -0400521 def SyncHostPrebuilts(self, key, git_sync, sync_binhost_conf):
David Jamesc0f158a2011-02-22 16:07:29 -0800522 """Synchronize host prebuilt files.
David James05bcb2b2011-02-09 09:25:47 -0800523
David Jamesc0f158a2011-02-22 16:07:29 -0800524 This function will sync both the standard host packages, plus the host
525 packages associated with all targets that have been "setup" with the
526 current host's chroot. For instance, if this host has been used to build
527 x86-generic, it will sync the host packages associated with
528 'i686-pc-linux-gnu'. If this host has also been used to build arm-generic,
529 it will also sync the host packages associated with
530 'armv7a-cros-linux-gnueabi'.
David James05bcb2b2011-02-09 09:25:47 -0800531
David Jamesc0f158a2011-02-22 16:07:29 -0800532 Args:
David Jamesc0f158a2011-02-22 16:07:29 -0800533 key: The variable key to update in the git file.
534 git_sync: If set, update make.conf of target to reference the latest
535 prebuilt packages generated here.
536 sync_binhost_conf: If set, update binhost config file in
537 chromiumos-overlay for the host.
538 """
David Jamese2488642011-11-14 16:15:20 -0800539 # Slave boards are listed before the master board so that the master board
540 # takes priority (i.e. x86-generic preflight host prebuilts takes priority
541 # over preflight host prebuilts from other builders.)
542 binhost_urls = []
Chris Sosa6a5dceb2012-05-14 13:48:56 -0700543 for target in self._GetTargets():
Mike Frysinger8092a632014-05-24 13:25:46 -0400544 url_suffix = _REL_HOST_PATH % {'version': self._version,
David James4058b0d2011-12-08 21:24:50 -0800545 'host_arch': _HOST_ARCH,
546 'target': target}
David Jamese2488642011-11-14 16:15:20 -0800547 packages_url_suffix = '%s/packages' % url_suffix.rstrip('/')
David James05bcb2b2011-02-09 09:25:47 -0800548
Mike Frysinger540883b2014-05-24 13:46:16 -0400549 if self._target == target and not self._skip_upload:
David Jamese2488642011-11-14 16:15:20 -0800550 # Upload prebuilts.
551 package_path = os.path.join(self._build_path, _HOST_PACKAGES_PATH)
552 self._UploadPrebuilt(package_path, packages_url_suffix)
David James8ece7ee2011-06-29 16:02:30 -0700553
David Jamese2488642011-11-14 16:15:20 -0800554 # Record URL where prebuilts were uploaded.
555 binhost_urls.append('%s/%s/' % (self._binhost_base_url.rstrip('/'),
556 packages_url_suffix.rstrip('/')))
557
David James20b2b6f2011-11-18 15:11:58 -0800558 binhost = ' '.join(binhost_urls)
David James8ece7ee2011-06-29 16:02:30 -0700559 if git_sync:
David Jamesb26b9312014-12-15 11:26:46 -0800560 git_file = os.path.join(self._build_path, _PREBUILT_MAKE_CONF[_HOST_ARCH])
Mike Frysinger86509232014-05-24 13:18:37 -0400561 RevGitFile(git_file, {key: binhost}, dryrun=self._dryrun)
David James8ece7ee2011-06-29 16:02:30 -0700562 if sync_binhost_conf:
David Jamesb26b9312014-12-15 11:26:46 -0800563 binhost_conf = os.path.join(
564 self._binhost_conf_dir, 'host', '%s-%s.conf' % (_HOST_ARCH, key))
David Jamese2488642011-11-14 16:15:20 -0800565 UpdateBinhostConfFile(binhost_conf, key, binhost)
David Jamesc0f158a2011-02-22 16:07:29 -0800566
Mike Frysinger8092a632014-05-24 13:25:46 -0400567 def SyncBoardPrebuilts(self, key, git_sync, sync_binhost_conf,
Mike Frysinger9e979b92012-11-29 02:55:09 -0500568 upload_board_tarball, prepackaged_board,
569 toolchain_tarballs, toolchain_upload_path):
David Jamesc0f158a2011-02-22 16:07:29 -0800570 """Synchronize board prebuilt files.
571
572 Args:
David Jamesc0f158a2011-02-22 16:07:29 -0800573 key: The variable key to update in the git file.
574 git_sync: If set, update make.conf of target to reference the latest
575 prebuilt packages generated here.
576 sync_binhost_conf: If set, update binhost config file in
577 chromiumos-overlay for the current board.
David James8fa34ea2011-04-15 13:00:20 -0700578 upload_board_tarball: Include a tarball of the board in our upload.
Zdenek Behan62a57792012-08-31 15:09:08 +0200579 prepackaged_board: A tarball of the board built outside of this script.
Mike Frysinger9e979b92012-11-29 02:55:09 -0500580 toolchain_tarballs: A list of toolchain tarballs to upload.
581 toolchain_upload_path: Path under the bucket to place toolchain tarballs.
David Jamesc0f158a2011-02-22 16:07:29 -0800582 """
David Jamesb26b9312014-12-15 11:26:46 -0800583 updated_binhosts = set()
Chris Sosa6a5dceb2012-05-14 13:48:56 -0700584 for target in self._GetTargets():
David Jamese2488642011-11-14 16:15:20 -0800585 board_path = os.path.join(self._build_path,
David James4058b0d2011-12-08 21:24:50 -0800586 _BOARD_PATH % {'board': target.board_variant})
David Jamese2488642011-11-14 16:15:20 -0800587 package_path = os.path.join(board_path, 'packages')
Mike Frysinger8092a632014-05-24 13:25:46 -0400588 url_suffix = _REL_BOARD_PATH % {'target': target,
589 'version': self._version}
David Jamese2488642011-11-14 16:15:20 -0800590 packages_url_suffix = '%s/packages' % url_suffix.rstrip('/')
David James8fa34ea2011-04-15 13:00:20 -0700591
Matt Tennante8179042013-10-01 15:47:32 -0700592 # Process the target board differently if it is the main --board.
Mike Frysinger540883b2014-05-24 13:46:16 -0400593 if self._target == target and not self._skip_upload:
Matt Tennante8179042013-10-01 15:47:32 -0700594 # This strips "chroot" prefix because that is sometimes added as the
595 # --prepend-version argument (e.g. by chromiumos-sdk bot).
596 # TODO(build): Clean it up to be less hard-coded.
Mike Frysinger8092a632014-05-24 13:25:46 -0400597 version_str = self._version[len('chroot-'):]
Mike Frysinger9e979b92012-11-29 02:55:09 -0500598
David Jamese2488642011-11-14 16:15:20 -0800599 # Upload board tarballs in the background.
600 if upload_board_tarball:
Mike Frysinger9e979b92012-11-29 02:55:09 -0500601 if toolchain_upload_path:
602 toolchain_upload_path %= {'version': version_str}
603 tar_process = multiprocessing.Process(
604 target=self._UploadSdkTarball,
Mike Frysinger8092a632014-05-24 13:25:46 -0400605 args=(board_path, url_suffix, prepackaged_board,
Mike Frysinger9e979b92012-11-29 02:55:09 -0500606 toolchain_tarballs, toolchain_upload_path))
David Jamese2488642011-11-14 16:15:20 -0800607 tar_process.start()
David James8fa34ea2011-04-15 13:00:20 -0700608
David Jamese2488642011-11-14 16:15:20 -0800609 # Upload prebuilts.
610 self._UploadPrebuilt(package_path, packages_url_suffix)
David James8fa34ea2011-04-15 13:00:20 -0700611
David Jamese2488642011-11-14 16:15:20 -0800612 # Make sure we finished uploading the board tarballs.
613 if upload_board_tarball:
614 tar_process.join()
615 assert tar_process.exitcode == 0
616 # TODO(zbehan): This should be done cleaner.
Zdenek Behan33a34112012-09-10 21:07:51 +0200617 if target.board == constants.CHROOT_BUILDER_BOARD:
David Jamesb26b9312014-12-15 11:26:46 -0800618 sdk_conf = os.path.join(self._binhost_conf_dir,
Mike Frysinger5b34d732013-01-17 15:11:58 -0500619 'host/sdk_version.conf')
620 sdk_settings = {
Mike Frysinger9e979b92012-11-29 02:55:09 -0500621 'SDK_LATEST_VERSION': version_str,
622 'TC_PATH': toolchain_upload_path,
Mike Frysinger5b34d732013-01-17 15:11:58 -0500623 }
Mike Frysinger86509232014-05-24 13:18:37 -0400624 RevGitFile(sdk_conf, sdk_settings, dryrun=self._dryrun)
David Jamesc0f158a2011-02-22 16:07:29 -0800625
David Jamese2488642011-11-14 16:15:20 -0800626 # Record URL where prebuilts were uploaded.
627 url_value = '%s/%s/' % (self._binhost_base_url.rstrip('/'),
628 packages_url_suffix.rstrip('/'))
629
630 if git_sync:
David James4058b0d2011-12-08 21:24:50 -0800631 git_file = DeterminePrebuiltConfFile(self._build_path, target)
Mike Frysinger86509232014-05-24 13:18:37 -0400632 RevGitFile(git_file, {key: url_value}, dryrun=self._dryrun)
Matt Tennante8179042013-10-01 15:47:32 -0700633
David Jamese2488642011-11-14 16:15:20 -0800634 if sync_binhost_conf:
Matt Tennante8179042013-10-01 15:47:32 -0700635 # Update the binhost configuration file in git.
David Jamesb26b9312014-12-15 11:26:46 -0800636 binhost_conf = os.path.join(
637 self._binhost_conf_dir, 'target', '%s-%s.conf' % (target, key))
638 updated_binhosts.add(binhost_conf)
David Jamese2488642011-11-14 16:15:20 -0800639 UpdateBinhostConfFile(binhost_conf, key, url_value)
David James05bcb2b2011-02-09 09:25:47 -0800640
David Jamesb26b9312014-12-15 11:26:46 -0800641 if sync_binhost_conf:
642 # Clear all old binhosts. The files must be left empty in case anybody
643 # is referring to them.
644 all_binhosts = set(glob.glob(os.path.join(
645 self._binhost_conf_dir, 'target', '*-%s.conf' % key)))
646 for binhost_conf in all_binhosts - updated_binhosts:
647 UpdateBinhostConfFile(binhost_conf, key, '')
648
David James05bcb2b2011-02-09 09:25:47 -0800649
Chris Sosa6a5dceb2012-05-14 13:48:56 -0700650def _AddSlaveBoard(_option, _opt_str, value, parser):
651 """Callback that adds a slave board to the list of slave targets."""
David James4058b0d2011-12-08 21:24:50 -0800652 parser.values.slave_targets.append(BuildTarget(value))
653
654
Chris Sosa6a5dceb2012-05-14 13:48:56 -0700655def _AddSlaveProfile(_option, _opt_str, value, parser):
656 """Callback that adds a slave profile to the list of slave targets."""
David James4058b0d2011-12-08 21:24:50 -0800657 if not parser.values.slave_targets:
Mike Frysinger86509232014-05-24 13:18:37 -0400658 parser.error('Must specify --slave-board before --slave-profile')
David James4058b0d2011-12-08 21:24:50 -0800659 if parser.values.slave_targets[-1].profile is not None:
Mike Frysinger86509232014-05-24 13:18:37 -0400660 parser.error('Cannot specify --slave-profile twice for same board')
David James4058b0d2011-12-08 21:24:50 -0800661 parser.values.slave_targets[-1].profile = value
662
663
Mike Frysinger86509232014-05-24 13:18:37 -0400664def ParseOptions(argv):
Chris Sosa6a5dceb2012-05-14 13:48:56 -0700665 """Returns options given by the user and the target specified.
666
Mike Frysinger86509232014-05-24 13:18:37 -0400667 Args:
668 argv: The args to parse.
669
Mike Frysinger1a736a82013-12-12 01:50:59 -0500670 Returns:
671 A tuple containing a parsed options object and BuildTarget.
672 The target instance is None if no board is specified.
Chris Sosa6a5dceb2012-05-14 13:48:56 -0700673 """
Mike Frysinger86509232014-05-24 13:18:37 -0400674 parser = commandline.OptionParser()
David James8c846492011-01-25 17:07:29 -0800675 parser.add_option('-H', '--binhost-base-url', dest='binhost_base_url',
676 default=_BINHOST_BASE_URL,
677 help='Base URL to use for binhost in make.conf updates')
678 parser.add_option('', '--previous-binhost-url', action='append',
679 default=[], dest='previous_binhost_url',
680 help='Previous binhost URL')
681 parser.add_option('-b', '--board', dest='board', default=None,
682 help='Board type that was built on this machine')
Zdenek Behan62a57792012-08-31 15:09:08 +0200683 parser.add_option('-B', '--prepackaged-tarball', dest='prepackaged_tarball',
684 default=None,
685 help='Board tarball prebuilt outside of this script.')
Mike Frysinger9e979b92012-11-29 02:55:09 -0500686 parser.add_option('--toolchain-tarball', dest='toolchain_tarballs',
687 action='append', default=[],
688 help='Redistributable toolchain tarball.')
689 parser.add_option('--toolchain-upload-path', default='',
690 help='Path to place toolchain tarballs in the sdk tree.')
David James4058b0d2011-12-08 21:24:50 -0800691 parser.add_option('', '--profile', dest='profile', default=None,
692 help='Profile that was built on this machine')
693 parser.add_option('', '--slave-board', default=[], action='callback',
694 dest='slave_targets', type='string',
Chris Sosa6a5dceb2012-05-14 13:48:56 -0700695 callback=_AddSlaveBoard,
David James4058b0d2011-12-08 21:24:50 -0800696 help='Board type that was built on a slave machine. To '
697 'add a profile to this board, use --slave-profile.')
698 parser.add_option('', '--slave-profile', action='callback', type='string',
Chris Sosa6a5dceb2012-05-14 13:48:56 -0700699 callback=_AddSlaveProfile,
David James4058b0d2011-12-08 21:24:50 -0800700 help='Board profile that was built on a slave machine. '
701 'Applies to previous slave board.')
David James8c846492011-01-25 17:07:29 -0800702 parser.add_option('-p', '--build-path', dest='build_path',
David James05bcb2b2011-02-09 09:25:47 -0800703 help='Path to the directory containing the chroot')
David James615e5b52011-06-03 11:10:15 -0700704 parser.add_option('', '--packages', action='append',
705 default=[], dest='packages',
706 help='Only include the specified packages. '
707 '(Default is to include all packages.)')
David James8c846492011-01-25 17:07:29 -0800708 parser.add_option('-s', '--sync-host', dest='sync_host',
709 default=False, action='store_true',
710 help='Sync host prebuilts')
711 parser.add_option('-g', '--git-sync', dest='git_sync',
712 default=False, action='store_true',
David Jamese2488642011-11-14 16:15:20 -0800713 help='Enable git version sync (This commits to a repo.) '
714 'This is used by full builders to commit directly '
715 'to board overlays.')
David James8c846492011-01-25 17:07:29 -0800716 parser.add_option('-u', '--upload', dest='upload',
717 default=None,
718 help='Upload location')
719 parser.add_option('-V', '--prepend-version', dest='prepend_version',
720 default=None,
721 help='Add an identifier to the front of the version')
722 parser.add_option('-f', '--filters', dest='filters', action='store_true',
723 default=False,
724 help='Turn on filtering of private ebuild packages')
725 parser.add_option('-k', '--key', dest='key',
726 default='PORTAGE_BINHOST',
727 help='Key to update in make.conf / binhost.conf')
David James8ece7ee2011-06-29 16:02:30 -0700728 parser.add_option('', '--set-version', dest='set_version',
729 default=None,
730 help='Specify the version string')
David James8c846492011-01-25 17:07:29 -0800731 parser.add_option('', '--sync-binhost-conf', dest='sync_binhost_conf',
732 default=False, action='store_true',
David Jamese2488642011-11-14 16:15:20 -0800733 help='Update binhost.conf in chromiumos-overlay or '
734 'chromeos-overlay. Commit the changes, but don\'t '
735 'push them. This is used for preflight binhosts.')
David James32b0b2f2011-07-13 20:56:50 -0700736 parser.add_option('', '--binhost-conf-dir', dest='binhost_conf_dir',
David James32b0b2f2011-07-13 20:56:50 -0700737 help='Directory to commit binhost config with '
738 '--sync-binhost-conf.')
David Jamesfd0b0852011-02-23 11:15:36 -0800739 parser.add_option('-P', '--private', dest='private', action='store_true',
740 default=False, help='Mark gs:// uploads as private.')
David James8ece7ee2011-06-29 16:02:30 -0700741 parser.add_option('', '--skip-upload', dest='skip_upload',
742 action='store_true', default=False,
743 help='Skip upload step.')
David James8fa34ea2011-04-15 13:00:20 -0700744 parser.add_option('', '--upload-board-tarball', dest='upload_board_tarball',
745 action='store_true', default=False,
746 help='Upload board tarball to Google Storage.')
Mike Frysinger86509232014-05-24 13:18:37 -0400747 parser.add_option('-n', '--dry-run', dest='dryrun',
David James27fa7d12011-06-29 17:24:14 -0700748 action='store_true', default=False,
749 help='Don\'t push or upload prebuilts.')
David James8c846492011-01-25 17:07:29 -0800750
Mike Frysinger86509232014-05-24 13:18:37 -0400751 options, args = parser.parse_args(argv)
David James8c846492011-01-25 17:07:29 -0800752 if not options.build_path:
Mike Frysinger86509232014-05-24 13:18:37 -0400753 parser.error('you need provide a chroot path')
David James8ece7ee2011-06-29 16:02:30 -0700754 if not options.upload and not options.skip_upload:
Mike Frysinger86509232014-05-24 13:18:37 -0400755 parser.error('you need to provide an upload location using -u')
David James8ece7ee2011-06-29 16:02:30 -0700756 if not options.set_version and options.skip_upload:
Mike Frysinger86509232014-05-24 13:18:37 -0400757 parser.error('If you are using --skip-upload, you must specify a '
758 'version number using --set-version.')
David James9417f272011-05-26 13:24:47 -0700759 if args:
Mike Frysinger86509232014-05-24 13:18:37 -0400760 parser.error('invalid arguments passed to upload_prebuilts: %r' % args)
Scott Zawalskiab1bed32011-03-16 15:24:24 -0700761
Chris Sosa6a5dceb2012-05-14 13:48:56 -0700762 target = None
763 if options.board:
764 target = BuildTarget(options.board, options.profile)
765
766 if target in options.slave_targets:
Mike Frysinger86509232014-05-24 13:18:37 -0400767 parser.error('--board/--profile must not also be a slave target.')
David Jamese2488642011-11-14 16:15:20 -0800768
David James4058b0d2011-12-08 21:24:50 -0800769 if len(set(options.slave_targets)) != len(options.slave_targets):
Mike Frysinger86509232014-05-24 13:18:37 -0400770 parser.error('--slave-boards must not have duplicates.')
David Jamese2488642011-11-14 16:15:20 -0800771
David James4058b0d2011-12-08 21:24:50 -0800772 if options.slave_targets and options.git_sync:
Mike Frysinger86509232014-05-24 13:18:37 -0400773 parser.error('--slave-boards is not compatible with --git-sync')
David Jamese2488642011-11-14 16:15:20 -0800774
David James8ece7ee2011-06-29 16:02:30 -0700775 if (options.upload_board_tarball and options.skip_upload and
776 options.board == 'amd64-host'):
Mike Frysinger86509232014-05-24 13:18:37 -0400777 parser.error('--skip-upload is not compatible with '
778 '--upload-board-tarball and --board=amd64-host')
David James8fa34ea2011-04-15 13:00:20 -0700779
David James8ece7ee2011-06-29 16:02:30 -0700780 if (options.upload_board_tarball and not options.skip_upload and
781 not options.upload.startswith('gs://')):
Mike Frysinger86509232014-05-24 13:18:37 -0400782 parser.error('--upload-board-tarball only works with gs:// URLs.\n'
783 '--upload must be a gs:// URL.')
David James8fa34ea2011-04-15 13:00:20 -0700784
Zdenek Behan86c15e92012-10-13 00:55:47 +0200785 if options.upload_board_tarball and options.prepackaged_tarball is None:
Mike Frysinger86509232014-05-24 13:18:37 -0400786 parser.error('--upload-board-tarball requires --prepackaged-tarball')
Zdenek Behan86c15e92012-10-13 00:55:47 +0200787
Scott Zawalskiab1bed32011-03-16 15:24:24 -0700788 if options.private:
789 if options.sync_host:
Mike Frysinger86509232014-05-24 13:18:37 -0400790 parser.error('--private and --sync-host/-s cannot be specified '
791 'together; we do not support private host prebuilts')
Scott Zawalskiab1bed32011-03-16 15:24:24 -0700792
David James8ece7ee2011-06-29 16:02:30 -0700793 if not options.upload or not options.upload.startswith('gs://'):
Mike Frysinger86509232014-05-24 13:18:37 -0400794 parser.error('--private is only valid for gs:// URLs; '
795 '--upload must be a gs:// URL.')
Scott Zawalskiab1bed32011-03-16 15:24:24 -0700796
797 if options.binhost_base_url != _BINHOST_BASE_URL:
Mike Frysinger86509232014-05-24 13:18:37 -0400798 parser.error('when using --private the --binhost-base-url '
799 'is automatically derived.')
David James27fa7d12011-06-29 17:24:14 -0700800
David Jamesc31168e2014-06-05 14:40:05 -0700801 if options.sync_binhost_conf and not options.binhost_conf_dir:
802 parser.error('--sync-binhost-conf requires --binhost-conf-dir')
803
Chris Sosa6a5dceb2012-05-14 13:48:56 -0700804 return options, target
David Jamesc0f158a2011-02-22 16:07:29 -0800805
Mike Frysingercc838832014-05-24 13:10:30 -0400806
Mike Frysinger86509232014-05-24 13:18:37 -0400807def main(argv):
David Jamesdb401072011-06-10 12:17:16 -0700808 # Set umask to a sane value so that files created as root are readable.
Mike Frysinger60ec1012013-10-21 00:11:10 -0400809 os.umask(0o22)
David Jamesdb401072011-06-10 12:17:16 -0700810
Mike Frysinger86509232014-05-24 13:18:37 -0400811 options, target = ParseOptions(argv)
David Jamesc0f158a2011-02-22 16:07:29 -0800812
David James05bcb2b2011-02-09 09:25:47 -0800813 # Calculate a list of Packages index files to compare against. Whenever we
814 # upload a package, we check to make sure it's not already stored in one of
815 # the packages files we uploaded. This list of packages files might contain
816 # both board and host packages.
David Jamesce093af2011-02-23 15:21:58 -0800817 pkg_indexes = _GrabAllRemotePackageIndexes(options.previous_binhost_url)
David James8c846492011-01-25 17:07:29 -0800818
David James8ece7ee2011-06-29 16:02:30 -0700819 if options.set_version:
820 version = options.set_version
821 else:
822 version = GetVersion()
Matt Tennante8179042013-10-01 15:47:32 -0700823
David Jamesc0f158a2011-02-22 16:07:29 -0800824 if options.prepend_version:
825 version = '%s-%s' % (options.prepend_version, version)
826
Scott Zawalskiab1bed32011-03-16 15:24:24 -0700827 acl = 'public-read'
828 binhost_base_url = options.binhost_base_url
829
David Jamesadd21432013-05-21 10:04:07 -0700830 if options.private:
Scott Zawalskiab1bed32011-03-16 15:24:24 -0700831 binhost_base_url = options.upload
David Jamesadd21432013-05-21 10:04:07 -0700832 if target:
Prathmesh Prabhu421eef22014-10-16 17:13:19 -0700833 acl = portage_util.FindOverlayFile(_GOOGLESTORAGE_GSUTIL_FILE,
834 board=target.board_variant,
835 buildroot=options.build_path)
Ben Chan067de492015-01-06 17:19:13 -0800836 if acl is None:
837 cros_build_lib.Die('No Google Storage ACL file %s found in %s overlay.',
838 _GOOGLESTORAGE_GSUTIL_FILE, target.board_variant)
Scott Zawalskiab1bed32011-03-16 15:24:24 -0700839
David Jamesb26b9312014-12-15 11:26:46 -0800840 binhost_conf_dir = None
841 if options.binhost_conf_dir:
842 binhost_conf_dir = os.path.join(options.build_path,
843 options.binhost_conf_dir)
844
Scott Zawalskiab1bed32011-03-16 15:24:24 -0700845 uploader = PrebuiltUploader(options.upload, acl, binhost_base_url,
David James615e5b52011-06-03 11:10:15 -0700846 pkg_indexes, options.build_path,
David James27fa7d12011-06-29 17:24:14 -0700847 options.packages, options.skip_upload,
David Jamesb26b9312014-12-15 11:26:46 -0800848 binhost_conf_dir, options.dryrun,
Mike Frysinger8092a632014-05-24 13:25:46 -0400849 target, options.slave_targets, version)
David Jamesc0f158a2011-02-22 16:07:29 -0800850
David James8c846492011-01-25 17:07:29 -0800851 if options.sync_host:
Mike Frysinger8092a632014-05-24 13:25:46 -0400852 uploader.SyncHostPrebuilts(options.key, options.git_sync,
Chris Sosa6a5dceb2012-05-14 13:48:56 -0700853 options.sync_binhost_conf)
David James8c846492011-01-25 17:07:29 -0800854
Chris Sosa62c8ff52012-06-04 15:03:12 -0700855 if options.board or options.slave_targets:
Mike Frysinger8092a632014-05-24 13:25:46 -0400856 uploader.SyncBoardPrebuilts(options.key, options.git_sync,
Chris Sosa6a5dceb2012-05-14 13:48:56 -0700857 options.sync_binhost_conf,
Zdenek Behan62a57792012-08-31 15:09:08 +0200858 options.upload_board_tarball,
Mike Frysinger9e979b92012-11-29 02:55:09 -0500859 options.prepackaged_tarball,
860 options.toolchain_tarballs,
861 options.toolchain_upload_path)