Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
| 2 # Copyright 2013 The Chromium Authors. All rights reserved. | 2 # Copyright 2013 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 """Downloads and unpacks a toolchain for building on Windows. The contents are | 6 """Downloads and unpacks a toolchain for building on Windows. The contents are |
| 7 matched by sha1 which will be updated when the toolchain is updated. | 7 matched by sha1 which will be updated when the toolchain is updated. |
| 8 | 8 |
| 9 Having a toolchain script in depot_tools means that it's not versioned | 9 Having a toolchain script in depot_tools means that it's not versioned |
| 10 directly with the source code. That is, if the toolchain is upgraded, but | 10 directly with the source code. That is, if the toolchain is upgraded, but |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 65 # Allow use of utility functions in this script from package_from_installed | 65 # Allow use of utility functions in this script from package_from_installed |
| 66 # on bare VM that doesn't have a full depot_tools. | 66 # on bare VM that doesn't have a full depot_tools. |
| 67 pass | 67 pass |
| 68 | 68 |
| 69 | 69 |
| 70 def GetFileList(root): | 70 def GetFileList(root): |
| 71 """Gets a normalized list of files under |root|.""" | 71 """Gets a normalized list of files under |root|.""" |
| 72 assert not os.path.isabs(root) | 72 assert not os.path.isabs(root) |
| 73 assert os.path.normpath(root) == root | 73 assert os.path.normpath(root) == root |
| 74 file_list = [] | 74 file_list = [] |
| 75 # Ignore WER ReportQueue entries that vctip/cl leave in the bin dir if/when | |
| 76 # they crash. Also ignores the content of the win_sdk/debuggers/x(86|64)/sym/ | |
| 77 # directories as this is just the temporarily location that Windbg might use | |
| 78 # to store the symbol files. | |
| 79 ignored_directories = ['wer\\reportqueue', | |
|
scottmg
2016/05/11 19:21:36
Does this intentionally not have a trailing \?
Sébastien Marchand
2016/05/11 19:59:50
I don't know if reportqueue is the name of the dir
| |
| 80 'win_sdk\\debuggers\\x86\\sym\\', | |
| 81 'win_sdk\\debuggers\\x64\\sym\\'] | |
| 75 for base, _, files in os.walk(root): | 82 for base, _, files in os.walk(root): |
| 76 paths = [os.path.join(base, f) for f in files] | 83 paths = [os.path.join(base, f).lower() for f in files] |
| 77 # Ignore WER ReportQueue entries that vctip/cl leave in the bin dir if/when | 84 for f in paths: |
|
scottmg
2016/05/11 19:21:36
maybe p instead of f since f is used above
Sébastien Marchand
2016/05/11 19:59:50
Done.
| |
| 78 # they crash. | 85 if any(ignored_dir in f for ignored_dir in ignored_directories): |
| 79 file_list.extend(x.lower() for x in paths if 'WER\\ReportQueue' not in x) | 86 continue |
| 87 file_list.append(f) | |
| 80 return sorted(file_list, key=lambda s: s.replace('/', '\\')) | 88 return sorted(file_list, key=lambda s: s.replace('/', '\\')) |
| 81 | 89 |
| 82 | 90 |
| 83 def MakeTimestampsFileName(root, sha1): | 91 def MakeTimestampsFileName(root, sha1): |
| 84 return os.path.join(root, os.pardir, '%s.timestamps' % sha1) | 92 return os.path.join(root, os.pardir, '%s.timestamps' % sha1) |
| 85 | 93 |
| 86 | 94 |
| 87 def CalculateHash(root, expected_hash): | 95 def CalculateHash(root, expected_hash): |
| 88 """Calculates the sha1 of the paths to all files in the given |root| and the | 96 """Calculates the sha1 of the paths to all files in the given |root| and the |
| 89 contents of those files, and returns as a hex string. | 97 contents of those files, and returns as a hex string. |
| (...skipping 22 matching lines...) Expand all Loading... | |
| 112 matches = len(file_list) == len(timestamps_data['files']) | 120 matches = len(file_list) == len(timestamps_data['files']) |
| 113 # Don't check the timestamp of the version file as we touch this file to | 121 # Don't check the timestamp of the version file as we touch this file to |
| 114 # indicates which versions of the toolchain are still being used. | 122 # indicates which versions of the toolchain are still being used. |
| 115 vc_dir = os.path.join(full_root_path, 'VC').lower() | 123 vc_dir = os.path.join(full_root_path, 'VC').lower() |
| 116 if matches: | 124 if matches: |
| 117 for disk, cached in zip(file_list, timestamps_data['files']): | 125 for disk, cached in zip(file_list, timestamps_data['files']): |
| 118 if disk != cached[0] or ( | 126 if disk != cached[0] or ( |
| 119 disk != vc_dir and os.path.getmtime(disk) != cached[1]): | 127 disk != vc_dir and os.path.getmtime(disk) != cached[1]): |
| 120 matches = False | 128 matches = False |
| 121 break | 129 break |
| 130 elif os.path.exists(timestamps_file): | |
| 131 # Print some information about the extra/missing files. Don't do this if we | |
| 132 # don't have a timestamp file, as all the files will be considered as | |
| 133 # missing. | |
| 134 timestamps_data_files = [] | |
| 135 for f in timestamps_data['files']: | |
| 136 timestamps_data_files.append(f[0]) | |
| 137 missing_files = [f for f in timestamps_data_files if f not in file_list] | |
| 138 if len(missing_files): | |
| 139 print ('Some files are missing from the %s version of the toolchain:' % | |
| 140 expected_hash) | |
| 141 for f in missing_files: | |
| 142 print '\t%s' % f | |
| 143 extra_files = [f for f in file_list if f not in timestamps_data_files] | |
| 144 if len(extra_files): | |
| 145 print ('There\'s some extra files in the %s version of the toolchain:' % | |
| 146 expected_hash) | |
| 147 for f in extra_files: | |
| 148 print '\t%s' % f | |
| 122 if matches: | 149 if matches: |
| 123 return timestamps_data['sha1'] | 150 return timestamps_data['sha1'] |
| 124 | 151 |
| 125 # Make long hangs when updating the toolchain less mysterious. | 152 # Make long hangs when updating the toolchain less mysterious. |
| 126 print 'Calculating hash of toolchain in %s. Please wait...' % full_root_path | 153 print 'Calculating hash of toolchain in %s. Please wait...' % full_root_path |
| 127 sys.stdout.flush() | 154 sys.stdout.flush() |
| 128 digest = hashlib.sha1() | 155 digest = hashlib.sha1() |
| 129 for path in file_list: | 156 for path in file_list: |
| 130 path_without_hash = str(path).replace('/', '\\') | 157 path_without_hash = str(path).replace('/', '\\') |
| 131 if expected_hash: | 158 if expected_hash: |
| 132 path_without_hash = path_without_hash.replace( | 159 path_without_hash = path_without_hash.replace( |
| 133 os.path.join(root, expected_hash).replace('/', '\\'), root) | 160 os.path.join(root, expected_hash).replace('/', '\\'), root) |
| 134 digest.update(path_without_hash) | 161 digest.update(path_without_hash) |
| 135 with open(path, 'rb') as f: | 162 with open(path, 'rb') as f: |
| 136 digest.update(f.read()) | 163 digest.update(f.read()) |
| 137 return digest.hexdigest() | 164 return digest.hexdigest() |
| 138 | 165 |
| 139 | 166 |
| 140 def CalculateToolchainHashes(root): | 167 def CalculateToolchainHashes(root, remove_corrupt_toolchains): |
|
scottmg
2016/05/11 19:21:36
This new argument doesn't seem to be used.
Sébastien Marchand
2016/05/11 19:59:50
Oops. Fixed.
| |
| 141 """Calculate the hash of the different toolchains installed in the |root| | 168 """Calculate the hash of the different toolchains installed in the |root| |
| 142 directory.""" | 169 directory.""" |
| 143 hashes = [] | 170 hashes = [] |
| 144 dir_list = [ | 171 dir_list = [ |
| 145 d for d in os.listdir(root) if os.path.isdir(os.path.join(root, d))] | 172 d for d in os.listdir(root) if os.path.isdir(os.path.join(root, d))] |
| 146 for d in dir_list: | 173 for d in dir_list: |
| 147 hashes.append(CalculateHash(root, d)) | 174 toolchain_hash = CalculateHash(root, d) |
| 175 if toolchain_hash != d: | |
| 176 print ('The hash of a version of the toolchain has an unexpected value (' | |
| 177 '%s instead of %s), removing it.' % (toolchain_hash, d)) | |
| 178 RemoveToolchain(root, d, True) | |
| 179 else: | |
| 180 hashes.append(toolchain_hash) | |
| 148 return hashes | 181 return hashes |
| 149 | 182 |
| 150 | 183 |
| 151 def SaveTimestampsAndHash(root, sha1): | 184 def SaveTimestampsAndHash(root, sha1): |
| 152 """Saves timestamps and the final hash to be able to early-out more quickly | 185 """Saves timestamps and the final hash to be able to early-out more quickly |
| 153 next time.""" | 186 next time.""" |
| 154 file_list = GetFileList(os.path.join(root, sha1)) | 187 file_list = GetFileList(os.path.join(root, sha1)) |
| 155 timestamps_data = { | 188 timestamps_data = { |
| 156 'files': [[f, os.path.getmtime(f)] for f in file_list], | 189 'files': [[f, os.path.getmtime(f)] for f in file_list], |
| 157 'sha1': sha1, | 190 'sha1': sha1, |
| (...skipping 260 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 418 toolchain_target_dir = os.path.join(target_dir, desired_hash) | 451 toolchain_target_dir = os.path.join(target_dir, desired_hash) |
| 419 | 452 |
| 420 abs_toolchain_target_dir = os.path.abspath(toolchain_target_dir) | 453 abs_toolchain_target_dir = os.path.abspath(toolchain_target_dir) |
| 421 | 454 |
| 422 got_new_toolchain = False | 455 got_new_toolchain = False |
| 423 | 456 |
| 424 # If the current hash doesn't match what we want in the file, nuke and pave. | 457 # If the current hash doesn't match what we want in the file, nuke and pave. |
| 425 # Typically this script is only run when the .sha1 one file is updated, but | 458 # Typically this script is only run when the .sha1 one file is updated, but |
| 426 # directly calling "gclient runhooks" will also run it, so we cache | 459 # directly calling "gclient runhooks" will also run it, so we cache |
| 427 # based on timestamps to make that case fast. | 460 # based on timestamps to make that case fast. |
| 428 current_hashes = CalculateToolchainHashes(target_dir) | 461 current_hashes = CalculateToolchainHashes(target_dir, True) |
| 429 if desired_hash not in current_hashes: | 462 if desired_hash not in current_hashes: |
| 430 should_use_gs = False | 463 should_use_gs = False |
| 431 if (HaveSrcInternalAccess() or | 464 if (HaveSrcInternalAccess() or |
| 432 LooksLikeGoogler() or | 465 LooksLikeGoogler() or |
| 433 CanAccessToolchainBucket()): | 466 CanAccessToolchainBucket()): |
| 434 should_use_gs = True | 467 should_use_gs = True |
| 435 if not CanAccessToolchainBucket(): | 468 if not CanAccessToolchainBucket(): |
| 436 RequestGsAuthentication() | 469 RequestGsAuthentication() |
| 437 if not should_use_gs: | 470 if not should_use_gs: |
| 438 print('\n\n\nPlease follow the instructions at ' | 471 print('\n\n\nPlease follow the instructions at ' |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 472 'wdk': os.path.join(abs_toolchain_target_dir, 'wdk'), | 505 'wdk': os.path.join(abs_toolchain_target_dir, 'wdk'), |
| 473 'runtime_dirs': [ | 506 'runtime_dirs': [ |
| 474 os.path.join(abs_toolchain_target_dir, 'sys64'), | 507 os.path.join(abs_toolchain_target_dir, 'sys64'), |
| 475 os.path.join(abs_toolchain_target_dir, 'sys32'), | 508 os.path.join(abs_toolchain_target_dir, 'sys32'), |
| 476 ], | 509 ], |
| 477 } | 510 } |
| 478 with open(os.path.join(target_dir, '..', 'data.json'), 'w') as f: | 511 with open(os.path.join(target_dir, '..', 'data.json'), 'w') as f: |
| 479 json.dump(data, f) | 512 json.dump(data, f) |
| 480 | 513 |
| 481 if got_new_toolchain: | 514 if got_new_toolchain: |
| 482 current_hashes = CalculateToolchainHashes(target_dir) | 515 current_hashes = CalculateToolchainHashes(target_dir, False) |
| 483 if desired_hash not in current_hashes: | 516 if desired_hash not in current_hashes: |
| 484 print >> sys.stderr, ( | 517 print >> sys.stderr, ( |
| 485 'Got wrong hash after pulling a new toolchain. ' | 518 'Got wrong hash after pulling a new toolchain. ' |
| 486 'Wanted \'%s\', got one of \'%s\'.' % ( | 519 'Wanted \'%s\', got one of \'%s\'.' % ( |
| 487 desired_hash, ', '.join(current_hashes))) | 520 desired_hash, ', '.join(current_hashes))) |
| 488 return 1 | 521 return 1 |
| 489 SaveTimestampsAndHash(target_dir, desired_hash) | 522 SaveTimestampsAndHash(target_dir, desired_hash) |
| 490 | 523 |
| 491 if options.output_json: | 524 if options.output_json: |
| 492 shutil.copyfile(os.path.join(target_dir, '..', 'data.json'), | 525 shutil.copyfile(os.path.join(target_dir, '..', 'data.json'), |
| 493 options.output_json) | 526 options.output_json) |
| 494 | 527 |
| 495 EnableCrashDumpCollection() | 528 EnableCrashDumpCollection() |
| 496 | 529 |
| 497 if os.environ.get('GYP_MSVS_VERSION') == '2015': | 530 if os.environ.get('GYP_MSVS_VERSION') == '2015': |
| 498 InstallUniversalCRTIfNeeded(abs_toolchain_target_dir) | 531 InstallUniversalCRTIfNeeded(abs_toolchain_target_dir) |
| 499 | 532 |
| 500 RemoveUnusedToolchains(target_dir) | 533 RemoveUnusedToolchains(target_dir) |
| 501 | 534 |
| 502 return 0 | 535 return 0 |
| 503 | 536 |
| 504 | 537 |
| 505 if __name__ == '__main__': | 538 if __name__ == '__main__': |
| 506 sys.exit(main()) | 539 sys.exit(main()) |
| OLD | NEW |