blob: a377f0690b72629abe4cc5d8910d43f5ab3a2a70 [file] [log] [blame]
Mike Frysingerf1ba7ad2022-09-12 05:42:57 -04001# Copyright 2016 The ChromiumOS Authors
David Rileyc0da9d92016-02-01 12:11:01 -08002# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
Shao-Chuan Lee717c7f82023-01-19 15:39:50 +09005"""This script performs an Android uprev.
David Rileyc0da9d92016-02-01 12:11:01 -08006
Shao-Chuan Lee84bf9a22021-11-19 17:42:11 +09007After calling, it prints out a JSON representing the result, with the new
8Android version atom string included. A caller could then use this atom with
9emerge to build the newly uprevved version of Android e.g.
David Rileyc0da9d92016-02-01 12:11:01 -080010
Shuhei Takahashi6d02c192017-04-05 14:01:24 +090011./cros_mark_android_as_stable \
Shao-Chuan Lee7e507e62022-11-15 02:17:34 +000012 --android_build_branch=git_pi-arc \
Shao-Chuan Lee9c39e0c2020-04-24 11:40:34 +090013 --android_package=android-container-pi
Shuhei Takahashi6d02c192017-04-05 14:01:24 +090014
Shao-Chuan Lee84bf9a22021-11-19 17:42:11 +090015Returns {"android_atom": "chromeos-base/android-container-pi-6417892-r1"}
David Rileyc0da9d92016-02-01 12:11:01 -080016
Shao-Chuan Lee9c39e0c2020-04-24 11:40:34 +090017emerge-eve =chromeos-base/android-container-pi-6417892-r1
David Rileyc0da9d92016-02-01 12:11:01 -080018"""
19
David Rileyc0da9d92016-02-01 12:11:01 -080020import filecmp
21import glob
Junichi Uekawad21f94d2020-07-27 15:50:05 +090022import json
Chris McDonaldb55b7032021-06-17 16:41:32 -060023import logging
David Rileyc0da9d92016-02-01 12:11:01 -080024import os
25
David Rileyc0da9d92016-02-01 12:11:01 -080026from chromite.lib import commandline
Chris McDonaldb55b7032021-06-17 16:41:32 -060027from chromite.lib import constants
David Rileyc0da9d92016-02-01 12:11:01 -080028from chromite.lib import cros_build_lib
David Rileyc0da9d92016-02-01 12:11:01 -080029from chromite.lib import git
Shao-Chuan Lee301a4192021-02-08 11:53:49 +090030from chromite.lib import osutils
David Rileyc0da9d92016-02-01 12:11:01 -080031from chromite.lib import portage_util
Shao-Chuan Lee007dbe82021-02-09 14:05:39 +090032from chromite.lib import repo_util
David Rileyc0da9d92016-02-01 12:11:01 -080033from chromite.scripts import cros_mark_as_stable
Shao-Chuan Lee7fd0ca12021-03-19 15:57:40 +090034from chromite.service import android
Yury Khmelc0a18442022-11-01 16:56:22 -070035from chromite.service import packages
David Rileyc0da9d92016-02-01 12:11:01 -080036
37
38# Dir where all the action happens.
Alex Klein1699fab2022-09-08 08:46:06 -060039_OVERLAY_DIR = "%(srcroot)s/private-overlays/project-cheets-private/"
David Rileyc0da9d92016-02-01 12:11:01 -080040
Junichi Uekawa6d61ab02020-04-15 14:52:28 +090041_GIT_COMMIT_MESSAGE = """Marking latest for %(android_package)s ebuild with \
42version %(android_version)s as stable.
43
44BUG=None
45TEST=CQ
46"""
David Rileyc0da9d92016-02-01 12:11:01 -080047
Alex Klein1699fab2022-09-08 08:46:06 -060048_RUNTIME_ARTIFACTS_BUCKET_URL = "gs://chromeos-arc-images/runtime_artifacts"
David Rileyc0da9d92016-02-01 12:11:01 -080049
David Rileyc0da9d92016-02-01 12:11:01 -080050
51def FindAndroidCandidates(package_dir):
Alex Klein1699fab2022-09-08 08:46:06 -060052 """Return a tuple of Android's unstable ebuild and stable ebuilds.
David Rileyc0da9d92016-02-01 12:11:01 -080053
Alex Klein1699fab2022-09-08 08:46:06 -060054 Args:
Alex Kleind7197402023-04-05 13:05:29 -060055 package_dir: The path to where the package ebuild is stored.
David Rileyc0da9d92016-02-01 12:11:01 -080056
Alex Klein1699fab2022-09-08 08:46:06 -060057 Returns:
Alex Kleind7197402023-04-05 13:05:29 -060058 Tuple [unstable_ebuild, stable_ebuilds].
David Rileyc0da9d92016-02-01 12:11:01 -080059
Alex Klein1699fab2022-09-08 08:46:06 -060060 Raises:
Alex Kleind7197402023-04-05 13:05:29 -060061 Exception: if no unstable ebuild exists for Android.
Alex Klein1699fab2022-09-08 08:46:06 -060062 """
63 stable_ebuilds = []
64 unstable_ebuilds = []
65 for path in glob.glob(os.path.join(package_dir, "*.ebuild")):
66 ebuild = portage_util.EBuild(path)
67 if ebuild.version == "9999":
68 unstable_ebuilds.append(ebuild)
69 else:
70 stable_ebuilds.append(ebuild)
David Rileyc0da9d92016-02-01 12:11:01 -080071
Alex Klein1699fab2022-09-08 08:46:06 -060072 # Apply some confidence checks.
73 if not unstable_ebuilds:
74 raise Exception("Missing 9999 ebuild for %s" % package_dir)
75 if not stable_ebuilds:
76 logging.warning("Missing stable ebuild for %s", package_dir)
David Rileyc0da9d92016-02-01 12:11:01 -080077
Alex Klein1699fab2022-09-08 08:46:06 -060078 return portage_util.BestEBuild(unstable_ebuilds), stable_ebuilds
David Rileyc0da9d92016-02-01 12:11:01 -080079
80
Alex Klein1699fab2022-09-08 08:46:06 -060081def UpdateDataCollectorArtifacts(
Yury Khmelc0a18442022-11-01 16:56:22 -070082 android_version, runtime_artifacts_bucket_url, package_name
Alex Klein1699fab2022-09-08 08:46:06 -060083):
84 r"""Finds and includes into variables artifacts from arc.DataCollector.
85
Alex Kleind7197402023-04-05 13:05:29 -060086 This verifies default android version. In case artifacts are not found for
Alex Klein1699fab2022-09-08 08:46:06 -060087 default Android version it tries to find artifacts for pinned version. If
88 pinned version is provided, it is required artifacts exist for the pinned
89 version.
90
91 Args:
Alex Kleind7197402023-04-05 13:05:29 -060092 android_version: The \d+ build id of Android.
93 runtime_artifacts_bucket_url: root of runtime artifacts
94 package_name: android package name. Used to determine the pinned version
95 if exists.
Alex Klein1699fab2022-09-08 08:46:06 -060096
97 Returns:
Alex Kleind7197402023-04-05 13:05:29 -060098 dictionary with filled ebuild variables.
Alex Klein1699fab2022-09-08 08:46:06 -060099 """
Alex Klein1699fab2022-09-08 08:46:06 -0600100 # Check the existing version. If we find any artifacts, use them.
Shao-Chuan Leefd5df6f2023-01-20 12:05:28 +0900101 variables = android.FindDataCollectorArtifacts(
Yury Khmelc0a18442022-11-01 16:56:22 -0700102 package_name,
Shao-Chuan Leefd5df6f2023-01-20 12:05:28 +0900103 android_version,
Yury Khmelc0a18442022-11-01 16:56:22 -0700104 "${PV}",
Shao-Chuan Leefd5df6f2023-01-20 12:05:28 +0900105 runtime_artifacts_bucket_url,
Alex Klein1699fab2022-09-08 08:46:06 -0600106 )
107 if variables:
Alex Kleind7197402023-04-05 13:05:29 -0600108 # Data artifacts were found.
Alex Klein1699fab2022-09-08 08:46:06 -0600109 return variables
110
111 # Check pinned version for the current branch.
Yury Khmelc0a18442022-11-01 16:56:22 -0700112 milestone = packages.determine_milestone_version()
Shao-Chuan Leefd5df6f2023-01-20 12:05:28 +0900113 pin_version = android.FindRuntimeArtifactsPin(
114 package_name,
115 milestone,
116 runtime_artifacts_bucket_url,
117 )
118 if pin_version is None:
Alex Klein1699fab2022-09-08 08:46:06 -0600119 # No pinned version.
120 logging.warning(
121 "No data collector artifacts were found for %s", android_version
122 )
123 return variables
124
Alex Klein1699fab2022-09-08 08:46:06 -0600125 logging.info("Pinned version %s overrides %s", pin_version, android_version)
Shao-Chuan Leefd5df6f2023-01-20 12:05:28 +0900126 variables = android.FindDataCollectorArtifacts(
Yury Khmelc0a18442022-11-01 16:56:22 -0700127 package_name,
Yury Khmelc0a18442022-11-01 16:56:22 -0700128 pin_version,
Shao-Chuan Leefd5df6f2023-01-20 12:05:28 +0900129 pin_version,
130 runtime_artifacts_bucket_url,
Alex Klein1699fab2022-09-08 08:46:06 -0600131 )
132 if not variables:
133 # If pin version set it must contain data.
134 raise Exception(
Shao-Chuan Leefd5df6f2023-01-20 12:05:28 +0900135 f"Pinned version {pin_version} does not contain artifacts"
Alex Klein1699fab2022-09-08 08:46:06 -0600136 )
Alex Klein1699fab2022-09-08 08:46:06 -0600137 return variables
138
139
140def MarkAndroidEBuildAsStable(
141 stable_candidate,
142 unstable_ebuild,
143 android_package,
144 android_version,
145 package_dir,
Shao-Chuan Lee7e507e62022-11-15 02:17:34 +0000146 build_branch,
Alex Klein1699fab2022-09-08 08:46:06 -0600147 arc_bucket_url,
148 runtime_artifacts_bucket_url,
149):
150 r"""Uprevs the Android ebuild.
151
152 This is the main function that uprevs from a stable candidate
153 to its new version.
154
155 Args:
Alex Kleind7197402023-04-05 13:05:29 -0600156 stable_candidate: ebuild that corresponds to the stable ebuild we are
157 revving from. If None, builds the new ebuild given the version with
158 revision set to 1.
159 unstable_ebuild: ebuild corresponding to the unstable ebuild for
160 Android.
161 android_package: android package name.
162 android_version: The \d+ build id of Android.
163 package_dir: Path to the android-container package dir.
164 build_branch: branch of Android builds.
165 arc_bucket_url: URL of the target ARC build gs bucket.
166 runtime_artifacts_bucket_url: root of runtime artifacts
Alex Klein1699fab2022-09-08 08:46:06 -0600167
168 Returns:
Alex Kleind7197402023-04-05 13:05:29 -0600169 Tuple[str, List[str], List[str]] if revved, or None
170 1. Full portage version atom (including rc's, etc.) that was revved.
171 2. List of files to be `git add`ed.
172 3. List of files to be `git rm`ed.
Alex Klein1699fab2022-09-08 08:46:06 -0600173 """
174
175 def IsTheNewEBuildRedundant(new_ebuild, stable_ebuild):
176 """Returns True if the new ebuild is redundant.
177
Alex Kleind7197402023-04-05 13:05:29 -0600178 This is True if the current stable ebuild is the exact same copy
Alex Klein1699fab2022-09-08 08:46:06 -0600179 of the new one.
180 """
181 if not stable_ebuild:
182 return False
183
184 if stable_candidate.version_no_rev == new_ebuild.version_no_rev:
185 return filecmp.cmp(
186 new_ebuild.ebuild_path, stable_ebuild.ebuild_path, shallow=False
187 )
188 return False
189
190 # Case where we have the last stable candidate with same version just rev.
191 if stable_candidate and stable_candidate.version_no_rev == android_version:
192 new_ebuild_path = "%s-r%d.ebuild" % (
193 stable_candidate.ebuild_path_no_revision,
194 stable_candidate.current_revision + 1,
195 )
196 else:
197 pf = "%s-%s-r1" % (android_package, android_version)
198 new_ebuild_path = os.path.join(package_dir, "%s.ebuild" % pf)
199
Shao-Chuan Leeca2cbcc2022-11-02 08:28:31 +0900200 build_targets = android.GetAndroidEbuildTargetsForPackage(android_package)
Alex Klein1699fab2022-09-08 08:46:06 -0600201 variables = {"BASE_URL": arc_bucket_url}
202 for var, target in build_targets.items():
Shao-Chuan Lee20c51d82022-10-26 21:56:56 +0900203 # TODO(b/255705023): Have MirrorArtifacts generate the mapping for us.
Alex Klein1699fab2022-09-08 08:46:06 -0600204 variables[var] = f"{build_branch}-linux-{target}"
205
206 variables.update(
207 UpdateDataCollectorArtifacts(
Yury Khmelc0a18442022-11-01 16:56:22 -0700208 android_version,
209 runtime_artifacts_bucket_url,
210 android_package,
Alex Klein1699fab2022-09-08 08:46:06 -0600211 )
212 )
213
214 portage_util.EBuild.MarkAsStable(
215 unstable_ebuild.ebuild_path,
216 new_ebuild_path,
217 variables,
218 make_stable=True,
219 )
220 new_ebuild = portage_util.EBuild(new_ebuild_path)
221
222 # Determine whether this is ebuild is redundant.
223 if IsTheNewEBuildRedundant(new_ebuild, stable_candidate):
224 msg = "Previous ebuild with same version found and ebuild is redundant."
225 logging.info(msg)
Alex Klein1699fab2022-09-08 08:46:06 -0600226 osutils.SafeUnlink(new_ebuild_path)
227 return None
228
Alex Klein1699fab2022-09-08 08:46:06 -0600229 files_to_add = [new_ebuild_path]
230 files_to_remove = []
231 if stable_candidate and not stable_candidate.IsSticky():
232 osutils.SafeUnlink(stable_candidate.ebuild_path)
233 files_to_remove.append(stable_candidate.ebuild_path)
234
235 # Update ebuild manifest and git add it.
236 gen_manifest_cmd = ["ebuild", new_ebuild_path, "manifest", "--force"]
237 cros_build_lib.run(gen_manifest_cmd, extra_env=None, print_cmd=True)
238 files_to_add.append(os.path.join(package_dir, "Manifest"))
239
240 return (
241 f"{new_ebuild.package}-{new_ebuild.version}",
242 files_to_add,
243 files_to_remove,
244 )
David Rileyc0da9d92016-02-01 12:11:01 -0800245
Shao-Chuan Lee301a4192021-02-08 11:53:49 +0900246
Shao-Chuan Lee007dbe82021-02-09 14:05:39 +0900247def _PrepareGitBranch(overlay_dir):
Alex Klein1699fab2022-09-08 08:46:06 -0600248 """Prepares a git branch for the uprev commit.
Shao-Chuan Lee301a4192021-02-08 11:53:49 +0900249
Alex Klein1699fab2022-09-08 08:46:06 -0600250 If the overlay project is currently on a branch (e.g. patches are being
251 applied), rebase the new branch on top of it.
Shao-Chuan Lee007dbe82021-02-09 14:05:39 +0900252
Alex Klein1699fab2022-09-08 08:46:06 -0600253 Args:
Alex Kleind7197402023-04-05 13:05:29 -0600254 overlay_dir: The overlay directory.
Alex Klein1699fab2022-09-08 08:46:06 -0600255 """
256 existing_branch = git.GetCurrentBranch(overlay_dir)
257 repo_util.Repository.MustFind(overlay_dir).StartBranch(
258 constants.STABLE_EBUILD_BRANCH, projects=["."], cwd=overlay_dir
259 )
260 if existing_branch:
261 git.RunGit(overlay_dir, ["rebase", existing_branch])
Shao-Chuan Lee301a4192021-02-08 11:53:49 +0900262
263
264def _CommitChange(message, android_package_dir, files_to_add, files_to_remove):
Alex Klein1699fab2022-09-08 08:46:06 -0600265 """Commit changes to git with list of files to add/remove."""
266 git.RunGit(android_package_dir, ["add", "--"] + files_to_add)
267 if files_to_remove:
268 git.RunGit(android_package_dir, ["rm", "--"] + files_to_remove)
Shao-Chuan Lee301a4192021-02-08 11:53:49 +0900269
Alex Klein1699fab2022-09-08 08:46:06 -0600270 portage_util.EBuild.CommitChange(message, android_package_dir)
David Rileyc0da9d92016-02-01 12:11:01 -0800271
272
273def GetParser():
Alex Klein1699fab2022-09-08 08:46:06 -0600274 """Creates the argument parser."""
275 parser = commandline.ArgumentParser()
276 parser.add_argument("-b", "--boards")
277 parser.add_argument(
278 "--android_bucket_url",
279 default=android.ANDROID_BUCKET_URL,
280 type="gs_path",
281 )
282 parser.add_argument(
283 "--android_build_branch",
Shao-Chuan Lee7e507e62022-11-15 02:17:34 +0000284 help="Android branch to import from, overriding default",
Alex Klein1699fab2022-09-08 08:46:06 -0600285 )
286 parser.add_argument(
287 "--android_package",
288 required=True,
Shao-Chuan Leeca2cbcc2022-11-02 08:28:31 +0900289 choices=android.GetAllAndroidPackages(),
Alex Klein1699fab2022-09-08 08:46:06 -0600290 help="Android package to uprev",
291 )
292 parser.add_argument(
293 "--arc_bucket_url", default=constants.ARC_BUCKET_URL, type="gs_path"
294 )
295 parser.add_argument("-f", "--force_version", help="Android build id to use")
296 parser.add_argument(
297 "-s",
298 "--srcroot",
299 default=os.path.join(constants.SOURCE_ROOT, "src"),
300 help="Path to the src directory",
301 )
302 parser.add_argument(
303 "--runtime_artifacts_bucket_url",
304 default=_RUNTIME_ARTIFACTS_BUCKET_URL,
305 type="gs_path",
306 )
307 parser.add_argument(
308 "--skip_commit",
309 action="store_true",
Alex Kleind7197402023-04-05 13:05:29 -0600310 help="Skip committing uprev changes to git",
Alex Klein1699fab2022-09-08 08:46:06 -0600311 )
Alex Klein1699fab2022-09-08 08:46:06 -0600312 return parser
David Rileyc0da9d92016-02-01 12:11:01 -0800313
314
315def main(argv):
Alex Klein1699fab2022-09-08 08:46:06 -0600316 parser = GetParser()
317 options = parser.parse_args(argv)
318 options.Freeze()
David Rileyc0da9d92016-02-01 12:11:01 -0800319
Alex Klein1699fab2022-09-08 08:46:06 -0600320 overlay_dir = os.path.abspath(_OVERLAY_DIR % {"srcroot": options.srcroot})
321 android_package_dir = android.GetAndroidPackageDir(
322 options.android_package, overlay_dir=overlay_dir
323 )
Shao-Chuan Lee3aa76522021-12-03 17:18:58 +0900324
325 if not options.skip_commit:
Alex Klein1699fab2022-09-08 08:46:06 -0600326 _PrepareGitBranch(overlay_dir)
Shao-Chuan Lee3aa76522021-12-03 17:18:58 +0900327
Shao-Chuan Lee7e507e62022-11-15 02:17:34 +0000328 # Use default Android branch if not overridden.
329 android_build_branch = (
Shao-Chuan Lee20c51d82022-10-26 21:56:56 +0900330 options.android_build_branch
Shao-Chuan Lee7e507e62022-11-15 02:17:34 +0000331 or android.GetAndroidBranchForPackage(options.android_package)
332 )
Shao-Chuan Leedea458f2021-11-25 23:46:53 +0900333
Alex Klein1699fab2022-09-08 08:46:06 -0600334 (unstable_ebuild, stable_ebuilds) = FindAndroidCandidates(
335 android_package_dir
336 )
337 # Mirror artifacts, i.e., images and some sdk tools (e.g., adb, aapt).
338 version_to_uprev = android.MirrorArtifacts(
Shao-Chuan Lee20c51d82022-10-26 21:56:56 +0900339 options.android_package,
Alex Klein1699fab2022-09-08 08:46:06 -0600340 options.android_bucket_url,
Shao-Chuan Lee7e507e62022-11-15 02:17:34 +0000341 android_build_branch,
Alex Klein1699fab2022-09-08 08:46:06 -0600342 options.arc_bucket_url,
343 android_package_dir,
344 options.force_version,
345 )
David Rileyc0da9d92016-02-01 12:11:01 -0800346
Alex Klein1699fab2022-09-08 08:46:06 -0600347 stable_candidate = portage_util.BestEBuild(stable_ebuilds)
Shao-Chuan Leedea458f2021-11-25 23:46:53 +0900348
Alex Klein1699fab2022-09-08 08:46:06 -0600349 if stable_candidate:
350 logging.info("Stable candidate found %s", stable_candidate.version)
351 else:
352 logging.info("No stable candidate found.")
353
354 revved = MarkAndroidEBuildAsStable(
355 stable_candidate,
356 unstable_ebuild,
357 options.android_package,
358 version_to_uprev,
359 android_package_dir,
Shao-Chuan Lee7e507e62022-11-15 02:17:34 +0000360 android_build_branch,
Alex Klein1699fab2022-09-08 08:46:06 -0600361 options.arc_bucket_url,
362 options.runtime_artifacts_bucket_url,
363 )
364
365 output = dict(revved=bool(revved))
366
367 if revved:
368 android_atom, files_to_add, files_to_remove = revved
369 if not options.skip_commit:
370 _CommitChange(
371 _GIT_COMMIT_MESSAGE
372 % {
373 "android_package": options.android_package,
374 "android_version": version_to_uprev,
375 },
376 android_package_dir,
377 files_to_add,
378 files_to_remove,
379 )
380 if options.boards:
381 cros_mark_as_stable.CleanStalePackages(
382 options.srcroot, options.boards.split(":"), [android_atom]
383 )
384
385 output["android_atom"] = android_atom
Alex Kleind7197402023-04-05 13:05:29 -0600386 # This field is read by the PUpr uprev handler for creating CLs. We
387 # cannot return absolute paths because this script runs inside chroot
388 # but the uprev handler runs outside.
Alex Klein1699fab2022-09-08 08:46:06 -0600389 # Here we return paths relative to |overlay_dir|.
390 output["modified_files"] = [
391 os.path.relpath(f, overlay_dir)
392 for f in files_to_add + files_to_remove
393 ]
394
395 # The output is being parsed by service.packages.uprev_android and has to be
396 # in its own single line. When invoked from chromite API endpoints, entering
Alex Kleind7197402023-04-05 13:05:29 -0600397 # chroot can generate junk messages on stdout, so we prefix our output with
398 # a line break to further ensure that.
Alex Klein1699fab2022-09-08 08:46:06 -0600399 print("\n" + json.dumps(output, sort_keys=True))