|  | #!/usr/bin/env python | 
|  | # Copyright 2014 The Chromium Authors. All rights reserved. | 
|  | # Use of this source code is governed by a BSD-style license that can be | 
|  | # found in the LICENSE file. | 
|  |  | 
|  | """Scans build output directory for .isolated files, calculates their SHA1 | 
|  | hashes, stores final list in JSON document and then removes *.isolated files | 
|  | found (to ensure no stale *.isolated stay around on the next build). | 
|  |  | 
|  | Used to figure out what tests were build in isolated mode to trigger these | 
|  | tests to run on swarming. | 
|  |  | 
|  | For more info see: | 
|  | https://sites.google.com/a/chromium.org/dev/developers/testing/isolated-testing | 
|  | """ | 
|  |  | 
|  | import glob | 
|  | import hashlib | 
|  | import json | 
|  | import optparse | 
|  | import os | 
|  | import re | 
|  | import sys | 
|  |  | 
|  |  | 
|  | def hash_file(filepath): | 
|  | """Calculates the hash of a file without reading it all in memory at once.""" | 
|  | digest = hashlib.sha1() | 
|  | with open(filepath, 'rb') as f: | 
|  | while True: | 
|  | chunk = f.read(1024*1024) | 
|  | if not chunk: | 
|  | break | 
|  | digest.update(chunk) | 
|  | return digest.hexdigest() | 
|  |  | 
|  |  | 
|  | def main(): | 
|  | parser = optparse.OptionParser( | 
|  | usage='%prog --build-dir <path> --output-json <path>', | 
|  | description=sys.modules[__name__].__doc__) | 
|  | parser.add_option( | 
|  | '--build-dir', | 
|  | help='Path to a directory to search for *.isolated files.') | 
|  | parser.add_option( | 
|  | '--output-json', | 
|  | help='File to dump JSON results into.') | 
|  |  | 
|  | options, _ = parser.parse_args() | 
|  | if not options.build_dir: | 
|  | parser.error('--build-dir option is required') | 
|  | if not options.output_json: | 
|  | parser.error('--output-json option is required') | 
|  |  | 
|  | result = {} | 
|  |  | 
|  | # Get the file hash values and output the pair. | 
|  | pattern = os.path.join(options.build_dir, '*.isolated') | 
|  | for filepath in sorted(glob.glob(pattern)): | 
|  | test_name = os.path.splitext(os.path.basename(filepath))[0] | 
|  | if re.match(r'^.+?\.\d$', test_name): | 
|  | # It's a split .isolated file, e.g. foo.0.isolated. Ignore these. | 
|  | continue | 
|  |  | 
|  | # TODO(csharp): Remove deletion once the isolate tracked dependencies are | 
|  | # inputs for the isolated files. | 
|  | sha1_hash = hash_file(filepath) | 
|  | os.remove(filepath) | 
|  | result[test_name] = sha1_hash | 
|  |  | 
|  | with open(options.output_json, 'wb') as f: | 
|  | json.dump(result, f) | 
|  |  | 
|  | return 0 | 
|  |  | 
|  |  | 
|  | if __name__ == '__main__': | 
|  | sys.exit(main()) |