blob: 231f31f69bd6f620edd3792bc4452a3cb8da0c1c [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:
55 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:
58 Tuple [unstable_ebuild, stable_ebuilds].
David Rileyc0da9d92016-02-01 12:11:01 -080059
Alex Klein1699fab2022-09-08 08:46:06 -060060 Raises:
61 Exception: if no unstable ebuild exists for Android.
62 """
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
86 This verifies default android version. In case artificts are not found for
87 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:
92 android_version: The \d+ build id of Android.
93 runtime_artifacts_bucket_url: root of runtime artifacts
Yury Khmelc0a18442022-11-01 16:56:22 -070094 package_name: android package name. Used to determine the pinned version if exists.
Alex Klein1699fab2022-09-08 08:46:06 -060095
96 Returns:
97 dictionary with filled ebuild variables.
98 """
Alex Klein1699fab2022-09-08 08:46:06 -060099 # Check the existing version. If we find any artifacts, use them.
Shao-Chuan Leefd5df6f2023-01-20 12:05:28 +0900100 variables = android.FindDataCollectorArtifacts(
Yury Khmelc0a18442022-11-01 16:56:22 -0700101 package_name,
Shao-Chuan Leefd5df6f2023-01-20 12:05:28 +0900102 android_version,
Yury Khmelc0a18442022-11-01 16:56:22 -0700103 "${PV}",
Shao-Chuan Leefd5df6f2023-01-20 12:05:28 +0900104 runtime_artifacts_bucket_url,
Alex Klein1699fab2022-09-08 08:46:06 -0600105 )
106 if variables:
107 # Data artificts were found.
108 return variables
109
110 # Check pinned version for the current branch.
Yury Khmelc0a18442022-11-01 16:56:22 -0700111 milestone = packages.determine_milestone_version()
Shao-Chuan Leefd5df6f2023-01-20 12:05:28 +0900112 pin_version = android.FindRuntimeArtifactsPin(
113 package_name,
114 milestone,
115 runtime_artifacts_bucket_url,
116 )
117 if pin_version is None:
Alex Klein1699fab2022-09-08 08:46:06 -0600118 # No pinned version.
119 logging.warning(
120 "No data collector artifacts were found for %s", android_version
121 )
122 return variables
123
Alex Klein1699fab2022-09-08 08:46:06 -0600124 logging.info("Pinned version %s overrides %s", pin_version, android_version)
Shao-Chuan Leefd5df6f2023-01-20 12:05:28 +0900125 variables = android.FindDataCollectorArtifacts(
Yury Khmelc0a18442022-11-01 16:56:22 -0700126 package_name,
Yury Khmelc0a18442022-11-01 16:56:22 -0700127 pin_version,
Shao-Chuan Leefd5df6f2023-01-20 12:05:28 +0900128 pin_version,
129 runtime_artifacts_bucket_url,
Alex Klein1699fab2022-09-08 08:46:06 -0600130 )
131 if not variables:
132 # If pin version set it must contain data.
133 raise Exception(
Shao-Chuan Leefd5df6f2023-01-20 12:05:28 +0900134 f"Pinned version {pin_version} does not contain artifacts"
Alex Klein1699fab2022-09-08 08:46:06 -0600135 )
Alex Klein1699fab2022-09-08 08:46:06 -0600136 return variables
137
138
139def MarkAndroidEBuildAsStable(
140 stable_candidate,
141 unstable_ebuild,
142 android_package,
143 android_version,
144 package_dir,
Shao-Chuan Lee7e507e62022-11-15 02:17:34 +0000145 build_branch,
Alex Klein1699fab2022-09-08 08:46:06 -0600146 arc_bucket_url,
147 runtime_artifacts_bucket_url,
148):
149 r"""Uprevs the Android ebuild.
150
151 This is the main function that uprevs from a stable candidate
152 to its new version.
153
154 Args:
155 stable_candidate: ebuild that corresponds to the stable ebuild we are
156 revving from. If None, builds the a new ebuild given the version
157 with revision set to 1.
158 unstable_ebuild: ebuild corresponding to the unstable ebuild for Android.
159 android_package: android package name.
160 android_version: The \d+ build id of Android.
161 package_dir: Path to the android-container package dir.
Shao-Chuan Lee7e507e62022-11-15 02:17:34 +0000162 build_branch: branch of Android builds.
Alex Klein1699fab2022-09-08 08:46:06 -0600163 arc_bucket_url: URL of the target ARC build gs bucket.
164 runtime_artifacts_bucket_url: root of runtime artifacts
165
166 Returns:
167 Tuple[str, List[str], List[str]] if revved, or None
168 1. Full portage version atom (including rc's, etc) that was revved.
169 2. List of files to be `git add`ed.
170 3. List of files to be `git rm`ed.
171 """
172
173 def IsTheNewEBuildRedundant(new_ebuild, stable_ebuild):
174 """Returns True if the new ebuild is redundant.
175
176 This is True if there if the current stable ebuild is the exact same copy
177 of the new one.
178 """
179 if not stable_ebuild:
180 return False
181
182 if stable_candidate.version_no_rev == new_ebuild.version_no_rev:
183 return filecmp.cmp(
184 new_ebuild.ebuild_path, stable_ebuild.ebuild_path, shallow=False
185 )
186 return False
187
188 # Case where we have the last stable candidate with same version just rev.
189 if stable_candidate and stable_candidate.version_no_rev == android_version:
190 new_ebuild_path = "%s-r%d.ebuild" % (
191 stable_candidate.ebuild_path_no_revision,
192 stable_candidate.current_revision + 1,
193 )
194 else:
195 pf = "%s-%s-r1" % (android_package, android_version)
196 new_ebuild_path = os.path.join(package_dir, "%s.ebuild" % pf)
197
Shao-Chuan Leeca2cbcc2022-11-02 08:28:31 +0900198 build_targets = android.GetAndroidEbuildTargetsForPackage(android_package)
Alex Klein1699fab2022-09-08 08:46:06 -0600199 variables = {"BASE_URL": arc_bucket_url}
200 for var, target in build_targets.items():
Shao-Chuan Lee20c51d82022-10-26 21:56:56 +0900201 # TODO(b/255705023): Have MirrorArtifacts generate the mapping for us.
Alex Klein1699fab2022-09-08 08:46:06 -0600202 variables[var] = f"{build_branch}-linux-{target}"
203
204 variables.update(
205 UpdateDataCollectorArtifacts(
Yury Khmelc0a18442022-11-01 16:56:22 -0700206 android_version,
207 runtime_artifacts_bucket_url,
208 android_package,
Alex Klein1699fab2022-09-08 08:46:06 -0600209 )
210 )
211
212 portage_util.EBuild.MarkAsStable(
213 unstable_ebuild.ebuild_path,
214 new_ebuild_path,
215 variables,
216 make_stable=True,
217 )
218 new_ebuild = portage_util.EBuild(new_ebuild_path)
219
220 # Determine whether this is ebuild is redundant.
221 if IsTheNewEBuildRedundant(new_ebuild, stable_candidate):
222 msg = "Previous ebuild with same version found and ebuild is redundant."
223 logging.info(msg)
Alex Klein1699fab2022-09-08 08:46:06 -0600224 osutils.SafeUnlink(new_ebuild_path)
225 return None
226
Alex Klein1699fab2022-09-08 08:46:06 -0600227 files_to_add = [new_ebuild_path]
228 files_to_remove = []
229 if stable_candidate and not stable_candidate.IsSticky():
230 osutils.SafeUnlink(stable_candidate.ebuild_path)
231 files_to_remove.append(stable_candidate.ebuild_path)
232
233 # Update ebuild manifest and git add it.
234 gen_manifest_cmd = ["ebuild", new_ebuild_path, "manifest", "--force"]
235 cros_build_lib.run(gen_manifest_cmd, extra_env=None, print_cmd=True)
236 files_to_add.append(os.path.join(package_dir, "Manifest"))
237
238 return (
239 f"{new_ebuild.package}-{new_ebuild.version}",
240 files_to_add,
241 files_to_remove,
242 )
David Rileyc0da9d92016-02-01 12:11:01 -0800243
Shao-Chuan Lee301a4192021-02-08 11:53:49 +0900244
Shao-Chuan Lee007dbe82021-02-09 14:05:39 +0900245def _PrepareGitBranch(overlay_dir):
Alex Klein1699fab2022-09-08 08:46:06 -0600246 """Prepares a git branch for the uprev commit.
Shao-Chuan Lee301a4192021-02-08 11:53:49 +0900247
Alex Klein1699fab2022-09-08 08:46:06 -0600248 If the overlay project is currently on a branch (e.g. patches are being
249 applied), rebase the new branch on top of it.
Shao-Chuan Lee007dbe82021-02-09 14:05:39 +0900250
Alex Klein1699fab2022-09-08 08:46:06 -0600251 Args:
252 overlay_dir: The overlay directory.
253 """
254 existing_branch = git.GetCurrentBranch(overlay_dir)
255 repo_util.Repository.MustFind(overlay_dir).StartBranch(
256 constants.STABLE_EBUILD_BRANCH, projects=["."], cwd=overlay_dir
257 )
258 if existing_branch:
259 git.RunGit(overlay_dir, ["rebase", existing_branch])
Shao-Chuan Lee301a4192021-02-08 11:53:49 +0900260
261
262def _CommitChange(message, android_package_dir, files_to_add, files_to_remove):
Alex Klein1699fab2022-09-08 08:46:06 -0600263 """Commit changes to git with list of files to add/remove."""
264 git.RunGit(android_package_dir, ["add", "--"] + files_to_add)
265 if files_to_remove:
266 git.RunGit(android_package_dir, ["rm", "--"] + files_to_remove)
Shao-Chuan Lee301a4192021-02-08 11:53:49 +0900267
Alex Klein1699fab2022-09-08 08:46:06 -0600268 portage_util.EBuild.CommitChange(message, android_package_dir)
David Rileyc0da9d92016-02-01 12:11:01 -0800269
270
271def GetParser():
Alex Klein1699fab2022-09-08 08:46:06 -0600272 """Creates the argument parser."""
273 parser = commandline.ArgumentParser()
274 parser.add_argument("-b", "--boards")
275 parser.add_argument(
276 "--android_bucket_url",
277 default=android.ANDROID_BUCKET_URL,
278 type="gs_path",
279 )
280 parser.add_argument(
281 "--android_build_branch",
Shao-Chuan Lee7e507e62022-11-15 02:17:34 +0000282 help="Android branch to import from, overriding default",
Alex Klein1699fab2022-09-08 08:46:06 -0600283 )
284 parser.add_argument(
285 "--android_package",
286 required=True,
Shao-Chuan Leeca2cbcc2022-11-02 08:28:31 +0900287 choices=android.GetAllAndroidPackages(),
Alex Klein1699fab2022-09-08 08:46:06 -0600288 help="Android package to uprev",
289 )
290 parser.add_argument(
291 "--arc_bucket_url", default=constants.ARC_BUCKET_URL, type="gs_path"
292 )
293 parser.add_argument("-f", "--force_version", help="Android build id to use")
294 parser.add_argument(
295 "-s",
296 "--srcroot",
297 default=os.path.join(constants.SOURCE_ROOT, "src"),
298 help="Path to the src directory",
299 )
300 parser.add_argument(
301 "--runtime_artifacts_bucket_url",
302 default=_RUNTIME_ARTIFACTS_BUCKET_URL,
303 type="gs_path",
304 )
305 parser.add_argument(
306 "--skip_commit",
307 action="store_true",
308 help="Skip commiting uprev changes to git",
309 )
Alex Klein1699fab2022-09-08 08:46:06 -0600310 return parser
David Rileyc0da9d92016-02-01 12:11:01 -0800311
312
313def main(argv):
Alex Klein1699fab2022-09-08 08:46:06 -0600314 parser = GetParser()
315 options = parser.parse_args(argv)
316 options.Freeze()
David Rileyc0da9d92016-02-01 12:11:01 -0800317
Alex Klein1699fab2022-09-08 08:46:06 -0600318 overlay_dir = os.path.abspath(_OVERLAY_DIR % {"srcroot": options.srcroot})
319 android_package_dir = android.GetAndroidPackageDir(
320 options.android_package, overlay_dir=overlay_dir
321 )
Shao-Chuan Lee3aa76522021-12-03 17:18:58 +0900322
323 if not options.skip_commit:
Alex Klein1699fab2022-09-08 08:46:06 -0600324 _PrepareGitBranch(overlay_dir)
Shao-Chuan Lee3aa76522021-12-03 17:18:58 +0900325
Shao-Chuan Lee7e507e62022-11-15 02:17:34 +0000326 # Use default Android branch if not overridden.
327 android_build_branch = (
Shao-Chuan Lee20c51d82022-10-26 21:56:56 +0900328 options.android_build_branch
Shao-Chuan Lee7e507e62022-11-15 02:17:34 +0000329 or android.GetAndroidBranchForPackage(options.android_package)
330 )
Shao-Chuan Leedea458f2021-11-25 23:46:53 +0900331
Alex Klein1699fab2022-09-08 08:46:06 -0600332 (unstable_ebuild, stable_ebuilds) = FindAndroidCandidates(
333 android_package_dir
334 )
335 # Mirror artifacts, i.e., images and some sdk tools (e.g., adb, aapt).
336 version_to_uprev = android.MirrorArtifacts(
Shao-Chuan Lee20c51d82022-10-26 21:56:56 +0900337 options.android_package,
Alex Klein1699fab2022-09-08 08:46:06 -0600338 options.android_bucket_url,
Shao-Chuan Lee7e507e62022-11-15 02:17:34 +0000339 android_build_branch,
Alex Klein1699fab2022-09-08 08:46:06 -0600340 options.arc_bucket_url,
341 android_package_dir,
342 options.force_version,
343 )
David Rileyc0da9d92016-02-01 12:11:01 -0800344
Alex Klein1699fab2022-09-08 08:46:06 -0600345 stable_candidate = portage_util.BestEBuild(stable_ebuilds)
Shao-Chuan Leedea458f2021-11-25 23:46:53 +0900346
Alex Klein1699fab2022-09-08 08:46:06 -0600347 if stable_candidate:
348 logging.info("Stable candidate found %s", stable_candidate.version)
349 else:
350 logging.info("No stable candidate found.")
351
352 revved = MarkAndroidEBuildAsStable(
353 stable_candidate,
354 unstable_ebuild,
355 options.android_package,
356 version_to_uprev,
357 android_package_dir,
Shao-Chuan Lee7e507e62022-11-15 02:17:34 +0000358 android_build_branch,
Alex Klein1699fab2022-09-08 08:46:06 -0600359 options.arc_bucket_url,
360 options.runtime_artifacts_bucket_url,
361 )
362
363 output = dict(revved=bool(revved))
364
365 if revved:
366 android_atom, files_to_add, files_to_remove = revved
367 if not options.skip_commit:
368 _CommitChange(
369 _GIT_COMMIT_MESSAGE
370 % {
371 "android_package": options.android_package,
372 "android_version": version_to_uprev,
373 },
374 android_package_dir,
375 files_to_add,
376 files_to_remove,
377 )
378 if options.boards:
379 cros_mark_as_stable.CleanStalePackages(
380 options.srcroot, options.boards.split(":"), [android_atom]
381 )
382
383 output["android_atom"] = android_atom
384 # This field is read by the PUpr uprev handler for creating CLs. We cannot
385 # return absolute paths because this script runs inside chroot but the uprev
386 # handler runs outside.
387 # Here we return paths relative to |overlay_dir|.
388 output["modified_files"] = [
389 os.path.relpath(f, overlay_dir)
390 for f in files_to_add + files_to_remove
391 ]
392
393 # The output is being parsed by service.packages.uprev_android and has to be
394 # in its own single line. When invoked from chromite API endpoints, entering
395 # chroot can generate junk messages on stdout, so we prefix our output with a
396 # line break to further ensure that.
397 print("\n" + json.dumps(output, sort_keys=True))