1*bb4ee6a4SAndroid Build Coastguard Worker#!/usr/bin/env python3 2*bb4ee6a4SAndroid Build Coastguard Worker# Copyright 2023 The ChromiumOS Authors 3*bb4ee6a4SAndroid Build Coastguard Worker# Use of this source code is governed by a BSD-style license that can be 4*bb4ee6a4SAndroid Build Coastguard Worker# found in the LICENSE file. 5*bb4ee6a4SAndroid Build Coastguard Worker 6*bb4ee6a4SAndroid Build Coastguard Worker""" 7*bb4ee6a4SAndroid Build Coastguard WorkerProvides general utility functions. 8*bb4ee6a4SAndroid Build Coastguard Worker""" 9*bb4ee6a4SAndroid Build Coastguard Worker 10*bb4ee6a4SAndroid Build Coastguard Workerimport argparse 11*bb4ee6a4SAndroid Build Coastguard Workerimport contextlib 12*bb4ee6a4SAndroid Build Coastguard Workerimport datetime 13*bb4ee6a4SAndroid Build Coastguard Workerimport functools 14*bb4ee6a4SAndroid Build Coastguard Workerimport os 15*bb4ee6a4SAndroid Build Coastguard Workerimport re 16*bb4ee6a4SAndroid Build Coastguard Workerimport subprocess 17*bb4ee6a4SAndroid Build Coastguard Workerimport sys 18*bb4ee6a4SAndroid Build Coastguard Workerimport urllib 19*bb4ee6a4SAndroid Build Coastguard Workerimport urllib.request 20*bb4ee6a4SAndroid Build Coastguard Workerimport urllib.error 21*bb4ee6a4SAndroid Build Coastguard Workerfrom pathlib import Path 22*bb4ee6a4SAndroid Build Coastguard Workerfrom subprocess import DEVNULL, PIPE, STDOUT # type: ignore 23*bb4ee6a4SAndroid Build Coastguard Workerfrom typing import ( 24*bb4ee6a4SAndroid Build Coastguard Worker Dict, 25*bb4ee6a4SAndroid Build Coastguard Worker List, 26*bb4ee6a4SAndroid Build Coastguard Worker NamedTuple, 27*bb4ee6a4SAndroid Build Coastguard Worker Optional, 28*bb4ee6a4SAndroid Build Coastguard Worker Tuple, 29*bb4ee6a4SAndroid Build Coastguard Worker Union, 30*bb4ee6a4SAndroid Build Coastguard Worker) 31*bb4ee6a4SAndroid Build Coastguard Worker 32*bb4ee6a4SAndroid Build Coastguard WorkerPathLike = Union[Path, str] 33*bb4ee6a4SAndroid Build Coastguard Worker 34*bb4ee6a4SAndroid Build Coastguard Worker# Regex that matches ANSI escape sequences 35*bb4ee6a4SAndroid Build Coastguard WorkerANSI_ESCAPE = re.compile(r"\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])") 36*bb4ee6a4SAndroid Build Coastguard Worker 37*bb4ee6a4SAndroid Build Coastguard Worker 38*bb4ee6a4SAndroid Build Coastguard Workerdef find_crosvm_root(): 39*bb4ee6a4SAndroid Build Coastguard Worker "Walk up from CWD until we find the crosvm root dir." 40*bb4ee6a4SAndroid Build Coastguard Worker path = Path("").resolve() 41*bb4ee6a4SAndroid Build Coastguard Worker while True: 42*bb4ee6a4SAndroid Build Coastguard Worker if (path / "tools/impl/common.py").is_file(): 43*bb4ee6a4SAndroid Build Coastguard Worker return path 44*bb4ee6a4SAndroid Build Coastguard Worker if path.parent: 45*bb4ee6a4SAndroid Build Coastguard Worker path = path.parent 46*bb4ee6a4SAndroid Build Coastguard Worker else: 47*bb4ee6a4SAndroid Build Coastguard Worker raise Exception("Cannot find crosvm root dir.") 48*bb4ee6a4SAndroid Build Coastguard Worker 49*bb4ee6a4SAndroid Build Coastguard Worker 50*bb4ee6a4SAndroid Build Coastguard Worker"Root directory of crosvm derived from CWD." 51*bb4ee6a4SAndroid Build Coastguard WorkerCROSVM_ROOT = find_crosvm_root() 52*bb4ee6a4SAndroid Build Coastguard Worker 53*bb4ee6a4SAndroid Build Coastguard Worker"Cargo.toml file of crosvm" 54*bb4ee6a4SAndroid Build Coastguard WorkerCROSVM_TOML = CROSVM_ROOT / "Cargo.toml" 55*bb4ee6a4SAndroid Build Coastguard Worker 56*bb4ee6a4SAndroid Build Coastguard Worker""" 57*bb4ee6a4SAndroid Build Coastguard WorkerRoot directory of crosvm devtools. 58*bb4ee6a4SAndroid Build Coastguard Worker 59*bb4ee6a4SAndroid Build Coastguard WorkerMay be different from `CROSVM_ROOT/tools`, which is allows you to run the crosvm dev 60*bb4ee6a4SAndroid Build Coastguard Workertools from this directory on another crosvm repo. 61*bb4ee6a4SAndroid Build Coastguard Worker 62*bb4ee6a4SAndroid Build Coastguard WorkerUse this if you want to call crosvm dev tools, which will use the scripts relative 63*bb4ee6a4SAndroid Build Coastguard Workerto this file. 64*bb4ee6a4SAndroid Build Coastguard Worker""" 65*bb4ee6a4SAndroid Build Coastguard WorkerTOOLS_ROOT = Path(__file__).parent.parent.resolve() 66*bb4ee6a4SAndroid Build Coastguard Worker 67*bb4ee6a4SAndroid Build Coastguard Worker"Cache directory that is preserved between builds in CI." 68*bb4ee6a4SAndroid Build Coastguard WorkerCACHE_DIR = Path(os.environ.get("CROSVM_CACHE_DIR", os.environ.get("TMPDIR", "/tmp"))) 69*bb4ee6a4SAndroid Build Coastguard Worker 70*bb4ee6a4SAndroid Build Coastguard Worker# Ensure that we really found the crosvm root directory 71*bb4ee6a4SAndroid Build Coastguard Workerassert 'name = "crosvm"' in CROSVM_TOML.read_text() 72*bb4ee6a4SAndroid Build Coastguard Worker 73*bb4ee6a4SAndroid Build Coastguard Worker# List of times recorded by `record_time` which will be printed if --timing-info is provided. 74*bb4ee6a4SAndroid Build Coastguard Workerglobal_time_records: List[Tuple[str, datetime.timedelta]] = [] 75*bb4ee6a4SAndroid Build Coastguard Worker 76*bb4ee6a4SAndroid Build Coastguard Worker 77*bb4ee6a4SAndroid Build Coastguard Workerdef crosvm_target_dir(): 78*bb4ee6a4SAndroid Build Coastguard Worker crosvm_target = os.environ.get("CROSVM_TARGET_DIR") 79*bb4ee6a4SAndroid Build Coastguard Worker cargo_target = os.environ.get("CARGO_TARGET_DIR") 80*bb4ee6a4SAndroid Build Coastguard Worker if crosvm_target: 81*bb4ee6a4SAndroid Build Coastguard Worker return Path(crosvm_target) 82*bb4ee6a4SAndroid Build Coastguard Worker elif cargo_target: 83*bb4ee6a4SAndroid Build Coastguard Worker return Path(cargo_target) / "crosvm" 84*bb4ee6a4SAndroid Build Coastguard Worker else: 85*bb4ee6a4SAndroid Build Coastguard Worker return CROSVM_ROOT / "target/crosvm" 86*bb4ee6a4SAndroid Build Coastguard Worker 87*bb4ee6a4SAndroid Build Coastguard Worker 88*bb4ee6a4SAndroid Build Coastguard Worker@functools.lru_cache(None) 89*bb4ee6a4SAndroid Build Coastguard Workerdef parse_common_args(): 90*bb4ee6a4SAndroid Build Coastguard Worker """ 91*bb4ee6a4SAndroid Build Coastguard Worker Parse args common to all scripts 92*bb4ee6a4SAndroid Build Coastguard Worker 93*bb4ee6a4SAndroid Build Coastguard Worker These args are parsed separately of the run_main/run_commands method so we can access 94*bb4ee6a4SAndroid Build Coastguard Worker verbose/etc before the commands arguments are parsed. 95*bb4ee6a4SAndroid Build Coastguard Worker """ 96*bb4ee6a4SAndroid Build Coastguard Worker parser = argparse.ArgumentParser(add_help=False) 97*bb4ee6a4SAndroid Build Coastguard Worker add_common_args(parser) 98*bb4ee6a4SAndroid Build Coastguard Worker return parser.parse_known_args()[0] 99*bb4ee6a4SAndroid Build Coastguard Worker 100*bb4ee6a4SAndroid Build Coastguard Worker 101*bb4ee6a4SAndroid Build Coastguard Workerdef add_common_args(parser: argparse.ArgumentParser): 102*bb4ee6a4SAndroid Build Coastguard Worker "These args are added to all commands." 103*bb4ee6a4SAndroid Build Coastguard Worker parser.add_argument( 104*bb4ee6a4SAndroid Build Coastguard Worker "--color", 105*bb4ee6a4SAndroid Build Coastguard Worker default="auto", 106*bb4ee6a4SAndroid Build Coastguard Worker choices=("always", "never", "auto"), 107*bb4ee6a4SAndroid Build Coastguard Worker help="Force enable or disable colors. Defaults to automatic detection.", 108*bb4ee6a4SAndroid Build Coastguard Worker ) 109*bb4ee6a4SAndroid Build Coastguard Worker parser.add_argument( 110*bb4ee6a4SAndroid Build Coastguard Worker "--verbose", 111*bb4ee6a4SAndroid Build Coastguard Worker "-v", 112*bb4ee6a4SAndroid Build Coastguard Worker action="store_true", 113*bb4ee6a4SAndroid Build Coastguard Worker default=False, 114*bb4ee6a4SAndroid Build Coastguard Worker help="Print more details about the commands this script is running.", 115*bb4ee6a4SAndroid Build Coastguard Worker ) 116*bb4ee6a4SAndroid Build Coastguard Worker parser.add_argument( 117*bb4ee6a4SAndroid Build Coastguard Worker "--very-verbose", 118*bb4ee6a4SAndroid Build Coastguard Worker "-vv", 119*bb4ee6a4SAndroid Build Coastguard Worker action="store_true", 120*bb4ee6a4SAndroid Build Coastguard Worker default=False, 121*bb4ee6a4SAndroid Build Coastguard Worker help="Print more debug output", 122*bb4ee6a4SAndroid Build Coastguard Worker ) 123*bb4ee6a4SAndroid Build Coastguard Worker parser.add_argument( 124*bb4ee6a4SAndroid Build Coastguard Worker "--timing-info", 125*bb4ee6a4SAndroid Build Coastguard Worker action="store_true", 126*bb4ee6a4SAndroid Build Coastguard Worker default=False, 127*bb4ee6a4SAndroid Build Coastguard Worker help="Print info on how long which parts of the command take", 128*bb4ee6a4SAndroid Build Coastguard Worker ) 129*bb4ee6a4SAndroid Build Coastguard Worker 130*bb4ee6a4SAndroid Build Coastguard Worker 131*bb4ee6a4SAndroid Build Coastguard Workerdef verbose(): 132*bb4ee6a4SAndroid Build Coastguard Worker return very_verbose() or parse_common_args().verbose 133*bb4ee6a4SAndroid Build Coastguard Worker 134*bb4ee6a4SAndroid Build Coastguard Worker 135*bb4ee6a4SAndroid Build Coastguard Workerdef very_verbose(): 136*bb4ee6a4SAndroid Build Coastguard Worker return parse_common_args().very_verbose 137*bb4ee6a4SAndroid Build Coastguard Worker 138*bb4ee6a4SAndroid Build Coastguard Worker 139*bb4ee6a4SAndroid Build Coastguard Workerdef color_enabled(): 140*bb4ee6a4SAndroid Build Coastguard Worker color_arg = parse_common_args().color 141*bb4ee6a4SAndroid Build Coastguard Worker if color_arg == "never": 142*bb4ee6a4SAndroid Build Coastguard Worker return False 143*bb4ee6a4SAndroid Build Coastguard Worker if color_arg == "always": 144*bb4ee6a4SAndroid Build Coastguard Worker return True 145*bb4ee6a4SAndroid Build Coastguard Worker return sys.stdout.isatty() 146*bb4ee6a4SAndroid Build Coastguard Worker 147*bb4ee6a4SAndroid Build Coastguard Worker 148*bb4ee6a4SAndroid Build Coastguard Workerdef find_scripts(path: Path, shebang: str): 149*bb4ee6a4SAndroid Build Coastguard Worker for file in path.glob("*"): 150*bb4ee6a4SAndroid Build Coastguard Worker if file.is_file() and file.open(errors="ignore").read(512).startswith(f"#!{shebang}"): 151*bb4ee6a4SAndroid Build Coastguard Worker yield file 152*bb4ee6a4SAndroid Build Coastguard Worker 153*bb4ee6a4SAndroid Build Coastguard Worker 154*bb4ee6a4SAndroid Build Coastguard Workerdef confirm(message: str, default: bool = False): 155*bb4ee6a4SAndroid Build Coastguard Worker print(message, "[y/N]" if default == False else "[Y/n]", end=" ", flush=True) 156*bb4ee6a4SAndroid Build Coastguard Worker response = sys.stdin.readline().strip() 157*bb4ee6a4SAndroid Build Coastguard Worker if response in ("y", "Y"): 158*bb4ee6a4SAndroid Build Coastguard Worker return True 159*bb4ee6a4SAndroid Build Coastguard Worker if response in ("n", "N"): 160*bb4ee6a4SAndroid Build Coastguard Worker return False 161*bb4ee6a4SAndroid Build Coastguard Worker return default 162*bb4ee6a4SAndroid Build Coastguard Worker 163*bb4ee6a4SAndroid Build Coastguard Worker 164*bb4ee6a4SAndroid Build Coastguard Workerdef is_cros_repo(): 165*bb4ee6a4SAndroid Build Coastguard Worker "Returns true if the crosvm repo is a symlink or worktree to a CrOS repo checkout." 166*bb4ee6a4SAndroid Build Coastguard Worker dot_git = CROSVM_ROOT / ".git" 167*bb4ee6a4SAndroid Build Coastguard Worker if not dot_git.is_symlink() and dot_git.is_dir(): 168*bb4ee6a4SAndroid Build Coastguard Worker return False 169*bb4ee6a4SAndroid Build Coastguard Worker return (cros_repo_root() / ".repo").exists() 170*bb4ee6a4SAndroid Build Coastguard Worker 171*bb4ee6a4SAndroid Build Coastguard Worker 172*bb4ee6a4SAndroid Build Coastguard Workerdef cros_repo_root(): 173*bb4ee6a4SAndroid Build Coastguard Worker "Root directory of the CrOS repo checkout." 174*bb4ee6a4SAndroid Build Coastguard Worker return (CROSVM_ROOT / "../../..").resolve() 175*bb4ee6a4SAndroid Build Coastguard Worker 176*bb4ee6a4SAndroid Build Coastguard Worker 177*bb4ee6a4SAndroid Build Coastguard Workerdef is_kiwi_repo(): 178*bb4ee6a4SAndroid Build Coastguard Worker "Returns true if the crosvm repo contains .kiwi_repo file." 179*bb4ee6a4SAndroid Build Coastguard Worker dot_kiwi_repo = CROSVM_ROOT / ".kiwi_repo" 180*bb4ee6a4SAndroid Build Coastguard Worker return dot_kiwi_repo.exists() 181*bb4ee6a4SAndroid Build Coastguard Worker 182*bb4ee6a4SAndroid Build Coastguard Worker 183*bb4ee6a4SAndroid Build Coastguard Workerdef kiwi_repo_root(): 184*bb4ee6a4SAndroid Build Coastguard Worker "Root directory of the kiwi repo checkout." 185*bb4ee6a4SAndroid Build Coastguard Worker return (CROSVM_ROOT / "../..").resolve() 186*bb4ee6a4SAndroid Build Coastguard Worker 187*bb4ee6a4SAndroid Build Coastguard Workerdef is_aosp_repo(): 188*bb4ee6a4SAndroid Build Coastguard Worker "Returns true if the crosvm repo is an AOSP repo checkout." 189*bb4ee6a4SAndroid Build Coastguard Worker android_bp = CROSVM_ROOT / "Android.bp" 190*bb4ee6a4SAndroid Build Coastguard Worker return android_bp.exists() 191*bb4ee6a4SAndroid Build Coastguard Worker 192*bb4ee6a4SAndroid Build Coastguard Workerdef aosp_repo_root(): 193*bb4ee6a4SAndroid Build Coastguard Worker "Root directory of AOSP repo checkout." 194*bb4ee6a4SAndroid Build Coastguard Worker return (CROSVM_ROOT / "../..").resolve() 195*bb4ee6a4SAndroid Build Coastguard Worker 196*bb4ee6a4SAndroid Build Coastguard Workerdef is_aosp_repo(): 197*bb4ee6a4SAndroid Build Coastguard Worker "Returns true if the crosvm repo is an AOSP repo checkout." 198*bb4ee6a4SAndroid Build Coastguard Worker android_bp = CROSVM_ROOT / "Android.bp" 199*bb4ee6a4SAndroid Build Coastguard Worker return android_bp.exists() 200*bb4ee6a4SAndroid Build Coastguard Worker 201*bb4ee6a4SAndroid Build Coastguard Worker 202*bb4ee6a4SAndroid Build Coastguard Workerdef aosp_repo_root(): 203*bb4ee6a4SAndroid Build Coastguard Worker "Root directory of AOSP repo checkout." 204*bb4ee6a4SAndroid Build Coastguard Worker return (CROSVM_ROOT / "../..").resolve() 205*bb4ee6a4SAndroid Build Coastguard Worker 206*bb4ee6a4SAndroid Build Coastguard Worker 207*bb4ee6a4SAndroid Build Coastguard Workerdef sudo_is_passwordless(): 208*bb4ee6a4SAndroid Build Coastguard Worker # Run with --askpass but no askpass set, succeeds only if passwordless sudo 209*bb4ee6a4SAndroid Build Coastguard Worker # is available. 210*bb4ee6a4SAndroid Build Coastguard Worker (ret, _) = subprocess.getstatusoutput("SUDO_ASKPASS=false sudo --askpass true") 211*bb4ee6a4SAndroid Build Coastguard Worker return ret == 0 212*bb4ee6a4SAndroid Build Coastguard Worker 213*bb4ee6a4SAndroid Build Coastguard Worker 214*bb4ee6a4SAndroid Build Coastguard WorkerSHORTHANDS = { 215*bb4ee6a4SAndroid Build Coastguard Worker "mingw64": "x86_64-pc-windows-gnu", 216*bb4ee6a4SAndroid Build Coastguard Worker "msvc64": "x86_64-pc-windows-msvc", 217*bb4ee6a4SAndroid Build Coastguard Worker "armhf": "armv7-unknown-linux-gnueabihf", 218*bb4ee6a4SAndroid Build Coastguard Worker "aarch64": "aarch64-unknown-linux-gnu", 219*bb4ee6a4SAndroid Build Coastguard Worker "riscv64": "riscv64gc-unknown-linux-gnu", 220*bb4ee6a4SAndroid Build Coastguard Worker "x86_64": "x86_64-unknown-linux-gnu", 221*bb4ee6a4SAndroid Build Coastguard Worker "android": "aarch64-linux-android", 222*bb4ee6a4SAndroid Build Coastguard Worker} 223*bb4ee6a4SAndroid Build Coastguard Worker 224*bb4ee6a4SAndroid Build Coastguard Worker 225*bb4ee6a4SAndroid Build Coastguard Workerclass Triple(NamedTuple): 226*bb4ee6a4SAndroid Build Coastguard Worker """ 227*bb4ee6a4SAndroid Build Coastguard Worker Build triple in cargo format. 228*bb4ee6a4SAndroid Build Coastguard Worker 229*bb4ee6a4SAndroid Build Coastguard Worker The format is: <arch><sub>-<vendor>-<sys>-<abi>, However, we will treat <arch><sub> as a single 230*bb4ee6a4SAndroid Build Coastguard Worker arch to simplify things. 231*bb4ee6a4SAndroid Build Coastguard Worker """ 232*bb4ee6a4SAndroid Build Coastguard Worker 233*bb4ee6a4SAndroid Build Coastguard Worker arch: str 234*bb4ee6a4SAndroid Build Coastguard Worker vendor: str 235*bb4ee6a4SAndroid Build Coastguard Worker sys: Optional[str] 236*bb4ee6a4SAndroid Build Coastguard Worker abi: Optional[str] 237*bb4ee6a4SAndroid Build Coastguard Worker 238*bb4ee6a4SAndroid Build Coastguard Worker @classmethod 239*bb4ee6a4SAndroid Build Coastguard Worker def from_shorthand(cls, shorthand: str): 240*bb4ee6a4SAndroid Build Coastguard Worker "These shorthands make it easier to specify triples on the command line." 241*bb4ee6a4SAndroid Build Coastguard Worker if "-" in shorthand: 242*bb4ee6a4SAndroid Build Coastguard Worker triple = shorthand 243*bb4ee6a4SAndroid Build Coastguard Worker elif shorthand in SHORTHANDS: 244*bb4ee6a4SAndroid Build Coastguard Worker triple = SHORTHANDS[shorthand] 245*bb4ee6a4SAndroid Build Coastguard Worker else: 246*bb4ee6a4SAndroid Build Coastguard Worker raise Exception(f"Not a valid build triple shorthand: {shorthand}") 247*bb4ee6a4SAndroid Build Coastguard Worker return cls.from_str(triple) 248*bb4ee6a4SAndroid Build Coastguard Worker 249*bb4ee6a4SAndroid Build Coastguard Worker @classmethod 250*bb4ee6a4SAndroid Build Coastguard Worker def from_str(cls, triple: str): 251*bb4ee6a4SAndroid Build Coastguard Worker parts = triple.split("-") 252*bb4ee6a4SAndroid Build Coastguard Worker if len(parts) < 2: 253*bb4ee6a4SAndroid Build Coastguard Worker raise Exception(f"Unsupported triple {triple}") 254*bb4ee6a4SAndroid Build Coastguard Worker return cls( 255*bb4ee6a4SAndroid Build Coastguard Worker parts[0], 256*bb4ee6a4SAndroid Build Coastguard Worker parts[1], 257*bb4ee6a4SAndroid Build Coastguard Worker parts[2] if len(parts) > 2 else None, 258*bb4ee6a4SAndroid Build Coastguard Worker parts[3] if len(parts) > 3 else None, 259*bb4ee6a4SAndroid Build Coastguard Worker ) 260*bb4ee6a4SAndroid Build Coastguard Worker 261*bb4ee6a4SAndroid Build Coastguard Worker @classmethod 262*bb4ee6a4SAndroid Build Coastguard Worker def from_linux_arch(cls, arch: str): 263*bb4ee6a4SAndroid Build Coastguard Worker "Rough logic to convert the output of `arch` into a corresponding linux build triple." 264*bb4ee6a4SAndroid Build Coastguard Worker if arch == "armhf": 265*bb4ee6a4SAndroid Build Coastguard Worker return cls.from_str("armv7-unknown-linux-gnueabihf") 266*bb4ee6a4SAndroid Build Coastguard Worker else: 267*bb4ee6a4SAndroid Build Coastguard Worker return cls.from_str(f"{arch}-unknown-linux-gnu") 268*bb4ee6a4SAndroid Build Coastguard Worker 269*bb4ee6a4SAndroid Build Coastguard Worker @classmethod 270*bb4ee6a4SAndroid Build Coastguard Worker def host_default(cls): 271*bb4ee6a4SAndroid Build Coastguard Worker "Returns the default build triple of the host." 272*bb4ee6a4SAndroid Build Coastguard Worker rustc_info = subprocess.check_output(["rustc", "-vV"], text=True) 273*bb4ee6a4SAndroid Build Coastguard Worker match = re.search(r"host: (\S+)", rustc_info) 274*bb4ee6a4SAndroid Build Coastguard Worker if not match: 275*bb4ee6a4SAndroid Build Coastguard Worker raise Exception(f"Cannot parse rustc info: {rustc_info}") 276*bb4ee6a4SAndroid Build Coastguard Worker return cls.from_str(match.group(1)) 277*bb4ee6a4SAndroid Build Coastguard Worker 278*bb4ee6a4SAndroid Build Coastguard Worker @property 279*bb4ee6a4SAndroid Build Coastguard Worker def feature_flag(self): 280*bb4ee6a4SAndroid Build Coastguard Worker triple_to_shorthand = {v: k for k, v in SHORTHANDS.items()} 281*bb4ee6a4SAndroid Build Coastguard Worker shorthand = triple_to_shorthand.get(str(self)) 282*bb4ee6a4SAndroid Build Coastguard Worker if not shorthand: 283*bb4ee6a4SAndroid Build Coastguard Worker raise Exception(f"No feature set for triple {self}") 284*bb4ee6a4SAndroid Build Coastguard Worker return f"all-{shorthand}" 285*bb4ee6a4SAndroid Build Coastguard Worker 286*bb4ee6a4SAndroid Build Coastguard Worker @property 287*bb4ee6a4SAndroid Build Coastguard Worker def target_dir(self): 288*bb4ee6a4SAndroid Build Coastguard Worker return crosvm_target_dir() / str(self) 289*bb4ee6a4SAndroid Build Coastguard Worker 290*bb4ee6a4SAndroid Build Coastguard Worker def get_cargo_env(self): 291*bb4ee6a4SAndroid Build Coastguard Worker """Environment variables to make cargo use the test target.""" 292*bb4ee6a4SAndroid Build Coastguard Worker env: Dict[str, str] = {} 293*bb4ee6a4SAndroid Build Coastguard Worker cargo_target = str(self) 294*bb4ee6a4SAndroid Build Coastguard Worker env["CARGO_BUILD_TARGET"] = cargo_target 295*bb4ee6a4SAndroid Build Coastguard Worker env["CARGO_TARGET_DIR"] = str(self.target_dir) 296*bb4ee6a4SAndroid Build Coastguard Worker env["CROSVM_TARGET_DIR"] = str(crosvm_target_dir()) 297*bb4ee6a4SAndroid Build Coastguard Worker # Android builds are not fully supported and can only be used to run clippy. 298*bb4ee6a4SAndroid Build Coastguard Worker # Underlying libraries (e.g. minijail) will be built for linux instead 299*bb4ee6a4SAndroid Build Coastguard Worker # TODO(denniskempin): This could be better done with [env] in Cargo.toml if it supported 300*bb4ee6a4SAndroid Build Coastguard Worker # per-target configuration. See https://github.com/rust-lang/cargo/issues/10273 301*bb4ee6a4SAndroid Build Coastguard Worker if str(self).endswith("-linux-android"): 302*bb4ee6a4SAndroid Build Coastguard Worker env["MINIJAIL_DO_NOT_BUILD"] = "true" 303*bb4ee6a4SAndroid Build Coastguard Worker env["MINIJAIL_BINDGEN_TARGET"] = f"{self.arch}-unknown-linux-gnu" 304*bb4ee6a4SAndroid Build Coastguard Worker return env 305*bb4ee6a4SAndroid Build Coastguard Worker 306*bb4ee6a4SAndroid Build Coastguard Worker def __str__(self): 307*bb4ee6a4SAndroid Build Coastguard Worker parts = [self.arch, self.vendor] 308*bb4ee6a4SAndroid Build Coastguard Worker if self.sys: 309*bb4ee6a4SAndroid Build Coastguard Worker parts = [*parts, self.sys] 310*bb4ee6a4SAndroid Build Coastguard Worker if self.abi: 311*bb4ee6a4SAndroid Build Coastguard Worker parts = [*parts, self.abi] 312*bb4ee6a4SAndroid Build Coastguard Worker return "-".join(parts) 313*bb4ee6a4SAndroid Build Coastguard Worker 314*bb4ee6a4SAndroid Build Coastguard Worker 315*bb4ee6a4SAndroid Build Coastguard Workerdef download_file(url: str, filename: Path, attempts: int = 3): 316*bb4ee6a4SAndroid Build Coastguard Worker assert attempts > 0 317*bb4ee6a4SAndroid Build Coastguard Worker while True: 318*bb4ee6a4SAndroid Build Coastguard Worker attempts -= 1 319*bb4ee6a4SAndroid Build Coastguard Worker try: 320*bb4ee6a4SAndroid Build Coastguard Worker urllib.request.urlretrieve(url, filename) 321*bb4ee6a4SAndroid Build Coastguard Worker return 322*bb4ee6a4SAndroid Build Coastguard Worker except Exception as e: 323*bb4ee6a4SAndroid Build Coastguard Worker if attempts == 0: 324*bb4ee6a4SAndroid Build Coastguard Worker raise e 325*bb4ee6a4SAndroid Build Coastguard Worker else: 326*bb4ee6a4SAndroid Build Coastguard Worker print("Download failed:", e) 327*bb4ee6a4SAndroid Build Coastguard Worker 328*bb4ee6a4SAndroid Build Coastguard Worker 329*bb4ee6a4SAndroid Build Coastguard Workerdef strip_ansi_escape_sequences(line: str) -> str: 330*bb4ee6a4SAndroid Build Coastguard Worker return ANSI_ESCAPE.sub("", line) 331*bb4ee6a4SAndroid Build Coastguard Worker 332*bb4ee6a4SAndroid Build Coastguard Worker 333*bb4ee6a4SAndroid Build Coastguard Workerdef ensure_packages_exist(*packages: str): 334*bb4ee6a4SAndroid Build Coastguard Worker """ 335*bb4ee6a4SAndroid Build Coastguard Worker Exits if one of the listed packages does not exist. 336*bb4ee6a4SAndroid Build Coastguard Worker """ 337*bb4ee6a4SAndroid Build Coastguard Worker missing_packages: List[str] = [] 338*bb4ee6a4SAndroid Build Coastguard Worker 339*bb4ee6a4SAndroid Build Coastguard Worker for package in packages: 340*bb4ee6a4SAndroid Build Coastguard Worker try: 341*bb4ee6a4SAndroid Build Coastguard Worker __import__(package) 342*bb4ee6a4SAndroid Build Coastguard Worker except ImportError: 343*bb4ee6a4SAndroid Build Coastguard Worker missing_packages.append(package) 344*bb4ee6a4SAndroid Build Coastguard Worker 345*bb4ee6a4SAndroid Build Coastguard Worker if missing_packages: 346*bb4ee6a4SAndroid Build Coastguard Worker debian_packages = [f"python3-{p}" for p in missing_packages] 347*bb4ee6a4SAndroid Build Coastguard Worker package_list = " ".join(debian_packages) 348*bb4ee6a4SAndroid Build Coastguard Worker print("Missing python dependencies. Please re-run ./tools/install-deps") 349*bb4ee6a4SAndroid Build Coastguard Worker print(f"Or `sudo apt install {package_list}`") 350*bb4ee6a4SAndroid Build Coastguard Worker sys.exit(1) 351*bb4ee6a4SAndroid Build Coastguard Worker 352*bb4ee6a4SAndroid Build Coastguard Worker 353*bb4ee6a4SAndroid Build Coastguard Worker@contextlib.contextmanager 354*bb4ee6a4SAndroid Build Coastguard Workerdef record_time(title: str): 355*bb4ee6a4SAndroid Build Coastguard Worker """ 356*bb4ee6a4SAndroid Build Coastguard Worker Records wall-time of how long this context lasts. 357*bb4ee6a4SAndroid Build Coastguard Worker 358*bb4ee6a4SAndroid Build Coastguard Worker The results will be printed at the end of script executation if --timing-info is specified. 359*bb4ee6a4SAndroid Build Coastguard Worker """ 360*bb4ee6a4SAndroid Build Coastguard Worker start_time = datetime.datetime.now() 361*bb4ee6a4SAndroid Build Coastguard Worker try: 362*bb4ee6a4SAndroid Build Coastguard Worker yield 363*bb4ee6a4SAndroid Build Coastguard Worker finally: 364*bb4ee6a4SAndroid Build Coastguard Worker global_time_records.append((title, datetime.datetime.now() - start_time)) 365*bb4ee6a4SAndroid Build Coastguard Worker 366*bb4ee6a4SAndroid Build Coastguard Worker 367*bb4ee6a4SAndroid Build Coastguard Workerdef print_timing_info(): 368*bb4ee6a4SAndroid Build Coastguard Worker print() 369*bb4ee6a4SAndroid Build Coastguard Worker print("Timing info:") 370*bb4ee6a4SAndroid Build Coastguard Worker print() 371*bb4ee6a4SAndroid Build Coastguard Worker for title, delta in global_time_records: 372*bb4ee6a4SAndroid Build Coastguard Worker print(f" {title:20} {delta.total_seconds():.2f}s") 373