1*cf78ab8cSAndroid Build Coastguard Worker#!/usr/bin/env python 2*cf78ab8cSAndroid Build Coastguard Worker# 3*cf78ab8cSAndroid Build Coastguard Worker# Copyright 2021 - The Android Open Source Project 4*cf78ab8cSAndroid Build Coastguard Worker# 5*cf78ab8cSAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the', help='License'); 6*cf78ab8cSAndroid Build Coastguard Worker# you may not use this file except in compliance with the License. 7*cf78ab8cSAndroid Build Coastguard Worker# You may obtain a copy of the License at 8*cf78ab8cSAndroid Build Coastguard Worker# 9*cf78ab8cSAndroid Build Coastguard Worker# http://www.apache.org/licenses/LICENSE-2.0 10*cf78ab8cSAndroid Build Coastguard Worker# 11*cf78ab8cSAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software 12*cf78ab8cSAndroid Build Coastguard Worker# distributed under the License is distributed on an', help='AS IS' BASIS, 13*cf78ab8cSAndroid Build Coastguard Worker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14*cf78ab8cSAndroid Build Coastguard Worker# See the License for the specific language governing permissions and 15*cf78ab8cSAndroid Build Coastguard Worker# limitations under the License. 16*cf78ab8cSAndroid Build Coastguard Workerimport glob 17*cf78ab8cSAndroid Build Coastguard Workerimport json 18*cf78ab8cSAndroid Build Coastguard Workerimport logging 19*cf78ab8cSAndroid Build Coastguard Workerimport os 20*cf78ab8cSAndroid Build Coastguard Workerfrom pathlib import Path 21*cf78ab8cSAndroid Build Coastguard Workerimport platform 22*cf78ab8cSAndroid Build Coastguard Workerimport shutil 23*cf78ab8cSAndroid Build Coastguard Workerimport socket 24*cf78ab8cSAndroid Build Coastguard Workerimport subprocess 25*cf78ab8cSAndroid Build Coastguard Workerimport sys 26*cf78ab8cSAndroid Build Coastguard Workerfrom threading import currentThread 27*cf78ab8cSAndroid Build Coastguard Worker 28*cf78ab8cSAndroid Build Coastguard Workerfrom time_formatter import TimeFormatter 29*cf78ab8cSAndroid Build Coastguard Worker 30*cf78ab8cSAndroid Build Coastguard Workerif sys.version_info[0] == 3: 31*cf78ab8cSAndroid Build Coastguard Worker from queue import Queue 32*cf78ab8cSAndroid Build Coastguard Workerelse: 33*cf78ab8cSAndroid Build Coastguard Worker from Queue import Queue 34*cf78ab8cSAndroid Build Coastguard Worker 35*cf78ab8cSAndroid Build Coastguard Workerfrom threading import Thread, currentThread 36*cf78ab8cSAndroid Build Coastguard Worker 37*cf78ab8cSAndroid Build Coastguard WorkerAOSP_ROOT = Path(__file__).absolute().parents[3] 38*cf78ab8cSAndroid Build Coastguard WorkerTOOLS = Path(AOSP_ROOT, "tools") 39*cf78ab8cSAndroid Build Coastguard WorkerEMULATOR_ARTIFACT_PATH = Path(AOSP_ROOT, "tools", "netsim", "emulator_tmp") 40*cf78ab8cSAndroid Build Coastguard WorkerPYTHON_EXE = sys.executable or "python3" 41*cf78ab8cSAndroid Build Coastguard WorkerTARGET_MAP = { 42*cf78ab8cSAndroid Build Coastguard Worker "windows": "windows_msvc-x86_64", 43*cf78ab8cSAndroid Build Coastguard Worker "windows_x64": "windows_msvc-x86_64", 44*cf78ab8cSAndroid Build Coastguard Worker "windows_x86_64": "windows_msvc-x86_64", 45*cf78ab8cSAndroid Build Coastguard Worker "linux": "linux-x86_64", 46*cf78ab8cSAndroid Build Coastguard Worker "linux_x64": "linux-x86_64", 47*cf78ab8cSAndroid Build Coastguard Worker "linux_x86_64": "linux-x86_64", 48*cf78ab8cSAndroid Build Coastguard Worker "linux_aarch64": "linux-aarch64", 49*cf78ab8cSAndroid Build Coastguard Worker "darwin": "darwin-x86_64", 50*cf78ab8cSAndroid Build Coastguard Worker "darwin_x64": "darwin-x86_64", 51*cf78ab8cSAndroid Build Coastguard Worker "darwin_x86_64": "darwin-x86_64", 52*cf78ab8cSAndroid Build Coastguard Worker "darwin_aarch64": "darwin-aarch64", 53*cf78ab8cSAndroid Build Coastguard Worker} 54*cf78ab8cSAndroid Build Coastguard Worker 55*cf78ab8cSAndroid Build Coastguard WorkerAVAILABLE = { 56*cf78ab8cSAndroid Build Coastguard Worker "windows_msvc-x86_64": "toolchain-windows_msvc-x86_64.cmake", 57*cf78ab8cSAndroid Build Coastguard Worker "linux-x86_64": "toolchain-linux-x86_64.cmake", 58*cf78ab8cSAndroid Build Coastguard Worker "darwin-x86_64": "toolchain-darwin-x86_64.cmake", 59*cf78ab8cSAndroid Build Coastguard Worker "linux-aarch64": "toolchain-linux-aarch64.cmake", 60*cf78ab8cSAndroid Build Coastguard Worker "darwin-aarch64": "toolchain-darwin-aarch64.cmake", 61*cf78ab8cSAndroid Build Coastguard Worker} 62*cf78ab8cSAndroid Build Coastguard Worker 63*cf78ab8cSAndroid Build Coastguard WorkerCMAKE = shutil.which( 64*cf78ab8cSAndroid Build Coastguard Worker "cmake", 65*cf78ab8cSAndroid Build Coastguard Worker path=str( 66*cf78ab8cSAndroid Build Coastguard Worker AOSP_ROOT 67*cf78ab8cSAndroid Build Coastguard Worker / "prebuilts" 68*cf78ab8cSAndroid Build Coastguard Worker / "cmake" 69*cf78ab8cSAndroid Build Coastguard Worker / f"{platform.system().lower()}-x86" 70*cf78ab8cSAndroid Build Coastguard Worker / "bin" 71*cf78ab8cSAndroid Build Coastguard Worker ), 72*cf78ab8cSAndroid Build Coastguard Worker) 73*cf78ab8cSAndroid Build Coastguard Worker 74*cf78ab8cSAndroid Build Coastguard Worker 75*cf78ab8cSAndroid Build Coastguard Workerdef rust_version() -> str: 76*cf78ab8cSAndroid Build Coastguard Worker """Returns rust version""" 77*cf78ab8cSAndroid Build Coastguard Worker with open( 78*cf78ab8cSAndroid Build Coastguard Worker AOSP_ROOT / "external" / "qemu" / "android" / "build" / "toolchains.json", 79*cf78ab8cSAndroid Build Coastguard Worker encoding="utf-8", 80*cf78ab8cSAndroid Build Coastguard Worker ) as f: 81*cf78ab8cSAndroid Build Coastguard Worker return json.load(f)["rust"] 82*cf78ab8cSAndroid Build Coastguard Worker 83*cf78ab8cSAndroid Build Coastguard Worker 84*cf78ab8cSAndroid Build Coastguard Workerdef default_target() -> str: 85*cf78ab8cSAndroid Build Coastguard Worker """Returns default value for target""" 86*cf78ab8cSAndroid Build Coastguard Worker # If Mac M1, the default target should be 'darwin-aarch64' 87*cf78ab8cSAndroid Build Coastguard Worker if platform.system() == "Darwin" and platform.machine() == "arm64": 88*cf78ab8cSAndroid Build Coastguard Worker return "darwin-aarch64" 89*cf78ab8cSAndroid Build Coastguard Worker return platform.system() 90*cf78ab8cSAndroid Build Coastguard Worker 91*cf78ab8cSAndroid Build Coastguard Worker 92*cf78ab8cSAndroid Build Coastguard Workerdef create_emulator_artifact_path(): 93*cf78ab8cSAndroid Build Coastguard Worker """Refresh or construct EMULATOR_ARTIFACT_PATH""" 94*cf78ab8cSAndroid Build Coastguard Worker if EMULATOR_ARTIFACT_PATH.exists(): 95*cf78ab8cSAndroid Build Coastguard Worker shutil.rmtree(EMULATOR_ARTIFACT_PATH) 96*cf78ab8cSAndroid Build Coastguard Worker EMULATOR_ARTIFACT_PATH.mkdir(exist_ok=True, parents=True) 97*cf78ab8cSAndroid Build Coastguard Worker 98*cf78ab8cSAndroid Build Coastguard Worker 99*cf78ab8cSAndroid Build Coastguard Workerdef fetch_build_chaining_artifacts(out_dir, presubmit): 100*cf78ab8cSAndroid Build Coastguard Worker """Fetch the Emulator prebuilts for build_bots (go/build_chaining)""" 101*cf78ab8cSAndroid Build Coastguard Worker try: 102*cf78ab8cSAndroid Build Coastguard Worker out = Path(out_dir) 103*cf78ab8cSAndroid Build Coastguard Worker prebuilt_path = out / "prebuilt_cached" / "artifacts" 104*cf78ab8cSAndroid Build Coastguard Worker files = glob.glob(str(prebuilt_path / f"*.zip")) 105*cf78ab8cSAndroid Build Coastguard Worker for file in files: 106*cf78ab8cSAndroid Build Coastguard Worker shutil.copy2(prebuilt_path / file, EMULATOR_ARTIFACT_PATH) 107*cf78ab8cSAndroid Build Coastguard Worker except Exception as e: 108*cf78ab8cSAndroid Build Coastguard Worker if presubmit: 109*cf78ab8cSAndroid Build Coastguard Worker raise e 110*cf78ab8cSAndroid Build Coastguard Worker else: 111*cf78ab8cSAndroid Build Coastguard Worker logging.warn( 112*cf78ab8cSAndroid Build Coastguard Worker f"An error occurred during fetch_build_chaining_artifacts: {e}" 113*cf78ab8cSAndroid Build Coastguard Worker ) 114*cf78ab8cSAndroid Build Coastguard Worker 115*cf78ab8cSAndroid Build Coastguard Worker 116*cf78ab8cSAndroid Build Coastguard Workerdef binary_extension(filename): 117*cf78ab8cSAndroid Build Coastguard Worker """Appends exe extension in case of Windows""" 118*cf78ab8cSAndroid Build Coastguard Worker if platform.system() == "Windows": 119*cf78ab8cSAndroid Build Coastguard Worker return filename + ".exe" 120*cf78ab8cSAndroid Build Coastguard Worker return filename 121*cf78ab8cSAndroid Build Coastguard Worker 122*cf78ab8cSAndroid Build Coastguard Worker 123*cf78ab8cSAndroid Build Coastguard Workerdef platform_to_cmake_target(target): 124*cf78ab8cSAndroid Build Coastguard Worker """Translates platform to cmake target""" 125*cf78ab8cSAndroid Build Coastguard Worker return TARGET_MAP[target.replace("-", "_")] 126*cf78ab8cSAndroid Build Coastguard Worker 127*cf78ab8cSAndroid Build Coastguard Worker 128*cf78ab8cSAndroid Build Coastguard Workerdef cmake_toolchain(target) -> str: 129*cf78ab8cSAndroid Build Coastguard Worker """Returns the path to the cmake toolchain file.""" 130*cf78ab8cSAndroid Build Coastguard Worker return ( 131*cf78ab8cSAndroid Build Coastguard Worker AOSP_ROOT 132*cf78ab8cSAndroid Build Coastguard Worker / "external" 133*cf78ab8cSAndroid Build Coastguard Worker / "qemu" 134*cf78ab8cSAndroid Build Coastguard Worker / "android" 135*cf78ab8cSAndroid Build Coastguard Worker / "build" 136*cf78ab8cSAndroid Build Coastguard Worker / "cmake" 137*cf78ab8cSAndroid Build Coastguard Worker / AVAILABLE[TARGET_MAP[target.replace("-", "_")]] 138*cf78ab8cSAndroid Build Coastguard Worker ) 139*cf78ab8cSAndroid Build Coastguard Worker 140*cf78ab8cSAndroid Build Coastguard Worker 141*cf78ab8cSAndroid Build Coastguard Workerdef is_presubmit(build_id): 142*cf78ab8cSAndroid Build Coastguard Worker return build_id.startswith("P") 143*cf78ab8cSAndroid Build Coastguard Worker 144*cf78ab8cSAndroid Build Coastguard Worker 145*cf78ab8cSAndroid Build Coastguard Workerdef get_host_and_ip(): 146*cf78ab8cSAndroid Build Coastguard Worker """Try to get my hostname and ip address.""" 147*cf78ab8cSAndroid Build Coastguard Worker st = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 148*cf78ab8cSAndroid Build Coastguard Worker try: 149*cf78ab8cSAndroid Build Coastguard Worker st.connect(("10.255.255.255", 1)) 150*cf78ab8cSAndroid Build Coastguard Worker my_ip = st.getsockname()[0] 151*cf78ab8cSAndroid Build Coastguard Worker except Exception: 152*cf78ab8cSAndroid Build Coastguard Worker my_ip = "127.0.0.1" 153*cf78ab8cSAndroid Build Coastguard Worker finally: 154*cf78ab8cSAndroid Build Coastguard Worker st.close() 155*cf78ab8cSAndroid Build Coastguard Worker 156*cf78ab8cSAndroid Build Coastguard Worker try: 157*cf78ab8cSAndroid Build Coastguard Worker hostname = socket.gethostname() 158*cf78ab8cSAndroid Build Coastguard Worker except Exception: 159*cf78ab8cSAndroid Build Coastguard Worker hostname = "Unkwown" 160*cf78ab8cSAndroid Build Coastguard Worker 161*cf78ab8cSAndroid Build Coastguard Worker return hostname, my_ip 162*cf78ab8cSAndroid Build Coastguard Worker 163*cf78ab8cSAndroid Build Coastguard Worker 164*cf78ab8cSAndroid Build Coastguard Workerclass LogBelowLevel(logging.Filter): 165*cf78ab8cSAndroid Build Coastguard Worker 166*cf78ab8cSAndroid Build Coastguard Worker def __init__(self, exclusive_maximum, name=""): 167*cf78ab8cSAndroid Build Coastguard Worker super(LogBelowLevel, self).__init__(name) 168*cf78ab8cSAndroid Build Coastguard Worker self.max_level = exclusive_maximum 169*cf78ab8cSAndroid Build Coastguard Worker 170*cf78ab8cSAndroid Build Coastguard Worker def filter(self, record): 171*cf78ab8cSAndroid Build Coastguard Worker return True if record.levelno < self.max_level else False 172*cf78ab8cSAndroid Build Coastguard Worker 173*cf78ab8cSAndroid Build Coastguard Worker 174*cf78ab8cSAndroid Build Coastguard Workerdef config_logging(): 175*cf78ab8cSAndroid Build Coastguard Worker logging_handler_out = logging.StreamHandler(sys.stdout) 176*cf78ab8cSAndroid Build Coastguard Worker logging_handler_out.setFormatter( 177*cf78ab8cSAndroid Build Coastguard Worker TimeFormatter("%(asctime)s %(threadName)s | %(message)s") 178*cf78ab8cSAndroid Build Coastguard Worker ) 179*cf78ab8cSAndroid Build Coastguard Worker logging_handler_out.setLevel(logging.DEBUG) 180*cf78ab8cSAndroid Build Coastguard Worker logging_handler_out.addFilter(LogBelowLevel(logging.WARNING)) 181*cf78ab8cSAndroid Build Coastguard Worker 182*cf78ab8cSAndroid Build Coastguard Worker logging_handler_err = logging.StreamHandler(sys.stderr) 183*cf78ab8cSAndroid Build Coastguard Worker logging_handler_err.setFormatter( 184*cf78ab8cSAndroid Build Coastguard Worker TimeFormatter("%(asctime)s %(threadName)s | %(message)s") 185*cf78ab8cSAndroid Build Coastguard Worker ) 186*cf78ab8cSAndroid Build Coastguard Worker logging_handler_err.setLevel(logging.WARNING) 187*cf78ab8cSAndroid Build Coastguard Worker 188*cf78ab8cSAndroid Build Coastguard Worker logging.root = logging.getLogger("build") 189*cf78ab8cSAndroid Build Coastguard Worker logging.root.setLevel(logging.INFO) 190*cf78ab8cSAndroid Build Coastguard Worker logging.root.addHandler(logging_handler_out) 191*cf78ab8cSAndroid Build Coastguard Worker logging.root.addHandler(logging_handler_err) 192*cf78ab8cSAndroid Build Coastguard Worker 193*cf78ab8cSAndroid Build Coastguard Worker currentThread().setName("inf") 194*cf78ab8cSAndroid Build Coastguard Worker 195*cf78ab8cSAndroid Build Coastguard Worker 196*cf78ab8cSAndroid Build Coastguard Workerdef log_system_info(): 197*cf78ab8cSAndroid Build Coastguard Worker """Log some useful system information.""" 198*cf78ab8cSAndroid Build Coastguard Worker version = "{0[0]}.{0[1]}.{0[2]}".format(sys.version_info) 199*cf78ab8cSAndroid Build Coastguard Worker hostname, my_ip = get_host_and_ip() 200*cf78ab8cSAndroid Build Coastguard Worker 201*cf78ab8cSAndroid Build Coastguard Worker logging.info( 202*cf78ab8cSAndroid Build Coastguard Worker "Hello from %s (%s). I'm a %s build bot", 203*cf78ab8cSAndroid Build Coastguard Worker hostname, 204*cf78ab8cSAndroid Build Coastguard Worker my_ip, 205*cf78ab8cSAndroid Build Coastguard Worker platform.system(), 206*cf78ab8cSAndroid Build Coastguard Worker ) 207*cf78ab8cSAndroid Build Coastguard Worker logging.info("My uname is: %s", platform.uname()) 208*cf78ab8cSAndroid Build Coastguard Worker logging.info( 209*cf78ab8cSAndroid Build Coastguard Worker "I'm happy to build the emulator using Python %s (%s)", 210*cf78ab8cSAndroid Build Coastguard Worker PYTHON_EXE, 211*cf78ab8cSAndroid Build Coastguard Worker version, 212*cf78ab8cSAndroid Build Coastguard Worker ) 213*cf78ab8cSAndroid Build Coastguard Worker 214*cf78ab8cSAndroid Build Coastguard Worker 215*cf78ab8cSAndroid Build Coastguard Workerdef run(cmd, env, log_prefix, cwd=AOSP_ROOT, throw_on_failure=True): 216*cf78ab8cSAndroid Build Coastguard Worker currentThread().setName(log_prefix) 217*cf78ab8cSAndroid Build Coastguard Worker cmd_env = os.environ.copy() 218*cf78ab8cSAndroid Build Coastguard Worker cmd_env.update(env) 219*cf78ab8cSAndroid Build Coastguard Worker is_windows = platform.system() == "Windows" 220*cf78ab8cSAndroid Build Coastguard Worker 221*cf78ab8cSAndroid Build Coastguard Worker cmd = [str(x) for x in cmd] 222*cf78ab8cSAndroid Build Coastguard Worker # logging.info("=" * 140) 223*cf78ab8cSAndroid Build Coastguard Worker # logging.info(json.dumps(cmd_env, sort_keys=True)) 224*cf78ab8cSAndroid Build Coastguard Worker logging.info("%s $> %s", cwd, " ".join(cmd)) 225*cf78ab8cSAndroid Build Coastguard Worker # logging.info("=" * 140) 226*cf78ab8cSAndroid Build Coastguard Worker 227*cf78ab8cSAndroid Build Coastguard Worker proc = subprocess.Popen( 228*cf78ab8cSAndroid Build Coastguard Worker cmd, 229*cf78ab8cSAndroid Build Coastguard Worker stdout=subprocess.PIPE, 230*cf78ab8cSAndroid Build Coastguard Worker stderr=subprocess.PIPE, 231*cf78ab8cSAndroid Build Coastguard Worker shell=is_windows, # Make sure windows propagates ENV vars properly. 232*cf78ab8cSAndroid Build Coastguard Worker cwd=cwd, 233*cf78ab8cSAndroid Build Coastguard Worker env=cmd_env, 234*cf78ab8cSAndroid Build Coastguard Worker ) 235*cf78ab8cSAndroid Build Coastguard Worker 236*cf78ab8cSAndroid Build Coastguard Worker _log_proc(proc, log_prefix) 237*cf78ab8cSAndroid Build Coastguard Worker proc.wait() 238*cf78ab8cSAndroid Build Coastguard Worker if proc.returncode != 0 and throw_on_failure: 239*cf78ab8cSAndroid Build Coastguard Worker raise Exception("Failed to run %s - %s" % (" ".join(cmd), proc.returncode)) 240*cf78ab8cSAndroid Build Coastguard Worker 241*cf78ab8cSAndroid Build Coastguard Worker 242*cf78ab8cSAndroid Build Coastguard Workerdef log_to_queue(q, line): 243*cf78ab8cSAndroid Build Coastguard Worker """Logs the output of the given process.""" 244*cf78ab8cSAndroid Build Coastguard Worker if q.full(): 245*cf78ab8cSAndroid Build Coastguard Worker q.get() 246*cf78ab8cSAndroid Build Coastguard Worker 247*cf78ab8cSAndroid Build Coastguard Worker strip = line.strip() 248*cf78ab8cSAndroid Build Coastguard Worker logging.info(strip) 249*cf78ab8cSAndroid Build Coastguard Worker q.put(strip) 250*cf78ab8cSAndroid Build Coastguard Worker 251*cf78ab8cSAndroid Build Coastguard Worker 252*cf78ab8cSAndroid Build Coastguard Workerdef _reader(pipe, logfn): 253*cf78ab8cSAndroid Build Coastguard Worker try: 254*cf78ab8cSAndroid Build Coastguard Worker with pipe: 255*cf78ab8cSAndroid Build Coastguard Worker for line in iter(pipe.readline, b""): 256*cf78ab8cSAndroid Build Coastguard Worker lg = line[:-1] 257*cf78ab8cSAndroid Build Coastguard Worker try: 258*cf78ab8cSAndroid Build Coastguard Worker lg = lg.decode("utf-8") 259*cf78ab8cSAndroid Build Coastguard Worker except Exception as e: 260*cf78ab8cSAndroid Build Coastguard Worker logfn("Failed to utf-8 decode line, {}".format(e)) 261*cf78ab8cSAndroid Build Coastguard Worker lg = str(lg) 262*cf78ab8cSAndroid Build Coastguard Worker logfn(lg.strip()) 263*cf78ab8cSAndroid Build Coastguard Worker finally: 264*cf78ab8cSAndroid Build Coastguard Worker pass 265*cf78ab8cSAndroid Build Coastguard Worker 266*cf78ab8cSAndroid Build Coastguard Worker 267*cf78ab8cSAndroid Build Coastguard Workerdef _log_proc(proc, log_prefix): 268*cf78ab8cSAndroid Build Coastguard Worker """Logs the output of the given process.""" 269*cf78ab8cSAndroid Build Coastguard Worker q = Queue() 270*cf78ab8cSAndroid Build Coastguard Worker for args in [[proc.stdout, logging.info], [proc.stderr, logging.error]]: 271*cf78ab8cSAndroid Build Coastguard Worker t = Thread(target=_reader, args=args) 272*cf78ab8cSAndroid Build Coastguard Worker t.setName(log_prefix) 273*cf78ab8cSAndroid Build Coastguard Worker t.start() 274*cf78ab8cSAndroid Build Coastguard Worker 275*cf78ab8cSAndroid Build Coastguard Worker return q 276