blob: bf829353e737e99f59e8895650d1c521d919f890 [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
57 runcmd = cros_build_lib.RunCommand
58 else:
59 suffix = ''
60 runcmd = cros_build_lib.SudoRunCommand
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).
66 result = runcmd([emerge, '-q', '--unmerge'] + 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
Matt Tennantcb522052013-11-25 14:23:43 -0800137 # Add a failsafe check here. Only CLs from the 'chrome-bot' user should
138 # be involved here. If any other CLs are found then complain.
139 # In dryruns extra CLs are normal, though, and can be ignored.
140 bad_cl_cmd = ['log', '--format=short', '--perl-regexp',
141 '--author', '^(?!chrome-bot)', '%s..%s' % (
Don Garrett99449592015-03-25 11:01:30 -0700142 remote_ref.ref, stable_branch)]
Matt Tennantcb522052013-11-25 14:23:43 -0800143 bad_cls = git.RunGit(cwd, bad_cl_cmd).output
144 if bad_cls.strip() and not dryrun:
Ralph Nathan59900422015-03-24 10:41:17 -0700145 logging.error('The Uprev stage found changes from users other than '
146 'chrome-bot:\n\n%s', bad_cls)
Matt Tennantcb522052013-11-25 14:23:43 -0800147 raise AssertionError('Unexpected CLs found during uprev stage.')
148
Lev Rumyantsev25352ba2016-09-07 15:53:58 -0700149 if staging_branch is not None:
150 logging.info('PFQ FAILED. Pushing uprev change to staging branch %s',
151 staging_branch)
152
Mike Frysingere65f3752014-12-08 00:46:39 -0500153 description = git.RunGit(
154 cwd,
155 ['log', '--format=format:%s%n%n%b',
Don Garrett99449592015-03-25 11:01:30 -0700156 '%s..%s' % (remote_ref.ref, stable_branch)]).output
Gabe Black71e963e2014-10-28 20:19:59 -0700157 description = '%s\n\n%s' % (GIT_COMMIT_SUBJECT, description)
Ralph Nathan03047282015-03-23 11:09:32 -0700158 logging.info('For %s, using description %s', cwd, description)
Paul Hobbsf52ea8f2015-10-21 17:24:23 -0700159 git.CreatePushBranch(constants.MERGE_BRANCH, cwd,
160 remote_push_branch=remote_ref)
David James97d95872012-11-16 15:09:56 -0800161 git.RunGit(cwd, ['merge', '--squash', stable_branch])
162 git.RunGit(cwd, ['commit', '-m', description])
163 git.RunGit(cwd, ['config', 'push.default', 'tracking'])
Mike Nicholsa6818c52018-04-09 11:05:42 -0600164 git.PushBranch(constants.MERGE_BRANCH, cwd, dryrun=dryrun,
165 staging_branch=staging_branch)
Chris Sosadad0d322011-01-31 16:37:33 -0800166
167
168class GitBranch(object):
169 """Wrapper class for a git branch."""
170
Mike Frysinger2ebe3732012-05-08 17:04:12 -0400171 def __init__(self, branch_name, tracking_branch, cwd):
David Jamesc7c4ff52013-09-18 17:57:13 -0700172 """Sets up variables but does not create the branch.
173
Mike Frysinger5cd8c742013-10-11 14:43:01 -0400174 Args:
David Jamesc7c4ff52013-09-18 17:57:13 -0700175 branch_name: The name of the branch.
176 tracking_branch: The associated tracking branch.
177 cwd: The git repository to work in.
178 """
Chris Sosadad0d322011-01-31 16:37:33 -0800179 self.branch_name = branch_name
180 self.tracking_branch = tracking_branch
Mike Frysinger2ebe3732012-05-08 17:04:12 -0400181 self.cwd = cwd
Chris Sosadad0d322011-01-31 16:37:33 -0800182
183 def CreateBranch(self):
Mike Frysinger2ebe3732012-05-08 17:04:12 -0400184 self.Checkout()
Chris Sosadad0d322011-01-31 16:37:33 -0800185
Mike Frysinger2ebe3732012-05-08 17:04:12 -0400186 def Checkout(self, branch=None):
Chris Sosadad0d322011-01-31 16:37:33 -0800187 """Function used to check out to another GitBranch."""
Mike Frysinger2ebe3732012-05-08 17:04:12 -0400188 if not branch:
189 branch = self.branch_name
190 if branch == self.tracking_branch or self.Exists(branch):
Lann Martinb26e1292018-08-09 13:59:19 -0600191 git.RunGit(self.cwd, ['checkout', '-f', branch], quiet=True)
Chris Sosadad0d322011-01-31 16:37:33 -0800192 else:
Lann Martinb26e1292018-08-09 13:59:19 -0600193 repo = repo_util.Repository.MustFind(self.cwd)
194 repo.StartBranch(branch, projects=['.'], cwd=self.cwd)
Chris Sosadad0d322011-01-31 16:37:33 -0800195
Mike Frysinger2ebe3732012-05-08 17:04:12 -0400196 def Exists(self, branch=None):
Chris Sosadad0d322011-01-31 16:37:33 -0800197 """Returns True if the branch exists."""
Mike Frysinger2ebe3732012-05-08 17:04:12 -0400198 if not branch:
199 branch = self.branch_name
David James67d73252013-09-19 17:33:12 -0700200 branches = git.RunGit(self.cwd, ['branch']).output
Mike Frysinger2ebe3732012-05-08 17:04:12 -0400201 return branch in branches.split()
Chris Sosadad0d322011-01-31 16:37:33 -0800202
203
Mike Frysingere8dcbfd2015-03-08 21:45:52 -0400204def GetParser():
205 """Creates the argparse parser."""
206 parser = commandline.ArgumentParser()
207 parser.add_argument('--all', action='store_true',
208 help='Mark all packages as stable.')
209 parser.add_argument('-b', '--boards', default='',
210 help='Colon-separated list of boards.')
211 parser.add_argument('--drop_file',
212 help='File to list packages that were revved.')
213 parser.add_argument('--dryrun', action='store_true',
214 help='Passes dry-run to git push if pushing a change.')
Bertrand SIMONNET6af54302015-08-05 10:12:49 -0700215 parser.add_argument('--force', action='store_true',
216 help='Force the stabilization of blacklisted packages. '
217 '(only compatible with -p)')
Sam McNallyeb5e2052018-09-05 16:34:55 +1000218 parser.add_argument('--list_revisions', action='store_true',
219 help='List all revisions included in the commit message.')
Mike Frysingere8dcbfd2015-03-08 21:45:52 -0400220 parser.add_argument('-o', '--overlays',
221 help='Colon-separated list of overlays to modify.')
Don Garrettf9eff952018-08-10 16:50:04 -0700222 parser.add_argument('--overlay-type',
223 help='Populates --overlays based on "public", "private"'
224 ', or "both".')
Mike Frysingere8dcbfd2015-03-08 21:45:52 -0400225 parser.add_argument('-p', '--packages',
226 help='Colon separated list of packages to rev.')
Don Garrett4fef8c32018-08-10 18:04:01 -0700227 parser.add_argument('--buildroot', type='path',
228 help='Path to buildroot.')
Mike Frysingere8dcbfd2015-03-08 21:45:52 -0400229 parser.add_argument('-r', '--srcroot', type='path',
Don Garrett4fef8c32018-08-10 18:04:01 -0700230 help='Path to root src. Deprecated in favor of '
231 '--buildroot')
Mike Frysingere8dcbfd2015-03-08 21:45:52 -0400232 parser.add_argument('--verbose', action='store_true',
233 help='Prints out debug info.')
Ningning Xia52009062016-05-09 14:33:51 -0700234 parser.add_argument('--staging_branch',
235 help='The staging branch to push changes')
Mike Frysingere8dcbfd2015-03-08 21:45:52 -0400236 parser.add_argument('command', choices=COMMAND_DICTIONARY.keys(),
237 help='Command to run.')
238 return parser
239
240
241def main(argv):
242 parser = GetParser()
243 options = parser.parse_args(argv)
Don Garrett4fef8c32018-08-10 18:04:01 -0700244
245 # TODO: Remove this code in favor of a simple default on buildroot when
246 # srcroot is removed.
247 if options.srcroot and not options.buildroot:
248 # Convert /<repo>/src -> <repo>
249 options.buildroot = os.path.dirname(options.srcroot)
250 if not options.buildroot:
251 options.buildroot = constants.SOURCE_ROOT
252 options.srcroot = None
253
Bertrand SIMONNET6af54302015-08-05 10:12:49 -0700254 options.Freeze()
Mike Frysingere8dcbfd2015-03-08 21:45:52 -0400255
Bertrand SIMONNET6af54302015-08-05 10:12:49 -0700256 if options.command == 'commit':
257 if not options.packages and not options.all:
258 parser.error('Please specify at least one package (--packages)')
259 if options.force and options.all:
260 parser.error('Cannot use --force with --all. You must specify a list of '
261 'packages you want to force uprev.')
262
Don Garrett4fef8c32018-08-10 18:04:01 -0700263 if not os.path.isdir(options.buildroot):
264 parser.error('buildroot is not a valid path: %s' % options.buildroot)
Mike Frysingere8dcbfd2015-03-08 21:45:52 -0400265
Don Garrettf9eff952018-08-10 16:50:04 -0700266 if options.overlay_type and options.overlays:
267 parser.error('Cannot use --overlay-type with --overlays.')
268
Alex Deymo075c2292014-09-04 18:31:50 -0700269 portage_util.EBuild.VERBOSE = options.verbose
Chris Sosa62ad8522011-03-08 17:46:17 -0800270
Chris Sosa62ad8522011-03-08 17:46:17 -0800271 package_list = None
272 if options.packages:
273 package_list = options.packages.split(':')
274
Ningning Xiadb884322018-01-26 16:27:06 -0800275 overlays = []
Chris Sosa62ad8522011-03-08 17:46:17 -0800276 if options.overlays:
Chris Sosa62ad8522011-03-08 17:46:17 -0800277 for path in options.overlays.split(':'):
Ryan Cui05a31ba2011-05-31 17:47:37 -0700278 if not os.path.isdir(path):
Chris Sosac13bba52011-05-24 15:14:09 -0700279 cros_build_lib.Die('Cannot find overlay: %s' % path)
Ningning Xiadb884322018-01-26 16:27:06 -0800280 overlays.append(os.path.realpath(path))
Don Garrettf9eff952018-08-10 16:50:04 -0700281 elif options.overlay_type:
282 overlays = portage_util.FindOverlays(
Don Garrett4fef8c32018-08-10 18:04:01 -0700283 options.overlay_type, buildroot=options.buildroot)
Chris Sosadad0d322011-01-31 16:37:33 -0800284 else:
Ralph Nathan446aee92015-03-23 14:44:56 -0700285 logging.warning('Missing --overlays argument')
Ningning Xiadb884322018-01-26 16:27:06 -0800286 overlays.extend([
Don Garrett4fef8c32018-08-10 18:04:01 -0700287 '%s/src/private-overlays/chromeos-overlay' % options.buildroot,
288 '%s/src/third_party/chromiumos-overlay' % options.buildroot])
Chris Sosadad0d322011-01-31 16:37:33 -0800289
Don Garrett4fef8c32018-08-10 18:04:01 -0700290 manifest = git.ManifestCheckout.Cached(options.buildroot)
Ryan Cui4656a3c2011-05-24 12:30:30 -0700291
Ningning Xia419e4eb2018-02-05 10:30:36 -0800292 # Dict mapping from each overlay to its tracking branch.
293 overlay_tracking_branch = {}
294 # Dict mapping from each git repository (project) to a list of its overlays.
295 git_project_overlays = {}
296
297 for overlay in overlays:
298 remote_ref = git.GetTrackingBranchViaManifest(overlay, manifest=manifest)
299 overlay_tracking_branch[overlay] = remote_ref.ref
300 git_project_overlays.setdefault(remote_ref.project_name, []).append(overlay)
301
302 if options.command == 'push':
303 _WorkOnPush(options, overlay_tracking_branch, git_project_overlays)
304 elif options.command == 'commit':
305 _WorkOnCommit(options, overlays, overlay_tracking_branch,
306 git_project_overlays, manifest, package_list)
307
308
309def _WorkOnPush(options, overlay_tracking_branch, git_project_overlays):
310 """Push uprevs of overlays belonging to differet git projects in parallel.
311
312 Args:
313 options: The options object returned by the argument parser.
314 overlay_tracking_branch: A dict mapping from each overlay to its tracking
315 branch.
316 git_project_overlays: A dict mapping from each git repository to a list of
317 its overlays.
318 """
319 inputs = [[options, overlays_per_project, overlay_tracking_branch]
320 for overlays_per_project in git_project_overlays.itervalues()]
321 parallel.RunTasksInProcessPool(_PushOverlays, inputs)
322
323
324def _PushOverlays(options, overlays, overlay_tracking_branch):
325 """Push uprevs for overlays in sequence.
326
327 Args:
328 options: The options object returned by the argument parser.
329 overlays: A list of overlays to push uprevs in sequence.
330 overlay_tracking_branch: A dict mapping from each overlay to its tracking
331 branch.
332 """
333 for overlay in overlays:
334 if not os.path.isdir(overlay):
335 logging.warning('Skipping %s, which is not a directory.', overlay)
336 continue
337
338 tracking_branch = overlay_tracking_branch[overlay]
339 PushChange(constants.STABLE_EBUILD_BRANCH, tracking_branch, options.dryrun,
340 cwd=overlay, staging_branch=options.staging_branch)
341
342
343def _WorkOnCommit(options, overlays, overlay_tracking_branch,
344 git_project_overlays, manifest, package_list):
345 """Commit uprevs of overlays belonging to different git projects in parallel.
346
347 Args:
348 options: The options object returned by the argument parser.
349 overlays: A list of overlays to work on.
350 overlay_tracking_branch: A dict mapping from each overlay to its tracking
351 branch.
352 git_project_overlays: A dict mapping from each git repository to a list of
353 its overlays.
354 manifest: The manifest of the given source root.
355 package_list: A list of packages passed from commandline to work on.
356 """
357 overlay_ebuilds = _GetOverlayToEbuildsMap(options, overlays, package_list)
David James84e953c2013-04-23 18:44:06 -0700358
Ningning Xia783efc02018-01-24 13:39:51 -0800359 with parallel.Manager() as manager:
360 # Contains the array of packages we actually revved.
361 revved_packages = manager.list()
362 new_package_atoms = manager.list()
David Jamesa8457b52011-05-28 00:03:20 -0700363
Ningning Xia419e4eb2018-02-05 10:30:36 -0800364 inputs = [[options, manifest, overlays_per_project, overlay_tracking_branch,
365 overlay_ebuilds, revved_packages, new_package_atoms]
366 for overlays_per_project in git_project_overlays.itervalues()]
367 parallel.RunTasksInProcessPool(_CommitOverlays, inputs)
Chris Sosadad0d322011-01-31 16:37:33 -0800368
Don Garrett4fef8c32018-08-10 18:04:01 -0700369 chroot_path = os.path.join(options.buildroot, constants.DEFAULT_CHROOT_DIR)
Ningning Xia419e4eb2018-02-05 10:30:36 -0800370 if os.path.exists(chroot_path):
Don Garrett4fef8c32018-08-10 18:04:01 -0700371 CleanStalePackages(options.buildroot, options.boards.split(':'),
Ningning Xia419e4eb2018-02-05 10:30:36 -0800372 new_package_atoms)
373 if options.drop_file:
374 osutils.WriteFile(options.drop_file, ' '.join(revved_packages))
Chris Sosadad0d322011-01-31 16:37:33 -0800375
Brian Harring609dc4e2012-05-07 02:17:44 -0700376
Ningning Xia419e4eb2018-02-05 10:30:36 -0800377def _GetOverlayToEbuildsMap(options, overlays, package_list):
378 """Get ebuilds for overlays.
David James15ed1302013-04-25 09:21:19 -0700379
Ningning Xia783efc02018-01-24 13:39:51 -0800380 Args:
Ningning Xia783efc02018-01-24 13:39:51 -0800381 options: The options object returned by the argument parser.
Ningning Xia419e4eb2018-02-05 10:30:36 -0800382 overlays: A list of overlays to work on.
383 package_list: A list of packages passed from commandline to work on.
384
385 Returns:
386 A dict mapping each overlay to a list of ebuilds belonging to it.
387 """
Don Garrett3dbb2932018-10-02 14:41:26 -0700388 root_version = manifest_version.VersionInfo.from_repo(options.buildroot)
389 subdir_removal = manifest_version.VersionInfo('10363.0.0')
390 require_subdir_support = root_version < subdir_removal
391
Ningning Xia419e4eb2018-02-05 10:30:36 -0800392 overlay_ebuilds = {}
Don Garrett3dbb2932018-10-02 14:41:26 -0700393 inputs = [[overlay, options.all, package_list, options.force,
394 require_subdir_support]
Ningning Xia419e4eb2018-02-05 10:30:36 -0800395 for overlay in overlays]
396 result = parallel.RunTasksInProcessPool(
397 portage_util.GetOverlayEBuilds, inputs)
398 for idx, ebuilds in enumerate(result):
399 overlay_ebuilds[overlays[idx]] = ebuilds
400
401 return overlay_ebuilds
402
403
404def _CommitOverlays(options, manifest, overlays, overlay_tracking_branch,
405 overlay_ebuilds, revved_packages, new_package_atoms):
406 """Commit uprevs for overlays in sequence.
407
408 Args:
409 options: The options object returned by the argument parser.
410 manifest: The manifest of the given source root.
411 overlays: A list over overlays to commit.
412 overlay_tracking_branch: A dict mapping from each overlay to its tracking
413 branch.
414 overlay_ebuilds: A dict mapping overlays to their ebuilds.
Ningning Xia783efc02018-01-24 13:39:51 -0800415 revved_packages: A shared list of revved packages.
416 new_package_atoms: A shared list of new package atoms.
417 """
Ningning Xia419e4eb2018-02-05 10:30:36 -0800418 for overlay in overlays:
419 if not os.path.isdir(overlay):
420 logging.warning('Skipping %s, which is not a directory.', overlay)
421 continue
Ningning Xia783efc02018-01-24 13:39:51 -0800422
Ningning Xia419e4eb2018-02-05 10:30:36 -0800423 # Note we intentionally work from the non push tracking branch;
424 # everything built thus far has been against it (meaning, http mirrors),
425 # thus we should honor that. During the actual push, the code switches
426 # to the correct urls, and does an appropriate rebasing.
427 tracking_branch = overlay_tracking_branch[overlay]
Ningning Xia783efc02018-01-24 13:39:51 -0800428
Ningning Xia783efc02018-01-24 13:39:51 -0800429 existing_commit = git.GetGitRepoRevision(overlay)
Lann Martine0ef98c2018-06-11 13:12:24 -0600430
431 # Make sure we run in the top-level git directory in case we are
432 # adding/removing an overlay in existing_commit.
433 git_root = git.FindGitTopLevel(overlay)
434 if git_root is None:
435 cros_build_lib.Die('No git repo at overlay directory %s.', overlay)
436
Ningning Xia783efc02018-01-24 13:39:51 -0800437 work_branch = GitBranch(constants.STABLE_EBUILD_BRANCH, tracking_branch,
Lann Martine0ef98c2018-06-11 13:12:24 -0600438 cwd=git_root)
Ningning Xia783efc02018-01-24 13:39:51 -0800439 work_branch.CreateBranch()
440 if not work_branch.Exists():
441 cros_build_lib.Die('Unable to create stabilizing branch in %s' %
442 overlay)
443
444 # In the case of uprevving overlays that have patches applied to them,
445 # include the patched changes in the stabilizing branch.
Lann Martine0ef98c2018-06-11 13:12:24 -0600446 git.RunGit(git_root, ['rebase', existing_commit])
Ningning Xia783efc02018-01-24 13:39:51 -0800447
Ningning Xiadb884322018-01-26 16:27:06 -0800448 ebuilds = overlay_ebuilds.get(overlay, [])
Ningning Xia783efc02018-01-24 13:39:51 -0800449 if ebuilds:
Ningning Xia419e4eb2018-02-05 10:30:36 -0800450 with parallel.Manager() as manager:
451 # Contains the array of packages we actually revved.
452 messages = manager.list()
453 ebuild_paths_to_add = manager.list()
454 ebuild_paths_to_remove = manager.list()
Ningning Xia783efc02018-01-24 13:39:51 -0800455
Ningning Xia419e4eb2018-02-05 10:30:36 -0800456 inputs = [[overlay, ebuild, manifest, options, ebuild_paths_to_add,
457 ebuild_paths_to_remove, messages, revved_packages,
458 new_package_atoms] for ebuild in ebuilds]
459 parallel.RunTasksInProcessPool(_WorkOnEbuild, inputs)
Ningning Xia783efc02018-01-24 13:39:51 -0800460
Ningning Xia419e4eb2018-02-05 10:30:36 -0800461 if ebuild_paths_to_add:
462 logging.info('Adding new stable ebuild paths %s in overlay %s.',
463 ebuild_paths_to_add, overlay)
464 git.RunGit(overlay, ['add'] + list(ebuild_paths_to_add))
David James15ed1302013-04-25 09:21:19 -0700465
Ningning Xia419e4eb2018-02-05 10:30:36 -0800466 if ebuild_paths_to_remove:
467 logging.info('Removing old ebuild paths %s in overlay %s.',
468 ebuild_paths_to_remove, overlay)
469 git.RunGit(overlay, ['rm', '-f'] + list(ebuild_paths_to_remove))
470
471 if messages:
472 portage_util.EBuild.CommitChange('\n\n'.join(messages), overlay)
David James15ed1302013-04-25 09:21:19 -0700473
Ningning Xia783efc02018-01-24 13:39:51 -0800474
475def _WorkOnEbuild(overlay, ebuild, manifest, options, ebuild_paths_to_add,
476 ebuild_paths_to_remove, messages, revved_packages,
477 new_package_atoms):
478 """Work on a single ebuild.
479
480 Args:
481 overlay: The overlay where the ebuild belongs to.
482 ebuild: The ebuild to work on.
483 manifest: The manifest of the given source root.
484 options: The options object returned by the argument parser.
485 ebuild_paths_to_add: New stable ebuild paths to add to git.
486 ebuild_paths_to_remove: Old ebuild paths to remove from git.
487 messages: A share list of commit messages.
488 revved_packages: A shared list of revved packages.
489 new_package_atoms: A shared list of new package atoms.
490 """
491 if options.verbose:
492 logging.info('Working on %s, info %s', ebuild.package,
493 ebuild.cros_workon_vars)
494 try:
Don Garrett4fef8c32018-08-10 18:04:01 -0700495 result = ebuild.RevWorkOnEBuild(os.path.join(options.buildroot, 'src'),
496 manifest)
Ningning Xia783efc02018-01-24 13:39:51 -0800497 if result:
498 new_package, ebuild_path_to_add, ebuild_path_to_remove = result
499
500 if ebuild_path_to_add:
501 ebuild_paths_to_add.append(ebuild_path_to_add)
502 if ebuild_path_to_remove:
503 ebuild_paths_to_remove.append(ebuild_path_to_remove)
504
505 messages.append(_GIT_COMMIT_MESSAGE % ebuild.package)
Sam McNallyeb5e2052018-09-05 16:34:55 +1000506
507 if options.list_revisions:
508 info = ebuild.GetSourceInfo(os.path.join(options.buildroot, 'src'),
Don Garrett3dbb2932018-10-02 14:41:26 -0700509 manifest, True)
Sam McNallyeb5e2052018-09-05 16:34:55 +1000510 srcdirs = [os.path.join(options.buildroot, 'src', srcdir)
511 for srcdir in ebuild.cros_workon_vars.localname]
512 old_commit_ids = dict(
513 zip(srcdirs, ebuild.cros_workon_vars.commit.split(',')))
514 git_log = []
515 for srcdir in info.srcdirs:
516 old_commit_id = old_commit_ids.get(srcdir)
517 new_commit_id = ebuild.GetCommitId(srcdir)
518 if not old_commit_id or old_commit_id == new_commit_id:
519 continue
520
521 logs = git.RunGit(srcdir, [
522 'log', '%s..%s' % (old_commit_id[:8], new_commit_id[:8]),
523 '--pretty=format:%h %<(63,trunc)%s'])
524 git_log.append('$ ' + logs.cmdstr)
525 git_log.extend(line.strip() for line in logs.output.splitlines())
526 if git_log:
527 messages.append('\n'.join(git_log))
528
Ningning Xia783efc02018-01-24 13:39:51 -0800529 revved_packages.append(ebuild.package)
530 new_package_atoms.append('=%s' % new_package)
531 except (OSError, IOError):
532 logging.warning(
533 'Cannot rev %s\n'
534 'Note you will have to go into %s '
Ningning Xia419e4eb2018-02-05 10:30:36 -0800535 'and reset the git repo yourself.', ebuild.package, overlay)
Ningning Xia783efc02018-01-24 13:39:51 -0800536 raise