blob: 9f3802030f7a224bf22ce27135381caecfca7d44 [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
Chris Sosadad0d322011-01-31 16:37:33 -080011
Aviv Keshetb7519e12016-10-04 00:50:00 -070012from chromite.lib import constants
Mike Frysingere8dcbfd2015-03-08 21:45:52 -040013from chromite.lib import commandline
Chris Sosac13bba52011-05-24 15:14:09 -070014from chromite.lib import cros_build_lib
Ralph Nathan03047282015-03-23 11:09:32 -070015from chromite.lib import cros_logging as logging
David James97d95872012-11-16 15:09:56 -080016from chromite.lib import git
Mike Frysingerfddaeb52012-11-20 11:17:31 -050017from chromite.lib import osutils
David James6450a0a2012-12-04 07:59:53 -080018from chromite.lib import parallel
Alex Deymo075c2292014-09-04 18:31:50 -070019from chromite.lib import portage_util
Lann Martinb26e1292018-08-09 13:59:19 -060020from chromite.lib import repo_util
Chris Sosac13bba52011-05-24 15:14:09 -070021
Don Garrett3dbb2932018-10-02 14:41:26 -070022from chromite.cbuildbot import manifest_version
23
Gabe Black71e963e2014-10-28 20:19:59 -070024# Commit message subject for uprevving Portage packages.
25GIT_COMMIT_SUBJECT = 'Marking set of ebuilds as stable'
David James15ed1302013-04-25 09:21:19 -070026
David James29e86d52013-04-19 09:41:29 -070027# Commit message for uprevving Portage packages.
28_GIT_COMMIT_MESSAGE = 'Marking 9999 ebuild for %s as stable.'
29
Chris Sosadad0d322011-01-31 16:37:33 -080030# Dictionary of valid commands with usage information.
31COMMAND_DICTIONARY = {
Mike Frysinger5cd8c742013-10-11 14:43:01 -040032 'commit': 'Marks given ebuilds as stable locally',
33 'push': 'Pushes previous marking of ebuilds to remote repo',
34}
Chris Sosadad0d322011-01-31 16:37:33 -080035
Chris Sosadad0d322011-01-31 16:37:33 -080036
Chris Sosadad0d322011-01-31 16:37:33 -080037# ======================= Global Helper Functions ========================
38
39
David James41124af2015-06-04 21:13:25 -070040def CleanStalePackages(srcroot, boards, package_atoms):
Chris Sosabf153872011-04-28 14:21:09 -070041 """Cleans up stale package info from a previous build.
Mike Frysinger5cd8c742013-10-11 14:43:01 -040042
Chris Sosabf153872011-04-28 14:21:09 -070043 Args:
David James41124af2015-06-04 21:13:25 -070044 srcroot: Root directory of the source tree.
David Jamescc09c9b2012-01-26 22:10:13 -080045 boards: Boards to clean the packages from.
Mike Frysingerde5ab0e2013-03-21 20:48:36 -040046 package_atoms: A list of package atoms to unmerge.
Chris Sosabf153872011-04-28 14:21:09 -070047 """
David James15ed1302013-04-25 09:21:19 -070048 if package_atoms:
Lann Martinffb95162018-08-28 12:02:54 -060049 logging.info('Cleaning up stale packages %s.', package_atoms)
David James15ed1302013-04-25 09:21:19 -070050
Mike Frysingerb7ab9b82012-04-04 16:22:43 -040051 # First unmerge all the packages for a board, then eclean it.
52 # We need these two steps to run in order (unmerge/eclean),
53 # but we can let all the boards run in parallel.
54 def _CleanStalePackages(board):
55 if board:
56 suffix = '-' + board
Mike Frysinger45602c72019-09-22 02:15:11 -040057 runcmd = cros_build_lib.run
Mike Frysingerb7ab9b82012-04-04 16:22:43 -040058 else:
59 suffix = ''
Mike Frysinger45602c72019-09-22 02:15:11 -040060 runcmd = cros_build_lib.sudo_run
Chris Sosadad0d322011-01-31 16:37:33 -080061
David James59a0a2b2013-03-22 14:04:44 -070062 emerge, eclean = 'emerge' + suffix, 'eclean' + suffix
63 if not osutils.FindMissingBinaries([emerge, eclean]):
David James63841a82014-01-16 14:39:24 -080064 if package_atoms:
65 # If nothing was found to be unmerged, emerge will exit(1).
Don Garrett7100fff2018-10-23 11:07:13 -070066 result = runcmd([emerge, '-q', '--unmerge'] + list(package_atoms),
David James41124af2015-06-04 21:13:25 -070067 enter_chroot=True, extra_env={'CLEAN_DELAY': '0'},
68 error_code_ok=True, cwd=srcroot)
David James63841a82014-01-16 14:39:24 -080069 if not result.returncode in (0, 1):
70 raise cros_build_lib.RunCommandError('unexpected error', result)
David James59a0a2b2013-03-22 14:04:44 -070071 runcmd([eclean, '-d', 'packages'],
David James41124af2015-06-04 21:13:25 -070072 cwd=srcroot, enter_chroot=True,
David James59a0a2b2013-03-22 14:04:44 -070073 redirect_stdout=True, redirect_stderr=True)
Mike Frysingerb7ab9b82012-04-04 16:22:43 -040074
75 tasks = []
David Jamescc09c9b2012-01-26 22:10:13 -080076 for board in boards:
Mike Frysingerb7ab9b82012-04-04 16:22:43 -040077 tasks.append([board])
78 tasks.append([None])
79
David James6450a0a2012-12-04 07:59:53 -080080 parallel.RunTasksInProcessPool(_CleanStalePackages, tasks)
Chris Sosadad0d322011-01-31 16:37:33 -080081
82
Mike Frysinger2ebe3732012-05-08 17:04:12 -040083# TODO(build): This code needs to be gutted and rebased to cros_build_lib.
84def _DoWeHaveLocalCommits(stable_branch, tracking_branch, cwd):
Chris Sosadad0d322011-01-31 16:37:33 -080085 """Returns true if there are local commits."""
David James97d95872012-11-16 15:09:56 -080086 output = git.RunGit(
Paul Hobbs72d8e392015-10-21 17:24:23 -070087 cwd, ['rev-parse', stable_branch, tracking_branch]).output.split()
Brian Harring5b86b5e2012-05-25 18:27:40 -070088 return output[0] != output[1]
Chris Sosadad0d322011-01-31 16:37:33 -080089
90
Chris Sosadad0d322011-01-31 16:37:33 -080091# ======================= End Global Helper Functions ========================
92
93
Ningning Xia52009062016-05-09 14:33:51 -070094def PushChange(stable_branch, tracking_branch, dryrun, cwd,
95 staging_branch=None):
Chris Sosadad0d322011-01-31 16:37:33 -080096 """Pushes commits in the stable_branch to the remote git repository.
97
David Jamesee2da622012-02-23 09:32:16 -080098 Pushes local commits from calls to CommitChange to the remote git
David James66009462012-03-25 10:08:38 -070099 repository specified by current working directory. If changes are
100 found to commit, they will be merged to the merge branch and pushed.
101 In that case, the local repository will be left on the merge branch.
Chris Sosadad0d322011-01-31 16:37:33 -0800102
103 Args:
104 stable_branch: The local branch with commits we want to push.
105 tracking_branch: The tracking branch of the local branch.
Chris Sosa62ad8522011-03-08 17:46:17 -0800106 dryrun: Use git push --dryrun to emulate a push.
Mike Frysinger2ebe3732012-05-08 17:04:12 -0400107 cwd: The directory to run commands in.
Ningning Xia52009062016-05-09 14:33:51 -0700108 staging_branch: The staging branch to push for a failed PFQ run
Mike Frysinger1a736a82013-12-12 01:50:59 -0500109
Chris Sosadad0d322011-01-31 16:37:33 -0800110 Raises:
Mike Frysinger5cd8c742013-10-11 14:43:01 -0400111 OSError: Error occurred while pushing.
Chris Sosadad0d322011-01-31 16:37:33 -0800112 """
David James47959632015-10-23 07:56:01 -0700113 if not git.DoesCommitExistInRepo(cwd, stable_branch):
114 logging.debug('No branch created for %s. Exiting', cwd)
115 return
116
Mike Frysinger2ebe3732012-05-08 17:04:12 -0400117 if not _DoWeHaveLocalCommits(stable_branch, tracking_branch, cwd):
David James47959632015-10-23 07:56:01 -0700118 logging.debug('No work found to push in %s. Exiting', cwd)
Chris Sosadad0d322011-01-31 16:37:33 -0800119 return
120
David James66009462012-03-25 10:08:38 -0700121 # For the commit queue, our local branch may contain commits that were
122 # just tested and pushed during the CommitQueueCompletion stage. Sync
123 # and rebase our local branch on top of the remote commits.
Paul Hobbs72d8e392015-10-21 17:24:23 -0700124 remote_ref = git.GetTrackingBranch(cwd,
125 branch=stable_branch,
126 for_push=True)
Paul Hobbs1e46be82015-10-30 13:46:02 -0700127 # SyncPushBranch rebases HEAD onto the updated remote. We need to checkout
128 # stable_branch here in order to update it.
129 git.RunGit(cwd, ['checkout', stable_branch])
Don Garrett99449592015-03-25 11:01:30 -0700130 git.SyncPushBranch(cwd, remote_ref.remote, remote_ref.ref)
David James66009462012-03-25 10:08:38 -0700131
132 # Check whether any local changes remain after the sync.
Don Garrett99449592015-03-25 11:01:30 -0700133 if not _DoWeHaveLocalCommits(stable_branch, remote_ref.ref, cwd):
Ralph Nathan03047282015-03-23 11:09:32 -0700134 logging.info('All changes already pushed for %s. Exiting', cwd)
David James66009462012-03-25 10:08:38 -0700135 return
136
Andrew Lamb7ef2c0b2019-07-17 09:43:27 -0600137 # Add a failsafe check here. Only CLs from the 'chrome-bot' or
138 # 'chromeos-ci-prod' user should be involved here. If any other CLs are
139 # found then complain. In dryruns extra CLs are normal, though, and can
140 # be ignored.
141 bad_cl_cmd = [
142 'log', '--format=short', '--perl-regexp', '--author',
143 '^(?!chrome-bot|chromeos-ci-prod)',
144 '%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 '
150 'chrome-bot or chromeos-ci-prod:\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',
220 help='Force the stabilization of blacklisted packages. '
221 '(only compatible with -p)')
Sam McNallyeb5e2052018-09-05 16:34:55 +1000222 parser.add_argument('--list_revisions', action='store_true',
223 help='List all revisions included in the commit message.')
Mike Frysingere8dcbfd2015-03-08 21:45:52 -0400224 parser.add_argument('-o', '--overlays',
225 help='Colon-separated list of overlays to modify.')
Don Garrettf9eff952018-08-10 16:50:04 -0700226 parser.add_argument('--overlay-type',
227 help='Populates --overlays based on "public", "private"'
228 ', or "both".')
Mike Frysingere8dcbfd2015-03-08 21:45:52 -0400229 parser.add_argument('-p', '--packages',
230 help='Colon separated list of packages to rev.')
Don Garrett4fef8c32018-08-10 18:04:01 -0700231 parser.add_argument('--buildroot', type='path',
232 help='Path to buildroot.')
Mike Frysingere8dcbfd2015-03-08 21:45:52 -0400233 parser.add_argument('-r', '--srcroot', type='path',
Don Garrett4fef8c32018-08-10 18:04:01 -0700234 help='Path to root src. Deprecated in favor of '
235 '--buildroot')
Mike Frysingere8dcbfd2015-03-08 21:45:52 -0400236 parser.add_argument('--verbose', action='store_true',
237 help='Prints out debug info.')
Ningning Xia52009062016-05-09 14:33:51 -0700238 parser.add_argument('--staging_branch',
239 help='The staging branch to push changes')
Mike Frysingere8dcbfd2015-03-08 21:45:52 -0400240 parser.add_argument('command', choices=COMMAND_DICTIONARY.keys(),
241 help='Command to run.')
242 return parser
243
244
245def main(argv):
246 parser = GetParser()
247 options = parser.parse_args(argv)
Don Garrett4fef8c32018-08-10 18:04:01 -0700248
249 # TODO: Remove this code in favor of a simple default on buildroot when
250 # srcroot is removed.
251 if options.srcroot and not options.buildroot:
252 # Convert /<repo>/src -> <repo>
253 options.buildroot = os.path.dirname(options.srcroot)
254 if not options.buildroot:
255 options.buildroot = constants.SOURCE_ROOT
256 options.srcroot = None
257
Bertrand SIMONNET6af54302015-08-05 10:12:49 -0700258 options.Freeze()
Mike Frysingere8dcbfd2015-03-08 21:45:52 -0400259
Bertrand SIMONNET6af54302015-08-05 10:12:49 -0700260 if options.command == 'commit':
261 if not options.packages and not options.all:
262 parser.error('Please specify at least one package (--packages)')
263 if options.force and options.all:
264 parser.error('Cannot use --force with --all. You must specify a list of '
265 'packages you want to force uprev.')
266
Don Garrett4fef8c32018-08-10 18:04:01 -0700267 if not os.path.isdir(options.buildroot):
268 parser.error('buildroot is not a valid path: %s' % options.buildroot)
Mike Frysingere8dcbfd2015-03-08 21:45:52 -0400269
Don Garrettf9eff952018-08-10 16:50:04 -0700270 if options.overlay_type and options.overlays:
271 parser.error('Cannot use --overlay-type with --overlays.')
272
Alex Deymo075c2292014-09-04 18:31:50 -0700273 portage_util.EBuild.VERBOSE = options.verbose
Chris Sosa62ad8522011-03-08 17:46:17 -0800274
Chris Sosa62ad8522011-03-08 17:46:17 -0800275 package_list = None
276 if options.packages:
277 package_list = options.packages.split(':')
278
Ningning Xiadb884322018-01-26 16:27:06 -0800279 overlays = []
Chris Sosa62ad8522011-03-08 17:46:17 -0800280 if options.overlays:
Chris Sosa62ad8522011-03-08 17:46:17 -0800281 for path in options.overlays.split(':'):
Ryan Cui05a31ba2011-05-31 17:47:37 -0700282 if not os.path.isdir(path):
Chris Sosac13bba52011-05-24 15:14:09 -0700283 cros_build_lib.Die('Cannot find overlay: %s' % path)
Ningning Xiadb884322018-01-26 16:27:06 -0800284 overlays.append(os.path.realpath(path))
Don Garrettf9eff952018-08-10 16:50:04 -0700285 elif options.overlay_type:
286 overlays = portage_util.FindOverlays(
Don Garrett4fef8c32018-08-10 18:04:01 -0700287 options.overlay_type, buildroot=options.buildroot)
Chris Sosadad0d322011-01-31 16:37:33 -0800288 else:
Ralph Nathan446aee92015-03-23 14:44:56 -0700289 logging.warning('Missing --overlays argument')
Ningning Xiadb884322018-01-26 16:27:06 -0800290 overlays.extend([
Don Garrett4fef8c32018-08-10 18:04:01 -0700291 '%s/src/private-overlays/chromeos-overlay' % options.buildroot,
292 '%s/src/third_party/chromiumos-overlay' % options.buildroot])
Chris Sosadad0d322011-01-31 16:37:33 -0800293
Don Garrett4fef8c32018-08-10 18:04:01 -0700294 manifest = git.ManifestCheckout.Cached(options.buildroot)
Ryan Cui4656a3c2011-05-24 12:30:30 -0700295
Ningning Xia419e4eb2018-02-05 10:30:36 -0800296 # Dict mapping from each overlay to its tracking branch.
297 overlay_tracking_branch = {}
298 # Dict mapping from each git repository (project) to a list of its overlays.
299 git_project_overlays = {}
300
301 for overlay in overlays:
302 remote_ref = git.GetTrackingBranchViaManifest(overlay, manifest=manifest)
303 overlay_tracking_branch[overlay] = remote_ref.ref
304 git_project_overlays.setdefault(remote_ref.project_name, []).append(overlay)
305
306 if options.command == 'push':
307 _WorkOnPush(options, overlay_tracking_branch, git_project_overlays)
308 elif options.command == 'commit':
309 _WorkOnCommit(options, overlays, overlay_tracking_branch,
310 git_project_overlays, manifest, package_list)
311
312
313def _WorkOnPush(options, overlay_tracking_branch, git_project_overlays):
314 """Push uprevs of overlays belonging to differet git projects in parallel.
315
316 Args:
317 options: The options object returned by the argument parser.
318 overlay_tracking_branch: A dict mapping from each overlay to its tracking
319 branch.
320 git_project_overlays: A dict mapping from each git repository to a list of
321 its overlays.
322 """
323 inputs = [[options, overlays_per_project, overlay_tracking_branch]
Mike Frysinger0bdbc102019-06-13 15:27:29 -0400324 for overlays_per_project in git_project_overlays.values()]
Ningning Xia419e4eb2018-02-05 10:30:36 -0800325 parallel.RunTasksInProcessPool(_PushOverlays, inputs)
326
327
328def _PushOverlays(options, overlays, overlay_tracking_branch):
329 """Push uprevs for overlays in sequence.
330
331 Args:
332 options: The options object returned by the argument parser.
333 overlays: A list of overlays to push uprevs in sequence.
334 overlay_tracking_branch: A dict mapping from each overlay to its tracking
335 branch.
336 """
337 for overlay in overlays:
338 if not os.path.isdir(overlay):
339 logging.warning('Skipping %s, which is not a directory.', overlay)
340 continue
341
342 tracking_branch = overlay_tracking_branch[overlay]
343 PushChange(constants.STABLE_EBUILD_BRANCH, tracking_branch, options.dryrun,
344 cwd=overlay, staging_branch=options.staging_branch)
345
346
347def _WorkOnCommit(options, overlays, overlay_tracking_branch,
348 git_project_overlays, manifest, package_list):
349 """Commit uprevs of overlays belonging to different git projects in parallel.
350
351 Args:
352 options: The options object returned by the argument parser.
353 overlays: A list of overlays to work on.
354 overlay_tracking_branch: A dict mapping from each overlay to its tracking
355 branch.
356 git_project_overlays: A dict mapping from each git repository to a list of
357 its overlays.
358 manifest: The manifest of the given source root.
359 package_list: A list of packages passed from commandline to work on.
360 """
361 overlay_ebuilds = _GetOverlayToEbuildsMap(options, overlays, package_list)
David James84e953c2013-04-23 18:44:06 -0700362
Ningning Xia783efc02018-01-24 13:39:51 -0800363 with parallel.Manager() as manager:
364 # Contains the array of packages we actually revved.
365 revved_packages = manager.list()
366 new_package_atoms = manager.list()
David Jamesa8457b52011-05-28 00:03:20 -0700367
Ningning Xia419e4eb2018-02-05 10:30:36 -0800368 inputs = [[options, manifest, overlays_per_project, overlay_tracking_branch,
369 overlay_ebuilds, revved_packages, new_package_atoms]
Mike Frysinger0bdbc102019-06-13 15:27:29 -0400370 for overlays_per_project in git_project_overlays.values()]
Ningning Xia419e4eb2018-02-05 10:30:36 -0800371 parallel.RunTasksInProcessPool(_CommitOverlays, inputs)
Chris Sosadad0d322011-01-31 16:37:33 -0800372
Don Garrett4fef8c32018-08-10 18:04:01 -0700373 chroot_path = os.path.join(options.buildroot, constants.DEFAULT_CHROOT_DIR)
Ningning Xia419e4eb2018-02-05 10:30:36 -0800374 if os.path.exists(chroot_path):
Don Garrett4fef8c32018-08-10 18:04:01 -0700375 CleanStalePackages(options.buildroot, options.boards.split(':'),
Ningning Xia419e4eb2018-02-05 10:30:36 -0800376 new_package_atoms)
Mike Nicholsf7f13a82019-01-11 17:11:04 +0000377 if options.drop_file:
378 osutils.WriteFile(options.drop_file, ' '.join(revved_packages))
Chris Sosadad0d322011-01-31 16:37:33 -0800379
Brian Harring609dc4e2012-05-07 02:17:44 -0700380
Ningning Xia419e4eb2018-02-05 10:30:36 -0800381def _GetOverlayToEbuildsMap(options, overlays, package_list):
382 """Get ebuilds for overlays.
David James15ed1302013-04-25 09:21:19 -0700383
Ningning Xia783efc02018-01-24 13:39:51 -0800384 Args:
Ningning Xia783efc02018-01-24 13:39:51 -0800385 options: The options object returned by the argument parser.
Ningning Xia419e4eb2018-02-05 10:30:36 -0800386 overlays: A list of overlays to work on.
387 package_list: A list of packages passed from commandline to work on.
388
389 Returns:
390 A dict mapping each overlay to a list of ebuilds belonging to it.
391 """
Don Garrett3dbb2932018-10-02 14:41:26 -0700392 root_version = manifest_version.VersionInfo.from_repo(options.buildroot)
393 subdir_removal = manifest_version.VersionInfo('10363.0.0')
394 require_subdir_support = root_version < subdir_removal
395
Ningning Xia419e4eb2018-02-05 10:30:36 -0800396 overlay_ebuilds = {}
Don Garrett3dbb2932018-10-02 14:41:26 -0700397 inputs = [[overlay, options.all, package_list, options.force,
398 require_subdir_support]
Ningning Xia419e4eb2018-02-05 10:30:36 -0800399 for overlay in overlays]
400 result = parallel.RunTasksInProcessPool(
401 portage_util.GetOverlayEBuilds, inputs)
402 for idx, ebuilds in enumerate(result):
403 overlay_ebuilds[overlays[idx]] = ebuilds
404
405 return overlay_ebuilds
406
407
408def _CommitOverlays(options, manifest, overlays, overlay_tracking_branch,
409 overlay_ebuilds, revved_packages, new_package_atoms):
410 """Commit uprevs for overlays in sequence.
411
412 Args:
413 options: The options object returned by the argument parser.
414 manifest: The manifest of the given source root.
415 overlays: A list over overlays to commit.
416 overlay_tracking_branch: A dict mapping from each overlay to its tracking
417 branch.
418 overlay_ebuilds: A dict mapping overlays to their ebuilds.
Ningning Xia783efc02018-01-24 13:39:51 -0800419 revved_packages: A shared list of revved packages.
420 new_package_atoms: A shared list of new package atoms.
421 """
Ningning Xia419e4eb2018-02-05 10:30:36 -0800422 for overlay in overlays:
423 if not os.path.isdir(overlay):
424 logging.warning('Skipping %s, which is not a directory.', overlay)
425 continue
Ningning Xia783efc02018-01-24 13:39:51 -0800426
Ningning Xia419e4eb2018-02-05 10:30:36 -0800427 # Note we intentionally work from the non push tracking branch;
428 # everything built thus far has been against it (meaning, http mirrors),
429 # thus we should honor that. During the actual push, the code switches
430 # to the correct urls, and does an appropriate rebasing.
431 tracking_branch = overlay_tracking_branch[overlay]
Ningning Xia783efc02018-01-24 13:39:51 -0800432
Ningning Xia783efc02018-01-24 13:39:51 -0800433 existing_commit = git.GetGitRepoRevision(overlay)
Lann Martine0ef98c2018-06-11 13:12:24 -0600434
435 # Make sure we run in the top-level git directory in case we are
436 # adding/removing an overlay in existing_commit.
437 git_root = git.FindGitTopLevel(overlay)
438 if git_root is None:
439 cros_build_lib.Die('No git repo at overlay directory %s.', overlay)
440
Ningning Xia783efc02018-01-24 13:39:51 -0800441 work_branch = GitBranch(constants.STABLE_EBUILD_BRANCH, tracking_branch,
Lann Martine0ef98c2018-06-11 13:12:24 -0600442 cwd=git_root)
Ningning Xia783efc02018-01-24 13:39:51 -0800443 work_branch.CreateBranch()
444 if not work_branch.Exists():
445 cros_build_lib.Die('Unable to create stabilizing branch in %s' %
446 overlay)
447
448 # In the case of uprevving overlays that have patches applied to them,
449 # include the patched changes in the stabilizing branch.
Lann Martine0ef98c2018-06-11 13:12:24 -0600450 git.RunGit(git_root, ['rebase', existing_commit])
Ningning Xia783efc02018-01-24 13:39:51 -0800451
Ningning Xiadb884322018-01-26 16:27:06 -0800452 ebuilds = overlay_ebuilds.get(overlay, [])
Ningning Xia783efc02018-01-24 13:39:51 -0800453 if ebuilds:
Ningning Xia419e4eb2018-02-05 10:30:36 -0800454 with parallel.Manager() as manager:
455 # Contains the array of packages we actually revved.
456 messages = manager.list()
457 ebuild_paths_to_add = manager.list()
458 ebuild_paths_to_remove = manager.list()
Ningning Xia783efc02018-01-24 13:39:51 -0800459
Ningning Xia419e4eb2018-02-05 10:30:36 -0800460 inputs = [[overlay, ebuild, manifest, options, ebuild_paths_to_add,
461 ebuild_paths_to_remove, messages, revved_packages,
462 new_package_atoms] for ebuild in ebuilds]
463 parallel.RunTasksInProcessPool(_WorkOnEbuild, inputs)
Ningning Xia783efc02018-01-24 13:39:51 -0800464
Ningning Xia419e4eb2018-02-05 10:30:36 -0800465 if ebuild_paths_to_add:
466 logging.info('Adding new stable ebuild paths %s in overlay %s.',
467 ebuild_paths_to_add, overlay)
468 git.RunGit(overlay, ['add'] + list(ebuild_paths_to_add))
David James15ed1302013-04-25 09:21:19 -0700469
Ningning Xia419e4eb2018-02-05 10:30:36 -0800470 if ebuild_paths_to_remove:
471 logging.info('Removing old ebuild paths %s in overlay %s.',
472 ebuild_paths_to_remove, overlay)
473 git.RunGit(overlay, ['rm', '-f'] + list(ebuild_paths_to_remove))
474
475 if messages:
476 portage_util.EBuild.CommitChange('\n\n'.join(messages), overlay)
David James15ed1302013-04-25 09:21:19 -0700477
Ningning Xia783efc02018-01-24 13:39:51 -0800478
479def _WorkOnEbuild(overlay, ebuild, manifest, options, ebuild_paths_to_add,
480 ebuild_paths_to_remove, messages, revved_packages,
481 new_package_atoms):
482 """Work on a single ebuild.
483
484 Args:
485 overlay: The overlay where the ebuild belongs to.
486 ebuild: The ebuild to work on.
487 manifest: The manifest of the given source root.
488 options: The options object returned by the argument parser.
489 ebuild_paths_to_add: New stable ebuild paths to add to git.
490 ebuild_paths_to_remove: Old ebuild paths to remove from git.
491 messages: A share list of commit messages.
492 revved_packages: A shared list of revved packages.
493 new_package_atoms: A shared list of new package atoms.
494 """
495 if options.verbose:
496 logging.info('Working on %s, info %s', ebuild.package,
497 ebuild.cros_workon_vars)
498 try:
Don Garrett4fef8c32018-08-10 18:04:01 -0700499 result = ebuild.RevWorkOnEBuild(os.path.join(options.buildroot, 'src'),
500 manifest)
Ningning Xia783efc02018-01-24 13:39:51 -0800501 if result:
502 new_package, ebuild_path_to_add, ebuild_path_to_remove = result
503
504 if ebuild_path_to_add:
505 ebuild_paths_to_add.append(ebuild_path_to_add)
506 if ebuild_path_to_remove:
507 ebuild_paths_to_remove.append(ebuild_path_to_remove)
508
509 messages.append(_GIT_COMMIT_MESSAGE % ebuild.package)
Sam McNallyeb5e2052018-09-05 16:34:55 +1000510
511 if options.list_revisions:
512 info = ebuild.GetSourceInfo(os.path.join(options.buildroot, 'src'),
Sam McNallyd8ed0542018-10-26 16:20:44 +1100513 manifest)
Sam McNallyeb5e2052018-09-05 16:34:55 +1000514 srcdirs = [os.path.join(options.buildroot, 'src', srcdir)
515 for srcdir in ebuild.cros_workon_vars.localname]
516 old_commit_ids = dict(
517 zip(srcdirs, ebuild.cros_workon_vars.commit.split(',')))
518 git_log = []
519 for srcdir in info.srcdirs:
520 old_commit_id = old_commit_ids.get(srcdir)
521 new_commit_id = ebuild.GetCommitId(srcdir)
522 if not old_commit_id or old_commit_id == new_commit_id:
523 continue
524
525 logs = git.RunGit(srcdir, [
526 'log', '%s..%s' % (old_commit_id[:8], new_commit_id[:8]),
527 '--pretty=format:%h %<(63,trunc)%s'])
528 git_log.append('$ ' + logs.cmdstr)
529 git_log.extend(line.strip() for line in logs.output.splitlines())
530 if git_log:
531 messages.append('\n'.join(git_log))
532
Ningning Xia783efc02018-01-24 13:39:51 -0800533 revved_packages.append(ebuild.package)
534 new_package_atoms.append('=%s' % new_package)
Alex Klein99920662019-10-14 15:30:15 -0600535 except portage_util.EbuildVersionError as e:
536 logging.warning('Unable to rev %s: %s', ebuild.package, e)
537 raise
Ningning Xia783efc02018-01-24 13:39:51 -0800538 except (OSError, IOError):
539 logging.warning(
540 'Cannot rev %s\n'
541 'Note you will have to go into %s '
Ningning Xia419e4eb2018-02-05 10:30:36 -0800542 'and reset the git repo yourself.', ebuild.package, overlay)
Ningning Xia783efc02018-01-24 13:39:51 -0800543 raise