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 |