blob: c8738aaaf3961e8b51935bfa912ba5b03acd0a1c [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 Frysinger1d4752b2014-11-08 04:00:18 -050020# pylint: disable=bad-continuation
21
Mike Frysingerff441bf2014-05-24 13:47:21 -040022from __future__ import print_function
23
Chris Sosa1dc96132012-05-11 15:40:50 -070024import datetime
Mike Frysinger540883b2014-05-24 13:46:16 -040025import functools
Chris Sosa1dc96132012-05-11 15:40:50 -070026import multiprocessing
Chris Sosa1dc96132012-05-11 15:40:50 -070027import os
28import sys
Mike Frysinger212e4292014-05-24 15:15:44 -040029import tempfile
Chris Sosa1dc96132012-05-11 15:40:50 -070030
Don Garrett88b8d782014-05-13 17:30:55 -070031from chromite.cbuildbot import constants
David James14e97772014-06-04 18:44:49 -070032from chromite.cbuildbot import commands
David James6450a0a2012-12-04 07:59:53 -080033from chromite.lib import binpkg
Mike Frysinger86509232014-05-24 13:18:37 -040034from chromite.lib import commandline
Chris Sosa1dc96132012-05-11 15:40:50 -070035from chromite.lib import cros_build_lib
David James97d95872012-11-16 15:09:56 -080036from chromite.lib import git
Brian Harring7904b482012-08-08 02:54:12 -070037from chromite.lib import gs
Brian Harringaf019fb2012-05-10 15:06:13 -070038from chromite.lib import osutils
David James6450a0a2012-12-04 07:59:53 -080039from chromite.lib import parallel
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)
105 """
106 if os.path.exists(filename):
107 file_fh = open(filename)
108 else:
109 file_fh = open(filename, 'w+')
110 file_lines = []
111 found = False
112 keyval_str = '%(key)s=%(value)s'
113 for line in file_fh:
114 # Strip newlines from end of line. We already add newlines below.
115 line = line.rstrip("\n")
116
117 if len(line.split('=')) != 2:
118 # Skip any line that doesn't fit key=val.
119 file_lines.append(line)
120 continue
121
122 file_var, file_val = line.split('=')
123 if file_var == key:
124 found = True
Mike Frysingerff441bf2014-05-24 13:47:21 -0400125 print('Updating %s=%s to %s="%s"' % (file_var, file_val, key, value))
David James8c846492011-01-25 17:07:29 -0800126 value = '"%s"' % value
127 file_lines.append(keyval_str % {'key': key, 'value': value})
128 else:
129 file_lines.append(keyval_str % {'key': file_var, 'value': file_val})
130
131 if not found:
Brian Harring2a014302012-05-12 00:53:33 -0700132 value = '"%s"' % value
David James8c846492011-01-25 17:07:29 -0800133 file_lines.append(keyval_str % {'key': key, 'value': value})
134
135 file_fh.close()
136 # write out new file
Brian Harringaf019fb2012-05-10 15:06:13 -0700137 osutils.WriteFile(filename, '\n'.join(file_lines) + '\n')
David James8c846492011-01-25 17:07:29 -0800138
139
Mike Frysinger5b34d732013-01-17 15:11:58 -0500140def RevGitFile(filename, data, retries=5, dryrun=False):
David James8c846492011-01-25 17:07:29 -0800141 """Update and push the git file.
142
Mike Frysinger5b34d732013-01-17 15:11:58 -0500143 Args:
144 filename: file to modify that is in a git repo already
145 data: A dict of key/values to update in |filename|
146 retries: The number of times to retry before giving up, default: 5
Matt Tennante8179042013-10-01 15:47:32 -0700147 dryrun: If True, do not actually commit the change.
David James8c846492011-01-25 17:07:29 -0800148 """
149 prebuilt_branch = 'prebuilt_branch'
David James1b6e67a2011-05-19 21:32:38 -0700150 cwd = os.path.abspath(os.path.dirname(filename))
David James97d95872012-11-16 15:09:56 -0800151 commit = git.RunGit(cwd, ['rev-parse', 'HEAD']).output.rstrip()
Mike Frysinger5b34d732013-01-17 15:11:58 -0500152 description = '%s: updating %s' % (os.path.basename(filename),
153 ', '.join(data.keys()))
154 # UpdateLocalFile will print out the keys/values for us.
Mike Frysingerff441bf2014-05-24 13:47:21 -0400155 print('Revving git file %s' % filename)
David James66009462012-03-25 10:08:38 -0700156
David James8c846492011-01-25 17:07:29 -0800157 try:
David James97d95872012-11-16 15:09:56 -0800158 git.CreatePushBranch(prebuilt_branch, cwd)
Mike Frysinger5b34d732013-01-17 15:11:58 -0500159 for key, value in data.iteritems():
160 UpdateLocalFile(filename, value, key)
David James97d95872012-11-16 15:09:56 -0800161 git.RunGit(cwd, ['add', filename])
162 git.RunGit(cwd, ['commit', '-m', description])
163 git.PushWithRetry(prebuilt_branch, cwd, dryrun=dryrun, retries=retries)
David James8c846492011-01-25 17:07:29 -0800164 finally:
David James67d73252013-09-19 17:33:12 -0700165 git.RunGit(cwd, ['checkout', commit])
David James8c846492011-01-25 17:07:29 -0800166
167
168def GetVersion():
169 """Get the version to put in LATEST and update the git version with."""
Mike Frysinger0b92cfe2012-12-13 02:13:45 -0500170 return datetime.datetime.now().strftime('%Y.%m.%d.%H%M%S')
David James8c846492011-01-25 17:07:29 -0800171
172
Mike Frysinger540883b2014-05-24 13:46:16 -0400173def _GsUpload(gs_context, acl, local_file, remote_file):
David James8c846492011-01-25 17:07:29 -0800174 """Upload to GS bucket.
175
176 Args:
Mike Frysinger540883b2014-05-24 13:46:16 -0400177 gs_context: A lib.gs.GSContext instance.
178 acl: The ACL to use for uploading the file.
Matt Tennante8179042013-10-01 15:47:32 -0700179 local_file: The local file to be uploaded.
180 remote_file: The remote location to upload to.
David James8c846492011-01-25 17:07:29 -0800181
182 Returns:
183 Return the arg tuple of two if the upload failed
184 """
Scott Zawalskiab1bed32011-03-16 15:24:24 -0700185 CANNED_ACLS = ['public-read', 'private', 'bucket-owner-read',
186 'authenticated-read', 'bucket-owner-full-control',
187 'public-read-write']
Scott Zawalskiab1bed32011-03-16 15:24:24 -0700188 if acl in CANNED_ACLS:
David James9374aac2013-10-08 16:00:17 -0700189 gs_context.Copy(local_file, remote_file, acl=acl)
Scott Zawalskiab1bed32011-03-16 15:24:24 -0700190 else:
191 # For private uploads we assume that the overlay board is set up properly
David James015af872012-06-19 15:24:36 -0700192 # and a googlestore_acl.xml is present. Otherwise, this script errors.
David James9374aac2013-10-08 16:00:17 -0700193 gs_context.Copy(local_file, remote_file, acl='private')
Gabe Black40169e62014-06-17 15:23:47 -0700194 if acl.endswith('.xml'):
195 # Apply the passed in ACL xml file to the uploaded object.
196 gs_context.SetACL(remote_file, acl=acl)
197 else:
198 gs_context.ChangeACL(remote_file, acl_args_file=acl)
Scott Zawalskiab1bed32011-03-16 15:24:24 -0700199
Mike Frysingercc838832014-05-24 13:10:30 -0400200
Mike Frysinger540883b2014-05-24 13:46:16 -0400201def RemoteUpload(gs_context, acl, files, pool=10):
David James8c846492011-01-25 17:07:29 -0800202 """Upload to google storage.
203
204 Create a pool of process and call _GsUpload with the proper arguments.
205
206 Args:
Mike Frysinger540883b2014-05-24 13:46:16 -0400207 gs_context: A lib.gs.GSContext instance.
David Jamesfd0b0852011-02-23 11:15:36 -0800208 acl: The canned acl used for uploading. acl can be one of: "public-read",
209 "public-read-write", "authenticated-read", "bucket-owner-read",
210 "bucket-owner-full-control", or "private".
David James8c846492011-01-25 17:07:29 -0800211 files: dictionary with keys to local files and values to remote path.
212 pool: integer of maximum proesses to have at the same time.
213
214 Returns:
215 Return a set of tuple arguments of the failed uploads
216 """
Mike Frysinger540883b2014-05-24 13:46:16 -0400217 upload = functools.partial(_GsUpload, gs_context, acl)
218 tasks = [[key, value] for key, value in files.iteritems()]
219 parallel.RunTasksInProcessPool(upload, tasks, pool)
David James8c846492011-01-25 17:07:29 -0800220
221
222def GenerateUploadDict(base_local_path, base_remote_path, pkgs):
223 """Build a dictionary of local remote file key pairs to upload.
224
225 Args:
226 base_local_path: The base path to the files on the local hard drive.
Matt Tennante8179042013-10-01 15:47:32 -0700227 base_remote_path: The base path to the remote paths.
David James8c846492011-01-25 17:07:29 -0800228 pkgs: The packages to upload.
229
230 Returns:
231 Returns a dictionary of local_path/remote_path pairs
232 """
233 upload_files = {}
234 for pkg in pkgs:
235 suffix = pkg['CPV'] + '.tbz2'
236 local_path = os.path.join(base_local_path, suffix)
237 assert os.path.exists(local_path)
238 remote_path = '%s/%s' % (base_remote_path.rstrip('/'), suffix)
239 upload_files[local_path] = remote_path
240
Bertrand SIMONNET22e828b2014-11-11 16:27:06 -0800241 debugsuffix = pkg['CPV'] + '.debug.tbz2'
242 local_path = os.path.join(base_local_path, debugsuffix)
243 if not os.path.exists(local_path):
244 continue
245 remote_path = '%s/%s' % (base_remote_path.rstrip('/'), debugsuffix)
246 upload_files[local_path] = remote_path
247
David James8c846492011-01-25 17:07:29 -0800248 return upload_files
249
Mike Frysingercc838832014-05-24 13:10:30 -0400250
Peter Mayo950e41a2014-02-06 21:07:33 +0000251def GetBoardOverlay(build_path, target):
David Jamese5867812012-10-19 12:02:20 -0700252 """Get the path to the board variant.
Mike Frysinger1a736a82013-12-12 01:50:59 -0500253
David James8c846492011-01-25 17:07:29 -0800254 Args:
255 build_path: The path to the root of the build directory
David Jamese5867812012-10-19 12:02:20 -0700256 target: The target board as a BuildTarget object.
Mike Frysinger1a736a82013-12-12 01:50:59 -0500257
David James8c846492011-01-25 17:07:29 -0800258 Returns:
David Jamese5867812012-10-19 12:02:20 -0700259 The last overlay configured for the given board as a string.
David James8c846492011-01-25 17:07:29 -0800260 """
David Jamese5867812012-10-19 12:02:20 -0700261 board = target.board_variant
Alex Deymo075c2292014-09-04 18:31:50 -0700262 overlays = portage_util.FindOverlays(constants.BOTH_OVERLAYS, board,
263 buildroot=build_path)
David Jamese5867812012-10-19 12:02:20 -0700264 # We only care about the last entry.
265 return overlays[-1]
David James8c846492011-01-25 17:07:29 -0800266
267
268def DeterminePrebuiltConfFile(build_path, target):
269 """Determine the prebuilt.conf file that needs to be updated for prebuilts.
270
Mike Frysinger1a736a82013-12-12 01:50:59 -0500271 Args:
272 build_path: The path to the root of the build directory
273 target: String representation of the board. This includes host and board
274 targets
David James8c846492011-01-25 17:07:29 -0800275
Mike Frysinger1a736a82013-12-12 01:50:59 -0500276 Returns:
277 A string path to a prebuilt.conf file to be updated.
David James8c846492011-01-25 17:07:29 -0800278 """
David James4058b0d2011-12-08 21:24:50 -0800279 if _HOST_ARCH == target:
David James8c846492011-01-25 17:07:29 -0800280 # We are host.
281 # Without more examples of hosts this is a kludge for now.
282 # TODO(Scottz): as new host targets come online expand this to
283 # work more like boards.
Chris Sosa471532a2011-02-01 15:10:06 -0800284 make_path = _PREBUILT_MAKE_CONF[target]
David James8c846492011-01-25 17:07:29 -0800285 else:
286 # We are a board
Peter Mayo950e41a2014-02-06 21:07:33 +0000287 board = GetBoardOverlay(build_path, target)
David James8c846492011-01-25 17:07:29 -0800288 make_path = os.path.join(board, 'prebuilt.conf')
289
290 return make_path
291
292
293def UpdateBinhostConfFile(path, key, value):
294 """Update binhost config file file with key=value.
295
296 Args:
297 path: Filename to update.
298 key: Key to update.
299 value: New value for key.
300 """
301 cwd = os.path.dirname(os.path.abspath(path))
302 filename = os.path.basename(path)
Brian Harringaf019fb2012-05-10 15:06:13 -0700303 osutils.SafeMakedirs(cwd)
David Jamesf6e8fb72013-05-10 08:58:43 -0700304 if not git.GetCurrentBranch(cwd):
305 git.CreatePushBranch(constants.STABLE_EBUILD_BRANCH, cwd, sync=False)
Brian Harring22edb442012-05-11 23:55:18 -0700306 osutils.WriteFile(path, '', mode='a')
David James8c846492011-01-25 17:07:29 -0800307 UpdateLocalFile(path, value, key)
David James67d73252013-09-19 17:33:12 -0700308 git.RunGit(cwd, ['add', filename])
Mike Frysinger109cada2013-01-17 15:50:44 -0500309 description = '%s: updating %s' % (os.path.basename(filename), key)
David James67d73252013-09-19 17:33:12 -0700310 git.RunGit(cwd, ['commit', '-m', description])
David James8c846492011-01-25 17:07:29 -0800311
312
Mike Frysinger212e4292014-05-24 15:15:44 -0400313def GenerateHtmlIndex(files, index, board, version):
314 """Given the list of |files|, generate an index.html at |index|.
315
316 Args:
317 files: The list of files to link to.
318 index: The path to the html index.
319 board: Name of the board this index is for.
320 version: Build version this index is for.
321 """
322 head = """<html>
323<head>
324 <title>Package Prebuilt Index: %(board)s / %(version)s</title>
325</head>
326<body>
327<h2>Package Prebuilt Index: %(board)s / %(version)s</h2>"""
328 head %= {
329 'board': board,
330 'version': version,
331 }
332
333 files = files + [
334 '.|Google Storage Index',
335 '..|',
336 ]
337 commands.GenerateHtmlIndex(index, files, head=head)
338
339
David Jamesce093af2011-02-23 15:21:58 -0800340def _GrabAllRemotePackageIndexes(binhost_urls):
David James05bcb2b2011-02-09 09:25:47 -0800341 """Grab all of the packages files associated with a list of binhost_urls.
342
David James05bcb2b2011-02-09 09:25:47 -0800343 Args:
344 binhost_urls: The URLs for the directories containing the Packages files we
345 want to grab.
David James05bcb2b2011-02-09 09:25:47 -0800346
347 Returns:
348 A list of PackageIndex objects.
349 """
350 pkg_indexes = []
351 for url in binhost_urls:
David James32faafe2012-06-08 14:25:03 -0700352 pkg_index = binpkg.GrabRemotePackageIndex(url)
David James05bcb2b2011-02-09 09:25:47 -0800353 if pkg_index:
354 pkg_indexes.append(pkg_index)
David James05bcb2b2011-02-09 09:25:47 -0800355 return pkg_indexes
356
357
David Jamesc0f158a2011-02-22 16:07:29 -0800358class PrebuiltUploader(object):
359 """Synchronize host and board prebuilts."""
David James8c846492011-01-25 17:07:29 -0800360
Mike Frysinger86509232014-05-24 13:18:37 -0400361 def __init__(self, upload_location, acl, binhost_base_url, pkg_indexes,
362 build_path, packages, skip_upload, binhost_conf_dir, dryrun,
Mike Frysinger8092a632014-05-24 13:25:46 -0400363 target, slave_targets, version):
David Jamesc0f158a2011-02-22 16:07:29 -0800364 """Constructor for prebuilt uploader object.
David James8c846492011-01-25 17:07:29 -0800365
David Jamesc0f158a2011-02-22 16:07:29 -0800366 This object can upload host or prebuilt files to Google Storage.
David James8c846492011-01-25 17:07:29 -0800367
David Jamesc0f158a2011-02-22 16:07:29 -0800368 Args:
369 upload_location: The upload location.
David Jamesfd0b0852011-02-23 11:15:36 -0800370 acl: The canned acl used for uploading to Google Storage. acl can be one
371 of: "public-read", "public-read-write", "authenticated-read",
Matt Tennante8179042013-10-01 15:47:32 -0700372 "bucket-owner-read", "bucket-owner-full-control", "project-private",
373 or "private" (see "gsutil help acls"). If we are not uploading to
374 Google Storage, this parameter is unused.
David Jamesfd0b0852011-02-23 11:15:36 -0800375 binhost_base_url: The URL used for downloading the prebuilts.
David Jamesc0f158a2011-02-22 16:07:29 -0800376 pkg_indexes: Old uploaded prebuilts to compare against. Instead of
377 uploading duplicate files, we just link to the old files.
David James615e5b52011-06-03 11:10:15 -0700378 build_path: The path to the directory containing the chroot.
379 packages: Packages to upload.
David James32b0b2f2011-07-13 20:56:50 -0700380 skip_upload: Don't actually upload the tarballs.
381 binhost_conf_dir: Directory where to store binhost.conf files.
Mike Frysinger86509232014-05-24 13:18:37 -0400382 dryrun: Don't push or upload prebuilts.
David James4058b0d2011-12-08 21:24:50 -0800383 target: BuildTarget managed by this builder.
384 slave_targets: List of BuildTargets managed by slave builders.
Mike Frysinger8092a632014-05-24 13:25:46 -0400385 version: A unique string, intended to be included in the upload path,
386 which identifies the version number of the uploaded prebuilts.
David Jamesc0f158a2011-02-22 16:07:29 -0800387 """
388 self._upload_location = upload_location
David Jamesfd0b0852011-02-23 11:15:36 -0800389 self._acl = acl
David Jamesc0f158a2011-02-22 16:07:29 -0800390 self._binhost_base_url = binhost_base_url
391 self._pkg_indexes = pkg_indexes
David James615e5b52011-06-03 11:10:15 -0700392 self._build_path = build_path
393 self._packages = set(packages)
Mike Frysingerf5f809a2013-02-12 13:47:37 -0500394 self._found_packages = set()
David James8ece7ee2011-06-29 16:02:30 -0700395 self._skip_upload = skip_upload
David James32b0b2f2011-07-13 20:56:50 -0700396 self._binhost_conf_dir = binhost_conf_dir
Mike Frysinger86509232014-05-24 13:18:37 -0400397 self._dryrun = dryrun
David James4058b0d2011-12-08 21:24:50 -0800398 self._target = target
399 self._slave_targets = slave_targets
Mike Frysinger8092a632014-05-24 13:25:46 -0400400 self._version = version
Mike Frysinger540883b2014-05-24 13:46:16 -0400401 self._gs_context = gs.GSContext(retries=_RETRIES, sleep=_SLEEP_TIME,
402 dry_run=self._dryrun)
403
404 def _Upload(self, local_file, remote_file):
405 """Wrapper around _GsUpload"""
406 _GsUpload(self._gs_context, self._acl, local_file, remote_file)
David James615e5b52011-06-03 11:10:15 -0700407
408 def _ShouldFilterPackage(self, pkg):
409 if not self._packages:
410 return False
411 pym_path = os.path.abspath(os.path.join(self._build_path, _PYM_PATH))
David James710b7dc2012-02-07 16:49:59 -0800412 sys.path.insert(0, pym_path)
Don Garrett25f309a2014-03-19 14:02:12 -0700413 # pylint: disable=F0401
David James615e5b52011-06-03 11:10:15 -0700414 import portage.versions
415 cat, pkgname = portage.versions.catpkgsplit(pkg['CPV'])[0:2]
416 cp = '%s/%s' % (cat, pkgname)
Mike Frysingerf5f809a2013-02-12 13:47:37 -0500417 self._found_packages.add(cp)
David James615e5b52011-06-03 11:10:15 -0700418 return pkgname not in self._packages and cp not in self._packages
David James8c846492011-01-25 17:07:29 -0800419
David Jamesc0f158a2011-02-22 16:07:29 -0800420 def _UploadPrebuilt(self, package_path, url_suffix):
421 """Upload host or board prebuilt files to Google Storage space.
David James8c846492011-01-25 17:07:29 -0800422
David Jamesc0f158a2011-02-22 16:07:29 -0800423 Args:
424 package_path: The path to the packages dir.
David Jamesce093af2011-02-23 15:21:58 -0800425 url_suffix: The remote subdirectory where we should upload the packages.
David Jamesc0f158a2011-02-22 16:07:29 -0800426 """
David Jamesc0f158a2011-02-22 16:07:29 -0800427 # Process Packages file, removing duplicates and filtered packages.
David James32faafe2012-06-08 14:25:03 -0700428 pkg_index = binpkg.GrabLocalPackageIndex(package_path)
David Jamesc0f158a2011-02-22 16:07:29 -0800429 pkg_index.SetUploadLocation(self._binhost_base_url, url_suffix)
David James615e5b52011-06-03 11:10:15 -0700430 pkg_index.RemoveFilteredPackages(self._ShouldFilterPackage)
David Jamesc0f158a2011-02-22 16:07:29 -0800431 uploads = pkg_index.ResolveDuplicateUploads(self._pkg_indexes)
Mike Frysingerf5f809a2013-02-12 13:47:37 -0500432 unmatched_pkgs = self._packages - self._found_packages
433 if unmatched_pkgs:
434 cros_build_lib.Warning('unable to match packages: %r' % unmatched_pkgs)
David James05bcb2b2011-02-09 09:25:47 -0800435
David Jamesc0f158a2011-02-22 16:07:29 -0800436 # Write Packages file.
David James5ab67e32014-10-24 08:19:59 -0700437 pkg_index.header['TTL'] = _BINPKG_TTL
David Jamesc0f158a2011-02-22 16:07:29 -0800438 tmp_packages_file = pkg_index.WriteToNamedTemporaryFile()
David James05bcb2b2011-02-09 09:25:47 -0800439
David Jamesc0f158a2011-02-22 16:07:29 -0800440 remote_location = '%s/%s' % (self._upload_location.rstrip('/'), url_suffix)
David James015af872012-06-19 15:24:36 -0700441 assert remote_location.startswith('gs://')
David James05bcb2b2011-02-09 09:25:47 -0800442
David James015af872012-06-19 15:24:36 -0700443 # Build list of files to upload.
444 upload_files = GenerateUploadDict(package_path, remote_location, uploads)
445 remote_file = '%s/Packages' % remote_location.rstrip('/')
446 upload_files[tmp_packages_file.name] = remote_file
447
Mike Frysinger540883b2014-05-24 13:46:16 -0400448 RemoteUpload(self._gs_context, self._acl, upload_files)
David James8c846492011-01-25 17:07:29 -0800449
Mike Frysinger212e4292014-05-24 15:15:44 -0400450 with tempfile.NamedTemporaryFile(
451 prefix='chromite.upload_prebuilts.index.') as index:
452 GenerateHtmlIndex(
453 [x[len(remote_location) + 1:] for x in upload_files.values()],
454 index.name, self._target, self._version)
455 self._Upload(index.name, '%s/index.html' % remote_location.rstrip('/'))
456
457 link_name = 'Prebuilts[%s]: %s' % (self._target, self._version)
458 url = '%s%s/index.html' % (gs.PUBLIC_BASE_HTTPS_URL,
459 remote_location[len(gs.BASE_GS_URL):])
460 cros_build_lib.PrintBuildbotLink(link_name, url)
461
Mike Frysinger8092a632014-05-24 13:25:46 -0400462 def _UploadSdkTarball(self, board_path, url_suffix, prepackaged,
Mike Frysinger9e979b92012-11-29 02:55:09 -0500463 toolchain_tarballs, toolchain_upload_path):
464 """Upload a tarball of the sdk at the specified path to Google Storage.
David James8fa34ea2011-04-15 13:00:20 -0700465
466 Args:
467 board_path: The path to the board dir.
468 url_suffix: The remote subdirectory where we should upload the packages.
Zdenek Behan62a57792012-08-31 15:09:08 +0200469 prepackaged: If given, a tarball that has been packaged outside of this
470 script and should be used.
Mike Frysinger9e979b92012-11-29 02:55:09 -0500471 toolchain_tarballs: List of toolchain tarballs to upload.
472 toolchain_upload_path: Path under the bucket to place toolchain tarballs.
David James8fa34ea2011-04-15 13:00:20 -0700473 """
474 remote_location = '%s/%s' % (self._upload_location.rstrip('/'), url_suffix)
475 assert remote_location.startswith('gs://')
Zdenek Behan86c15e92012-10-13 00:55:47 +0200476 boardname = os.path.basename(board_path.rstrip('/'))
477 # We do not upload non SDK board tarballs,
478 assert boardname == constants.CHROOT_BUILDER_BOARD
479 assert prepackaged is not None
Zdenek Behan62a57792012-08-31 15:09:08 +0200480
Mike Frysinger8092a632014-05-24 13:25:46 -0400481 version_str = self._version[len('chroot-'):]
Mike Frysinger8e727a32013-01-16 16:57:53 -0500482 remote_tarfile = toolchain.GetSdkURL(
483 for_gsutil=True, suburl='cros-sdk-%s.tar.xz' % (version_str,))
Zdenek Behan86c15e92012-10-13 00:55:47 +0200484 # For SDK, also upload the manifest which is guaranteed to exist
485 # by the builderstage.
Mike Frysinger540883b2014-05-24 13:46:16 -0400486 self._Upload(prepackaged + '.Manifest', remote_tarfile + '.Manifest')
487 self._Upload(prepackaged, remote_tarfile)
Zdenek Behan86c15e92012-10-13 00:55:47 +0200488
Mike Frysinger9e979b92012-11-29 02:55:09 -0500489 # Post the toolchain tarballs too.
490 for tarball in toolchain_tarballs:
491 target, local_path = tarball.split(':')
492 suburl = toolchain_upload_path % {'target': target}
493 remote_path = toolchain.GetSdkURL(for_gsutil=True, suburl=suburl)
Mike Frysinger540883b2014-05-24 13:46:16 -0400494 self._Upload(local_path, remote_path)
Mike Frysinger9e979b92012-11-29 02:55:09 -0500495
Zdenek Behan86c15e92012-10-13 00:55:47 +0200496 # Finally, also update the pointer to the latest SDK on which polling
497 # scripts rely.
David James4bc13702013-03-26 08:08:04 -0700498 with osutils.TempDir() as tmpdir:
Zdenek Behan86c15e92012-10-13 00:55:47 +0200499 pointerfile = os.path.join(tmpdir, 'cros-sdk-latest.conf')
Mike Frysinger8e727a32013-01-16 16:57:53 -0500500 remote_pointerfile = toolchain.GetSdkURL(for_gsutil=True,
501 suburl='cros-sdk-latest.conf')
Zdenek Behan86c15e92012-10-13 00:55:47 +0200502 osutils.WriteFile(pointerfile, 'LATEST_SDK="%s"' % version_str)
Mike Frysinger540883b2014-05-24 13:46:16 -0400503 self._Upload(pointerfile, remote_pointerfile)
Zdenek Behan33a34112012-09-10 21:07:51 +0200504
Chris Sosa6a5dceb2012-05-14 13:48:56 -0700505 def _GetTargets(self):
506 """Retuns the list of targets to use."""
507 targets = self._slave_targets[:]
508 if self._target:
509 targets.append(self._target)
510
511 return targets
512
Mike Frysinger8092a632014-05-24 13:25:46 -0400513 def SyncHostPrebuilts(self, key, git_sync, sync_binhost_conf):
David Jamesc0f158a2011-02-22 16:07:29 -0800514 """Synchronize host prebuilt files.
David James05bcb2b2011-02-09 09:25:47 -0800515
David Jamesc0f158a2011-02-22 16:07:29 -0800516 This function will sync both the standard host packages, plus the host
517 packages associated with all targets that have been "setup" with the
518 current host's chroot. For instance, if this host has been used to build
519 x86-generic, it will sync the host packages associated with
520 'i686-pc-linux-gnu'. If this host has also been used to build arm-generic,
521 it will also sync the host packages associated with
522 'armv7a-cros-linux-gnueabi'.
David James05bcb2b2011-02-09 09:25:47 -0800523
David Jamesc0f158a2011-02-22 16:07:29 -0800524 Args:
David Jamesc0f158a2011-02-22 16:07:29 -0800525 key: The variable key to update in the git file.
526 git_sync: If set, update make.conf of target to reference the latest
527 prebuilt packages generated here.
528 sync_binhost_conf: If set, update binhost config file in
529 chromiumos-overlay for the host.
530 """
David Jamese2488642011-11-14 16:15:20 -0800531 # Slave boards are listed before the master board so that the master board
532 # takes priority (i.e. x86-generic preflight host prebuilts takes priority
533 # over preflight host prebuilts from other builders.)
534 binhost_urls = []
Chris Sosa6a5dceb2012-05-14 13:48:56 -0700535 for target in self._GetTargets():
Mike Frysinger8092a632014-05-24 13:25:46 -0400536 url_suffix = _REL_HOST_PATH % {'version': self._version,
David James4058b0d2011-12-08 21:24:50 -0800537 'host_arch': _HOST_ARCH,
538 'target': target}
David Jamese2488642011-11-14 16:15:20 -0800539 packages_url_suffix = '%s/packages' % url_suffix.rstrip('/')
David James05bcb2b2011-02-09 09:25:47 -0800540
Mike Frysinger540883b2014-05-24 13:46:16 -0400541 if self._target == target and not self._skip_upload:
David Jamese2488642011-11-14 16:15:20 -0800542 # Upload prebuilts.
543 package_path = os.path.join(self._build_path, _HOST_PACKAGES_PATH)
544 self._UploadPrebuilt(package_path, packages_url_suffix)
David James8ece7ee2011-06-29 16:02:30 -0700545
David Jamese2488642011-11-14 16:15:20 -0800546 # Record URL where prebuilts were uploaded.
547 binhost_urls.append('%s/%s/' % (self._binhost_base_url.rstrip('/'),
548 packages_url_suffix.rstrip('/')))
549
David James20b2b6f2011-11-18 15:11:58 -0800550 binhost = ' '.join(binhost_urls)
David James8ece7ee2011-06-29 16:02:30 -0700551 if git_sync:
552 git_file = os.path.join(self._build_path,
David James4058b0d2011-12-08 21:24:50 -0800553 _PREBUILT_MAKE_CONF[_HOST_ARCH])
Mike Frysinger86509232014-05-24 13:18:37 -0400554 RevGitFile(git_file, {key: binhost}, dryrun=self._dryrun)
David James8ece7ee2011-06-29 16:02:30 -0700555 if sync_binhost_conf:
David James32b0b2f2011-07-13 20:56:50 -0700556 binhost_conf = os.path.join(self._build_path, self._binhost_conf_dir,
David James4058b0d2011-12-08 21:24:50 -0800557 'host', '%s-%s.conf' % (_HOST_ARCH, key))
David Jamese2488642011-11-14 16:15:20 -0800558 UpdateBinhostConfFile(binhost_conf, key, binhost)
David Jamesc0f158a2011-02-22 16:07:29 -0800559
Mike Frysinger8092a632014-05-24 13:25:46 -0400560 def SyncBoardPrebuilts(self, key, git_sync, sync_binhost_conf,
Mike Frysinger9e979b92012-11-29 02:55:09 -0500561 upload_board_tarball, prepackaged_board,
562 toolchain_tarballs, toolchain_upload_path):
David Jamesc0f158a2011-02-22 16:07:29 -0800563 """Synchronize board prebuilt files.
564
565 Args:
David Jamesc0f158a2011-02-22 16:07:29 -0800566 key: The variable key to update in the git file.
567 git_sync: If set, update make.conf of target to reference the latest
568 prebuilt packages generated here.
569 sync_binhost_conf: If set, update binhost config file in
570 chromiumos-overlay for the current board.
David James8fa34ea2011-04-15 13:00:20 -0700571 upload_board_tarball: Include a tarball of the board in our upload.
Zdenek Behan62a57792012-08-31 15:09:08 +0200572 prepackaged_board: A tarball of the board built outside of this script.
Mike Frysinger9e979b92012-11-29 02:55:09 -0500573 toolchain_tarballs: A list of toolchain tarballs to upload.
574 toolchain_upload_path: Path under the bucket to place toolchain tarballs.
David Jamesc0f158a2011-02-22 16:07:29 -0800575 """
Chris Sosa6a5dceb2012-05-14 13:48:56 -0700576 for target in self._GetTargets():
David Jamese2488642011-11-14 16:15:20 -0800577 board_path = os.path.join(self._build_path,
David James4058b0d2011-12-08 21:24:50 -0800578 _BOARD_PATH % {'board': target.board_variant})
David Jamese2488642011-11-14 16:15:20 -0800579 package_path = os.path.join(board_path, 'packages')
Mike Frysinger8092a632014-05-24 13:25:46 -0400580 url_suffix = _REL_BOARD_PATH % {'target': target,
581 'version': self._version}
David Jamese2488642011-11-14 16:15:20 -0800582 packages_url_suffix = '%s/packages' % url_suffix.rstrip('/')
David James8fa34ea2011-04-15 13:00:20 -0700583
Matt Tennante8179042013-10-01 15:47:32 -0700584 # Process the target board differently if it is the main --board.
Mike Frysinger540883b2014-05-24 13:46:16 -0400585 if self._target == target and not self._skip_upload:
Matt Tennante8179042013-10-01 15:47:32 -0700586 # This strips "chroot" prefix because that is sometimes added as the
587 # --prepend-version argument (e.g. by chromiumos-sdk bot).
588 # TODO(build): Clean it up to be less hard-coded.
Mike Frysinger8092a632014-05-24 13:25:46 -0400589 version_str = self._version[len('chroot-'):]
Mike Frysinger9e979b92012-11-29 02:55:09 -0500590
David Jamese2488642011-11-14 16:15:20 -0800591 # Upload board tarballs in the background.
592 if upload_board_tarball:
Mike Frysinger9e979b92012-11-29 02:55:09 -0500593 if toolchain_upload_path:
594 toolchain_upload_path %= {'version': version_str}
595 tar_process = multiprocessing.Process(
596 target=self._UploadSdkTarball,
Mike Frysinger8092a632014-05-24 13:25:46 -0400597 args=(board_path, url_suffix, prepackaged_board,
Mike Frysinger9e979b92012-11-29 02:55:09 -0500598 toolchain_tarballs, toolchain_upload_path))
David Jamese2488642011-11-14 16:15:20 -0800599 tar_process.start()
David James8fa34ea2011-04-15 13:00:20 -0700600
David Jamese2488642011-11-14 16:15:20 -0800601 # Upload prebuilts.
602 self._UploadPrebuilt(package_path, packages_url_suffix)
David James8fa34ea2011-04-15 13:00:20 -0700603
David Jamese2488642011-11-14 16:15:20 -0800604 # Make sure we finished uploading the board tarballs.
605 if upload_board_tarball:
606 tar_process.join()
607 assert tar_process.exitcode == 0
608 # TODO(zbehan): This should be done cleaner.
Zdenek Behan33a34112012-09-10 21:07:51 +0200609 if target.board == constants.CHROOT_BUILDER_BOARD:
David Jamese2488642011-11-14 16:15:20 -0800610 sdk_conf = os.path.join(self._build_path, self._binhost_conf_dir,
Mike Frysinger5b34d732013-01-17 15:11:58 -0500611 'host/sdk_version.conf')
612 sdk_settings = {
Mike Frysinger9e979b92012-11-29 02:55:09 -0500613 'SDK_LATEST_VERSION': version_str,
614 'TC_PATH': toolchain_upload_path,
Mike Frysinger5b34d732013-01-17 15:11:58 -0500615 }
Mike Frysinger86509232014-05-24 13:18:37 -0400616 RevGitFile(sdk_conf, sdk_settings, dryrun=self._dryrun)
David Jamesc0f158a2011-02-22 16:07:29 -0800617
David Jamese2488642011-11-14 16:15:20 -0800618 # Record URL where prebuilts were uploaded.
619 url_value = '%s/%s/' % (self._binhost_base_url.rstrip('/'),
620 packages_url_suffix.rstrip('/'))
621
622 if git_sync:
David James4058b0d2011-12-08 21:24:50 -0800623 git_file = DeterminePrebuiltConfFile(self._build_path, target)
Mike Frysinger86509232014-05-24 13:18:37 -0400624 RevGitFile(git_file, {key: url_value}, dryrun=self._dryrun)
Matt Tennante8179042013-10-01 15:47:32 -0700625
David Jamese2488642011-11-14 16:15:20 -0800626 if sync_binhost_conf:
Matt Tennante8179042013-10-01 15:47:32 -0700627 # Update the binhost configuration file in git.
David Jamese2488642011-11-14 16:15:20 -0800628 binhost_conf = os.path.join(self._build_path, self._binhost_conf_dir,
David James4058b0d2011-12-08 21:24:50 -0800629 'target', '%s-%s.conf' % (target, key))
David Jamese2488642011-11-14 16:15:20 -0800630 UpdateBinhostConfFile(binhost_conf, key, url_value)
David James05bcb2b2011-02-09 09:25:47 -0800631
632
Chris Sosa6a5dceb2012-05-14 13:48:56 -0700633def _AddSlaveBoard(_option, _opt_str, value, parser):
634 """Callback that adds a slave board to the list of slave targets."""
David James4058b0d2011-12-08 21:24:50 -0800635 parser.values.slave_targets.append(BuildTarget(value))
636
637
Chris Sosa6a5dceb2012-05-14 13:48:56 -0700638def _AddSlaveProfile(_option, _opt_str, value, parser):
639 """Callback that adds a slave profile to the list of slave targets."""
David James4058b0d2011-12-08 21:24:50 -0800640 if not parser.values.slave_targets:
Mike Frysinger86509232014-05-24 13:18:37 -0400641 parser.error('Must specify --slave-board before --slave-profile')
David James4058b0d2011-12-08 21:24:50 -0800642 if parser.values.slave_targets[-1].profile is not None:
Mike Frysinger86509232014-05-24 13:18:37 -0400643 parser.error('Cannot specify --slave-profile twice for same board')
David James4058b0d2011-12-08 21:24:50 -0800644 parser.values.slave_targets[-1].profile = value
645
646
Mike Frysinger86509232014-05-24 13:18:37 -0400647def ParseOptions(argv):
Chris Sosa6a5dceb2012-05-14 13:48:56 -0700648 """Returns options given by the user and the target specified.
649
Mike Frysinger86509232014-05-24 13:18:37 -0400650 Args:
651 argv: The args to parse.
652
Mike Frysinger1a736a82013-12-12 01:50:59 -0500653 Returns:
654 A tuple containing a parsed options object and BuildTarget.
655 The target instance is None if no board is specified.
Chris Sosa6a5dceb2012-05-14 13:48:56 -0700656 """
Mike Frysinger86509232014-05-24 13:18:37 -0400657 parser = commandline.OptionParser()
David James8c846492011-01-25 17:07:29 -0800658 parser.add_option('-H', '--binhost-base-url', dest='binhost_base_url',
659 default=_BINHOST_BASE_URL,
660 help='Base URL to use for binhost in make.conf updates')
661 parser.add_option('', '--previous-binhost-url', action='append',
662 default=[], dest='previous_binhost_url',
663 help='Previous binhost URL')
664 parser.add_option('-b', '--board', dest='board', default=None,
665 help='Board type that was built on this machine')
Zdenek Behan62a57792012-08-31 15:09:08 +0200666 parser.add_option('-B', '--prepackaged-tarball', dest='prepackaged_tarball',
667 default=None,
668 help='Board tarball prebuilt outside of this script.')
Mike Frysinger9e979b92012-11-29 02:55:09 -0500669 parser.add_option('--toolchain-tarball', dest='toolchain_tarballs',
670 action='append', default=[],
671 help='Redistributable toolchain tarball.')
672 parser.add_option('--toolchain-upload-path', default='',
673 help='Path to place toolchain tarballs in the sdk tree.')
David James4058b0d2011-12-08 21:24:50 -0800674 parser.add_option('', '--profile', dest='profile', default=None,
675 help='Profile that was built on this machine')
676 parser.add_option('', '--slave-board', default=[], action='callback',
677 dest='slave_targets', type='string',
Chris Sosa6a5dceb2012-05-14 13:48:56 -0700678 callback=_AddSlaveBoard,
David James4058b0d2011-12-08 21:24:50 -0800679 help='Board type that was built on a slave machine. To '
680 'add a profile to this board, use --slave-profile.')
681 parser.add_option('', '--slave-profile', action='callback', type='string',
Chris Sosa6a5dceb2012-05-14 13:48:56 -0700682 callback=_AddSlaveProfile,
David James4058b0d2011-12-08 21:24:50 -0800683 help='Board profile that was built on a slave machine. '
684 'Applies to previous slave board.')
David James8c846492011-01-25 17:07:29 -0800685 parser.add_option('-p', '--build-path', dest='build_path',
David James05bcb2b2011-02-09 09:25:47 -0800686 help='Path to the directory containing the chroot')
David James615e5b52011-06-03 11:10:15 -0700687 parser.add_option('', '--packages', action='append',
688 default=[], dest='packages',
689 help='Only include the specified packages. '
690 '(Default is to include all packages.)')
David James8c846492011-01-25 17:07:29 -0800691 parser.add_option('-s', '--sync-host', dest='sync_host',
692 default=False, action='store_true',
693 help='Sync host prebuilts')
694 parser.add_option('-g', '--git-sync', dest='git_sync',
695 default=False, action='store_true',
David Jamese2488642011-11-14 16:15:20 -0800696 help='Enable git version sync (This commits to a repo.) '
697 'This is used by full builders to commit directly '
698 'to board overlays.')
David James8c846492011-01-25 17:07:29 -0800699 parser.add_option('-u', '--upload', dest='upload',
700 default=None,
701 help='Upload location')
702 parser.add_option('-V', '--prepend-version', dest='prepend_version',
703 default=None,
704 help='Add an identifier to the front of the version')
705 parser.add_option('-f', '--filters', dest='filters', action='store_true',
706 default=False,
707 help='Turn on filtering of private ebuild packages')
708 parser.add_option('-k', '--key', dest='key',
709 default='PORTAGE_BINHOST',
710 help='Key to update in make.conf / binhost.conf')
David James8ece7ee2011-06-29 16:02:30 -0700711 parser.add_option('', '--set-version', dest='set_version',
712 default=None,
713 help='Specify the version string')
David James8c846492011-01-25 17:07:29 -0800714 parser.add_option('', '--sync-binhost-conf', dest='sync_binhost_conf',
715 default=False, action='store_true',
David Jamese2488642011-11-14 16:15:20 -0800716 help='Update binhost.conf in chromiumos-overlay or '
717 'chromeos-overlay. Commit the changes, but don\'t '
718 'push them. This is used for preflight binhosts.')
David James32b0b2f2011-07-13 20:56:50 -0700719 parser.add_option('', '--binhost-conf-dir', dest='binhost_conf_dir',
David James32b0b2f2011-07-13 20:56:50 -0700720 help='Directory to commit binhost config with '
721 '--sync-binhost-conf.')
David Jamesfd0b0852011-02-23 11:15:36 -0800722 parser.add_option('-P', '--private', dest='private', action='store_true',
723 default=False, help='Mark gs:// uploads as private.')
David James8ece7ee2011-06-29 16:02:30 -0700724 parser.add_option('', '--skip-upload', dest='skip_upload',
725 action='store_true', default=False,
726 help='Skip upload step.')
David James8fa34ea2011-04-15 13:00:20 -0700727 parser.add_option('', '--upload-board-tarball', dest='upload_board_tarball',
728 action='store_true', default=False,
729 help='Upload board tarball to Google Storage.')
Mike Frysinger86509232014-05-24 13:18:37 -0400730 parser.add_option('-n', '--dry-run', dest='dryrun',
David James27fa7d12011-06-29 17:24:14 -0700731 action='store_true', default=False,
732 help='Don\'t push or upload prebuilts.')
David James8c846492011-01-25 17:07:29 -0800733
Mike Frysinger86509232014-05-24 13:18:37 -0400734 options, args = parser.parse_args(argv)
David James8c846492011-01-25 17:07:29 -0800735 if not options.build_path:
Mike Frysinger86509232014-05-24 13:18:37 -0400736 parser.error('you need provide a chroot path')
David James8ece7ee2011-06-29 16:02:30 -0700737 if not options.upload and not options.skip_upload:
Mike Frysinger86509232014-05-24 13:18:37 -0400738 parser.error('you need to provide an upload location using -u')
David James8ece7ee2011-06-29 16:02:30 -0700739 if not options.set_version and options.skip_upload:
Mike Frysinger86509232014-05-24 13:18:37 -0400740 parser.error('If you are using --skip-upload, you must specify a '
741 'version number using --set-version.')
David James9417f272011-05-26 13:24:47 -0700742 if args:
Mike Frysinger86509232014-05-24 13:18:37 -0400743 parser.error('invalid arguments passed to upload_prebuilts: %r' % args)
Scott Zawalskiab1bed32011-03-16 15:24:24 -0700744
Chris Sosa6a5dceb2012-05-14 13:48:56 -0700745 target = None
746 if options.board:
747 target = BuildTarget(options.board, options.profile)
748
749 if target in options.slave_targets:
Mike Frysinger86509232014-05-24 13:18:37 -0400750 parser.error('--board/--profile must not also be a slave target.')
David Jamese2488642011-11-14 16:15:20 -0800751
David James4058b0d2011-12-08 21:24:50 -0800752 if len(set(options.slave_targets)) != len(options.slave_targets):
Mike Frysinger86509232014-05-24 13:18:37 -0400753 parser.error('--slave-boards must not have duplicates.')
David Jamese2488642011-11-14 16:15:20 -0800754
David James4058b0d2011-12-08 21:24:50 -0800755 if options.slave_targets and options.git_sync:
Mike Frysinger86509232014-05-24 13:18:37 -0400756 parser.error('--slave-boards is not compatible with --git-sync')
David Jamese2488642011-11-14 16:15:20 -0800757
David James8ece7ee2011-06-29 16:02:30 -0700758 if (options.upload_board_tarball and options.skip_upload and
759 options.board == 'amd64-host'):
Mike Frysinger86509232014-05-24 13:18:37 -0400760 parser.error('--skip-upload is not compatible with '
761 '--upload-board-tarball and --board=amd64-host')
David James8fa34ea2011-04-15 13:00:20 -0700762
David James8ece7ee2011-06-29 16:02:30 -0700763 if (options.upload_board_tarball and not options.skip_upload and
764 not options.upload.startswith('gs://')):
Mike Frysinger86509232014-05-24 13:18:37 -0400765 parser.error('--upload-board-tarball only works with gs:// URLs.\n'
766 '--upload must be a gs:// URL.')
David James8fa34ea2011-04-15 13:00:20 -0700767
Zdenek Behan86c15e92012-10-13 00:55:47 +0200768 if options.upload_board_tarball and options.prepackaged_tarball is None:
Mike Frysinger86509232014-05-24 13:18:37 -0400769 parser.error('--upload-board-tarball requires --prepackaged-tarball')
Zdenek Behan86c15e92012-10-13 00:55:47 +0200770
Scott Zawalskiab1bed32011-03-16 15:24:24 -0700771 if options.private:
772 if options.sync_host:
Mike Frysinger86509232014-05-24 13:18:37 -0400773 parser.error('--private and --sync-host/-s cannot be specified '
774 'together; we do not support private host prebuilts')
Scott Zawalskiab1bed32011-03-16 15:24:24 -0700775
David James8ece7ee2011-06-29 16:02:30 -0700776 if not options.upload or not options.upload.startswith('gs://'):
Mike Frysinger86509232014-05-24 13:18:37 -0400777 parser.error('--private is only valid for gs:// URLs; '
778 '--upload must be a gs:// URL.')
Scott Zawalskiab1bed32011-03-16 15:24:24 -0700779
780 if options.binhost_base_url != _BINHOST_BASE_URL:
Mike Frysinger86509232014-05-24 13:18:37 -0400781 parser.error('when using --private the --binhost-base-url '
782 'is automatically derived.')
David James27fa7d12011-06-29 17:24:14 -0700783
David Jamesc31168e2014-06-05 14:40:05 -0700784 if options.sync_binhost_conf and not options.binhost_conf_dir:
785 parser.error('--sync-binhost-conf requires --binhost-conf-dir')
786
Chris Sosa6a5dceb2012-05-14 13:48:56 -0700787 return options, target
David Jamesc0f158a2011-02-22 16:07:29 -0800788
Mike Frysingercc838832014-05-24 13:10:30 -0400789
Mike Frysinger86509232014-05-24 13:18:37 -0400790def main(argv):
David Jamesdb401072011-06-10 12:17:16 -0700791 # Set umask to a sane value so that files created as root are readable.
Mike Frysinger60ec1012013-10-21 00:11:10 -0400792 os.umask(0o22)
David Jamesdb401072011-06-10 12:17:16 -0700793
Mike Frysinger86509232014-05-24 13:18:37 -0400794 options, target = ParseOptions(argv)
David Jamesc0f158a2011-02-22 16:07:29 -0800795
David James05bcb2b2011-02-09 09:25:47 -0800796 # Calculate a list of Packages index files to compare against. Whenever we
797 # upload a package, we check to make sure it's not already stored in one of
798 # the packages files we uploaded. This list of packages files might contain
799 # both board and host packages.
David Jamesce093af2011-02-23 15:21:58 -0800800 pkg_indexes = _GrabAllRemotePackageIndexes(options.previous_binhost_url)
David James8c846492011-01-25 17:07:29 -0800801
David James8ece7ee2011-06-29 16:02:30 -0700802 if options.set_version:
803 version = options.set_version
804 else:
805 version = GetVersion()
Matt Tennante8179042013-10-01 15:47:32 -0700806
David Jamesc0f158a2011-02-22 16:07:29 -0800807 if options.prepend_version:
808 version = '%s-%s' % (options.prepend_version, version)
809
Scott Zawalskiab1bed32011-03-16 15:24:24 -0700810 acl = 'public-read'
811 binhost_base_url = options.binhost_base_url
812
David Jamesadd21432013-05-21 10:04:07 -0700813 if options.private:
Scott Zawalskiab1bed32011-03-16 15:24:24 -0700814 binhost_base_url = options.upload
David Jamesadd21432013-05-21 10:04:07 -0700815 if target:
Prathmesh Prabhu421eef22014-10-16 17:13:19 -0700816 acl = portage_util.FindOverlayFile(_GOOGLESTORAGE_GSUTIL_FILE,
817 board=target.board_variant,
818 buildroot=options.build_path)
Scott Zawalskiab1bed32011-03-16 15:24:24 -0700819
820 uploader = PrebuiltUploader(options.upload, acl, binhost_base_url,
David James615e5b52011-06-03 11:10:15 -0700821 pkg_indexes, options.build_path,
David James27fa7d12011-06-29 17:24:14 -0700822 options.packages, options.skip_upload,
Mike Frysinger86509232014-05-24 13:18:37 -0400823 options.binhost_conf_dir, options.dryrun,
Mike Frysinger8092a632014-05-24 13:25:46 -0400824 target, options.slave_targets, version)
David Jamesc0f158a2011-02-22 16:07:29 -0800825
David James8c846492011-01-25 17:07:29 -0800826 if options.sync_host:
Mike Frysinger8092a632014-05-24 13:25:46 -0400827 uploader.SyncHostPrebuilts(options.key, options.git_sync,
Chris Sosa6a5dceb2012-05-14 13:48:56 -0700828 options.sync_binhost_conf)
David James8c846492011-01-25 17:07:29 -0800829
Chris Sosa62c8ff52012-06-04 15:03:12 -0700830 if options.board or options.slave_targets:
Mike Frysinger8092a632014-05-24 13:25:46 -0400831 uploader.SyncBoardPrebuilts(options.key, options.git_sync,
Chris Sosa6a5dceb2012-05-14 13:48:56 -0700832 options.sync_binhost_conf,
Zdenek Behan62a57792012-08-31 15:09:08 +0200833 options.upload_board_tarball,
Mike Frysinger9e979b92012-11-29 02:55:09 -0500834 options.prepackaged_tarball,
835 options.toolchain_tarballs,
836 options.toolchain_upload_path)