blob: 772977bc4cbba86d3d7c80d0453dec6e47abb1f1 [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 Sosadad0d322011-01-31 16:37:33 -08007import os
Chris Sosadad0d322011-01-31 16:37:33 -08008
Aviv Keshetb7519e12016-10-04 00:50:00 -07009from chromite.lib import constants
Mike Frysingere8dcbfd2015-03-08 21:45:52 -040010from chromite.lib import commandline
Chris Sosac13bba52011-05-24 15:14:09 -070011from chromite.lib import cros_build_lib
Ralph Nathan03047282015-03-23 11:09:32 -070012from chromite.lib import cros_logging as logging
David James97d95872012-11-16 15:09:56 -080013from chromite.lib import git
Mike Frysingerfddaeb52012-11-20 11:17:31 -050014from chromite.lib import osutils
David James6450a0a2012-12-04 07:59:53 -080015from chromite.lib import parallel
Alex Deymo075c2292014-09-04 18:31:50 -070016from chromite.lib import portage_util
Lann Martinb26e1292018-08-09 13:59:19 -060017from chromite.lib import repo_util
Chris Sosac13bba52011-05-24 15:14:09 -070018
Don Garrett3dbb2932018-10-02 14:41:26 -070019from chromite.cbuildbot import manifest_version
20
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(
Paul Hobbs72d8e392015-10-21 17:24:23 -070085 cwd, ['rev-parse', stable_branch, tracking_branch]).output.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
Andrew Lamb7ef2c0b2019-07-17 09:43:27 -0600135 # Add a failsafe check here. Only CLs from the 'chrome-bot' or
136 # 'chromeos-ci-prod' user should be involved here. If any other CLs are
137 # found then complain. In dryruns extra CLs are normal, though, and can
138 # be ignored.
139 bad_cl_cmd = [
140 'log', '--format=short', '--perl-regexp', '--author',
141 '^(?!chrome-bot|chromeos-ci-prod)',
142 '%s..%s' % (remote_ref.ref, stable_branch)
143 ]
Matt Tennantcb522052013-11-25 14:23:43 -0800144 bad_cls = git.RunGit(cwd, bad_cl_cmd).output
145 if bad_cls.strip() and not dryrun:
Andrew Lamb7ef2c0b2019-07-17 09:43:27 -0600146 logging.error(
147 'The Uprev stage found changes from users other than '
148 'chrome-bot or chromeos-ci-prod:\n\n%s', bad_cls)
Matt Tennantcb522052013-11-25 14:23:43 -0800149 raise AssertionError('Unexpected CLs found during uprev stage.')
150
Lev Rumyantsev25352ba2016-09-07 15:53:58 -0700151 if staging_branch is not None:
152 logging.info('PFQ FAILED. Pushing uprev change to staging branch %s',
153 staging_branch)
154
Mike Frysingere65f3752014-12-08 00:46:39 -0500155 description = git.RunGit(
156 cwd,
157 ['log', '--format=format:%s%n%n%b',
Don Garrett99449592015-03-25 11:01:30 -0700158 '%s..%s' % (remote_ref.ref, stable_branch)]).output
Gabe Black71e963e2014-10-28 20:19:59 -0700159 description = '%s\n\n%s' % (GIT_COMMIT_SUBJECT, description)
Ralph Nathan03047282015-03-23 11:09:32 -0700160 logging.info('For %s, using description %s', cwd, description)
Paul Hobbsf52ea8f2015-10-21 17:24:23 -0700161 git.CreatePushBranch(constants.MERGE_BRANCH, cwd,
162 remote_push_branch=remote_ref)
David James97d95872012-11-16 15:09:56 -0800163 git.RunGit(cwd, ['merge', '--squash', stable_branch])
164 git.RunGit(cwd, ['commit', '-m', description])
165 git.RunGit(cwd, ['config', 'push.default', 'tracking'])
Mike Nicholsa6818c52018-04-09 11:05:42 -0600166 git.PushBranch(constants.MERGE_BRANCH, cwd, dryrun=dryrun,
Sean Abraham11b57f82019-09-20 19:33:17 +0000167 staging_branch=staging_branch)
Chris Sosadad0d322011-01-31 16:37:33 -0800168
169
170class GitBranch(object):
171 """Wrapper class for a git branch."""
172
Mike Frysinger2ebe3732012-05-08 17:04:12 -0400173 def __init__(self, branch_name, tracking_branch, cwd):
David Jamesc7c4ff52013-09-18 17:57:13 -0700174 """Sets up variables but does not create the branch.
175
Mike Frysinger5cd8c742013-10-11 14:43:01 -0400176 Args:
David Jamesc7c4ff52013-09-18 17:57:13 -0700177 branch_name: The name of the branch.
178 tracking_branch: The associated tracking branch.
179 cwd: The git repository to work in.
180 """
Chris Sosadad0d322011-01-31 16:37:33 -0800181 self.branch_name = branch_name
182 self.tracking_branch = tracking_branch
Mike Frysinger2ebe3732012-05-08 17:04:12 -0400183 self.cwd = cwd
Chris Sosadad0d322011-01-31 16:37:33 -0800184
185 def CreateBranch(self):
Mike Frysinger2ebe3732012-05-08 17:04:12 -0400186 self.Checkout()
Chris Sosadad0d322011-01-31 16:37:33 -0800187
Mike Frysinger2ebe3732012-05-08 17:04:12 -0400188 def Checkout(self, branch=None):
Chris Sosadad0d322011-01-31 16:37:33 -0800189 """Function used to check out to another GitBranch."""
Mike Frysinger2ebe3732012-05-08 17:04:12 -0400190 if not branch:
191 branch = self.branch_name
192 if branch == self.tracking_branch or self.Exists(branch):
Lann Martinb26e1292018-08-09 13:59:19 -0600193 git.RunGit(self.cwd, ['checkout', '-f', branch], quiet=True)
Chris Sosadad0d322011-01-31 16:37:33 -0800194 else:
Lann Martinb26e1292018-08-09 13:59:19 -0600195 repo = repo_util.Repository.MustFind(self.cwd)
196 repo.StartBranch(branch, projects=['.'], cwd=self.cwd)
Chris Sosadad0d322011-01-31 16:37:33 -0800197
Mike Frysinger2ebe3732012-05-08 17:04:12 -0400198 def Exists(self, branch=None):
Chris Sosadad0d322011-01-31 16:37:33 -0800199 """Returns True if the branch exists."""
Mike Frysinger2ebe3732012-05-08 17:04:12 -0400200 if not branch:
201 branch = self.branch_name
David James67d73252013-09-19 17:33:12 -0700202 branches = git.RunGit(self.cwd, ['branch']).output
Mike Frysinger2ebe3732012-05-08 17:04:12 -0400203 return branch in branches.split()
Chris Sosadad0d322011-01-31 16:37:33 -0800204
205
Mike Frysingere8dcbfd2015-03-08 21:45:52 -0400206def GetParser():
207 """Creates the argparse parser."""
208 parser = commandline.ArgumentParser()
209 parser.add_argument('--all', action='store_true',
210 help='Mark all packages as stable.')
211 parser.add_argument('-b', '--boards', default='',
212 help='Colon-separated list of boards.')
Mike Nicholsf7f13a82019-01-11 17:11:04 +0000213 parser.add_argument('--drop_file',
214 help='File to list packages that were revved.')
Mike Frysingere8dcbfd2015-03-08 21:45:52 -0400215 parser.add_argument('--dryrun', action='store_true',
216 help='Passes dry-run to git push if pushing a change.')
Bertrand SIMONNET6af54302015-08-05 10:12:49 -0700217 parser.add_argument('--force', action='store_true',
Nicolas Boichatde92a6d2021-03-31 16:43:50 +0800218 help='Force the stabilization of packages marked for '
219 'manual uprev. '
Bertrand SIMONNET6af54302015-08-05 10:12:49 -0700220 '(only compatible with -p)')
Sam McNallyeb5e2052018-09-05 16:34:55 +1000221 parser.add_argument('--list_revisions', action='store_true',
222 help='List all revisions included in the commit message.')
Mike Frysingere8dcbfd2015-03-08 21:45:52 -0400223 parser.add_argument('-o', '--overlays',
224 help='Colon-separated list of overlays to modify.')
Don Garrettf9eff952018-08-10 16:50:04 -0700225 parser.add_argument('--overlay-type',
226 help='Populates --overlays based on "public", "private"'
227 ', or "both".')
Mike Frysingere8dcbfd2015-03-08 21:45:52 -0400228 parser.add_argument('-p', '--packages',
229 help='Colon separated list of packages to rev.')
Don Garrett4fef8c32018-08-10 18:04:01 -0700230 parser.add_argument('--buildroot', type='path',
231 help='Path to buildroot.')
Mike Frysingere8dcbfd2015-03-08 21:45:52 -0400232 parser.add_argument('-r', '--srcroot', type='path',
Don Garrett4fef8c32018-08-10 18:04:01 -0700233 help='Path to root src. Deprecated in favor of '
234 '--buildroot')
Ningning Xia52009062016-05-09 14:33:51 -0700235 parser.add_argument('--staging_branch',
236 help='The staging branch to push changes')
Mike Frysinger1f4478c2019-10-20 18:33:17 -0400237 parser.add_argument('command', choices=sorted(COMMAND_DICTIONARY),
Mike Frysingere8dcbfd2015-03-08 21:45:52 -0400238 help='Command to run.')
239 return parser
240
241
242def main(argv):
243 parser = GetParser()
244 options = parser.parse_args(argv)
Don Garrett4fef8c32018-08-10 18:04:01 -0700245
246 # TODO: Remove this code in favor of a simple default on buildroot when
247 # srcroot is removed.
248 if options.srcroot and not options.buildroot:
249 # Convert /<repo>/src -> <repo>
250 options.buildroot = os.path.dirname(options.srcroot)
251 if not options.buildroot:
252 options.buildroot = constants.SOURCE_ROOT
253 options.srcroot = None
254
Bertrand SIMONNET6af54302015-08-05 10:12:49 -0700255 options.Freeze()
Mike Frysingere8dcbfd2015-03-08 21:45:52 -0400256
Bertrand SIMONNET6af54302015-08-05 10:12:49 -0700257 if options.command == 'commit':
258 if not options.packages and not options.all:
259 parser.error('Please specify at least one package (--packages)')
260 if options.force and options.all:
261 parser.error('Cannot use --force with --all. You must specify a list of '
262 'packages you want to force uprev.')
263
Don Garrett4fef8c32018-08-10 18:04:01 -0700264 if not os.path.isdir(options.buildroot):
265 parser.error('buildroot is not a valid path: %s' % options.buildroot)
Mike Frysingere8dcbfd2015-03-08 21:45:52 -0400266
Don Garrettf9eff952018-08-10 16:50:04 -0700267 if options.overlay_type and options.overlays:
268 parser.error('Cannot use --overlay-type with --overlays.')
269
Alex Deymo075c2292014-09-04 18:31:50 -0700270 portage_util.EBuild.VERBOSE = options.verbose
Chris Sosa62ad8522011-03-08 17:46:17 -0800271
Chris Sosa62ad8522011-03-08 17:46:17 -0800272 package_list = None
273 if options.packages:
274 package_list = options.packages.split(':')
275
Ningning Xiadb884322018-01-26 16:27:06 -0800276 overlays = []
Chris Sosa62ad8522011-03-08 17:46:17 -0800277 if options.overlays:
Chris Sosa62ad8522011-03-08 17:46:17 -0800278 for path in options.overlays.split(':'):
Ryan Cui05a31ba2011-05-31 17:47:37 -0700279 if not os.path.isdir(path):
Chris Sosac13bba52011-05-24 15:14:09 -0700280 cros_build_lib.Die('Cannot find overlay: %s' % path)
Ningning Xiadb884322018-01-26 16:27:06 -0800281 overlays.append(os.path.realpath(path))
Don Garrettf9eff952018-08-10 16:50:04 -0700282 elif options.overlay_type:
283 overlays = portage_util.FindOverlays(
Don Garrett4fef8c32018-08-10 18:04:01 -0700284 options.overlay_type, buildroot=options.buildroot)
Chris Sosadad0d322011-01-31 16:37:33 -0800285 else:
Ralph Nathan446aee92015-03-23 14:44:56 -0700286 logging.warning('Missing --overlays argument')
Ningning Xiadb884322018-01-26 16:27:06 -0800287 overlays.extend([
Don Garrett4fef8c32018-08-10 18:04:01 -0700288 '%s/src/private-overlays/chromeos-overlay' % options.buildroot,
289 '%s/src/third_party/chromiumos-overlay' % options.buildroot])
Chris Sosadad0d322011-01-31 16:37:33 -0800290
Don Garrett4fef8c32018-08-10 18:04:01 -0700291 manifest = git.ManifestCheckout.Cached(options.buildroot)
Ryan Cui4656a3c2011-05-24 12:30:30 -0700292
Ningning Xia419e4eb2018-02-05 10:30:36 -0800293 # Dict mapping from each overlay to its tracking branch.
294 overlay_tracking_branch = {}
295 # Dict mapping from each git repository (project) to a list of its overlays.
296 git_project_overlays = {}
297
298 for overlay in overlays:
299 remote_ref = git.GetTrackingBranchViaManifest(overlay, manifest=manifest)
300 overlay_tracking_branch[overlay] = remote_ref.ref
301 git_project_overlays.setdefault(remote_ref.project_name, []).append(overlay)
302
303 if options.command == 'push':
304 _WorkOnPush(options, overlay_tracking_branch, git_project_overlays)
305 elif options.command == 'commit':
306 _WorkOnCommit(options, overlays, overlay_tracking_branch,
307 git_project_overlays, manifest, package_list)
308
309
310def _WorkOnPush(options, overlay_tracking_branch, git_project_overlays):
311 """Push uprevs of overlays belonging to differet git projects in parallel.
312
313 Args:
314 options: The options object returned by the argument parser.
315 overlay_tracking_branch: A dict mapping from each overlay to its tracking
316 branch.
317 git_project_overlays: A dict mapping from each git repository to a list of
318 its overlays.
319 """
320 inputs = [[options, overlays_per_project, overlay_tracking_branch]
Mike Frysinger0bdbc102019-06-13 15:27:29 -0400321 for overlays_per_project in git_project_overlays.values()]
Ningning Xia419e4eb2018-02-05 10:30:36 -0800322 parallel.RunTasksInProcessPool(_PushOverlays, inputs)
323
324
325def _PushOverlays(options, overlays, overlay_tracking_branch):
326 """Push uprevs for overlays in sequence.
327
328 Args:
329 options: The options object returned by the argument parser.
330 overlays: A list of overlays to push uprevs in sequence.
331 overlay_tracking_branch: A dict mapping from each overlay to its tracking
332 branch.
333 """
334 for overlay in overlays:
335 if not os.path.isdir(overlay):
336 logging.warning('Skipping %s, which is not a directory.', overlay)
337 continue
338
339 tracking_branch = overlay_tracking_branch[overlay]
340 PushChange(constants.STABLE_EBUILD_BRANCH, tracking_branch, options.dryrun,
341 cwd=overlay, staging_branch=options.staging_branch)
342
343
344def _WorkOnCommit(options, overlays, overlay_tracking_branch,
345 git_project_overlays, manifest, package_list):
346 """Commit uprevs of overlays belonging to different git projects in parallel.
347
348 Args:
349 options: The options object returned by the argument parser.
350 overlays: A list of overlays to work on.
351 overlay_tracking_branch: A dict mapping from each overlay to its tracking
352 branch.
353 git_project_overlays: A dict mapping from each git repository to a list of
354 its overlays.
355 manifest: The manifest of the given source root.
356 package_list: A list of packages passed from commandline to work on.
357 """
Mike Frysinger62ff8d72020-05-19 03:06:51 -0400358 # We cleaned up self referential ebuilds by this version, but don't enforce
359 # the check on older ones to avoid breaking factory/firmware branches.
360 root_version = manifest_version.VersionInfo.from_repo(options.buildroot)
361 no_self_repos_version = manifest_version.VersionInfo('13099.0.0')
362 reject_self_repo = root_version >= no_self_repos_version
363
Ningning Xia419e4eb2018-02-05 10:30:36 -0800364 overlay_ebuilds = _GetOverlayToEbuildsMap(options, overlays, package_list)
David James84e953c2013-04-23 18:44:06 -0700365
Ningning Xia783efc02018-01-24 13:39:51 -0800366 with parallel.Manager() as manager:
367 # Contains the array of packages we actually revved.
368 revved_packages = manager.list()
369 new_package_atoms = manager.list()
David Jamesa8457b52011-05-28 00:03:20 -0700370
Ningning Xia419e4eb2018-02-05 10:30:36 -0800371 inputs = [[options, manifest, overlays_per_project, overlay_tracking_branch,
Mike Frysinger62ff8d72020-05-19 03:06:51 -0400372 overlay_ebuilds, revved_packages, new_package_atoms,
373 reject_self_repo]
Mike Frysinger0bdbc102019-06-13 15:27:29 -0400374 for overlays_per_project in git_project_overlays.values()]
Ningning Xia419e4eb2018-02-05 10:30:36 -0800375 parallel.RunTasksInProcessPool(_CommitOverlays, inputs)
Chris Sosadad0d322011-01-31 16:37:33 -0800376
Don Garrett4fef8c32018-08-10 18:04:01 -0700377 chroot_path = os.path.join(options.buildroot, constants.DEFAULT_CHROOT_DIR)
Ningning Xia419e4eb2018-02-05 10:30:36 -0800378 if os.path.exists(chroot_path):
Don Garrett4fef8c32018-08-10 18:04:01 -0700379 CleanStalePackages(options.buildroot, options.boards.split(':'),
Ningning Xia419e4eb2018-02-05 10:30:36 -0800380 new_package_atoms)
Mike Nicholsf7f13a82019-01-11 17:11:04 +0000381 if options.drop_file:
382 osutils.WriteFile(options.drop_file, ' '.join(revved_packages))
Chris Sosadad0d322011-01-31 16:37:33 -0800383
Brian Harring609dc4e2012-05-07 02:17:44 -0700384
Ningning Xia419e4eb2018-02-05 10:30:36 -0800385def _GetOverlayToEbuildsMap(options, overlays, package_list):
386 """Get ebuilds for overlays.
David James15ed1302013-04-25 09:21:19 -0700387
Ningning Xia783efc02018-01-24 13:39:51 -0800388 Args:
Ningning Xia783efc02018-01-24 13:39:51 -0800389 options: The options object returned by the argument parser.
Ningning Xia419e4eb2018-02-05 10:30:36 -0800390 overlays: A list of overlays to work on.
391 package_list: A list of packages passed from commandline to work on.
392
393 Returns:
394 A dict mapping each overlay to a list of ebuilds belonging to it.
395 """
Don Garrett3dbb2932018-10-02 14:41:26 -0700396 root_version = manifest_version.VersionInfo.from_repo(options.buildroot)
397 subdir_removal = manifest_version.VersionInfo('10363.0.0')
398 require_subdir_support = root_version < subdir_removal
399
Ningning Xia419e4eb2018-02-05 10:30:36 -0800400 overlay_ebuilds = {}
Don Garrett3dbb2932018-10-02 14:41:26 -0700401 inputs = [[overlay, options.all, package_list, options.force,
402 require_subdir_support]
Ningning Xia419e4eb2018-02-05 10:30:36 -0800403 for overlay in overlays]
404 result = parallel.RunTasksInProcessPool(
405 portage_util.GetOverlayEBuilds, inputs)
406 for idx, ebuilds in enumerate(result):
407 overlay_ebuilds[overlays[idx]] = ebuilds
408
409 return overlay_ebuilds
410
411
412def _CommitOverlays(options, manifest, overlays, overlay_tracking_branch,
Mike Frysinger62ff8d72020-05-19 03:06:51 -0400413 overlay_ebuilds, revved_packages, new_package_atoms,
414 reject_self_repo=True):
Ningning Xia419e4eb2018-02-05 10:30:36 -0800415 """Commit uprevs for overlays in sequence.
416
417 Args:
418 options: The options object returned by the argument parser.
419 manifest: The manifest of the given source root.
420 overlays: A list over overlays to commit.
421 overlay_tracking_branch: A dict mapping from each overlay to its tracking
422 branch.
423 overlay_ebuilds: A dict mapping overlays to their ebuilds.
Ningning Xia783efc02018-01-24 13:39:51 -0800424 revved_packages: A shared list of revved packages.
425 new_package_atoms: A shared list of new package atoms.
Mike Frysinger62ff8d72020-05-19 03:06:51 -0400426 reject_self_repo: Whether to abort if the ebuild lives in the same git
427 repo as it is tracking for uprevs.
Ningning Xia783efc02018-01-24 13:39:51 -0800428 """
Ningning Xia419e4eb2018-02-05 10:30:36 -0800429 for overlay in overlays:
430 if not os.path.isdir(overlay):
431 logging.warning('Skipping %s, which is not a directory.', overlay)
432 continue
Ningning Xia783efc02018-01-24 13:39:51 -0800433
Ningning Xia419e4eb2018-02-05 10:30:36 -0800434 # Note we intentionally work from the non push tracking branch;
435 # everything built thus far has been against it (meaning, http mirrors),
436 # thus we should honor that. During the actual push, the code switches
437 # to the correct urls, and does an appropriate rebasing.
438 tracking_branch = overlay_tracking_branch[overlay]
Ningning Xia783efc02018-01-24 13:39:51 -0800439
Ningning Xia783efc02018-01-24 13:39:51 -0800440 existing_commit = git.GetGitRepoRevision(overlay)
Lann Martine0ef98c2018-06-11 13:12:24 -0600441
442 # Make sure we run in the top-level git directory in case we are
443 # adding/removing an overlay in existing_commit.
444 git_root = git.FindGitTopLevel(overlay)
445 if git_root is None:
446 cros_build_lib.Die('No git repo at overlay directory %s.', overlay)
447
Ningning Xia783efc02018-01-24 13:39:51 -0800448 work_branch = GitBranch(constants.STABLE_EBUILD_BRANCH, tracking_branch,
Lann Martine0ef98c2018-06-11 13:12:24 -0600449 cwd=git_root)
Ningning Xia783efc02018-01-24 13:39:51 -0800450 work_branch.CreateBranch()
451 if not work_branch.Exists():
452 cros_build_lib.Die('Unable to create stabilizing branch in %s' %
453 overlay)
454
455 # In the case of uprevving overlays that have patches applied to them,
456 # include the patched changes in the stabilizing branch.
Lann Martine0ef98c2018-06-11 13:12:24 -0600457 git.RunGit(git_root, ['rebase', existing_commit])
Ningning Xia783efc02018-01-24 13:39:51 -0800458
Ningning Xiadb884322018-01-26 16:27:06 -0800459 ebuilds = overlay_ebuilds.get(overlay, [])
Ningning Xia783efc02018-01-24 13:39:51 -0800460 if ebuilds:
Ningning Xia419e4eb2018-02-05 10:30:36 -0800461 with parallel.Manager() as manager:
462 # Contains the array of packages we actually revved.
463 messages = manager.list()
464 ebuild_paths_to_add = manager.list()
465 ebuild_paths_to_remove = manager.list()
Ningning Xia783efc02018-01-24 13:39:51 -0800466
Ningning Xia419e4eb2018-02-05 10:30:36 -0800467 inputs = [[overlay, ebuild, manifest, options, ebuild_paths_to_add,
468 ebuild_paths_to_remove, messages, revved_packages,
Mike Frysinger62ff8d72020-05-19 03:06:51 -0400469 new_package_atoms, reject_self_repo]
470 for ebuild in ebuilds]
Ningning Xia419e4eb2018-02-05 10:30:36 -0800471 parallel.RunTasksInProcessPool(_WorkOnEbuild, inputs)
Ningning Xia783efc02018-01-24 13:39:51 -0800472
Ningning Xia419e4eb2018-02-05 10:30:36 -0800473 if ebuild_paths_to_add:
474 logging.info('Adding new stable ebuild paths %s in overlay %s.',
475 ebuild_paths_to_add, overlay)
476 git.RunGit(overlay, ['add'] + list(ebuild_paths_to_add))
David James15ed1302013-04-25 09:21:19 -0700477
Ningning Xia419e4eb2018-02-05 10:30:36 -0800478 if ebuild_paths_to_remove:
479 logging.info('Removing old ebuild paths %s in overlay %s.',
480 ebuild_paths_to_remove, overlay)
481 git.RunGit(overlay, ['rm', '-f'] + list(ebuild_paths_to_remove))
482
483 if messages:
484 portage_util.EBuild.CommitChange('\n\n'.join(messages), overlay)
David James15ed1302013-04-25 09:21:19 -0700485
Ningning Xia783efc02018-01-24 13:39:51 -0800486
487def _WorkOnEbuild(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=True):
Ningning Xia783efc02018-01-24 13:39:51 -0800490 """Work on a single ebuild.
491
492 Args:
493 overlay: The overlay where the ebuild belongs to.
494 ebuild: The ebuild to work on.
495 manifest: The manifest of the given source root.
496 options: The options object returned by the argument parser.
497 ebuild_paths_to_add: New stable ebuild paths to add to git.
498 ebuild_paths_to_remove: Old ebuild paths to remove from git.
499 messages: A share list of commit messages.
500 revved_packages: A shared list of revved packages.
501 new_package_atoms: A shared list of new package atoms.
Mike Frysinger62ff8d72020-05-19 03:06:51 -0400502 reject_self_repo: Whether to abort if the ebuild lives in the same git
503 repo as it is tracking for uprevs.
Ningning Xia783efc02018-01-24 13:39:51 -0800504 """
505 if options.verbose:
506 logging.info('Working on %s, info %s', ebuild.package,
507 ebuild.cros_workon_vars)
Mike Frysinger00ba05a2020-06-12 02:44:02 -0400508 if not ebuild.cros_workon_vars:
509 logging.warning('%s: unable to parse workon settings', ebuild.ebuild_path)
510
Ningning Xia783efc02018-01-24 13:39:51 -0800511 try:
Don Garrett4fef8c32018-08-10 18:04:01 -0700512 result = ebuild.RevWorkOnEBuild(os.path.join(options.buildroot, 'src'),
Mike Frysinger62ff8d72020-05-19 03:06:51 -0400513 manifest, reject_self_repo=reject_self_repo)
Ningning Xia783efc02018-01-24 13:39:51 -0800514 if result:
515 new_package, ebuild_path_to_add, ebuild_path_to_remove = result
516
517 if ebuild_path_to_add:
518 ebuild_paths_to_add.append(ebuild_path_to_add)
519 if ebuild_path_to_remove:
520 ebuild_paths_to_remove.append(ebuild_path_to_remove)
521
522 messages.append(_GIT_COMMIT_MESSAGE % ebuild.package)
Sam McNallyeb5e2052018-09-05 16:34:55 +1000523
524 if options.list_revisions:
525 info = ebuild.GetSourceInfo(os.path.join(options.buildroot, 'src'),
Mike Frysinger62ff8d72020-05-19 03:06:51 -0400526 manifest, reject_self_repo=reject_self_repo)
Sam McNallyeb5e2052018-09-05 16:34:55 +1000527 srcdirs = [os.path.join(options.buildroot, 'src', srcdir)
528 for srcdir in ebuild.cros_workon_vars.localname]
529 old_commit_ids = dict(
530 zip(srcdirs, ebuild.cros_workon_vars.commit.split(',')))
531 git_log = []
532 for srcdir in info.srcdirs:
533 old_commit_id = old_commit_ids.get(srcdir)
534 new_commit_id = ebuild.GetCommitId(srcdir)
535 if not old_commit_id or old_commit_id == new_commit_id:
536 continue
537
538 logs = git.RunGit(srcdir, [
539 'log', '%s..%s' % (old_commit_id[:8], new_commit_id[:8]),
540 '--pretty=format:%h %<(63,trunc)%s'])
541 git_log.append('$ ' + logs.cmdstr)
542 git_log.extend(line.strip() for line in logs.output.splitlines())
543 if git_log:
544 messages.append('\n'.join(git_log))
545
Ningning Xia783efc02018-01-24 13:39:51 -0800546 revved_packages.append(ebuild.package)
547 new_package_atoms.append('=%s' % new_package)
David Burger8cf4a762020-03-09 10:33:38 -0600548 except portage_util.InvalidUprevSourceError as e:
549 logging.error('An error occurred while uprevving %s: %s',
550 ebuild.package, e)
551 raise
Alex Klein99920662019-10-14 15:30:15 -0600552 except portage_util.EbuildVersionError as e:
553 logging.warning('Unable to rev %s: %s', ebuild.package, e)
554 raise
Mike Frysingerb32cc472020-05-15 00:17:54 -0400555 except OSError:
Ningning Xia783efc02018-01-24 13:39:51 -0800556 logging.warning(
557 'Cannot rev %s\n'
558 'Note you will have to go into %s '
Ningning Xia419e4eb2018-02-05 10:30:36 -0800559 'and reset the git repo yourself.', ebuild.package, overlay)
Ningning Xia783efc02018-01-24 13:39:51 -0800560 raise