blob: e727d53092f7b6cc039eb3a0e577f11f84d3ef2e [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
Shao-Chuan Lee5d86b6e2023-09-06 11:07:33 +090048# The bucket where we save Android artifacts indefinitely, to ensure any old
49# Android versions in the commit history can be built.
50_ARC_BUCKET_URL = "gs://chromeos-arc-images/builds"
51
52# The bucket hosting runtime artifacts generated by arc.DataCollector.
Alex Klein1699fab2022-09-08 08:46:06 -060053_RUNTIME_ARTIFACTS_BUCKET_URL = "gs://chromeos-arc-images/runtime_artifacts"
David Rileyc0da9d92016-02-01 12:11:01 -080054
David Rileyc0da9d92016-02-01 12:11:01 -080055
56def FindAndroidCandidates(package_dir):
Alex Klein1699fab2022-09-08 08:46:06 -060057 """Return a tuple of Android's unstable ebuild and stable ebuilds.
David Rileyc0da9d92016-02-01 12:11:01 -080058
Alex Klein1699fab2022-09-08 08:46:06 -060059 Args:
Alex Kleind7197402023-04-05 13:05:29 -060060 package_dir: The path to where the package ebuild is stored.
David Rileyc0da9d92016-02-01 12:11:01 -080061
Alex Klein1699fab2022-09-08 08:46:06 -060062 Returns:
Alex Kleind7197402023-04-05 13:05:29 -060063 Tuple [unstable_ebuild, stable_ebuilds].
David Rileyc0da9d92016-02-01 12:11:01 -080064
Alex Klein1699fab2022-09-08 08:46:06 -060065 Raises:
Alex Kleind7197402023-04-05 13:05:29 -060066 Exception: if no unstable ebuild exists for Android.
Alex Klein1699fab2022-09-08 08:46:06 -060067 """
68 stable_ebuilds = []
69 unstable_ebuilds = []
70 for path in glob.glob(os.path.join(package_dir, "*.ebuild")):
71 ebuild = portage_util.EBuild(path)
72 if ebuild.version == "9999":
73 unstable_ebuilds.append(ebuild)
74 else:
75 stable_ebuilds.append(ebuild)
David Rileyc0da9d92016-02-01 12:11:01 -080076
Alex Klein1699fab2022-09-08 08:46:06 -060077 # Apply some confidence checks.
78 if not unstable_ebuilds:
79 raise Exception("Missing 9999 ebuild for %s" % package_dir)
80 if not stable_ebuilds:
81 logging.warning("Missing stable ebuild for %s", package_dir)
David Rileyc0da9d92016-02-01 12:11:01 -080082
Alex Klein1699fab2022-09-08 08:46:06 -060083 return portage_util.BestEBuild(unstable_ebuilds), stable_ebuilds
David Rileyc0da9d92016-02-01 12:11:01 -080084
85
Alex Klein1699fab2022-09-08 08:46:06 -060086def UpdateDataCollectorArtifacts(
Yury Khmelc0a18442022-11-01 16:56:22 -070087 android_version, runtime_artifacts_bucket_url, package_name
Alex Klein1699fab2022-09-08 08:46:06 -060088):
89 r"""Finds and includes into variables artifacts from arc.DataCollector.
90
Alex Kleind7197402023-04-05 13:05:29 -060091 This verifies default android version. In case artifacts are not found for
Alex Klein1699fab2022-09-08 08:46:06 -060092 default Android version it tries to find artifacts for pinned version. If
93 pinned version is provided, it is required artifacts exist for the pinned
94 version.
95
96 Args:
Alex Kleind7197402023-04-05 13:05:29 -060097 android_version: The \d+ build id of Android.
98 runtime_artifacts_bucket_url: root of runtime artifacts
99 package_name: android package name. Used to determine the pinned version
100 if exists.
Alex Klein1699fab2022-09-08 08:46:06 -0600101
102 Returns:
Alex Kleind7197402023-04-05 13:05:29 -0600103 dictionary with filled ebuild variables.
Alex Klein1699fab2022-09-08 08:46:06 -0600104 """
Alex Klein1699fab2022-09-08 08:46:06 -0600105 # Check the existing version. If we find any artifacts, use them.
Shao-Chuan Leefd5df6f2023-01-20 12:05:28 +0900106 variables = android.FindDataCollectorArtifacts(
Yury Khmelc0a18442022-11-01 16:56:22 -0700107 package_name,
Shao-Chuan Leefd5df6f2023-01-20 12:05:28 +0900108 android_version,
Yury Khmelc0a18442022-11-01 16:56:22 -0700109 "${PV}",
Shao-Chuan Leefd5df6f2023-01-20 12:05:28 +0900110 runtime_artifacts_bucket_url,
Alex Klein1699fab2022-09-08 08:46:06 -0600111 )
112 if variables:
Alex Kleind7197402023-04-05 13:05:29 -0600113 # Data artifacts were found.
Alex Klein1699fab2022-09-08 08:46:06 -0600114 return variables
115
116 # Check pinned version for the current branch.
Yury Khmelc0a18442022-11-01 16:56:22 -0700117 milestone = packages.determine_milestone_version()
Shao-Chuan Leefd5df6f2023-01-20 12:05:28 +0900118 pin_version = android.FindRuntimeArtifactsPin(
119 package_name,
120 milestone,
121 runtime_artifacts_bucket_url,
122 )
123 if pin_version is None:
Alex Klein1699fab2022-09-08 08:46:06 -0600124 # No pinned version.
125 logging.warning(
126 "No data collector artifacts were found for %s", android_version
127 )
128 return variables
129
Alex Klein1699fab2022-09-08 08:46:06 -0600130 logging.info("Pinned version %s overrides %s", pin_version, android_version)
Shao-Chuan Leefd5df6f2023-01-20 12:05:28 +0900131 variables = android.FindDataCollectorArtifacts(
Yury Khmelc0a18442022-11-01 16:56:22 -0700132 package_name,
Yury Khmelc0a18442022-11-01 16:56:22 -0700133 pin_version,
Shao-Chuan Leefd5df6f2023-01-20 12:05:28 +0900134 pin_version,
135 runtime_artifacts_bucket_url,
Alex Klein1699fab2022-09-08 08:46:06 -0600136 )
137 if not variables:
138 # If pin version set it must contain data.
139 raise Exception(
Shao-Chuan Leefd5df6f2023-01-20 12:05:28 +0900140 f"Pinned version {pin_version} does not contain artifacts"
Alex Klein1699fab2022-09-08 08:46:06 -0600141 )
Alex Klein1699fab2022-09-08 08:46:06 -0600142 return variables
143
144
145def MarkAndroidEBuildAsStable(
146 stable_candidate,
147 unstable_ebuild,
148 android_package,
149 android_version,
150 package_dir,
Shao-Chuan Lee7e507e62022-11-15 02:17:34 +0000151 build_branch,
Alex Klein1699fab2022-09-08 08:46:06 -0600152 arc_bucket_url,
153 runtime_artifacts_bucket_url,
154):
155 r"""Uprevs the Android ebuild.
156
157 This is the main function that uprevs from a stable candidate
158 to its new version.
159
160 Args:
Alex Kleind7197402023-04-05 13:05:29 -0600161 stable_candidate: ebuild that corresponds to the stable ebuild we are
162 revving from. If None, builds the new ebuild given the version with
163 revision set to 1.
164 unstable_ebuild: ebuild corresponding to the unstable ebuild for
165 Android.
166 android_package: android package name.
167 android_version: The \d+ build id of Android.
168 package_dir: Path to the android-container package dir.
169 build_branch: branch of Android builds.
170 arc_bucket_url: URL of the target ARC build gs bucket.
171 runtime_artifacts_bucket_url: root of runtime artifacts
Alex Klein1699fab2022-09-08 08:46:06 -0600172
173 Returns:
Alex Kleind7197402023-04-05 13:05:29 -0600174 Tuple[str, List[str], List[str]] if revved, or None
175 1. Full portage version atom (including rc's, etc.) that was revved.
176 2. List of files to be `git add`ed.
177 3. List of files to be `git rm`ed.
Alex Klein1699fab2022-09-08 08:46:06 -0600178 """
179
180 def IsTheNewEBuildRedundant(new_ebuild, stable_ebuild):
181 """Returns True if the new ebuild is redundant.
182
Alex Kleind7197402023-04-05 13:05:29 -0600183 This is True if the current stable ebuild is the exact same copy
Alex Klein1699fab2022-09-08 08:46:06 -0600184 of the new one.
185 """
186 if not stable_ebuild:
187 return False
188
189 if stable_candidate.version_no_rev == new_ebuild.version_no_rev:
190 return filecmp.cmp(
191 new_ebuild.ebuild_path, stable_ebuild.ebuild_path, shallow=False
192 )
193 return False
194
195 # Case where we have the last stable candidate with same version just rev.
196 if stable_candidate and stable_candidate.version_no_rev == android_version:
197 new_ebuild_path = "%s-r%d.ebuild" % (
198 stable_candidate.ebuild_path_no_revision,
199 stable_candidate.current_revision + 1,
200 )
201 else:
202 pf = "%s-%s-r1" % (android_package, android_version)
203 new_ebuild_path = os.path.join(package_dir, "%s.ebuild" % pf)
204
Shao-Chuan Leeca2cbcc2022-11-02 08:28:31 +0900205 build_targets = android.GetAndroidEbuildTargetsForPackage(android_package)
Alex Klein1699fab2022-09-08 08:46:06 -0600206 variables = {"BASE_URL": arc_bucket_url}
207 for var, target in build_targets.items():
Shao-Chuan Lee20c51d82022-10-26 21:56:56 +0900208 # TODO(b/255705023): Have MirrorArtifacts generate the mapping for us.
Alex Klein1699fab2022-09-08 08:46:06 -0600209 variables[var] = f"{build_branch}-linux-{target}"
210
211 variables.update(
212 UpdateDataCollectorArtifacts(
Yury Khmelc0a18442022-11-01 16:56:22 -0700213 android_version,
214 runtime_artifacts_bucket_url,
215 android_package,
Alex Klein1699fab2022-09-08 08:46:06 -0600216 )
217 )
218
219 portage_util.EBuild.MarkAsStable(
220 unstable_ebuild.ebuild_path,
221 new_ebuild_path,
222 variables,
223 make_stable=True,
224 )
225 new_ebuild = portage_util.EBuild(new_ebuild_path)
226
227 # Determine whether this is ebuild is redundant.
228 if IsTheNewEBuildRedundant(new_ebuild, stable_candidate):
229 msg = "Previous ebuild with same version found and ebuild is redundant."
230 logging.info(msg)
Alex Klein1699fab2022-09-08 08:46:06 -0600231 osutils.SafeUnlink(new_ebuild_path)
232 return None
233
Alex Klein1699fab2022-09-08 08:46:06 -0600234 files_to_add = [new_ebuild_path]
235 files_to_remove = []
236 if stable_candidate and not stable_candidate.IsSticky():
237 osutils.SafeUnlink(stable_candidate.ebuild_path)
238 files_to_remove.append(stable_candidate.ebuild_path)
239
240 # Update ebuild manifest and git add it.
241 gen_manifest_cmd = ["ebuild", new_ebuild_path, "manifest", "--force"]
242 cros_build_lib.run(gen_manifest_cmd, extra_env=None, print_cmd=True)
243 files_to_add.append(os.path.join(package_dir, "Manifest"))
244
245 return (
246 f"{new_ebuild.package}-{new_ebuild.version}",
247 files_to_add,
248 files_to_remove,
249 )
David Rileyc0da9d92016-02-01 12:11:01 -0800250
Shao-Chuan Lee301a4192021-02-08 11:53:49 +0900251
Shao-Chuan Lee007dbe82021-02-09 14:05:39 +0900252def _PrepareGitBranch(overlay_dir):
Alex Klein1699fab2022-09-08 08:46:06 -0600253 """Prepares a git branch for the uprev commit.
Shao-Chuan Lee301a4192021-02-08 11:53:49 +0900254
Alex Klein1699fab2022-09-08 08:46:06 -0600255 If the overlay project is currently on a branch (e.g. patches are being
256 applied), rebase the new branch on top of it.
Shao-Chuan Lee007dbe82021-02-09 14:05:39 +0900257
Alex Klein1699fab2022-09-08 08:46:06 -0600258 Args:
Alex Kleind7197402023-04-05 13:05:29 -0600259 overlay_dir: The overlay directory.
Alex Klein1699fab2022-09-08 08:46:06 -0600260 """
261 existing_branch = git.GetCurrentBranch(overlay_dir)
262 repo_util.Repository.MustFind(overlay_dir).StartBranch(
263 constants.STABLE_EBUILD_BRANCH, projects=["."], cwd=overlay_dir
264 )
265 if existing_branch:
266 git.RunGit(overlay_dir, ["rebase", existing_branch])
Shao-Chuan Lee301a4192021-02-08 11:53:49 +0900267
268
269def _CommitChange(message, android_package_dir, files_to_add, files_to_remove):
Alex Klein1699fab2022-09-08 08:46:06 -0600270 """Commit changes to git with list of files to add/remove."""
271 git.RunGit(android_package_dir, ["add", "--"] + files_to_add)
272 if files_to_remove:
273 git.RunGit(android_package_dir, ["rm", "--"] + files_to_remove)
Shao-Chuan Lee301a4192021-02-08 11:53:49 +0900274
Alex Klein1699fab2022-09-08 08:46:06 -0600275 portage_util.EBuild.CommitChange(message, android_package_dir)
David Rileyc0da9d92016-02-01 12:11:01 -0800276
277
278def GetParser():
Alex Klein1699fab2022-09-08 08:46:06 -0600279 """Creates the argument parser."""
280 parser = commandline.ArgumentParser()
281 parser.add_argument("-b", "--boards")
282 parser.add_argument(
283 "--android_bucket_url",
284 default=android.ANDROID_BUCKET_URL,
285 type="gs_path",
286 )
287 parser.add_argument(
288 "--android_build_branch",
Shao-Chuan Lee7e507e62022-11-15 02:17:34 +0000289 help="Android branch to import from, overriding default",
Alex Klein1699fab2022-09-08 08:46:06 -0600290 )
291 parser.add_argument(
292 "--android_package",
293 required=True,
Shao-Chuan Leeca2cbcc2022-11-02 08:28:31 +0900294 choices=android.GetAllAndroidPackages(),
Alex Klein1699fab2022-09-08 08:46:06 -0600295 help="Android package to uprev",
296 )
297 parser.add_argument(
Shao-Chuan Lee5d86b6e2023-09-06 11:07:33 +0900298 "--arc_bucket_url", default=_ARC_BUCKET_URL, type="gs_path"
Alex Klein1699fab2022-09-08 08:46:06 -0600299 )
300 parser.add_argument("-f", "--force_version", help="Android build id to use")
301 parser.add_argument(
302 "-s",
303 "--srcroot",
304 default=os.path.join(constants.SOURCE_ROOT, "src"),
305 help="Path to the src directory",
306 )
307 parser.add_argument(
308 "--runtime_artifacts_bucket_url",
309 default=_RUNTIME_ARTIFACTS_BUCKET_URL,
310 type="gs_path",
311 )
312 parser.add_argument(
313 "--skip_commit",
314 action="store_true",
Alex Kleind7197402023-04-05 13:05:29 -0600315 help="Skip committing uprev changes to git",
Alex Klein1699fab2022-09-08 08:46:06 -0600316 )
Alex Klein1699fab2022-09-08 08:46:06 -0600317 return parser
David Rileyc0da9d92016-02-01 12:11:01 -0800318
319
320def main(argv):
Alex Klein1699fab2022-09-08 08:46:06 -0600321 parser = GetParser()
322 options = parser.parse_args(argv)
323 options.Freeze()
David Rileyc0da9d92016-02-01 12:11:01 -0800324
Alex Klein1699fab2022-09-08 08:46:06 -0600325 overlay_dir = os.path.abspath(_OVERLAY_DIR % {"srcroot": options.srcroot})
326 android_package_dir = android.GetAndroidPackageDir(
327 options.android_package, overlay_dir=overlay_dir
328 )
Shao-Chuan Lee3aa76522021-12-03 17:18:58 +0900329
330 if not options.skip_commit:
Alex Klein1699fab2022-09-08 08:46:06 -0600331 _PrepareGitBranch(overlay_dir)
Shao-Chuan Lee3aa76522021-12-03 17:18:58 +0900332
Shao-Chuan Lee7e507e62022-11-15 02:17:34 +0000333 # Use default Android branch if not overridden.
334 android_build_branch = (
Shao-Chuan Lee20c51d82022-10-26 21:56:56 +0900335 options.android_build_branch
Shao-Chuan Lee7e507e62022-11-15 02:17:34 +0000336 or android.GetAndroidBranchForPackage(options.android_package)
337 )
Shao-Chuan Leedea458f2021-11-25 23:46:53 +0900338
Alex Klein1699fab2022-09-08 08:46:06 -0600339 (unstable_ebuild, stable_ebuilds) = FindAndroidCandidates(
340 android_package_dir
341 )
342 # Mirror artifacts, i.e., images and some sdk tools (e.g., adb, aapt).
343 version_to_uprev = android.MirrorArtifacts(
Shao-Chuan Lee20c51d82022-10-26 21:56:56 +0900344 options.android_package,
Alex Klein1699fab2022-09-08 08:46:06 -0600345 options.android_bucket_url,
Shao-Chuan Lee7e507e62022-11-15 02:17:34 +0000346 android_build_branch,
Alex Klein1699fab2022-09-08 08:46:06 -0600347 options.arc_bucket_url,
348 android_package_dir,
349 options.force_version,
350 )
David Rileyc0da9d92016-02-01 12:11:01 -0800351
Alex Klein1699fab2022-09-08 08:46:06 -0600352 stable_candidate = portage_util.BestEBuild(stable_ebuilds)
Shao-Chuan Leedea458f2021-11-25 23:46:53 +0900353
Alex Klein1699fab2022-09-08 08:46:06 -0600354 if stable_candidate:
355 logging.info("Stable candidate found %s", stable_candidate.version)
356 else:
357 logging.info("No stable candidate found.")
358
359 revved = MarkAndroidEBuildAsStable(
360 stable_candidate,
361 unstable_ebuild,
362 options.android_package,
363 version_to_uprev,
364 android_package_dir,
Shao-Chuan Lee7e507e62022-11-15 02:17:34 +0000365 android_build_branch,
Alex Klein1699fab2022-09-08 08:46:06 -0600366 options.arc_bucket_url,
367 options.runtime_artifacts_bucket_url,
368 )
369
370 output = dict(revved=bool(revved))
371
372 if revved:
373 android_atom, files_to_add, files_to_remove = revved
374 if not options.skip_commit:
375 _CommitChange(
376 _GIT_COMMIT_MESSAGE
377 % {
378 "android_package": options.android_package,
379 "android_version": version_to_uprev,
380 },
381 android_package_dir,
382 files_to_add,
383 files_to_remove,
384 )
385 if options.boards:
386 cros_mark_as_stable.CleanStalePackages(
387 options.srcroot, options.boards.split(":"), [android_atom]
388 )
389
390 output["android_atom"] = android_atom
Alex Kleind7197402023-04-05 13:05:29 -0600391 # This field is read by the PUpr uprev handler for creating CLs. We
392 # cannot return absolute paths because this script runs inside chroot
393 # but the uprev handler runs outside.
Alex Klein1699fab2022-09-08 08:46:06 -0600394 # Here we return paths relative to |overlay_dir|.
395 output["modified_files"] = [
396 os.path.relpath(f, overlay_dir)
397 for f in files_to_add + files_to_remove
398 ]
399
400 # The output is being parsed by service.packages.uprev_android and has to be
401 # in its own single line. When invoked from chromite API endpoints, entering
Alex Kleind7197402023-04-05 13:05:29 -0600402 # chroot can generate junk messages on stdout, so we prefix our output with
403 # a line break to further ensure that.
Alex Klein1699fab2022-09-08 08:46:06 -0600404 print("\n" + json.dumps(output, sort_keys=True))