xref: /aosp_15_r20/prebuilts/runtime/mainline/update.py (revision 924841fff420cd6b931e1027ee46b85e0a18fe17)
1*924841ffSAndroid Build Coastguard Worker#!/usr/bin/env -S python3 -B
2*924841ffSAndroid Build Coastguard Worker#
3*924841ffSAndroid Build Coastguard Worker# Copyright (C) 2020 The Android Open Source Project
4*924841ffSAndroid Build Coastguard Worker#
5*924841ffSAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License");
6*924841ffSAndroid Build Coastguard Worker# you may not use this file except in compliance with the License.
7*924841ffSAndroid Build Coastguard Worker# You may obtain a copy of the License at
8*924841ffSAndroid Build Coastguard Worker#
9*924841ffSAndroid Build Coastguard Worker#      http://www.apache.org/licenses/LICENSE-2.0
10*924841ffSAndroid Build Coastguard Worker#
11*924841ffSAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software
12*924841ffSAndroid Build Coastguard Worker# distributed under the License is distributed on an "AS IS" BASIS,
13*924841ffSAndroid Build Coastguard Worker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14*924841ffSAndroid Build Coastguard Worker# See the License for the specific language governing permissions and
15*924841ffSAndroid Build Coastguard Worker# limitations under the License.
16*924841ffSAndroid Build Coastguard Worker
17*924841ffSAndroid Build Coastguard Worker"""Downloads prebuilts for ART Module dependencies and creates CLs in git."""
18*924841ffSAndroid Build Coastguard Worker
19*924841ffSAndroid Build Coastguard Workerimport argparse
20*924841ffSAndroid Build Coastguard Workerimport collections
21*924841ffSAndroid Build Coastguard Workerimport os
22*924841ffSAndroid Build Coastguard Workerimport subprocess
23*924841ffSAndroid Build Coastguard Workerimport sys
24*924841ffSAndroid Build Coastguard Workerimport tempfile
25*924841ffSAndroid Build Coastguard Worker
26*924841ffSAndroid Build Coastguard Worker
27*924841ffSAndroid Build Coastguard Worker# Prebuilt description used in commit message
28*924841ffSAndroid Build Coastguard WorkerPREBUILT_DESCR = "ART dependencies"
29*924841ffSAndroid Build Coastguard Worker
30*924841ffSAndroid Build Coastguard Worker
31*924841ffSAndroid Build Coastguard Worker# Branch and target tuple for a CI build
32*924841ffSAndroid Build Coastguard WorkerBuildSource = collections.namedtuple("BuildSource", [
33*924841ffSAndroid Build Coastguard Worker    "branch",
34*924841ffSAndroid Build Coastguard Worker    "target",
35*924841ffSAndroid Build Coastguard Worker])
36*924841ffSAndroid Build Coastguard Worker
37*924841ffSAndroid Build Coastguard Worker
38*924841ffSAndroid Build Coastguard Worker# The list of arches does not include riscv64: it is not supported by mainline,
39*924841ffSAndroid Build Coastguard Worker# and it is updated from a local build with --local-dist-riscv64 option (which
40*924841ffSAndroid Build Coastguard Worker# overwrites the list of arches to include only riscv64).
41*924841ffSAndroid Build Coastguard Worker#
42*924841ffSAndroid Build Coastguard Worker# TODO(b/286551985): add riscv64 here and don't override the global list.
43*924841ffSAndroid Build Coastguard WorkerARCHES = ["arm", "arm64", "x86", "x86_64"]
44*924841ffSAndroid Build Coastguard Worker
45*924841ffSAndroid Build Coastguard Worker# CI build for SDK snapshots
46*924841ffSAndroid Build Coastguard WorkerSDK_SOURCE = BuildSource("aosp-main",
47*924841ffSAndroid Build Coastguard Worker                         "mainline_modules_sdks-trunk_staging-userdebug")
48*924841ffSAndroid Build Coastguard Worker
49*924841ffSAndroid Build Coastguard Worker# Architecture-specific CI builds for APEXes. These are only used in the chroot
50*924841ffSAndroid Build Coastguard Worker# test setup (see art/tools/buildbot-build.sh). They never become part of any
51*924841ffSAndroid Build Coastguard Worker# dist artifact.
52*924841ffSAndroid Build Coastguard Worker#
53*924841ffSAndroid Build Coastguard Worker# There are currently no CI builds except for x86_64, so APEX updates are
54*924841ffSAndroid Build Coastguard Worker# skipped by default.
55*924841ffSAndroid Build Coastguard WorkerAPEX_SOURCE = {
56*924841ffSAndroid Build Coastguard Worker    "x86_64": BuildSource("aosp-main",
57*924841ffSAndroid Build Coastguard Worker                          "mainline_modules_x86_64-trunk_staging-userdebug"),
58*924841ffSAndroid Build Coastguard Worker}
59*924841ffSAndroid Build Coastguard Worker
60*924841ffSAndroid Build Coastguard Worker# Paths to git projects to prepare CLs in
61*924841ffSAndroid Build Coastguard WorkerGIT_PROJECT_ROOTS = [
62*924841ffSAndroid Build Coastguard Worker    "prebuilts/module_sdk/conscrypt",
63*924841ffSAndroid Build Coastguard Worker    "prebuilts/runtime",
64*924841ffSAndroid Build Coastguard Worker]
65*924841ffSAndroid Build Coastguard Worker
66*924841ffSAndroid Build Coastguard WorkerSDK_VERSION = "current"
67*924841ffSAndroid Build Coastguard Worker
68*924841ffSAndroid Build Coastguard WorkerSCRIPT_PATH = "prebuilts/runtime/mainline/update.py"
69*924841ffSAndroid Build Coastguard Worker
70*924841ffSAndroid Build Coastguard Worker
71*924841ffSAndroid Build Coastguard WorkerInstallEntry = collections.namedtuple(
72*924841ffSAndroid Build Coastguard Worker    "InstallEntry",
73*924841ffSAndroid Build Coastguard Worker    [
74*924841ffSAndroid Build Coastguard Worker        # Either "apex" or "module_sdk", for the --skip-* flags.
75*924841ffSAndroid Build Coastguard Worker        "type",
76*924841ffSAndroid Build Coastguard Worker        # Source CI build as a BuildSource tuple, or None if none exists.
77*924841ffSAndroid Build Coastguard Worker        "source_build",
78*924841ffSAndroid Build Coastguard Worker        # Artifact path in the build, passed to fetch_target. Should match a
79*924841ffSAndroid Build Coastguard Worker        # single file. "{BUILD}" gets replaced with the build number.
80*924841ffSAndroid Build Coastguard Worker        "source_path",
81*924841ffSAndroid Build Coastguard Worker        # Local install path.
82*924841ffSAndroid Build Coastguard Worker        "install_path",
83*924841ffSAndroid Build Coastguard Worker        # True if the entry is a zip file that should be unzipped to
84*924841ffSAndroid Build Coastguard Worker        # install_path.
85*924841ffSAndroid Build Coastguard Worker        "install_unzipped",
86*924841ffSAndroid Build Coastguard Worker        # If set, the entry is a zip from which this single file is extracted to
87*924841ffSAndroid Build Coastguard Worker        # install_path.
88*924841ffSAndroid Build Coastguard Worker        "unzip_single_file",
89*924841ffSAndroid Build Coastguard Worker    ],
90*924841ffSAndroid Build Coastguard Worker    defaults=(False, None), # Defaults for install_unzipped and unzip_single_file.
91*924841ffSAndroid Build Coastguard Worker)
92*924841ffSAndroid Build Coastguard Worker
93*924841ffSAndroid Build Coastguard Worker
94*924841ffSAndroid Build Coastguard Workerdef install_apex_entries(module_name, apex_name):
95*924841ffSAndroid Build Coastguard Worker  return [
96*924841ffSAndroid Build Coastguard Worker      InstallEntry(
97*924841ffSAndroid Build Coastguard Worker          type="apex",
98*924841ffSAndroid Build Coastguard Worker          source_build=APEX_SOURCE.get(arch, None),
99*924841ffSAndroid Build Coastguard Worker          source_path=os.path.join(
100*924841ffSAndroid Build Coastguard Worker              "mainline_modules_" + arch,
101*924841ffSAndroid Build Coastguard Worker              apex_name + ".apex"),
102*924841ffSAndroid Build Coastguard Worker          install_path=os.path.join(
103*924841ffSAndroid Build Coastguard Worker              "prebuilts/runtime/mainline",
104*924841ffSAndroid Build Coastguard Worker              module_name,
105*924841ffSAndroid Build Coastguard Worker              "apex",
106*924841ffSAndroid Build Coastguard Worker              apex_name + "-" + arch + ".apex"))
107*924841ffSAndroid Build Coastguard Worker      for arch in ARCHES]
108*924841ffSAndroid Build Coastguard Worker
109*924841ffSAndroid Build Coastguard Worker
110*924841ffSAndroid Build Coastguard Workerdef install_unbundled_sdk_entries(apex_name, mainline_sdk_name, sdk_type, install_path):
111*924841ffSAndroid Build Coastguard Worker  if "riscv64" in ARCHES:
112*924841ffSAndroid Build Coastguard Worker    if sdk_type == "host-exports": # no host prebuilts for riscv64
113*924841ffSAndroid Build Coastguard Worker      return []
114*924841ffSAndroid Build Coastguard Worker    install_path = os.path.join("prebuilts/runtime/mainline/local_riscv64",
115*924841ffSAndroid Build Coastguard Worker                                install_path)
116*924841ffSAndroid Build Coastguard Worker  return [
117*924841ffSAndroid Build Coastguard Worker      InstallEntry(
118*924841ffSAndroid Build Coastguard Worker          type="module_sdk",
119*924841ffSAndroid Build Coastguard Worker          source_build=SDK_SOURCE,
120*924841ffSAndroid Build Coastguard Worker          source_path=os.path.join(
121*924841ffSAndroid Build Coastguard Worker              "mainline-sdks/for-latest-build",
122*924841ffSAndroid Build Coastguard Worker              SDK_VERSION,
123*924841ffSAndroid Build Coastguard Worker              apex_name,
124*924841ffSAndroid Build Coastguard Worker              sdk_type,
125*924841ffSAndroid Build Coastguard Worker              mainline_sdk_name + "-" + sdk_type + "-" + SDK_VERSION + ".zip"),
126*924841ffSAndroid Build Coastguard Worker          install_path=install_path,
127*924841ffSAndroid Build Coastguard Worker          install_unzipped=True)]
128*924841ffSAndroid Build Coastguard Worker
129*924841ffSAndroid Build Coastguard Worker
130*924841ffSAndroid Build Coastguard Workerdef install_bundled_sdk_entries(module_name, sdk_type):
131*924841ffSAndroid Build Coastguard Worker  if "riscv64" in ARCHES:
132*924841ffSAndroid Build Coastguard Worker    if sdk_type == "host-exports": # no host prebuilts for riscv64
133*924841ffSAndroid Build Coastguard Worker      return []
134*924841ffSAndroid Build Coastguard Worker  return [
135*924841ffSAndroid Build Coastguard Worker      InstallEntry(
136*924841ffSAndroid Build Coastguard Worker          type="module_sdk",
137*924841ffSAndroid Build Coastguard Worker          source_build=SDK_SOURCE,
138*924841ffSAndroid Build Coastguard Worker          source_path=os.path.join(
139*924841ffSAndroid Build Coastguard Worker              "bundled-mainline-sdks",
140*924841ffSAndroid Build Coastguard Worker              "com.android." + module_name,
141*924841ffSAndroid Build Coastguard Worker              sdk_type,
142*924841ffSAndroid Build Coastguard Worker              module_name + "-module-" + sdk_type + "-" + SDK_VERSION + ".zip"),
143*924841ffSAndroid Build Coastguard Worker          install_path=os.path.join(
144*924841ffSAndroid Build Coastguard Worker              "prebuilts/runtime/mainline",
145*924841ffSAndroid Build Coastguard Worker              module_name,
146*924841ffSAndroid Build Coastguard Worker              sdk_type),
147*924841ffSAndroid Build Coastguard Worker          install_unzipped=True)]
148*924841ffSAndroid Build Coastguard Worker
149*924841ffSAndroid Build Coastguard Worker
150*924841ffSAndroid Build Coastguard Workerdef install_platform_mainline_sdk_entries(sdk_type):
151*924841ffSAndroid Build Coastguard Worker  if "riscv64" in ARCHES:
152*924841ffSAndroid Build Coastguard Worker    if sdk_type == "host-exports": # no host prebuilts for riscv64
153*924841ffSAndroid Build Coastguard Worker      return []
154*924841ffSAndroid Build Coastguard Worker  return [
155*924841ffSAndroid Build Coastguard Worker      InstallEntry(
156*924841ffSAndroid Build Coastguard Worker          type="module_sdk",
157*924841ffSAndroid Build Coastguard Worker          source_build=SDK_SOURCE,
158*924841ffSAndroid Build Coastguard Worker          source_path=os.path.join(
159*924841ffSAndroid Build Coastguard Worker              "bundled-mainline-sdks",
160*924841ffSAndroid Build Coastguard Worker              "platform-mainline",
161*924841ffSAndroid Build Coastguard Worker              sdk_type,
162*924841ffSAndroid Build Coastguard Worker              "platform-mainline-" + sdk_type + "-" + SDK_VERSION + ".zip"),
163*924841ffSAndroid Build Coastguard Worker          install_path=os.path.join(
164*924841ffSAndroid Build Coastguard Worker              "prebuilts/runtime/mainline/platform",
165*924841ffSAndroid Build Coastguard Worker              sdk_type),
166*924841ffSAndroid Build Coastguard Worker          install_unzipped=True)]
167*924841ffSAndroid Build Coastguard Worker
168*924841ffSAndroid Build Coastguard Worker
169*924841ffSAndroid Build Coastguard Worker# This is defined as a function (not a global list) because it depends on the
170*924841ffSAndroid Build Coastguard Worker# list of architectures, which may change after parsing options.
171*924841ffSAndroid Build Coastguard Workerdef install_entries():
172*924841ffSAndroid Build Coastguard Worker  return (
173*924841ffSAndroid Build Coastguard Worker    # Conscrypt
174*924841ffSAndroid Build Coastguard Worker    install_apex_entries("conscrypt", "com.android.conscrypt") +
175*924841ffSAndroid Build Coastguard Worker    install_unbundled_sdk_entries(
176*924841ffSAndroid Build Coastguard Worker        "com.android.conscrypt", "conscrypt-module", "sdk",
177*924841ffSAndroid Build Coastguard Worker        "prebuilts/module_sdk/conscrypt/current") +
178*924841ffSAndroid Build Coastguard Worker    install_unbundled_sdk_entries(
179*924841ffSAndroid Build Coastguard Worker        "com.android.conscrypt", "conscrypt-module", "test-exports",
180*924841ffSAndroid Build Coastguard Worker        "prebuilts/module_sdk/conscrypt/current/test-exports") +
181*924841ffSAndroid Build Coastguard Worker    install_unbundled_sdk_entries(
182*924841ffSAndroid Build Coastguard Worker        "com.android.conscrypt", "conscrypt-module", "host-exports",
183*924841ffSAndroid Build Coastguard Worker        "prebuilts/module_sdk/conscrypt/current/host-exports") +
184*924841ffSAndroid Build Coastguard Worker
185*924841ffSAndroid Build Coastguard Worker    # Runtime (Bionic)
186*924841ffSAndroid Build Coastguard Worker    # sdk and host-exports must always be updated together, because the linker
187*924841ffSAndroid Build Coastguard Worker    # and the CRT object files gets embedded in the binaries on linux host
188*924841ffSAndroid Build Coastguard Worker    # Bionic (see code and comments around host_bionic_linker_script in
189*924841ffSAndroid Build Coastguard Worker    # build/soong).
190*924841ffSAndroid Build Coastguard Worker    install_apex_entries("runtime", "com.android.runtime") +
191*924841ffSAndroid Build Coastguard Worker    install_bundled_sdk_entries("runtime", "sdk") +
192*924841ffSAndroid Build Coastguard Worker    install_bundled_sdk_entries("runtime", "host-exports") +
193*924841ffSAndroid Build Coastguard Worker
194*924841ffSAndroid Build Coastguard Worker    # I18N
195*924841ffSAndroid Build Coastguard Worker    install_apex_entries("i18n", "com.android.i18n") +
196*924841ffSAndroid Build Coastguard Worker    install_bundled_sdk_entries("i18n", "sdk") +
197*924841ffSAndroid Build Coastguard Worker    install_bundled_sdk_entries("i18n", "test-exports") +
198*924841ffSAndroid Build Coastguard Worker
199*924841ffSAndroid Build Coastguard Worker    # tzdata
200*924841ffSAndroid Build Coastguard Worker    install_apex_entries("tzdata", "com.android.tzdata") +
201*924841ffSAndroid Build Coastguard Worker    install_bundled_sdk_entries("tzdata", "test-exports") +
202*924841ffSAndroid Build Coastguard Worker
203*924841ffSAndroid Build Coastguard Worker    # Platform
204*924841ffSAndroid Build Coastguard Worker    install_platform_mainline_sdk_entries("sdk") +
205*924841ffSAndroid Build Coastguard Worker    install_platform_mainline_sdk_entries("test-exports") +
206*924841ffSAndroid Build Coastguard Worker
207*924841ffSAndroid Build Coastguard Worker    [])
208*924841ffSAndroid Build Coastguard Worker
209*924841ffSAndroid Build Coastguard Worker
210*924841ffSAndroid Build Coastguard Workerdef check_call(cmd, **kwargs):
211*924841ffSAndroid Build Coastguard Worker  """Proxy for subprocess.check_call with logging."""
212*924841ffSAndroid Build Coastguard Worker  msg = " ".join(cmd) if isinstance(cmd, list) else cmd
213*924841ffSAndroid Build Coastguard Worker  if "cwd" in kwargs:
214*924841ffSAndroid Build Coastguard Worker    msg = "In " + kwargs["cwd"] + ": " + msg
215*924841ffSAndroid Build Coastguard Worker  print(msg)
216*924841ffSAndroid Build Coastguard Worker  subprocess.check_call(cmd, **kwargs)
217*924841ffSAndroid Build Coastguard Worker
218*924841ffSAndroid Build Coastguard Worker
219*924841ffSAndroid Build Coastguard Workerdef fetch_artifact(branch, target, build, fetch_pattern, local_dir, zip_entry=None):
220*924841ffSAndroid Build Coastguard Worker  """Fetches artifact from the build server."""
221*924841ffSAndroid Build Coastguard Worker  fetch_artifact_path = "/google/data/ro/projects/android/fetch_artifact"
222*924841ffSAndroid Build Coastguard Worker  cmd = [fetch_artifact_path, "--branch", branch, "--target", target,
223*924841ffSAndroid Build Coastguard Worker         "--bid", build, fetch_pattern]
224*924841ffSAndroid Build Coastguard Worker  if zip_entry:
225*924841ffSAndroid Build Coastguard Worker    cmd += ["--zip_entry", zip_entry]
226*924841ffSAndroid Build Coastguard Worker  check_call(cmd, cwd=local_dir)
227*924841ffSAndroid Build Coastguard Worker
228*924841ffSAndroid Build Coastguard Worker
229*924841ffSAndroid Build Coastguard Workerdef start_branch(git_branch_name, git_dirs):
230*924841ffSAndroid Build Coastguard Worker  """Creates a new repo branch in the given projects."""
231*924841ffSAndroid Build Coastguard Worker  check_call(["repo", "start", git_branch_name] + git_dirs)
232*924841ffSAndroid Build Coastguard Worker  # In case the branch already exists we reset it to upstream, to get a clean
233*924841ffSAndroid Build Coastguard Worker  # update CL.
234*924841ffSAndroid Build Coastguard Worker  for git_dir in git_dirs:
235*924841ffSAndroid Build Coastguard Worker    check_call(["git", "reset", "--hard", "@{upstream}"], cwd=git_dir)
236*924841ffSAndroid Build Coastguard Worker
237*924841ffSAndroid Build Coastguard Worker
238*924841ffSAndroid Build Coastguard Workerdef upload_branch(git_root, git_branch_name):
239*924841ffSAndroid Build Coastguard Worker  """Uploads the CLs in the given branch in the given project."""
240*924841ffSAndroid Build Coastguard Worker  # Set the branch as topic to bundle with the CLs in other git projects (if
241*924841ffSAndroid Build Coastguard Worker  # any).
242*924841ffSAndroid Build Coastguard Worker  check_call(["repo", "upload", "-t", "--br=" + git_branch_name, git_root])
243*924841ffSAndroid Build Coastguard Worker
244*924841ffSAndroid Build Coastguard Worker
245*924841ffSAndroid Build Coastguard Workerdef remove_files(git_root, subpaths, stage_removals):
246*924841ffSAndroid Build Coastguard Worker  """Removes files in the work tree, optionally staging them in git."""
247*924841ffSAndroid Build Coastguard Worker  if stage_removals:
248*924841ffSAndroid Build Coastguard Worker    check_call(["git", "rm", "-qrf", "--ignore-unmatch"] + subpaths, cwd=git_root)
249*924841ffSAndroid Build Coastguard Worker  # Need a plain rm afterwards even if git rm was executed, because git won't
250*924841ffSAndroid Build Coastguard Worker  # remove directories if they have non-git files in them.
251*924841ffSAndroid Build Coastguard Worker  check_call(["rm", "-rf"] + subpaths, cwd=git_root)
252*924841ffSAndroid Build Coastguard Worker
253*924841ffSAndroid Build Coastguard Worker
254*924841ffSAndroid Build Coastguard Workerdef commit(git_root, prebuilt_descr, installed_sources, add_paths, bug_number):
255*924841ffSAndroid Build Coastguard Worker  """Commits the new prebuilts."""
256*924841ffSAndroid Build Coastguard Worker  check_call(["git", "add"] +
257*924841ffSAndroid Build Coastguard Worker             [path for path in add_paths
258*924841ffSAndroid Build Coastguard Worker              if os.path.exists(os.path.join(git_root, path))],
259*924841ffSAndroid Build Coastguard Worker             cwd=git_root)
260*924841ffSAndroid Build Coastguard Worker
261*924841ffSAndroid Build Coastguard Worker  if installed_sources:
262*924841ffSAndroid Build Coastguard Worker    message = "Update {} prebuilts.\n\n".format(prebuilt_descr)
263*924841ffSAndroid Build Coastguard Worker    if len(installed_sources) == 1:
264*924841ffSAndroid Build Coastguard Worker      message += "Taken from {}.".format(installed_sources[0])
265*924841ffSAndroid Build Coastguard Worker    else:
266*924841ffSAndroid Build Coastguard Worker      message += "Taken from:\n{}".format(
267*924841ffSAndroid Build Coastguard Worker          "\n".join([s.capitalize() for s in installed_sources]))
268*924841ffSAndroid Build Coastguard Worker  else:
269*924841ffSAndroid Build Coastguard Worker    # For riscv64, update from a local tree is the only available option.
270*924841ffSAndroid Build Coastguard Worker    message = "" if "riscv64" in ARCHES else "DO NOT SUBMIT: "
271*924841ffSAndroid Build Coastguard Worker    message += (
272*924841ffSAndroid Build Coastguard Worker        "Update {prebuilt_descr} prebuilts from local build."
273*924841ffSAndroid Build Coastguard Worker        .format(prebuilt_descr=prebuilt_descr))
274*924841ffSAndroid Build Coastguard Worker  message += ("\n\nCL prepared by {}."
275*924841ffSAndroid Build Coastguard Worker              "\n\nTest: Presubmits".format(SCRIPT_PATH))
276*924841ffSAndroid Build Coastguard Worker  if bug_number:
277*924841ffSAndroid Build Coastguard Worker    message += ("\nBug: {}".format(bug_number))
278*924841ffSAndroid Build Coastguard Worker
279*924841ffSAndroid Build Coastguard Worker  msg_fd, msg_path = tempfile.mkstemp()
280*924841ffSAndroid Build Coastguard Worker  try:
281*924841ffSAndroid Build Coastguard Worker    with os.fdopen(msg_fd, "w") as f:
282*924841ffSAndroid Build Coastguard Worker      f.write(message)
283*924841ffSAndroid Build Coastguard Worker    # Do a diff first to skip the commit without error if there are no changes
284*924841ffSAndroid Build Coastguard Worker    # to commit.
285*924841ffSAndroid Build Coastguard Worker    check_call("git diff-index --quiet --cached HEAD -- || "
286*924841ffSAndroid Build Coastguard Worker               "git commit -F " + msg_path, shell=True, cwd=git_root)
287*924841ffSAndroid Build Coastguard Worker  finally:
288*924841ffSAndroid Build Coastguard Worker    os.unlink(msg_path)
289*924841ffSAndroid Build Coastguard Worker
290*924841ffSAndroid Build Coastguard Worker
291*924841ffSAndroid Build Coastguard Workerdef install_entry(tmp_dir, local_dist, build_numbers, entry):
292*924841ffSAndroid Build Coastguard Worker  """Installs one file specified by entry."""
293*924841ffSAndroid Build Coastguard Worker
294*924841ffSAndroid Build Coastguard Worker  if not local_dist and not entry.source_build:
295*924841ffSAndroid Build Coastguard Worker    print("WARNING: No CI build for {} - skipping.".format(entry.source_path))
296*924841ffSAndroid Build Coastguard Worker    return None
297*924841ffSAndroid Build Coastguard Worker
298*924841ffSAndroid Build Coastguard Worker  build_number = (build_numbers[entry.source_build.branch]
299*924841ffSAndroid Build Coastguard Worker                  if build_numbers else None)
300*924841ffSAndroid Build Coastguard Worker
301*924841ffSAndroid Build Coastguard Worker  # Fall back to the username as the build ID if we have no build number. That's
302*924841ffSAndroid Build Coastguard Worker  # what a dist install does in a local build.
303*924841ffSAndroid Build Coastguard Worker  source_path = entry.source_path.replace(
304*924841ffSAndroid Build Coastguard Worker      "{BUILD}", str(build_number) if build_number else os.getenv("USER"))
305*924841ffSAndroid Build Coastguard Worker
306*924841ffSAndroid Build Coastguard Worker  source_dir, source_file = os.path.split(source_path)
307*924841ffSAndroid Build Coastguard Worker
308*924841ffSAndroid Build Coastguard Worker  if local_dist:
309*924841ffSAndroid Build Coastguard Worker    download_dir = os.path.join(tmp_dir, source_dir)
310*924841ffSAndroid Build Coastguard Worker  else:
311*924841ffSAndroid Build Coastguard Worker    download_dir = os.path.join(tmp_dir,
312*924841ffSAndroid Build Coastguard Worker                                entry.source_build.branch,
313*924841ffSAndroid Build Coastguard Worker                                build_number,
314*924841ffSAndroid Build Coastguard Worker                                entry.source_build.target,
315*924841ffSAndroid Build Coastguard Worker                                source_dir)
316*924841ffSAndroid Build Coastguard Worker  os.makedirs(download_dir, exist_ok=True)
317*924841ffSAndroid Build Coastguard Worker  download_file = os.path.join(download_dir, source_file)
318*924841ffSAndroid Build Coastguard Worker
319*924841ffSAndroid Build Coastguard Worker  unzip_dir = None
320*924841ffSAndroid Build Coastguard Worker  unzip_file = None
321*924841ffSAndroid Build Coastguard Worker  if entry.unzip_single_file:
322*924841ffSAndroid Build Coastguard Worker    unzip_dir = os.path.join(download_dir,
323*924841ffSAndroid Build Coastguard Worker                             source_path.removesuffix(".zip") + "_unzip")
324*924841ffSAndroid Build Coastguard Worker    os.makedirs(unzip_dir, exist_ok=True)
325*924841ffSAndroid Build Coastguard Worker    unzip_file = os.path.join(unzip_dir, entry.unzip_single_file)
326*924841ffSAndroid Build Coastguard Worker
327*924841ffSAndroid Build Coastguard Worker  if not local_dist and unzip_file:
328*924841ffSAndroid Build Coastguard Worker    if not os.path.exists(unzip_file):
329*924841ffSAndroid Build Coastguard Worker      # Use the --zip_entry option to fetch_artifact to avoid downloading the
330*924841ffSAndroid Build Coastguard Worker      # whole zip.
331*924841ffSAndroid Build Coastguard Worker      fetch_artifact(entry.source_build.branch,
332*924841ffSAndroid Build Coastguard Worker                     entry.source_build.target,
333*924841ffSAndroid Build Coastguard Worker                     build_number,
334*924841ffSAndroid Build Coastguard Worker                     source_path,
335*924841ffSAndroid Build Coastguard Worker                     unzip_dir,
336*924841ffSAndroid Build Coastguard Worker                     entry.unzip_single_file)
337*924841ffSAndroid Build Coastguard Worker      if not os.path.exists(unzip_file):
338*924841ffSAndroid Build Coastguard Worker        sys.exit("fetch_artifact didn't create expected file {}".format(unzip_file))
339*924841ffSAndroid Build Coastguard Worker  else:
340*924841ffSAndroid Build Coastguard Worker    # Fetch files once by downloading them into a specific location in tmp_dir
341*924841ffSAndroid Build Coastguard Worker    # only if they're not already there.
342*924841ffSAndroid Build Coastguard Worker    if not os.path.exists(download_file):
343*924841ffSAndroid Build Coastguard Worker      if local_dist:
344*924841ffSAndroid Build Coastguard Worker        check_call(["cp", os.path.join(local_dist, source_path), download_dir])
345*924841ffSAndroid Build Coastguard Worker      else:
346*924841ffSAndroid Build Coastguard Worker        fetch_artifact(entry.source_build.branch,
347*924841ffSAndroid Build Coastguard Worker                       entry.source_build.target,
348*924841ffSAndroid Build Coastguard Worker                       build_number,
349*924841ffSAndroid Build Coastguard Worker                       source_path,
350*924841ffSAndroid Build Coastguard Worker                       download_dir)
351*924841ffSAndroid Build Coastguard Worker      if not os.path.exists(download_file):
352*924841ffSAndroid Build Coastguard Worker        sys.exit("Failed to retrieve {}".format(source_path))
353*924841ffSAndroid Build Coastguard Worker
354*924841ffSAndroid Build Coastguard Worker  install_dir, install_file = os.path.split(entry.install_path)
355*924841ffSAndroid Build Coastguard Worker  os.makedirs(install_dir, exist_ok=True)
356*924841ffSAndroid Build Coastguard Worker
357*924841ffSAndroid Build Coastguard Worker  if entry.install_unzipped:
358*924841ffSAndroid Build Coastguard Worker    if "riscv64" in ARCHES:
359*924841ffSAndroid Build Coastguard Worker      tmp_dir = os.path.join(install_file, "tmp")
360*924841ffSAndroid Build Coastguard Worker      check_call(["mkdir", "-p", tmp_dir], cwd=install_dir)
361*924841ffSAndroid Build Coastguard Worker      check_call(["unzip", "-DD", "-o", download_file, "-d", tmp_dir],
362*924841ffSAndroid Build Coastguard Worker                 cwd=install_dir)
363*924841ffSAndroid Build Coastguard Worker      # Conscrypt is not owned by the ART team, so we keep a local copy of its
364*924841ffSAndroid Build Coastguard Worker      # prebuilt with Android.bp files renamed to ArtThinBuild.bp to avoid Soong
365*924841ffSAndroid Build Coastguard Worker      # adding them as part of the build graph.
366*924841ffSAndroid Build Coastguard Worker      if "local_riscv64" in install_dir:
367*924841ffSAndroid Build Coastguard Worker        patch_cmd = ("sed -i 's|This is auto-generated. DO NOT EDIT.|"
368*924841ffSAndroid Build Coastguard Worker            "DO NOT COMMIT. Changes in this file are temporary and generated "
369*924841ffSAndroid Build Coastguard Worker            "by art/tools/buildbot-build.sh. See b/286551985.|g' {} ; ")
370*924841ffSAndroid Build Coastguard Worker        rename_cmd = 'f="{}" ; mv "$f" "$(dirname $f)"/ArtThinBuild.bp'
371*924841ffSAndroid Build Coastguard Worker        check_call(["find", "-type", "f", "-name", "Android.bp",
372*924841ffSAndroid Build Coastguard Worker                       "-exec", "sh", "-c", patch_cmd + rename_cmd, ";"],
373*924841ffSAndroid Build Coastguard Worker                   cwd=os.path.join(install_dir, tmp_dir))
374*924841ffSAndroid Build Coastguard Worker      check_call(["find", "-type", "f", "-regextype", "posix-extended",
375*924841ffSAndroid Build Coastguard Worker                     "-regex", ".*riscv64.*|.*Android.bp|.*ArtThinBuild.bp",
376*924841ffSAndroid Build Coastguard Worker                     "-exec", "cp", "--parents", "{}", "..", ";"],
377*924841ffSAndroid Build Coastguard Worker                 cwd=os.path.join(install_dir, tmp_dir))
378*924841ffSAndroid Build Coastguard Worker      check_call(["rm", "-rf", tmp_dir], cwd=install_dir)
379*924841ffSAndroid Build Coastguard Worker    else:
380*924841ffSAndroid Build Coastguard Worker      check_call(["mkdir", install_file], cwd=install_dir)
381*924841ffSAndroid Build Coastguard Worker      # Add -DD to not extract timestamps that may confuse the build system.
382*924841ffSAndroid Build Coastguard Worker      check_call(["unzip", "-DD", download_file, "-d", install_file],
383*924841ffSAndroid Build Coastguard Worker                 cwd=install_dir)
384*924841ffSAndroid Build Coastguard Worker  elif entry.unzip_single_file:
385*924841ffSAndroid Build Coastguard Worker    if not os.path.exists(unzip_file):
386*924841ffSAndroid Build Coastguard Worker      check_call(["unzip", download_file, "-d", unzip_dir, entry.unzip_single_file])
387*924841ffSAndroid Build Coastguard Worker    check_call(["cp", unzip_file, install_file], cwd=install_dir)
388*924841ffSAndroid Build Coastguard Worker  else:
389*924841ffSAndroid Build Coastguard Worker    check_call(["cp", download_file, install_file], cwd=install_dir)
390*924841ffSAndroid Build Coastguard Worker
391*924841ffSAndroid Build Coastguard Worker  # Return a description of the source location for inclusion in the commit
392*924841ffSAndroid Build Coastguard Worker  # message.
393*924841ffSAndroid Build Coastguard Worker  return (
394*924841ffSAndroid Build Coastguard Worker      "branch {}, target {}, build {}".format(
395*924841ffSAndroid Build Coastguard Worker          entry.source_build.branch,
396*924841ffSAndroid Build Coastguard Worker          entry.source_build.target,
397*924841ffSAndroid Build Coastguard Worker          build_number)
398*924841ffSAndroid Build Coastguard Worker      if not local_dist else None)
399*924841ffSAndroid Build Coastguard Worker
400*924841ffSAndroid Build Coastguard Worker
401*924841ffSAndroid Build Coastguard Workerdef install_paths_per_git_root(roots, paths):
402*924841ffSAndroid Build Coastguard Worker  """Partitions the given paths into subpaths within the given roots.
403*924841ffSAndroid Build Coastguard Worker
404*924841ffSAndroid Build Coastguard Worker  Args:
405*924841ffSAndroid Build Coastguard Worker    roots: List of root paths.
406*924841ffSAndroid Build Coastguard Worker    paths: List of paths relative to the same directory as the root paths.
407*924841ffSAndroid Build Coastguard Worker
408*924841ffSAndroid Build Coastguard Worker  Returns:
409*924841ffSAndroid Build Coastguard Worker    A dict mapping each root to the subpaths under it. It's an error if some
410*924841ffSAndroid Build Coastguard Worker    path doesn't go into any root.
411*924841ffSAndroid Build Coastguard Worker  """
412*924841ffSAndroid Build Coastguard Worker  res = collections.defaultdict(list)
413*924841ffSAndroid Build Coastguard Worker  for path in paths:
414*924841ffSAndroid Build Coastguard Worker    found = False
415*924841ffSAndroid Build Coastguard Worker    for root in roots:
416*924841ffSAndroid Build Coastguard Worker      if path.startswith(root + "/"):
417*924841ffSAndroid Build Coastguard Worker        res[root].append(path[len(root) + 1:])
418*924841ffSAndroid Build Coastguard Worker        found = True
419*924841ffSAndroid Build Coastguard Worker        break
420*924841ffSAndroid Build Coastguard Worker    if not found:
421*924841ffSAndroid Build Coastguard Worker      sys.exit("Install path {} is not in any of the git roots: {}"
422*924841ffSAndroid Build Coastguard Worker               .format(path, " ".join(roots)))
423*924841ffSAndroid Build Coastguard Worker  return res
424*924841ffSAndroid Build Coastguard Worker
425*924841ffSAndroid Build Coastguard Worker
426*924841ffSAndroid Build Coastguard Workerdef get_args():
427*924841ffSAndroid Build Coastguard Worker  need_aosp_main_throttled = any(
428*924841ffSAndroid Build Coastguard Worker      source is not None and source.branch == "aosp-main-throttled"
429*924841ffSAndroid Build Coastguard Worker      for source in ([SDK_SOURCE] + list(APEX_SOURCE.values())))
430*924841ffSAndroid Build Coastguard Worker  if need_aosp_main_throttled:
431*924841ffSAndroid Build Coastguard Worker    epilog="Either --aosp-main-build and --aosp-main-throttled-build, or --local-dist, is required."
432*924841ffSAndroid Build Coastguard Worker  else:
433*924841ffSAndroid Build Coastguard Worker    epilog="Either --aosp-main-build or --local-dist is required."
434*924841ffSAndroid Build Coastguard Worker
435*924841ffSAndroid Build Coastguard Worker  """Parses and returns command line arguments."""
436*924841ffSAndroid Build Coastguard Worker  parser = argparse.ArgumentParser(epilog=epilog)
437*924841ffSAndroid Build Coastguard Worker
438*924841ffSAndroid Build Coastguard Worker  parser.add_argument("--aosp-main-build", metavar="NUMBER",
439*924841ffSAndroid Build Coastguard Worker                      help="Build number to fetch from aosp-main")
440*924841ffSAndroid Build Coastguard Worker  parser.add_argument("--aosp-main-throttled-build", metavar="NUMBER",
441*924841ffSAndroid Build Coastguard Worker                      help="Build number to fetch from aosp-main-throttled")
442*924841ffSAndroid Build Coastguard Worker  parser.add_argument("--local-dist", metavar="PATH",
443*924841ffSAndroid Build Coastguard Worker                      help="Take prebuilts from this local dist dir instead of "
444*924841ffSAndroid Build Coastguard Worker                      "using fetch_artifact")
445*924841ffSAndroid Build Coastguard Worker  parser.add_argument("--local-dist-riscv64", metavar="PATH",
446*924841ffSAndroid Build Coastguard Worker                      help="Copy riscv64 prebuilts from a local path, which "
447*924841ffSAndroid Build Coastguard Worker                      "must be $HOME/<path-to-aosp-root>/out/dist with prebuilts "
448*924841ffSAndroid Build Coastguard Worker                      "already built for aosp_riscv64-trunk_staging-userdebug "
449*924841ffSAndroid Build Coastguard Worker                      "target as described in README_riscv64.md. Only "
450*924841ffSAndroid Build Coastguard Worker                      "riscv64-specific files and Android.bp are updated.")
451*924841ffSAndroid Build Coastguard Worker  parser.add_argument("--skip-apex", default=True,
452*924841ffSAndroid Build Coastguard Worker                      action=argparse.BooleanOptionalAction,
453*924841ffSAndroid Build Coastguard Worker                      help="Do not fetch .apex files.")
454*924841ffSAndroid Build Coastguard Worker  parser.add_argument("--skip-module-sdk", action="store_true",
455*924841ffSAndroid Build Coastguard Worker                      help="Do not fetch and unpack sdk and module_export zips.")
456*924841ffSAndroid Build Coastguard Worker  parser.add_argument("--skip-cls", action="store_true",
457*924841ffSAndroid Build Coastguard Worker                      help="Do not create branches or git commits")
458*924841ffSAndroid Build Coastguard Worker  parser.add_argument("--bug", metavar="NUMBER",
459*924841ffSAndroid Build Coastguard Worker                      help="Add a 'Bug' line with this number to commit "
460*924841ffSAndroid Build Coastguard Worker                      "messages.")
461*924841ffSAndroid Build Coastguard Worker  parser.add_argument("--upload", action="store_true",
462*924841ffSAndroid Build Coastguard Worker                      help="Upload the CLs to Gerrit")
463*924841ffSAndroid Build Coastguard Worker  parser.add_argument("--tmp-dir", metavar="PATH",
464*924841ffSAndroid Build Coastguard Worker                      help="Temporary directory for downloads. The default is "
465*924841ffSAndroid Build Coastguard Worker                      "to create one and delete it when finished, but this one "
466*924841ffSAndroid Build Coastguard Worker                      "will be kept, and any files already in it won't be "
467*924841ffSAndroid Build Coastguard Worker                      "downloaded again.")
468*924841ffSAndroid Build Coastguard Worker
469*924841ffSAndroid Build Coastguard Worker  args = parser.parse_args()
470*924841ffSAndroid Build Coastguard Worker
471*924841ffSAndroid Build Coastguard Worker  if args.local_dist_riscv64:
472*924841ffSAndroid Build Coastguard Worker    global ARCHES
473*924841ffSAndroid Build Coastguard Worker    ARCHES = ["riscv64"]
474*924841ffSAndroid Build Coastguard Worker    args.local_dist = args.local_dist_riscv64
475*924841ffSAndroid Build Coastguard Worker
476*924841ffSAndroid Build Coastguard Worker  got_build_numbers = bool(args.aosp_main_build and
477*924841ffSAndroid Build Coastguard Worker                           (args.aosp_main_throttled_build or not need_aosp_main_throttled))
478*924841ffSAndroid Build Coastguard Worker  if ((not got_build_numbers and not args.local_dist) or
479*924841ffSAndroid Build Coastguard Worker      (got_build_numbers and args.local_dist)):
480*924841ffSAndroid Build Coastguard Worker    sys.exit(parser.format_help())
481*924841ffSAndroid Build Coastguard Worker
482*924841ffSAndroid Build Coastguard Worker  return args
483*924841ffSAndroid Build Coastguard Worker
484*924841ffSAndroid Build Coastguard Worker
485*924841ffSAndroid Build Coastguard Workerdef main():
486*924841ffSAndroid Build Coastguard Worker  """Program entry point."""
487*924841ffSAndroid Build Coastguard Worker  args = get_args()
488*924841ffSAndroid Build Coastguard Worker
489*924841ffSAndroid Build Coastguard Worker  if any(path for path in GIT_PROJECT_ROOTS if not os.path.exists(path)):
490*924841ffSAndroid Build Coastguard Worker    sys.exit("This script must be run in the root of the Android build tree.")
491*924841ffSAndroid Build Coastguard Worker
492*924841ffSAndroid Build Coastguard Worker  build_numbers = None
493*924841ffSAndroid Build Coastguard Worker  if args.aosp_main_build:
494*924841ffSAndroid Build Coastguard Worker    build_numbers = {
495*924841ffSAndroid Build Coastguard Worker        "aosp-main": args.aosp_main_build,
496*924841ffSAndroid Build Coastguard Worker        "aosp-main-throttled": args.aosp_main_throttled_build,
497*924841ffSAndroid Build Coastguard Worker    }
498*924841ffSAndroid Build Coastguard Worker
499*924841ffSAndroid Build Coastguard Worker  entries = install_entries()
500*924841ffSAndroid Build Coastguard Worker
501*924841ffSAndroid Build Coastguard Worker  if args.skip_apex:
502*924841ffSAndroid Build Coastguard Worker    entries = [entry for entry in entries if entry.type != "apex"]
503*924841ffSAndroid Build Coastguard Worker  if args.skip_module_sdk:
504*924841ffSAndroid Build Coastguard Worker    entries = [entry for entry in entries if entry.type != "module_sdk"]
505*924841ffSAndroid Build Coastguard Worker  if not entries:
506*924841ffSAndroid Build Coastguard Worker    sys.exit("All prebuilts skipped - nothing to do.")
507*924841ffSAndroid Build Coastguard Worker
508*924841ffSAndroid Build Coastguard Worker  install_paths = [entry.install_path for entry in entries]
509*924841ffSAndroid Build Coastguard Worker  install_paths_per_root = install_paths_per_git_root(
510*924841ffSAndroid Build Coastguard Worker      GIT_PROJECT_ROOTS, install_paths)
511*924841ffSAndroid Build Coastguard Worker
512*924841ffSAndroid Build Coastguard Worker  git_branch_name = PREBUILT_DESCR.lower().replace(" ", "-") + "-update"
513*924841ffSAndroid Build Coastguard Worker  if args.aosp_main_build:
514*924841ffSAndroid Build Coastguard Worker    git_branch_name += "-" + args.aosp_main_build
515*924841ffSAndroid Build Coastguard Worker
516*924841ffSAndroid Build Coastguard Worker  if not args.skip_cls:
517*924841ffSAndroid Build Coastguard Worker    git_paths = list(install_paths_per_root.keys())
518*924841ffSAndroid Build Coastguard Worker    start_branch(git_branch_name, git_paths)
519*924841ffSAndroid Build Coastguard Worker
520*924841ffSAndroid Build Coastguard Worker  if not args.local_dist_riscv64:
521*924841ffSAndroid Build Coastguard Worker    for git_root, subpaths in install_paths_per_root.items():
522*924841ffSAndroid Build Coastguard Worker      remove_files(git_root, subpaths, not args.skip_cls)
523*924841ffSAndroid Build Coastguard Worker
524*924841ffSAndroid Build Coastguard Worker  all_installed_sources = {}
525*924841ffSAndroid Build Coastguard Worker
526*924841ffSAndroid Build Coastguard Worker  tmp_dir_obj = None
527*924841ffSAndroid Build Coastguard Worker  tmp_dir = args.tmp_dir
528*924841ffSAndroid Build Coastguard Worker  if not args.tmp_dir:
529*924841ffSAndroid Build Coastguard Worker    tmp_dir_obj = tempfile.TemporaryDirectory()
530*924841ffSAndroid Build Coastguard Worker    tmp_dir = tmp_dir_obj.name
531*924841ffSAndroid Build Coastguard Worker  tmp_dir = os.path.abspath(tmp_dir)
532*924841ffSAndroid Build Coastguard Worker  try:
533*924841ffSAndroid Build Coastguard Worker    for entry in entries:
534*924841ffSAndroid Build Coastguard Worker      installed_source = install_entry(
535*924841ffSAndroid Build Coastguard Worker          tmp_dir, args.local_dist, build_numbers, entry)
536*924841ffSAndroid Build Coastguard Worker      if installed_source:
537*924841ffSAndroid Build Coastguard Worker        all_installed_sources[entry.install_path] = installed_source
538*924841ffSAndroid Build Coastguard Worker  finally:
539*924841ffSAndroid Build Coastguard Worker    if tmp_dir_obj:
540*924841ffSAndroid Build Coastguard Worker      tmp_dir_obj.cleanup()
541*924841ffSAndroid Build Coastguard Worker
542*924841ffSAndroid Build Coastguard Worker  if not args.skip_cls:
543*924841ffSAndroid Build Coastguard Worker    for git_root, subpaths in install_paths_per_root.items():
544*924841ffSAndroid Build Coastguard Worker      installed_sources = set(src for path, src in all_installed_sources.items()
545*924841ffSAndroid Build Coastguard Worker                              if path.startswith(git_root + "/"))
546*924841ffSAndroid Build Coastguard Worker      commit(git_root, PREBUILT_DESCR, sorted(list(installed_sources)),
547*924841ffSAndroid Build Coastguard Worker             subpaths, args.bug)
548*924841ffSAndroid Build Coastguard Worker
549*924841ffSAndroid Build Coastguard Worker    if args.upload:
550*924841ffSAndroid Build Coastguard Worker      # Don't upload all projects in a single repo upload call, because that
551*924841ffSAndroid Build Coastguard Worker      # makes it pop up an interactive editor.
552*924841ffSAndroid Build Coastguard Worker      for git_root in install_paths_per_root:
553*924841ffSAndroid Build Coastguard Worker        upload_branch(git_root, git_branch_name)
554*924841ffSAndroid Build Coastguard Worker
555*924841ffSAndroid Build Coastguard Worker
556*924841ffSAndroid Build Coastguard Workerif __name__ == "__main__":
557*924841ffSAndroid Build Coastguard Worker  main()
558