blob: 00e904e3eeaddf1270059c0097ec086cff5606f6 [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')
Mike Frysingere8dcbfd2015-03-08 21:45:52 -0400241 parser.add_argument('--verbose', action='store_true',
242 help='Prints out debug info.')
Ningning Xia52009062016-05-09 14:33:51 -0700243 parser.add_argument('--staging_branch',
244 help='The staging branch to push changes')
Mike Frysinger1f4478c2019-10-20 18:33:17 -0400245 parser.add_argument('command', choices=sorted(COMMAND_DICTIONARY),
Mike Frysingere8dcbfd2015-03-08 21:45:52 -0400246 help='Command to run.')
247 return parser
248
249
250def main(argv):
251 parser = GetParser()
252 options = parser.parse_args(argv)
Don Garrett4fef8c32018-08-10 18:04:01 -0700253
254 # TODO: Remove this code in favor of a simple default on buildroot when
255 # srcroot is removed.
256 if options.srcroot and not options.buildroot:
257 # Convert /<repo>/src -> <repo>
258 options.buildroot = os.path.dirname(options.srcroot)
259 if not options.buildroot:
260 options.buildroot = constants.SOURCE_ROOT
261 options.srcroot = None
262
Bertrand SIMONNET6af54302015-08-05 10:12:49 -0700263 options.Freeze()
Mike Frysingere8dcbfd2015-03-08 21:45:52 -0400264
Bertrand SIMONNET6af54302015-08-05 10:12:49 -0700265 if options.command == 'commit':
266 if not options.packages and not options.all:
267 parser.error('Please specify at least one package (--packages)')
268 if options.force and options.all:
269 parser.error('Cannot use --force with --all. You must specify a list of '
270 'packages you want to force uprev.')
271
Don Garrett4fef8c32018-08-10 18:04:01 -0700272 if not os.path.isdir(options.buildroot):
273 parser.error('buildroot is not a valid path: %s' % options.buildroot)
Mike Frysingere8dcbfd2015-03-08 21:45:52 -0400274
Don Garrettf9eff952018-08-10 16:50:04 -0700275 if options.overlay_type and options.overlays:
276 parser.error('Cannot use --overlay-type with --overlays.')
277
Alex Deymo075c2292014-09-04 18:31:50 -0700278 portage_util.EBuild.VERBOSE = options.verbose
Chris Sosa62ad8522011-03-08 17:46:17 -0800279
Chris Sosa62ad8522011-03-08 17:46:17 -0800280 package_list = None
281 if options.packages:
282 package_list = options.packages.split(':')
283
Ningning Xiadb884322018-01-26 16:27:06 -0800284 overlays = []
Chris Sosa62ad8522011-03-08 17:46:17 -0800285 if options.overlays:
Chris Sosa62ad8522011-03-08 17:46:17 -0800286 for path in options.overlays.split(':'):
Ryan Cui05a31ba2011-05-31 17:47:37 -0700287 if not os.path.isdir(path):
Chris Sosac13bba52011-05-24 15:14:09 -0700288 cros_build_lib.Die('Cannot find overlay: %s' % path)
Ningning Xiadb884322018-01-26 16:27:06 -0800289 overlays.append(os.path.realpath(path))
Don Garrettf9eff952018-08-10 16:50:04 -0700290 elif options.overlay_type:
291 overlays = portage_util.FindOverlays(
Don Garrett4fef8c32018-08-10 18:04:01 -0700292 options.overlay_type, buildroot=options.buildroot)
Chris Sosadad0d322011-01-31 16:37:33 -0800293 else:
Ralph Nathan446aee92015-03-23 14:44:56 -0700294 logging.warning('Missing --overlays argument')
Ningning Xiadb884322018-01-26 16:27:06 -0800295 overlays.extend([
Don Garrett4fef8c32018-08-10 18:04:01 -0700296 '%s/src/private-overlays/chromeos-overlay' % options.buildroot,
297 '%s/src/third_party/chromiumos-overlay' % options.buildroot])
Chris Sosadad0d322011-01-31 16:37:33 -0800298
Don Garrett4fef8c32018-08-10 18:04:01 -0700299 manifest = git.ManifestCheckout.Cached(options.buildroot)
Ryan Cui4656a3c2011-05-24 12:30:30 -0700300
Ningning Xia419e4eb2018-02-05 10:30:36 -0800301 # Dict mapping from each overlay to its tracking branch.
302 overlay_tracking_branch = {}
303 # Dict mapping from each git repository (project) to a list of its overlays.
304 git_project_overlays = {}
305
306 for overlay in overlays:
307 remote_ref = git.GetTrackingBranchViaManifest(overlay, manifest=manifest)
308 overlay_tracking_branch[overlay] = remote_ref.ref
309 git_project_overlays.setdefault(remote_ref.project_name, []).append(overlay)
310
311 if options.command == 'push':
312 _WorkOnPush(options, overlay_tracking_branch, git_project_overlays)
313 elif options.command == 'commit':
314 _WorkOnCommit(options, overlays, overlay_tracking_branch,
315 git_project_overlays, manifest, package_list)
316
317
318def _WorkOnPush(options, overlay_tracking_branch, git_project_overlays):
319 """Push uprevs of overlays belonging to differet git projects in parallel.
320
321 Args:
322 options: The options object returned by the argument parser.
323 overlay_tracking_branch: A dict mapping from each overlay to its tracking
324 branch.
325 git_project_overlays: A dict mapping from each git repository to a list of
326 its overlays.
327 """
328 inputs = [[options, overlays_per_project, overlay_tracking_branch]
Mike Frysinger0bdbc102019-06-13 15:27:29 -0400329 for overlays_per_project in git_project_overlays.values()]
Ningning Xia419e4eb2018-02-05 10:30:36 -0800330 parallel.RunTasksInProcessPool(_PushOverlays, inputs)
331
332
333def _PushOverlays(options, overlays, overlay_tracking_branch):
334 """Push uprevs for overlays in sequence.
335
336 Args:
337 options: The options object returned by the argument parser.
338 overlays: A list of overlays to push uprevs in sequence.
339 overlay_tracking_branch: A dict mapping from each overlay to its tracking
340 branch.
341 """
342 for overlay in overlays:
343 if not os.path.isdir(overlay):
344 logging.warning('Skipping %s, which is not a directory.', overlay)
345 continue
346
347 tracking_branch = overlay_tracking_branch[overlay]
348 PushChange(constants.STABLE_EBUILD_BRANCH, tracking_branch, options.dryrun,
349 cwd=overlay, staging_branch=options.staging_branch)
350
351
352def _WorkOnCommit(options, overlays, overlay_tracking_branch,
353 git_project_overlays, manifest, package_list):
354 """Commit uprevs of overlays belonging to different git projects in parallel.
355
356 Args:
357 options: The options object returned by the argument parser.
358 overlays: A list of overlays to work on.
359 overlay_tracking_branch: A dict mapping from each overlay to its tracking
360 branch.
361 git_project_overlays: A dict mapping from each git repository to a list of
362 its overlays.
363 manifest: The manifest of the given source root.
364 package_list: A list of packages passed from commandline to work on.
365 """
Mike Frysinger62ff8d72020-05-19 03:06:51 -0400366 # We cleaned up self referential ebuilds by this version, but don't enforce
367 # the check on older ones to avoid breaking factory/firmware branches.
368 root_version = manifest_version.VersionInfo.from_repo(options.buildroot)
369 no_self_repos_version = manifest_version.VersionInfo('13099.0.0')
370 reject_self_repo = root_version >= no_self_repos_version
371
Ningning Xia419e4eb2018-02-05 10:30:36 -0800372 overlay_ebuilds = _GetOverlayToEbuildsMap(options, overlays, package_list)
David James84e953c2013-04-23 18:44:06 -0700373
Ningning Xia783efc02018-01-24 13:39:51 -0800374 with parallel.Manager() as manager:
375 # Contains the array of packages we actually revved.
376 revved_packages = manager.list()
377 new_package_atoms = manager.list()
David Jamesa8457b52011-05-28 00:03:20 -0700378
Ningning Xia419e4eb2018-02-05 10:30:36 -0800379 inputs = [[options, manifest, overlays_per_project, overlay_tracking_branch,
Mike Frysinger62ff8d72020-05-19 03:06:51 -0400380 overlay_ebuilds, revved_packages, new_package_atoms,
381 reject_self_repo]
Mike Frysinger0bdbc102019-06-13 15:27:29 -0400382 for overlays_per_project in git_project_overlays.values()]
Ningning Xia419e4eb2018-02-05 10:30:36 -0800383 parallel.RunTasksInProcessPool(_CommitOverlays, inputs)
Chris Sosadad0d322011-01-31 16:37:33 -0800384
Don Garrett4fef8c32018-08-10 18:04:01 -0700385 chroot_path = os.path.join(options.buildroot, constants.DEFAULT_CHROOT_DIR)
Ningning Xia419e4eb2018-02-05 10:30:36 -0800386 if os.path.exists(chroot_path):
Don Garrett4fef8c32018-08-10 18:04:01 -0700387 CleanStalePackages(options.buildroot, options.boards.split(':'),
Ningning Xia419e4eb2018-02-05 10:30:36 -0800388 new_package_atoms)
Mike Nicholsf7f13a82019-01-11 17:11:04 +0000389 if options.drop_file:
390 osutils.WriteFile(options.drop_file, ' '.join(revved_packages))
Chris Sosadad0d322011-01-31 16:37:33 -0800391
Brian Harring609dc4e2012-05-07 02:17:44 -0700392
Ningning Xia419e4eb2018-02-05 10:30:36 -0800393def _GetOverlayToEbuildsMap(options, overlays, package_list):
394 """Get ebuilds for overlays.
David James15ed1302013-04-25 09:21:19 -0700395
Ningning Xia783efc02018-01-24 13:39:51 -0800396 Args:
Ningning Xia783efc02018-01-24 13:39:51 -0800397 options: The options object returned by the argument parser.
Ningning Xia419e4eb2018-02-05 10:30:36 -0800398 overlays: A list of overlays to work on.
399 package_list: A list of packages passed from commandline to work on.
400
401 Returns:
402 A dict mapping each overlay to a list of ebuilds belonging to it.
403 """
Don Garrett3dbb2932018-10-02 14:41:26 -0700404 root_version = manifest_version.VersionInfo.from_repo(options.buildroot)
405 subdir_removal = manifest_version.VersionInfo('10363.0.0')
406 require_subdir_support = root_version < subdir_removal
407
Ningning Xia419e4eb2018-02-05 10:30:36 -0800408 overlay_ebuilds = {}
Don Garrett3dbb2932018-10-02 14:41:26 -0700409 inputs = [[overlay, options.all, package_list, options.force,
410 require_subdir_support]
Ningning Xia419e4eb2018-02-05 10:30:36 -0800411 for overlay in overlays]
412 result = parallel.RunTasksInProcessPool(
413 portage_util.GetOverlayEBuilds, inputs)
414 for idx, ebuilds in enumerate(result):
415 overlay_ebuilds[overlays[idx]] = ebuilds
416
417 return overlay_ebuilds
418
419
420def _CommitOverlays(options, manifest, overlays, overlay_tracking_branch,
Mike Frysinger62ff8d72020-05-19 03:06:51 -0400421 overlay_ebuilds, revved_packages, new_package_atoms,
422 reject_self_repo=True):
Ningning Xia419e4eb2018-02-05 10:30:36 -0800423 """Commit uprevs for overlays in sequence.
424
425 Args:
426 options: The options object returned by the argument parser.
427 manifest: The manifest of the given source root.
428 overlays: A list over overlays to commit.
429 overlay_tracking_branch: A dict mapping from each overlay to its tracking
430 branch.
431 overlay_ebuilds: A dict mapping overlays to their ebuilds.
Ningning Xia783efc02018-01-24 13:39:51 -0800432 revved_packages: A shared list of revved packages.
433 new_package_atoms: A shared list of new package atoms.
Mike Frysinger62ff8d72020-05-19 03:06:51 -0400434 reject_self_repo: Whether to abort if the ebuild lives in the same git
435 repo as it is tracking for uprevs.
Ningning Xia783efc02018-01-24 13:39:51 -0800436 """
Ningning Xia419e4eb2018-02-05 10:30:36 -0800437 for overlay in overlays:
438 if not os.path.isdir(overlay):
439 logging.warning('Skipping %s, which is not a directory.', overlay)
440 continue
Ningning Xia783efc02018-01-24 13:39:51 -0800441
Ningning Xia419e4eb2018-02-05 10:30:36 -0800442 # Note we intentionally work from the non push tracking branch;
443 # everything built thus far has been against it (meaning, http mirrors),
444 # thus we should honor that. During the actual push, the code switches
445 # to the correct urls, and does an appropriate rebasing.
446 tracking_branch = overlay_tracking_branch[overlay]
Ningning Xia783efc02018-01-24 13:39:51 -0800447
Ningning Xia783efc02018-01-24 13:39:51 -0800448 existing_commit = git.GetGitRepoRevision(overlay)
Lann Martine0ef98c2018-06-11 13:12:24 -0600449
450 # Make sure we run in the top-level git directory in case we are
451 # adding/removing an overlay in existing_commit.
452 git_root = git.FindGitTopLevel(overlay)
453 if git_root is None:
454 cros_build_lib.Die('No git repo at overlay directory %s.', overlay)
455
Ningning Xia783efc02018-01-24 13:39:51 -0800456 work_branch = GitBranch(constants.STABLE_EBUILD_BRANCH, tracking_branch,
Lann Martine0ef98c2018-06-11 13:12:24 -0600457 cwd=git_root)
Ningning Xia783efc02018-01-24 13:39:51 -0800458 work_branch.CreateBranch()
459 if not work_branch.Exists():
460 cros_build_lib.Die('Unable to create stabilizing branch in %s' %
461 overlay)
462
463 # In the case of uprevving overlays that have patches applied to them,
464 # include the patched changes in the stabilizing branch.
Lann Martine0ef98c2018-06-11 13:12:24 -0600465 git.RunGit(git_root, ['rebase', existing_commit])
Ningning Xia783efc02018-01-24 13:39:51 -0800466
Ningning Xiadb884322018-01-26 16:27:06 -0800467 ebuilds = overlay_ebuilds.get(overlay, [])
Ningning Xia783efc02018-01-24 13:39:51 -0800468 if ebuilds:
Ningning Xia419e4eb2018-02-05 10:30:36 -0800469 with parallel.Manager() as manager:
470 # Contains the array of packages we actually revved.
471 messages = manager.list()
472 ebuild_paths_to_add = manager.list()
473 ebuild_paths_to_remove = manager.list()
Ningning Xia783efc02018-01-24 13:39:51 -0800474
Ningning Xia419e4eb2018-02-05 10:30:36 -0800475 inputs = [[overlay, ebuild, manifest, options, ebuild_paths_to_add,
476 ebuild_paths_to_remove, messages, revved_packages,
Mike Frysinger62ff8d72020-05-19 03:06:51 -0400477 new_package_atoms, reject_self_repo]
478 for ebuild in ebuilds]
Ningning Xia419e4eb2018-02-05 10:30:36 -0800479 parallel.RunTasksInProcessPool(_WorkOnEbuild, inputs)
Ningning Xia783efc02018-01-24 13:39:51 -0800480
Ningning Xia419e4eb2018-02-05 10:30:36 -0800481 if ebuild_paths_to_add:
482 logging.info('Adding new stable ebuild paths %s in overlay %s.',
483 ebuild_paths_to_add, overlay)
484 git.RunGit(overlay, ['add'] + list(ebuild_paths_to_add))
David James15ed1302013-04-25 09:21:19 -0700485
Ningning Xia419e4eb2018-02-05 10:30:36 -0800486 if ebuild_paths_to_remove:
487 logging.info('Removing old ebuild paths %s in overlay %s.',
488 ebuild_paths_to_remove, overlay)
489 git.RunGit(overlay, ['rm', '-f'] + list(ebuild_paths_to_remove))
490
491 if messages:
492 portage_util.EBuild.CommitChange('\n\n'.join(messages), overlay)
David James15ed1302013-04-25 09:21:19 -0700493
Ningning Xia783efc02018-01-24 13:39:51 -0800494
495def _WorkOnEbuild(overlay, ebuild, manifest, options, ebuild_paths_to_add,
496 ebuild_paths_to_remove, messages, revved_packages,
Mike Frysinger62ff8d72020-05-19 03:06:51 -0400497 new_package_atoms, reject_self_repo=True):
Ningning Xia783efc02018-01-24 13:39:51 -0800498 """Work on a single ebuild.
499
500 Args:
501 overlay: The overlay where the ebuild belongs to.
502 ebuild: The ebuild to work on.
503 manifest: The manifest of the given source root.
504 options: The options object returned by the argument parser.
505 ebuild_paths_to_add: New stable ebuild paths to add to git.
506 ebuild_paths_to_remove: Old ebuild paths to remove from git.
507 messages: A share list of commit messages.
508 revved_packages: A shared list of revved packages.
509 new_package_atoms: A shared list of new package atoms.
Mike Frysinger62ff8d72020-05-19 03:06:51 -0400510 reject_self_repo: Whether to abort if the ebuild lives in the same git
511 repo as it is tracking for uprevs.
Ningning Xia783efc02018-01-24 13:39:51 -0800512 """
513 if options.verbose:
514 logging.info('Working on %s, info %s', ebuild.package,
515 ebuild.cros_workon_vars)
516 try:
Don Garrett4fef8c32018-08-10 18:04:01 -0700517 result = ebuild.RevWorkOnEBuild(os.path.join(options.buildroot, 'src'),
Mike Frysinger62ff8d72020-05-19 03:06:51 -0400518 manifest, reject_self_repo=reject_self_repo)
Ningning Xia783efc02018-01-24 13:39:51 -0800519 if result:
520 new_package, ebuild_path_to_add, ebuild_path_to_remove = result
521
522 if ebuild_path_to_add:
523 ebuild_paths_to_add.append(ebuild_path_to_add)
524 if ebuild_path_to_remove:
525 ebuild_paths_to_remove.append(ebuild_path_to_remove)
526
527 messages.append(_GIT_COMMIT_MESSAGE % ebuild.package)
Sam McNallyeb5e2052018-09-05 16:34:55 +1000528
529 if options.list_revisions:
530 info = ebuild.GetSourceInfo(os.path.join(options.buildroot, 'src'),
Mike Frysinger62ff8d72020-05-19 03:06:51 -0400531 manifest, reject_self_repo=reject_self_repo)
Sam McNallyeb5e2052018-09-05 16:34:55 +1000532 srcdirs = [os.path.join(options.buildroot, 'src', srcdir)
533 for srcdir in ebuild.cros_workon_vars.localname]
534 old_commit_ids = dict(
535 zip(srcdirs, ebuild.cros_workon_vars.commit.split(',')))
536 git_log = []
537 for srcdir in info.srcdirs:
538 old_commit_id = old_commit_ids.get(srcdir)
539 new_commit_id = ebuild.GetCommitId(srcdir)
540 if not old_commit_id or old_commit_id == new_commit_id:
541 continue
542
543 logs = git.RunGit(srcdir, [
544 'log', '%s..%s' % (old_commit_id[:8], new_commit_id[:8]),
545 '--pretty=format:%h %<(63,trunc)%s'])
546 git_log.append('$ ' + logs.cmdstr)
547 git_log.extend(line.strip() for line in logs.output.splitlines())
548 if git_log:
549 messages.append('\n'.join(git_log))
550
Ningning Xia783efc02018-01-24 13:39:51 -0800551 revved_packages.append(ebuild.package)
552 new_package_atoms.append('=%s' % new_package)
David Burger8cf4a762020-03-09 10:33:38 -0600553 except portage_util.InvalidUprevSourceError as e:
554 logging.error('An error occurred while uprevving %s: %s',
555 ebuild.package, e)
556 raise
Alex Klein99920662019-10-14 15:30:15 -0600557 except portage_util.EbuildVersionError as e:
558 logging.warning('Unable to rev %s: %s', ebuild.package, e)
559 raise
Mike Frysingerb32cc472020-05-15 00:17:54 -0400560 except OSError:
Ningning Xia783efc02018-01-24 13:39:51 -0800561 logging.warning(
562 'Cannot rev %s\n'
563 'Note you will have to go into %s '
Ningning Xia419e4eb2018-02-05 10:30:36 -0800564 'and reset the git repo yourself.', ebuild.package, overlay)
Ningning Xia783efc02018-01-24 13:39:51 -0800565 raise