110 lines
4.6 KiB
Python
Executable File
110 lines
4.6 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
#
|
|
# Copyright (C) 2021 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 scripts compiles Java files which are needed to execute run-tests.
|
|
It is intended to be used only from soong genrule.
|
|
"""
|
|
|
|
import argparse, os, tempfile, shutil, subprocess, glob, textwrap, re, json, concurrent.futures
|
|
|
|
ZIP = "prebuilts/build-tools/linux-x86/bin/soong_zip"
|
|
BUILDFAILURES = json.loads(open(os.path.join("art", "test", "buildfailures.json"), "rt").read())
|
|
|
|
def copy_sources(args, tmp, mode, srcdir):
|
|
"""Copy test files from Android tree into the build sandbox and return its path."""
|
|
|
|
join = os.path.join
|
|
test = os.path.basename(srcdir)
|
|
dstdir = join(tmp, mode, test)
|
|
|
|
# Don't build tests that are disabled since they might not compile (e.g. on jvm).
|
|
def is_buildfailure(kf):
|
|
return test in kf.get("tests", []) and mode == kf.get("variant") and not kf.get("env_vars")
|
|
if any(is_buildfailure(kf) for kf in BUILDFAILURES):
|
|
return None
|
|
|
|
# Copy all source files to the temporary directory.
|
|
shutil.copytree(srcdir, dstdir)
|
|
|
|
# Copy the default scripts if the test does not have a custom ones.
|
|
for name in ["build", "run", "check"]:
|
|
src, dst = f"art/test/etc/default-{name}", join(dstdir, name)
|
|
if os.path.exists(dst):
|
|
shutil.copy2(src, dstdir) # Copy default script next to the custom script.
|
|
else:
|
|
shutil.copy2(src, dst) # Use just the default script.
|
|
os.chmod(dst, 0o755)
|
|
|
|
return dstdir
|
|
|
|
def build_test(args, mode, dstdir):
|
|
"""Run the build script for single run-test"""
|
|
|
|
join = os.path.join
|
|
build_top = os.getcwd()
|
|
java_home = os.environ.get("JAVA_HOME")
|
|
tools_dir = os.path.abspath(join(os.path.dirname(__file__), "../../../out/bin"))
|
|
env = {
|
|
"PATH": os.environ.get("PATH"),
|
|
"ANDROID_BUILD_TOP": build_top,
|
|
"ART_TEST_RUN_TEST_BOOTCLASSPATH": join(build_top, args.bootclasspath),
|
|
"TEST_NAME": os.path.basename(dstdir),
|
|
"SOONG_ZIP": join(build_top, "prebuilts/build-tools/linux-x86/bin/soong_zip"),
|
|
"ZIPALIGN": join(build_top, "prebuilts/build-tools/linux-x86/bin/zipalign"),
|
|
"JAVA": join(java_home, "bin/java"),
|
|
"JAVAC": join(java_home, "bin/javac"),
|
|
"JAVAC_ARGS": "-g -Xlint:-options -source 1.8 -target 1.8",
|
|
"D8": join(tools_dir, "d8"),
|
|
"HIDDENAPI": join(tools_dir, "hiddenapi"),
|
|
"JASMIN": join(tools_dir, "jasmin"),
|
|
"SMALI": join(tools_dir, "smali"),
|
|
"NEED_DEX": {"host": "true", "target": "true", "jvm": "false"}[mode],
|
|
"USE_DESUGAR": "true",
|
|
}
|
|
proc = subprocess.run([join(dstdir, "build"), "--" + mode],
|
|
cwd=dstdir,
|
|
env=env,
|
|
encoding=os.sys.stdout.encoding,
|
|
stderr=subprocess.STDOUT,
|
|
stdout=subprocess.PIPE)
|
|
return proc.stdout, proc.returncode
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser(description=__doc__)
|
|
parser.add_argument("--out", help="Path of the generated ZIP file with the build data")
|
|
parser.add_argument('--mode', choices=['host', 'jvm', 'target'])
|
|
parser.add_argument("--shard", help="Identifies subset of tests to build (00..99)")
|
|
parser.add_argument("--bootclasspath", help="JAR files used for javac compilation")
|
|
args = parser.parse_args()
|
|
|
|
with tempfile.TemporaryDirectory(prefix=os.path.basename(__file__)) as tmp:
|
|
srcdirs = sorted(glob.glob(os.path.join("art", "test", "*")))
|
|
srcdirs = filter(lambda srcdir: re.match(".*/\d*{}-.*".format(args.shard), srcdir), srcdirs)
|
|
dstdirs = [copy_sources(args, tmp, args.mode, srcdir) for srcdir in srcdirs]
|
|
dstdirs = filter(lambda dstdir: dstdir, dstdirs) # Remove None (skipped tests).
|
|
with concurrent.futures.ThreadPoolExecutor() as pool:
|
|
for stdout, exitcode in pool.map(lambda dstdir: build_test(args, args.mode, dstdir), dstdirs):
|
|
if stdout:
|
|
print(stdout.strip())
|
|
assert(exitcode == 0) # Build failed. Add test to buildfailures.json if this is expected.
|
|
|
|
# Create the final zip file which contains the content of the temporary directory.
|
|
proc = subprocess.run([ZIP, "-o", args.out, "-C", tmp, "-D", tmp], check=True)
|
|
|
|
if __name__ == "__main__":
|
|
main()
|