blob: aaee89c1697207876213f56792685ac2a18b5e59 [file] [log] [blame]
David Srbecky7cf6c582021-07-20 16:56:06 +01001#!/usr/bin/env python3
2#
3# Copyright (C) 2021 The Android Open Source Project
4#
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9# http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16
17"""
18This scripts compiles Java files which are needed to execute run-tests.
19It is intended to be used only from soong genrule.
20"""
21
22import argparse, os, tempfile, shutil, subprocess, glob, textwrap, re, json, concurrent.futures
23
24ZIP = "prebuilts/build-tools/linux-x86/bin/soong_zip"
25KNOWNFAILURES = json.loads(open(os.path.join("art", "test", "knownfailures.json"), "rt").read())
26
David Srbecky271d5722021-10-06 13:40:20 +010027def copy_sources(args, tmp, mode, srcdir):
28 """Copy test files from Android tree into the build sandbox and return its path."""
29
David Srbecky7cf6c582021-07-20 16:56:06 +010030 join = os.path.join
31 test = os.path.basename(srcdir)
32 dstdir = join(tmp, mode, test)
33
34 # Don't build tests that are disabled since they might not compile (e.g. on jvm).
35 def is_knownfailure(kf):
36 return test in kf.get("tests", []) and mode == kf.get("variant") and not kf.get("env_vars")
37 if any(is_knownfailure(kf) for kf in KNOWNFAILURES):
David Srbecky271d5722021-10-06 13:40:20 +010038 return None
David Srbecky7cf6c582021-07-20 16:56:06 +010039
40 # Copy all source files to the temporary directory.
41 shutil.copytree(srcdir, dstdir)
42
43 # Copy the default scripts if the test does not have a custom ones.
44 for name in ["build", "run", "check"]:
45 src, dst = f"art/test/etc/default-{name}", join(dstdir, name)
46 if os.path.exists(dst):
47 shutil.copy2(src, dstdir) # Copy default script next to the custom script.
48 else:
49 shutil.copy2(src, dst) # Use just the default script.
50 os.chmod(dst, 0o755)
David Srbecky7cf6c582021-07-20 16:56:06 +010051
David Srbecky271d5722021-10-06 13:40:20 +010052 return dstdir
53
54def build_test(args, mode, dstdir):
55 """Run the build script for single run-test"""
56
57 join = os.path.join
David Srbecky7cf6c582021-07-20 16:56:06 +010058 build_top = os.getcwd()
59 java_home = os.environ.get("JAVA_HOME")
60 tools_dir = os.path.abspath(join(os.path.dirname(__file__), "../../../out/bin"))
61 env = {
62 "PATH": os.environ.get("PATH"),
63 "ANDROID_BUILD_TOP": build_top,
64 "ART_TEST_RUN_TEST_BOOTCLASSPATH": join(build_top, args.bootclasspath),
David Srbecky271d5722021-10-06 13:40:20 +010065 "TEST_NAME": os.path.basename(dstdir),
David Srbecky7cf6c582021-07-20 16:56:06 +010066 "SOONG_ZIP": join(build_top, "prebuilts/build-tools/linux-x86/bin/soong_zip"),
67 "ZIPALIGN": join(build_top, "prebuilts/build-tools/linux-x86/bin/zipalign"),
68 "JAVA": join(java_home, "bin/java"),
69 "JAVAC": join(java_home, "bin/javac") + " -g -Xlint:-options -source 1.8 -target 1.8",
70 "D8": join(tools_dir, "d8"),
71 "HIDDENAPI": join(tools_dir, "hiddenapi"),
72 "JASMIN": join(tools_dir, "jasmin"),
73 "SMALI": join(tools_dir, "smali"),
74 "NEED_DEX": {"host": "true", "target": "true", "jvm": "false"}[mode],
75 "USE_DESUGAR": "true",
76 }
77 proc = subprocess.run([join(dstdir, "build"), "--" + mode],
78 cwd=dstdir,
79 env=env,
80 encoding=os.sys.stdout.encoding,
81 stderr=subprocess.STDOUT,
82 stdout=subprocess.PIPE)
83 return proc.stdout, proc.returncode
84
85def main():
86 parser = argparse.ArgumentParser(description=__doc__)
87 parser.add_argument("--out", help="Path of the generated ZIP file with the build data")
88 parser.add_argument('--mode', choices=['host', 'jvm', 'target'])
89 parser.add_argument("--shard", help="Identifies subset of tests to build (00..99)")
90 parser.add_argument("--bootclasspath", help="JAR files used for javac compilation")
91 args = parser.parse_args()
92
93 with tempfile.TemporaryDirectory(prefix=os.path.basename(__file__)) as tmp:
94 srcdirs = sorted(glob.glob(os.path.join("art", "test", "*")))
95 srcdirs = filter(lambda srcdir: re.match(".*/\d*{}-.*".format(args.shard), srcdir), srcdirs)
David Srbecky271d5722021-10-06 13:40:20 +010096 dstdirs = [copy_sources(args, tmp, args.mode, srcdir) for srcdir in srcdirs]
97 dstdirs = filter(lambda dstdir: dstdir, dstdirs) # Remove None (skipped tests).
David Srbecky7cf6c582021-07-20 16:56:06 +010098 with concurrent.futures.ThreadPoolExecutor() as pool:
David Srbecky271d5722021-10-06 13:40:20 +010099 for stdout, exitcode in pool.map(lambda dstdir: build_test(args, args.mode, dstdir), dstdirs):
David Srbecky7cf6c582021-07-20 16:56:06 +0100100 if stdout:
101 print(stdout.strip())
102 assert(exitcode == 0) # Build failed.
103
104 # Create the final zip file which contains the content of the temporary directory.
David Srbecky271d5722021-10-06 13:40:20 +0100105 proc = subprocess.run([ZIP, "-o", args.out, "-C", tmp, "-D", tmp], check=True)
David Srbecky7cf6c582021-07-20 16:56:06 +0100106
107if __name__ == "__main__":
108 main()