Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
| 2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. | 2 # Copyright (c) 2012 The Chromium 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 """Uploads files to Google Storage content addressed.""" | 6 """Uploads files to Google Storage content addressed.""" |
| 7 | 7 |
| 8 import hashlib | 8 import hashlib |
| 9 import optparse | 9 import optparse |
| 10 import os | 10 import os |
| (...skipping 21 matching lines...) Expand all Loading... | |
| 32 DEPS file to call download_from_google_storage.py. | 32 DEPS file to call download_from_google_storage.py. |
| 33 | 33 |
| 34 Example usages | 34 Example usages |
| 35 -------------- | 35 -------------- |
| 36 | 36 |
| 37 Scan the current directory and upload all files larger than 1MB: | 37 Scan the current directory and upload all files larger than 1MB: |
| 38 find . -name .svn -prune -o -size +1000k -type f -print0 | %prog -0 -b bkt - | 38 find . -name .svn -prune -o -size +1000k -type f -print0 | %prog -0 -b bkt - |
| 39 (Replace "bkt" with the name of a writable bucket.) | 39 (Replace "bkt" with the name of a writable bucket.) |
| 40 """ | 40 """ |
| 41 | 41 |
| 42 SET_EXECUTABLE_RETRY_DELAY = 5.0 | |
| 43 SET_EXECUTABLE_MAX_TRIES = 6 | |
|
tandrii(chromium)
2016/03/24 09:49:24
i think these are no longer neede.d
dsansome
2016/03/29 03:24:54
Oops thanks
| |
| 44 | |
| 42 | 45 |
| 43 def get_md5(filename): | 46 def get_md5(filename): |
| 44 md5_calculator = hashlib.md5() | 47 md5_calculator = hashlib.md5() |
| 45 with open(filename, 'rb') as f: | 48 with open(filename, 'rb') as f: |
| 46 while True: | 49 while True: |
| 47 chunk = f.read(1024*1024) | 50 chunk = f.read(1024*1024) |
| 48 if not chunk: | 51 if not chunk: |
| 49 break | 52 break |
| 50 md5_calculator.update(chunk) | 53 md5_calculator.update(chunk) |
| 51 return md5_calculator.hexdigest() | 54 return md5_calculator.hexdigest() |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 69 def _upload_worker( | 72 def _upload_worker( |
| 70 thread_num, upload_queue, base_url, gsutil, md5_lock, force, | 73 thread_num, upload_queue, base_url, gsutil, md5_lock, force, |
| 71 use_md5, stdout_queue, ret_codes, gzip): | 74 use_md5, stdout_queue, ret_codes, gzip): |
| 72 while True: | 75 while True: |
| 73 filename, sha1_sum = upload_queue.get() | 76 filename, sha1_sum = upload_queue.get() |
| 74 if not filename: | 77 if not filename: |
| 75 break | 78 break |
| 76 file_url = '%s/%s' % (base_url, sha1_sum) | 79 file_url = '%s/%s' % (base_url, sha1_sum) |
| 77 if gsutil.check_call('ls', file_url)[0] == 0 and not force: | 80 if gsutil.check_call('ls', file_url)[0] == 0 and not force: |
| 78 # File exists, check MD5 hash. | 81 # File exists, check MD5 hash. |
| 79 _, out, _ = gsutil.check_call('ls', '-L', file_url) | 82 _, out, _ = gsutil.check_call_with_retries('ls', '-L', file_url) |
| 80 etag_match = re.search('ETag:\s+([a-z0-9]{32})', out) | 83 etag_match = re.search('ETag:\s+([a-z0-9]{32})', out) |
| 81 if etag_match: | 84 if etag_match: |
| 82 remote_md5 = etag_match.group(1) | 85 remote_md5 = etag_match.group(1) |
| 83 # Calculate the MD5 checksum to match it to Google Storage's ETag. | 86 # Calculate the MD5 checksum to match it to Google Storage's ETag. |
| 84 with md5_lock: | 87 with md5_lock: |
| 85 if use_md5: | 88 if use_md5: |
| 86 local_md5 = get_md5_cached(filename) | 89 local_md5 = get_md5_cached(filename) |
| 87 else: | 90 else: |
| 88 local_md5 = get_md5(filename) | 91 local_md5 = get_md5(filename) |
| 89 if local_md5 == remote_md5: | 92 if local_md5 == remote_md5: |
| 90 stdout_queue.put( | 93 stdout_queue.put( |
| 91 '%d> File %s already exists and MD5 matches, upload skipped' % | 94 '%d> File %s already exists and MD5 matches, upload skipped' % |
| 92 (thread_num, filename)) | 95 (thread_num, filename)) |
| 93 continue | 96 continue |
| 94 stdout_queue.put('%d> Uploading %s...' % ( | 97 stdout_queue.put('%d> Uploading %s...' % ( |
| 95 thread_num, filename)) | 98 thread_num, filename)) |
| 96 gsutil_args = ['cp'] | 99 gsutil_args = ['cp'] |
| 97 if gzip: | 100 if gzip: |
| 98 gsutil_args.extend(['-z', gzip]) | 101 gsutil_args.extend(['-z', gzip]) |
| 99 gsutil_args.extend([filename, file_url]) | 102 gsutil_args.extend([filename, file_url]) |
| 100 code, _, err = gsutil.check_call(*gsutil_args) | 103 code, _, err = gsutil.check_call_with_retries(*gsutil_args) |
|
tandrii(chromium)
2016/03/24 09:49:24
+hinoka@ I'm not sure retrying any non-0 code is a
hinoka
2016/03/24 11:28:54
In general I think if this one fails once, it migh
| |
| 101 if code != 0: | 104 if code != 0: |
| 102 ret_codes.put( | 105 ret_codes.put( |
| 103 (code, | 106 (code, |
| 104 'Encountered error on uploading %s to %s\n%s' % | 107 'Encountered error on uploading %s to %s\n%s' % |
| 105 (filename, file_url, err))) | 108 (filename, file_url, err))) |
| 106 continue | 109 continue |
| 107 | 110 |
| 108 # Mark executable files with the header "x-goog-meta-executable: 1" which | 111 # Mark executable files with the header "x-goog-meta-executable: 1" which |
| 109 # the download script will check for to preserve the executable bit. | 112 # the download script will check for to preserve the executable bit. |
| 110 if not sys.platform.startswith('win'): | 113 if not sys.platform.startswith('win'): |
| 111 if os.stat(filename).st_mode & stat.S_IEXEC: | 114 if os.stat(filename).st_mode & stat.S_IEXEC: |
| 112 code, _, err = gsutil.check_call('setmeta', '-h', | 115 code, _, err = gsutil.check_call_with_retries( |
| 113 'x-goog-meta-executable:1', file_url) | 116 'setmeta', '-h', 'x-goog-meta-executable:1', file_url) |
| 114 if code: | 117 if not code: |
| 115 ret_codes.put( | 118 ret_codes.put( |
| 116 (code, | 119 (code, |
| 117 'Encountered error on setting metadata on %s\n%s' % | 120 'Encountered error on setting metadata on %s after %d ' |
| 118 (file_url, err))) | 121 'tries\n%s' % (file_url, SET_EXECUTABLE_MAX_TRIES, err))) |
| 119 | 122 |
| 120 | 123 |
| 121 def get_targets(args, parser, use_null_terminator): | 124 def get_targets(args, parser, use_null_terminator): |
| 122 if not args: | 125 if not args: |
| 123 parser.error('Missing target.') | 126 parser.error('Missing target.') |
| 124 | 127 |
| 125 if len(args) == 1 and args[0] == '-': | 128 if len(args) == 1 and args[0] == '-': |
| 126 # Take stdin as a newline or null seperated list of files. | 129 # Take stdin as a newline or null seperated list of files. |
| 127 if use_null_terminator: | 130 if use_null_terminator: |
| 128 return sys.stdin.read().split('\0') | 131 return sys.stdin.read().split('\0') |
| (...skipping 161 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 290 input_filenames, base_url, gsutil, options.force, options.use_md5, | 293 input_filenames, base_url, gsutil, options.force, options.use_md5, |
| 291 options.num_threads, options.skip_hashing, options.gzip) | 294 options.num_threads, options.skip_hashing, options.gzip) |
| 292 | 295 |
| 293 | 296 |
| 294 if __name__ == '__main__': | 297 if __name__ == '__main__': |
| 295 try: | 298 try: |
| 296 sys.exit(main()) | 299 sys.exit(main()) |
| 297 except KeyboardInterrupt: | 300 except KeyboardInterrupt: |
| 298 sys.stderr.write('interrupted\n') | 301 sys.stderr.write('interrupted\n') |
| 299 sys.exit(1) | 302 sys.exit(1) |
| OLD | NEW |