blob: a89e6d7a533d16b0fdaaff26b39aa6e42cf3c136 [file] [log] [blame]
Mike Frysinger110750a2012-03-26 14:19:20 -04001# Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
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.
23GIT_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.
26_GIT_COMMIT_MESSAGE = 'Marking 9999 ebuild for %s as stable.'
27
Chris Sosadad0d322011-01-31 16:37:33 -080028# Dictionary of valid commands with usage information.
29COMMAND_DICTIONARY = {
Mike Frysinger5cd8c742013-10-11 14:43:01 -040030 'commit': 'Marks given ebuilds as stable locally',
31 'push': 'Pushes previous marking of ebuilds to remote repo',
32}
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):
Chris Sosabf153872011-04-28 14:21:09 -070039 """Cleans up stale package info from a previous build.
Mike Frysinger5cd8c742013-10-11 14:43:01 -040040
Chris Sosabf153872011-04-28 14:21:09 -070041 Args:
David James41124af2015-06-04 21:13:25 -070042 srcroot: Root directory of the source tree.
David Jamescc09c9b2012-01-26 22:10:13 -080043 boards: Boards to clean the packages from.
Mike Frysingerde5ab0e2013-03-21 20:48:36 -040044 package_atoms: A list of package atoms to unmerge.
Chris Sosabf153872011-04-28 14:21:09 -070045 """
David James15ed1302013-04-25 09:21:19 -070046 if package_atoms:
Lann Martinffb95162018-08-28 12:02:54 -060047 logging.info('Cleaning up stale packages %s.', package_atoms)
David James15ed1302013-04-25 09:21:19 -070048
Mike Frysingerb7ab9b82012-04-04 16:22:43 -040049 # 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
Mike Frysinger45602c72019-09-22 02:15:11 -040055 runcmd = cros_build_lib.run
Mike Frysingerb7ab9b82012-04-04 16:22:43 -040056 else:
57 suffix = ''
Mike Frysinger45602c72019-09-22 02:15:11 -040058 runcmd = cros_build_lib.sudo_run
Chris Sosadad0d322011-01-31 16:37:33 -080059
David James59a0a2b2013-03-22 14:04:44 -070060 emerge, eclean = 'emerge' + suffix, 'eclean' + suffix
61 if not osutils.FindMissingBinaries([emerge, eclean]):
David James63841a82014-01-16 14:39:24 -080062 if package_atoms:
63 # If nothing was found to be unmerged, emerge will exit(1).
Don Garrett7100fff2018-10-23 11:07:13 -070064 result = runcmd([emerge, '-q', '--unmerge'] + list(package_atoms),
David James41124af2015-06-04 21:13:25 -070065 enter_chroot=True, extra_env={'CLEAN_DELAY': '0'},
Mike Frysingerf5a3b2d2019-12-12 14:36:17 -050066 check=False, cwd=srcroot)
Mike Frysinger01504112019-08-24 19:35:24 -040067 if result.returncode not in (0, 1):
David James63841a82014-01-16 14:39:24 -080068 raise cros_build_lib.RunCommandError('unexpected error', result)
David James59a0a2b2013-03-22 14:04:44 -070069 runcmd([eclean, '-d', 'packages'],
David James41124af2015-06-04 21:13:25 -070070 cwd=srcroot, enter_chroot=True,
Mike Frysinger0282d222019-12-17 17:15:48 -050071 stdout=True, stderr=True)
Mike Frysingerb7ab9b82012-04-04 16:22:43 -040072
73 tasks = []
David Jamescc09c9b2012-01-26 22:10:13 -080074 for board in boards:
Mike Frysingerb7ab9b82012-04-04 16:22:43 -040075 tasks.append([board])
76 tasks.append([None])
77
David James6450a0a2012-12-04 07:59:53 -080078 parallel.RunTasksInProcessPool(_CleanStalePackages, tasks)
Chris Sosadad0d322011-01-31 16:37:33 -080079
80
Mike Frysinger2ebe3732012-05-08 17:04:12 -040081# TODO(build): This code needs to be gutted and rebased to cros_build_lib.
82def _DoWeHaveLocalCommits(stable_branch, tracking_branch, cwd):
Chris Sosadad0d322011-01-31 16:37:33 -080083 """Returns true if there are local commits."""
David James97d95872012-11-16 15:09:56 -080084 output = git.RunGit(
Mike Frysinger876a8e52022-06-23 18:07:30 -040085 cwd, ['rev-parse', stable_branch, tracking_branch]).stdout.split()
Brian Harring5b86b5e2012-05-25 18:27:40 -070086 return output[0] != output[1]
Chris Sosadad0d322011-01-31 16:37:33 -080087
88
Chris Sosadad0d322011-01-31 16:37:33 -080089# ======================= End Global Helper Functions ========================
90
91
Ningning Xia52009062016-05-09 14:33:51 -070092def PushChange(stable_branch, tracking_branch, dryrun, cwd,
93 staging_branch=None):
Chris Sosadad0d322011-01-31 16:37:33 -080094 """Pushes commits in the stable_branch to the remote git repository.
95
David Jamesee2da622012-02-23 09:32:16 -080096 Pushes local commits from calls to CommitChange to the remote git
David James66009462012-03-25 10:08:38 -070097 repository specified by current working directory. If changes are
98 found to commit, they will be merged to the merge branch and pushed.
99 In that case, the local repository will be left on the merge branch.
Chris Sosadad0d322011-01-31 16:37:33 -0800100
101 Args:
102 stable_branch: The local branch with commits we want to push.
103 tracking_branch: The tracking branch of the local branch.
Chris Sosa62ad8522011-03-08 17:46:17 -0800104 dryrun: Use git push --dryrun to emulate a push.
Mike Frysinger2ebe3732012-05-08 17:04:12 -0400105 cwd: The directory to run commands in.
Ningning Xia52009062016-05-09 14:33:51 -0700106 staging_branch: The staging branch to push for a failed PFQ run
Mike Frysinger1a736a82013-12-12 01:50:59 -0500107
Chris Sosadad0d322011-01-31 16:37:33 -0800108 Raises:
Mike Frysinger5cd8c742013-10-11 14:43:01 -0400109 OSError: Error occurred while pushing.
Chris Sosadad0d322011-01-31 16:37:33 -0800110 """
David James47959632015-10-23 07:56:01 -0700111 if not git.DoesCommitExistInRepo(cwd, stable_branch):
112 logging.debug('No branch created for %s. Exiting', cwd)
113 return
114
Mike Frysinger2ebe3732012-05-08 17:04:12 -0400115 if not _DoWeHaveLocalCommits(stable_branch, tracking_branch, cwd):
David James47959632015-10-23 07:56:01 -0700116 logging.debug('No work found to push in %s. Exiting', cwd)
Chris Sosadad0d322011-01-31 16:37:33 -0800117 return
118
David James66009462012-03-25 10:08:38 -0700119 # For the commit queue, our local branch may contain commits that were
120 # just tested and pushed during the CommitQueueCompletion stage. Sync
121 # and rebase our local branch on top of the remote commits.
Paul Hobbs72d8e392015-10-21 17:24:23 -0700122 remote_ref = git.GetTrackingBranch(cwd,
123 branch=stable_branch,
124 for_push=True)
Paul Hobbs1e46be82015-10-30 13:46:02 -0700125 # SyncPushBranch rebases HEAD onto the updated remote. We need to checkout
126 # stable_branch here in order to update it.
127 git.RunGit(cwd, ['checkout', stable_branch])
Don Garrett99449592015-03-25 11:01:30 -0700128 git.SyncPushBranch(cwd, remote_ref.remote, remote_ref.ref)
David James66009462012-03-25 10:08:38 -0700129
130 # Check whether any local changes remain after the sync.
Don Garrett99449592015-03-25 11:01:30 -0700131 if not _DoWeHaveLocalCommits(stable_branch, remote_ref.ref, cwd):
Ralph Nathan03047282015-03-23 11:09:32 -0700132 logging.info('All changes already pushed for %s. Exiting', cwd)
David James66009462012-03-25 10:08:38 -0700133 return
134
LaMont Jonese708e402021-06-10 08:54:30 -0600135 # Add a failsafe check here. Only CLs from these users should be here.
136 # - 'chrome-bot',
137 # - 'chromeos-ci-prod'
138 # - 'chromeos-ci-release'
139 # If any other CLs are found then complain. In dryruns extra CLs are normal,
140 # though, and can be ignored.
Andrew Lamb7ef2c0b2019-07-17 09:43:27 -0600141 bad_cl_cmd = [
142 'log', '--format=short', '--perl-regexp', '--author',
LaMont Jonese708e402021-06-10 08:54:30 -0600143 '^(?!chrome-bot|chromeos-ci-prod|chromeos-ci-release)',
Andrew Lamb7ef2c0b2019-07-17 09:43:27 -0600144 '%s..%s' % (remote_ref.ref, stable_branch)
145 ]
Mike Frysinger876a8e52022-06-23 18:07:30 -0400146 bad_cls = git.RunGit(cwd, bad_cl_cmd).stdout
Matt Tennantcb522052013-11-25 14:23:43 -0800147 if bad_cls.strip() and not dryrun:
Andrew Lamb7ef2c0b2019-07-17 09:43:27 -0600148 logging.error(
149 'The Uprev stage found changes from users other than '
LaMont Jonese708e402021-06-10 08:54:30 -0600150 'chrome-bot or chromeos-ci-prod or chromeos-ci-release:\n\n%s', bad_cls)
Matt Tennantcb522052013-11-25 14:23:43 -0800151 raise AssertionError('Unexpected CLs found during uprev stage.')
152
Lev Rumyantsev25352ba2016-09-07 15:53:58 -0700153 if staging_branch is not None:
154 logging.info('PFQ FAILED. Pushing uprev change to staging branch %s',
155 staging_branch)
156
Mike Frysingere65f3752014-12-08 00:46:39 -0500157 description = git.RunGit(
158 cwd,
159 ['log', '--format=format:%s%n%n%b',
Mike Frysinger876a8e52022-06-23 18:07:30 -0400160 '%s..%s' % (remote_ref.ref, stable_branch)]).stdout
Gabe Black71e963e2014-10-28 20:19:59 -0700161 description = '%s\n\n%s' % (GIT_COMMIT_SUBJECT, description)
Ralph Nathan03047282015-03-23 11:09:32 -0700162 logging.info('For %s, using description %s', cwd, description)
Paul Hobbsf52ea8f2015-10-21 17:24:23 -0700163 git.CreatePushBranch(constants.MERGE_BRANCH, cwd,
164 remote_push_branch=remote_ref)
David James97d95872012-11-16 15:09:56 -0800165 git.RunGit(cwd, ['merge', '--squash', stable_branch])
166 git.RunGit(cwd, ['commit', '-m', description])
167 git.RunGit(cwd, ['config', 'push.default', 'tracking'])
Sergey Frolov0161f8b2021-07-07 17:41:10 -0600168
169 # Run git.PushBranch and retry up to 5 times.
170 # retry_util.RetryCommand will only retry on RunCommandErrors,
171 # which would be thrown by git.PushBranch when it gets to
172 # cros_build_lib.run()'ning the actual git command,
173 # which may fail with a transient HTTP 429 Too Many Requests error,
174 # and we need to retry on that.
175 # Do not retry if it fails to setup before cros_build_lib.run
176 # or upon other errors, like getting SIGINT.
177 max_retries = 5
178 retry_util.RetryCommand(
179 git.PushBranch,
180 max_retries,
181 constants.MERGE_BRANCH,
182 cwd,
183 dryrun=dryrun,
184 staging_branch=staging_branch,
185 sleep=15,
186 log_retries=True,
187 )
Chris Sosadad0d322011-01-31 16:37:33 -0800188
189
190class GitBranch(object):
191 """Wrapper class for a git branch."""
192
Mike Frysinger2ebe3732012-05-08 17:04:12 -0400193 def __init__(self, branch_name, tracking_branch, cwd):
David Jamesc7c4ff52013-09-18 17:57:13 -0700194 """Sets up variables but does not create the branch.
195
Mike Frysinger5cd8c742013-10-11 14:43:01 -0400196 Args:
David Jamesc7c4ff52013-09-18 17:57:13 -0700197 branch_name: The name of the branch.
198 tracking_branch: The associated tracking branch.
199 cwd: The git repository to work in.
200 """
Chris Sosadad0d322011-01-31 16:37:33 -0800201 self.branch_name = branch_name
202 self.tracking_branch = tracking_branch
Mike Frysinger2ebe3732012-05-08 17:04:12 -0400203 self.cwd = cwd
Chris Sosadad0d322011-01-31 16:37:33 -0800204
205 def CreateBranch(self):
Mike Frysinger2ebe3732012-05-08 17:04:12 -0400206 self.Checkout()
Chris Sosadad0d322011-01-31 16:37:33 -0800207
Mike Frysinger2ebe3732012-05-08 17:04:12 -0400208 def Checkout(self, branch=None):
Chris Sosadad0d322011-01-31 16:37:33 -0800209 """Function used to check out to another GitBranch."""
Mike Frysinger2ebe3732012-05-08 17:04:12 -0400210 if not branch:
211 branch = self.branch_name
212 if branch == self.tracking_branch or self.Exists(branch):
Mike Frysingerb89977d2022-08-18 21:53:26 -0400213 git.RunGit(self.cwd, ['checkout', '-f', branch])
Chris Sosadad0d322011-01-31 16:37:33 -0800214 else:
Lann Martinb26e1292018-08-09 13:59:19 -0600215 repo = repo_util.Repository.MustFind(self.cwd)
216 repo.StartBranch(branch, projects=['.'], cwd=self.cwd)
Chris Sosadad0d322011-01-31 16:37:33 -0800217
Mike Frysinger2ebe3732012-05-08 17:04:12 -0400218 def Exists(self, branch=None):
Chris Sosadad0d322011-01-31 16:37:33 -0800219 """Returns True if the branch exists."""
Mike Frysinger2ebe3732012-05-08 17:04:12 -0400220 if not branch:
221 branch = self.branch_name
Mike Frysinger876a8e52022-06-23 18:07:30 -0400222 branches = git.RunGit(self.cwd, ['branch']).stdout
Mike Frysinger2ebe3732012-05-08 17:04:12 -0400223 return branch in branches.split()
Chris Sosadad0d322011-01-31 16:37:33 -0800224
225
Mike Frysingere8dcbfd2015-03-08 21:45:52 -0400226def GetParser():
227 """Creates the argparse parser."""
228 parser = commandline.ArgumentParser()
229 parser.add_argument('--all', action='store_true',
230 help='Mark all packages as stable.')
231 parser.add_argument('-b', '--boards', default='',
232 help='Colon-separated list of boards.')
Mike Nicholsf7f13a82019-01-11 17:11:04 +0000233 parser.add_argument('--drop_file',
234 help='File to list packages that were revved.')
Mike Frysingere8dcbfd2015-03-08 21:45:52 -0400235 parser.add_argument('--dryrun', action='store_true',
236 help='Passes dry-run to git push if pushing a change.')
Bertrand SIMONNET6af54302015-08-05 10:12:49 -0700237 parser.add_argument('--force', action='store_true',
Nicolas Boichatde92a6d2021-03-31 16:43:50 +0800238 help='Force the stabilization of packages marked for '
239 'manual uprev. '
Bertrand SIMONNET6af54302015-08-05 10:12:49 -0700240 '(only compatible with -p)')
Sam McNallyeb5e2052018-09-05 16:34:55 +1000241 parser.add_argument('--list_revisions', action='store_true',
242 help='List all revisions included in the commit message.')
Mike Frysingere8dcbfd2015-03-08 21:45:52 -0400243 parser.add_argument('-o', '--overlays',
244 help='Colon-separated list of overlays to modify.')
Don Garrettf9eff952018-08-10 16:50:04 -0700245 parser.add_argument('--overlay-type',
246 help='Populates --overlays based on "public", "private"'
247 ', or "both".')
Mike Frysingere8dcbfd2015-03-08 21:45:52 -0400248 parser.add_argument('-p', '--packages',
249 help='Colon separated list of packages to rev.')
Don Garrett4fef8c32018-08-10 18:04:01 -0700250 parser.add_argument('--buildroot', type='path',
251 help='Path to buildroot.')
Mike Frysingere8dcbfd2015-03-08 21:45:52 -0400252 parser.add_argument('-r', '--srcroot', type='path',
Don Garrett4fef8c32018-08-10 18:04:01 -0700253 help='Path to root src. Deprecated in favor of '
254 '--buildroot')
Ningning Xia52009062016-05-09 14:33:51 -0700255 parser.add_argument('--staging_branch',
256 help='The staging branch to push changes')
Mike Frysinger1f4478c2019-10-20 18:33:17 -0400257 parser.add_argument('command', choices=sorted(COMMAND_DICTIONARY),
Mike Frysingere8dcbfd2015-03-08 21:45:52 -0400258 help='Command to run.')
259 return parser
260
261
262def main(argv):
263 parser = GetParser()
264 options = parser.parse_args(argv)
Don Garrett4fef8c32018-08-10 18:04:01 -0700265
266 # TODO: Remove this code in favor of a simple default on buildroot when
267 # srcroot is removed.
268 if options.srcroot and not options.buildroot:
269 # Convert /<repo>/src -> <repo>
270 options.buildroot = os.path.dirname(options.srcroot)
271 if not options.buildroot:
272 options.buildroot = constants.SOURCE_ROOT
273 options.srcroot = None
274
Bertrand SIMONNET6af54302015-08-05 10:12:49 -0700275 options.Freeze()
Mike Frysingere8dcbfd2015-03-08 21:45:52 -0400276
Bertrand SIMONNET6af54302015-08-05 10:12:49 -0700277 if options.command == 'commit':
278 if not options.packages and not options.all:
279 parser.error('Please specify at least one package (--packages)')
280 if options.force and options.all:
281 parser.error('Cannot use --force with --all. You must specify a list of '
282 'packages you want to force uprev.')
283
Don Garrett4fef8c32018-08-10 18:04:01 -0700284 if not os.path.isdir(options.buildroot):
285 parser.error('buildroot is not a valid path: %s' % options.buildroot)
Mike Frysingere8dcbfd2015-03-08 21:45:52 -0400286
Don Garrettf9eff952018-08-10 16:50:04 -0700287 if options.overlay_type and options.overlays:
288 parser.error('Cannot use --overlay-type with --overlays.')
289
Alex Deymo075c2292014-09-04 18:31:50 -0700290 portage_util.EBuild.VERBOSE = options.verbose
Chris Sosa62ad8522011-03-08 17:46:17 -0800291
Chris Sosa62ad8522011-03-08 17:46:17 -0800292 package_list = None
293 if options.packages:
294 package_list = options.packages.split(':')
295
Ningning Xiadb884322018-01-26 16:27:06 -0800296 overlays = []
Chris Sosa62ad8522011-03-08 17:46:17 -0800297 if options.overlays:
Chris Sosa62ad8522011-03-08 17:46:17 -0800298 for path in options.overlays.split(':'):
Ryan Cui05a31ba2011-05-31 17:47:37 -0700299 if not os.path.isdir(path):
Chris Sosac13bba52011-05-24 15:14:09 -0700300 cros_build_lib.Die('Cannot find overlay: %s' % path)
Ningning Xiadb884322018-01-26 16:27:06 -0800301 overlays.append(os.path.realpath(path))
Don Garrettf9eff952018-08-10 16:50:04 -0700302 elif options.overlay_type:
303 overlays = portage_util.FindOverlays(
Don Garrett4fef8c32018-08-10 18:04:01 -0700304 options.overlay_type, buildroot=options.buildroot)
Chris Sosadad0d322011-01-31 16:37:33 -0800305 else:
Ralph Nathan446aee92015-03-23 14:44:56 -0700306 logging.warning('Missing --overlays argument')
Ningning Xiadb884322018-01-26 16:27:06 -0800307 overlays.extend([
Don Garrett4fef8c32018-08-10 18:04:01 -0700308 '%s/src/private-overlays/chromeos-overlay' % options.buildroot,
309 '%s/src/third_party/chromiumos-overlay' % options.buildroot])
Chris Sosadad0d322011-01-31 16:37:33 -0800310
Don Garrett4fef8c32018-08-10 18:04:01 -0700311 manifest = git.ManifestCheckout.Cached(options.buildroot)
Ryan Cui4656a3c2011-05-24 12:30:30 -0700312
Ningning Xia419e4eb2018-02-05 10:30:36 -0800313 # Dict mapping from each overlay to its tracking branch.
314 overlay_tracking_branch = {}
315 # Dict mapping from each git repository (project) to a list of its overlays.
316 git_project_overlays = {}
317
318 for overlay in overlays:
319 remote_ref = git.GetTrackingBranchViaManifest(overlay, manifest=manifest)
320 overlay_tracking_branch[overlay] = remote_ref.ref
321 git_project_overlays.setdefault(remote_ref.project_name, []).append(overlay)
322
323 if options.command == 'push':
324 _WorkOnPush(options, overlay_tracking_branch, git_project_overlays)
325 elif options.command == 'commit':
326 _WorkOnCommit(options, overlays, overlay_tracking_branch,
327 git_project_overlays, manifest, package_list)
328
329
330def _WorkOnPush(options, overlay_tracking_branch, git_project_overlays):
331 """Push uprevs of overlays belonging to differet git projects in parallel.
332
333 Args:
334 options: The options object returned by the argument parser.
335 overlay_tracking_branch: A dict mapping from each overlay to its tracking
336 branch.
337 git_project_overlays: A dict mapping from each git repository to a list of
338 its overlays.
339 """
340 inputs = [[options, overlays_per_project, overlay_tracking_branch]
Mike Frysinger0bdbc102019-06-13 15:27:29 -0400341 for overlays_per_project in git_project_overlays.values()]
Ningning Xia419e4eb2018-02-05 10:30:36 -0800342 parallel.RunTasksInProcessPool(_PushOverlays, inputs)
343
344
345def _PushOverlays(options, overlays, overlay_tracking_branch):
346 """Push uprevs for overlays in sequence.
347
348 Args:
349 options: The options object returned by the argument parser.
350 overlays: A list of overlays to push uprevs in sequence.
351 overlay_tracking_branch: A dict mapping from each overlay to its tracking
352 branch.
353 """
354 for overlay in overlays:
355 if not os.path.isdir(overlay):
356 logging.warning('Skipping %s, which is not a directory.', overlay)
357 continue
358
359 tracking_branch = overlay_tracking_branch[overlay]
360 PushChange(constants.STABLE_EBUILD_BRANCH, tracking_branch, options.dryrun,
361 cwd=overlay, staging_branch=options.staging_branch)
362
363
364def _WorkOnCommit(options, overlays, overlay_tracking_branch,
365 git_project_overlays, manifest, package_list):
366 """Commit uprevs of overlays belonging to different git projects in parallel.
367
368 Args:
369 options: The options object returned by the argument parser.
370 overlays: A list of overlays to work on.
371 overlay_tracking_branch: A dict mapping from each overlay to its tracking
372 branch.
373 git_project_overlays: A dict mapping from each git repository to a list of
374 its overlays.
375 manifest: The manifest of the given source root.
376 package_list: A list of packages passed from commandline to work on.
377 """
Mike Frysinger62ff8d72020-05-19 03:06:51 -0400378 # We cleaned up self referential ebuilds by this version, but don't enforce
379 # the check on older ones to avoid breaking factory/firmware branches.
Ram Chandrasekar60f69f32022-06-03 22:49:30 +0000380 root_version = chromeos_version.VersionInfo.from_repo(options.buildroot)
381 no_self_repos_version = chromeos_version.VersionInfo('13099.0.0')
Mike Frysinger62ff8d72020-05-19 03:06:51 -0400382 reject_self_repo = root_version >= no_self_repos_version
383
Ningning Xia419e4eb2018-02-05 10:30:36 -0800384 overlay_ebuilds = _GetOverlayToEbuildsMap(options, overlays, package_list)
David James84e953c2013-04-23 18:44:06 -0700385
Ningning Xia783efc02018-01-24 13:39:51 -0800386 with parallel.Manager() as manager:
387 # Contains the array of packages we actually revved.
388 revved_packages = manager.list()
389 new_package_atoms = manager.list()
David Jamesa8457b52011-05-28 00:03:20 -0700390
Ningning Xia419e4eb2018-02-05 10:30:36 -0800391 inputs = [[options, manifest, overlays_per_project, overlay_tracking_branch,
Mike Frysinger62ff8d72020-05-19 03:06:51 -0400392 overlay_ebuilds, revved_packages, new_package_atoms,
393 reject_self_repo]
Mike Frysinger0bdbc102019-06-13 15:27:29 -0400394 for overlays_per_project in git_project_overlays.values()]
Ningning Xia419e4eb2018-02-05 10:30:36 -0800395 parallel.RunTasksInProcessPool(_CommitOverlays, inputs)
Chris Sosadad0d322011-01-31 16:37:33 -0800396
Don Garrett4fef8c32018-08-10 18:04:01 -0700397 chroot_path = os.path.join(options.buildroot, constants.DEFAULT_CHROOT_DIR)
Ningning Xia419e4eb2018-02-05 10:30:36 -0800398 if os.path.exists(chroot_path):
Don Garrett4fef8c32018-08-10 18:04:01 -0700399 CleanStalePackages(options.buildroot, options.boards.split(':'),
Ningning Xia419e4eb2018-02-05 10:30:36 -0800400 new_package_atoms)
Mike Nicholsf7f13a82019-01-11 17:11:04 +0000401 if options.drop_file:
402 osutils.WriteFile(options.drop_file, ' '.join(revved_packages))
Chris Sosadad0d322011-01-31 16:37:33 -0800403
Brian Harring609dc4e2012-05-07 02:17:44 -0700404
Ningning Xia419e4eb2018-02-05 10:30:36 -0800405def _GetOverlayToEbuildsMap(options, overlays, package_list):
406 """Get ebuilds for overlays.
David James15ed1302013-04-25 09:21:19 -0700407
Ningning Xia783efc02018-01-24 13:39:51 -0800408 Args:
Ningning Xia783efc02018-01-24 13:39:51 -0800409 options: The options object returned by the argument parser.
Ningning Xia419e4eb2018-02-05 10:30:36 -0800410 overlays: A list of overlays to work on.
411 package_list: A list of packages passed from commandline to work on.
412
413 Returns:
414 A dict mapping each overlay to a list of ebuilds belonging to it.
415 """
Ram Chandrasekar60f69f32022-06-03 22:49:30 +0000416 root_version = chromeos_version.VersionInfo.from_repo(options.buildroot)
417 subdir_removal = chromeos_version.VersionInfo('10363.0.0')
Don Garrett3dbb2932018-10-02 14:41:26 -0700418 require_subdir_support = root_version < subdir_removal
419
Ningning Xia419e4eb2018-02-05 10:30:36 -0800420 overlay_ebuilds = {}
Don Garrett3dbb2932018-10-02 14:41:26 -0700421 inputs = [[overlay, options.all, package_list, options.force,
422 require_subdir_support]
Ningning Xia419e4eb2018-02-05 10:30:36 -0800423 for overlay in overlays]
424 result = parallel.RunTasksInProcessPool(
425 portage_util.GetOverlayEBuilds, inputs)
426 for idx, ebuilds in enumerate(result):
427 overlay_ebuilds[overlays[idx]] = ebuilds
428
429 return overlay_ebuilds
430
431
432def _CommitOverlays(options, manifest, overlays, overlay_tracking_branch,
Mike Frysinger62ff8d72020-05-19 03:06:51 -0400433 overlay_ebuilds, revved_packages, new_package_atoms,
434 reject_self_repo=True):
Ningning Xia419e4eb2018-02-05 10:30:36 -0800435 """Commit uprevs for overlays in sequence.
436
437 Args:
438 options: The options object returned by the argument parser.
439 manifest: The manifest of the given source root.
440 overlays: A list over overlays to commit.
441 overlay_tracking_branch: A dict mapping from each overlay to its tracking
442 branch.
443 overlay_ebuilds: A dict mapping overlays to their ebuilds.
Ningning Xia783efc02018-01-24 13:39:51 -0800444 revved_packages: A shared list of revved packages.
445 new_package_atoms: A shared list of new package atoms.
Mike Frysinger62ff8d72020-05-19 03:06:51 -0400446 reject_self_repo: Whether to abort if the ebuild lives in the same git
447 repo as it is tracking for uprevs.
Ningning Xia783efc02018-01-24 13:39:51 -0800448 """
Ningning Xia419e4eb2018-02-05 10:30:36 -0800449 for overlay in overlays:
450 if not os.path.isdir(overlay):
451 logging.warning('Skipping %s, which is not a directory.', overlay)
452 continue
Ningning Xia783efc02018-01-24 13:39:51 -0800453
Ningning Xia419e4eb2018-02-05 10:30:36 -0800454 # Note we intentionally work from the non push tracking branch;
455 # everything built thus far has been against it (meaning, http mirrors),
456 # thus we should honor that. During the actual push, the code switches
457 # to the correct urls, and does an appropriate rebasing.
458 tracking_branch = overlay_tracking_branch[overlay]
Ningning Xia783efc02018-01-24 13:39:51 -0800459
Ningning Xia783efc02018-01-24 13:39:51 -0800460 existing_commit = git.GetGitRepoRevision(overlay)
Lann Martine0ef98c2018-06-11 13:12:24 -0600461
462 # Make sure we run in the top-level git directory in case we are
463 # adding/removing an overlay in existing_commit.
464 git_root = git.FindGitTopLevel(overlay)
465 if git_root is None:
466 cros_build_lib.Die('No git repo at overlay directory %s.', overlay)
467
Ningning Xia783efc02018-01-24 13:39:51 -0800468 work_branch = GitBranch(constants.STABLE_EBUILD_BRANCH, tracking_branch,
Lann Martine0ef98c2018-06-11 13:12:24 -0600469 cwd=git_root)
Ningning Xia783efc02018-01-24 13:39:51 -0800470 work_branch.CreateBranch()
471 if not work_branch.Exists():
472 cros_build_lib.Die('Unable to create stabilizing branch in %s' %
473 overlay)
474
475 # In the case of uprevving overlays that have patches applied to them,
476 # include the patched changes in the stabilizing branch.
Lann Martine0ef98c2018-06-11 13:12:24 -0600477 git.RunGit(git_root, ['rebase', existing_commit])
Ningning Xia783efc02018-01-24 13:39:51 -0800478
Ningning Xiadb884322018-01-26 16:27:06 -0800479 ebuilds = overlay_ebuilds.get(overlay, [])
Ningning Xia783efc02018-01-24 13:39:51 -0800480 if ebuilds:
Ningning Xia419e4eb2018-02-05 10:30:36 -0800481 with parallel.Manager() as manager:
482 # Contains the array of packages we actually revved.
483 messages = manager.list()
484 ebuild_paths_to_add = manager.list()
485 ebuild_paths_to_remove = manager.list()
Ningning Xia783efc02018-01-24 13:39:51 -0800486
Ningning Xia419e4eb2018-02-05 10:30:36 -0800487 inputs = [[overlay, ebuild, manifest, options, ebuild_paths_to_add,
488 ebuild_paths_to_remove, messages, revved_packages,
Mike Frysinger62ff8d72020-05-19 03:06:51 -0400489 new_package_atoms, reject_self_repo]
490 for ebuild in ebuilds]
Ningning Xia419e4eb2018-02-05 10:30:36 -0800491 parallel.RunTasksInProcessPool(_WorkOnEbuild, inputs)
Ningning Xia783efc02018-01-24 13:39:51 -0800492
Ningning Xia419e4eb2018-02-05 10:30:36 -0800493 if ebuild_paths_to_add:
494 logging.info('Adding new stable ebuild paths %s in overlay %s.',
495 ebuild_paths_to_add, overlay)
496 git.RunGit(overlay, ['add'] + list(ebuild_paths_to_add))
David James15ed1302013-04-25 09:21:19 -0700497
Ningning Xia419e4eb2018-02-05 10:30:36 -0800498 if ebuild_paths_to_remove:
499 logging.info('Removing old ebuild paths %s in overlay %s.',
500 ebuild_paths_to_remove, overlay)
501 git.RunGit(overlay, ['rm', '-f'] + list(ebuild_paths_to_remove))
502
503 if messages:
504 portage_util.EBuild.CommitChange('\n\n'.join(messages), overlay)
David James15ed1302013-04-25 09:21:19 -0700505
Ningning Xia783efc02018-01-24 13:39:51 -0800506
507def _WorkOnEbuild(overlay, ebuild, manifest, options, ebuild_paths_to_add,
508 ebuild_paths_to_remove, messages, revved_packages,
Mike Frysinger62ff8d72020-05-19 03:06:51 -0400509 new_package_atoms, reject_self_repo=True):
Ningning Xia783efc02018-01-24 13:39:51 -0800510 """Work on a single ebuild.
511
512 Args:
513 overlay: The overlay where the ebuild belongs to.
514 ebuild: The ebuild to work on.
515 manifest: The manifest of the given source root.
516 options: The options object returned by the argument parser.
517 ebuild_paths_to_add: New stable ebuild paths to add to git.
518 ebuild_paths_to_remove: Old ebuild paths to remove from git.
519 messages: A share list of commit messages.
520 revved_packages: A shared list of revved packages.
521 new_package_atoms: A shared list of new package atoms.
Mike Frysinger62ff8d72020-05-19 03:06:51 -0400522 reject_self_repo: Whether to abort if the ebuild lives in the same git
523 repo as it is tracking for uprevs.
Ningning Xia783efc02018-01-24 13:39:51 -0800524 """
525 if options.verbose:
526 logging.info('Working on %s, info %s', ebuild.package,
527 ebuild.cros_workon_vars)
Mike Frysinger00ba05a2020-06-12 02:44:02 -0400528 if not ebuild.cros_workon_vars:
529 logging.warning('%s: unable to parse workon settings', ebuild.ebuild_path)
530
Ningning Xia783efc02018-01-24 13:39:51 -0800531 try:
Don Garrett4fef8c32018-08-10 18:04:01 -0700532 result = ebuild.RevWorkOnEBuild(os.path.join(options.buildroot, 'src'),
Mike Frysinger62ff8d72020-05-19 03:06:51 -0400533 manifest, reject_self_repo=reject_self_repo)
Ningning Xia783efc02018-01-24 13:39:51 -0800534 if result:
535 new_package, ebuild_path_to_add, ebuild_path_to_remove = result
536
537 if ebuild_path_to_add:
538 ebuild_paths_to_add.append(ebuild_path_to_add)
539 if ebuild_path_to_remove:
540 ebuild_paths_to_remove.append(ebuild_path_to_remove)
541
542 messages.append(_GIT_COMMIT_MESSAGE % ebuild.package)
Sam McNallyeb5e2052018-09-05 16:34:55 +1000543
544 if options.list_revisions:
545 info = ebuild.GetSourceInfo(os.path.join(options.buildroot, 'src'),
Mike Frysinger62ff8d72020-05-19 03:06:51 -0400546 manifest, reject_self_repo=reject_self_repo)
Sam McNallyeb5e2052018-09-05 16:34:55 +1000547 srcdirs = [os.path.join(options.buildroot, 'src', srcdir)
548 for srcdir in ebuild.cros_workon_vars.localname]
549 old_commit_ids = dict(
550 zip(srcdirs, ebuild.cros_workon_vars.commit.split(',')))
551 git_log = []
552 for srcdir in info.srcdirs:
553 old_commit_id = old_commit_ids.get(srcdir)
554 new_commit_id = ebuild.GetCommitId(srcdir)
555 if not old_commit_id or old_commit_id == new_commit_id:
556 continue
557
558 logs = git.RunGit(srcdir, [
559 'log', '%s..%s' % (old_commit_id[:8], new_commit_id[:8]),
560 '--pretty=format:%h %<(63,trunc)%s'])
561 git_log.append('$ ' + logs.cmdstr)
Mike Frysinger876a8e52022-06-23 18:07:30 -0400562 git_log.extend(line.strip() for line in logs.stdout.splitlines())
Sam McNallyeb5e2052018-09-05 16:34:55 +1000563 if git_log:
564 messages.append('\n'.join(git_log))
565
Ningning Xia783efc02018-01-24 13:39:51 -0800566 revved_packages.append(ebuild.package)
567 new_package_atoms.append('=%s' % new_package)
David Burger8cf4a762020-03-09 10:33:38 -0600568 except portage_util.InvalidUprevSourceError as e:
569 logging.error('An error occurred while uprevving %s: %s',
570 ebuild.package, e)
571 raise
Alex Klein99920662019-10-14 15:30:15 -0600572 except portage_util.EbuildVersionError as e:
573 logging.warning('Unable to rev %s: %s', ebuild.package, e)
574 raise
Mike Frysingerb32cc472020-05-15 00:17:54 -0400575 except OSError:
Ningning Xia783efc02018-01-24 13:39:51 -0800576 logging.warning(
577 'Cannot rev %s\n'
578 'Note you will have to go into %s '
Ningning Xia419e4eb2018-02-05 10:30:36 -0800579 'and reset the git repo yourself.', ebuild.package, overlay)
Ningning Xia783efc02018-01-24 13:39:51 -0800580 raise