blob: a80615d6d8c6f15f84d1c9e6ab2743d204640b2a [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
30from chromite.lib import gs
Shao-Chuan Lee301a4192021-02-08 11:53:49 +090031from chromite.lib import osutils
David Rileyc0da9d92016-02-01 12:11:01 -080032from chromite.lib import portage_util
Shao-Chuan Lee007dbe82021-02-09 14:05:39 +090033from chromite.lib import repo_util
David Rileyc0da9d92016-02-01 12:11:01 -080034from chromite.scripts import cros_mark_as_stable
Shao-Chuan Lee7fd0ca12021-03-19 15:57:40 +090035from chromite.service import android
Yury Khmelc0a18442022-11-01 16:56:22 -070036from chromite.service import packages
David Rileyc0da9d92016-02-01 12:11:01 -080037
38
39# Dir where all the action happens.
Alex Klein1699fab2022-09-08 08:46:06 -060040_OVERLAY_DIR = "%(srcroot)s/private-overlays/project-cheets-private/"
David Rileyc0da9d92016-02-01 12:11:01 -080041
Junichi Uekawa6d61ab02020-04-15 14:52:28 +090042_GIT_COMMIT_MESSAGE = """Marking latest for %(android_package)s ebuild with \
43version %(android_version)s as stable.
44
45BUG=None
46TEST=CQ
47"""
David Rileyc0da9d92016-02-01 12:11:01 -080048
Alex Klein1699fab2022-09-08 08:46:06 -060049_RUNTIME_ARTIFACTS_BUCKET_URL = "gs://chromeos-arc-images/runtime_artifacts"
David Rileyc0da9d92016-02-01 12:11:01 -080050
David Rileyc0da9d92016-02-01 12:11:01 -080051
52def FindAndroidCandidates(package_dir):
Alex Klein1699fab2022-09-08 08:46:06 -060053 """Return a tuple of Android's unstable ebuild and stable ebuilds.
David Rileyc0da9d92016-02-01 12:11:01 -080054
Alex Klein1699fab2022-09-08 08:46:06 -060055 Args:
56 package_dir: The path to where the package ebuild is stored.
David Rileyc0da9d92016-02-01 12:11:01 -080057
Alex Klein1699fab2022-09-08 08:46:06 -060058 Returns:
59 Tuple [unstable_ebuild, stable_ebuilds].
David Rileyc0da9d92016-02-01 12:11:01 -080060
Alex Klein1699fab2022-09-08 08:46:06 -060061 Raises:
62 Exception: if no unstable ebuild exists for Android.
63 """
64 stable_ebuilds = []
65 unstable_ebuilds = []
66 for path in glob.glob(os.path.join(package_dir, "*.ebuild")):
67 ebuild = portage_util.EBuild(path)
68 if ebuild.version == "9999":
69 unstable_ebuilds.append(ebuild)
70 else:
71 stable_ebuilds.append(ebuild)
David Rileyc0da9d92016-02-01 12:11:01 -080072
Alex Klein1699fab2022-09-08 08:46:06 -060073 # Apply some confidence checks.
74 if not unstable_ebuilds:
75 raise Exception("Missing 9999 ebuild for %s" % package_dir)
76 if not stable_ebuilds:
77 logging.warning("Missing stable ebuild for %s", package_dir)
David Rileyc0da9d92016-02-01 12:11:01 -080078
Alex Klein1699fab2022-09-08 08:46:06 -060079 return portage_util.BestEBuild(unstable_ebuilds), stable_ebuilds
David Rileyc0da9d92016-02-01 12:11:01 -080080
81
Alex Klein1699fab2022-09-08 08:46:06 -060082def FindDataCollectorArtifacts(
Yury Khmelc0a18442022-11-01 16:56:22 -070083 gs_context,
84 android_version,
85 package_name,
86 runtime_artifacts_bucket_url,
87 version_reference,
Alex Klein1699fab2022-09-08 08:46:06 -060088):
89 r"""Finds and includes into variables artifacts from arc.DataCollector.
David Rileyc0da9d92016-02-01 12:11:01 -080090
Alex Klein1699fab2022-09-08 08:46:06 -060091 This is used from UpdateDataCollectorArtifacts in order to check the
92 particular version.
David Rileyc0da9d92016-02-01 12:11:01 -080093
Alex Klein1699fab2022-09-08 08:46:06 -060094 Args:
95 gs_context: context to execute gsutil
96 android_version: The \d+ build id of Android.
Yury Khmelc0a18442022-11-01 16:56:22 -070097 package_name: android package name. Used as folder to locate the cache.
Alex Klein1699fab2022-09-08 08:46:06 -060098 runtime_artifacts_bucket_url: root of runtime artifacts
Alex Klein1699fab2022-09-08 08:46:06 -060099 version_reference: which version to use as a reference. Could be '${PV}' in
100 case version of data collector artifacts matches the
101 Android version or direct version in case of override.
David Rileyc0da9d92016-02-01 12:11:01 -0800102
Alex Klein1699fab2022-09-08 08:46:06 -0600103 Returns:
104 dictionary with filled ebuild variables. This dictionary is empty in case
105 no artificats are found.
106 """
107 variables = {}
David Rileyc0da9d92016-02-01 12:11:01 -0800108
Yury Khmel697863b2022-10-25 09:02:57 -0700109 buckets = ["ureadahead_pack_host", "gms_core_cache", "tts_cache"]
Alex Klein1699fab2022-09-08 08:46:06 -0600110 archs = ["arm", "arm64", "x86", "x86_64"]
111 build_types = ["user", "userdebug"]
David Rileyc0da9d92016-02-01 12:11:01 -0800112
Alex Klein1699fab2022-09-08 08:46:06 -0600113 for bucket in buckets:
114 for arch in archs:
115 for build_type in build_types:
Yury Khmelc0a18442022-11-01 16:56:22 -0700116 # TODO(b/255854925): remove path without |package_name|.
117 # |package_name| is required to separate artefacts for bertha
118 # and cheets.
119 root_paths = [
120 f"{runtime_artifacts_bucket_url}/{package_name}/{bucket}_{arch}_{build_type}",
121 f"{runtime_artifacts_bucket_url}/{bucket}_{arch}_{build_type}",
122 ]
123
124 for _, root_path in enumerate(root_paths):
125 path = f"{root_path}_{android_version}.tar"
126 if gs_context.Exists(path):
127 variables[
128 (f"{arch}_{build_type}_{bucket}").upper()
129 ] = f"{root_path}_{version_reference}.tar"
130 break
Alex Klein1699fab2022-09-08 08:46:06 -0600131
132 return variables
133
134
135def UpdateDataCollectorArtifacts(
Yury Khmelc0a18442022-11-01 16:56:22 -0700136 android_version, runtime_artifacts_bucket_url, package_name
Alex Klein1699fab2022-09-08 08:46:06 -0600137):
138 r"""Finds and includes into variables artifacts from arc.DataCollector.
139
140 This verifies default android version. In case artificts are not found for
141 default Android version it tries to find artifacts for pinned version. If
142 pinned version is provided, it is required artifacts exist for the pinned
143 version.
144
145 Args:
146 android_version: The \d+ build id of Android.
147 runtime_artifacts_bucket_url: root of runtime artifacts
Yury Khmelc0a18442022-11-01 16:56:22 -0700148 package_name: android package name. Used to determine the pinned version if exists.
Alex Klein1699fab2022-09-08 08:46:06 -0600149
150 Returns:
151 dictionary with filled ebuild variables.
152 """
153
154 gs_context = gs.GSContext()
155 # Check the existing version. If we find any artifacts, use them.
156 variables = FindDataCollectorArtifacts(
Yury Khmelc0a18442022-11-01 16:56:22 -0700157 gs_context,
158 android_version,
159 package_name,
160 runtime_artifacts_bucket_url,
161 "${PV}",
Alex Klein1699fab2022-09-08 08:46:06 -0600162 )
163 if variables:
164 # Data artificts were found.
165 return variables
166
167 # Check pinned version for the current branch.
Yury Khmelc0a18442022-11-01 16:56:22 -0700168 milestone = packages.determine_milestone_version()
169 pin_path = f"{runtime_artifacts_bucket_url}/{package_name}/M{milestone}_pin_version"
Alex Klein1699fab2022-09-08 08:46:06 -0600170 if not gs_context.Exists(pin_path):
171 # No pinned version.
172 logging.warning(
173 "No data collector artifacts were found for %s", android_version
174 )
175 return variables
176
177 pin_version = gs_context.Cat(pin_path, encoding="utf-8").rstrip()
178 logging.info("Pinned version %s overrides %s", pin_version, android_version)
179 variables = FindDataCollectorArtifacts(
Yury Khmelc0a18442022-11-01 16:56:22 -0700180 gs_context,
181 pin_version,
182 package_name,
183 runtime_artifacts_bucket_url,
184 pin_version,
Alex Klein1699fab2022-09-08 08:46:06 -0600185 )
186 if not variables:
187 # If pin version set it must contain data.
188 raise Exception(
Yury Khmelc0a18442022-11-01 16:56:22 -0700189 "Pinned version %s does not contain artificats" % pin_path
Alex Klein1699fab2022-09-08 08:46:06 -0600190 )
Alex Klein1699fab2022-09-08 08:46:06 -0600191 return variables
192
193
194def MarkAndroidEBuildAsStable(
195 stable_candidate,
196 unstable_ebuild,
197 android_package,
198 android_version,
199 package_dir,
Shao-Chuan Lee7e507e62022-11-15 02:17:34 +0000200 build_branch,
Alex Klein1699fab2022-09-08 08:46:06 -0600201 arc_bucket_url,
202 runtime_artifacts_bucket_url,
203):
204 r"""Uprevs the Android ebuild.
205
206 This is the main function that uprevs from a stable candidate
207 to its new version.
208
209 Args:
210 stable_candidate: ebuild that corresponds to the stable ebuild we are
211 revving from. If None, builds the a new ebuild given the version
212 with revision set to 1.
213 unstable_ebuild: ebuild corresponding to the unstable ebuild for Android.
214 android_package: android package name.
215 android_version: The \d+ build id of Android.
216 package_dir: Path to the android-container package dir.
Shao-Chuan Lee7e507e62022-11-15 02:17:34 +0000217 build_branch: branch of Android builds.
Alex Klein1699fab2022-09-08 08:46:06 -0600218 arc_bucket_url: URL of the target ARC build gs bucket.
219 runtime_artifacts_bucket_url: root of runtime artifacts
220
221 Returns:
222 Tuple[str, List[str], List[str]] if revved, or None
223 1. Full portage version atom (including rc's, etc) that was revved.
224 2. List of files to be `git add`ed.
225 3. List of files to be `git rm`ed.
226 """
227
228 def IsTheNewEBuildRedundant(new_ebuild, stable_ebuild):
229 """Returns True if the new ebuild is redundant.
230
231 This is True if there if the current stable ebuild is the exact same copy
232 of the new one.
233 """
234 if not stable_ebuild:
235 return False
236
237 if stable_candidate.version_no_rev == new_ebuild.version_no_rev:
238 return filecmp.cmp(
239 new_ebuild.ebuild_path, stable_ebuild.ebuild_path, shallow=False
240 )
241 return False
242
243 # Case where we have the last stable candidate with same version just rev.
244 if stable_candidate and stable_candidate.version_no_rev == android_version:
245 new_ebuild_path = "%s-r%d.ebuild" % (
246 stable_candidate.ebuild_path_no_revision,
247 stable_candidate.current_revision + 1,
248 )
249 else:
250 pf = "%s-%s-r1" % (android_package, android_version)
251 new_ebuild_path = os.path.join(package_dir, "%s.ebuild" % pf)
252
Shao-Chuan Leeca2cbcc2022-11-02 08:28:31 +0900253 build_targets = android.GetAndroidEbuildTargetsForPackage(android_package)
Alex Klein1699fab2022-09-08 08:46:06 -0600254 variables = {"BASE_URL": arc_bucket_url}
255 for var, target in build_targets.items():
Shao-Chuan Lee20c51d82022-10-26 21:56:56 +0900256 # TODO(b/255705023): Have MirrorArtifacts generate the mapping for us.
Alex Klein1699fab2022-09-08 08:46:06 -0600257 variables[var] = f"{build_branch}-linux-{target}"
258
259 variables.update(
260 UpdateDataCollectorArtifacts(
Yury Khmelc0a18442022-11-01 16:56:22 -0700261 android_version,
262 runtime_artifacts_bucket_url,
263 android_package,
Alex Klein1699fab2022-09-08 08:46:06 -0600264 )
265 )
266
267 portage_util.EBuild.MarkAsStable(
268 unstable_ebuild.ebuild_path,
269 new_ebuild_path,
270 variables,
271 make_stable=True,
272 )
273 new_ebuild = portage_util.EBuild(new_ebuild_path)
274
275 # Determine whether this is ebuild is redundant.
276 if IsTheNewEBuildRedundant(new_ebuild, stable_candidate):
277 msg = "Previous ebuild with same version found and ebuild is redundant."
278 logging.info(msg)
Alex Klein1699fab2022-09-08 08:46:06 -0600279 osutils.SafeUnlink(new_ebuild_path)
280 return None
281
Alex Klein1699fab2022-09-08 08:46:06 -0600282 files_to_add = [new_ebuild_path]
283 files_to_remove = []
284 if stable_candidate and not stable_candidate.IsSticky():
285 osutils.SafeUnlink(stable_candidate.ebuild_path)
286 files_to_remove.append(stable_candidate.ebuild_path)
287
288 # Update ebuild manifest and git add it.
289 gen_manifest_cmd = ["ebuild", new_ebuild_path, "manifest", "--force"]
290 cros_build_lib.run(gen_manifest_cmd, extra_env=None, print_cmd=True)
291 files_to_add.append(os.path.join(package_dir, "Manifest"))
292
293 return (
294 f"{new_ebuild.package}-{new_ebuild.version}",
295 files_to_add,
296 files_to_remove,
297 )
David Rileyc0da9d92016-02-01 12:11:01 -0800298
Shao-Chuan Lee301a4192021-02-08 11:53:49 +0900299
Shao-Chuan Lee007dbe82021-02-09 14:05:39 +0900300def _PrepareGitBranch(overlay_dir):
Alex Klein1699fab2022-09-08 08:46:06 -0600301 """Prepares a git branch for the uprev commit.
Shao-Chuan Lee301a4192021-02-08 11:53:49 +0900302
Alex Klein1699fab2022-09-08 08:46:06 -0600303 If the overlay project is currently on a branch (e.g. patches are being
304 applied), rebase the new branch on top of it.
Shao-Chuan Lee007dbe82021-02-09 14:05:39 +0900305
Alex Klein1699fab2022-09-08 08:46:06 -0600306 Args:
307 overlay_dir: The overlay directory.
308 """
309 existing_branch = git.GetCurrentBranch(overlay_dir)
310 repo_util.Repository.MustFind(overlay_dir).StartBranch(
311 constants.STABLE_EBUILD_BRANCH, projects=["."], cwd=overlay_dir
312 )
313 if existing_branch:
314 git.RunGit(overlay_dir, ["rebase", existing_branch])
Shao-Chuan Lee301a4192021-02-08 11:53:49 +0900315
316
317def _CommitChange(message, android_package_dir, files_to_add, files_to_remove):
Alex Klein1699fab2022-09-08 08:46:06 -0600318 """Commit changes to git with list of files to add/remove."""
319 git.RunGit(android_package_dir, ["add", "--"] + files_to_add)
320 if files_to_remove:
321 git.RunGit(android_package_dir, ["rm", "--"] + files_to_remove)
Shao-Chuan Lee301a4192021-02-08 11:53:49 +0900322
Alex Klein1699fab2022-09-08 08:46:06 -0600323 portage_util.EBuild.CommitChange(message, android_package_dir)
David Rileyc0da9d92016-02-01 12:11:01 -0800324
325
326def GetParser():
Alex Klein1699fab2022-09-08 08:46:06 -0600327 """Creates the argument parser."""
328 parser = commandline.ArgumentParser()
329 parser.add_argument("-b", "--boards")
330 parser.add_argument(
331 "--android_bucket_url",
332 default=android.ANDROID_BUCKET_URL,
333 type="gs_path",
334 )
335 parser.add_argument(
336 "--android_build_branch",
Shao-Chuan Lee7e507e62022-11-15 02:17:34 +0000337 help="Android branch to import from, overriding default",
Alex Klein1699fab2022-09-08 08:46:06 -0600338 )
339 parser.add_argument(
340 "--android_package",
341 required=True,
Shao-Chuan Leeca2cbcc2022-11-02 08:28:31 +0900342 choices=android.GetAllAndroidPackages(),
Alex Klein1699fab2022-09-08 08:46:06 -0600343 help="Android package to uprev",
344 )
345 parser.add_argument(
346 "--arc_bucket_url", default=constants.ARC_BUCKET_URL, type="gs_path"
347 )
348 parser.add_argument("-f", "--force_version", help="Android build id to use")
349 parser.add_argument(
350 "-s",
351 "--srcroot",
352 default=os.path.join(constants.SOURCE_ROOT, "src"),
353 help="Path to the src directory",
354 )
355 parser.add_argument(
356 "--runtime_artifacts_bucket_url",
357 default=_RUNTIME_ARTIFACTS_BUCKET_URL,
358 type="gs_path",
359 )
360 parser.add_argument(
361 "--skip_commit",
362 action="store_true",
363 help="Skip commiting uprev changes to git",
364 )
Alex Klein1699fab2022-09-08 08:46:06 -0600365 return parser
David Rileyc0da9d92016-02-01 12:11:01 -0800366
367
368def main(argv):
Alex Klein1699fab2022-09-08 08:46:06 -0600369 parser = GetParser()
370 options = parser.parse_args(argv)
371 options.Freeze()
David Rileyc0da9d92016-02-01 12:11:01 -0800372
Alex Klein1699fab2022-09-08 08:46:06 -0600373 overlay_dir = os.path.abspath(_OVERLAY_DIR % {"srcroot": options.srcroot})
374 android_package_dir = android.GetAndroidPackageDir(
375 options.android_package, overlay_dir=overlay_dir
376 )
Shao-Chuan Lee3aa76522021-12-03 17:18:58 +0900377
378 if not options.skip_commit:
Alex Klein1699fab2022-09-08 08:46:06 -0600379 _PrepareGitBranch(overlay_dir)
Shao-Chuan Lee3aa76522021-12-03 17:18:58 +0900380
Shao-Chuan Lee7e507e62022-11-15 02:17:34 +0000381 # Use default Android branch if not overridden.
382 android_build_branch = (
Shao-Chuan Lee20c51d82022-10-26 21:56:56 +0900383 options.android_build_branch
Shao-Chuan Lee7e507e62022-11-15 02:17:34 +0000384 or android.GetAndroidBranchForPackage(options.android_package)
385 )
Shao-Chuan Leedea458f2021-11-25 23:46:53 +0900386
Alex Klein1699fab2022-09-08 08:46:06 -0600387 (unstable_ebuild, stable_ebuilds) = FindAndroidCandidates(
388 android_package_dir
389 )
390 # Mirror artifacts, i.e., images and some sdk tools (e.g., adb, aapt).
391 version_to_uprev = android.MirrorArtifacts(
Shao-Chuan Lee20c51d82022-10-26 21:56:56 +0900392 options.android_package,
Alex Klein1699fab2022-09-08 08:46:06 -0600393 options.android_bucket_url,
Shao-Chuan Lee7e507e62022-11-15 02:17:34 +0000394 android_build_branch,
Alex Klein1699fab2022-09-08 08:46:06 -0600395 options.arc_bucket_url,
396 android_package_dir,
397 options.force_version,
398 )
David Rileyc0da9d92016-02-01 12:11:01 -0800399
Alex Klein1699fab2022-09-08 08:46:06 -0600400 stable_candidate = portage_util.BestEBuild(stable_ebuilds)
Shao-Chuan Leedea458f2021-11-25 23:46:53 +0900401
Alex Klein1699fab2022-09-08 08:46:06 -0600402 if stable_candidate:
403 logging.info("Stable candidate found %s", stable_candidate.version)
404 else:
405 logging.info("No stable candidate found.")
406
407 revved = MarkAndroidEBuildAsStable(
408 stable_candidate,
409 unstable_ebuild,
410 options.android_package,
411 version_to_uprev,
412 android_package_dir,
Shao-Chuan Lee7e507e62022-11-15 02:17:34 +0000413 android_build_branch,
Alex Klein1699fab2022-09-08 08:46:06 -0600414 options.arc_bucket_url,
415 options.runtime_artifacts_bucket_url,
416 )
417
418 output = dict(revved=bool(revved))
419
420 if revved:
421 android_atom, files_to_add, files_to_remove = revved
422 if not options.skip_commit:
423 _CommitChange(
424 _GIT_COMMIT_MESSAGE
425 % {
426 "android_package": options.android_package,
427 "android_version": version_to_uprev,
428 },
429 android_package_dir,
430 files_to_add,
431 files_to_remove,
432 )
433 if options.boards:
434 cros_mark_as_stable.CleanStalePackages(
435 options.srcroot, options.boards.split(":"), [android_atom]
436 )
437
438 output["android_atom"] = android_atom
439 # This field is read by the PUpr uprev handler for creating CLs. We cannot
440 # return absolute paths because this script runs inside chroot but the uprev
441 # handler runs outside.
442 # Here we return paths relative to |overlay_dir|.
443 output["modified_files"] = [
444 os.path.relpath(f, overlay_dir)
445 for f in files_to_add + files_to_remove
446 ]
447
448 # The output is being parsed by service.packages.uprev_android and has to be
449 # in its own single line. When invoked from chromite API endpoints, entering
450 # chroot can generate junk messages on stdout, so we prefix our output with a
451 # line break to further ensure that.
452 print("\n" + json.dumps(output, sort_keys=True))