blob: be8f846f59ae2dec55cb6cff0ba35be0734bb682 [file] [log] [blame]
Mike Frysingerf1ba7ad2022-09-12 05:42:57 -04001# Copyright 2012 The ChromiumOS Authors
Chris Sosadad0d322011-01-31 16:37:33 -08002# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5"""This module uprevs a given package's ebuild to the next revision."""
6
Chris McDonald59650c32021-07-20 15:29:28 -06007import logging
Chris Sosadad0d322011-01-31 16:37:33 -08008import os
Chris Sosadad0d322011-01-31 16:37:33 -08009
Ram Chandrasekar60f69f32022-06-03 22:49:30 +000010from chromite.lib import chromeos_version
Mike Frysingere8dcbfd2015-03-08 21:45:52 -040011from chromite.lib import commandline
Chris McDonald59650c32021-07-20 15:29:28 -060012from chromite.lib import constants
Chris Sosac13bba52011-05-24 15:14:09 -070013from chromite.lib import cros_build_lib
David James97d95872012-11-16 15:09:56 -080014from chromite.lib import git
Mike Frysingerfddaeb52012-11-20 11:17:31 -050015from chromite.lib import osutils
David James6450a0a2012-12-04 07:59:53 -080016from chromite.lib import parallel
Alex Deymo075c2292014-09-04 18:31:50 -070017from chromite.lib import portage_util
Lann Martinb26e1292018-08-09 13:59:19 -060018from chromite.lib import repo_util
Sergey Frolov0161f8b2021-07-07 17:41:10 -060019from chromite.lib import retry_util
Chris Sosac13bba52011-05-24 15:14:09 -070020
Mike Frysinger32781402020-04-19 06:34:17 -040021
Gabe Black71e963e2014-10-28 20:19:59 -070022# Commit message subject for uprevving Portage packages.
Alex Klein1699fab2022-09-08 08:46:06 -060023GIT_COMMIT_SUBJECT = "Marking set of ebuilds as stable"
David James15ed1302013-04-25 09:21:19 -070024
David James29e86d52013-04-19 09:41:29 -070025# Commit message for uprevving Portage packages.
Alex Klein1699fab2022-09-08 08:46:06 -060026_GIT_COMMIT_MESSAGE = "Marking 9999 ebuild for %s as stable."
David James29e86d52013-04-19 09:41:29 -070027
Chris Sosadad0d322011-01-31 16:37:33 -080028# Dictionary of valid commands with usage information.
29COMMAND_DICTIONARY = {
Alex Klein1699fab2022-09-08 08:46:06 -060030 "commit": "Marks given ebuilds as stable locally",
31 "push": "Pushes previous marking of ebuilds to remote repo",
Mike Frysinger5cd8c742013-10-11 14:43:01 -040032}
Chris Sosadad0d322011-01-31 16:37:33 -080033
Chris Sosadad0d322011-01-31 16:37:33 -080034
Chris Sosadad0d322011-01-31 16:37:33 -080035# ======================= Global Helper Functions ========================
36
37
David James41124af2015-06-04 21:13:25 -070038def CleanStalePackages(srcroot, boards, package_atoms):
Alex Klein1699fab2022-09-08 08:46:06 -060039 """Cleans up stale package info from a previous build.
Mike Frysinger5cd8c742013-10-11 14:43:01 -040040
Alex Klein1699fab2022-09-08 08:46:06 -060041 Args:
Alex Klein68b270c2023-04-14 14:42:50 -060042 srcroot: Root directory of the source tree.
43 boards: Boards to clean the packages from.
44 package_atoms: A list of package atoms to unmerge.
Alex Klein1699fab2022-09-08 08:46:06 -060045 """
46 if package_atoms:
47 logging.info("Cleaning up stale packages %s.", package_atoms)
David James15ed1302013-04-25 09:21:19 -070048
Alex Klein1699fab2022-09-08 08:46:06 -060049 # First unmerge all the packages for a board, then eclean it.
50 # We need these two steps to run in order (unmerge/eclean),
51 # but we can let all the boards run in parallel.
52 def _CleanStalePackages(board):
53 if board:
54 suffix = "-" + board
55 runcmd = cros_build_lib.run
56 else:
57 suffix = ""
58 runcmd = cros_build_lib.sudo_run
Chris Sosadad0d322011-01-31 16:37:33 -080059
Alex Klein1699fab2022-09-08 08:46:06 -060060 emerge, eclean = "emerge" + suffix, "eclean" + suffix
61 if not osutils.FindMissingBinaries([emerge, eclean]):
62 if package_atoms:
63 # If nothing was found to be unmerged, emerge will exit(1).
64 result = runcmd(
65 [emerge, "-q", "--unmerge"] + list(package_atoms),
66 enter_chroot=True,
67 extra_env={"CLEAN_DELAY": "0"},
68 check=False,
69 cwd=srcroot,
70 )
71 if result.returncode not in (0, 1):
72 raise cros_build_lib.RunCommandError(
73 "unexpected error", result
74 )
75 runcmd(
76 [eclean, "-d", "packages"],
77 cwd=srcroot,
78 enter_chroot=True,
79 stdout=True,
80 stderr=True,
81 )
Mike Frysingerb7ab9b82012-04-04 16:22:43 -040082
Alex Klein1699fab2022-09-08 08:46:06 -060083 tasks = []
84 for board in boards:
85 tasks.append([board])
86 tasks.append([None])
Mike Frysingerb7ab9b82012-04-04 16:22:43 -040087
Alex Klein1699fab2022-09-08 08:46:06 -060088 parallel.RunTasksInProcessPool(_CleanStalePackages, tasks)
Chris Sosadad0d322011-01-31 16:37:33 -080089
90
Mike Frysinger2ebe3732012-05-08 17:04:12 -040091# TODO(build): This code needs to be gutted and rebased to cros_build_lib.
92def _DoWeHaveLocalCommits(stable_branch, tracking_branch, cwd):
Alex Klein1699fab2022-09-08 08:46:06 -060093 """Returns true if there are local commits."""
94 output = git.RunGit(
95 cwd, ["rev-parse", stable_branch, tracking_branch]
96 ).stdout.split()
97 return output[0] != output[1]
Chris Sosadad0d322011-01-31 16:37:33 -080098
99
Chris Sosadad0d322011-01-31 16:37:33 -0800100# ======================= End Global Helper Functions ========================
101
102
Alex Klein1699fab2022-09-08 08:46:06 -0600103def PushChange(
104 stable_branch, tracking_branch, dryrun, cwd, staging_branch=None
105):
106 """Pushes commits in the stable_branch to the remote git repository.
Chris Sosadad0d322011-01-31 16:37:33 -0800107
Alex Klein1699fab2022-09-08 08:46:06 -0600108 Pushes local commits from calls to CommitChange to the remote git
109 repository specified by current working directory. If changes are
110 found to commit, they will be merged to the merge branch and pushed.
111 In that case, the local repository will be left on the merge branch.
Chris Sosadad0d322011-01-31 16:37:33 -0800112
Alex Klein1699fab2022-09-08 08:46:06 -0600113 Args:
Alex Klein68b270c2023-04-14 14:42:50 -0600114 stable_branch: The local branch with commits we want to push.
115 tracking_branch: The tracking branch of the local branch.
116 dryrun: Use git push --dryrun to emulate a push.
117 cwd: The directory to run commands in.
118 staging_branch: The staging branch to push for a failed PFQ run.
Mike Frysinger1a736a82013-12-12 01:50:59 -0500119
Alex Klein1699fab2022-09-08 08:46:06 -0600120 Raises:
Alex Klein68b270c2023-04-14 14:42:50 -0600121 OSError: Error occurred while pushing.
Alex Klein1699fab2022-09-08 08:46:06 -0600122 """
123 if not git.DoesCommitExistInRepo(cwd, stable_branch):
124 logging.debug("No branch created for %s. Exiting", cwd)
125 return
David James47959632015-10-23 07:56:01 -0700126
Alex Klein1699fab2022-09-08 08:46:06 -0600127 if not _DoWeHaveLocalCommits(stable_branch, tracking_branch, cwd):
128 logging.debug("No work found to push in %s. Exiting", cwd)
129 return
Chris Sosadad0d322011-01-31 16:37:33 -0800130
Alex Klein1699fab2022-09-08 08:46:06 -0600131 # For the commit queue, our local branch may contain commits that were
132 # just tested and pushed during the CommitQueueCompletion stage. Sync
133 # and rebase our local branch on top of the remote commits.
134 remote_ref = git.GetTrackingBranch(cwd, branch=stable_branch, for_push=True)
Alex Klein68b270c2023-04-14 14:42:50 -0600135 # SyncPushBranch rebases HEAD onto the updated remote. We need to check out
Alex Klein1699fab2022-09-08 08:46:06 -0600136 # stable_branch here in order to update it.
137 git.RunGit(cwd, ["checkout", stable_branch])
138 git.SyncPushBranch(cwd, remote_ref.remote, remote_ref.ref)
David James66009462012-03-25 10:08:38 -0700139
Alex Klein1699fab2022-09-08 08:46:06 -0600140 # Check whether any local changes remain after the sync.
141 if not _DoWeHaveLocalCommits(stable_branch, remote_ref.ref, cwd):
142 logging.info("All changes already pushed for %s. Exiting", cwd)
143 return
David James66009462012-03-25 10:08:38 -0700144
Alex Klein1699fab2022-09-08 08:46:06 -0600145 # Add a failsafe check here. Only CLs from these users should be here.
146 # - 'chrome-bot',
147 # - 'chromeos-ci-prod'
148 # - 'chromeos-ci-release'
149 # If any other CLs are found then complain. In dryruns extra CLs are normal,
150 # though, and can be ignored.
151 bad_cl_cmd = [
152 "log",
153 "--format=short",
154 "--perl-regexp",
155 "--author",
156 "^(?!chrome-bot|chromeos-ci-prod|chromeos-ci-release)",
157 "%s..%s" % (remote_ref.ref, stable_branch),
158 ]
159 bad_cls = git.RunGit(cwd, bad_cl_cmd).stdout
160 if bad_cls.strip() and not dryrun:
161 logging.error(
162 "The Uprev stage found changes from users other than "
163 "chrome-bot or chromeos-ci-prod or chromeos-ci-release:\n\n%s",
164 bad_cls,
165 )
166 raise AssertionError("Unexpected CLs found during uprev stage.")
Matt Tennantcb522052013-11-25 14:23:43 -0800167
Alex Klein1699fab2022-09-08 08:46:06 -0600168 if staging_branch is not None:
169 logging.info(
170 "PFQ FAILED. Pushing uprev change to staging branch %s",
171 staging_branch,
172 )
Lev Rumyantsev25352ba2016-09-07 15:53:58 -0700173
Alex Klein1699fab2022-09-08 08:46:06 -0600174 description = git.RunGit(
175 cwd,
176 [
177 "log",
178 "--format=format:%s%n%n%b",
179 "%s..%s" % (remote_ref.ref, stable_branch),
180 ],
181 ).stdout
182 description = "%s\n\n%s" % (GIT_COMMIT_SUBJECT, description)
183 logging.info("For %s, using description %s", cwd, description)
184 git.CreatePushBranch(
185 constants.MERGE_BRANCH, cwd, remote_push_branch=remote_ref
186 )
187 git.RunGit(cwd, ["merge", "--squash", stable_branch])
188 git.RunGit(cwd, ["commit", "-m", description])
189 git.RunGit(cwd, ["config", "push.default", "tracking"])
Sergey Frolov0161f8b2021-07-07 17:41:10 -0600190
Alex Klein1699fab2022-09-08 08:46:06 -0600191 # Run git.PushBranch and retry up to 5 times.
192 # retry_util.RetryCommand will only retry on RunCommandErrors,
193 # which would be thrown by git.PushBranch when it gets to
194 # cros_build_lib.run()'ning the actual git command,
195 # which may fail with a transient HTTP 429 Too Many Requests error,
196 # and we need to retry on that.
197 # Do not retry if it fails to setup before cros_build_lib.run
198 # or upon other errors, like getting SIGINT.
199 max_retries = 5
200 retry_util.RetryCommand(
201 git.PushBranch,
202 max_retries,
203 constants.MERGE_BRANCH,
204 cwd,
205 dryrun=dryrun,
206 staging_branch=staging_branch,
207 sleep=15,
208 log_retries=True,
209 )
Chris Sosadad0d322011-01-31 16:37:33 -0800210
211
212class GitBranch(object):
Alex Klein1699fab2022-09-08 08:46:06 -0600213 """Wrapper class for a git branch."""
Chris Sosadad0d322011-01-31 16:37:33 -0800214
Alex Klein1699fab2022-09-08 08:46:06 -0600215 def __init__(self, branch_name, tracking_branch, cwd):
216 """Sets up variables but does not create the branch.
David Jamesc7c4ff52013-09-18 17:57:13 -0700217
Alex Klein1699fab2022-09-08 08:46:06 -0600218 Args:
Alex Klein68b270c2023-04-14 14:42:50 -0600219 branch_name: The name of the branch.
220 tracking_branch: The associated tracking branch.
221 cwd: The git repository to work in.
Alex Klein1699fab2022-09-08 08:46:06 -0600222 """
223 self.branch_name = branch_name
224 self.tracking_branch = tracking_branch
225 self.cwd = cwd
Chris Sosadad0d322011-01-31 16:37:33 -0800226
Alex Klein1699fab2022-09-08 08:46:06 -0600227 def CreateBranch(self):
228 self.Checkout()
Chris Sosadad0d322011-01-31 16:37:33 -0800229
Alex Klein1699fab2022-09-08 08:46:06 -0600230 def Checkout(self, branch=None):
231 """Function used to check out to another GitBranch."""
232 if not branch:
233 branch = self.branch_name
234 if branch == self.tracking_branch or self.Exists(branch):
235 git.RunGit(self.cwd, ["checkout", "-f", branch])
236 else:
237 repo = repo_util.Repository.MustFind(self.cwd)
238 repo.StartBranch(branch, projects=["."], cwd=self.cwd)
Chris Sosadad0d322011-01-31 16:37:33 -0800239
Alex Klein1699fab2022-09-08 08:46:06 -0600240 def Exists(self, branch=None):
241 """Returns True if the branch exists."""
242 if not branch:
243 branch = self.branch_name
244 branches = git.RunGit(self.cwd, ["branch"]).stdout
245 return branch in branches.split()
Chris Sosadad0d322011-01-31 16:37:33 -0800246
247
Mike Frysingere8dcbfd2015-03-08 21:45:52 -0400248def GetParser():
Alex Klein1699fab2022-09-08 08:46:06 -0600249 """Creates the argparse parser."""
250 parser = commandline.ArgumentParser()
251 parser.add_argument(
252 "--all", action="store_true", help="Mark all packages as stable."
253 )
254 parser.add_argument(
255 "-b", "--boards", default="", help="Colon-separated list of boards."
256 )
257 parser.add_argument(
258 "--drop_file", help="File to list packages that were revved."
259 )
260 parser.add_argument(
261 "--dryrun",
262 action="store_true",
263 help="Passes dry-run to git push if pushing a change.",
264 )
265 parser.add_argument(
266 "--force",
267 action="store_true",
268 help="Force the stabilization of packages marked for "
269 "manual uprev. "
270 "(only compatible with -p)",
271 )
272 parser.add_argument(
273 "--list_revisions",
274 action="store_true",
275 help="List all revisions included in the commit message.",
276 )
277 parser.add_argument(
278 "-o", "--overlays", help="Colon-separated list of overlays to modify."
279 )
280 parser.add_argument(
281 "--overlay-type",
282 help='Populates --overlays based on "public", "private"' ', or "both".',
283 )
284 parser.add_argument(
285 "-p", "--packages", help="Colon separated list of packages to rev."
286 )
287 parser.add_argument("--buildroot", type="path", help="Path to buildroot.")
288 parser.add_argument(
289 "-r",
290 "--srcroot",
291 type="path",
292 help="Path to root src. Deprecated in favor of " "--buildroot",
293 )
294 parser.add_argument(
295 "--staging_branch", help="The staging branch to push changes"
296 )
297 parser.add_argument(
298 "command", choices=sorted(COMMAND_DICTIONARY), help="Command to run."
299 )
300 return parser
Mike Frysingere8dcbfd2015-03-08 21:45:52 -0400301
302
303def main(argv):
Alex Klein1699fab2022-09-08 08:46:06 -0600304 parser = GetParser()
305 options = parser.parse_args(argv)
Don Garrett4fef8c32018-08-10 18:04:01 -0700306
Alex Klein1699fab2022-09-08 08:46:06 -0600307 # TODO: Remove this code in favor of a simple default on buildroot when
308 # srcroot is removed.
309 if options.srcroot and not options.buildroot:
310 # Convert /<repo>/src -> <repo>
311 options.buildroot = os.path.dirname(options.srcroot)
312 if not options.buildroot:
313 options.buildroot = constants.SOURCE_ROOT
314 options.srcroot = None
Don Garrett4fef8c32018-08-10 18:04:01 -0700315
Alex Klein1699fab2022-09-08 08:46:06 -0600316 options.Freeze()
Mike Frysingere8dcbfd2015-03-08 21:45:52 -0400317
Alex Klein1699fab2022-09-08 08:46:06 -0600318 if options.command == "commit":
319 if not options.packages and not options.all:
320 parser.error("Please specify at least one package (--packages)")
321 if options.force and options.all:
322 parser.error(
323 "Cannot use --force with --all. You must specify a list of "
324 "packages you want to force uprev."
325 )
Bertrand SIMONNET6af54302015-08-05 10:12:49 -0700326
Alex Klein1699fab2022-09-08 08:46:06 -0600327 if not os.path.isdir(options.buildroot):
328 parser.error("buildroot is not a valid path: %s" % options.buildroot)
Mike Frysingere8dcbfd2015-03-08 21:45:52 -0400329
Alex Klein1699fab2022-09-08 08:46:06 -0600330 if options.overlay_type and options.overlays:
331 parser.error("Cannot use --overlay-type with --overlays.")
Don Garrettf9eff952018-08-10 16:50:04 -0700332
Alex Klein1699fab2022-09-08 08:46:06 -0600333 portage_util.EBuild.VERBOSE = options.verbose
Chris Sosa62ad8522011-03-08 17:46:17 -0800334
Alex Klein1699fab2022-09-08 08:46:06 -0600335 package_list = None
336 if options.packages:
337 package_list = options.packages.split(":")
Chris Sosa62ad8522011-03-08 17:46:17 -0800338
Alex Klein1699fab2022-09-08 08:46:06 -0600339 overlays = []
340 if options.overlays:
341 for path in options.overlays.split(":"):
342 if not os.path.isdir(path):
Alex Kleindf8ee502022-10-18 09:48:15 -0600343 cros_build_lib.Die("Cannot find overlay: %s", path)
Alex Klein1699fab2022-09-08 08:46:06 -0600344 overlays.append(os.path.realpath(path))
345 elif options.overlay_type:
346 overlays = portage_util.FindOverlays(
347 options.overlay_type, buildroot=options.buildroot
348 )
349 else:
350 logging.warning("Missing --overlays argument")
351 overlays.extend(
352 [
353 "%s/src/private-overlays/chromeos-overlay" % options.buildroot,
354 "%s/src/third_party/chromiumos-overlay" % options.buildroot,
355 ]
356 )
Chris Sosadad0d322011-01-31 16:37:33 -0800357
Alex Klein1699fab2022-09-08 08:46:06 -0600358 manifest = git.ManifestCheckout.Cached(options.buildroot)
Ryan Cui4656a3c2011-05-24 12:30:30 -0700359
Alex Klein1699fab2022-09-08 08:46:06 -0600360 # Dict mapping from each overlay to its tracking branch.
361 overlay_tracking_branch = {}
362 # Dict mapping from each git repository (project) to a list of its overlays.
363 git_project_overlays = {}
Ningning Xia419e4eb2018-02-05 10:30:36 -0800364
Alex Klein1699fab2022-09-08 08:46:06 -0600365 for overlay in overlays:
366 remote_ref = git.GetTrackingBranchViaManifest(
367 overlay, manifest=manifest
368 )
369 overlay_tracking_branch[overlay] = remote_ref.ref
370 git_project_overlays.setdefault(remote_ref.project_name, []).append(
371 overlay
372 )
Ningning Xia419e4eb2018-02-05 10:30:36 -0800373
Alex Klein1699fab2022-09-08 08:46:06 -0600374 if options.command == "push":
375 _WorkOnPush(options, overlay_tracking_branch, git_project_overlays)
376 elif options.command == "commit":
377 _WorkOnCommit(
378 options,
379 overlays,
380 overlay_tracking_branch,
381 git_project_overlays,
382 manifest,
383 package_list,
384 )
Ningning Xia419e4eb2018-02-05 10:30:36 -0800385
386
387def _WorkOnPush(options, overlay_tracking_branch, git_project_overlays):
Alex Klein68b270c2023-04-14 14:42:50 -0600388 """Push uprevs of overlays belonging to different git projects in parallel.
Ningning Xia419e4eb2018-02-05 10:30:36 -0800389
Alex Klein1699fab2022-09-08 08:46:06 -0600390 Args:
Alex Klein68b270c2023-04-14 14:42:50 -0600391 options: The options object returned by the argument parser.
392 overlay_tracking_branch: A dict mapping from each overlay to its
393 tracking branch.
394 git_project_overlays: A dict mapping from each git repository to a list
395 of its overlays.
Alex Klein1699fab2022-09-08 08:46:06 -0600396 """
397 inputs = [
398 [options, overlays_per_project, overlay_tracking_branch]
399 for overlays_per_project in git_project_overlays.values()
400 ]
401 parallel.RunTasksInProcessPool(_PushOverlays, inputs)
Ningning Xia419e4eb2018-02-05 10:30:36 -0800402
403
404def _PushOverlays(options, overlays, overlay_tracking_branch):
Alex Klein1699fab2022-09-08 08:46:06 -0600405 """Push uprevs for overlays in sequence.
Ningning Xia419e4eb2018-02-05 10:30:36 -0800406
Alex Klein1699fab2022-09-08 08:46:06 -0600407 Args:
Alex Klein68b270c2023-04-14 14:42:50 -0600408 options: The options object returned by the argument parser.
409 overlays: A list of overlays to push uprevs in sequence.
410 overlay_tracking_branch: A dict mapping from each overlay to its
411 tracking branch.
Alex Klein1699fab2022-09-08 08:46:06 -0600412 """
413 for overlay in overlays:
414 if not os.path.isdir(overlay):
415 logging.warning("Skipping %s, which is not a directory.", overlay)
416 continue
Ningning Xia419e4eb2018-02-05 10:30:36 -0800417
Alex Klein1699fab2022-09-08 08:46:06 -0600418 tracking_branch = overlay_tracking_branch[overlay]
419 PushChange(
420 constants.STABLE_EBUILD_BRANCH,
421 tracking_branch,
422 options.dryrun,
423 cwd=overlay,
424 staging_branch=options.staging_branch,
425 )
Ningning Xia419e4eb2018-02-05 10:30:36 -0800426
427
Alex Klein1699fab2022-09-08 08:46:06 -0600428def _WorkOnCommit(
429 options,
430 overlays,
431 overlay_tracking_branch,
432 git_project_overlays,
433 manifest,
434 package_list,
435):
Alex Klein68b270c2023-04-14 14:42:50 -0600436 """Commit uprevs of overlays in different git projects in parallel.
Ningning Xia419e4eb2018-02-05 10:30:36 -0800437
Alex Klein1699fab2022-09-08 08:46:06 -0600438 Args:
Alex Klein68b270c2023-04-14 14:42:50 -0600439 options: The options object returned by the argument parser.
440 overlays: A list of overlays to work on.
441 overlay_tracking_branch: A dict mapping from each overlay to its
442 tracking branch.
443 git_project_overlays: A dict mapping from each git repository to a list
444 of its overlays.
445 manifest: The manifest of the given source root.
446 package_list: A list of packages passed from commandline to work on.
Alex Klein1699fab2022-09-08 08:46:06 -0600447 """
Alex Klein68b270c2023-04-14 14:42:50 -0600448 # We cleaned up self-referential ebuilds by this version, but don't enforce
Alex Klein1699fab2022-09-08 08:46:06 -0600449 # the check on older ones to avoid breaking factory/firmware branches.
450 root_version = chromeos_version.VersionInfo.from_repo(options.buildroot)
451 no_self_repos_version = chromeos_version.VersionInfo("13099.0.0")
452 reject_self_repo = root_version >= no_self_repos_version
Mike Frysinger62ff8d72020-05-19 03:06:51 -0400453
Alex Klein1699fab2022-09-08 08:46:06 -0600454 overlay_ebuilds = _GetOverlayToEbuildsMap(options, overlays, package_list)
David James84e953c2013-04-23 18:44:06 -0700455
Alex Klein1699fab2022-09-08 08:46:06 -0600456 with parallel.Manager() as manager:
457 # Contains the array of packages we actually revved.
458 revved_packages = manager.list()
459 new_package_atoms = manager.list()
David Jamesa8457b52011-05-28 00:03:20 -0700460
Alex Klein1699fab2022-09-08 08:46:06 -0600461 inputs = [
462 [
463 options,
464 manifest,
465 overlays_per_project,
466 overlay_tracking_branch,
467 overlay_ebuilds,
468 revved_packages,
469 new_package_atoms,
470 reject_self_repo,
471 ]
472 for overlays_per_project in git_project_overlays.values()
473 ]
474 parallel.RunTasksInProcessPool(_CommitOverlays, inputs)
Chris Sosadad0d322011-01-31 16:37:33 -0800475
Alex Klein1699fab2022-09-08 08:46:06 -0600476 chroot_path = os.path.join(
477 options.buildroot, constants.DEFAULT_CHROOT_DIR
478 )
479 if os.path.exists(chroot_path):
480 CleanStalePackages(
481 options.buildroot, options.boards.split(":"), new_package_atoms
482 )
483 if options.drop_file:
484 osutils.WriteFile(options.drop_file, " ".join(revved_packages))
Chris Sosadad0d322011-01-31 16:37:33 -0800485
Brian Harring609dc4e2012-05-07 02:17:44 -0700486
Ningning Xia419e4eb2018-02-05 10:30:36 -0800487def _GetOverlayToEbuildsMap(options, overlays, package_list):
Alex Klein1699fab2022-09-08 08:46:06 -0600488 """Get ebuilds for overlays.
David James15ed1302013-04-25 09:21:19 -0700489
Alex Klein1699fab2022-09-08 08:46:06 -0600490 Args:
Alex Klein68b270c2023-04-14 14:42:50 -0600491 options: The options object returned by the argument parser.
492 overlays: A list of overlays to work on.
493 package_list: A list of packages passed from commandline to work on.
Ningning Xia419e4eb2018-02-05 10:30:36 -0800494
Alex Klein1699fab2022-09-08 08:46:06 -0600495 Returns:
Alex Klein68b270c2023-04-14 14:42:50 -0600496 A dict mapping each overlay to a list of ebuilds belonging to it.
Alex Klein1699fab2022-09-08 08:46:06 -0600497 """
498 root_version = chromeos_version.VersionInfo.from_repo(options.buildroot)
499 subdir_removal = chromeos_version.VersionInfo("10363.0.0")
500 require_subdir_support = root_version < subdir_removal
Don Garrett3dbb2932018-10-02 14:41:26 -0700501
Alex Klein1699fab2022-09-08 08:46:06 -0600502 overlay_ebuilds = {}
503 inputs = [
504 [
505 overlay,
506 options.all,
507 package_list,
508 options.force,
509 require_subdir_support,
510 ]
511 for overlay in overlays
512 ]
513 result = parallel.RunTasksInProcessPool(
514 portage_util.GetOverlayEBuilds, inputs
515 )
516 for idx, ebuilds in enumerate(result):
517 overlay_ebuilds[overlays[idx]] = ebuilds
Ningning Xia419e4eb2018-02-05 10:30:36 -0800518
Alex Klein1699fab2022-09-08 08:46:06 -0600519 return overlay_ebuilds
Ningning Xia419e4eb2018-02-05 10:30:36 -0800520
521
Alex Klein1699fab2022-09-08 08:46:06 -0600522def _CommitOverlays(
523 options,
524 manifest,
525 overlays,
526 overlay_tracking_branch,
527 overlay_ebuilds,
528 revved_packages,
529 new_package_atoms,
530 reject_self_repo=True,
531):
532 """Commit uprevs for overlays in sequence.
Ningning Xia419e4eb2018-02-05 10:30:36 -0800533
Alex Klein1699fab2022-09-08 08:46:06 -0600534 Args:
Alex Klein68b270c2023-04-14 14:42:50 -0600535 options: The options object returned by the argument parser.
536 manifest: The manifest of the given source root.
537 overlays: A list over overlays to commit.
538 overlay_tracking_branch: A dict mapping from each overlay to its
539 tracking branch.
540 overlay_ebuilds: A dict mapping overlays to their ebuilds.
541 revved_packages: A shared list of revved packages.
542 new_package_atoms: A shared list of new package atoms.
543 reject_self_repo: Whether to abort if the ebuild lives in the same git
544 repo as it is tracking for uprevs.
Alex Klein1699fab2022-09-08 08:46:06 -0600545 """
546 for overlay in overlays:
547 if not os.path.isdir(overlay):
548 logging.warning("Skipping %s, which is not a directory.", overlay)
Sam McNallyeb5e2052018-09-05 16:34:55 +1000549 continue
550
Alex Klein1699fab2022-09-08 08:46:06 -0600551 # Note we intentionally work from the non push tracking branch;
552 # everything built thus far has been against it (meaning, http mirrors),
553 # thus we should honor that. During the actual push, the code switches
554 # to the correct urls, and does an appropriate rebasing.
555 tracking_branch = overlay_tracking_branch[overlay]
Sam McNallyeb5e2052018-09-05 16:34:55 +1000556
Alex Klein1699fab2022-09-08 08:46:06 -0600557 existing_commit = git.GetGitRepoRevision(overlay)
558
559 # Make sure we run in the top-level git directory in case we are
560 # adding/removing an overlay in existing_commit.
561 git_root = git.FindGitTopLevel(overlay)
562 if git_root is None:
563 cros_build_lib.Die("No git repo at overlay directory %s.", overlay)
564
565 work_branch = GitBranch(
566 constants.STABLE_EBUILD_BRANCH, tracking_branch, cwd=git_root
567 )
568 work_branch.CreateBranch()
569 if not work_branch.Exists():
570 cros_build_lib.Die(
571 "Unable to create stabilizing branch in %s" % overlay
572 )
573
574 # In the case of uprevving overlays that have patches applied to them,
575 # include the patched changes in the stabilizing branch.
576 git.RunGit(git_root, ["rebase", existing_commit])
577
578 ebuilds = overlay_ebuilds.get(overlay, [])
579 if ebuilds:
580 with parallel.Manager() as manager:
581 # Contains the array of packages we actually revved.
582 messages = manager.list()
583 ebuild_paths_to_add = manager.list()
584 ebuild_paths_to_remove = manager.list()
585
586 inputs = [
587 [
588 overlay,
589 ebuild,
590 manifest,
591 options,
592 ebuild_paths_to_add,
593 ebuild_paths_to_remove,
594 messages,
595 revved_packages,
596 new_package_atoms,
597 reject_self_repo,
598 ]
599 for ebuild in ebuilds
600 ]
601 parallel.RunTasksInProcessPool(_WorkOnEbuild, inputs)
602
603 if ebuild_paths_to_add:
604 logging.info(
605 "Adding new stable ebuild paths %s in overlay %s.",
606 ebuild_paths_to_add,
607 overlay,
608 )
609 git.RunGit(overlay, ["add"] + list(ebuild_paths_to_add))
610
611 if ebuild_paths_to_remove:
612 logging.info(
613 "Removing old ebuild paths %s in overlay %s.",
614 ebuild_paths_to_remove,
615 overlay,
616 )
617 git.RunGit(
618 overlay, ["rm", "-f"] + list(ebuild_paths_to_remove)
619 )
620
621 if messages:
622 portage_util.EBuild.CommitChange(
623 "\n\n".join(messages), overlay
624 )
625
626
627def _WorkOnEbuild(
628 overlay,
629 ebuild,
630 manifest,
631 options,
632 ebuild_paths_to_add,
633 ebuild_paths_to_remove,
634 messages,
635 revved_packages,
636 new_package_atoms,
637 reject_self_repo=True,
638):
639 """Work on a single ebuild.
640
641 Args:
Alex Klein68b270c2023-04-14 14:42:50 -0600642 overlay: The overlay where the ebuild belongs to.
643 ebuild: The ebuild to work on.
644 manifest: The manifest of the given source root.
645 options: The options object returned by the argument parser.
646 ebuild_paths_to_add: New stable ebuild paths to add to git.
647 ebuild_paths_to_remove: Old ebuild paths to remove from git.
648 messages: A share list of commit messages.
649 revved_packages: A shared list of revved packages.
650 new_package_atoms: A shared list of new package atoms.
651 reject_self_repo: Whether to abort if the ebuild lives in the same git
652 repo as it is tracking for uprevs.
Alex Klein1699fab2022-09-08 08:46:06 -0600653 """
654 if options.verbose:
655 logging.info(
656 "Working on %s, info %s", ebuild.package, ebuild.cros_workon_vars
657 )
658 if not ebuild.cros_workon_vars:
659 logging.warning(
660 "%s: unable to parse workon settings", ebuild.ebuild_path
661 )
662
663 try:
664 result = ebuild.RevWorkOnEBuild(
665 os.path.join(options.buildroot, "src"),
666 manifest,
667 reject_self_repo=reject_self_repo,
668 )
669 if result:
670 new_package, ebuild_path_to_add, ebuild_path_to_remove = result
671
672 if ebuild_path_to_add:
673 ebuild_paths_to_add.append(ebuild_path_to_add)
674 if ebuild_path_to_remove:
675 ebuild_paths_to_remove.append(ebuild_path_to_remove)
676
677 messages.append(_GIT_COMMIT_MESSAGE % ebuild.package)
678
679 if options.list_revisions:
680 info = ebuild.GetSourceInfo(
681 os.path.join(options.buildroot, "src"),
682 manifest,
683 reject_self_repo=reject_self_repo,
684 )
685 srcdirs = [
686 os.path.join(options.buildroot, "src", srcdir)
687 for srcdir in ebuild.cros_workon_vars.localname
688 ]
689 old_commit_ids = dict(
690 zip(srcdirs, ebuild.cros_workon_vars.commit.split(","))
691 )
692 git_log = []
693 for srcdir in info.srcdirs:
694 old_commit_id = old_commit_ids.get(srcdir)
695 new_commit_id = ebuild.GetCommitId(srcdir)
696 if not old_commit_id or old_commit_id == new_commit_id:
697 continue
698
699 logs = git.RunGit(
700 srcdir,
701 [
702 "log",
703 "%s..%s" % (old_commit_id[:8], new_commit_id[:8]),
704 "--pretty=format:%h %<(63,trunc)%s",
705 ],
706 )
707 git_log.append("$ " + logs.cmdstr)
708 git_log.extend(
709 line.strip() for line in logs.stdout.splitlines()
710 )
711 if git_log:
712 messages.append("\n".join(git_log))
713
714 revved_packages.append(ebuild.package)
715 new_package_atoms.append("=%s" % new_package)
716 except portage_util.InvalidUprevSourceError as e:
717 logging.error(
718 "An error occurred while uprevving %s: %s", ebuild.package, e
719 )
720 raise
721 except portage_util.EbuildVersionError as e:
722 logging.warning("Unable to rev %s: %s", ebuild.package, e)
723 raise
724 except OSError:
725 logging.warning(
726 "Cannot rev %s\n"
727 "Note you will have to go into %s "
728 "and reset the git repo yourself.",
729 ebuild.package,
730 overlay,
731 )
732 raise