Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(10)

Side by Side Diff: mojo/tools/mopy/transitive_hash.py

Issue 728783003: Add infrastructure to run tests on android. (Closed) Base URL: https://github.com/domokit/mojo.git@master
Patch Set: Use file_hash Created 6 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 # Copyright 2014 The Chromium Authors. All rights reserved. 1 # Copyright 2014 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 hashlib
6 import logging 5 import logging
7 import platform 6 import platform
8 import subprocess 7 import subprocess
9 import sys 8 import sys
10 9
11 # pylint: disable=E0611 10 # pylint: disable=E0611
12 from hashlib import sha256 11 from hashlib import sha256
12 from mopy.file_hash import file_hash
13 from mopy.memoize import memoize
13 # pylint: enable=E0611 14 # pylint: enable=E0611
14 from os.path import basename, realpath 15 from os.path import basename, realpath
15 16
16 _logging = logging.getLogger() 17 _logging = logging.getLogger()
17 18
18 # pylint: disable=C0301 19 @memoize
19 # Based on/taken from
20 # http://code.activestate.com/recipes/578231-probably-the-fastest-memoization- decorator-in-the-/
21 # (with cosmetic changes).
22 # pylint: enable=C0301
23 def _memoize(f):
24 """Memoization decorator for a function taking a single argument."""
25 class Memoize(dict):
26 def __missing__(self, key):
27 rv = self[key] = f(key)
28 return rv
29 return Memoize().__getitem__
30
31 @_memoize
32 def _file_hash(filename):
33 """Returns a string representing the hash of the given file."""
34 _logging.debug("Hashing %s ...", filename)
35 with open(filename, mode='rb') as f:
36 m = hashlib.sha256()
37 while True:
38 block = f.read(4096)
39 if not block:
40 break
41 m.update(block)
42 _logging.debug(" => %s", m.hexdigest())
43 return m.hexdigest()
44
45 @_memoize
46 def _get_dependencies(filename): 20 def _get_dependencies(filename):
47 """Returns a list of filenames for files that the given file depends on.""" 21 """Returns a list of filenames for files that the given file depends on."""
48 if platform.system() == 'Windows': 22 if platform.system() == 'Windows':
49 # There's no ldd on Windows. We can try to bundle or require depends, but 23 # There's no ldd on Windows. We can try to bundle or require depends, but
50 # given that we're not supporting component build this seems low priority. 24 # given that we're not supporting component build this seems low priority.
51 return [] 25 return []
52 _logging.debug("Getting dependencies for %s ...", filename) 26 _logging.debug("Getting dependencies for %s ...", filename)
53 lines = subprocess.check_output(['ldd', filename]).splitlines() 27 lines = subprocess.check_output(['ldd', filename]).splitlines()
54 rv = [] 28 rv = []
55 for line in lines: 29 for line in lines:
56 i = line.find('/') 30 i = line.find('/')
57 if i < 0: 31 if i < 0:
58 _logging.debug(" => no file found in line: %s", line) 32 _logging.debug(" => no file found in line: %s", line)
59 continue 33 continue
60 rv.append(line[i:].split(None, 1)[0]) 34 rv.append(line[i:].split(None, 1)[0])
61 _logging.debug(" => %s", rv) 35 _logging.debug(" => %s", rv)
62 return rv 36 return rv
63 37
64 def transitive_hash(filename): 38 def transitive_hash(filename):
65 """Returns a string that represents the "transitive" hash of the given 39 """Returns a string that represents the "transitive" hash of the given
66 file. The transitive hash is a hash of the file and all the shared libraries 40 file. The transitive hash is a hash of the file and all the shared libraries
67 on which it depends (done in an order-independent way).""" 41 on which it depends (done in an order-independent way)."""
68 hashes = set() 42 hashes = set()
69 to_hash = [filename] 43 to_hash = [filename]
70 while to_hash: 44 while to_hash:
71 current_filename = realpath(to_hash.pop()) 45 current_filename = realpath(to_hash.pop())
72 current_hash = _file_hash(current_filename) 46 current_hash = file_hash(current_filename)
73 if current_hash in hashes: 47 if current_hash in hashes:
74 _logging.debug("Already seen %s (%s) ...", current_filename, current_hash) 48 _logging.debug("Already seen %s (%s) ...", current_filename, current_hash)
75 continue 49 continue
76 _logging.debug("Haven't seen %s (%s) ...", current_filename, current_hash) 50 _logging.debug("Haven't seen %s (%s) ...", current_filename, current_hash)
77 hashes.add(current_hash) 51 hashes.add(current_hash)
78 to_hash.extend(_get_dependencies(current_filename)) 52 to_hash.extend(_get_dependencies(current_filename))
79 return sha256('|'.join(sorted(hashes))).hexdigest() 53 return sha256('|'.join(sorted(hashes))).hexdigest()
80 54
81 def main(argv): 55 def main(argv):
82 logging.basicConfig() 56 logging.basicConfig()
(...skipping 13 matching lines...) Expand all
96 for filename in argv[1:]: 70 for filename in argv[1:]:
97 try: 71 try:
98 print transitive_hash(filename), filename 72 print transitive_hash(filename), filename
99 except subprocess.CalledProcessError: 73 except subprocess.CalledProcessError:
100 print "ERROR", filename 74 print "ERROR", filename
101 rv = 1 75 rv = 1
102 return rv 76 return rv
103 77
104 if __name__ == '__main__': 78 if __name__ == '__main__':
105 sys.exit(main(sys.argv)) 79 sys.exit(main(sys.argv))
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698