| OLD | NEW |
| 1 # Copyright 2013 The Chromium Authors. All rights reserved. | 1 # Copyright 2013 The Chromium Authors. All rights reserved. |
| 2 # Use of this source code is governed by a BSD-style license that can be | 2 # Use of this source code is governed by a BSD-style license that can be |
| 3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
| 4 | 4 |
| 5 import difflib | 5 import difflib |
| 6 import hashlib | 6 import hashlib |
| 7 import itertools | 7 import itertools |
| 8 import json | 8 import json |
| 9 import os | 9 import os |
| 10 import sys | 10 import sys |
| 11 import zipfile | 11 import zipfile |
| 12 | 12 |
| 13 | 13 |
| 14 # When set and a difference is detected, a diff of what changed is printed. | 14 # When set and a difference is detected, a diff of what changed is printed. |
| 15 _PRINT_MD5_DIFFS = int(os.environ.get('PRINT_MD5_DIFFS', 0)) | 15 _PRINT_MD5_DIFFS = int(os.environ.get('PRINT_MD5_DIFFS', 0)) |
| 16 | 16 |
| 17 # An escape hatch that causes all targets to be rebuilt. |
| 18 _FORCE_REBUILD = int(os.environ.get('FORCE_REBUILD', 0)) |
| 19 |
| 17 | 20 |
| 18 def CallAndRecordIfStale( | 21 def CallAndRecordIfStale( |
| 19 function, record_path=None, input_paths=None, input_strings=None, | 22 function, record_path=None, input_paths=None, input_strings=None, |
| 20 output_paths=None, force=False, pass_changes=False): | 23 output_paths=None, force=False, pass_changes=False): |
| 21 """Calls function if outputs are stale. | 24 """Calls function if outputs are stale. |
| 22 | 25 |
| 23 Outputs are considered stale if: | 26 Outputs are considered stale if: |
| 24 - any output_paths are missing, or | 27 - any output_paths are missing, or |
| 25 - the contents of any file within input_paths has changed, or | 28 - the contents of any file within input_paths has changed, or |
| 26 - the contents of input_strings has changed. | 29 - the contents of input_strings has changed. |
| (...skipping 26 matching lines...) Expand all Loading... |
| 53 new_metadata.AddStrings(input_strings) | 56 new_metadata.AddStrings(input_strings) |
| 54 | 57 |
| 55 for path in input_paths: | 58 for path in input_paths: |
| 56 if _IsZipFile(path): | 59 if _IsZipFile(path): |
| 57 entries = _ExtractZipEntries(path) | 60 entries = _ExtractZipEntries(path) |
| 58 new_metadata.AddZipFile(path, entries) | 61 new_metadata.AddZipFile(path, entries) |
| 59 else: | 62 else: |
| 60 new_metadata.AddFile(path, _Md5ForPath(path)) | 63 new_metadata.AddFile(path, _Md5ForPath(path)) |
| 61 | 64 |
| 62 old_metadata = None | 65 old_metadata = None |
| 66 force = force or _FORCE_REBUILD |
| 63 missing_outputs = [x for x in output_paths if force or not os.path.exists(x)] | 67 missing_outputs = [x for x in output_paths if force or not os.path.exists(x)] |
| 64 # When outputs are missing, don't bother gathering change information. | 68 # When outputs are missing, don't bother gathering change information. |
| 65 if not missing_outputs and os.path.exists(record_path): | 69 if not missing_outputs and os.path.exists(record_path): |
| 66 with open(record_path, 'r') as jsonfile: | 70 with open(record_path, 'r') as jsonfile: |
| 67 try: | 71 try: |
| 68 old_metadata = _Metadata.FromFile(jsonfile) | 72 old_metadata = _Metadata.FromFile(jsonfile) |
| 69 except: # pylint: disable=bare-except | 73 except: # pylint: disable=bare-except |
| 70 pass # Not yet using new file format. | 74 pass # Not yet using new file format. |
| 71 | 75 |
| 72 changes = Changes(old_metadata, new_metadata, force, missing_outputs) | 76 changes = Changes(old_metadata, new_metadata, force, missing_outputs) |
| 73 if not changes.HasChanges(): | 77 if not changes.HasChanges(): |
| 74 return | 78 return |
| 75 | 79 |
| 76 if _PRINT_MD5_DIFFS: | 80 if _PRINT_MD5_DIFFS: |
| 77 print '=' * 80 | 81 print '=' * 80 |
| 78 print 'Target is stale: %s' % record_path | 82 print 'Target is stale: %s' % record_path |
| 79 print changes.DescribeDifference() | 83 print changes.DescribeDifference() |
| 80 print '=' * 80 | 84 print '=' * 80 |
| 81 | 85 |
| 82 # Delete the old metdata beforehand since failures leave it in an | |
| 83 # inderterminate state. | |
| 84 if old_metadata: | |
| 85 os.unlink(record_path) | |
| 86 | |
| 87 args = (changes,) if pass_changes else () | 86 args = (changes,) if pass_changes else () |
| 88 function(*args) | 87 function(*args) |
| 89 | 88 |
| 90 with open(record_path, 'w') as f: | 89 with open(record_path, 'w') as f: |
| 91 new_metadata.ToFile(f) | 90 new_metadata.ToFile(f) |
| 92 | 91 |
| 93 | 92 |
| 94 class Changes(object): | 93 class Changes(object): |
| 95 """Provides and API for querying what changed between runs.""" | 94 """Provides and API for querying what changed between runs.""" |
| 96 | 95 |
| (...skipping 293 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 390 | 389 |
| 391 def _ExtractZipEntries(path): | 390 def _ExtractZipEntries(path): |
| 392 """Returns a list of (path, CRC32) of all files within |path|.""" | 391 """Returns a list of (path, CRC32) of all files within |path|.""" |
| 393 entries = [] | 392 entries = [] |
| 394 with zipfile.ZipFile(path) as zip_file: | 393 with zipfile.ZipFile(path) as zip_file: |
| 395 for zip_info in zip_file.infolist(): | 394 for zip_info in zip_file.infolist(): |
| 396 # Skip directories and empty files. | 395 # Skip directories and empty files. |
| 397 if zip_info.CRC: | 396 if zip_info.CRC: |
| 398 entries.append((zip_info.filename, zip_info.CRC)) | 397 entries.append((zip_info.filename, zip_info.CRC)) |
| 399 return entries | 398 return entries |
| OLD | NEW |