You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
250 lines
8.6 KiB
250 lines
8.6 KiB
# Lint as: python3
|
|
#
|
|
# Copyright (C) 2019 The Android Open Source Project
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
# you may not use this file except in compliance with the License.
|
|
# You may obtain a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
# See the License for the specific language governing permissions and
|
|
# limitations under the License.
|
|
"""This script generates C-Suite configuration files for a list of apps."""
|
|
|
|
import argparse
|
|
import contextlib
|
|
import glob
|
|
import os
|
|
import string
|
|
import sys
|
|
|
|
from typing import IO, Set, Text
|
|
|
|
_ANDROID_BP_FILE_NAME = 'Android.bp'
|
|
_ANDROID_XML_FILE_NAME = 'AndroidTest.xml'
|
|
_AUTO_GENERATE_NOTE = 'THIS FILE WAS AUTO-GENERATED. DO NOT EDIT MANUALLY!'
|
|
|
|
DEFAULT_BUILD_MODULE_TEMPLATE = string.Template("""\
|
|
// Copyright (C) 2019 The Android Open Source Project
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
// ${auto_generate_note}
|
|
|
|
csuite_config {
|
|
name: "csuite_${package_name}",
|
|
}
|
|
""")
|
|
|
|
DEFAULT_TEST_MODULE_TEMPLATE = string.Template("""\
|
|
<?xml version="1.0" encoding="utf-8"?>
|
|
<!-- Copyright (C) 2019 The Android Open Source Project
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
you may not use this file except in compliance with the License.
|
|
You may obtain a copy of the License at
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
See the License for the specific language governing permissions and
|
|
limitations under the License.
|
|
-->
|
|
<!-- ${auto_generate_note}-->
|
|
|
|
<configuration description="Tests the compatibility of apps">
|
|
<option key="plan" name="config-descriptor:metadata" value="app-launch"/>
|
|
<option name="package-name" value="${package_name}"/>
|
|
<target_preparer class="com.android.compatibility.targetprep.AppSetupPreparer">
|
|
<option name="test-file-name" value="csuite-launch-instrumentation.apk"/>
|
|
<option name="test-file-name" value="app://${package_name}"/>
|
|
</target_preparer>
|
|
<target_preparer class="com.android.compatibility.targetprep.CheckGmsPreparer"/>
|
|
<target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
|
|
<option name="run-command" value="input keyevent KEYCODE_WAKEUP"/>
|
|
<option name="run-command" value="input keyevent KEYCODE_MENU"/>
|
|
<option name="run-command" value="input keyevent KEYCODE_HOME"/>
|
|
</target_preparer>
|
|
<test class="com.android.compatibility.testtype.AppLaunchTest"/>
|
|
</configuration>
|
|
""")
|
|
|
|
|
|
def generate_all_modules_from_config(package_list_file_path,
|
|
root_dir,
|
|
build_module_template_file_path=None,
|
|
test_module_template_file_path=None):
|
|
"""Generate multiple test and build modules.
|
|
|
|
Args:
|
|
package_list_file_path: path of a file containing package names.
|
|
root_dir: root directory that modules will be generated in.
|
|
build_module_template_file_path: path of a file containing build module
|
|
template.
|
|
test_module_template_file_path: path of a file containing test module
|
|
template.
|
|
"""
|
|
build_module_template = DEFAULT_BUILD_MODULE_TEMPLATE
|
|
test_module_template = DEFAULT_TEST_MODULE_TEMPLATE
|
|
if build_module_template_file_path:
|
|
with open(build_module_template_file_path, 'r') as f:
|
|
build_module_template = string.Template(f.read())
|
|
if test_module_template_file_path:
|
|
with open(test_module_template_file_path, 'r') as f:
|
|
test_module_template = string.Template(f.read())
|
|
|
|
remove_existing_package_files(root_dir)
|
|
|
|
with open(package_list_file_path) as fp:
|
|
for line in parse_package_list(fp):
|
|
_generate_module_files(line.strip(), root_dir, build_module_template,
|
|
test_module_template)
|
|
|
|
|
|
def remove_existing_package_files(root_dir):
|
|
for filename in glob.iglob(root_dir + '/**/AndroidTest.xml'):
|
|
if _is_auto_generated(filename):
|
|
os.remove(filename)
|
|
|
|
for filename in glob.iglob(root_dir + '/**/Android.bp'):
|
|
if _is_auto_generated(filename):
|
|
os.remove(filename)
|
|
|
|
_remove_empty_dirs(root_dir)
|
|
|
|
|
|
def _is_auto_generated(filename):
|
|
with open(filename, 'r') as f:
|
|
return _AUTO_GENERATE_NOTE in f.read()
|
|
|
|
|
|
def _remove_empty_dirs(path):
|
|
for filename in os.listdir(path):
|
|
file_path = os.path.join(path, filename)
|
|
if os.path.isdir(file_path) and not os.listdir(file_path):
|
|
os.rmdir(file_path)
|
|
|
|
|
|
def parse_package_list(package_list_file: IO[bytes]) -> Set[bytes]:
|
|
packages = {line.strip() for line in package_list_file.readlines()}
|
|
for package in packages:
|
|
if package and not package.startswith('#'):
|
|
yield package
|
|
|
|
|
|
def _generate_module_files(package_name, root_dir, build_module_template,
|
|
test_module_template):
|
|
"""Generate test and build modules for a single package.
|
|
|
|
Args:
|
|
package_name: package name of test and build modules.
|
|
root_dir: root directory that modules will be generated in.
|
|
build_module_template: template for build module.
|
|
test_module_template: template for test module.
|
|
"""
|
|
package_dir = _create_package_dir(root_dir, package_name)
|
|
|
|
build_module_path = os.path.join(package_dir, _ANDROID_BP_FILE_NAME)
|
|
test_module_path = os.path.join(package_dir, _ANDROID_XML_FILE_NAME)
|
|
|
|
with open(build_module_path, 'w') as f:
|
|
write_module(build_module_template, package_name, f)
|
|
|
|
with open(test_module_path, 'w') as f:
|
|
write_module(test_module_template, package_name, f)
|
|
|
|
|
|
def _create_package_dir(root_dir, package_name):
|
|
package_dir_path = os.path.join(root_dir, package_name)
|
|
os.mkdir(package_dir_path)
|
|
|
|
return package_dir_path
|
|
|
|
|
|
def write_module(template: string.Template, package_name: Text,
|
|
out_file: IO[bytes]) -> Text:
|
|
"""Writes the build or test module for the provided package into a file."""
|
|
test_module = template.substitute(
|
|
package_name=package_name, auto_generate_note=_AUTO_GENERATE_NOTE)
|
|
out_file.write(test_module)
|
|
|
|
|
|
def _file_path(path):
|
|
if os.path.isfile(path):
|
|
return path
|
|
raise argparse.ArgumentTypeError('%s is not a valid path' % path)
|
|
|
|
|
|
def _dir_path(path):
|
|
if os.path.isdir(path):
|
|
return path
|
|
raise argparse.ArgumentTypeError('%s is not a valid path' % path)
|
|
|
|
|
|
@contextlib.contextmanager
|
|
def _redirect_sys_output(out, err):
|
|
current_out, current_err = sys.stdout, sys.stderr
|
|
try:
|
|
sys.stdout, sys.stderr = out, err
|
|
yield
|
|
finally:
|
|
sys.stdout, sys.stderr = current_out, current_err
|
|
|
|
|
|
def parse_args(args, out=sys.stdout, err=sys.stderr):
|
|
"""Parses the provided sequence of arguments."""
|
|
parser = argparse.ArgumentParser()
|
|
parser.add_argument(
|
|
'--package-list',
|
|
type=_file_path,
|
|
required=True,
|
|
help='path of the file containing package names')
|
|
parser.add_argument(
|
|
'--root-dir',
|
|
type=_dir_path,
|
|
required=True,
|
|
help='path of the root directory that' + 'modules will be generated in')
|
|
parser.add_argument(
|
|
'--test-module-template',
|
|
type=_file_path,
|
|
required=False,
|
|
help='path of the file containing test module configuration template')
|
|
parser.add_argument(
|
|
'--build-module-template',
|
|
type=_file_path,
|
|
required=False,
|
|
help='path of the file containing build module configuration template')
|
|
|
|
# We redirect stdout and stderr to improve testability since ArgumentParser
|
|
# always writes to those files. More specifically, the TradeFed python test
|
|
# runner will choke parsing output that is not in the expected format.
|
|
with _redirect_sys_output(out, err):
|
|
return parser.parse_args(args)
|
|
|
|
|
|
def main():
|
|
parser = parse_args(sys.argv[1:])
|
|
generate_all_modules_from_config(parser.package_list, parser.root_dir,
|
|
parser.build_module_template,
|
|
parser.test_module_template)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
main()
|