diff options
author | cjhopman@chromium.org <cjhopman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-04-16 17:05:20 +0000 |
---|---|---|
committer | cjhopman@chromium.org <cjhopman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-04-16 17:05:20 +0000 |
commit | ba50fd8275458583684065943041fdbd96254713 (patch) | |
tree | be19ae14cd8a9a1d12b961f6c5fa33f9302ec438 /build | |
parent | bfe06bc74b95f3c1ca8e41afcf9bed115b12679b (diff) | |
download | chromium_src-ba50fd8275458583684065943041fdbd96254713.zip chromium_src-ba50fd8275458583684065943041fdbd96254713.tar.gz chromium_src-ba50fd8275458583684065943041fdbd96254713.tar.bz2 |
[Android] Refactor md5_check + add tests
This adds a function md5_check.CallAndRecordIfStale that makes the
common (and currently only) use of Md5Checker much simpler (i.e just
call this function). All the users of md5_check are updated to use this
function, and everything else in md5_check is no longer part of the
public API.
Also, adds tests for the md5_check module. These are only run manually currently.
BUG=158821
Review URL: https://codereview.chromium.org/14263006
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@194377 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'build')
-rwxr-xr-x | build/android/gyp/apk_install.py | 13 | ||||
-rwxr-xr-x | build/android/gyp/create_device_library_links.py | 12 | ||||
-rwxr-xr-x | build/android/gyp/dex.py | 16 | ||||
-rwxr-xr-x | build/android/gyp/jar.py | 17 | ||||
-rwxr-xr-x | build/android/gyp/jar_toc.py | 14 | ||||
-rwxr-xr-x | build/android/gyp/javac.py | 16 | ||||
-rwxr-xr-x | build/android/gyp/push_libraries.py | 14 | ||||
-rw-r--r-- | build/android/gyp/util/md5_check.py | 55 | ||||
-rw-r--r-- | build/android/gyp/util/md5_check_test.py | 67 |
9 files changed, 158 insertions, 66 deletions
diff --git a/build/android/gyp/apk_install.py b/build/android/gyp/apk_install.py index f8e7caa..8f1e69b 100755 --- a/build/android/gyp/apk_install.py +++ b/build/android/gyp/apk_install.py @@ -38,13 +38,12 @@ def main(argv): options.apk_path] serial_number = android_commands.AndroidCommands().Adb().GetSerialNumber() - md5_stamp = '%s.%s.md5' % (options.apk_path, serial_number) - - md5_checker = md5_check.Md5Checker( - stamp=md5_stamp, inputs=[options.apk_path], command=install_cmd) - if md5_checker.IsStale(): - build_utils.CheckCallDie(install_cmd) - md5_checker.Write() + record_path = '%s.%s.md5.stamp' % (options.apk_path, serial_number) + md5_check.CallAndRecordIfStale( + lambda: build_utils.CheckCallDie(install_cmd), + record_path=record_path, + input_paths=[options.apk_path], + input_strings=install_cmd) if options.stamp: build_utils.Touch(options.stamp) diff --git a/build/android/gyp/create_device_library_links.py b/build/android/gyp/create_device_library_links.py index e71f727..48aa61e 100755 --- a/build/android/gyp/create_device_library_links.py +++ b/build/android/gyp/create_device_library_links.py @@ -47,14 +47,16 @@ def CreateLinks(options): serial_number = adb.Adb().GetSerialNumber() for lib in libraries: host_path = os.path.join(options.libraries_dir, lib) - - md5_stamp = '%s.%s.link.md5' % (host_path, serial_number) - md5_checker = md5_check.Md5Checker(stamp=md5_stamp, inputs=[host_path]) - if md5_checker.IsStale(): + def CreateLink(): link = '/data/data/' + apk_package + '/lib/' + lib target = options.target_dir + '/' + lib RunLinkCommand(adb, target, link) - md5_checker.Write() + + record_path = '%s.%s.link.md5.stamp' % (host_path, serial_number) + md5_check.CallAndRecordIfStale( + CreateLink, + record_path=record_path, + input_paths=[host_path]) def main(argv): diff --git a/build/android/gyp/dex.py b/build/android/gyp/dex.py index 99834c4..84a9c63 100755 --- a/build/android/gyp/dex.py +++ b/build/android/gyp/dex.py @@ -17,14 +17,14 @@ def DoDex(options, paths): dx_binary = os.path.join(options.android_sdk_root, 'platform-tools', 'dx') dex_cmd = [dx_binary, '--dex', '--output', options.dex_path] + paths - md5_stamp = '%s.md5' % options.dex_path - md5_checker = md5_check.Md5Checker( - stamp=md5_stamp, inputs=paths, command=dex_cmd) - if md5_checker.IsStale(): - build_utils.CheckCallDie(dex_cmd, suppress_output=True) - else: - build_utils.Touch(options.dex_path) - md5_checker.Write() + record_path = '%s.md5.stamp' % options.dex_path + md5_check.CallAndRecordIfStale( + lambda: build_utils.CheckCallDie(dex_cmd, suppress_output=True), + record_path=record_path, + input_paths=paths, + input_strings=dex_cmd) + + build_utils.Touch(options.dex_path) def main(argv): diff --git a/build/android/gyp/jar.py b/build/android/gyp/jar.py index 7618def..6d4fe12 100755 --- a/build/android/gyp/jar.py +++ b/build/android/gyp/jar.py @@ -28,15 +28,14 @@ def DoJar(options): class_files_rel = [os.path.relpath(f, jar_cwd) for f in class_files] jar_cmd = ['jar', 'cf0', jar_path] + class_files_rel - - md5_stamp = '%s.md5' % options.jar_path - md5_checker = md5_check.Md5Checker( - stamp=md5_stamp, inputs=class_files, command=jar_cmd) - if md5_checker.IsStale(): - build_utils.CheckCallDie(jar_cmd, cwd=jar_cwd) - else: - build_utils.Touch(options.jar_path) - md5_checker.Write() + record_path = '%s.md5.stamp' % options.jar_path + md5_check.CallAndRecordIfStale( + lambda: build_utils.CheckCallDie(jar_cmd, cwd=jar_cwd), + record_path=record_path, + input_paths=class_files, + input_strings=jar_cmd) + + build_utils.Touch(options.jar_path) def main(argv): diff --git a/build/android/gyp/jar_toc.py b/build/android/gyp/jar_toc.py index b40f43d..9db9d26 100755 --- a/build/android/gyp/jar_toc.py +++ b/build/android/gyp/jar_toc.py @@ -81,13 +81,13 @@ def UpdateToc(jar_path, toc_path): def DoJarToc(options): jar_path = options.jar_path toc_path = options.toc_path - md5_stamp_path = '%s.md5' % toc_path - md5_checker = md5_check.Md5Checker(stamp=md5_stamp_path, inputs=[jar_path]) - if md5_checker.IsStale(): - UpdateToc(jar_path, toc_path) - md5_checker.Write() - else: - build_utils.Touch(toc_path) + record_path = '%s.md5.stamp' % toc_path + md5_check.CallAndRecordIfStale( + lambda: UpdateToc(jar_path, toc_path), + record_path=record_path, + input_paths=[jar_path], + ) + build_utils.Touch(toc_path) def main(argv): diff --git a/build/android/gyp/javac.py b/build/android/gyp/javac.py index cbd4293..c117004 100755 --- a/build/android/gyp/javac.py +++ b/build/android/gyp/javac.py @@ -52,12 +52,7 @@ def DoJavac(options): '-Xlint:deprecation', ] + java_files - md5_stamp = '%s/javac.md5' % options.output_dir - md5_checker = md5_check.Md5Checker( - stamp=md5_stamp, - inputs=java_files + jar_inputs, - command=javac_cmd) - if md5_checker.IsStale(): + def Compile(): # Delete the classes directory. This ensures that all .class files in the # output are actually from the input .java files. For example, if a .java # file is deleted or an inner class is removed, the classes directory should @@ -66,7 +61,14 @@ def DoJavac(options): build_utils.MakeDirectory(output_dir) suppress_output = not options.chromium_code build_utils.CheckCallDie(javac_cmd, suppress_output=suppress_output) - md5_checker.Write() + + record_path = '%s/javac.md5.stamp' % options.output_dir + md5_check.CallAndRecordIfStale( + Compile, + record_path=record_path, + input_paths=java_files + jar_inputs, + input_strings=javac_cmd) + def main(argv): parser = optparse.OptionParser() diff --git a/build/android/gyp/push_libraries.py b/build/android/gyp/push_libraries.py index e586d0b..70a1fcb 100755 --- a/build/android/gyp/push_libraries.py +++ b/build/android/gyp/push_libraries.py @@ -27,19 +27,21 @@ def DoPush(options): adb = android_commands.AndroidCommands() serial_number = adb.Adb().GetSerialNumber() - needs_directory = True + # A list so that it is modifiable in Push below. + needs_directory = [True] for lib in libraries: device_path = os.path.join(options.device_dir, lib) host_path = os.path.join(options.libraries_dir, lib) - md5_stamp = '%s.%s.push.md5' % (host_path, serial_number) - md5_checker = md5_check.Md5Checker(stamp=md5_stamp, inputs=[host_path]) - if md5_checker.IsStale(): + def Push(): if needs_directory: adb.RunShellCommand('mkdir ' + options.device_dir) - needs_directory = False + needs_directory[:] = [] # = False adb.PushIfNeeded(host_path, device_path) - md5_checker.Write() + + record_path = '%s.%s.push.md5.stamp' % (host_path, serial_number) + md5_check.CallAndRecordIfStale( + Push, record_path=record_path, input_paths=[host_path]) def main(argv): diff --git a/build/android/gyp/util/md5_check.py b/build/android/gyp/util/md5_check.py index 47f1ec9..acf707c 100644 --- a/build/android/gyp/util/md5_check.py +++ b/build/android/gyp/util/md5_check.py @@ -6,7 +6,24 @@ import hashlib import os -def UpdateMd5ForFile(md5, path, block_size=2**16): +def CallAndRecordIfStale( + function, record_path=None, input_paths=[], input_strings=[]): + """Calls function if the md5sum of the input paths/strings has changed. + + The md5sum of the inputs is compared with the one stored in record_path. If + this has changed (or the record doesn't exist), function will be called and + the new md5sum will be recorded. + """ + md5_checker = _Md5Checker( + record_path=record_path, + input_paths=input_paths, + input_strings=input_strings) + if md5_checker.IsStale(): + function() + md5_checker.Write() + + +def _UpdateMd5ForFile(md5, path, block_size=2**16): with open(path, 'rb') as infile: while True: data = infile.read(block_size) @@ -15,38 +32,42 @@ def UpdateMd5ForFile(md5, path, block_size=2**16): md5.update(data) -def UpdateMd5ForDirectory(md5, dir_path): +def _UpdateMd5ForDirectory(md5, dir_path): for root, _, files in os.walk(dir_path): for f in files: - UpdateMd5ForFile(md5, os.path.join(root, f)) + _UpdateMd5ForFile(md5, os.path.join(root, f)) -def UpdateMd5ForPath(md5, path): +def _UpdateMd5ForPath(md5, path): if os.path.isdir(path): - UpdateMd5ForDirectory(md5, path) + _UpdateMd5ForDirectory(md5, path) else: - UpdateMd5ForFile(md5, path) + _UpdateMd5ForFile(md5, path) + +class _Md5Checker(object): + def __init__(self, record_path=None, input_paths=[], input_strings=[]): + assert record_path.endswith('.stamp'), ( + 'record paths must end in \'.stamp\' so that they are easy to find ' + 'and delete') -class Md5Checker(object): - def __init__(self, stamp=None, inputs=[], command=[]): - self.stamp = stamp + self.record_path = record_path md5 = hashlib.md5() - for i in inputs: - UpdateMd5ForPath(md5, i) - for s in command: + for i in sorted(input_paths): + _UpdateMd5ForPath(md5, i) + for s in input_strings: md5.update(s) self.new_digest = md5.hexdigest() self.old_digest = '' - if os.path.exists(stamp): - with open(stamp, 'r') as old_stamp: - self.old_digest = old_stamp.read() + if os.path.exists(self.record_path): + with open(self.record_path, 'r') as old_record: + self.old_digest = old_record.read() def IsStale(self): return self.old_digest != self.new_digest def Write(self): - with open(self.stamp, 'w') as new_stamp: - new_stamp.write(self.new_digest) + with open(self.record_path, 'w') as new_record: + new_record.write(self.new_digest) diff --git a/build/android/gyp/util/md5_check_test.py b/build/android/gyp/util/md5_check_test.py new file mode 100644 index 0000000..a18942e --- /dev/null +++ b/build/android/gyp/util/md5_check_test.py @@ -0,0 +1,67 @@ +# Copyright 2013 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. + +import tempfile +import unittest + +import md5_check + + +class TestMd5Check(unittest.TestCase): + def testCallAndRecordIfStale(self): + input_strings = ['string1', 'string2'] + input_file1 = tempfile.NamedTemporaryFile() + input_file2 = tempfile.NamedTemporaryFile() + file1_contents = 'input file 1' + file2_contents = 'input file 2' + input_file1.write(file1_contents) + input_file1.flush() + input_file2.write(file2_contents) + input_file2.flush() + input_files = [input_file1.name, input_file2.name] + + record_path = tempfile.NamedTemporaryFile(suffix='.stamp') + + def CheckCallAndRecord(should_call, message): + self.called = False + def MarkCalled(): + self.called = True + md5_check.CallAndRecordIfStale( + MarkCalled, + record_path=record_path.name, + input_paths=input_files, + input_strings=input_strings) + self.failUnlessEqual(should_call, self.called, message) + + CheckCallAndRecord(True, 'should call when record doesn\'t exist') + CheckCallAndRecord(False, 'should not call when nothing changed') + + input_file1.write('some more input') + input_file1.flush() + CheckCallAndRecord(True, 'changed input file should trigger call') + + input_files = input_files[::-1] + CheckCallAndRecord(False, 'reordering of inputs shouldn\'t trigger call') + + input_files = input_files[:1] + CheckCallAndRecord(True, 'removing file should trigger call') + + input_files.append(input_file2.name) + CheckCallAndRecord(True, 'added input file should trigger call') + + input_strings[0] = input_strings[0] + ' a bit longer' + CheckCallAndRecord(True, 'changed input string should trigger call') + + input_strings = input_strings[::-1] + CheckCallAndRecord(True, 'reordering of string inputs should trigger call') + + input_strings = input_strings[:1] + CheckCallAndRecord(True, 'removing a string should trigger call') + + input_strings.append('a brand new string') + CheckCallAndRecord(True, 'added input string should trigger call') + + +if __name__ == '__main__': + unittest.main() |