blob: 9dc0755e115ccf97a7659c51dbb3b3559bdb6f9a [file] [log] [blame]
Mike Frysingere58c0e22017-10-04 15:43:30 -04001# -*- coding: utf-8 -*-
Mike Frysinger110750a2012-03-26 14:19:20 -04002# Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
Chris Sosadad0d322011-01-31 16:37:33 -08003# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
5
6"""This module uprevs a given package's ebuild to the next revision."""
7
Mike Frysinger383367e2014-09-16 15:06:17 -04008from __future__ import print_function
9
Chris Sosadad0d322011-01-31 16:37:33 -080010import os
Mike Frysinger32781402020-04-19 06:34:17 -040011import sys
Chris Sosadad0d322011-01-31 16:37:33 -080012
Aviv Keshetb7519e12016-10-04 00:50:00 -070013from chromite.lib import constants
Mike Frysingere8dcbfd2015-03-08 21:45:52 -040014from chromite.lib import commandline
Chris Sosac13bba52011-05-24 15:14:09 -070015from chromite.lib import cros_build_lib
Ralph Nathan03047282015-03-23 11:09:32 -070016from chromite.lib import cros_logging as logging
David James97d95872012-11-16 15:09:56 -080017from chromite.lib import git
Mike Frysingerfddaeb52012-11-20 11:17:31 -050018from chromite.lib import osutils
David James6450a0a2012-12-04 07:59:53 -080019from chromite.lib import parallel
Alex Deymo075c2292014-09-04 18:31:50 -070020from chromite.lib import portage_util
Lann Martinb26e1292018-08-09 13:59:19 -060021from chromite.lib import repo_util
Chris Sosac13bba52011-05-24 15:14:09 -070022
Don Garrett3dbb2932018-10-02 14:41:26 -070023from chromite.cbuildbot import manifest_version
24
Mike Frysinger32781402020-04-19 06:34:17 -040025
26assert sys.version_info >= (3, 6), 'This module requires Python 3.6+'
27
28
Gabe Black71e963e2014-10-28 20:19:59 -070029# Commit message subject for uprevving Portage packages.
30GIT_COMMIT_SUBJECT = 'Marking set of ebuilds as stable'
David James15ed1302013-04-25 09:21:19 -070031
David James29e86d52013-04-19 09:41:29 -070032# Commit message for uprevving Portage packages.
33_GIT_COMMIT_MESSAGE = 'Marking 9999 ebuild for %s as stable.'
34
Chris Sosadad0d322011-01-31 16:37:33 -080035# Dictionary of valid commands with usage information.
36COMMAND_DICTIONARY = {
Mike Frysinger5cd8c742013-10-11 14:43:01 -040037 'commit': 'Marks given ebuilds as stable locally',
38 'push': 'Pushes previous marking of ebuilds to remote repo',
39}
Chris Sosadad0d322011-01-31 16:37:33 -080040
Chris Sosadad0d322011-01-31 16:37:33 -080041
Chris Sosadad0d322011-01-31 16:37:33 -080042# ======================= Global Helper Functions ========================
43
44
David James41124af2015-06-04 21:13:25 -070045def CleanStalePackages(srcroot, boards, package_atoms):
Chris Sosabf153872011-04-28 14:21:09 -070046 """Cleans up stale package info from a previous build.
Mike Frysinger5cd8c742013-10-11 14:43:01 -040047
Chris Sosabf153872011-04-28 14:21:09 -070048 Args:
David James41124af2015-06-04 21:13:25 -070049 srcroot: Root directory of the source tree.
David Jamescc09c9b2012-01-26 22:10:13 -080050 boards: Boards to clean the packages from.
Mike Frysingerde5ab0e2013-03-21 20:48:36 -040051 package_atoms: A list of package atoms to unmerge.
Chris Sosabf153872011-04-28 14:21:09 -070052 """
David James15ed1302013-04-25 09:21:19 -070053 if package_atoms:
Lann Martinffb95162018-08-28 12:02:54 -060054 logging.info('Cleaning up stale packages %s.', package_atoms)
David James15ed1302013-04-25 09:21:19 -070055
Mike Frysingerb7ab9b82012-04-04 16:22:43 -040056 # First unmerge all the packages for a board, then eclean it.
57 # We need these two steps to run in order (unmerge/eclean),
58 # but we can let all the boards run in parallel.
59 def _CleanStalePackages(board):
60 if board:
61 suffix = '-' + board
Mike Frysinger45602c72019-09-22 02:15:11 -040062 runcmd = cros_build_lib.run
Mike Frysingerb7ab9b82012-04-04 16:22:43 -040063 else:
64 suffix = ''
Mike Frysinger45602c72019-09-22 02:15:11 -040065 runcmd = cros_build_lib.sudo_run
Chris Sosadad0d322011-01-31 16:37:33 -080066
David James59a0a2b2013-03-22 14:04:44 -070067 emerge, eclean = 'emerge' + suffix, 'eclean' + suffix
68 if not osutils.FindMissingBinaries([emerge, eclean]):
David James63841a82014-01-16 14:39:24 -080069 if package_atoms:
70 # If nothing was found to be unmerged, emerge will exit(1).
Don Garrett7100fff2018-10-23 11:07:13 -070071 result = runcmd([emerge, '-q', '--unmerge'] + list(package_atoms),
David James41124af2015-06-04 21:13:25 -070072 enter_chroot=True, extra_env={'CLEAN_DELAY': '0'},
Mike Frysingerf5a3b2d2019-12-12 14:36:17 -050073 check=False, cwd=srcroot)
Mike Frysinger01504112019-08-24 19:35:24 -040074 if result.returncode not in (0, 1):
David James63841a82014-01-16 14:39:24 -080075 raise cros_build_lib.RunCommandError('unexpected error', result)
David James59a0a2b2013-03-22 14:04:44 -070076 runcmd([eclean, '-d', 'packages'],
David James41124af2015-06-04 21:13:25 -070077 cwd=srcroot, enter_chroot=True,
Mike Frysinger0282d222019-12-17 17:15:48 -050078 stdout=True, stderr=True)
Mike Frysingerb7ab9b82012-04-04 16:22:43 -040079
80 tasks = []
David Jamescc09c9b2012-01-26 22:10:13 -080081 for board in boards:
Mike Frysingerb7ab9b82012-04-04 16:22:43 -040082 tasks.append([board])
83 tasks.append([None])
84
David James6450a0a2012-12-04 07:59:53 -080085 parallel.RunTasksInProcessPool(_CleanStalePackages, tasks)
Chris Sosadad0d322011-01-31 16:37:33 -080086
87
Mike Frysinger2ebe3732012-05-08 17:04:12 -040088# TODO(build): This code needs to be gutted and rebased to cros_build_lib.
89def _DoWeHaveLocalCommits(stable_branch, tracking_branch, cwd):
Chris Sosadad0d322011-01-31 16:37:33 -080090 """Returns true if there are local commits."""
David James97d95872012-11-16 15:09:56 -080091 output = git.RunGit(
Paul Hobbs72d8e392015-10-21 17:24:23 -070092 cwd, ['rev-parse', stable_branch, tracking_branch]).output.split()
Brian Harring5b86b5e2012-05-25 18:27:40 -070093 return output[0] != output[1]
Chris Sosadad0d322011-01-31 16:37:33 -080094
95
Chris Sosadad0d322011-01-31 16:37:33 -080096# ======================= End Global Helper Functions ========================
97
98
Ningning Xia52009062016-05-09 14:33:51 -070099def PushChange(stable_branch, tracking_branch, dryrun, cwd,
100 staging_branch=None):
Chris Sosadad0d322011-01-31 16:37:33 -0800101 """Pushes commits in the stable_branch to the remote git repository.
102
David Jamesee2da622012-02-23 09:32:16 -0800103 Pushes local commits from calls to CommitChange to the remote git
David James66009462012-03-25 10:08:38 -0700104 repository specified by current working directory. If changes are
105 found to commit, they will be merged to the merge branch and pushed.
106 In that case, the local repository will be left on the merge branch.
Chris Sosadad0d322011-01-31 16:37:33 -0800107
108 Args:
109 stable_branch: The local branch with commits we want to push.
110 tracking_branch: The tracking branch of the local branch.
Chris Sosa62ad8522011-03-08 17:46:17 -0800111 dryrun: Use git push --dryrun to emulate a push.
Mike Frysinger2ebe3732012-05-08 17:04:12 -0400112 cwd: The directory to run commands in.
Ningning Xia52009062016-05-09 14:33:51 -0700113 staging_branch: The staging branch to push for a failed PFQ run
Mike Frysinger1a736a82013-12-12 01:50:59 -0500114
Chris Sosadad0d322011-01-31 16:37:33 -0800115 Raises:
Mike Frysinger5cd8c742013-10-11 14:43:01 -0400116 OSError: Error occurred while pushing.
Chris Sosadad0d322011-01-31 16:37:33 -0800117 """
David James47959632015-10-23 07:56:01 -0700118 if not git.DoesCommitExistInRepo(cwd, stable_branch):
119 logging.debug('No branch created for %s. Exiting', cwd)
120 return
121
Mike Frysinger2ebe3732012-05-08 17:04:12 -0400122 if not _DoWeHaveLocalCommits(stable_branch, tracking_branch, cwd):
David James47959632015-10-23 07:56:01 -0700123 logging.debug('No work found to push in %s. Exiting', cwd)
Chris Sosadad0d322011-01-31 16:37:33 -0800124 return
125
David James66009462012-03-25 10:08:38 -0700126 # For the commit queue, our local branch may contain commits that were
127 # just tested and pushed during the CommitQueueCompletion stage. Sync
128 # and rebase our local branch on top of the remote commits.
Paul Hobbs72d8e392015-10-21 17:24:23 -0700129 remote_ref = git.GetTrackingBranch(cwd,
130 branch=stable_branch,
131 for_push=True)
Paul Hobbs1e46be82015-10-30 13:46:02 -0700132 # SyncPushBranch rebases HEAD onto the updated remote. We need to checkout
133 # stable_branch here in order to update it.
134 git.RunGit(cwd, ['checkout', stable_branch])
Don Garrett99449592015-03-25 11:01:30 -0700135 git.SyncPushBranch(cwd, remote_ref.remote, remote_ref.ref)
David James66009462012-03-25 10:08:38 -0700136
137 # Check whether any local changes remain after the sync.
Don Garrett99449592015-03-25 11:01:30 -0700138 if not _DoWeHaveLocalCommits(stable_branch, remote_ref.ref, cwd):
Ralph Nathan03047282015-03-23 11:09:32 -0700139 logging.info('All changes already pushed for %s. Exiting', cwd)
David James66009462012-03-25 10:08:38 -0700140 return
141
Andrew Lamb7ef2c0b2019-07-17 09:43:27 -0600142 # Add a failsafe check here. Only CLs from the 'chrome-bot' or
143 # 'chromeos-ci-prod' user should be involved here. If any other CLs are
144 # found then complain. In dryruns extra CLs are normal, though, and can
145 # be ignored.
146 bad_cl_cmd = [
147 'log', '--format=short', '--perl-regexp', '--author',
148 '^(?!chrome-bot|chromeos-ci-prod)',
149 '%s..%s' % (remote_ref.ref, stable_branch)
150 ]
Matt Tennantcb522052013-11-25 14:23:43 -0800151 bad_cls = git.RunGit(cwd, bad_cl_cmd).output
152 if bad_cls.strip() and not dryrun:
Andrew Lamb7ef2c0b2019-07-17 09:43:27 -0600153 logging.error(
154 'The Uprev stage found changes from users other than '
155 'chrome-bot or chromeos-ci-prod:\n\n%s', bad_cls)
Matt Tennantcb522052013-11-25 14:23:43 -0800156 raise AssertionError('Unexpected CLs found during uprev stage.')
157
Lev Rumyantsev25352ba2016-09-07 15:53:58 -0700158 if staging_branch is not None:
159 logging.info('PFQ FAILED. Pushing uprev change to staging branch %s',
160 staging_branch)
161
Mike Frysingere65f3752014-12-08 00:46:39 -0500162 description = git.RunGit(
163 cwd,
164 ['log', '--format=format:%s%n%n%b',
Don Garrett99449592015-03-25 11:01:30 -0700165 '%s..%s' % (remote_ref.ref, stable_branch)]).output
Gabe Black71e963e2014-10-28 20:19:59 -0700166 description = '%s\n\n%s' % (GIT_COMMIT_SUBJECT, description)
Ralph Nathan03047282015-03-23 11:09:32 -0700167 logging.info('For %s, using description %s', cwd, description)
Paul Hobbsf52ea8f2015-10-21 17:24:23 -0700168 git.CreatePushBranch(constants.MERGE_BRANCH, cwd,
169 remote_push_branch=remote_ref)
David James97d95872012-11-16 15:09:56 -0800170 git.RunGit(cwd, ['merge', '--squash', stable_branch])
171 git.RunGit(cwd, ['commit', '-m', description])
172 git.RunGit(cwd, ['config', 'push.default', 'tracking'])
Mike Nicholsa6818c52018-04-09 11:05:42 -0600173 git.PushBranch(constants.MERGE_BRANCH, cwd, dryrun=dryrun,
Sean Abraham11b57f82019-09-20 19:33:17 +0000174 staging_branch=staging_branch)
Chris Sosadad0d322011-01-31 16:37:33 -0800175
176
177class GitBranch(object):
178 """Wrapper class for a git branch."""
179
Mike Frysinger2ebe3732012-05-08 17:04:12 -0400180 def __init__(self, branch_name, tracking_branch, cwd):
David Jamesc7c4ff52013-09-18 17:57:13 -0700181 """Sets up variables but does not create the branch.
182
Mike Frysinger5cd8c742013-10-11 14:43:01 -0400183 Args:
David Jamesc7c4ff52013-09-18 17:57:13 -0700184 branch_name: The name of the branch.
185 tracking_branch: The associated tracking branch.
186 cwd: The git repository to work in.
187 """
Chris Sosadad0d322011-01-31 16:37:33 -0800188 self.branch_name = branch_name
189 self.tracking_branch = tracking_branch
Mike Frysinger2ebe3732012-05-08 17:04:12 -0400190 self.cwd = cwd
Chris Sosadad0d322011-01-31 16:37:33 -0800191
192 def CreateBranch(self):
Mike Frysinger2ebe3732012-05-08 17:04:12 -0400193 self.Checkout()
Chris Sosadad0d322011-01-31 16:37:33 -0800194
Mike Frysinger2ebe3732012-05-08 17:04:12 -0400195 def Checkout(self, branch=None):
Chris Sosadad0d322011-01-31 16:37:33 -0800196 """Function used to check out to another GitBranch."""
Mike Frysinger2ebe3732012-05-08 17:04:12 -0400197 if not branch:
198 branch = self.branch_name
199 if branch == self.tracking_branch or self.Exists(branch):
Lann Martinb26e1292018-08-09 13:59:19 -0600200 git.RunGit(self.cwd, ['checkout', '-f', branch], quiet=True)
Chris Sosadad0d322011-01-31 16:37:33 -0800201 else:
Lann Martinb26e1292018-08-09 13:59:19 -0600202 repo = repo_util.Repository.MustFind(self.cwd)
203 repo.StartBranch(branch, projects=['.'], cwd=self.cwd)
Chris Sosadad0d322011-01-31 16:37:33 -0800204
Mike Frysinger2ebe3732012-05-08 17:04:12 -0400205 def Exists(self, branch=None):
Chris Sosadad0d322011-01-31 16:37:33 -0800206 """Returns True if the branch exists."""
Mike Frysinger2ebe3732012-05-08 17:04:12 -0400207 if not branch:
208 branch = self.branch_name
David James67d73252013-09-19 17:33:12 -0700209 branches = git.RunGit(self.cwd, ['branch']).output
Mike Frysinger2ebe3732012-05-08 17:04:12 -0400210 return branch in branches.split()
Chris Sosadad0d322011-01-31 16:37:33 -0800211
212
Mike Frysingere8dcbfd2015-03-08 21:45:52 -0400213def GetParser():
214 """Creates the argparse parser."""
215 parser = commandline.ArgumentParser()
216 parser.add_argument('--all', action='store_true',
217 help='Mark all packages as stable.')
218 parser.add_argument('-b', '--boards', default='',
219 help='Colon-separated list of boards.')
Mike Nicholsf7f13a82019-01-11 17:11:04 +0000220 parser.add_argument('--drop_file',
221 help='File to list packages that were revved.')
Mike Frysingere8dcbfd2015-03-08 21:45:52 -0400222 parser.add_argument('--dryrun', action='store_true',
223 help='Passes dry-run to git push if pushing a change.')
Bertrand SIMONNET6af54302015-08-05 10:12:49 -0700224 parser.add_argument('--force', action='store_true',
225 help='Force the stabilization of blacklisted packages. '
226 '(only compatible with -p)')
Sam McNallyeb5e2052018-09-05 16:34:55 +1000227 parser.add_argument('--list_revisions', action='store_true',
228 help='List all revisions included in the commit message.')
Mike Frysingere8dcbfd2015-03-08 21:45:52 -0400229 parser.add_argument('-o', '--overlays',
230 help='Colon-separated list of overlays to modify.')
Don Garrettf9eff952018-08-10 16:50:04 -0700231 parser.add_argument('--overlay-type',
232 help='Populates --overlays based on "public", "private"'
233 ', or "both".')
Mike Frysingere8dcbfd2015-03-08 21:45:52 -0400234 parser.add_argument('-p', '--packages',
235 help='Colon separated list of packages to rev.')
Don Garrett4fef8c32018-08-10 18:04:01 -0700236 parser.add_argument('--buildroot', type='path',
237 help='Path to buildroot.')
Mike Frysingere8dcbfd2015-03-08 21:45:52 -0400238 parser.add_argument('-r', '--srcroot', type='path',
Don Garrett4fef8c32018-08-10 18:04:01 -0700239 help='Path to root src. Deprecated in favor of '
240 '--buildroot')
Ningning Xia52009062016-05-09 14:33:51 -0700241 parser.add_argument('--staging_branch',
242 help='The staging branch to push changes')
Mike Frysinger1f4478c2019-10-20 18:33:17 -0400243 parser.add_argument('command', choices=sorted(COMMAND_DICTIONARY),
Mike Frysingere8dcbfd2015-03-08 21:45:52 -0400244 help='Command to run.')
245 return parser
246
247
248def main(argv):
249 parser = GetParser()
250 options = parser.parse_args(argv)
Don Garrett4fef8c32018-08-10 18:04:01 -0700251
252 # TODO: Remove this code in favor of a simple default on buildroot when
253 # srcroot is removed.
254 if options.srcroot and not options.buildroot:
255 # Convert /<repo>/src -> <repo>
256 options.buildroot = os.path.dirname(options.srcroot)
257 if not options.buildroot:
258 options.buildroot = constants.SOURCE_ROOT
259 options.srcroot = None
260
Bertrand SIMONNET6af54302015-08-05 10:12:49 -0700261 options.Freeze()
Mike Frysingere8dcbfd2015-03-08 21:45:52 -0400262
Bertrand SIMONNET6af54302015-08-05 10:12:49 -0700263 if options.command == 'commit':
264 if not options.packages and not options.all:
265 parser.error('Please specify at least one package (--packages)')
266 if options.force and options.all:
267 parser.error('Cannot use --force with --all. You must specify a list of '
268 'packages you want to force uprev.')
269
Don Garrett4fef8c32018-08-10 18:04:01 -0700270 if not os.path.isdir(options.buildroot):
271 parser.error('buildroot is not a valid path: %s' % options.buildroot)
Mike Frysingere8dcbfd2015-03-08 21:45:52 -0400272
Don Garrettf9eff952018-08-10 16:50:04 -0700273 if options.overlay_type and options.overlays:
274 parser.error('Cannot use --overlay-type with --overlays.')
275
Alex Deymo075c2292014-09-04 18:31:50 -0700276 portage_util.EBuild.VERBOSE = options.verbose
Chris Sosa62ad8522011-03-08 17:46:17 -0800277
Chris Sosa62ad8522011-03-08 17:46:17 -0800278 package_list = None
279 if options.packages:
280 package_list = options.packages.split(':')
281
Ningning Xiadb884322018-01-26 16:27:06 -0800282 overlays = []
Chris Sosa62ad8522011-03-08 17:46:17 -0800283 if options.overlays:
Chris Sosa62ad8522011-03-08 17:46:17 -0800284 for path in options.overlays.split(':'):
Ryan Cui05a31ba2011-05-31 17:47:37 -0700285 if not os.path.isdir(path):
Chris Sosac13bba52011-05-24 15:14:09 -0700286 cros_build_lib.Die('Cannot find overlay: %s' % path)
Ningning Xiadb884322018-01-26 16:27:06 -0800287 overlays.append(os.path.realpath(path))
Don Garrettf9eff952018-08-10 16:50:04 -0700288 elif options.overlay_type:
289 overlays = portage_util.FindOverlays(
Don Garrett4fef8c32018-08-10 18:04:01 -0700290 options.overlay_type, buildroot=options.buildroot)
Chris Sosadad0d322011-01-31 16:37:33 -0800291 else:
Ralph Nathan446aee92015-03-23 14:44:56 -0700292 logging.warning('Missing --overlays argument')
Ningning Xiadb884322018-01-26 16:27:06 -0800293 overlays.extend([
Don Garrett4fef8c32018-08-10 18:04:01 -0700294 '%s/src/private-overlays/chromeos-overlay' % options.buildroot,
295 '%s/src/third_party/chromiumos-overlay' % options.buildroot])
Chris Sosadad0d322011-01-31 16:37:33 -0800296
Don Garrett4fef8c32018-08-10 18:04:01 -0700297 manifest = git.ManifestCheckout.Cached(options.buildroot)
Ryan Cui4656a3c2011-05-24 12:30:30 -0700298
Ningning Xia419e4eb2018-02-05 10:30:36 -0800299 # Dict mapping from each overlay to its tracking branch.
300 overlay_tracking_branch = {}
301 # Dict mapping from each git repository (project) to a list of its overlays.
302 git_project_overlays = {}
303
304 for overlay in overlays:
305 remote_ref = git.GetTrackingBranchViaManifest(overlay, manifest=manifest)
306 overlay_tracking_branch[overlay] = remote_ref.ref
307 git_project_overlays.setdefault(remote_ref.project_name, []).append(overlay)
308
309 if options.command == 'push':
310 _WorkOnPush(options, overlay_tracking_branch, git_project_overlays)
311 elif options.command == 'commit':
312 _WorkOnCommit(options, overlays, overlay_tracking_branch,
313 git_project_overlays, manifest, package_list)
314
315
316def _WorkOnPush(options, overlay_tracking_branch, git_project_overlays):
317 """Push uprevs of overlays belonging to differet git projects in parallel.
318
319 Args:
320 options: The options object returned by the argument parser.
321 overlay_tracking_branch: A dict mapping from each overlay to its tracking
322 branch.
323 git_project_overlays: A dict mapping from each git repository to a list of
324 its overlays.
325 """
326 inputs = [[options, overlays_per_project, overlay_tracking_branch]
Mike Frysinger0bdbc102019-06-13 15:27:29 -0400327 for overlays_per_project in git_project_overlays.values()]
Ningning Xia419e4eb2018-02-05 10:30:36 -0800328 parallel.RunTasksInProcessPool(_PushOverlays, inputs)
329
330
331def _PushOverlays(options, overlays, overlay_tracking_branch):
332 """Push uprevs for overlays in sequence.
333
334 Args:
335 options: The options object returned by the argument parser.
336 overlays: A list of overlays to push uprevs in sequence.
337 overlay_tracking_branch: A dict mapping from each overlay to its tracking
338 branch.
339 """
340 for overlay in overlays:
341 if not os.path.isdir(overlay):
342 logging.warning('Skipping %s, which is not a directory.', overlay)
343 continue
344
345 tracking_branch = overlay_tracking_branch[overlay]
346 PushChange(constants.STABLE_EBUILD_BRANCH, tracking_branch, options.dryrun,
347 cwd=overlay, staging_branch=options.staging_branch)
348
349
350def _WorkOnCommit(options, overlays, overlay_tracking_branch,
351 git_project_overlays, manifest, package_list):
352 """Commit uprevs of overlays belonging to different git projects in parallel.
353
354 Args:
355 options: The options object returned by the argument parser.
356 overlays: A list of overlays to work on.
357 overlay_tracking_branch: A dict mapping from each overlay to its tracking
358 branch.
359 git_project_overlays: A dict mapping from each git repository to a list of
360 its overlays.
361 manifest: The manifest of the given source root.
362 package_list: A list of packages passed from commandline to work on.
363 """
Mike Frysinger62ff8d72020-05-19 03:06:51 -0400364 # We cleaned up self referential ebuilds by this version, but don't enforce
365 # the check on older ones to avoid breaking factory/firmware branches.
366 root_version = manifest_version.VersionInfo.from_repo(options.buildroot)
367 no_self_repos_version = manifest_version.VersionInfo('13099.0.0')
368 reject_self_repo = root_version >= no_self_repos_version
369
Ningning Xia419e4eb2018-02-05 10:30:36 -0800370 overlay_ebuilds = _GetOverlayToEbuildsMap(options, overlays, package_list)
David James84e953c2013-04-23 18:44:06 -0700371
Ningning Xia783efc02018-01-24 13:39:51 -0800372 with parallel.Manager() as manager:
373 # Contains the array of packages we actually revved.
374 revved_packages = manager.list()
375 new_package_atoms = manager.list()
David Jamesa8457b52011-05-28 00:03:20 -0700376
Ningning Xia419e4eb2018-02-05 10:30:36 -0800377 inputs = [[options, manifest, overlays_per_project, overlay_tracking_branch,
Mike Frysinger62ff8d72020-05-19 03:06:51 -0400378 overlay_ebuilds, revved_packages, new_package_atoms,
379 reject_self_repo]
Mike Frysinger0bdbc102019-06-13 15:27:29 -0400380 for overlays_per_project in git_project_overlays.values()]
Ningning Xia419e4eb2018-02-05 10:30:36 -0800381 parallel.RunTasksInProcessPool(_CommitOverlays, inputs)
Chris Sosadad0d322011-01-31 16:37:33 -0800382
Don Garrett4fef8c32018-08-10 18:04:01 -0700383 chroot_path = os.path.join(options.buildroot, constants.DEFAULT_CHROOT_DIR)
Ningning Xia419e4eb2018-02-05 10:30:36 -0800384 if os.path.exists(chroot_path):
Don Garrett4fef8c32018-08-10 18:04:01 -0700385 CleanStalePackages(options.buildroot, options.boards.split(':'),
Ningning Xia419e4eb2018-02-05 10:30:36 -0800386 new_package_atoms)
Mike Nicholsf7f13a82019-01-11 17:11:04 +0000387 if options.drop_file:
388 osutils.WriteFile(options.drop_file, ' '.join(revved_packages))
Chris Sosadad0d322011-01-31 16:37:33 -0800389
Brian Harring609dc4e2012-05-07 02:17:44 -0700390
Ningning Xia419e4eb2018-02-05 10:30:36 -0800391def _GetOverlayToEbuildsMap(options, overlays, package_list):
392 """Get ebuilds for overlays.
David James15ed1302013-04-25 09:21:19 -0700393
Ningning Xia783efc02018-01-24 13:39:51 -0800394 Args:
Ningning Xia783efc02018-01-24 13:39:51 -0800395 options: The options object returned by the argument parser.
Ningning Xia419e4eb2018-02-05 10:30:36 -0800396 overlays: A list of overlays to work on.
397 package_list: A list of packages passed from commandline to work on.
398
399 Returns:
400 A dict mapping each overlay to a list of ebuilds belonging to it.
401 """
Don Garrett3dbb2932018-10-02 14:41:26 -0700402 root_version = manifest_version.VersionInfo.from_repo(options.buildroot)
403 subdir_removal = manifest_version.VersionInfo('10363.0.0')
404 require_subdir_support = root_version < subdir_removal
405
Ningning Xia419e4eb2018-02-05 10:30:36 -0800406 overlay_ebuilds = {}
Don Garrett3dbb2932018-10-02 14:41:26 -0700407 inputs = [[overlay, options.all, package_list, options.force,
408 require_subdir_support]
Ningning Xia419e4eb2018-02-05 10:30:36 -0800409 for overlay in overlays]
410 result = parallel.RunTasksInProcessPool(
411 portage_util.GetOverlayEBuilds, inputs)
412 for idx, ebuilds in enumerate(result):
413 overlay_ebuilds[overlays[idx]] = ebuilds
414
415 return overlay_ebuilds
416
417
418def _CommitOverlays(options, manifest, overlays, overlay_tracking_branch,
Mike Frysinger62ff8d72020-05-19 03:06:51 -0400419 overlay_ebuilds, revved_packages, new_package_atoms,
420 reject_self_repo=True):
Ningning Xia419e4eb2018-02-05 10:30:36 -0800421 """Commit uprevs for overlays in sequence.
422
423 Args:
424 options: The options object returned by the argument parser.
425 manifest: The manifest of the given source root.
426 overlays: A list over overlays to commit.
427 overlay_tracking_branch: A dict mapping from each overlay to its tracking
428 branch.
429 overlay_ebuilds: A dict mapping overlays to their ebuilds.
Ningning Xia783efc02018-01-24 13:39:51 -0800430 revved_packages: A shared list of revved packages.
431 new_package_atoms: A shared list of new package atoms.
Mike Frysinger62ff8d72020-05-19 03:06:51 -0400432 reject_self_repo: Whether to abort if the ebuild lives in the same git
433 repo as it is tracking for uprevs.
Ningning Xia783efc02018-01-24 13:39:51 -0800434 """
Ningning Xia419e4eb2018-02-05 10:30:36 -0800435 for overlay in overlays:
436 if not os.path.isdir(overlay):
437 logging.warning('Skipping %s, which is not a directory.', overlay)
438 continue
Ningning Xia783efc02018-01-24 13:39:51 -0800439
Ningning Xia419e4eb2018-02-05 10:30:36 -0800440 # Note we intentionally work from the non push tracking branch;
441 # everything built thus far has been against it (meaning, http mirrors),
442 # thus we should honor that. During the actual push, the code switches
443 # to the correct urls, and does an appropriate rebasing.
444 tracking_branch = overlay_tracking_branch[overlay]
Ningning Xia783efc02018-01-24 13:39:51 -0800445
Ningning Xia783efc02018-01-24 13:39:51 -0800446 existing_commit = git.GetGitRepoRevision(overlay)
Lann Martine0ef98c2018-06-11 13:12:24 -0600447
448 # Make sure we run in the top-level git directory in case we are
449 # adding/removing an overlay in existing_commit.
450 git_root = git.FindGitTopLevel(overlay)
451 if git_root is None:
452 cros_build_lib.Die('No git repo at overlay directory %s.', overlay)
453
Ningning Xia783efc02018-01-24 13:39:51 -0800454 work_branch = GitBranch(constants.STABLE_EBUILD_BRANCH, tracking_branch,
Lann Martine0ef98c2018-06-11 13:12:24 -0600455 cwd=git_root)
Ningning Xia783efc02018-01-24 13:39:51 -0800456 work_branch.CreateBranch()
457 if not work_branch.Exists():
458 cros_build_lib.Die('Unable to create stabilizing branch in %s' %
459 overlay)
460
461 # In the case of uprevving overlays that have patches applied to them,
462 # include the patched changes in the stabilizing branch.
Lann Martine0ef98c2018-06-11 13:12:24 -0600463 git.RunGit(git_root, ['rebase', existing_commit])
Ningning Xia783efc02018-01-24 13:39:51 -0800464
Ningning Xiadb884322018-01-26 16:27:06 -0800465 ebuilds = overlay_ebuilds.get(overlay, [])
Ningning Xia783efc02018-01-24 13:39:51 -0800466 if ebuilds:
Ningning Xia419e4eb2018-02-05 10:30:36 -0800467 with parallel.Manager() as manager:
468 # Contains the array of packages we actually revved.
469 messages = manager.list()
470 ebuild_paths_to_add = manager.list()
471 ebuild_paths_to_remove = manager.list()
Ningning Xia783efc02018-01-24 13:39:51 -0800472
Ningning Xia419e4eb2018-02-05 10:30:36 -0800473 inputs = [[overlay, ebuild, manifest, options, ebuild_paths_to_add,
474 ebuild_paths_to_remove, messages, revved_packages,
Mike Frysinger62ff8d72020-05-19 03:06:51 -0400475 new_package_atoms, reject_self_repo]
476 for ebuild in ebuilds]
Ningning Xia419e4eb2018-02-05 10:30:36 -0800477 parallel.RunTasksInProcessPool(_WorkOnEbuild, inputs)
Ningning Xia783efc02018-01-24 13:39:51 -0800478
Ningning Xia419e4eb2018-02-05 10:30:36 -0800479 if ebuild_paths_to_add:
480 logging.info('Adding new stable ebuild paths %s in overlay %s.',
481 ebuild_paths_to_add, overlay)
482 git.RunGit(overlay, ['add'] + list(ebuild_paths_to_add))
David James15ed1302013-04-25 09:21:19 -0700483
Ningning Xia419e4eb2018-02-05 10:30:36 -0800484 if ebuild_paths_to_remove:
485 logging.info('Removing old ebuild paths %s in overlay %s.',
486 ebuild_paths_to_remove, overlay)
487 git.RunGit(overlay, ['rm', '-f'] + list(ebuild_paths_to_remove))
488
489 if messages:
490 portage_util.EBuild.CommitChange('\n\n'.join(messages), overlay)
David James15ed1302013-04-25 09:21:19 -0700491
Ningning Xia783efc02018-01-24 13:39:51 -0800492
493def _WorkOnEbuild(overlay, ebuild, manifest, options, ebuild_paths_to_add,
494 ebuild_paths_to_remove, messages, revved_packages,
Mike Frysinger62ff8d72020-05-19 03:06:51 -0400495 new_package_atoms, reject_self_repo=True):
Ningning Xia783efc02018-01-24 13:39:51 -0800496 """Work on a single ebuild.
497
498 Args:
499 overlay: The overlay where the ebuild belongs to.
500 ebuild: The ebuild to work on.
501 manifest: The manifest of the given source root.
502 options: The options object returned by the argument parser.
503 ebuild_paths_to_add: New stable ebuild paths to add to git.
504 ebuild_paths_to_remove: Old ebuild paths to remove from git.
505 messages: A share list of commit messages.
506 revved_packages: A shared list of revved packages.
507 new_package_atoms: A shared list of new package atoms.
Mike Frysinger62ff8d72020-05-19 03:06:51 -0400508 reject_self_repo: Whether to abort if the ebuild lives in the same git
509 repo as it is tracking for uprevs.
Ningning Xia783efc02018-01-24 13:39:51 -0800510 """
511 if options.verbose:
512 logging.info('Working on %s, info %s', ebuild.package,
513 ebuild.cros_workon_vars)
Mike Frysinger00ba05a2020-06-12 02:44:02 -0400514 if not ebuild.cros_workon_vars:
515 logging.warning('%s: unable to parse workon settings', ebuild.ebuild_path)
516
Ningning Xia783efc02018-01-24 13:39:51 -0800517 try:
Don Garrett4fef8c32018-08-10 18:04:01 -0700518 result = ebuild.RevWorkOnEBuild(os.path.join(options.buildroot, 'src'),
Mike Frysinger62ff8d72020-05-19 03:06:51 -0400519 manifest, reject_self_repo=reject_self_repo)
Ningning Xia783efc02018-01-24 13:39:51 -0800520 if result:
521 new_package, ebuild_path_to_add, ebuild_path_to_remove = result
522
523 if ebuild_path_to_add:
524 ebuild_paths_to_add.append(ebuild_path_to_add)
525 if ebuild_path_to_remove:
526 ebuild_paths_to_remove.append(ebuild_path_to_remove)
527
528 messages.append(_GIT_COMMIT_MESSAGE % ebuild.package)
Sam McNallyeb5e2052018-09-05 16:34:55 +1000529
530 if options.list_revisions:
531 info = ebuild.GetSourceInfo(os.path.join(options.buildroot, 'src'),
Mike Frysinger62ff8d72020-05-19 03:06:51 -0400532 manifest, reject_self_repo=reject_self_repo)
Sam McNallyeb5e2052018-09-05 16:34:55 +1000533 srcdirs = [os.path.join(options.buildroot, 'src', srcdir)
534 for srcdir in ebuild.cros_workon_vars.localname]
535 old_commit_ids = dict(
536 zip(srcdirs, ebuild.cros_workon_vars.commit.split(',')))
537 git_log = []
538 for srcdir in info.srcdirs:
539 old_commit_id = old_commit_ids.get(srcdir)
540 new_commit_id = ebuild.GetCommitId(srcdir)
541 if not old_commit_id or old_commit_id == new_commit_id:
542 continue
543
544 logs = git.RunGit(srcdir, [
545 'log', '%s..%s' % (old_commit_id[:8], new_commit_id[:8]),
546 '--pretty=format:%h %<(63,trunc)%s'])
547 git_log.append('$ ' + logs.cmdstr)
548 git_log.extend(line.strip() for line in logs.output.splitlines())
549 if git_log:
550 messages.append('\n'.join(git_log))
551
Ningning Xia783efc02018-01-24 13:39:51 -0800552 revved_packages.append(ebuild.package)
553 new_package_atoms.append('=%s' % new_package)
David Burger8cf4a762020-03-09 10:33:38 -0600554 except portage_util.InvalidUprevSourceError as e:
555 logging.error('An error occurred while uprevving %s: %s',
556 ebuild.package, e)
557 raise
Alex Klein99920662019-10-14 15:30:15 -0600558 except portage_util.EbuildVersionError as e:
559 logging.warning('Unable to rev %s: %s', ebuild.package, e)
560 raise
Mike Frysingerb32cc472020-05-15 00:17:54 -0400561 except OSError:
Ningning Xia783efc02018-01-24 13:39:51 -0800562 logging.warning(
563 'Cannot rev %s\n'
564 'Note you will have to go into %s '
Ningning Xia419e4eb2018-02-05 10:30:36 -0800565 'and reset the git repo yourself.', ebuild.package, overlay)
Ningning Xia783efc02018-01-24 13:39:51 -0800566 raise