[Android] Make gyp/apk_install.py resilient to user actions

If a user reinstalls/uninstalls/etc an APK, then the next build of that
APK should always install it (regardless of whether the md5sum of the
inputs matches the recording or not).

Adds an option to CheckCallAndRecord to force the call.

NOTRY=true
BUG=158821,234048

Review URL: https://codereview.chromium.org/14254005

git-svn-id: http://src.chromium.org/svn/trunk/src/build@196170 4ff67af0-8c30-449e-8e8b-ad334ec8d88c
This commit is contained in:
cjhopman@chromium.org 2013-04-24 17:17:10 +00:00
Родитель 943a38a7f5
Коммит a23902746b
3 изменённых файлов: 59 добавлений и 9 удалений

Просмотреть файл

@ -10,6 +10,7 @@
import optparse
import os
import re
import subprocess
import sys
@ -20,6 +21,39 @@ BUILD_ANDROID_DIR = os.path.join(os.path.dirname(__file__), '..')
sys.path.append(BUILD_ANDROID_DIR)
from pylib import android_commands
from pylib.utils import apk_helper
def GetMetadata(apk_package):
"""Gets the metadata on the device for the apk_package apk."""
adb = android_commands.AndroidCommands()
output = adb.RunShellCommand('ls -l /data/app/')
# Matches lines like:
# -rw-r--r-- system system 7376582 2013-04-19 16:34 org.chromium.chrome.testshell.apk
# -rw-r--r-- system system 7376582 2013-04-19 16:34 org.chromium.chrome.testshell-1.apk
apk_matcher = lambda s: re.match('.*%s(-[0-9]*)?.apk$' % apk_package, s)
matches = filter(apk_matcher, output)
return matches[0] if matches else None
def HasInstallMetadataChanged(apk_package, metadata_path):
"""Checks if the metadata on the device for apk_package has changed."""
if not os.path.exists(metadata_path):
return True
with open(metadata_path, 'r') as expected_file:
return expected_file.read() != GetMetadata(apk_package)
def RecordInstallMetadata(apk_package, metadata_path):
"""Records the metadata from the device for apk_package."""
metadata = GetMetadata(apk_package)
if not metadata:
raise 'APK install failed unexpectedly.'
with open(metadata_path, 'w') as outfile:
outfile.write(metadata)
def main(argv):
parser = optparse.OptionParser()
@ -39,17 +73,28 @@ def main(argv):
'install', '-r',
options.apk_path]
def Install():
build_utils.CheckCallDie(install_cmd)
build_utils.Touch(options.install_record)
serial_number = android_commands.AndroidCommands().Adb().GetSerialNumber()
apk_package = apk_helper.GetPackageName(options.apk_path)
metadata_path = '%s.%s.device.time.stamp' % (options.apk_path, serial_number)
# If the APK on the device does not match the one that was last installed by
# the build, then the APK has to be installed (regardless of the md5 record).
force_install = HasInstallMetadataChanged(apk_package, metadata_path)
def Install():
build_utils.CheckCallDie(install_cmd)
RecordInstallMetadata(apk_package, metadata_path)
build_utils.Touch(options.install_record)
record_path = '%s.%s.md5.stamp' % (options.apk_path, serial_number)
md5_check.CallAndRecordIfStale(
Install,
record_path=record_path,
input_paths=[options.apk_path],
input_strings=install_cmd)
input_strings=install_cmd,
force=force_install)
if options.stamp:
build_utils.Touch(options.stamp)

Просмотреть файл

@ -7,18 +7,21 @@ import os
def CallAndRecordIfStale(
function, record_path=None, input_paths=[], input_strings=[]):
function, record_path=None, input_paths=[], input_strings=[], force=False):
"""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.
If force is True, the function will be called regardless of whether the
md5sum is out of date.
"""
md5_checker = _Md5Checker(
record_path=record_path,
input_paths=input_paths,
input_strings=input_strings)
if md5_checker.IsStale():
if force or md5_checker.IsStale():
function()
md5_checker.Write()

Просмотреть файл

@ -23,7 +23,7 @@ class TestMd5Check(unittest.TestCase):
record_path = tempfile.NamedTemporaryFile(suffix='.stamp')
def CheckCallAndRecord(should_call, message):
def CheckCallAndRecord(should_call, message, force=False):
self.called = False
def MarkCalled():
self.called = True
@ -31,11 +31,13 @@ class TestMd5Check(unittest.TestCase):
MarkCalled,
record_path=record_path.name,
input_paths=input_files,
input_strings=input_strings)
input_strings=input_strings,
force=force)
self.failUnlessEqual(should_call, self.called, message)
CheckCallAndRecord(True, 'should call when record doesn\'t exist')
CheckCallAndRecord(False, 'should not call when nothing changed')
CheckCallAndRecord(True, force=True, message='should call when forced')
input_file1.write('some more input')
input_file1.flush()