| #!/usr/bin/env python3 |
| # |
| # Copyright (C) 2022 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. |
| |
| |
| import argparse |
| import inspect |
| from pathlib import Path |
| import re |
| import shutil |
| import sys |
| from typing import Optional |
| |
| import build_platform |
| from paths import ( |
| DIST_PATH_DEFAULT, |
| OUT_PATH_PROFILES, |
| RUST_PREBUILT_PATH) |
| from utils import TEST_VERSION_NUMBER, ResolvedPath, export_profiles, run_build_command, run_quiet_and_exit_on_failure |
| |
| RUST_PREBUILT_NAME_PATTERN = re.compile("rust-(?!profraw)(\S*)\.tar\.gz") |
| RUST_PROFILES_NAME_PATTERN = re.compile("rust-profraw-(\S*)\.tar\.gz") |
| |
| # |
| # Helper functions |
| # |
| |
| def resolve_argument_path(arg_path: Path, name_pattern: re.Pattern) -> Optional[Path]: |
| # Resolve prebuilt path |
| resolved_path: Path = arg_path |
| if resolved_path.exists(): |
| if resolved_path.is_dir(): |
| matches = [f for f in resolved_path.iterdir() if name_pattern.match(f.name)] |
| if len(matches) > 1: |
| return None |
| |
| resolved_path = matches.pop() |
| |
| return resolved_path.resolve() |
| |
| else: |
| return None |
| |
| # |
| # Program logic |
| # |
| |
| def parse_args() -> argparse.Namespace: |
| parser = argparse.ArgumentParser(description=inspect.getdoc(sys.modules[__name__])) |
| |
| parser.add_argument( |
| "--prebuilt-path", type=ResolvedPath, required=True, |
| help="Path to either the build artifact or the directory that contains it") |
| parser.add_argument( |
| "--target", type=str, default="aosp_cf_x86_64_phone", |
| help="Device target to build for") |
| parser.add_argument( |
| "--dist", "-d", dest="dist_path", type=ResolvedPath, default=DIST_PATH_DEFAULT, |
| help="Where to place distributable artifacts") |
| |
| parser.add_argument( |
| "--image", "-i", action="store_true", |
| help="Build an image as part of the compiler test") |
| parser.add_argument( |
| "--test-targets", "-t", action="store_true", |
| help="Build the targets necessary to run tests in EngProd") |
| |
| pgo_group = parser.add_mutually_exclusive_group() |
| pgo_group.add_argument( |
| "--profile-generate", type=Path, nargs="?", const=OUT_PATH_PROFILES, |
| help="Path where instrumented prebuilts will place their profiles") |
| pgo_group.add_argument( |
| "--cs-profile-generate", type=Path, nargs="?", const=OUT_PATH_PROFILES, |
| help="Path were context-sensitive instrumented prebuilts will place their profiles") |
| |
| return parser.parse_args() |
| |
| |
| def prepare_prebuilts(prebuilt_path: Path) -> Path: |
| prebuilt_path = resolve_argument_path(prebuilt_path, RUST_PREBUILT_NAME_PATTERN) |
| if prebuilt_path == None: |
| sys.exit("Failed to resolve prebuilt path. Path either doesn't exist or contains multiple prebuilt archives.") |
| |
| # Prepare host/version path |
| target_and_version_path: Path = RUST_PREBUILT_PATH / build_platform.prebuilt() / TEST_VERSION_NUMBER |
| if target_and_version_path.exists(): |
| print("Test prebuilt directory already exists. Deleting contents.") |
| shutil.rmtree(target_and_version_path, ignore_errors=True) |
| |
| target_and_version_path.mkdir() |
| |
| # Unpack prebuilt |
| print(f"Extracting archive {prebuilt_path}") |
| run_quiet_and_exit_on_failure( |
| f"tar -xzf {prebuilt_path}", |
| f"Failed to extract prebuilt archive", |
| cwd=target_and_version_path) |
| |
| return target_and_version_path |
| |
| |
| def build_rust_artifacts(target: str) -> int: |
| print("Building Rust targets") |
| return run_build_command("rust", target, prebuilt_version=TEST_VERSION_NUMBER) |
| |
| |
| def build_image(target: str) -> int: |
| print("Building Android image") |
| return run_build_command("droid", target, prebuilt_version=TEST_VERSION_NUMBER) |
| |
| |
| def build_test_targets(target: str) -> int: |
| # Build the targets necessary for running tests in EngProd |
| TEST_TARGETS = [ |
| "droid", |
| "dist", |
| "continuous_instrumentation_tests", |
| "continuous_native_tests", |
| "device-tests", |
| "platform_tests", |
| "host-unit-tests" |
| ] |
| |
| print("Building Android test targets") |
| return run_build_command(f"{' '.join(TEST_TARGETS)}", target, prebuilt_version=TEST_VERSION_NUMBER) |
| |
| |
| def run_test(prebuilt_path: Path, target: str, dist_path: Path, profile_generate: Optional[Path], cs_profile_generate: Optional[Path]) -> int: |
| prepare_prebuilts(prebuilt_path) |
| retcode = build_rust_artifacts(target) |
| export_profiles(profile_generate or cs_profile_generate, dist_path) |
| return retcode |
| |
| |
| def main() -> None: |
| args = parse_args() |
| |
| retcode = run_test( |
| args.prebuilt_path, args.target, args.dist_path, args.profile_generate, args.cs_profile_generate) |
| |
| if retcode == 0 and args.image: |
| retcode = build_image(args.target) |
| |
| if retcode == 0 and args.test_targets: |
| retcode = build_test_targets(args.target) |
| |
| sys.exit(retcode) |
| |
| if __name__ == "__main__": |
| main() |