Commit d4b611f0 authored by jbudorick's avatar jbudorick Committed by Commit bot

[Android] Extract isolate logic from gtest setup to its own module.

BUG=428729

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

Cr-Commit-Position: refs/heads/master@{#302191}
parent cf29ede8
...@@ -5,14 +5,10 @@ ...@@ -5,14 +5,10 @@
"""Generates test runner factory and tests for GTests.""" """Generates test runner factory and tests for GTests."""
# pylint: disable=W0212 # pylint: disable=W0212
import fnmatch
import glob
import logging import logging
import os import os
import shutil
import sys import sys
from pylib import cmd_helper
from pylib import constants from pylib import constants
from pylib import valgrind_tools from pylib import valgrind_tools
...@@ -22,6 +18,7 @@ from pylib.device import device_utils ...@@ -22,6 +18,7 @@ from pylib.device import device_utils
from pylib.gtest import test_package_apk from pylib.gtest import test_package_apk
from pylib.gtest import test_package_exe from pylib.gtest import test_package_exe
from pylib.gtest import test_runner from pylib.gtest import test_runner
from pylib.utils import isolator
sys.path.insert(0, sys.path.insert(0,
os.path.join(constants.DIR_SOURCE_ROOT, 'build', 'util', 'lib', os.path.join(constants.DIR_SOURCE_ROOT, 'build', 'util', 'lib',
...@@ -71,9 +68,6 @@ _DEPS_EXCLUSION_LIST = [ ...@@ -71,9 +68,6 @@ _DEPS_EXCLUSION_LIST = [
'webkit/data/ico_decoder', 'webkit/data/ico_decoder',
] ]
_ISOLATE_SCRIPT = os.path.join(
constants.DIR_SOURCE_ROOT, 'tools', 'swarming_client', 'isolate.py')
def _GenerateDepsDirUsingIsolate(suite_name, isolate_file_path=None): def _GenerateDepsDirUsingIsolate(suite_name, isolate_file_path=None):
"""Generate the dependency dir for the test suite using isolate. """Generate the dependency dir for the test suite using isolate.
...@@ -83,9 +77,6 @@ def _GenerateDepsDirUsingIsolate(suite_name, isolate_file_path=None): ...@@ -83,9 +77,6 @@ def _GenerateDepsDirUsingIsolate(suite_name, isolate_file_path=None):
isolate_file_path: .isolate file path to use. If there is a default .isolate isolate_file_path: .isolate file path to use. If there is a default .isolate
file path for the suite_name, this will override it. file path for the suite_name, this will override it.
""" """
if os.path.isdir(constants.ISOLATE_DEPS_DIR):
shutil.rmtree(constants.ISOLATE_DEPS_DIR)
if isolate_file_path: if isolate_file_path:
if os.path.isabs(isolate_file_path): if os.path.isabs(isolate_file_path):
isolate_abs_path = isolate_file_path isolate_abs_path = isolate_file_path
...@@ -102,85 +93,17 @@ def _GenerateDepsDirUsingIsolate(suite_name, isolate_file_path=None): ...@@ -102,85 +93,17 @@ def _GenerateDepsDirUsingIsolate(suite_name, isolate_file_path=None):
isolated_abs_path = os.path.join( isolated_abs_path = os.path.join(
constants.GetOutDirectory(), '%s.isolated' % suite_name) constants.GetOutDirectory(), '%s.isolated' % suite_name)
assert os.path.exists(isolate_abs_path), 'Cannot find %s' % isolate_abs_path assert os.path.exists(isolate_abs_path), 'Cannot find %s' % isolate_abs_path
# This needs to be kept in sync with the cmd line options for isolate.py
# in src/build/isolate.gypi.
isolate_cmd = [
'python', _ISOLATE_SCRIPT,
'remap',
'--isolate', isolate_abs_path,
'--isolated', isolated_abs_path,
'--outdir', constants.ISOLATE_DEPS_DIR,
'--path-variable', 'DEPTH', constants.DIR_SOURCE_ROOT,
'--path-variable', 'PRODUCT_DIR', constants.GetOutDirectory(),
'--config-variable', 'OS', 'android',
'--config-variable', 'CONFIGURATION_NAME', constants.GetBuildType(),
'--config-variable', 'asan', '0',
'--config-variable', 'chromeos', '0',
'--config-variable', 'component', 'static_library',
'--config-variable', 'fastbuild', '0',
'--config-variable', 'icu_use_data_file_flag', '1',
'--config-variable', 'libpeer_target_type', 'static_library',
'--config-variable', 'v8_use_external_startup_data', '0',
'--config-variable', 'lsan', '0',
# TODO(maruel): This may not be always true.
'--config-variable', 'target_arch', 'arm',
'--config-variable', 'use_openssl', '0',
'--config-variable', 'use_ozone', '0',
]
assert not cmd_helper.RunCmd(isolate_cmd)
i = isolator.Isolator(constants.ISOLATE_DEPS_DIR)
i.Clear()
i.Remap(isolate_abs_path, isolated_abs_path)
# We're relying on the fact that timestamps are preserved # We're relying on the fact that timestamps are preserved
# by the remap command (hardlinked). Otherwise, all the data # by the remap command (hardlinked). Otherwise, all the data
# will be pushed to the device once we move to using time diff # will be pushed to the device once we move to using time diff
# instead of md5sum. Perform a sanity check here. # instead of md5sum. Perform a sanity check here.
for root, _, filenames in os.walk(constants.ISOLATE_DEPS_DIR): i.VerifyHardlinks()
if filenames: i.PurgeExcluded(_DEPS_EXCLUSION_LIST)
linked_file = os.path.join(root, filenames[0]) i.MoveOutputDeps()
orig_file = os.path.join(
constants.DIR_SOURCE_ROOT,
os.path.relpath(linked_file, constants.ISOLATE_DEPS_DIR))
if os.stat(linked_file).st_ino == os.stat(orig_file).st_ino:
break
else:
raise Exception('isolate remap command did not use hardlinks.')
# Delete excluded files as defined by _DEPS_EXCLUSION_LIST.
old_cwd = os.getcwd()
try:
os.chdir(constants.ISOLATE_DEPS_DIR)
excluded_paths = [x for y in _DEPS_EXCLUSION_LIST for x in glob.glob(y)]
if excluded_paths:
logging.info('Excluding the following from dependency list: %s',
excluded_paths)
for p in excluded_paths:
if os.path.isdir(p):
shutil.rmtree(p)
else:
os.remove(p)
finally:
os.chdir(old_cwd)
# On Android, all pak files need to be in the top-level 'paks' directory.
paks_dir = os.path.join(constants.ISOLATE_DEPS_DIR, 'paks')
os.mkdir(paks_dir)
deps_out_dir = os.path.join(
constants.ISOLATE_DEPS_DIR,
os.path.relpath(os.path.join(constants.GetOutDirectory(), os.pardir),
constants.DIR_SOURCE_ROOT))
for root, _, filenames in os.walk(deps_out_dir):
for filename in fnmatch.filter(filenames, '*.pak'):
shutil.move(os.path.join(root, filename), paks_dir)
# Move everything in PRODUCT_DIR to top level.
deps_product_dir = os.path.join(deps_out_dir, constants.GetBuildType())
if os.path.isdir(deps_product_dir):
for p in os.listdir(deps_product_dir):
shutil.move(os.path.join(deps_product_dir, p), constants.ISOLATE_DEPS_DIR)
os.rmdir(deps_product_dir)
os.rmdir(deps_out_dir)
def _GetDisabledTestsFilterFromFile(suite_name): def _GetDisabledTestsFilterFromFile(suite_name):
......
# Copyright 2014 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 fnmatch
import glob
import os
import shutil
import sys
from pylib import cmd_helper
from pylib import constants
_ISOLATE_SCRIPT = os.path.join(
constants.DIR_SOURCE_ROOT, 'tools', 'swarming_client', 'isolate.py')
def DefaultPathVariables():
return {
'DEPTH': constants.DIR_SOURCE_ROOT,
'PRODUCT_DIR': constants.GetOutDirectory(),
}
def DefaultConfigVariables():
return {
'CONFIGURATION_NAME': constants.GetBuildType(),
'OS': 'android',
'asan': '0',
'chromeos': '0',
'component': 'static_library',
'fastbuild': '0',
'icu_use_data_file_flag': '1',
'libpeer_target_type': 'static_library',
'lsan': '0',
# TODO(maruel): This may not always be true.
'target_arch': 'arm',
'use_openssl': '0',
'use_ozone': '0',
'v8_use_external_startup_data': '0',
}
class Isolator(object):
"""Manages calls to isolate.py for the android test runner scripts."""
def __init__(self, isolate_deps_dir):
"""
Args:
isolate_deps_dir: The directory in which dependencies specified by
isolate are or should be stored.
"""
self._isolate_deps_dir = isolate_deps_dir
def Clear(self):
"""Deletes the isolate dependency directory."""
if os.path.exists(self._isolate_deps_dir):
shutil.rmtree(self._isolate_deps_dir)
def Remap(self, isolate_abs_path, isolated_abs_path,
path_variables=None, config_variables=None):
"""Remaps data dependencies into |self._isolate_deps_dir|.
Args:
isolate_abs_path: The absolute path to the .isolate file, which specifies
data dependencies in the source tree.
isolated_abs_path: The absolute path to the .isolated file, which is
generated by isolate.py and specifies data dependencies in
|self._isolate_deps_dir| and their digests.
path_variables: A dict containing everything that should be passed
as a |--path-variable| to the isolate script. Defaults to the return
value of |DefaultPathVariables()|.
config_variables: A dict containing everything that should be passed
as a |--config-variable| to the isolate script. Defaults to the return
value of |DefaultConfigVariables()|.
Raises:
Exception if the isolate command fails for some reason.
"""
if not path_variables:
path_variables = DefaultPathVariables()
if not config_variables:
config_variables = DefaultConfigVariables()
isolate_cmd = [
sys.executable, _ISOLATE_SCRIPT, 'remap',
'--isolate', isolate_abs_path,
'--isolated', isolated_abs_path,
'--outdir', self._isolate_deps_dir,
]
for k, v in path_variables.iteritems():
isolate_cmd.extend(['--path-variable', k, v])
for k, v in config_variables.iteritems():
isolate_cmd.extend(['--config-variable', k, v])
if cmd_helper.RunCmd(isolate_cmd):
raise Exception('isolate command failed: %s' % ' '.join(isolate_cmd))
def VerifyHardlinks(self):
"""Checks |isolate_deps_dir| for a hardlink.
Returns:
True if a hardlink is found.
False if nothing is found.
Raises:
Exception if a non-hardlink is found.
"""
for root, _, filenames in os.walk(self._isolate_deps_dir):
if filenames:
linked_file = os.path.join(root, filenames[0])
orig_file = os.path.join(
self._isolate_deps_dir,
os.path.relpath(linked_file, self._isolate_deps_dir))
if os.stat(linked_file).st_ino == os.stat(orig_file).st_ino:
return True
else:
raise Exception('isolate remap command did not use hardlinks.')
return False
def PurgeExcluded(self, deps_exclusion_list):
"""Deletes anything on |deps_exclusion_list| from |self._isolate_deps_dir|.
Args:
deps_exclusion_list: A list of globs to exclude from the isolate
dependency directory.
"""
excluded_paths = (
x for y in deps_exclusion_list
for x in glob.glob(
os.path.abspath(os.path.join(self._isolate_deps_dir, y))))
for p in excluded_paths:
if os.path.isdir(p):
shutil.rmtree(p)
else:
os.remove(p)
def MoveOutputDeps(self):
"""Moves files from the output directory to the top level of
|self._isolate_deps_dir|.
Moves pak files from the output directory to to <isolate_deps_dir>/paks
Moves files from the product directory to <isolate_deps_dir>
"""
# On Android, all pak files need to be in the top-level 'paks' directory.
paks_dir = os.path.join(self._isolate_deps_dir, 'paks')
os.mkdir(paks_dir)
deps_out_dir = os.path.join(
self._isolate_deps_dir,
os.path.relpath(os.path.join(constants.GetOutDirectory(), os.pardir),
constants.DIR_SOURCE_ROOT))
for root, _, filenames in os.walk(deps_out_dir):
for filename in fnmatch.filter(filenames, '*.pak'):
shutil.move(os.path.join(root, filename), paks_dir)
# Move everything in PRODUCT_DIR to top level.
deps_product_dir = os.path.join(deps_out_dir, constants.GetBuildType())
if os.path.isdir(deps_product_dir):
for p in os.listdir(deps_product_dir):
shutil.move(os.path.join(deps_product_dir, p), self._isolate_deps_dir)
os.rmdir(deps_product_dir)
os.rmdir(deps_out_dir)
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment