blob: 248a5e1966116639b5f5718e15eb89ec80a3bf35 [file] [log] [blame]
David James8c846492011-01-25 17:07:29 -08001#!/usr/bin/python
2# Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
3# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
5
6import datetime
7import multiprocessing
8import optparse
9import os
10import re
11import sys
12import tempfile
13import time
14
Chris Sosa471532a2011-02-01 15:10:06 -080015if __name__ == '__main__':
16 import constants
17 sys.path.append(constants.SOURCE_ROOT)
18
David James8c846492011-01-25 17:07:29 -080019from chromite.lib import cros_build_lib
20from chromite.lib.binpkg import (GrabLocalPackageIndex, GrabRemotePackageIndex,
21 PackageIndex)
22"""
23This script is used to upload host prebuilts as well as board BINHOSTS.
24
25If the URL starts with 'gs://', we upload using gsutil to Google Storage.
26Otherwise, rsync is used.
27
28After a build is successfully uploaded a file is updated with the proper
29BINHOST version as well as the target board. This file is defined in GIT_FILE
30
31
32To read more about prebuilts/binhost binary packages please refer to:
33http://sites/chromeos/for-team-members/engineering/releng/prebuilt-binaries-for-streamlining-the-build-process
34
35
36Example of uploading prebuilt amd64 host files to Google Storage:
37./prebuilt.py -p /b/cbuild/build -s -u gs://chromeos-prebuilt
38
39Example of uploading x86-dogfood binhosts to Google Storage:
40./prebuilt.py -b x86-dogfood -p /b/cbuild/build/ -u gs://chromeos-prebuilt -g
41
42Example of uploading prebuilt amd64 host files using rsync:
43./prebuilt.py -p /b/cbuild/build -s -u codf30.jail:/tmp
44"""
45
46# as per http://crosbug.com/5855 always filter the below packages
47_FILTER_PACKAGES = set()
48_RETRIES = 3
49_GSUTIL_BIN = '/b/build/third_party/gsutil/gsutil'
50_HOST_PACKAGES_PATH = 'chroot/var/lib/portage/pkgs'
David James05bcb2b2011-02-09 09:25:47 -080051_CATEGORIES_PATH = 'chroot/etc/portage/categories'
David James8c846492011-01-25 17:07:29 -080052_HOST_TARGET = 'amd64'
53_BOARD_PATH = 'chroot/build/%(board)s'
54_BOTO_CONFIG = '/home/chrome-bot/external-boto'
55# board/board-target/version/packages/'
56_REL_BOARD_PATH = 'board/%(board)s/%(version)s/packages'
57# host/host-target/version/packages/'
58_REL_HOST_PATH = 'host/%(target)s/%(version)s/packages'
59# Private overlays to look at for builds to filter
60# relative to build path
61_PRIVATE_OVERLAY_DIR = 'src/private-overlays'
62_BINHOST_BASE_URL = 'http://commondatastorage.googleapis.com/chromeos-prebuilt'
63_PREBUILT_BASE_DIR = 'src/third_party/chromiumos-overlay/chromeos/config/'
64# Created in the event of new host targets becoming available
65_PREBUILT_MAKE_CONF = {'amd64': os.path.join(_PREBUILT_BASE_DIR,
66 'make.conf.amd64-host')}
67_BINHOST_CONF_DIR = 'src/third_party/chromiumos-overlay/chromeos/binhost'
68
69
70class FiltersEmpty(Exception):
71 """Raised when filters are used but none are found."""
72 pass
73
74
75class UploadFailed(Exception):
76 """Raised when one of the files uploaded failed."""
77 pass
78
79class UnknownBoardFormat(Exception):
80 """Raised when a function finds an unknown board format."""
81 pass
82
83class GitPushFailed(Exception):
84 """Raised when a git push failed after retry."""
85 pass
86
87
88def UpdateLocalFile(filename, value, key='PORTAGE_BINHOST'):
89 """Update the key in file with the value passed.
90 File format:
91 key="value"
92 Note quotes are added automatically
93
94 Args:
95 filename: Name of file to modify.
96 value: Value to write with the key.
97 key: The variable key to update. (Default: PORTAGE_BINHOST)
98 """
99 if os.path.exists(filename):
100 file_fh = open(filename)
101 else:
102 file_fh = open(filename, 'w+')
103 file_lines = []
104 found = False
105 keyval_str = '%(key)s=%(value)s'
106 for line in file_fh:
107 # Strip newlines from end of line. We already add newlines below.
108 line = line.rstrip("\n")
109
110 if len(line.split('=')) != 2:
111 # Skip any line that doesn't fit key=val.
112 file_lines.append(line)
113 continue
114
115 file_var, file_val = line.split('=')
116 if file_var == key:
117 found = True
118 print 'Updating %s=%s to %s="%s"' % (file_var, file_val, key, value)
119 value = '"%s"' % value
120 file_lines.append(keyval_str % {'key': key, 'value': value})
121 else:
122 file_lines.append(keyval_str % {'key': file_var, 'value': file_val})
123
124 if not found:
125 file_lines.append(keyval_str % {'key': key, 'value': value})
126
127 file_fh.close()
128 # write out new file
129 new_file_fh = open(filename, 'w')
130 new_file_fh.write('\n'.join(file_lines) + '\n')
131 new_file_fh.close()
132
133
134def RevGitPushWithRetry(retries=5):
135 """Repo sync and then push git changes in flight.
136
137 Args:
138 retries: The number of times to retry before giving up, default: 5
139
140 Raises:
141 GitPushFailed if push was unsuccessful after retries
142 """
Chris Sosa471532a2011-02-01 15:10:06 -0800143 for retry in range(1, retries + 1):
David James8c846492011-01-25 17:07:29 -0800144 try:
145 cros_build_lib.RunCommand('repo sync .', shell=True)
146 cros_build_lib.RunCommand('git push', shell=True)
147 break
148 except cros_build_lib.RunCommandError:
149 if retry < retries:
150 print 'Error pushing changes trying again (%s/%s)' % (retry, retries)
Chris Sosa471532a2011-02-01 15:10:06 -0800151 time.sleep(5 * retry)
David James8c846492011-01-25 17:07:29 -0800152 else:
153 raise GitPushFailed('Failed to push change after %s retries' % retries)
154
155
156def RevGitFile(filename, value, retries=5, key='PORTAGE_BINHOST'):
157 """Update and push the git file.
158
159 Args:
160 filename: file to modify that is in a git repo already
161 value: string representing the version of the prebuilt that has been
162 uploaded.
163 retries: The number of times to retry before giving up, default: 5
164 key: The variable key to update in the git file.
165 (Default: PORTAGE_BINHOST)
166 """
167 prebuilt_branch = 'prebuilt_branch'
168 old_cwd = os.getcwd()
169 os.chdir(os.path.dirname(filename))
170
171 cros_build_lib.RunCommand('repo sync .', shell=True)
172 cros_build_lib.RunCommand('repo start %s .' % prebuilt_branch, shell=True)
173 git_ssh_config_cmd = (
174 'git config url.ssh://git@gitrw.chromium.org:9222.pushinsteadof '
175 'http://git.chromium.org/git')
176 cros_build_lib.RunCommand(git_ssh_config_cmd, shell=True)
177 description = 'Update %s="%s" in %s' % (key, value, filename)
178 print description
179 try:
180 UpdateLocalFile(filename, value, key)
181 cros_build_lib.RunCommand('git config push.default tracking', shell=True)
182 cros_build_lib.RunCommand('git commit -am "%s"' % description, shell=True)
183 RevGitPushWithRetry(retries)
184 finally:
185 cros_build_lib.RunCommand('repo abandon %s .' % prebuilt_branch, shell=True)
186 os.chdir(old_cwd)
187
188
189def GetVersion():
190 """Get the version to put in LATEST and update the git version with."""
191 return datetime.datetime.now().strftime('%d.%m.%y.%H%M%S')
192
193
194def LoadPrivateFilters(build_path):
195 """Load private filters based on ebuilds found under _PRIVATE_OVERLAY_DIR.
196
197 This function adds filters to the global set _FILTER_PACKAGES.
198 Args:
199 build_path: Path that _PRIVATE_OVERLAY_DIR is in.
200 """
201 # TODO(scottz): eventually use manifest.xml to find the proper
202 # private overlay path.
203 filter_path = os.path.join(build_path, _PRIVATE_OVERLAY_DIR)
204 files = cros_build_lib.ListFiles(filter_path)
205 filters = []
206 for file in files:
207 if file.endswith('.ebuild'):
208 basename = os.path.basename(file)
209 match = re.match('(.*?)-\d.*.ebuild', basename)
210 if match:
211 filters.append(match.group(1))
212
213 if not filters:
214 raise FiltersEmpty('No filters were returned')
215
216 _FILTER_PACKAGES.update(filters)
217
218
219def ShouldFilterPackage(file_path):
220 """Skip a particular file if it matches a pattern.
221
222 Skip any files that machine the list of packages to filter in
223 _FILTER_PACKAGES.
224
225 Args:
226 file_path: string of a file path to inspect against _FILTER_PACKAGES
227
228 Returns:
229 True if we should filter the package,
230 False otherwise.
231 """
232 for name in _FILTER_PACKAGES:
233 if name in file_path:
234 print 'FILTERING %s' % file_path
235 return True
236
237 return False
238
239
240def _RetryRun(cmd, print_cmd=True, shell=False, cwd=None):
241 """Run the specified command, retrying if necessary.
242
243 Args:
244 cmd: The command to run.
245 print_cmd: Whether to print out the cmd.
246 shell: Whether to treat the command as a shell.
247 cwd: Working directory to run command in.
248
249 Returns:
250 True if the command succeeded. Otherwise, returns False.
251 """
252
253 # TODO(scottz): port to use _Run or similar when it is available in
254 # cros_build_lib.
255 for attempt in range(_RETRIES):
256 try:
257 output = cros_build_lib.RunCommand(cmd, print_cmd=print_cmd, shell=shell,
258 cwd=cwd)
259 return True
260 except cros_build_lib.RunCommandError:
261 print 'Failed to run %s' % cmd
262 else:
263 print 'Retry failed run %s, giving up' % cmd
264 return False
265
266
267def _GsUpload(args):
268 """Upload to GS bucket.
269
270 Args:
271 args: a tuple of two arguments that contains local_file and remote_file.
272
273 Returns:
274 Return the arg tuple of two if the upload failed
275 """
276 (local_file, remote_file) = args
277
278 cmd = '%s cp -a public-read %s %s' % (_GSUTIL_BIN, local_file, remote_file)
279 if not _RetryRun(cmd, print_cmd=False, shell=True):
280 return (local_file, remote_file)
281
282
283def RemoteUpload(files, pool=10):
284 """Upload to google storage.
285
286 Create a pool of process and call _GsUpload with the proper arguments.
287
288 Args:
289 files: dictionary with keys to local files and values to remote path.
290 pool: integer of maximum proesses to have at the same time.
291
292 Returns:
293 Return a set of tuple arguments of the failed uploads
294 """
295 # TODO(scottz) port this to use _RunManyParallel when it is available in
296 # cros_build_lib
297 pool = multiprocessing.Pool(processes=pool)
298 workers = []
299 for local_file, remote_path in files.iteritems():
300 workers.append((local_file, remote_path))
301
302 result = pool.map_async(_GsUpload, workers, chunksize=1)
303 while True:
304 try:
Chris Sosa471532a2011-02-01 15:10:06 -0800305 return set(result.get(60 * 60))
David James8c846492011-01-25 17:07:29 -0800306 except multiprocessing.TimeoutError:
307 pass
308
309
310def GenerateUploadDict(base_local_path, base_remote_path, pkgs):
311 """Build a dictionary of local remote file key pairs to upload.
312
313 Args:
314 base_local_path: The base path to the files on the local hard drive.
315 remote_path: The base path to the remote paths.
316 pkgs: The packages to upload.
317
318 Returns:
319 Returns a dictionary of local_path/remote_path pairs
320 """
321 upload_files = {}
322 for pkg in pkgs:
323 suffix = pkg['CPV'] + '.tbz2'
324 local_path = os.path.join(base_local_path, suffix)
325 assert os.path.exists(local_path)
326 remote_path = '%s/%s' % (base_remote_path.rstrip('/'), suffix)
327 upload_files[local_path] = remote_path
328
329 return upload_files
330
331def GetBoardPathFromCrosOverlayList(build_path, target):
332 """Use the cros_overlay_list to determine the path to the board overlay
333 Args:
334 build_path: The path to the root of the build directory
335 target: The target that we are looking for, could consist of board and
336 board_variant, we handle that properly
337 Returns:
338 The last line from cros_overlay_list as a string
339 """
Chris Sosa471532a2011-02-01 15:10:06 -0800340 script_dir = os.path.join(build_path, 'src/platform/dev/host')
David James8c846492011-01-25 17:07:29 -0800341 cmd = ['./cros_overlay_list']
342 if re.match('.*?_.*', target):
343 (board, variant) = target.split('_')
344 cmd += ['--board', board, '--variant', variant]
345 elif re.match('.*?-\w+', target):
346 cmd += ['--board', target]
347 else:
348 raise UnknownBoardFormat('Unknown format: %s' % target)
349
350 cmd_output = cros_build_lib.RunCommand(cmd, redirect_stdout=True,
351 cwd=script_dir)
352 # We only care about the last entry
353 return cmd_output.output.splitlines().pop()
354
355
356def DeterminePrebuiltConfFile(build_path, target):
357 """Determine the prebuilt.conf file that needs to be updated for prebuilts.
358
359 Args:
360 build_path: The path to the root of the build directory
361 target: String representation of the board. This includes host and board
362 targets
363
364 Returns
365 A string path to a prebuilt.conf file to be updated.
366 """
367 if _HOST_TARGET == target:
368 # We are host.
369 # Without more examples of hosts this is a kludge for now.
370 # TODO(Scottz): as new host targets come online expand this to
371 # work more like boards.
Chris Sosa471532a2011-02-01 15:10:06 -0800372 make_path = _PREBUILT_MAKE_CONF[target]
David James8c846492011-01-25 17:07:29 -0800373 else:
374 # We are a board
375 board = GetBoardPathFromCrosOverlayList(build_path, target)
376 make_path = os.path.join(board, 'prebuilt.conf')
377
378 return make_path
379
380
381def UpdateBinhostConfFile(path, key, value):
382 """Update binhost config file file with key=value.
383
384 Args:
385 path: Filename to update.
386 key: Key to update.
387 value: New value for key.
388 """
389 cwd = os.path.dirname(os.path.abspath(path))
390 filename = os.path.basename(path)
391 if not os.path.isdir(cwd):
392 os.makedirs(cwd)
393 if not os.path.isfile(path):
394 config_file = file(path, 'w')
David James8c846492011-01-25 17:07:29 -0800395 config_file.close()
396 UpdateLocalFile(path, value, key)
397 cros_build_lib.RunCommand('git add %s' % filename, cwd=cwd, shell=True)
398 description = 'Update %s=%s in %s' % (key, value, filename)
399 cros_build_lib.RunCommand('git commit -m "%s"' % description, cwd=cwd,
400 shell=True)
401
402
David James05bcb2b2011-02-09 09:25:47 -0800403def _GetCrossCompilerSubdirectories(build_path):
404 """Get a list of the subdirectories where cross-compilers are stored.
405
406 This function looks at what cross-compilers have been configured on the
407 current host, and uses it to calculate the subdirectories where Portage will
408 store their prebuilts for each board.
David James8c846492011-01-25 17:07:29 -0800409
410 Args:
David James05bcb2b2011-02-09 09:25:47 -0800411 build_path: The path to the directory containing the chroot.
412
413 Returns:
414 A list of subdirs, like: ['cross/i686-pc-linux-gnu',
415 'cross/armv7a-cros-linux-gnueabi', ...]
416 """
417 path = os.path.join(build_path, _CATEGORIES_PATH)
418 categories_file = file(path)
419 categories = []
420 for line in categories_file:
421 if line.startswith('cross-'):
422 categories.append(line.rstrip('\n').replace('cross-', 'cross/'))
423 categories_file.close()
424 return categories
425
426
427def _GrabAllRemotePackageIndexes(binhost_urls, subdirs):
428 """Grab all of the packages files associated with a list of binhost_urls.
429
430 Besides grabbing the Packages file associated with each binhost_url, this
431 function also grabs the associated cross-compiler prebuilts, if available.
432
433 cross-compiler prebuilts have separate Packages files and prebuilts. These
434 binhosts are stored in subdirectories of the regular binhosts. For each
David James09b8b172011-02-09 10:14:34 -0800435 binhost, we use subdirs to find the subdirectories.
David James05bcb2b2011-02-09 09:25:47 -0800436
437 Args:
438 binhost_urls: The URLs for the directories containing the Packages files we
439 want to grab.
440 subdirs: A list of the subdirectories for the cross-compilers, like:
441 ['cross/i686-pc-linux-gnu',
442 'cross/armv7a-cros-linux-gnueabi', ...]
443
444 Returns:
445 A list of PackageIndex objects.
446 """
447 pkg_indexes = []
448 for url in binhost_urls:
449 pkg_index = GrabRemotePackageIndex(url)
450 if pkg_index:
451 pkg_indexes.append(pkg_index)
David James09b8b172011-02-09 10:14:34 -0800452 for subdir in subdirs:
David James05bcb2b2011-02-09 09:25:47 -0800453 cross_url = '%s/%s' % (url.rstrip('/'), subdir)
454 cross_pkg_index = GrabRemotePackageIndex(cross_url)
455 if cross_pkg_index:
456 pkg_indexes.append(cross_pkg_index)
457 return pkg_indexes
458
459
460def UploadPrebuilt(package_path, upload_location, url_suffix, binhost_base_url,
461 pkg_indexes):
462 """Upload host or board prebuilt files to Google Storage space.
463
464 Args:
465 package_path: The path to the packages dir.
David James8c846492011-01-25 17:07:29 -0800466 upload_location: The upload location.
David James05bcb2b2011-02-09 09:25:47 -0800467 url_suffix: If set, upload the Packages file from the specified subdir of
468 the Packages directory. This subdirectory must be self-contained and have
469 its own Packages file.
David James8c846492011-01-25 17:07:29 -0800470 pkg_indexes: Old uploaded prebuilts to compare against. Instead of
471 uploading duplicate files, we just link to the old files.
David James8c846492011-01-25 17:07:29 -0800472 """
473
David James8c846492011-01-25 17:07:29 -0800474 # Process Packages file, removing duplicates and filtered packages.
475 pkg_index = GrabLocalPackageIndex(package_path)
476 pkg_index.SetUploadLocation(binhost_base_url, url_suffix)
David James05bcb2b2011-02-09 09:25:47 -0800477 pkg_index.RemoveFilteredPackages(ShouldFilterPackage)
David James8c846492011-01-25 17:07:29 -0800478 uploads = pkg_index.ResolveDuplicateUploads(pkg_indexes)
479
480 # Write Packages file.
481 tmp_packages_file = pkg_index.WriteToNamedTemporaryFile()
482
David James05bcb2b2011-02-09 09:25:47 -0800483 remote_location = '%s/%s' % (upload_location.rstrip('/'), url_suffix)
484 if remote_location.startswith('gs://'):
David James8c846492011-01-25 17:07:29 -0800485 # Build list of files to upload.
486 upload_files = GenerateUploadDict(package_path, remote_location, uploads)
487 remote_file = '%s/Packages' % remote_location.rstrip('/')
488 upload_files[tmp_packages_file.name] = remote_file
489
David James8c846492011-01-25 17:07:29 -0800490 failed_uploads = RemoteUpload(upload_files)
491 if len(failed_uploads) > 1 or (None not in failed_uploads):
492 error_msg = ['%s -> %s\n' % args for args in failed_uploads]
493 raise UploadFailed('Error uploading:\n%s' % error_msg)
494 else:
495 pkgs = ' '.join(p['CPV'] + '.tbz2' for p in uploads)
496 ssh_server, remote_path = remote_location.split(':', 1)
497 d = { 'pkg_index': tmp_packages_file.name,
498 'pkgs': pkgs,
499 'remote_packages': '%s/Packages' % remote_location.rstrip('/'),
David James05bcb2b2011-02-09 09:25:47 -0800500 'remote_path': remote_path.rstrip('/'),
501 'remote_location': remote_location.rstrip('/'),
David James8c846492011-01-25 17:07:29 -0800502 'ssh_server': ssh_server }
503 cmds = ['ssh %(ssh_server)s mkdir -p %(remote_path)s' % d,
504 'rsync -av --chmod=a+r %(pkg_index)s %(remote_packages)s' % d]
505 if pkgs:
506 cmds.append('rsync -Rav %(pkgs)s %(remote_location)s/' % d)
507 for cmd in cmds:
508 if not _RetryRun(cmd, shell=True, cwd=package_path):
509 raise UploadFailed('Could not run %s' % cmd)
510
David James8c846492011-01-25 17:07:29 -0800511
David James05bcb2b2011-02-09 09:25:47 -0800512def _SyncHostPrebuilts(build_path, upload_location, version, binhost_base_url,
513 pkg_indexes, key, git_sync, sync_binhost_conf):
514 """Synchronize host prebuilt files.
515
516 This function will sync both the standard host packages, plus the host
517 packages associated with all targets that have been "setup" with the current
518 host's chroot. For instance, if this host has been used to build x86-generic,
519 it will sync the host packages associated with 'i686-pc-linux-gnu'. If this
520 host has also been used to build arm-generic, it will also sync the host
521 packages associated with 'armv7a-cros-linux-gnueabi'.
522
523 Args:
524 build_path: The path to the directory containing the chroot.
525 upload_location: The upload location.
526 pkg_indexes: Old uploaded prebuilts to compare against. Instead of
527 uploading duplicate files, we just link to the old files.
528 key: The variable key to update in the git file.
529 git_sync: If set, update make.conf of target to reference the latest
530 prebuilt packages generated here.
531 sync_binhost_conf: If set, update binhost config file in chromiumos-overlay
532 for the host.
533 """
534 # Upload prebuilts.
535 package_path = os.path.join(build_path, _HOST_PACKAGES_PATH)
536 url_suffix = _REL_HOST_PATH % {'version': version, 'target': _HOST_TARGET}
537 for subdir in _GetCrossCompilerSubdirectories(build_path):
538 cross_url_suffix = '%s/%s' % (url_suffix.rstrip('/'), subdir)
539 UploadPrebuilt(os.path.join(package_path, subdir), upload_location,
540 cross_url_suffix, binhost_base_url, pkg_indexes)
541 UploadPrebuilt(package_path, upload_location, url_suffix, binhost_base_url,
542 pkg_indexes)
543
544 # Record URL where prebuilts were uploaded.
545 url_value = '%s/%s/' % (binhost_base_url.rstrip('/'), url_suffix.rstrip('/'))
David James8c846492011-01-25 17:07:29 -0800546 if git_sync:
David James05bcb2b2011-02-09 09:25:47 -0800547 git_file = os.path.join(build_path, _PREBUILT_MAKE_CONF[_HOST_TARGET])
548 RevGitFile(git_file, url_value, key=key)
David James8c846492011-01-25 17:07:29 -0800549 if sync_binhost_conf:
David James05bcb2b2011-02-09 09:25:47 -0800550 binhost_conf = os.path.join(build_path, _BINHOST_CONF_DIR, 'host',
David James82064dc2011-02-14 13:21:31 -0800551 '%s-%s.conf' % (_HOST_TARGET, key))
David James8c846492011-01-25 17:07:29 -0800552 UpdateBinhostConfFile(binhost_conf, key, url_value)
553
David James05bcb2b2011-02-09 09:25:47 -0800554
555def _SyncBoardPrebuilts(build_path, upload_location, version, binhost_base_url,
556 pkg_indexes, board, key, git_sync, sync_binhost_conf):
557 """Synchronize board prebuilt files.
558
559 Args:
560 build_path: The path to the directory containing the chroot.
561 upload_location: The upload location.
562 pkg_indexes: Old uploaded prebuilts to compare against. Instead of
563 uploading duplicate files, we just link to the old files.
564 board: The board to upload to Google Storage.
565 key: The variable key to update in the git file.
566 git_sync: If set, update make.conf of target to reference the latest
567 prebuilt packages generated here.
568 sync_binhost_conf: If set, update binhost config file in chromiumos-overlay
569 for the current board.
570 """
571 # Upload prebuilts.
572 board_path = os.path.join(build_path, _BOARD_PATH % {'board': board})
573 package_path = os.path.join(board_path, 'packages')
574 url_suffix = _REL_BOARD_PATH % {'board': board, 'version': version}
575 UploadPrebuilt(package_path, upload_location, url_suffix, binhost_base_url,
576 pkg_indexes)
577
578 # Record URL where prebuilts were uploaded.
579 url_value = '%s/%s/' % (binhost_base_url.rstrip('/'), url_suffix.rstrip('/'))
580 if git_sync:
581 git_file = DeterminePrebuiltConfFile(build_path, board)
582 RevGitFile(git_file, url_value, key=key)
583 if sync_binhost_conf:
584 binhost_conf = os.path.join(build_path, _BINHOST_CONF_DIR, 'target',
David James82064dc2011-02-14 13:21:31 -0800585 '%s-%s.conf' % (board, key))
David James05bcb2b2011-02-09 09:25:47 -0800586 UpdateBinhostConfFile(binhost_conf, key, url_value)
587
588
David James8c846492011-01-25 17:07:29 -0800589def usage(parser, msg):
590 """Display usage message and parser help then exit with 1."""
591 print >> sys.stderr, msg
592 parser.print_help()
593 sys.exit(1)
594
595
596def main():
597 parser = optparse.OptionParser()
598 parser.add_option('-H', '--binhost-base-url', dest='binhost_base_url',
599 default=_BINHOST_BASE_URL,
600 help='Base URL to use for binhost in make.conf updates')
601 parser.add_option('', '--previous-binhost-url', action='append',
602 default=[], dest='previous_binhost_url',
603 help='Previous binhost URL')
604 parser.add_option('-b', '--board', dest='board', default=None,
605 help='Board type that was built on this machine')
606 parser.add_option('-p', '--build-path', dest='build_path',
David James05bcb2b2011-02-09 09:25:47 -0800607 help='Path to the directory containing the chroot')
David James8c846492011-01-25 17:07:29 -0800608 parser.add_option('-s', '--sync-host', dest='sync_host',
609 default=False, action='store_true',
610 help='Sync host prebuilts')
611 parser.add_option('-g', '--git-sync', dest='git_sync',
612 default=False, action='store_true',
613 help='Enable git version sync (This commits to a repo)')
614 parser.add_option('-u', '--upload', dest='upload',
615 default=None,
616 help='Upload location')
617 parser.add_option('-V', '--prepend-version', dest='prepend_version',
618 default=None,
619 help='Add an identifier to the front of the version')
620 parser.add_option('-f', '--filters', dest='filters', action='store_true',
621 default=False,
622 help='Turn on filtering of private ebuild packages')
623 parser.add_option('-k', '--key', dest='key',
624 default='PORTAGE_BINHOST',
625 help='Key to update in make.conf / binhost.conf')
626 parser.add_option('', '--sync-binhost-conf', dest='sync_binhost_conf',
627 default=False, action='store_true',
628 help='Update binhost.conf')
629
630 options, args = parser.parse_args()
631 # Setup boto environment for gsutil to use
632 os.environ['BOTO_CONFIG'] = _BOTO_CONFIG
633 if not options.build_path:
634 usage(parser, 'Error: you need provide a chroot path')
635
636 if not options.upload:
637 usage(parser, 'Error: you need to provide an upload location using -u')
638
639 if options.filters:
640 LoadPrivateFilters(options.build_path)
641
642 version = GetVersion()
643 if options.prepend_version:
644 version = '%s-%s' % (options.prepend_version, version)
645
David James05bcb2b2011-02-09 09:25:47 -0800646 # Calculate a list of Packages index files to compare against. Whenever we
647 # upload a package, we check to make sure it's not already stored in one of
648 # the packages files we uploaded. This list of packages files might contain
649 # both board and host packages.
650 cross_subdirs = _GetCrossCompilerSubdirectories(options.build_path)
651 pkg_indexes = _GrabAllRemotePackageIndexes(options.previous_binhost_url,
652 cross_subdirs)
David James8c846492011-01-25 17:07:29 -0800653
654 if options.sync_host:
David James05bcb2b2011-02-09 09:25:47 -0800655 _SyncHostPrebuilts(options.build_path, options.upload, version,
656 options.binhost_base_url, pkg_indexes, options.key,
657 options.git_sync, options.sync_binhost_conf)
David James8c846492011-01-25 17:07:29 -0800658
659 if options.board:
David James05bcb2b2011-02-09 09:25:47 -0800660 _SyncBoardPrebuilts(options.build_path, options.upload, version,
661 options.binhost_base_url, pkg_indexes, options.board,
662 options.key, options.git_sync,
663 options.sync_binhost_conf)
David James8c846492011-01-25 17:07:29 -0800664
665if __name__ == '__main__':
666 main()