1#!/usr/bin/env python 2# Copyright 2014 The Chromium Authors. All rights reserved. 3# Use of this source code is governed by a BSD-style license that can be 4# found in the LICENSE file. 5 6"""Scans build output directory for .isolated files, calculates their SHA1 7hashes and stores final list in JSON document. 8 9Used to figure out what tests were build in isolated mode to trigger these 10tests to run on swarming. 11 12For more info see: 13https://sites.google.com/a/chromium.org/dev/developers/testing/isolated-testing 14""" 15 16import glob 17import hashlib 18import json 19import optparse 20import os 21import re 22import sys 23 24 25def hash_file(filepath): 26 """Calculates the hash of a file without reading it all in memory at once.""" 27 digest = hashlib.sha1() 28 with open(filepath, 'rb') as f: 29 while True: 30 chunk = f.read(1024*1024) 31 if not chunk: 32 break 33 digest.update(chunk) 34 return digest.hexdigest() 35 36 37def main(): 38 parser = optparse.OptionParser( 39 usage='%prog --build-dir <path> ' 40 '[--output-json <path> | --clean-isolated-files]', 41 description=sys.modules[__name__].__doc__) 42 parser.add_option( 43 '--build-dir', 44 help='Path to a directory to search for *.isolated files.') 45 parser.add_option( 46 '--output-json', 47 help='File to dump JSON results into. ' 48 'Mutually exclusive with --clean-isolated-files.') 49 parser.add_option( 50 '--clean-isolated-files', 51 action='store_true', 52 help='Whether to clean out all .isolated and .isolated.gen.json files. ' 53 'Mutually exclusive with --output-json.') 54 55 options, _ = parser.parse_args() 56 if not options.build_dir: 57 parser.error('--build-dir option is required') 58 if not (options.output_json or options.clean_isolated_files): 59 parser.error('either --output-json or --clean-isolated-files is required') 60 if options.output_json and options.clean_isolated_files: 61 parser.error('only one of --output-json and ' 62 '--clean-isolated-files is allowed') 63 64 result = {} 65 66 # Clean up generated *.isolated.gen.json files, produced by isolate_driver.py 67 # in test_isolation_mode='prepare'. 68 if options.clean_isolated_files: 69 pattern = os.path.join(options.build_dir, '*.isolated.gen.json') 70 for filepath in sorted(glob.glob(pattern)): 71 os.remove(filepath) 72 73 # Get the file hash values and output the pair. 74 pattern = os.path.join(options.build_dir, '*.isolated') 75 for filepath in sorted(glob.glob(pattern)): 76 test_name = os.path.splitext(os.path.basename(filepath))[0] 77 if re.match(r'^.+?\.\d$', test_name): 78 # It's a split .isolated file, e.g. foo.0.isolated. Ignore these. 79 continue 80 81 if options.clean_isolated_files: 82 # TODO(csharp): Remove deletion entirely once the isolate 83 # tracked dependencies are inputs for the isolated files. 84 # http://crbug.com/419031 85 os.remove(filepath) 86 else: 87 sha1_hash = hash_file(filepath) 88 result[test_name] = sha1_hash 89 90 if options.output_json: 91 with open(options.output_json, 'wb') as f: 92 json.dump(result, f) 93 94 return 0 95 96 97if __name__ == '__main__': 98 sys.exit(main()) 99