1*635a8641SAndroid Build Coastguard Worker#!/usr/bin/env python 2*635a8641SAndroid Build Coastguard Worker# Copyright 2014 The Chromium Authors. All rights reserved. 3*635a8641SAndroid Build Coastguard Worker# Use of this source code is governed by a BSD-style license that can be 4*635a8641SAndroid Build Coastguard Worker# found in the LICENSE file. 5*635a8641SAndroid Build Coastguard Worker 6*635a8641SAndroid Build Coastguard Worker"""Scans build output directory for .isolated files, calculates their SHA1 7*635a8641SAndroid Build Coastguard Workerhashes, stores final list in JSON document and then removes *.isolated files 8*635a8641SAndroid Build Coastguard Workerfound (to ensure no stale *.isolated stay around on the next build). 9*635a8641SAndroid Build Coastguard Worker 10*635a8641SAndroid Build Coastguard WorkerUsed to figure out what tests were build in isolated mode to trigger these 11*635a8641SAndroid Build Coastguard Workertests to run on swarming. 12*635a8641SAndroid Build Coastguard Worker 13*635a8641SAndroid Build Coastguard WorkerFor more info see: 14*635a8641SAndroid Build Coastguard Workerhttps://sites.google.com/a/chromium.org/dev/developers/testing/isolated-testing 15*635a8641SAndroid Build Coastguard Worker""" 16*635a8641SAndroid Build Coastguard Worker 17*635a8641SAndroid Build Coastguard Workerimport glob 18*635a8641SAndroid Build Coastguard Workerimport hashlib 19*635a8641SAndroid Build Coastguard Workerimport json 20*635a8641SAndroid Build Coastguard Workerimport optparse 21*635a8641SAndroid Build Coastguard Workerimport os 22*635a8641SAndroid Build Coastguard Workerimport re 23*635a8641SAndroid Build Coastguard Workerimport sys 24*635a8641SAndroid Build Coastguard Worker 25*635a8641SAndroid Build Coastguard Worker 26*635a8641SAndroid Build Coastguard Workerdef hash_file(filepath): 27*635a8641SAndroid Build Coastguard Worker """Calculates the hash of a file without reading it all in memory at once.""" 28*635a8641SAndroid Build Coastguard Worker digest = hashlib.sha1() 29*635a8641SAndroid Build Coastguard Worker with open(filepath, 'rb') as f: 30*635a8641SAndroid Build Coastguard Worker while True: 31*635a8641SAndroid Build Coastguard Worker chunk = f.read(1024*1024) 32*635a8641SAndroid Build Coastguard Worker if not chunk: 33*635a8641SAndroid Build Coastguard Worker break 34*635a8641SAndroid Build Coastguard Worker digest.update(chunk) 35*635a8641SAndroid Build Coastguard Worker return digest.hexdigest() 36*635a8641SAndroid Build Coastguard Worker 37*635a8641SAndroid Build Coastguard Worker 38*635a8641SAndroid Build Coastguard Workerdef main(): 39*635a8641SAndroid Build Coastguard Worker parser = optparse.OptionParser( 40*635a8641SAndroid Build Coastguard Worker usage='%prog --build-dir <path> --output-json <path>', 41*635a8641SAndroid Build Coastguard Worker description=sys.modules[__name__].__doc__) 42*635a8641SAndroid Build Coastguard Worker parser.add_option( 43*635a8641SAndroid Build Coastguard Worker '--build-dir', 44*635a8641SAndroid Build Coastguard Worker help='Path to a directory to search for *.isolated files.') 45*635a8641SAndroid Build Coastguard Worker parser.add_option( 46*635a8641SAndroid Build Coastguard Worker '--output-json', 47*635a8641SAndroid Build Coastguard Worker help='File to dump JSON results into.') 48*635a8641SAndroid Build Coastguard Worker 49*635a8641SAndroid Build Coastguard Worker options, _ = parser.parse_args() 50*635a8641SAndroid Build Coastguard Worker if not options.build_dir: 51*635a8641SAndroid Build Coastguard Worker parser.error('--build-dir option is required') 52*635a8641SAndroid Build Coastguard Worker if not options.output_json: 53*635a8641SAndroid Build Coastguard Worker parser.error('--output-json option is required') 54*635a8641SAndroid Build Coastguard Worker 55*635a8641SAndroid Build Coastguard Worker result = {} 56*635a8641SAndroid Build Coastguard Worker 57*635a8641SAndroid Build Coastguard Worker # Get the file hash values and output the pair. 58*635a8641SAndroid Build Coastguard Worker pattern = os.path.join(options.build_dir, '*.isolated') 59*635a8641SAndroid Build Coastguard Worker for filepath in sorted(glob.glob(pattern)): 60*635a8641SAndroid Build Coastguard Worker test_name = os.path.splitext(os.path.basename(filepath))[0] 61*635a8641SAndroid Build Coastguard Worker if re.match(r'^.+?\.\d$', test_name): 62*635a8641SAndroid Build Coastguard Worker # It's a split .isolated file, e.g. foo.0.isolated. Ignore these. 63*635a8641SAndroid Build Coastguard Worker continue 64*635a8641SAndroid Build Coastguard Worker 65*635a8641SAndroid Build Coastguard Worker # TODO(csharp): Remove deletion once the isolate tracked dependencies are 66*635a8641SAndroid Build Coastguard Worker # inputs for the isolated files. 67*635a8641SAndroid Build Coastguard Worker sha1_hash = hash_file(filepath) 68*635a8641SAndroid Build Coastguard Worker os.remove(filepath) 69*635a8641SAndroid Build Coastguard Worker result[test_name] = sha1_hash 70*635a8641SAndroid Build Coastguard Worker 71*635a8641SAndroid Build Coastguard Worker with open(options.output_json, 'wb') as f: 72*635a8641SAndroid Build Coastguard Worker json.dump(result, f) 73*635a8641SAndroid Build Coastguard Worker 74*635a8641SAndroid Build Coastguard Worker return 0 75*635a8641SAndroid Build Coastguard Worker 76*635a8641SAndroid Build Coastguard Worker 77*635a8641SAndroid Build Coastguard Workerif __name__ == '__main__': 78*635a8641SAndroid Build Coastguard Worker sys.exit(main()) 79