| OLD | NEW |
| 1 #!/usr/bin/python | 1 #!/usr/bin/python |
| 2 # Copyright (c) 2010 The Chromium OS Authors. All rights reserved. | 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 | 3 # Use of this source code is governed by a BSD-style license that can be |
| 4 # found in the LICENSE file. | 4 # found in the LICENSE file. |
| 5 | 5 |
| 6 import datetime | 6 import datetime |
| 7 import multiprocessing | 7 import multiprocessing |
| 8 import optparse | 8 import optparse |
| 9 import os | 9 import os |
| 10 import re | 10 import re |
| (...skipping 12 matching lines...) Expand all Loading... |
| 23 http://sites/chromeos/for-team-members/engineering/releng/prebuilt-binaries-for-
streamlining-the-build-process | 23 http://sites/chromeos/for-team-members/engineering/releng/prebuilt-binaries-for-
streamlining-the-build-process |
| 24 | 24 |
| 25 | 25 |
| 26 Example of uploading prebuilt amd64 host files | 26 Example of uploading prebuilt amd64 host files |
| 27 ./prebuilt.py -p /b/cbuild/build -s -u gs://chromeos-prebuilt | 27 ./prebuilt.py -p /b/cbuild/build -s -u gs://chromeos-prebuilt |
| 28 | 28 |
| 29 Example of uploading x86-dogfood binhosts | 29 Example of uploading x86-dogfood binhosts |
| 30 ./prebuilt.py -b x86-dogfood -p /b/cbuild/build/ -u gs://chromeos-prebuilt -g | 30 ./prebuilt.py -b x86-dogfood -p /b/cbuild/build/ -u gs://chromeos-prebuilt -g |
| 31 """ | 31 """ |
| 32 | 32 |
| 33 VER_FILE = 'src/third_party/chromiumos-overlay/chromeos/config/stable_versions' | |
| 34 | |
| 35 # as per http://crosbug.com/5855 always filter the below packages | 33 # as per http://crosbug.com/5855 always filter the below packages |
| 36 _FILTER_PACKAGES = set() | 34 _FILTER_PACKAGES = set() |
| 37 _RETRIES = 3 | 35 _RETRIES = 3 |
| 38 _GSUTIL_BIN = '/b/third_party/gsutil/gsutil' | 36 _GSUTIL_BIN = '/b/third_party/gsutil/gsutil' |
| 39 _HOST_PACKAGES_PATH = 'chroot/var/lib/portage/pkgs' | 37 _HOST_PACKAGES_PATH = 'chroot/var/lib/portage/pkgs' |
| 40 _HOST_TARGET = 'amd64' | 38 _HOST_TARGET = 'amd64' |
| 41 _BOARD_PATH = 'chroot/build/%(board)s' | 39 _BOARD_PATH = 'chroot/build/%(board)s' |
| 42 _BOTO_CONFIG = '/home/chrome-bot/external-boto' | 40 _BOTO_CONFIG = '/home/chrome-bot/external-boto' |
| 43 # board/board-target/version' | 41 # board/board-target/version' |
| 44 _GS_BOARD_PATH = 'board/%(board)s/%(version)s/' | 42 _GS_BOARD_PATH = 'board/%(board)s/%(version)s/' |
| 45 # We only support amd64 right now | 43 # We only support amd64 right now |
| 46 _GS_HOST_PATH = 'host/%s' % _HOST_TARGET | 44 _GS_HOST_PATH = 'host/%s' % _HOST_TARGET |
| 47 # Private overlays to look at for builds to filter | 45 # Private overlays to look at for builds to filter |
| 48 # relative to build path | 46 # relative to build path |
| 49 _PRIVATE_OVERLAY_DIR = 'src/private-overlays' | 47 _PRIVATE_OVERLAY_DIR = 'src/private-overlays' |
| 48 _BINHOST_BASE_DIR = 'src/overlays' |
| 49 _BINHOST_BASE_URL = 'http://commondatastorage.googleapis.com/chromeos-prebuilt' |
| 50 _PREBUILT_BASE_DIR = 'src/third_party/chromiumos-overlay/chromeos/config/' |
| 51 # Created in the event of new host targets becoming available |
| 52 _PREBUILT_MAKE_CONF = {'amd64': os.path.join(_PREBUILT_BASE_DIR, |
| 53 'make.conf.amd64-host')} |
| 50 | 54 |
| 51 | 55 |
| 52 class FiltersEmpty(Exception): | 56 class FiltersEmpty(Exception): |
| 53 """Raised when filters are used but none are found.""" | 57 """Raised when filters are used but none are found.""" |
| 54 pass | 58 pass |
| 55 | 59 |
| 56 | 60 |
| 57 class UploadFailed(Exception): | 61 class UploadFailed(Exception): |
| 58 """Raised when one of the files uploaded failed.""" | 62 """Raised when one of the files uploaded failed.""" |
| 59 pass | 63 pass |
| 60 | 64 |
| 65 class UnknownBoardFormat(Exception): |
| 66 """Raised when a function finds an unknown board format.""" |
| 67 pass |
| 61 | 68 |
| 62 def UpdateLocalFile(filename, key, value): | 69 |
| 70 def UpdateLocalFile(filename, value, key='PORTAGE_BINHOST'): |
| 63 """Update the key in file with the value passed. | 71 """Update the key in file with the value passed. |
| 64 File format: | 72 File format: |
| 65 key value | 73 key="value" |
| 74 Note quotes are added automatically |
| 66 | 75 |
| 67 Args: | 76 Args: |
| 68 filename: Name of file to modify. | 77 filename: Name of file to modify. |
| 69 key: The variable key to update. | |
| 70 value: Value to write with the key. | 78 value: Value to write with the key. |
| 79 key: The variable key to update. (Default: PORTAGE_BINHOST) |
| 71 """ | 80 """ |
| 72 file_fh = open(filename) | 81 file_fh = open(filename) |
| 73 file_lines = [] | 82 file_lines = [] |
| 74 found = False | 83 found = False |
| 75 for line in file_fh: | 84 for line in file_fh: |
| 76 file_var, file_val = line.split() | 85 if '=' not in line: |
| 86 # Skip any line without an equal in it and just write it out |
| 87 file_lines.append(line) |
| 88 continue |
| 89 |
| 90 file_var, file_val = line.split('=') |
| 91 keyval_str = '%(key)s=%(value)s' |
| 77 if file_var == key: | 92 if file_var == key: |
| 78 found = True | 93 found = True |
| 79 print 'Updating %s %s to %s %s' % (file_var, file_val, key, value) | 94 print 'Updating %s=%s to %s="%s"' % (file_var, file_val, key, value) |
| 80 file_lines.append('%s %s' % (key, value)) | 95 value = '"%s"' % value |
| 96 file_lines.append(keyval_str % {'key': key, 'value': value}) |
| 81 else: | 97 else: |
| 82 file_lines.append('%s %s' % (file_var, file_val)) | 98 file_lines.append(keyval_str % {'key': file_var, 'value': file_val}) |
| 83 | 99 |
| 84 if not found: | 100 if not found: |
| 85 file_lines.append('%s %s' % (key, value)) | 101 file_lines.append(keyval_str % {'key': key, 'value': value}) |
| 86 | 102 |
| 87 file_fh.close() | 103 file_fh.close() |
| 88 # write out new file | 104 # write out new file |
| 89 new_file_fh = open(filename, 'w') | 105 new_file_fh = open(filename, 'w') |
| 90 new_file_fh.write('\n'.join(file_lines)) | 106 new_file_fh.write('\n'.join(file_lines)) |
| 91 new_file_fh.close() | 107 new_file_fh.close() |
| 92 | 108 |
| 93 | 109 |
| 94 def RevGitFile(filename, key, value): | 110 def RevGitFile(filename, value): |
| 95 """Update and push the git file. | 111 """Update and push the git file. |
| 96 | 112 |
| 97 Args: | 113 Args: |
| 98 filename: file to modify that is in a git repo already | 114 filename: file to modify that is in a git repo already |
| 99 key: board or host package type e.g. x86-dogfood | 115 key: board or host package type e.g. x86-dogfood |
| 100 value: string representing the version of the prebuilt that has been | 116 value: string representing the version of the prebuilt that has been |
| 101 uploaded. | 117 uploaded. |
| 102 """ | 118 """ |
| 103 prebuilt_branch = 'prebuilt_branch' | 119 prebuilt_branch = 'prebuilt_branch' |
| 104 old_cwd = os.getcwd() | 120 old_cwd = os.getcwd() |
| 105 os.chdir(os.path.dirname(filename)) | 121 os.chdir(os.path.dirname(filename)) |
| 122 |
| 123 cros_build_lib.RunCommand('repo sync', shell=True) |
| 106 cros_build_lib.RunCommand('repo start %s .' % prebuilt_branch, shell=True) | 124 cros_build_lib.RunCommand('repo start %s .' % prebuilt_branch, shell=True) |
| 107 UpdateLocalFile(filename, key, value) | |
| 108 description = 'Update BINHOST key/value %s %s' % (key, value) | |
| 109 print description | |
| 110 git_ssh_config_cmd = ( | 125 git_ssh_config_cmd = ( |
| 111 'git config url.ssh://git@gitrw.chromium.org:9222.pushinsteadof ' | 126 'git config url.ssh://git@gitrw.chromium.org:9222.pushinsteadof ' |
| 112 'http://git.chromium.org/git') | 127 'http://git.chromium.org/git') |
| 128 cros_build_lib.RunCommand(git_ssh_config_cmd, shell=True) |
| 129 description = 'Update PORTAGE_BINHOST="%s" in %s' % (value, file) |
| 130 print description |
| 113 try: | 131 try: |
| 114 cros_build_lib.RunCommand(git_ssh_config_cmd, shell=True) | 132 UpdateLocalFile(filename, value) |
| 115 cros_build_lib.RunCommand('git pull', shell=True) | |
| 116 cros_build_lib.RunCommand('git config push.default tracking', shell=True) | 133 cros_build_lib.RunCommand('git config push.default tracking', shell=True) |
| 117 cros_build_lib.RunCommand('git commit -am "%s"' % description, shell=True) | 134 cros_build_lib.RunCommand('git commit -am "%s"' % description, shell=True) |
| 135 cros_build_lib.RunCommand('repo sync', shell=True) |
| 118 cros_build_lib.RunCommand('git push', shell=True) | 136 cros_build_lib.RunCommand('git push', shell=True) |
| 119 finally: | 137 finally: |
| 120 cros_build_lib.RunCommand('repo abandon %s .' % prebuilt_branch, shell=True) | 138 cros_build_lib.RunCommand('repo abandon %s .' % prebuilt_branch, shell=True) |
| 121 os.chdir(old_cwd) | 139 os.chdir(old_cwd) |
| 122 | 140 |
| 123 | 141 |
| 124 def GetVersion(): | 142 def GetVersion(): |
| 125 """Get the version to put in LATEST and update the git version with.""" | 143 """Get the version to put in LATEST and update the git version with.""" |
| 126 return datetime.datetime.now().strftime('%d.%m.%y.%H%M%S') | 144 return datetime.datetime.now().strftime('%d.%m.%y.%H%M%S') |
| 127 | 145 |
| (...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 244 files_to_sync = cros_build_lib.ListFiles(local_path) | 262 files_to_sync = cros_build_lib.ListFiles(local_path) |
| 245 upload_files = {} | 263 upload_files = {} |
| 246 for file_path in files_to_sync: | 264 for file_path in files_to_sync: |
| 247 filename = file_path.replace(strip_str, '').lstrip('/') | 265 filename = file_path.replace(strip_str, '').lstrip('/') |
| 248 gs_file_path = os.path.join(gs_path, filename) | 266 gs_file_path = os.path.join(gs_path, filename) |
| 249 upload_files[file_path] = gs_file_path | 267 upload_files[file_path] = gs_file_path |
| 250 | 268 |
| 251 return upload_files | 269 return upload_files |
| 252 | 270 |
| 253 | 271 |
| 254 def UploadPrebuilt(build_path, bucket, board=None, git_file=None): | 272 def DetermineMakeConfFile(target): |
| 273 """Determine the make.conf file that needs to be updated for prebuilts. |
| 274 |
| 275 Args: |
| 276 target: String representation of the board. This includes host and board |
| 277 targets |
| 278 |
| 279 Returns |
| 280 A string path to a make.conf file to be updated. |
| 281 """ |
| 282 if _HOST_TARGET == target: |
| 283 # We are host. |
| 284 # Without more examples of hosts this is a kludge for now. |
| 285 # TODO(Scottz): as new host targets come online expand this to |
| 286 # work more like boards. |
| 287 make_path = _PREBUILT_MAKE_CONF[target] |
| 288 elif re.match('.*?-.*?_.*', target): |
| 289 # We are a board variant |
| 290 overlay_str = 'overlay-variant-%s' % target.replace('_', '-') |
| 291 make_path = os.path.join(_BINHOST_BASE_DIR, overlay_str, 'make.conf') |
| 292 elif re.match('.*?-\w+', target): |
| 293 overlay_str = 'overlay-%s' % target |
| 294 make_path = os.path.join(_BINHOST_BASE_DIR, overlay_str, 'make.conf') |
| 295 else: |
| 296 raise UnknownBoardFormat('Unknown format: %s' % target) |
| 297 |
| 298 return os.path.join(make_path) |
| 299 |
| 300 |
| 301 def UploadPrebuilt(build_path, bucket, version, board=None, git_sync=False): |
| 255 """Upload Host prebuilt files to Google Storage space. | 302 """Upload Host prebuilt files to Google Storage space. |
| 256 | 303 |
| 257 Args: | 304 Args: |
| 258 build_path: The path to the root of the chroot. | 305 build_path: The path to the root of the chroot. |
| 259 bucket: The Google Storage bucket to upload to. | 306 bucket: The Google Storage bucket to upload to. |
| 260 board: The board to upload to Google Storage, if this is None upload | 307 board: The board to upload to Google Storage, if this is None upload |
| 261 host packages. | 308 host packages. |
| 262 git_file: If set, update this file with a host/version combo, commit and | 309 git_sync: If set, update make.conf of target to reference the latest |
| 263 push it. | 310 prebuilt packages genereated here. |
| 264 """ | 311 """ |
| 265 version = GetVersion() | |
| 266 | 312 |
| 267 if not board: | 313 if not board: |
| 268 # We are uploading host packages | 314 # We are uploading host packages |
| 269 # TODO(scottz): eventually add support for different host_targets | 315 # TODO(scottz): eventually add support for different host_targets |
| 270 package_path = os.path.join(build_path, _HOST_PACKAGES_PATH) | 316 package_path = os.path.join(build_path, _HOST_PACKAGES_PATH) |
| 271 gs_path = os.path.join(bucket, _GS_HOST_PATH, version) | 317 gs_path = os.path.join(bucket, _GS_HOST_PATH, version) |
| 272 strip_pattern = package_path | 318 strip_pattern = package_path |
| 273 package_string = _HOST_TARGET | 319 package_string = _HOST_TARGET |
| 320 git_file = os.path.join(build_path, _PREBUILT_MAKE_CONF[_HOST_TARGET]) |
| 321 url_suffix = '%s/%s' % (_GS_HOST_PATH, version) |
| 274 else: | 322 else: |
| 275 board_path = os.path.join(build_path, _BOARD_PATH % {'board': board}) | 323 board_path = os.path.join(build_path, _BOARD_PATH % {'board': board}) |
| 276 package_path = os.path.join(board_path, 'packages') | 324 package_path = os.path.join(board_path, 'packages') |
| 277 package_string = board | 325 package_string = board |
| 278 strip_pattern = board_path | 326 strip_pattern = board_path |
| 279 gs_path = os.path.join(bucket, _GS_BOARD_PATH % {'board': board, | 327 remote_board_path = _GS_BOARD_PATH % {'board': board, 'version': version} |
| 280 'version': version}) | 328 gs_path = os.path.join(bucket, remote_board_path) |
| 329 git_file = os.path.join(build_path, DetermineMakeConfFile(board)) |
| 330 url_suffix = remote_board_path |
| 281 | 331 |
| 282 upload_files = GenerateUploadDict(package_path, gs_path, strip_pattern) | 332 upload_files = GenerateUploadDict(package_path, gs_path, strip_pattern) |
| 283 | 333 |
| 284 print 'Uploading %s' % package_string | 334 print 'Uploading %s' % package_string |
| 285 failed_uploads = RemoteUpload(upload_files) | 335 failed_uploads = RemoteUpload(upload_files) |
| 286 if len(failed_uploads) > 1 or (None not in failed_uploads): | 336 if len(failed_uploads) > 1 or (None not in failed_uploads): |
| 287 error_msg = ['%s -> %s\n' % args for args in failed_uploads] | 337 error_msg = ['%s -> %s\n' % args for args in failed_uploads] |
| 288 raise UploadFailed('Error uploading:\n%s' % error_msg) | 338 raise UploadFailed('Error uploading:\n%s' % error_msg) |
| 289 | 339 |
| 290 if git_file: | 340 if git_sync: |
| 291 RevGitFile(git_file, package_string, version) | 341 url_value = '%s/%s' % (_BINHOST_BASE_URL, url_suffix) |
| 342 RevGitFile(git_file, url_value) |
| 292 | 343 |
| 293 | 344 |
| 294 def usage(parser, msg): | 345 def usage(parser, msg): |
| 295 """Display usage message and parser help then exit with 1.""" | 346 """Display usage message and parser help then exit with 1.""" |
| 296 print >> sys.stderr, msg | 347 print >> sys.stderr, msg |
| 297 parser.print_help() | 348 parser.print_help() |
| 298 sys.exit(1) | 349 sys.exit(1) |
| 299 | 350 |
| 300 | 351 |
| 301 def main(): | 352 def main(): |
| 302 parser = optparse.OptionParser() | 353 parser = optparse.OptionParser() |
| 303 parser.add_option('-b', '--board', dest='board', default=None, | 354 parser.add_option('-b', '--board', dest='board', default=None, |
| 304 help='Board type that was built on this machine') | 355 help='Board type that was built on this machine') |
| 305 parser.add_option('-p', '--build-path', dest='build_path', | 356 parser.add_option('-p', '--build-path', dest='build_path', |
| 306 help='Path to the chroot') | 357 help='Path to the chroot') |
| 307 parser.add_option('-s', '--sync-host', dest='sync_host', | 358 parser.add_option('-s', '--sync-host', dest='sync_host', |
| 308 default=False, action='store_true', | 359 default=False, action='store_true', |
| 309 help='Sync host prebuilts') | 360 help='Sync host prebuilts') |
| 310 parser.add_option('-g', '--git-sync', dest='git_sync', | 361 parser.add_option('-g', '--git-sync', dest='git_sync', |
| 311 default=False, action='store_true', | 362 default=False, action='store_true', |
| 312 help='Enable git version sync (This commits to a repo)') | 363 help='Enable git version sync (This commits to a repo)') |
| 313 parser.add_option('-u', '--upload', dest='upload', | 364 parser.add_option('-u', '--upload', dest='upload', |
| 314 default=None, | 365 default=None, |
| 315 help='Upload to GS bucket') | 366 help='Upload to GS bucket') |
| 367 parser.add_option('-V', '--prepend-version', dest='prepend_version', |
| 368 default=None, |
| 369 help='Add an identifier to the front of the version') |
| 316 parser.add_option('-f', '--filters', dest='filters', action='store_true', | 370 parser.add_option('-f', '--filters', dest='filters', action='store_true', |
| 317 default=False, | 371 default=False, |
| 318 help='Turn on filtering of private ebuild packages') | 372 help='Turn on filtering of private ebuild packages') |
| 319 | 373 |
| 320 options, args = parser.parse_args() | 374 options, args = parser.parse_args() |
| 321 # Setup boto environment for gsutil to use | 375 # Setup boto environment for gsutil to use |
| 322 os.environ['BOTO_CONFIG'] = _BOTO_CONFIG | 376 os.environ['BOTO_CONFIG'] = _BOTO_CONFIG |
| 323 if not options.build_path: | 377 if not options.build_path: |
| 324 usage(parser, 'Error: you need provide a chroot path') | 378 usage(parser, 'Error: you need provide a chroot path') |
| 325 | 379 |
| 326 if not options.upload: | 380 if not options.upload: |
| 327 usage(parser, 'Error: you need to provide a gsutil upload bucket -u') | 381 usage(parser, 'Error: you need to provide a gsutil upload bucket -u') |
| 328 | 382 |
| 329 if options.filters: | 383 if options.filters: |
| 330 LoadPrivateFilters(options.build_path) | 384 LoadPrivateFilters(options.build_path) |
| 331 | 385 |
| 332 git_file = None | 386 version = GetVersion() |
| 333 if options.git_sync: | 387 if options.prepend_version: |
| 334 git_file = os.path.join(options.build_path, VER_FILE) | 388 version = '%s-%s' % (options.prepend_version, version) |
| 335 | 389 |
| 336 if options.sync_host: | 390 if options.sync_host: |
| 337 UploadPrebuilt(options.build_path, options.upload, git_file=git_file) | 391 UploadPrebuilt(options.build_path, options.upload, version, |
| 392 git_sync=options.git_sync) |
| 338 | 393 |
| 339 if options.board: | 394 if options.board: |
| 340 UploadPrebuilt(options.build_path, options.upload, board=options.board, | 395 UploadPrebuilt(options.build_path, options.upload, version, |
| 341 git_file=git_file) | 396 board=options.board, git_sync=options.git_sync) |
| 342 | 397 |
| 343 | 398 |
| 344 if __name__ == '__main__': | 399 if __name__ == '__main__': |
| 345 main() | 400 main() |
| OLD | NEW |