xref: /aosp_15_r20/tools/netsim/scripts/utils.py (revision cf78ab8cffb8fc9207af348f23af247fb04370a6)
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