blob: 3e1bf8b98ca9d18b6643d6de6363a3a8f80b1ff7 [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
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 ]
Matt Tennantcb522052013-11-25 14:23:43 -0800146 bad_cls = git.RunGit(cwd, bad_cl_cmd).output
147 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',
Don Garrett99449592015-03-25 11:01:30 -0700160 '%s..%s' % (remote_ref.ref, stable_branch)]).output
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'])
Mike Nicholsa6818c52018-04-09 11:05:42 -0600168 git.PushBranch(constants.MERGE_BRANCH, cwd, dryrun=dryrun,
Sean Abraham11b57f82019-09-20 19:33:17 +0000169 staging_branch=staging_branch)
Chris Sosadad0d322011-01-31 16:37:33 -0800170
171
172class GitBranch(object):
173 """Wrapper class for a git branch."""
174
Mike Frysinger2ebe3732012-05-08 17:04:12 -0400175 def __init__(self, branch_name, tracking_branch, cwd):
David Jamesc7c4ff52013-09-18 17:57:13 -0700176 """Sets up variables but does not create the branch.
177
Mike Frysinger5cd8c742013-10-11 14:43:01 -0400178 Args:
David Jamesc7c4ff52013-09-18 17:57:13 -0700179 branch_name: The name of the branch.
180 tracking_branch: The associated tracking branch.
181 cwd: The git repository to work in.
182 """
Chris Sosadad0d322011-01-31 16:37:33 -0800183 self.branch_name = branch_name
184 self.tracking_branch = tracking_branch
Mike Frysinger2ebe3732012-05-08 17:04:12 -0400185 self.cwd = cwd
Chris Sosadad0d322011-01-31 16:37:33 -0800186
187 def CreateBranch(self):
Mike Frysinger2ebe3732012-05-08 17:04:12 -0400188 self.Checkout()
Chris Sosadad0d322011-01-31 16:37:33 -0800189
Mike Frysinger2ebe3732012-05-08 17:04:12 -0400190 def Checkout(self, branch=None):
Chris Sosadad0d322011-01-31 16:37:33 -0800191 """Function used to check out to another GitBranch."""
Mike Frysinger2ebe3732012-05-08 17:04:12 -0400192 if not branch:
193 branch = self.branch_name
194 if branch == self.tracking_branch or self.Exists(branch):
Lann Martinb26e1292018-08-09 13:59:19 -0600195 git.RunGit(self.cwd, ['checkout', '-f', branch], quiet=True)
Chris Sosadad0d322011-01-31 16:37:33 -0800196 else:
Lann Martinb26e1292018-08-09 13:59:19 -0600197 repo = repo_util.Repository.MustFind(self.cwd)
198 repo.StartBranch(branch, projects=['.'], cwd=self.cwd)
Chris Sosadad0d322011-01-31 16:37:33 -0800199
Mike Frysinger2ebe3732012-05-08 17:04:12 -0400200 def Exists(self, branch=None):
Chris Sosadad0d322011-01-31 16:37:33 -0800201 """Returns True if the branch exists."""
Mike Frysinger2ebe3732012-05-08 17:04:12 -0400202 if not branch:
203 branch = self.branch_name
David James67d73252013-09-19 17:33:12 -0700204 branches = git.RunGit(self.cwd, ['branch']).output
Mike Frysinger2ebe3732012-05-08 17:04:12 -0400205 return branch in branches.split()
Chris Sosadad0d322011-01-31 16:37:33 -0800206
207
Mike Frysingere8dcbfd2015-03-08 21:45:52 -0400208def GetParser():
209 """Creates the argparse parser."""
210 parser = commandline.ArgumentParser()
211 parser.add_argument('--all', action='store_true',
212 help='Mark all packages as stable.')
213 parser.add_argument('-b', '--boards', default='',
214 help='Colon-separated list of boards.')
Mike Nicholsf7f13a82019-01-11 17:11:04 +0000215 parser.add_argument('--drop_file',
216 help='File to list packages that were revved.')
Mike Frysingere8dcbfd2015-03-08 21:45:52 -0400217 parser.add_argument('--dryrun', action='store_true',
218 help='Passes dry-run to git push if pushing a change.')
Bertrand SIMONNET6af54302015-08-05 10:12:49 -0700219 parser.add_argument('--force', action='store_true',
Nicolas Boichatde92a6d2021-03-31 16:43:50 +0800220 help='Force the stabilization of packages marked for '
221 'manual uprev. '
Bertrand SIMONNET6af54302015-08-05 10:12:49 -0700222 '(only compatible with -p)')
Sam McNallyeb5e2052018-09-05 16:34:55 +1000223 parser.add_argument('--list_revisions', action='store_true',
224 help='List all revisions included in the commit message.')
Mike Frysingere8dcbfd2015-03-08 21:45:52 -0400225 parser.add_argument('-o', '--overlays',
226 help='Colon-separated list of overlays to modify.')
Don Garrettf9eff952018-08-10 16:50:04 -0700227 parser.add_argument('--overlay-type',
228 help='Populates --overlays based on "public", "private"'
229 ', or "both".')
Mike Frysingere8dcbfd2015-03-08 21:45:52 -0400230 parser.add_argument('-p', '--packages',
231 help='Colon separated list of packages to rev.')
Don Garrett4fef8c32018-08-10 18:04:01 -0700232 parser.add_argument('--buildroot', type='path',
233 help='Path to buildroot.')
Mike Frysingere8dcbfd2015-03-08 21:45:52 -0400234 parser.add_argument('-r', '--srcroot', type='path',
Don Garrett4fef8c32018-08-10 18:04:01 -0700235 help='Path to root src. Deprecated in favor of '
236 '--buildroot')
Ningning Xia52009062016-05-09 14:33:51 -0700237 parser.add_argument('--staging_branch',
238 help='The staging branch to push changes')
Mike Frysinger1f4478c2019-10-20 18:33:17 -0400239 parser.add_argument('command', choices=sorted(COMMAND_DICTIONARY),
Mike Frysingere8dcbfd2015-03-08 21:45:52 -0400240 help='Command to run.')
241 return parser
242
243
244def main(argv):
245 parser = GetParser()
246 options = parser.parse_args(argv)
Don Garrett4fef8c32018-08-10 18:04:01 -0700247
248 # TODO: Remove this code in favor of a simple default on buildroot when
249 # srcroot is removed.
250 if options.srcroot and not options.buildroot:
251 # Convert /<repo>/src -> <repo>
252 options.buildroot = os.path.dirname(options.srcroot)
253 if not options.buildroot:
254 options.buildroot = constants.SOURCE_ROOT
255 options.srcroot = None
256
Bertrand SIMONNET6af54302015-08-05 10:12:49 -0700257 options.Freeze()
Mike Frysingere8dcbfd2015-03-08 21:45:52 -0400258
Bertrand SIMONNET6af54302015-08-05 10:12:49 -0700259 if options.command == 'commit':
260 if not options.packages and not options.all:
261 parser.error('Please specify at least one package (--packages)')
262 if options.force and options.all:
263 parser.error('Cannot use --force with --all. You must specify a list of '
264 'packages you want to force uprev.')
265
Don Garrett4fef8c32018-08-10 18:04:01 -0700266 if not os.path.isdir(options.buildroot):
267 parser.error('buildroot is not a valid path: %s' % options.buildroot)
Mike Frysingere8dcbfd2015-03-08 21:45:52 -0400268
Don Garrettf9eff952018-08-10 16:50:04 -0700269 if options.overlay_type and options.overlays:
270 parser.error('Cannot use --overlay-type with --overlays.')
271
Alex Deymo075c2292014-09-04 18:31:50 -0700272 portage_util.EBuild.VERBOSE = options.verbose
Chris Sosa62ad8522011-03-08 17:46:17 -0800273
Chris Sosa62ad8522011-03-08 17:46:17 -0800274 package_list = None
275 if options.packages:
276 package_list = options.packages.split(':')
277
Ningning Xiadb884322018-01-26 16:27:06 -0800278 overlays = []
Chris Sosa62ad8522011-03-08 17:46:17 -0800279 if options.overlays:
Chris Sosa62ad8522011-03-08 17:46:17 -0800280 for path in options.overlays.split(':'):
Ryan Cui05a31ba2011-05-31 17:47:37 -0700281 if not os.path.isdir(path):
Chris Sosac13bba52011-05-24 15:14:09 -0700282 cros_build_lib.Die('Cannot find overlay: %s' % path)
Ningning Xiadb884322018-01-26 16:27:06 -0800283 overlays.append(os.path.realpath(path))
Don Garrettf9eff952018-08-10 16:50:04 -0700284 elif options.overlay_type:
285 overlays = portage_util.FindOverlays(
Don Garrett4fef8c32018-08-10 18:04:01 -0700286 options.overlay_type, buildroot=options.buildroot)
Chris Sosadad0d322011-01-31 16:37:33 -0800287 else:
Ralph Nathan446aee92015-03-23 14:44:56 -0700288 logging.warning('Missing --overlays argument')
Ningning Xiadb884322018-01-26 16:27:06 -0800289 overlays.extend([
Don Garrett4fef8c32018-08-10 18:04:01 -0700290 '%s/src/private-overlays/chromeos-overlay' % options.buildroot,
291 '%s/src/third_party/chromiumos-overlay' % options.buildroot])
Chris Sosadad0d322011-01-31 16:37:33 -0800292
Don Garrett4fef8c32018-08-10 18:04:01 -0700293 manifest = git.ManifestCheckout.Cached(options.buildroot)
Ryan Cui4656a3c2011-05-24 12:30:30 -0700294
Ningning Xia419e4eb2018-02-05 10:30:36 -0800295 # Dict mapping from each overlay to its tracking branch.
296 overlay_tracking_branch = {}
297 # Dict mapping from each git repository (project) to a list of its overlays.
298 git_project_overlays = {}
299
300 for overlay in overlays:
301 remote_ref = git.GetTrackingBranchViaManifest(overlay, manifest=manifest)
302 overlay_tracking_branch[overlay] = remote_ref.ref
303 git_project_overlays.setdefault(remote_ref.project_name, []).append(overlay)
304
305 if options.command == 'push':
306 _WorkOnPush(options, overlay_tracking_branch, git_project_overlays)
307 elif options.command == 'commit':
308 _WorkOnCommit(options, overlays, overlay_tracking_branch,
309 git_project_overlays, manifest, package_list)
310
311
312def _WorkOnPush(options, overlay_tracking_branch, git_project_overlays):
313 """Push uprevs of overlays belonging to differet git projects in parallel.
314
315 Args:
316 options: The options object returned by the argument parser.
317 overlay_tracking_branch: A dict mapping from each overlay to its tracking
318 branch.
319 git_project_overlays: A dict mapping from each git repository to a list of
320 its overlays.
321 """
322 inputs = [[options, overlays_per_project, overlay_tracking_branch]
Mike Frysinger0bdbc102019-06-13 15:27:29 -0400323 for overlays_per_project in git_project_overlays.values()]
Ningning Xia419e4eb2018-02-05 10:30:36 -0800324 parallel.RunTasksInProcessPool(_PushOverlays, inputs)
325
326
327def _PushOverlays(options, overlays, overlay_tracking_branch):
328 """Push uprevs for overlays in sequence.
329
330 Args:
331 options: The options object returned by the argument parser.
332 overlays: A list of overlays to push uprevs in sequence.
333 overlay_tracking_branch: A dict mapping from each overlay to its tracking
334 branch.
335 """
336 for overlay in overlays:
337 if not os.path.isdir(overlay):
338 logging.warning('Skipping %s, which is not a directory.', overlay)
339 continue
340
341 tracking_branch = overlay_tracking_branch[overlay]
342 PushChange(constants.STABLE_EBUILD_BRANCH, tracking_branch, options.dryrun,
343 cwd=overlay, staging_branch=options.staging_branch)
344
345
346def _WorkOnCommit(options, overlays, overlay_tracking_branch,
347 git_project_overlays, manifest, package_list):
348 """Commit uprevs of overlays belonging to different git projects in parallel.
349
350 Args:
351 options: The options object returned by the argument parser.
352 overlays: A list of overlays to work on.
353 overlay_tracking_branch: A dict mapping from each overlay to its tracking
354 branch.
355 git_project_overlays: A dict mapping from each git repository to a list of
356 its overlays.
357 manifest: The manifest of the given source root.
358 package_list: A list of packages passed from commandline to work on.
359 """
Mike Frysinger62ff8d72020-05-19 03:06:51 -0400360 # We cleaned up self referential ebuilds by this version, but don't enforce
361 # the check on older ones to avoid breaking factory/firmware branches.
362 root_version = manifest_version.VersionInfo.from_repo(options.buildroot)
363 no_self_repos_version = manifest_version.VersionInfo('13099.0.0')
364 reject_self_repo = root_version >= no_self_repos_version
365
Ningning Xia419e4eb2018-02-05 10:30:36 -0800366 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,
Mike Frysinger62ff8d72020-05-19 03:06:51 -0400374 overlay_ebuilds, revved_packages, new_package_atoms,
375 reject_self_repo]
Mike Frysinger0bdbc102019-06-13 15:27:29 -0400376 for overlays_per_project in git_project_overlays.values()]
Ningning Xia419e4eb2018-02-05 10:30:36 -0800377 parallel.RunTasksInProcessPool(_CommitOverlays, inputs)
Chris Sosadad0d322011-01-31 16:37:33 -0800378
Don Garrett4fef8c32018-08-10 18:04:01 -0700379 chroot_path = os.path.join(options.buildroot, constants.DEFAULT_CHROOT_DIR)
Ningning Xia419e4eb2018-02-05 10:30:36 -0800380 if os.path.exists(chroot_path):
Don Garrett4fef8c32018-08-10 18:04:01 -0700381 CleanStalePackages(options.buildroot, options.boards.split(':'),
Ningning Xia419e4eb2018-02-05 10:30:36 -0800382 new_package_atoms)
Mike Nicholsf7f13a82019-01-11 17:11:04 +0000383 if options.drop_file:
384 osutils.WriteFile(options.drop_file, ' '.join(revved_packages))
Chris Sosadad0d322011-01-31 16:37:33 -0800385
Brian Harring609dc4e2012-05-07 02:17:44 -0700386
Ningning Xia419e4eb2018-02-05 10:30:36 -0800387def _GetOverlayToEbuildsMap(options, overlays, package_list):
388 """Get ebuilds for overlays.
David James15ed1302013-04-25 09:21:19 -0700389
Ningning Xia783efc02018-01-24 13:39:51 -0800390 Args:
Ningning Xia783efc02018-01-24 13:39:51 -0800391 options: The options object returned by the argument parser.
Ningning Xia419e4eb2018-02-05 10:30:36 -0800392 overlays: A list of overlays to work on.
393 package_list: A list of packages passed from commandline to work on.
394
395 Returns:
396 A dict mapping each overlay to a list of ebuilds belonging to it.
397 """
Don Garrett3dbb2932018-10-02 14:41:26 -0700398 root_version = manifest_version.VersionInfo.from_repo(options.buildroot)
399 subdir_removal = manifest_version.VersionInfo('10363.0.0')
400 require_subdir_support = root_version < subdir_removal
401
Ningning Xia419e4eb2018-02-05 10:30:36 -0800402 overlay_ebuilds = {}
Don Garrett3dbb2932018-10-02 14:41:26 -0700403 inputs = [[overlay, options.all, package_list, options.force,
404 require_subdir_support]
Ningning Xia419e4eb2018-02-05 10:30:36 -0800405 for overlay in overlays]
406 result = parallel.RunTasksInProcessPool(
407 portage_util.GetOverlayEBuilds, inputs)
408 for idx, ebuilds in enumerate(result):
409 overlay_ebuilds[overlays[idx]] = ebuilds
410
411 return overlay_ebuilds
412
413
414def _CommitOverlays(options, manifest, overlays, overlay_tracking_branch,
Mike Frysinger62ff8d72020-05-19 03:06:51 -0400415 overlay_ebuilds, revved_packages, new_package_atoms,
416 reject_self_repo=True):
Ningning Xia419e4eb2018-02-05 10:30:36 -0800417 """Commit uprevs for overlays in sequence.
418
419 Args:
420 options: The options object returned by the argument parser.
421 manifest: The manifest of the given source root.
422 overlays: A list over overlays to commit.
423 overlay_tracking_branch: A dict mapping from each overlay to its tracking
424 branch.
425 overlay_ebuilds: A dict mapping overlays to their ebuilds.
Ningning Xia783efc02018-01-24 13:39:51 -0800426 revved_packages: A shared list of revved packages.
427 new_package_atoms: A shared list of new package atoms.
Mike Frysinger62ff8d72020-05-19 03:06:51 -0400428 reject_self_repo: Whether to abort if the ebuild lives in the same git
429 repo as it is tracking for uprevs.
Ningning Xia783efc02018-01-24 13:39:51 -0800430 """
Ningning Xia419e4eb2018-02-05 10:30:36 -0800431 for overlay in overlays:
432 if not os.path.isdir(overlay):
433 logging.warning('Skipping %s, which is not a directory.', overlay)
434 continue
Ningning Xia783efc02018-01-24 13:39:51 -0800435
Ningning Xia419e4eb2018-02-05 10:30:36 -0800436 # Note we intentionally work from the non push tracking branch;
437 # everything built thus far has been against it (meaning, http mirrors),
438 # thus we should honor that. During the actual push, the code switches
439 # to the correct urls, and does an appropriate rebasing.
440 tracking_branch = overlay_tracking_branch[overlay]
Ningning Xia783efc02018-01-24 13:39:51 -0800441
Ningning Xia783efc02018-01-24 13:39:51 -0800442 existing_commit = git.GetGitRepoRevision(overlay)
Lann Martine0ef98c2018-06-11 13:12:24 -0600443
444 # Make sure we run in the top-level git directory in case we are
445 # adding/removing an overlay in existing_commit.
446 git_root = git.FindGitTopLevel(overlay)
447 if git_root is None:
448 cros_build_lib.Die('No git repo at overlay directory %s.', overlay)
449
Ningning Xia783efc02018-01-24 13:39:51 -0800450 work_branch = GitBranch(constants.STABLE_EBUILD_BRANCH, tracking_branch,
Lann Martine0ef98c2018-06-11 13:12:24 -0600451 cwd=git_root)
Ningning Xia783efc02018-01-24 13:39:51 -0800452 work_branch.CreateBranch()
453 if not work_branch.Exists():
454 cros_build_lib.Die('Unable to create stabilizing branch in %s' %
455 overlay)
456
457 # In the case of uprevving overlays that have patches applied to them,
458 # include the patched changes in the stabilizing branch.
Lann Martine0ef98c2018-06-11 13:12:24 -0600459 git.RunGit(git_root, ['rebase', existing_commit])
Ningning Xia783efc02018-01-24 13:39:51 -0800460
Ningning Xiadb884322018-01-26 16:27:06 -0800461 ebuilds = overlay_ebuilds.get(overlay, [])
Ningning Xia783efc02018-01-24 13:39:51 -0800462 if ebuilds:
Ningning Xia419e4eb2018-02-05 10:30:36 -0800463 with parallel.Manager() as manager:
464 # Contains the array of packages we actually revved.
465 messages = manager.list()
466 ebuild_paths_to_add = manager.list()
467 ebuild_paths_to_remove = manager.list()
Ningning Xia783efc02018-01-24 13:39:51 -0800468
Ningning Xia419e4eb2018-02-05 10:30:36 -0800469 inputs = [[overlay, ebuild, manifest, options, ebuild_paths_to_add,
470 ebuild_paths_to_remove, messages, revved_packages,
Mike Frysinger62ff8d72020-05-19 03:06:51 -0400471 new_package_atoms, reject_self_repo]
472 for ebuild in ebuilds]
Ningning Xia419e4eb2018-02-05 10:30:36 -0800473 parallel.RunTasksInProcessPool(_WorkOnEbuild, inputs)
Ningning Xia783efc02018-01-24 13:39:51 -0800474
Ningning Xia419e4eb2018-02-05 10:30:36 -0800475 if ebuild_paths_to_add:
476 logging.info('Adding new stable ebuild paths %s in overlay %s.',
477 ebuild_paths_to_add, overlay)
478 git.RunGit(overlay, ['add'] + list(ebuild_paths_to_add))
David James15ed1302013-04-25 09:21:19 -0700479
Ningning Xia419e4eb2018-02-05 10:30:36 -0800480 if ebuild_paths_to_remove:
481 logging.info('Removing old ebuild paths %s in overlay %s.',
482 ebuild_paths_to_remove, overlay)
483 git.RunGit(overlay, ['rm', '-f'] + list(ebuild_paths_to_remove))
484
485 if messages:
486 portage_util.EBuild.CommitChange('\n\n'.join(messages), overlay)
David James15ed1302013-04-25 09:21:19 -0700487
Ningning Xia783efc02018-01-24 13:39:51 -0800488
489def _WorkOnEbuild(overlay, ebuild, manifest, options, ebuild_paths_to_add,
490 ebuild_paths_to_remove, messages, revved_packages,
Mike Frysinger62ff8d72020-05-19 03:06:51 -0400491 new_package_atoms, reject_self_repo=True):
Ningning Xia783efc02018-01-24 13:39:51 -0800492 """Work on a single ebuild.
493
494 Args:
495 overlay: The overlay where the ebuild belongs to.
496 ebuild: The ebuild to work on.
497 manifest: The manifest of the given source root.
498 options: The options object returned by the argument parser.
499 ebuild_paths_to_add: New stable ebuild paths to add to git.
500 ebuild_paths_to_remove: Old ebuild paths to remove from git.
501 messages: A share list of commit messages.
502 revved_packages: A shared list of revved packages.
503 new_package_atoms: A shared list of new package atoms.
Mike Frysinger62ff8d72020-05-19 03:06:51 -0400504 reject_self_repo: Whether to abort if the ebuild lives in the same git
505 repo as it is tracking for uprevs.
Ningning Xia783efc02018-01-24 13:39:51 -0800506 """
507 if options.verbose:
508 logging.info('Working on %s, info %s', ebuild.package,
509 ebuild.cros_workon_vars)
Mike Frysinger00ba05a2020-06-12 02:44:02 -0400510 if not ebuild.cros_workon_vars:
511 logging.warning('%s: unable to parse workon settings', ebuild.ebuild_path)
512
Ningning Xia783efc02018-01-24 13:39:51 -0800513 try:
Don Garrett4fef8c32018-08-10 18:04:01 -0700514 result = ebuild.RevWorkOnEBuild(os.path.join(options.buildroot, 'src'),
Mike Frysinger62ff8d72020-05-19 03:06:51 -0400515 manifest, reject_self_repo=reject_self_repo)
Ningning Xia783efc02018-01-24 13:39:51 -0800516 if result:
517 new_package, ebuild_path_to_add, ebuild_path_to_remove = result
518
519 if ebuild_path_to_add:
520 ebuild_paths_to_add.append(ebuild_path_to_add)
521 if ebuild_path_to_remove:
522 ebuild_paths_to_remove.append(ebuild_path_to_remove)
523
524 messages.append(_GIT_COMMIT_MESSAGE % ebuild.package)
Sam McNallyeb5e2052018-09-05 16:34:55 +1000525
526 if options.list_revisions:
527 info = ebuild.GetSourceInfo(os.path.join(options.buildroot, 'src'),
Mike Frysinger62ff8d72020-05-19 03:06:51 -0400528 manifest, reject_self_repo=reject_self_repo)
Sam McNallyeb5e2052018-09-05 16:34:55 +1000529 srcdirs = [os.path.join(options.buildroot, 'src', srcdir)
530 for srcdir in ebuild.cros_workon_vars.localname]
531 old_commit_ids = dict(
532 zip(srcdirs, ebuild.cros_workon_vars.commit.split(',')))
533 git_log = []
534 for srcdir in info.srcdirs:
535 old_commit_id = old_commit_ids.get(srcdir)
536 new_commit_id = ebuild.GetCommitId(srcdir)
537 if not old_commit_id or old_commit_id == new_commit_id:
538 continue
539
540 logs = git.RunGit(srcdir, [
541 'log', '%s..%s' % (old_commit_id[:8], new_commit_id[:8]),
542 '--pretty=format:%h %<(63,trunc)%s'])
543 git_log.append('$ ' + logs.cmdstr)
544 git_log.extend(line.strip() for line in logs.output.splitlines())
545 if git_log:
546 messages.append('\n'.join(git_log))
547
Ningning Xia783efc02018-01-24 13:39:51 -0800548 revved_packages.append(ebuild.package)
549 new_package_atoms.append('=%s' % new_package)
David Burger8cf4a762020-03-09 10:33:38 -0600550 except portage_util.InvalidUprevSourceError as e:
551 logging.error('An error occurred while uprevving %s: %s',
552 ebuild.package, e)
553 raise
Alex Klein99920662019-10-14 15:30:15 -0600554 except portage_util.EbuildVersionError as e:
555 logging.warning('Unable to rev %s: %s', ebuild.package, e)
556 raise
Mike Frysingerb32cc472020-05-15 00:17:54 -0400557 except OSError:
Ningning Xia783efc02018-01-24 13:39:51 -0800558 logging.warning(
559 'Cannot rev %s\n'
560 'Note you will have to go into %s '
Ningning Xia419e4eb2018-02-05 10:30:36 -0800561 'and reset the git repo yourself.', ebuild.package, overlay)
Ningning Xia783efc02018-01-24 13:39:51 -0800562 raise