blob: 7c691b8d6275af977dc24b5f50ba17dbdc33bb4a [file] [log] [blame]
Mike Frysingere58c0e22017-10-04 15:43:30 -04001# -*- coding: utf-8 -*-
Mike Frysinger110750a2012-03-26 14:19:20 -04002# Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
Chris Sosadad0d322011-01-31 16:37:33 -08003# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
5
6"""This module uprevs a given package's ebuild to the next revision."""
7
Mike Frysinger383367e2014-09-16 15:06:17 -04008from __future__ import print_function
9
Chris Sosadad0d322011-01-31 16:37:33 -080010import os
Mike Frysinger32781402020-04-19 06:34:17 -040011import sys
Chris Sosadad0d322011-01-31 16:37:33 -080012
Aviv Keshetb7519e12016-10-04 00:50:00 -070013from chromite.lib import constants
Mike Frysingere8dcbfd2015-03-08 21:45:52 -040014from chromite.lib import commandline
Chris Sosac13bba52011-05-24 15:14:09 -070015from chromite.lib import cros_build_lib
Ralph Nathan03047282015-03-23 11:09:32 -070016from chromite.lib import cros_logging as logging
David James97d95872012-11-16 15:09:56 -080017from chromite.lib import git
Mike Frysingerfddaeb52012-11-20 11:17:31 -050018from chromite.lib import osutils
David James6450a0a2012-12-04 07:59:53 -080019from chromite.lib import parallel
Alex Deymo075c2292014-09-04 18:31:50 -070020from chromite.lib import portage_util
Lann Martinb26e1292018-08-09 13:59:19 -060021from chromite.lib import repo_util
Chris Sosac13bba52011-05-24 15:14:09 -070022
Don Garrett3dbb2932018-10-02 14:41:26 -070023from chromite.cbuildbot import manifest_version
24
Mike Frysinger32781402020-04-19 06:34:17 -040025
26assert sys.version_info >= (3, 6), 'This module requires Python 3.6+'
27
28
Gabe Black71e963e2014-10-28 20:19:59 -070029# Commit message subject for uprevving Portage packages.
30GIT_COMMIT_SUBJECT = 'Marking set of ebuilds as stable'
David James15ed1302013-04-25 09:21:19 -070031
David James29e86d52013-04-19 09:41:29 -070032# Commit message for uprevving Portage packages.
33_GIT_COMMIT_MESSAGE = 'Marking 9999 ebuild for %s as stable.'
34
Chris Sosadad0d322011-01-31 16:37:33 -080035# Dictionary of valid commands with usage information.
36COMMAND_DICTIONARY = {
Mike Frysinger5cd8c742013-10-11 14:43:01 -040037 'commit': 'Marks given ebuilds as stable locally',
38 'push': 'Pushes previous marking of ebuilds to remote repo',
39}
Chris Sosadad0d322011-01-31 16:37:33 -080040
Chris Sosadad0d322011-01-31 16:37:33 -080041
Chris Sosadad0d322011-01-31 16:37:33 -080042# ======================= Global Helper Functions ========================
43
44
David James41124af2015-06-04 21:13:25 -070045def CleanStalePackages(srcroot, boards, package_atoms):
Chris Sosabf153872011-04-28 14:21:09 -070046 """Cleans up stale package info from a previous build.
Mike Frysinger5cd8c742013-10-11 14:43:01 -040047
Chris Sosabf153872011-04-28 14:21:09 -070048 Args:
David James41124af2015-06-04 21:13:25 -070049 srcroot: Root directory of the source tree.
David Jamescc09c9b2012-01-26 22:10:13 -080050 boards: Boards to clean the packages from.
Mike Frysingerde5ab0e2013-03-21 20:48:36 -040051 package_atoms: A list of package atoms to unmerge.
Chris Sosabf153872011-04-28 14:21:09 -070052 """
David James15ed1302013-04-25 09:21:19 -070053 if package_atoms:
Lann Martinffb95162018-08-28 12:02:54 -060054 logging.info('Cleaning up stale packages %s.', package_atoms)
David James15ed1302013-04-25 09:21:19 -070055
Mike Frysingerb7ab9b82012-04-04 16:22:43 -040056 # First unmerge all the packages for a board, then eclean it.
57 # We need these two steps to run in order (unmerge/eclean),
58 # but we can let all the boards run in parallel.
59 def _CleanStalePackages(board):
60 if board:
61 suffix = '-' + board
Mike Frysinger45602c72019-09-22 02:15:11 -040062 runcmd = cros_build_lib.run
Mike Frysingerb7ab9b82012-04-04 16:22:43 -040063 else:
64 suffix = ''
Mike Frysinger45602c72019-09-22 02:15:11 -040065 runcmd = cros_build_lib.sudo_run
Chris Sosadad0d322011-01-31 16:37:33 -080066
David James59a0a2b2013-03-22 14:04:44 -070067 emerge, eclean = 'emerge' + suffix, 'eclean' + suffix
68 if not osutils.FindMissingBinaries([emerge, eclean]):
David James63841a82014-01-16 14:39:24 -080069 if package_atoms:
70 # If nothing was found to be unmerged, emerge will exit(1).
Don Garrett7100fff2018-10-23 11:07:13 -070071 result = runcmd([emerge, '-q', '--unmerge'] + list(package_atoms),
David James41124af2015-06-04 21:13:25 -070072 enter_chroot=True, extra_env={'CLEAN_DELAY': '0'},
Mike Frysingerf5a3b2d2019-12-12 14:36:17 -050073 check=False, cwd=srcroot)
Mike Frysinger01504112019-08-24 19:35:24 -040074 if result.returncode not in (0, 1):
David James63841a82014-01-16 14:39:24 -080075 raise cros_build_lib.RunCommandError('unexpected error', result)
David James59a0a2b2013-03-22 14:04:44 -070076 runcmd([eclean, '-d', 'packages'],
David James41124af2015-06-04 21:13:25 -070077 cwd=srcroot, enter_chroot=True,
Mike Frysinger0282d222019-12-17 17:15:48 -050078 stdout=True, stderr=True)
Mike Frysingerb7ab9b82012-04-04 16:22:43 -040079
80 tasks = []
David Jamescc09c9b2012-01-26 22:10:13 -080081 for board in boards:
Mike Frysingerb7ab9b82012-04-04 16:22:43 -040082 tasks.append([board])
83 tasks.append([None])
84
David James6450a0a2012-12-04 07:59:53 -080085 parallel.RunTasksInProcessPool(_CleanStalePackages, tasks)
Chris Sosadad0d322011-01-31 16:37:33 -080086
87
Mike Frysinger2ebe3732012-05-08 17:04:12 -040088# TODO(build): This code needs to be gutted and rebased to cros_build_lib.
89def _DoWeHaveLocalCommits(stable_branch, tracking_branch, cwd):
Chris Sosadad0d322011-01-31 16:37:33 -080090 """Returns true if there are local commits."""
David James97d95872012-11-16 15:09:56 -080091 output = git.RunGit(
Paul Hobbs72d8e392015-10-21 17:24:23 -070092 cwd, ['rev-parse', stable_branch, tracking_branch]).output.split()
Brian Harring5b86b5e2012-05-25 18:27:40 -070093 return output[0] != output[1]
Chris Sosadad0d322011-01-31 16:37:33 -080094
95
Chris Sosadad0d322011-01-31 16:37:33 -080096# ======================= End Global Helper Functions ========================
97
98
Ningning Xia52009062016-05-09 14:33:51 -070099def PushChange(stable_branch, tracking_branch, dryrun, cwd,
100 staging_branch=None):
Chris Sosadad0d322011-01-31 16:37:33 -0800101 """Pushes commits in the stable_branch to the remote git repository.
102
David Jamesee2da622012-02-23 09:32:16 -0800103 Pushes local commits from calls to CommitChange to the remote git
David James66009462012-03-25 10:08:38 -0700104 repository specified by current working directory. If changes are
105 found to commit, they will be merged to the merge branch and pushed.
106 In that case, the local repository will be left on the merge branch.
Chris Sosadad0d322011-01-31 16:37:33 -0800107
108 Args:
109 stable_branch: The local branch with commits we want to push.
110 tracking_branch: The tracking branch of the local branch.
Chris Sosa62ad8522011-03-08 17:46:17 -0800111 dryrun: Use git push --dryrun to emulate a push.
Mike Frysinger2ebe3732012-05-08 17:04:12 -0400112 cwd: The directory to run commands in.
Ningning Xia52009062016-05-09 14:33:51 -0700113 staging_branch: The staging branch to push for a failed PFQ run
Mike Frysinger1a736a82013-12-12 01:50:59 -0500114
Chris Sosadad0d322011-01-31 16:37:33 -0800115 Raises:
Mike Frysinger5cd8c742013-10-11 14:43:01 -0400116 OSError: Error occurred while pushing.
Chris Sosadad0d322011-01-31 16:37:33 -0800117 """
David James47959632015-10-23 07:56:01 -0700118 if not git.DoesCommitExistInRepo(cwd, stable_branch):
119 logging.debug('No branch created for %s. Exiting', cwd)
120 return
121
Mike Frysinger2ebe3732012-05-08 17:04:12 -0400122 if not _DoWeHaveLocalCommits(stable_branch, tracking_branch, cwd):
David James47959632015-10-23 07:56:01 -0700123 logging.debug('No work found to push in %s. Exiting', cwd)
Chris Sosadad0d322011-01-31 16:37:33 -0800124 return
125
David James66009462012-03-25 10:08:38 -0700126 # For the commit queue, our local branch may contain commits that were
127 # just tested and pushed during the CommitQueueCompletion stage. Sync
128 # and rebase our local branch on top of the remote commits.
Paul Hobbs72d8e392015-10-21 17:24:23 -0700129 remote_ref = git.GetTrackingBranch(cwd,
130 branch=stable_branch,
131 for_push=True)
Paul Hobbs1e46be82015-10-30 13:46:02 -0700132 # SyncPushBranch rebases HEAD onto the updated remote. We need to checkout
133 # stable_branch here in order to update it.
134 git.RunGit(cwd, ['checkout', stable_branch])
Don Garrett99449592015-03-25 11:01:30 -0700135 git.SyncPushBranch(cwd, remote_ref.remote, remote_ref.ref)
David James66009462012-03-25 10:08:38 -0700136
137 # Check whether any local changes remain after the sync.
Don Garrett99449592015-03-25 11:01:30 -0700138 if not _DoWeHaveLocalCommits(stable_branch, remote_ref.ref, cwd):
Ralph Nathan03047282015-03-23 11:09:32 -0700139 logging.info('All changes already pushed for %s. Exiting', cwd)
David James66009462012-03-25 10:08:38 -0700140 return
141
Andrew Lamb7ef2c0b2019-07-17 09:43:27 -0600142 # Add a failsafe check here. Only CLs from the 'chrome-bot' or
143 # 'chromeos-ci-prod' user should be involved here. If any other CLs are
144 # found then complain. In dryruns extra CLs are normal, though, and can
145 # be ignored.
146 bad_cl_cmd = [
147 'log', '--format=short', '--perl-regexp', '--author',
148 '^(?!chrome-bot|chromeos-ci-prod)',
149 '%s..%s' % (remote_ref.ref, stable_branch)
150 ]
Matt Tennantcb522052013-11-25 14:23:43 -0800151 bad_cls = git.RunGit(cwd, bad_cl_cmd).output
152 if bad_cls.strip() and not dryrun:
Andrew Lamb7ef2c0b2019-07-17 09:43:27 -0600153 logging.error(
154 'The Uprev stage found changes from users other than '
155 'chrome-bot or chromeos-ci-prod:\n\n%s', bad_cls)
Matt Tennantcb522052013-11-25 14:23:43 -0800156 raise AssertionError('Unexpected CLs found during uprev stage.')
157
Lev Rumyantsev25352ba2016-09-07 15:53:58 -0700158 if staging_branch is not None:
159 logging.info('PFQ FAILED. Pushing uprev change to staging branch %s',
160 staging_branch)
161
Mike Frysingere65f3752014-12-08 00:46:39 -0500162 description = git.RunGit(
163 cwd,
164 ['log', '--format=format:%s%n%n%b',
Don Garrett99449592015-03-25 11:01:30 -0700165 '%s..%s' % (remote_ref.ref, stable_branch)]).output
Gabe Black71e963e2014-10-28 20:19:59 -0700166 description = '%s\n\n%s' % (GIT_COMMIT_SUBJECT, description)
Ralph Nathan03047282015-03-23 11:09:32 -0700167 logging.info('For %s, using description %s', cwd, description)
Paul Hobbsf52ea8f2015-10-21 17:24:23 -0700168 git.CreatePushBranch(constants.MERGE_BRANCH, cwd,
169 remote_push_branch=remote_ref)
David James97d95872012-11-16 15:09:56 -0800170 git.RunGit(cwd, ['merge', '--squash', stable_branch])
171 git.RunGit(cwd, ['commit', '-m', description])
172 git.RunGit(cwd, ['config', 'push.default', 'tracking'])
Mike Nicholsa6818c52018-04-09 11:05:42 -0600173 git.PushBranch(constants.MERGE_BRANCH, cwd, dryrun=dryrun,
Sean Abraham11b57f82019-09-20 19:33:17 +0000174 staging_branch=staging_branch)
Chris Sosadad0d322011-01-31 16:37:33 -0800175
176
177class GitBranch(object):
178 """Wrapper class for a git branch."""
179
Mike Frysinger2ebe3732012-05-08 17:04:12 -0400180 def __init__(self, branch_name, tracking_branch, cwd):
David Jamesc7c4ff52013-09-18 17:57:13 -0700181 """Sets up variables but does not create the branch.
182
Mike Frysinger5cd8c742013-10-11 14:43:01 -0400183 Args:
David Jamesc7c4ff52013-09-18 17:57:13 -0700184 branch_name: The name of the branch.
185 tracking_branch: The associated tracking branch.
186 cwd: The git repository to work in.
187 """
Chris Sosadad0d322011-01-31 16:37:33 -0800188 self.branch_name = branch_name
189 self.tracking_branch = tracking_branch
Mike Frysinger2ebe3732012-05-08 17:04:12 -0400190 self.cwd = cwd
Chris Sosadad0d322011-01-31 16:37:33 -0800191
192 def CreateBranch(self):
Mike Frysinger2ebe3732012-05-08 17:04:12 -0400193 self.Checkout()
Chris Sosadad0d322011-01-31 16:37:33 -0800194
Mike Frysinger2ebe3732012-05-08 17:04:12 -0400195 def Checkout(self, branch=None):
Chris Sosadad0d322011-01-31 16:37:33 -0800196 """Function used to check out to another GitBranch."""
Mike Frysinger2ebe3732012-05-08 17:04:12 -0400197 if not branch:
198 branch = self.branch_name
199 if branch == self.tracking_branch or self.Exists(branch):
Lann Martinb26e1292018-08-09 13:59:19 -0600200 git.RunGit(self.cwd, ['checkout', '-f', branch], quiet=True)
Chris Sosadad0d322011-01-31 16:37:33 -0800201 else:
Lann Martinb26e1292018-08-09 13:59:19 -0600202 repo = repo_util.Repository.MustFind(self.cwd)
203 repo.StartBranch(branch, projects=['.'], cwd=self.cwd)
Chris Sosadad0d322011-01-31 16:37:33 -0800204
Mike Frysinger2ebe3732012-05-08 17:04:12 -0400205 def Exists(self, branch=None):
Chris Sosadad0d322011-01-31 16:37:33 -0800206 """Returns True if the branch exists."""
Mike Frysinger2ebe3732012-05-08 17:04:12 -0400207 if not branch:
208 branch = self.branch_name
David James67d73252013-09-19 17:33:12 -0700209 branches = git.RunGit(self.cwd, ['branch']).output
Mike Frysinger2ebe3732012-05-08 17:04:12 -0400210 return branch in branches.split()
Chris Sosadad0d322011-01-31 16:37:33 -0800211
212
Mike Frysingere8dcbfd2015-03-08 21:45:52 -0400213def GetParser():
214 """Creates the argparse parser."""
215 parser = commandline.ArgumentParser()
216 parser.add_argument('--all', action='store_true',
217 help='Mark all packages as stable.')
218 parser.add_argument('-b', '--boards', default='',
219 help='Colon-separated list of boards.')
Mike Nicholsf7f13a82019-01-11 17:11:04 +0000220 parser.add_argument('--drop_file',
221 help='File to list packages that were revved.')
Mike Frysingere8dcbfd2015-03-08 21:45:52 -0400222 parser.add_argument('--dryrun', action='store_true',
223 help='Passes dry-run to git push if pushing a change.')
Bertrand SIMONNET6af54302015-08-05 10:12:49 -0700224 parser.add_argument('--force', action='store_true',
225 help='Force the stabilization of blacklisted packages. '
226 '(only compatible with -p)')
Sam McNallyeb5e2052018-09-05 16:34:55 +1000227 parser.add_argument('--list_revisions', action='store_true',
228 help='List all revisions included in the commit message.')
Mike Frysingere8dcbfd2015-03-08 21:45:52 -0400229 parser.add_argument('-o', '--overlays',
230 help='Colon-separated list of overlays to modify.')
Don Garrettf9eff952018-08-10 16:50:04 -0700231 parser.add_argument('--overlay-type',
232 help='Populates --overlays based on "public", "private"'
233 ', or "both".')
Mike Frysingere8dcbfd2015-03-08 21:45:52 -0400234 parser.add_argument('-p', '--packages',
235 help='Colon separated list of packages to rev.')
Don Garrett4fef8c32018-08-10 18:04:01 -0700236 parser.add_argument('--buildroot', type='path',
237 help='Path to buildroot.')
Mike Frysingere8dcbfd2015-03-08 21:45:52 -0400238 parser.add_argument('-r', '--srcroot', type='path',
Don Garrett4fef8c32018-08-10 18:04:01 -0700239 help='Path to root src. Deprecated in favor of '
240 '--buildroot')
Mike Frysingere8dcbfd2015-03-08 21:45:52 -0400241 parser.add_argument('--verbose', action='store_true',
242 help='Prints out debug info.')
Ningning Xia52009062016-05-09 14:33:51 -0700243 parser.add_argument('--staging_branch',
244 help='The staging branch to push changes')
Mike Frysinger1f4478c2019-10-20 18:33:17 -0400245 parser.add_argument('command', choices=sorted(COMMAND_DICTIONARY),
Mike Frysingere8dcbfd2015-03-08 21:45:52 -0400246 help='Command to run.')
247 return parser
248
249
250def main(argv):
251 parser = GetParser()
252 options = parser.parse_args(argv)
Don Garrett4fef8c32018-08-10 18:04:01 -0700253
254 # TODO: Remove this code in favor of a simple default on buildroot when
255 # srcroot is removed.
256 if options.srcroot and not options.buildroot:
257 # Convert /<repo>/src -> <repo>
258 options.buildroot = os.path.dirname(options.srcroot)
259 if not options.buildroot:
260 options.buildroot = constants.SOURCE_ROOT
261 options.srcroot = None
262
Bertrand SIMONNET6af54302015-08-05 10:12:49 -0700263 options.Freeze()
Mike Frysingere8dcbfd2015-03-08 21:45:52 -0400264
Bertrand SIMONNET6af54302015-08-05 10:12:49 -0700265 if options.command == 'commit':
266 if not options.packages and not options.all:
267 parser.error('Please specify at least one package (--packages)')
268 if options.force and options.all:
269 parser.error('Cannot use --force with --all. You must specify a list of '
270 'packages you want to force uprev.')
271
Don Garrett4fef8c32018-08-10 18:04:01 -0700272 if not os.path.isdir(options.buildroot):
273 parser.error('buildroot is not a valid path: %s' % options.buildroot)
Mike Frysingere8dcbfd2015-03-08 21:45:52 -0400274
Don Garrettf9eff952018-08-10 16:50:04 -0700275 if options.overlay_type and options.overlays:
276 parser.error('Cannot use --overlay-type with --overlays.')
277
Alex Deymo075c2292014-09-04 18:31:50 -0700278 portage_util.EBuild.VERBOSE = options.verbose
Chris Sosa62ad8522011-03-08 17:46:17 -0800279
Chris Sosa62ad8522011-03-08 17:46:17 -0800280 package_list = None
281 if options.packages:
282 package_list = options.packages.split(':')
283
Ningning Xiadb884322018-01-26 16:27:06 -0800284 overlays = []
Chris Sosa62ad8522011-03-08 17:46:17 -0800285 if options.overlays:
Chris Sosa62ad8522011-03-08 17:46:17 -0800286 for path in options.overlays.split(':'):
Ryan Cui05a31ba2011-05-31 17:47:37 -0700287 if not os.path.isdir(path):
Chris Sosac13bba52011-05-24 15:14:09 -0700288 cros_build_lib.Die('Cannot find overlay: %s' % path)
Ningning Xiadb884322018-01-26 16:27:06 -0800289 overlays.append(os.path.realpath(path))
Don Garrettf9eff952018-08-10 16:50:04 -0700290 elif options.overlay_type:
291 overlays = portage_util.FindOverlays(
Don Garrett4fef8c32018-08-10 18:04:01 -0700292 options.overlay_type, buildroot=options.buildroot)
Chris Sosadad0d322011-01-31 16:37:33 -0800293 else:
Ralph Nathan446aee92015-03-23 14:44:56 -0700294 logging.warning('Missing --overlays argument')
Ningning Xiadb884322018-01-26 16:27:06 -0800295 overlays.extend([
Don Garrett4fef8c32018-08-10 18:04:01 -0700296 '%s/src/private-overlays/chromeos-overlay' % options.buildroot,
297 '%s/src/third_party/chromiumos-overlay' % options.buildroot])
Chris Sosadad0d322011-01-31 16:37:33 -0800298
Don Garrett4fef8c32018-08-10 18:04:01 -0700299 manifest = git.ManifestCheckout.Cached(options.buildroot)
Ryan Cui4656a3c2011-05-24 12:30:30 -0700300
Ningning Xia419e4eb2018-02-05 10:30:36 -0800301 # Dict mapping from each overlay to its tracking branch.
302 overlay_tracking_branch = {}
303 # Dict mapping from each git repository (project) to a list of its overlays.
304 git_project_overlays = {}
305
306 for overlay in overlays:
307 remote_ref = git.GetTrackingBranchViaManifest(overlay, manifest=manifest)
308 overlay_tracking_branch[overlay] = remote_ref.ref
309 git_project_overlays.setdefault(remote_ref.project_name, []).append(overlay)
310
311 if options.command == 'push':
312 _WorkOnPush(options, overlay_tracking_branch, git_project_overlays)
313 elif options.command == 'commit':
314 _WorkOnCommit(options, overlays, overlay_tracking_branch,
315 git_project_overlays, manifest, package_list)
316
317
318def _WorkOnPush(options, overlay_tracking_branch, git_project_overlays):
319 """Push uprevs of overlays belonging to differet git projects in parallel.
320
321 Args:
322 options: The options object returned by the argument parser.
323 overlay_tracking_branch: A dict mapping from each overlay to its tracking
324 branch.
325 git_project_overlays: A dict mapping from each git repository to a list of
326 its overlays.
327 """
328 inputs = [[options, overlays_per_project, overlay_tracking_branch]
Mike Frysinger0bdbc102019-06-13 15:27:29 -0400329 for overlays_per_project in git_project_overlays.values()]
Ningning Xia419e4eb2018-02-05 10:30:36 -0800330 parallel.RunTasksInProcessPool(_PushOverlays, inputs)
331
332
333def _PushOverlays(options, overlays, overlay_tracking_branch):
334 """Push uprevs for overlays in sequence.
335
336 Args:
337 options: The options object returned by the argument parser.
338 overlays: A list of overlays to push uprevs in sequence.
339 overlay_tracking_branch: A dict mapping from each overlay to its tracking
340 branch.
341 """
342 for overlay in overlays:
343 if not os.path.isdir(overlay):
344 logging.warning('Skipping %s, which is not a directory.', overlay)
345 continue
346
347 tracking_branch = overlay_tracking_branch[overlay]
348 PushChange(constants.STABLE_EBUILD_BRANCH, tracking_branch, options.dryrun,
349 cwd=overlay, staging_branch=options.staging_branch)
350
351
352def _WorkOnCommit(options, overlays, overlay_tracking_branch,
353 git_project_overlays, manifest, package_list):
354 """Commit uprevs of overlays belonging to different git projects in parallel.
355
356 Args:
357 options: The options object returned by the argument parser.
358 overlays: A list of overlays to work on.
359 overlay_tracking_branch: A dict mapping from each overlay to its tracking
360 branch.
361 git_project_overlays: A dict mapping from each git repository to a list of
362 its overlays.
363 manifest: The manifest of the given source root.
364 package_list: A list of packages passed from commandline to work on.
365 """
366 overlay_ebuilds = _GetOverlayToEbuildsMap(options, overlays, package_list)
David James84e953c2013-04-23 18:44:06 -0700367
Ningning Xia783efc02018-01-24 13:39:51 -0800368 with parallel.Manager() as manager:
369 # Contains the array of packages we actually revved.
370 revved_packages = manager.list()
371 new_package_atoms = manager.list()
David Jamesa8457b52011-05-28 00:03:20 -0700372
Ningning Xia419e4eb2018-02-05 10:30:36 -0800373 inputs = [[options, manifest, overlays_per_project, overlay_tracking_branch,
374 overlay_ebuilds, revved_packages, new_package_atoms]
Mike Frysinger0bdbc102019-06-13 15:27:29 -0400375 for overlays_per_project in git_project_overlays.values()]
Ningning Xia419e4eb2018-02-05 10:30:36 -0800376 parallel.RunTasksInProcessPool(_CommitOverlays, inputs)
Chris Sosadad0d322011-01-31 16:37:33 -0800377
Don Garrett4fef8c32018-08-10 18:04:01 -0700378 chroot_path = os.path.join(options.buildroot, constants.DEFAULT_CHROOT_DIR)
Ningning Xia419e4eb2018-02-05 10:30:36 -0800379 if os.path.exists(chroot_path):
Don Garrett4fef8c32018-08-10 18:04:01 -0700380 CleanStalePackages(options.buildroot, options.boards.split(':'),
Ningning Xia419e4eb2018-02-05 10:30:36 -0800381 new_package_atoms)
Mike Nicholsf7f13a82019-01-11 17:11:04 +0000382 if options.drop_file:
383 osutils.WriteFile(options.drop_file, ' '.join(revved_packages))
Chris Sosadad0d322011-01-31 16:37:33 -0800384
Brian Harring609dc4e2012-05-07 02:17:44 -0700385
Ningning Xia419e4eb2018-02-05 10:30:36 -0800386def _GetOverlayToEbuildsMap(options, overlays, package_list):
387 """Get ebuilds for overlays.
David James15ed1302013-04-25 09:21:19 -0700388
Ningning Xia783efc02018-01-24 13:39:51 -0800389 Args:
Ningning Xia783efc02018-01-24 13:39:51 -0800390 options: The options object returned by the argument parser.
Ningning Xia419e4eb2018-02-05 10:30:36 -0800391 overlays: A list of overlays to work on.
392 package_list: A list of packages passed from commandline to work on.
393
394 Returns:
395 A dict mapping each overlay to a list of ebuilds belonging to it.
396 """
Don Garrett3dbb2932018-10-02 14:41:26 -0700397 root_version = manifest_version.VersionInfo.from_repo(options.buildroot)
398 subdir_removal = manifest_version.VersionInfo('10363.0.0')
399 require_subdir_support = root_version < subdir_removal
400
Ningning Xia419e4eb2018-02-05 10:30:36 -0800401 overlay_ebuilds = {}
Don Garrett3dbb2932018-10-02 14:41:26 -0700402 inputs = [[overlay, options.all, package_list, options.force,
403 require_subdir_support]
Ningning Xia419e4eb2018-02-05 10:30:36 -0800404 for overlay in overlays]
405 result = parallel.RunTasksInProcessPool(
406 portage_util.GetOverlayEBuilds, inputs)
407 for idx, ebuilds in enumerate(result):
408 overlay_ebuilds[overlays[idx]] = ebuilds
409
410 return overlay_ebuilds
411
412
413def _CommitOverlays(options, manifest, overlays, overlay_tracking_branch,
414 overlay_ebuilds, revved_packages, new_package_atoms):
415 """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.
426 """
Ningning Xia419e4eb2018-02-05 10:30:36 -0800427 for overlay in overlays:
428 if not os.path.isdir(overlay):
429 logging.warning('Skipping %s, which is not a directory.', overlay)
430 continue
Ningning Xia783efc02018-01-24 13:39:51 -0800431
Ningning Xia419e4eb2018-02-05 10:30:36 -0800432 # Note we intentionally work from the non push tracking branch;
433 # everything built thus far has been against it (meaning, http mirrors),
434 # thus we should honor that. During the actual push, the code switches
435 # to the correct urls, and does an appropriate rebasing.
436 tracking_branch = overlay_tracking_branch[overlay]
Ningning Xia783efc02018-01-24 13:39:51 -0800437
Ningning Xia783efc02018-01-24 13:39:51 -0800438 existing_commit = git.GetGitRepoRevision(overlay)
Lann Martine0ef98c2018-06-11 13:12:24 -0600439
440 # Make sure we run in the top-level git directory in case we are
441 # adding/removing an overlay in existing_commit.
442 git_root = git.FindGitTopLevel(overlay)
443 if git_root is None:
444 cros_build_lib.Die('No git repo at overlay directory %s.', overlay)
445
Ningning Xia783efc02018-01-24 13:39:51 -0800446 work_branch = GitBranch(constants.STABLE_EBUILD_BRANCH, tracking_branch,
Lann Martine0ef98c2018-06-11 13:12:24 -0600447 cwd=git_root)
Ningning Xia783efc02018-01-24 13:39:51 -0800448 work_branch.CreateBranch()
449 if not work_branch.Exists():
450 cros_build_lib.Die('Unable to create stabilizing branch in %s' %
451 overlay)
452
453 # In the case of uprevving overlays that have patches applied to them,
454 # include the patched changes in the stabilizing branch.
Lann Martine0ef98c2018-06-11 13:12:24 -0600455 git.RunGit(git_root, ['rebase', existing_commit])
Ningning Xia783efc02018-01-24 13:39:51 -0800456
Ningning Xiadb884322018-01-26 16:27:06 -0800457 ebuilds = overlay_ebuilds.get(overlay, [])
Ningning Xia783efc02018-01-24 13:39:51 -0800458 if ebuilds:
Ningning Xia419e4eb2018-02-05 10:30:36 -0800459 with parallel.Manager() as manager:
460 # Contains the array of packages we actually revved.
461 messages = manager.list()
462 ebuild_paths_to_add = manager.list()
463 ebuild_paths_to_remove = manager.list()
Ningning Xia783efc02018-01-24 13:39:51 -0800464
Ningning Xia419e4eb2018-02-05 10:30:36 -0800465 inputs = [[overlay, ebuild, manifest, options, ebuild_paths_to_add,
466 ebuild_paths_to_remove, messages, revved_packages,
467 new_package_atoms] for ebuild in ebuilds]
468 parallel.RunTasksInProcessPool(_WorkOnEbuild, inputs)
Ningning Xia783efc02018-01-24 13:39:51 -0800469
Ningning Xia419e4eb2018-02-05 10:30:36 -0800470 if ebuild_paths_to_add:
471 logging.info('Adding new stable ebuild paths %s in overlay %s.',
472 ebuild_paths_to_add, overlay)
473 git.RunGit(overlay, ['add'] + list(ebuild_paths_to_add))
David James15ed1302013-04-25 09:21:19 -0700474
Ningning Xia419e4eb2018-02-05 10:30:36 -0800475 if ebuild_paths_to_remove:
476 logging.info('Removing old ebuild paths %s in overlay %s.',
477 ebuild_paths_to_remove, overlay)
478 git.RunGit(overlay, ['rm', '-f'] + list(ebuild_paths_to_remove))
479
480 if messages:
481 portage_util.EBuild.CommitChange('\n\n'.join(messages), overlay)
David James15ed1302013-04-25 09:21:19 -0700482
Ningning Xia783efc02018-01-24 13:39:51 -0800483
484def _WorkOnEbuild(overlay, ebuild, manifest, options, ebuild_paths_to_add,
485 ebuild_paths_to_remove, messages, revved_packages,
486 new_package_atoms):
487 """Work on a single ebuild.
488
489 Args:
490 overlay: The overlay where the ebuild belongs to.
491 ebuild: The ebuild to work on.
492 manifest: The manifest of the given source root.
493 options: The options object returned by the argument parser.
494 ebuild_paths_to_add: New stable ebuild paths to add to git.
495 ebuild_paths_to_remove: Old ebuild paths to remove from git.
496 messages: A share list of commit messages.
497 revved_packages: A shared list of revved packages.
498 new_package_atoms: A shared list of new package atoms.
499 """
500 if options.verbose:
501 logging.info('Working on %s, info %s', ebuild.package,
502 ebuild.cros_workon_vars)
503 try:
Don Garrett4fef8c32018-08-10 18:04:01 -0700504 result = ebuild.RevWorkOnEBuild(os.path.join(options.buildroot, 'src'),
505 manifest)
Ningning Xia783efc02018-01-24 13:39:51 -0800506 if result:
507 new_package, ebuild_path_to_add, ebuild_path_to_remove = result
508
509 if ebuild_path_to_add:
510 ebuild_paths_to_add.append(ebuild_path_to_add)
511 if ebuild_path_to_remove:
512 ebuild_paths_to_remove.append(ebuild_path_to_remove)
513
514 messages.append(_GIT_COMMIT_MESSAGE % ebuild.package)
Sam McNallyeb5e2052018-09-05 16:34:55 +1000515
516 if options.list_revisions:
517 info = ebuild.GetSourceInfo(os.path.join(options.buildroot, 'src'),
Sam McNallyd8ed0542018-10-26 16:20:44 +1100518 manifest)
Sam McNallyeb5e2052018-09-05 16:34:55 +1000519 srcdirs = [os.path.join(options.buildroot, 'src', srcdir)
520 for srcdir in ebuild.cros_workon_vars.localname]
521 old_commit_ids = dict(
522 zip(srcdirs, ebuild.cros_workon_vars.commit.split(',')))
523 git_log = []
524 for srcdir in info.srcdirs:
525 old_commit_id = old_commit_ids.get(srcdir)
526 new_commit_id = ebuild.GetCommitId(srcdir)
527 if not old_commit_id or old_commit_id == new_commit_id:
528 continue
529
530 logs = git.RunGit(srcdir, [
531 'log', '%s..%s' % (old_commit_id[:8], new_commit_id[:8]),
532 '--pretty=format:%h %<(63,trunc)%s'])
533 git_log.append('$ ' + logs.cmdstr)
534 git_log.extend(line.strip() for line in logs.output.splitlines())
535 if git_log:
536 messages.append('\n'.join(git_log))
537
Ningning Xia783efc02018-01-24 13:39:51 -0800538 revved_packages.append(ebuild.package)
539 new_package_atoms.append('=%s' % new_package)
David Burger8cf4a762020-03-09 10:33:38 -0600540 except portage_util.InvalidUprevSourceError as e:
541 logging.error('An error occurred while uprevving %s: %s',
542 ebuild.package, e)
543 raise
Alex Klein99920662019-10-14 15:30:15 -0600544 except portage_util.EbuildVersionError as e:
545 logging.warning('Unable to rev %s: %s', ebuild.package, e)
546 raise
Mike Frysingerb32cc472020-05-15 00:17:54 -0400547 except OSError:
Ningning Xia783efc02018-01-24 13:39:51 -0800548 logging.warning(
549 'Cannot rev %s\n'
550 'Note you will have to go into %s '
Ningning Xia419e4eb2018-02-05 10:30:36 -0800551 'and reset the git repo yourself.', ebuild.package, overlay)
Ningning Xia783efc02018-01-24 13:39:51 -0800552 raise