blob: e09bccb28ac907392e3395ea3180576eb95abebe [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
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
55 runcmd = cros_build_lib.RunCommand
56 else:
57 suffix = ''
58 runcmd = cros_build_lib.SudoRunCommand
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).
64 result = runcmd([emerge, '-q', '--unmerge'] + package_atoms,
David James41124af2015-06-04 21:13:25 -070065 enter_chroot=True, extra_env={'CLEAN_DELAY': '0'},
66 error_code_ok=True, cwd=srcroot)
David James63841a82014-01-16 14:39:24 -080067 if not result.returncode in (0, 1):
68 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,
David James59a0a2b2013-03-22 14:04:44 -070071 redirect_stdout=True, redirect_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
Matt Tennantcb522052013-11-25 14:23:43 -0800135 # Add a failsafe check here. Only CLs from the 'chrome-bot' user should
136 # be involved here. If any other CLs are found then complain.
137 # In dryruns extra CLs are normal, though, and can be ignored.
138 bad_cl_cmd = ['log', '--format=short', '--perl-regexp',
139 '--author', '^(?!chrome-bot)', '%s..%s' % (
Don Garrett99449592015-03-25 11:01:30 -0700140 remote_ref.ref, stable_branch)]
Matt Tennantcb522052013-11-25 14:23:43 -0800141 bad_cls = git.RunGit(cwd, bad_cl_cmd).output
142 if bad_cls.strip() and not dryrun:
Ralph Nathan59900422015-03-24 10:41:17 -0700143 logging.error('The Uprev stage found changes from users other than '
144 'chrome-bot:\n\n%s', bad_cls)
Matt Tennantcb522052013-11-25 14:23:43 -0800145 raise AssertionError('Unexpected CLs found during uprev stage.')
146
Lev Rumyantsev25352ba2016-09-07 15:53:58 -0700147 if staging_branch is not None:
148 logging.info('PFQ FAILED. Pushing uprev change to staging branch %s',
149 staging_branch)
150
Mike Frysingere65f3752014-12-08 00:46:39 -0500151 description = git.RunGit(
152 cwd,
153 ['log', '--format=format:%s%n%n%b',
Don Garrett99449592015-03-25 11:01:30 -0700154 '%s..%s' % (remote_ref.ref, stable_branch)]).output
Gabe Black71e963e2014-10-28 20:19:59 -0700155 description = '%s\n\n%s' % (GIT_COMMIT_SUBJECT, description)
Ralph Nathan03047282015-03-23 11:09:32 -0700156 logging.info('For %s, using description %s', cwd, description)
Paul Hobbsf52ea8f2015-10-21 17:24:23 -0700157 git.CreatePushBranch(constants.MERGE_BRANCH, cwd,
158 remote_push_branch=remote_ref)
David James97d95872012-11-16 15:09:56 -0800159 git.RunGit(cwd, ['merge', '--squash', stable_branch])
160 git.RunGit(cwd, ['commit', '-m', description])
161 git.RunGit(cwd, ['config', 'push.default', 'tracking'])
Mike Nicholsa6818c52018-04-09 11:05:42 -0600162 git.PushBranch(constants.MERGE_BRANCH, cwd, dryrun=dryrun,
163 staging_branch=staging_branch)
Chris Sosadad0d322011-01-31 16:37:33 -0800164
165
166class GitBranch(object):
167 """Wrapper class for a git branch."""
168
Mike Frysinger2ebe3732012-05-08 17:04:12 -0400169 def __init__(self, branch_name, tracking_branch, cwd):
David Jamesc7c4ff52013-09-18 17:57:13 -0700170 """Sets up variables but does not create the branch.
171
Mike Frysinger5cd8c742013-10-11 14:43:01 -0400172 Args:
David Jamesc7c4ff52013-09-18 17:57:13 -0700173 branch_name: The name of the branch.
174 tracking_branch: The associated tracking branch.
175 cwd: The git repository to work in.
176 """
Chris Sosadad0d322011-01-31 16:37:33 -0800177 self.branch_name = branch_name
178 self.tracking_branch = tracking_branch
Mike Frysinger2ebe3732012-05-08 17:04:12 -0400179 self.cwd = cwd
Chris Sosadad0d322011-01-31 16:37:33 -0800180
181 def CreateBranch(self):
Mike Frysinger2ebe3732012-05-08 17:04:12 -0400182 self.Checkout()
Chris Sosadad0d322011-01-31 16:37:33 -0800183
Mike Frysinger2ebe3732012-05-08 17:04:12 -0400184 def Checkout(self, branch=None):
Chris Sosadad0d322011-01-31 16:37:33 -0800185 """Function used to check out to another GitBranch."""
Mike Frysinger2ebe3732012-05-08 17:04:12 -0400186 if not branch:
187 branch = self.branch_name
188 if branch == self.tracking_branch or self.Exists(branch):
Lann Martinb26e1292018-08-09 13:59:19 -0600189 git.RunGit(self.cwd, ['checkout', '-f', branch], quiet=True)
Chris Sosadad0d322011-01-31 16:37:33 -0800190 else:
Lann Martinb26e1292018-08-09 13:59:19 -0600191 repo = repo_util.Repository.MustFind(self.cwd)
192 repo.StartBranch(branch, projects=['.'], cwd=self.cwd)
Chris Sosadad0d322011-01-31 16:37:33 -0800193
Mike Frysinger2ebe3732012-05-08 17:04:12 -0400194 def Exists(self, branch=None):
Chris Sosadad0d322011-01-31 16:37:33 -0800195 """Returns True if the branch exists."""
Mike Frysinger2ebe3732012-05-08 17:04:12 -0400196 if not branch:
197 branch = self.branch_name
David James67d73252013-09-19 17:33:12 -0700198 branches = git.RunGit(self.cwd, ['branch']).output
Mike Frysinger2ebe3732012-05-08 17:04:12 -0400199 return branch in branches.split()
Chris Sosadad0d322011-01-31 16:37:33 -0800200
201
Mike Frysingere8dcbfd2015-03-08 21:45:52 -0400202def GetParser():
203 """Creates the argparse parser."""
204 parser = commandline.ArgumentParser()
205 parser.add_argument('--all', action='store_true',
206 help='Mark all packages as stable.')
207 parser.add_argument('-b', '--boards', default='',
208 help='Colon-separated list of boards.')
209 parser.add_argument('--drop_file',
210 help='File to list packages that were revved.')
211 parser.add_argument('--dryrun', action='store_true',
212 help='Passes dry-run to git push if pushing a change.')
Bertrand SIMONNET6af54302015-08-05 10:12:49 -0700213 parser.add_argument('--force', action='store_true',
214 help='Force the stabilization of blacklisted packages. '
215 '(only compatible with -p)')
Sam McNallyeb5e2052018-09-05 16:34:55 +1000216 parser.add_argument('--list_revisions', action='store_true',
217 help='List all revisions included in the commit message.')
Mike Frysingere8dcbfd2015-03-08 21:45:52 -0400218 parser.add_argument('-o', '--overlays',
219 help='Colon-separated list of overlays to modify.')
Don Garrettf9eff952018-08-10 16:50:04 -0700220 parser.add_argument('--overlay-type',
221 help='Populates --overlays based on "public", "private"'
222 ', or "both".')
Mike Frysingere8dcbfd2015-03-08 21:45:52 -0400223 parser.add_argument('-p', '--packages',
224 help='Colon separated list of packages to rev.')
Don Garrett4fef8c32018-08-10 18:04:01 -0700225 parser.add_argument('--buildroot', type='path',
226 help='Path to buildroot.')
Mike Frysingere8dcbfd2015-03-08 21:45:52 -0400227 parser.add_argument('-r', '--srcroot', type='path',
Don Garrett4fef8c32018-08-10 18:04:01 -0700228 help='Path to root src. Deprecated in favor of '
229 '--buildroot')
Mike Frysingere8dcbfd2015-03-08 21:45:52 -0400230 parser.add_argument('--verbose', action='store_true',
231 help='Prints out debug info.')
Ningning Xia52009062016-05-09 14:33:51 -0700232 parser.add_argument('--staging_branch',
233 help='The staging branch to push changes')
Mike Frysingere8dcbfd2015-03-08 21:45:52 -0400234 parser.add_argument('command', choices=COMMAND_DICTIONARY.keys(),
235 help='Command to run.')
236 return parser
237
238
239def main(argv):
240 parser = GetParser()
241 options = parser.parse_args(argv)
Don Garrett4fef8c32018-08-10 18:04:01 -0700242
243 # TODO: Remove this code in favor of a simple default on buildroot when
244 # srcroot is removed.
245 if options.srcroot and not options.buildroot:
246 # Convert /<repo>/src -> <repo>
247 options.buildroot = os.path.dirname(options.srcroot)
248 if not options.buildroot:
249 options.buildroot = constants.SOURCE_ROOT
250 options.srcroot = None
251
Bertrand SIMONNET6af54302015-08-05 10:12:49 -0700252 options.Freeze()
Mike Frysingere8dcbfd2015-03-08 21:45:52 -0400253
Bertrand SIMONNET6af54302015-08-05 10:12:49 -0700254 if options.command == 'commit':
255 if not options.packages and not options.all:
256 parser.error('Please specify at least one package (--packages)')
257 if options.force and options.all:
258 parser.error('Cannot use --force with --all. You must specify a list of '
259 'packages you want to force uprev.')
260
Don Garrett4fef8c32018-08-10 18:04:01 -0700261 if not os.path.isdir(options.buildroot):
262 parser.error('buildroot is not a valid path: %s' % options.buildroot)
Mike Frysingere8dcbfd2015-03-08 21:45:52 -0400263
Don Garrettf9eff952018-08-10 16:50:04 -0700264 if options.overlay_type and options.overlays:
265 parser.error('Cannot use --overlay-type with --overlays.')
266
Alex Deymo075c2292014-09-04 18:31:50 -0700267 portage_util.EBuild.VERBOSE = options.verbose
Chris Sosa62ad8522011-03-08 17:46:17 -0800268
Chris Sosa62ad8522011-03-08 17:46:17 -0800269 package_list = None
270 if options.packages:
271 package_list = options.packages.split(':')
272
Ningning Xiadb884322018-01-26 16:27:06 -0800273 overlays = []
Chris Sosa62ad8522011-03-08 17:46:17 -0800274 if options.overlays:
Chris Sosa62ad8522011-03-08 17:46:17 -0800275 for path in options.overlays.split(':'):
Ryan Cui05a31ba2011-05-31 17:47:37 -0700276 if not os.path.isdir(path):
Chris Sosac13bba52011-05-24 15:14:09 -0700277 cros_build_lib.Die('Cannot find overlay: %s' % path)
Ningning Xiadb884322018-01-26 16:27:06 -0800278 overlays.append(os.path.realpath(path))
Don Garrettf9eff952018-08-10 16:50:04 -0700279 elif options.overlay_type:
280 overlays = portage_util.FindOverlays(
Don Garrett4fef8c32018-08-10 18:04:01 -0700281 options.overlay_type, buildroot=options.buildroot)
Chris Sosadad0d322011-01-31 16:37:33 -0800282 else:
Ralph Nathan446aee92015-03-23 14:44:56 -0700283 logging.warning('Missing --overlays argument')
Ningning Xiadb884322018-01-26 16:27:06 -0800284 overlays.extend([
Don Garrett4fef8c32018-08-10 18:04:01 -0700285 '%s/src/private-overlays/chromeos-overlay' % options.buildroot,
286 '%s/src/third_party/chromiumos-overlay' % options.buildroot])
Chris Sosadad0d322011-01-31 16:37:33 -0800287
Don Garrett4fef8c32018-08-10 18:04:01 -0700288 manifest = git.ManifestCheckout.Cached(options.buildroot)
Ryan Cui4656a3c2011-05-24 12:30:30 -0700289
Ningning Xia419e4eb2018-02-05 10:30:36 -0800290 # Dict mapping from each overlay to its tracking branch.
291 overlay_tracking_branch = {}
292 # Dict mapping from each git repository (project) to a list of its overlays.
293 git_project_overlays = {}
294
295 for overlay in overlays:
296 remote_ref = git.GetTrackingBranchViaManifest(overlay, manifest=manifest)
297 overlay_tracking_branch[overlay] = remote_ref.ref
298 git_project_overlays.setdefault(remote_ref.project_name, []).append(overlay)
299
300 if options.command == 'push':
301 _WorkOnPush(options, overlay_tracking_branch, git_project_overlays)
302 elif options.command == 'commit':
303 _WorkOnCommit(options, overlays, overlay_tracking_branch,
304 git_project_overlays, manifest, package_list)
305
306
307def _WorkOnPush(options, overlay_tracking_branch, git_project_overlays):
308 """Push uprevs of overlays belonging to differet git projects in parallel.
309
310 Args:
311 options: The options object returned by the argument parser.
312 overlay_tracking_branch: A dict mapping from each overlay to its tracking
313 branch.
314 git_project_overlays: A dict mapping from each git repository to a list of
315 its overlays.
316 """
317 inputs = [[options, overlays_per_project, overlay_tracking_branch]
318 for overlays_per_project in git_project_overlays.itervalues()]
319 parallel.RunTasksInProcessPool(_PushOverlays, inputs)
320
321
322def _PushOverlays(options, overlays, overlay_tracking_branch):
323 """Push uprevs for overlays in sequence.
324
325 Args:
326 options: The options object returned by the argument parser.
327 overlays: A list of overlays to push uprevs in sequence.
328 overlay_tracking_branch: A dict mapping from each overlay to its tracking
329 branch.
330 """
331 for overlay in overlays:
332 if not os.path.isdir(overlay):
333 logging.warning('Skipping %s, which is not a directory.', overlay)
334 continue
335
336 tracking_branch = overlay_tracking_branch[overlay]
337 PushChange(constants.STABLE_EBUILD_BRANCH, tracking_branch, options.dryrun,
338 cwd=overlay, staging_branch=options.staging_branch)
339
340
341def _WorkOnCommit(options, overlays, overlay_tracking_branch,
342 git_project_overlays, manifest, package_list):
343 """Commit uprevs of overlays belonging to different git projects in parallel.
344
345 Args:
346 options: The options object returned by the argument parser.
347 overlays: A list of overlays to work on.
348 overlay_tracking_branch: A dict mapping from each overlay to its tracking
349 branch.
350 git_project_overlays: A dict mapping from each git repository to a list of
351 its overlays.
352 manifest: The manifest of the given source root.
353 package_list: A list of packages passed from commandline to work on.
354 """
355 overlay_ebuilds = _GetOverlayToEbuildsMap(options, overlays, package_list)
David James84e953c2013-04-23 18:44:06 -0700356
Ningning Xia783efc02018-01-24 13:39:51 -0800357 with parallel.Manager() as manager:
358 # Contains the array of packages we actually revved.
359 revved_packages = manager.list()
360 new_package_atoms = manager.list()
David Jamesa8457b52011-05-28 00:03:20 -0700361
Ningning Xia419e4eb2018-02-05 10:30:36 -0800362 inputs = [[options, manifest, overlays_per_project, overlay_tracking_branch,
363 overlay_ebuilds, revved_packages, new_package_atoms]
364 for overlays_per_project in git_project_overlays.itervalues()]
365 parallel.RunTasksInProcessPool(_CommitOverlays, inputs)
Chris Sosadad0d322011-01-31 16:37:33 -0800366
Don Garrett4fef8c32018-08-10 18:04:01 -0700367 chroot_path = os.path.join(options.buildroot, constants.DEFAULT_CHROOT_DIR)
Ningning Xia419e4eb2018-02-05 10:30:36 -0800368 if os.path.exists(chroot_path):
Don Garrett4fef8c32018-08-10 18:04:01 -0700369 CleanStalePackages(options.buildroot, options.boards.split(':'),
Ningning Xia419e4eb2018-02-05 10:30:36 -0800370 new_package_atoms)
371 if options.drop_file:
372 osutils.WriteFile(options.drop_file, ' '.join(revved_packages))
Chris Sosadad0d322011-01-31 16:37:33 -0800373
Brian Harring609dc4e2012-05-07 02:17:44 -0700374
Ningning Xia419e4eb2018-02-05 10:30:36 -0800375def _GetOverlayToEbuildsMap(options, overlays, package_list):
376 """Get ebuilds for overlays.
David James15ed1302013-04-25 09:21:19 -0700377
Ningning Xia783efc02018-01-24 13:39:51 -0800378 Args:
Ningning Xia783efc02018-01-24 13:39:51 -0800379 options: The options object returned by the argument parser.
Ningning Xia419e4eb2018-02-05 10:30:36 -0800380 overlays: A list of overlays to work on.
381 package_list: A list of packages passed from commandline to work on.
382
383 Returns:
384 A dict mapping each overlay to a list of ebuilds belonging to it.
385 """
386 overlay_ebuilds = {}
387 inputs = [[overlay, options.all, package_list, options.force]
388 for overlay in overlays]
389 result = parallel.RunTasksInProcessPool(
390 portage_util.GetOverlayEBuilds, inputs)
391 for idx, ebuilds in enumerate(result):
392 overlay_ebuilds[overlays[idx]] = ebuilds
393
394 return overlay_ebuilds
395
396
397def _CommitOverlays(options, manifest, overlays, overlay_tracking_branch,
398 overlay_ebuilds, revved_packages, new_package_atoms):
399 """Commit uprevs for overlays in sequence.
400
401 Args:
402 options: The options object returned by the argument parser.
403 manifest: The manifest of the given source root.
404 overlays: A list over overlays to commit.
405 overlay_tracking_branch: A dict mapping from each overlay to its tracking
406 branch.
407 overlay_ebuilds: A dict mapping overlays to their ebuilds.
Ningning Xia783efc02018-01-24 13:39:51 -0800408 revved_packages: A shared list of revved packages.
409 new_package_atoms: A shared list of new package atoms.
410 """
Ningning Xia419e4eb2018-02-05 10:30:36 -0800411 for overlay in overlays:
412 if not os.path.isdir(overlay):
413 logging.warning('Skipping %s, which is not a directory.', overlay)
414 continue
Ningning Xia783efc02018-01-24 13:39:51 -0800415
Ningning Xia419e4eb2018-02-05 10:30:36 -0800416 # Note we intentionally work from the non push tracking branch;
417 # everything built thus far has been against it (meaning, http mirrors),
418 # thus we should honor that. During the actual push, the code switches
419 # to the correct urls, and does an appropriate rebasing.
420 tracking_branch = overlay_tracking_branch[overlay]
Ningning Xia783efc02018-01-24 13:39:51 -0800421
Ningning Xia783efc02018-01-24 13:39:51 -0800422 existing_commit = git.GetGitRepoRevision(overlay)
Lann Martine0ef98c2018-06-11 13:12:24 -0600423
424 # Make sure we run in the top-level git directory in case we are
425 # adding/removing an overlay in existing_commit.
426 git_root = git.FindGitTopLevel(overlay)
427 if git_root is None:
428 cros_build_lib.Die('No git repo at overlay directory %s.', overlay)
429
Ningning Xia783efc02018-01-24 13:39:51 -0800430 work_branch = GitBranch(constants.STABLE_EBUILD_BRANCH, tracking_branch,
Lann Martine0ef98c2018-06-11 13:12:24 -0600431 cwd=git_root)
Ningning Xia783efc02018-01-24 13:39:51 -0800432 work_branch.CreateBranch()
433 if not work_branch.Exists():
434 cros_build_lib.Die('Unable to create stabilizing branch in %s' %
435 overlay)
436
437 # In the case of uprevving overlays that have patches applied to them,
438 # include the patched changes in the stabilizing branch.
Lann Martine0ef98c2018-06-11 13:12:24 -0600439 git.RunGit(git_root, ['rebase', existing_commit])
Ningning Xia783efc02018-01-24 13:39:51 -0800440
Ningning Xiadb884322018-01-26 16:27:06 -0800441 ebuilds = overlay_ebuilds.get(overlay, [])
Ningning Xia783efc02018-01-24 13:39:51 -0800442 if ebuilds:
Ningning Xia419e4eb2018-02-05 10:30:36 -0800443 with parallel.Manager() as manager:
444 # Contains the array of packages we actually revved.
445 messages = manager.list()
446 ebuild_paths_to_add = manager.list()
447 ebuild_paths_to_remove = manager.list()
Ningning Xia783efc02018-01-24 13:39:51 -0800448
Ningning Xia419e4eb2018-02-05 10:30:36 -0800449 inputs = [[overlay, ebuild, manifest, options, ebuild_paths_to_add,
450 ebuild_paths_to_remove, messages, revved_packages,
451 new_package_atoms] for ebuild in ebuilds]
452 parallel.RunTasksInProcessPool(_WorkOnEbuild, inputs)
Ningning Xia783efc02018-01-24 13:39:51 -0800453
Ningning Xia419e4eb2018-02-05 10:30:36 -0800454 if ebuild_paths_to_add:
455 logging.info('Adding new stable ebuild paths %s in overlay %s.',
456 ebuild_paths_to_add, overlay)
457 git.RunGit(overlay, ['add'] + list(ebuild_paths_to_add))
David James15ed1302013-04-25 09:21:19 -0700458
Ningning Xia419e4eb2018-02-05 10:30:36 -0800459 if ebuild_paths_to_remove:
460 logging.info('Removing old ebuild paths %s in overlay %s.',
461 ebuild_paths_to_remove, overlay)
462 git.RunGit(overlay, ['rm', '-f'] + list(ebuild_paths_to_remove))
463
464 if messages:
465 portage_util.EBuild.CommitChange('\n\n'.join(messages), overlay)
David James15ed1302013-04-25 09:21:19 -0700466
Ningning Xia783efc02018-01-24 13:39:51 -0800467
468def _WorkOnEbuild(overlay, ebuild, manifest, options, ebuild_paths_to_add,
469 ebuild_paths_to_remove, messages, revved_packages,
470 new_package_atoms):
471 """Work on a single ebuild.
472
473 Args:
474 overlay: The overlay where the ebuild belongs to.
475 ebuild: The ebuild to work on.
476 manifest: The manifest of the given source root.
477 options: The options object returned by the argument parser.
478 ebuild_paths_to_add: New stable ebuild paths to add to git.
479 ebuild_paths_to_remove: Old ebuild paths to remove from git.
480 messages: A share list of commit messages.
481 revved_packages: A shared list of revved packages.
482 new_package_atoms: A shared list of new package atoms.
483 """
484 if options.verbose:
485 logging.info('Working on %s, info %s', ebuild.package,
486 ebuild.cros_workon_vars)
487 try:
Don Garrett4fef8c32018-08-10 18:04:01 -0700488 result = ebuild.RevWorkOnEBuild(os.path.join(options.buildroot, 'src'),
489 manifest)
Ningning Xia783efc02018-01-24 13:39:51 -0800490 if result:
491 new_package, ebuild_path_to_add, ebuild_path_to_remove = result
492
493 if ebuild_path_to_add:
494 ebuild_paths_to_add.append(ebuild_path_to_add)
495 if ebuild_path_to_remove:
496 ebuild_paths_to_remove.append(ebuild_path_to_remove)
497
498 messages.append(_GIT_COMMIT_MESSAGE % ebuild.package)
Sam McNallyeb5e2052018-09-05 16:34:55 +1000499
500 if options.list_revisions:
501 info = ebuild.GetSourceInfo(os.path.join(options.buildroot, 'src'),
502 manifest)
503 srcdirs = [os.path.join(options.buildroot, 'src', srcdir)
504 for srcdir in ebuild.cros_workon_vars.localname]
505 old_commit_ids = dict(
506 zip(srcdirs, ebuild.cros_workon_vars.commit.split(',')))
507 git_log = []
508 for srcdir in info.srcdirs:
509 old_commit_id = old_commit_ids.get(srcdir)
510 new_commit_id = ebuild.GetCommitId(srcdir)
511 if not old_commit_id or old_commit_id == new_commit_id:
512 continue
513
514 logs = git.RunGit(srcdir, [
515 'log', '%s..%s' % (old_commit_id[:8], new_commit_id[:8]),
516 '--pretty=format:%h %<(63,trunc)%s'])
517 git_log.append('$ ' + logs.cmdstr)
518 git_log.extend(line.strip() for line in logs.output.splitlines())
519 if git_log:
520 messages.append('\n'.join(git_log))
521
Ningning Xia783efc02018-01-24 13:39:51 -0800522 revved_packages.append(ebuild.package)
523 new_package_atoms.append('=%s' % new_package)
524 except (OSError, IOError):
525 logging.warning(
526 'Cannot rev %s\n'
527 'Note you will have to go into %s '
Ningning Xia419e4eb2018-02-05 10:30:36 -0800528 'and reset the git repo yourself.', ebuild.package, overlay)
Ningning Xia783efc02018-01-24 13:39:51 -0800529 raise