blob: 87c5bcda4433dfd452814859065782ddb016bb42 [file] [log] [blame]
Mike Frysinger110750a2012-03-26 14:19:20 -04001# Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
Chris Sosadad0d322011-01-31 16:37:33 -08002# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5"""This module uprevs a given package's ebuild to the next revision."""
6
Chris Sosadad0d322011-01-31 16:37:33 -08007import os
Chris Sosadad0d322011-01-31 16:37:33 -08008
Aviv Keshetb7519e12016-10-04 00:50:00 -07009from chromite.lib import constants
Mike Frysingere8dcbfd2015-03-08 21:45:52 -040010from chromite.lib import commandline
Chris Sosac13bba52011-05-24 15:14:09 -070011from chromite.lib import cros_build_lib
Ralph Nathan03047282015-03-23 11:09:32 -070012from chromite.lib import cros_logging as logging
David James97d95872012-11-16 15:09:56 -080013from chromite.lib import git
Mike Frysingerfddaeb52012-11-20 11:17:31 -050014from chromite.lib import osutils
David James6450a0a2012-12-04 07:59:53 -080015from chromite.lib import parallel
Alex Deymo075c2292014-09-04 18:31:50 -070016from chromite.lib import portage_util
Lann Martinb26e1292018-08-09 13:59:19 -060017from chromite.lib import repo_util
Sergey Frolov0161f8b2021-07-07 17:41:10 -060018from chromite.lib import retry_util
Chris Sosac13bba52011-05-24 15:14:09 -070019
Don Garrett3dbb2932018-10-02 14:41:26 -070020from chromite.cbuildbot import manifest_version
21
Mike Frysinger32781402020-04-19 06:34:17 -040022
Gabe Black71e963e2014-10-28 20:19:59 -070023# Commit message subject for uprevving Portage packages.
24GIT_COMMIT_SUBJECT = 'Marking set of ebuilds as stable'
David James15ed1302013-04-25 09:21:19 -070025
David James29e86d52013-04-19 09:41:29 -070026# Commit message for uprevving Portage packages.
27_GIT_COMMIT_MESSAGE = 'Marking 9999 ebuild for %s as stable.'
28
Chris Sosadad0d322011-01-31 16:37:33 -080029# Dictionary of valid commands with usage information.
30COMMAND_DICTIONARY = {
Mike Frysinger5cd8c742013-10-11 14:43:01 -040031 'commit': 'Marks given ebuilds as stable locally',
32 'push': 'Pushes previous marking of ebuilds to remote repo',
33}
Chris Sosadad0d322011-01-31 16:37:33 -080034
Chris Sosadad0d322011-01-31 16:37:33 -080035
Chris Sosadad0d322011-01-31 16:37:33 -080036# ======================= Global Helper Functions ========================
37
38
David James41124af2015-06-04 21:13:25 -070039def CleanStalePackages(srcroot, boards, package_atoms):
Chris Sosabf153872011-04-28 14:21:09 -070040 """Cleans up stale package info from a previous build.
Mike Frysinger5cd8c742013-10-11 14:43:01 -040041
Chris Sosabf153872011-04-28 14:21:09 -070042 Args:
David James41124af2015-06-04 21:13:25 -070043 srcroot: Root directory of the source tree.
David Jamescc09c9b2012-01-26 22:10:13 -080044 boards: Boards to clean the packages from.
Mike Frysingerde5ab0e2013-03-21 20:48:36 -040045 package_atoms: A list of package atoms to unmerge.
Chris Sosabf153872011-04-28 14:21:09 -070046 """
David James15ed1302013-04-25 09:21:19 -070047 if package_atoms:
Lann Martinffb95162018-08-28 12:02:54 -060048 logging.info('Cleaning up stale packages %s.', package_atoms)
David James15ed1302013-04-25 09:21:19 -070049
Mike Frysingerb7ab9b82012-04-04 16:22:43 -040050 # First unmerge all the packages for a board, then eclean it.
51 # We need these two steps to run in order (unmerge/eclean),
52 # but we can let all the boards run in parallel.
53 def _CleanStalePackages(board):
54 if board:
55 suffix = '-' + board
Mike Frysinger45602c72019-09-22 02:15:11 -040056 runcmd = cros_build_lib.run
Mike Frysingerb7ab9b82012-04-04 16:22:43 -040057 else:
58 suffix = ''
Mike Frysinger45602c72019-09-22 02:15:11 -040059 runcmd = cros_build_lib.sudo_run
Chris Sosadad0d322011-01-31 16:37:33 -080060
David James59a0a2b2013-03-22 14:04:44 -070061 emerge, eclean = 'emerge' + suffix, 'eclean' + suffix
62 if not osutils.FindMissingBinaries([emerge, eclean]):
David James63841a82014-01-16 14:39:24 -080063 if package_atoms:
64 # If nothing was found to be unmerged, emerge will exit(1).
Don Garrett7100fff2018-10-23 11:07:13 -070065 result = runcmd([emerge, '-q', '--unmerge'] + list(package_atoms),
David James41124af2015-06-04 21:13:25 -070066 enter_chroot=True, extra_env={'CLEAN_DELAY': '0'},
Mike Frysingerf5a3b2d2019-12-12 14:36:17 -050067 check=False, cwd=srcroot)
Mike Frysinger01504112019-08-24 19:35:24 -040068 if result.returncode not in (0, 1):
David James63841a82014-01-16 14:39:24 -080069 raise cros_build_lib.RunCommandError('unexpected error', result)
David James59a0a2b2013-03-22 14:04:44 -070070 runcmd([eclean, '-d', 'packages'],
David James41124af2015-06-04 21:13:25 -070071 cwd=srcroot, enter_chroot=True,
Mike Frysinger0282d222019-12-17 17:15:48 -050072 stdout=True, stderr=True)
Mike Frysingerb7ab9b82012-04-04 16:22:43 -040073
74 tasks = []
David Jamescc09c9b2012-01-26 22:10:13 -080075 for board in boards:
Mike Frysingerb7ab9b82012-04-04 16:22:43 -040076 tasks.append([board])
77 tasks.append([None])
78
David James6450a0a2012-12-04 07:59:53 -080079 parallel.RunTasksInProcessPool(_CleanStalePackages, tasks)
Chris Sosadad0d322011-01-31 16:37:33 -080080
81
Mike Frysinger2ebe3732012-05-08 17:04:12 -040082# TODO(build): This code needs to be gutted and rebased to cros_build_lib.
83def _DoWeHaveLocalCommits(stable_branch, tracking_branch, cwd):
Chris Sosadad0d322011-01-31 16:37:33 -080084 """Returns true if there are local commits."""
David James97d95872012-11-16 15:09:56 -080085 output = git.RunGit(
Paul Hobbs72d8e392015-10-21 17:24:23 -070086 cwd, ['rev-parse', stable_branch, tracking_branch]).output.split()
Brian Harring5b86b5e2012-05-25 18:27:40 -070087 return output[0] != output[1]
Chris Sosadad0d322011-01-31 16:37:33 -080088
89
Chris Sosadad0d322011-01-31 16:37:33 -080090# ======================= End Global Helper Functions ========================
91
92
Ningning Xia52009062016-05-09 14:33:51 -070093def PushChange(stable_branch, tracking_branch, dryrun, cwd,
94 staging_branch=None):
Chris Sosadad0d322011-01-31 16:37:33 -080095 """Pushes commits in the stable_branch to the remote git repository.
96
David Jamesee2da622012-02-23 09:32:16 -080097 Pushes local commits from calls to CommitChange to the remote git
David James66009462012-03-25 10:08:38 -070098 repository specified by current working directory. If changes are
99 found to commit, they will be merged to the merge branch and pushed.
100 In that case, the local repository will be left on the merge branch.
Chris Sosadad0d322011-01-31 16:37:33 -0800101
102 Args:
103 stable_branch: The local branch with commits we want to push.
104 tracking_branch: The tracking branch of the local branch.
Chris Sosa62ad8522011-03-08 17:46:17 -0800105 dryrun: Use git push --dryrun to emulate a push.
Mike Frysinger2ebe3732012-05-08 17:04:12 -0400106 cwd: The directory to run commands in.
Ningning Xia52009062016-05-09 14:33:51 -0700107 staging_branch: The staging branch to push for a failed PFQ run
Mike Frysinger1a736a82013-12-12 01:50:59 -0500108
Chris Sosadad0d322011-01-31 16:37:33 -0800109 Raises:
Mike Frysinger5cd8c742013-10-11 14:43:01 -0400110 OSError: Error occurred while pushing.
Chris Sosadad0d322011-01-31 16:37:33 -0800111 """
David James47959632015-10-23 07:56:01 -0700112 if not git.DoesCommitExistInRepo(cwd, stable_branch):
113 logging.debug('No branch created for %s. Exiting', cwd)
114 return
115
Mike Frysinger2ebe3732012-05-08 17:04:12 -0400116 if not _DoWeHaveLocalCommits(stable_branch, tracking_branch, cwd):
David James47959632015-10-23 07:56:01 -0700117 logging.debug('No work found to push in %s. Exiting', cwd)
Chris Sosadad0d322011-01-31 16:37:33 -0800118 return
119
David James66009462012-03-25 10:08:38 -0700120 # For the commit queue, our local branch may contain commits that were
121 # just tested and pushed during the CommitQueueCompletion stage. Sync
122 # and rebase our local branch on top of the remote commits.
Paul Hobbs72d8e392015-10-21 17:24:23 -0700123 remote_ref = git.GetTrackingBranch(cwd,
124 branch=stable_branch,
125 for_push=True)
Paul Hobbs1e46be82015-10-30 13:46:02 -0700126 # SyncPushBranch rebases HEAD onto the updated remote. We need to checkout
127 # stable_branch here in order to update it.
128 git.RunGit(cwd, ['checkout', stable_branch])
Don Garrett99449592015-03-25 11:01:30 -0700129 git.SyncPushBranch(cwd, remote_ref.remote, remote_ref.ref)
David James66009462012-03-25 10:08:38 -0700130
131 # Check whether any local changes remain after the sync.
Don Garrett99449592015-03-25 11:01:30 -0700132 if not _DoWeHaveLocalCommits(stable_branch, remote_ref.ref, cwd):
Ralph Nathan03047282015-03-23 11:09:32 -0700133 logging.info('All changes already pushed for %s. Exiting', cwd)
David James66009462012-03-25 10:08:38 -0700134 return
135
LaMont Jonese708e402021-06-10 08:54:30 -0600136 # Add a failsafe check here. Only CLs from these users should be here.
137 # - 'chrome-bot',
138 # - 'chromeos-ci-prod'
139 # - 'chromeos-ci-release'
140 # If any other CLs are found then complain. In dryruns extra CLs are normal,
141 # though, and can be ignored.
Andrew Lamb7ef2c0b2019-07-17 09:43:27 -0600142 bad_cl_cmd = [
143 'log', '--format=short', '--perl-regexp', '--author',
LaMont Jonese708e402021-06-10 08:54:30 -0600144 '^(?!chrome-bot|chromeos-ci-prod|chromeos-ci-release)',
Andrew Lamb7ef2c0b2019-07-17 09:43:27 -0600145 '%s..%s' % (remote_ref.ref, stable_branch)
146 ]
Matt Tennantcb522052013-11-25 14:23:43 -0800147 bad_cls = git.RunGit(cwd, bad_cl_cmd).output
148 if bad_cls.strip() and not dryrun:
Andrew Lamb7ef2c0b2019-07-17 09:43:27 -0600149 logging.error(
150 'The Uprev stage found changes from users other than '
LaMont Jonese708e402021-06-10 08:54:30 -0600151 'chrome-bot or chromeos-ci-prod or chromeos-ci-release:\n\n%s', bad_cls)
Matt Tennantcb522052013-11-25 14:23:43 -0800152 raise AssertionError('Unexpected CLs found during uprev stage.')
153
Lev Rumyantsev25352ba2016-09-07 15:53:58 -0700154 if staging_branch is not None:
155 logging.info('PFQ FAILED. Pushing uprev change to staging branch %s',
156 staging_branch)
157
Mike Frysingere65f3752014-12-08 00:46:39 -0500158 description = git.RunGit(
159 cwd,
160 ['log', '--format=format:%s%n%n%b',
Don Garrett99449592015-03-25 11:01:30 -0700161 '%s..%s' % (remote_ref.ref, stable_branch)]).output
Gabe Black71e963e2014-10-28 20:19:59 -0700162 description = '%s\n\n%s' % (GIT_COMMIT_SUBJECT, description)
Ralph Nathan03047282015-03-23 11:09:32 -0700163 logging.info('For %s, using description %s', cwd, description)
Paul Hobbsf52ea8f2015-10-21 17:24:23 -0700164 git.CreatePushBranch(constants.MERGE_BRANCH, cwd,
165 remote_push_branch=remote_ref)
David James97d95872012-11-16 15:09:56 -0800166 git.RunGit(cwd, ['merge', '--squash', stable_branch])
167 git.RunGit(cwd, ['commit', '-m', description])
168 git.RunGit(cwd, ['config', 'push.default', 'tracking'])
Sergey Frolov0161f8b2021-07-07 17:41:10 -0600169
170 # Run git.PushBranch and retry up to 5 times.
171 # retry_util.RetryCommand will only retry on RunCommandErrors,
172 # which would be thrown by git.PushBranch when it gets to
173 # cros_build_lib.run()'ning the actual git command,
174 # which may fail with a transient HTTP 429 Too Many Requests error,
175 # and we need to retry on that.
176 # Do not retry if it fails to setup before cros_build_lib.run
177 # or upon other errors, like getting SIGINT.
178 max_retries = 5
179 retry_util.RetryCommand(
180 git.PushBranch,
181 max_retries,
182 constants.MERGE_BRANCH,
183 cwd,
184 dryrun=dryrun,
185 staging_branch=staging_branch,
186 sleep=15,
187 log_retries=True,
188 )
Chris Sosadad0d322011-01-31 16:37:33 -0800189
190
191class GitBranch(object):
192 """Wrapper class for a git branch."""
193
Mike Frysinger2ebe3732012-05-08 17:04:12 -0400194 def __init__(self, branch_name, tracking_branch, cwd):
David Jamesc7c4ff52013-09-18 17:57:13 -0700195 """Sets up variables but does not create the branch.
196
Mike Frysinger5cd8c742013-10-11 14:43:01 -0400197 Args:
David Jamesc7c4ff52013-09-18 17:57:13 -0700198 branch_name: The name of the branch.
199 tracking_branch: The associated tracking branch.
200 cwd: The git repository to work in.
201 """
Chris Sosadad0d322011-01-31 16:37:33 -0800202 self.branch_name = branch_name
203 self.tracking_branch = tracking_branch
Mike Frysinger2ebe3732012-05-08 17:04:12 -0400204 self.cwd = cwd
Chris Sosadad0d322011-01-31 16:37:33 -0800205
206 def CreateBranch(self):
Mike Frysinger2ebe3732012-05-08 17:04:12 -0400207 self.Checkout()
Chris Sosadad0d322011-01-31 16:37:33 -0800208
Mike Frysinger2ebe3732012-05-08 17:04:12 -0400209 def Checkout(self, branch=None):
Chris Sosadad0d322011-01-31 16:37:33 -0800210 """Function used to check out to another GitBranch."""
Mike Frysinger2ebe3732012-05-08 17:04:12 -0400211 if not branch:
212 branch = self.branch_name
213 if branch == self.tracking_branch or self.Exists(branch):
Lann Martinb26e1292018-08-09 13:59:19 -0600214 git.RunGit(self.cwd, ['checkout', '-f', branch], quiet=True)
Chris Sosadad0d322011-01-31 16:37:33 -0800215 else:
Lann Martinb26e1292018-08-09 13:59:19 -0600216 repo = repo_util.Repository.MustFind(self.cwd)
217 repo.StartBranch(branch, projects=['.'], cwd=self.cwd)
Chris Sosadad0d322011-01-31 16:37:33 -0800218
Mike Frysinger2ebe3732012-05-08 17:04:12 -0400219 def Exists(self, branch=None):
Chris Sosadad0d322011-01-31 16:37:33 -0800220 """Returns True if the branch exists."""
Mike Frysinger2ebe3732012-05-08 17:04:12 -0400221 if not branch:
222 branch = self.branch_name
David James67d73252013-09-19 17:33:12 -0700223 branches = git.RunGit(self.cwd, ['branch']).output
Mike Frysinger2ebe3732012-05-08 17:04:12 -0400224 return branch in branches.split()
Chris Sosadad0d322011-01-31 16:37:33 -0800225
226
Mike Frysingere8dcbfd2015-03-08 21:45:52 -0400227def GetParser():
228 """Creates the argparse parser."""
229 parser = commandline.ArgumentParser()
230 parser.add_argument('--all', action='store_true',
231 help='Mark all packages as stable.')
232 parser.add_argument('-b', '--boards', default='',
233 help='Colon-separated list of boards.')
Mike Nicholsf7f13a82019-01-11 17:11:04 +0000234 parser.add_argument('--drop_file',
235 help='File to list packages that were revved.')
Mike Frysingere8dcbfd2015-03-08 21:45:52 -0400236 parser.add_argument('--dryrun', action='store_true',
237 help='Passes dry-run to git push if pushing a change.')
Bertrand SIMONNET6af54302015-08-05 10:12:49 -0700238 parser.add_argument('--force', action='store_true',
Nicolas Boichatde92a6d2021-03-31 16:43:50 +0800239 help='Force the stabilization of packages marked for '
240 'manual uprev. '
Bertrand SIMONNET6af54302015-08-05 10:12:49 -0700241 '(only compatible with -p)')
Sam McNallyeb5e2052018-09-05 16:34:55 +1000242 parser.add_argument('--list_revisions', action='store_true',
243 help='List all revisions included in the commit message.')
Mike Frysingere8dcbfd2015-03-08 21:45:52 -0400244 parser.add_argument('-o', '--overlays',
245 help='Colon-separated list of overlays to modify.')
Don Garrettf9eff952018-08-10 16:50:04 -0700246 parser.add_argument('--overlay-type',
247 help='Populates --overlays based on "public", "private"'
248 ', or "both".')
Mike Frysingere8dcbfd2015-03-08 21:45:52 -0400249 parser.add_argument('-p', '--packages',
250 help='Colon separated list of packages to rev.')
Don Garrett4fef8c32018-08-10 18:04:01 -0700251 parser.add_argument('--buildroot', type='path',
252 help='Path to buildroot.')
Mike Frysingere8dcbfd2015-03-08 21:45:52 -0400253 parser.add_argument('-r', '--srcroot', type='path',
Don Garrett4fef8c32018-08-10 18:04:01 -0700254 help='Path to root src. Deprecated in favor of '
255 '--buildroot')
Ningning Xia52009062016-05-09 14:33:51 -0700256 parser.add_argument('--staging_branch',
257 help='The staging branch to push changes')
Mike Frysinger1f4478c2019-10-20 18:33:17 -0400258 parser.add_argument('command', choices=sorted(COMMAND_DICTIONARY),
Mike Frysingere8dcbfd2015-03-08 21:45:52 -0400259 help='Command to run.')
260 return parser
261
262
263def main(argv):
264 parser = GetParser()
265 options = parser.parse_args(argv)
Don Garrett4fef8c32018-08-10 18:04:01 -0700266
267 # TODO: Remove this code in favor of a simple default on buildroot when
268 # srcroot is removed.
269 if options.srcroot and not options.buildroot:
270 # Convert /<repo>/src -> <repo>
271 options.buildroot = os.path.dirname(options.srcroot)
272 if not options.buildroot:
273 options.buildroot = constants.SOURCE_ROOT
274 options.srcroot = None
275
Bertrand SIMONNET6af54302015-08-05 10:12:49 -0700276 options.Freeze()
Mike Frysingere8dcbfd2015-03-08 21:45:52 -0400277
Bertrand SIMONNET6af54302015-08-05 10:12:49 -0700278 if options.command == 'commit':
279 if not options.packages and not options.all:
280 parser.error('Please specify at least one package (--packages)')
281 if options.force and options.all:
282 parser.error('Cannot use --force with --all. You must specify a list of '
283 'packages you want to force uprev.')
284
Don Garrett4fef8c32018-08-10 18:04:01 -0700285 if not os.path.isdir(options.buildroot):
286 parser.error('buildroot is not a valid path: %s' % options.buildroot)
Mike Frysingere8dcbfd2015-03-08 21:45:52 -0400287
Don Garrettf9eff952018-08-10 16:50:04 -0700288 if options.overlay_type and options.overlays:
289 parser.error('Cannot use --overlay-type with --overlays.')
290
Alex Deymo075c2292014-09-04 18:31:50 -0700291 portage_util.EBuild.VERBOSE = options.verbose
Chris Sosa62ad8522011-03-08 17:46:17 -0800292
Chris Sosa62ad8522011-03-08 17:46:17 -0800293 package_list = None
294 if options.packages:
295 package_list = options.packages.split(':')
296
Ningning Xiadb884322018-01-26 16:27:06 -0800297 overlays = []
Chris Sosa62ad8522011-03-08 17:46:17 -0800298 if options.overlays:
Chris Sosa62ad8522011-03-08 17:46:17 -0800299 for path in options.overlays.split(':'):
Ryan Cui05a31ba2011-05-31 17:47:37 -0700300 if not os.path.isdir(path):
Chris Sosac13bba52011-05-24 15:14:09 -0700301 cros_build_lib.Die('Cannot find overlay: %s' % path)
Ningning Xiadb884322018-01-26 16:27:06 -0800302 overlays.append(os.path.realpath(path))
Don Garrettf9eff952018-08-10 16:50:04 -0700303 elif options.overlay_type:
304 overlays = portage_util.FindOverlays(
Don Garrett4fef8c32018-08-10 18:04:01 -0700305 options.overlay_type, buildroot=options.buildroot)
Chris Sosadad0d322011-01-31 16:37:33 -0800306 else:
Ralph Nathan446aee92015-03-23 14:44:56 -0700307 logging.warning('Missing --overlays argument')
Ningning Xiadb884322018-01-26 16:27:06 -0800308 overlays.extend([
Don Garrett4fef8c32018-08-10 18:04:01 -0700309 '%s/src/private-overlays/chromeos-overlay' % options.buildroot,
310 '%s/src/third_party/chromiumos-overlay' % options.buildroot])
Chris Sosadad0d322011-01-31 16:37:33 -0800311
Don Garrett4fef8c32018-08-10 18:04:01 -0700312 manifest = git.ManifestCheckout.Cached(options.buildroot)
Ryan Cui4656a3c2011-05-24 12:30:30 -0700313
Ningning Xia419e4eb2018-02-05 10:30:36 -0800314 # Dict mapping from each overlay to its tracking branch.
315 overlay_tracking_branch = {}
316 # Dict mapping from each git repository (project) to a list of its overlays.
317 git_project_overlays = {}
318
319 for overlay in overlays:
320 remote_ref = git.GetTrackingBranchViaManifest(overlay, manifest=manifest)
321 overlay_tracking_branch[overlay] = remote_ref.ref
322 git_project_overlays.setdefault(remote_ref.project_name, []).append(overlay)
323
324 if options.command == 'push':
325 _WorkOnPush(options, overlay_tracking_branch, git_project_overlays)
326 elif options.command == 'commit':
327 _WorkOnCommit(options, overlays, overlay_tracking_branch,
328 git_project_overlays, manifest, package_list)
329
330
331def _WorkOnPush(options, overlay_tracking_branch, git_project_overlays):
332 """Push uprevs of overlays belonging to differet git projects in parallel.
333
334 Args:
335 options: The options object returned by the argument parser.
336 overlay_tracking_branch: A dict mapping from each overlay to its tracking
337 branch.
338 git_project_overlays: A dict mapping from each git repository to a list of
339 its overlays.
340 """
341 inputs = [[options, overlays_per_project, overlay_tracking_branch]
Mike Frysinger0bdbc102019-06-13 15:27:29 -0400342 for overlays_per_project in git_project_overlays.values()]
Ningning Xia419e4eb2018-02-05 10:30:36 -0800343 parallel.RunTasksInProcessPool(_PushOverlays, inputs)
344
345
346def _PushOverlays(options, overlays, overlay_tracking_branch):
347 """Push uprevs for overlays in sequence.
348
349 Args:
350 options: The options object returned by the argument parser.
351 overlays: A list of overlays to push uprevs in sequence.
352 overlay_tracking_branch: A dict mapping from each overlay to its tracking
353 branch.
354 """
355 for overlay in overlays:
356 if not os.path.isdir(overlay):
357 logging.warning('Skipping %s, which is not a directory.', overlay)
358 continue
359
360 tracking_branch = overlay_tracking_branch[overlay]
361 PushChange(constants.STABLE_EBUILD_BRANCH, tracking_branch, options.dryrun,
362 cwd=overlay, staging_branch=options.staging_branch)
363
364
365def _WorkOnCommit(options, overlays, overlay_tracking_branch,
366 git_project_overlays, manifest, package_list):
367 """Commit uprevs of overlays belonging to different git projects in parallel.
368
369 Args:
370 options: The options object returned by the argument parser.
371 overlays: A list of overlays to work on.
372 overlay_tracking_branch: A dict mapping from each overlay to its tracking
373 branch.
374 git_project_overlays: A dict mapping from each git repository to a list of
375 its overlays.
376 manifest: The manifest of the given source root.
377 package_list: A list of packages passed from commandline to work on.
378 """
Mike Frysinger62ff8d72020-05-19 03:06:51 -0400379 # We cleaned up self referential ebuilds by this version, but don't enforce
380 # the check on older ones to avoid breaking factory/firmware branches.
381 root_version = manifest_version.VersionInfo.from_repo(options.buildroot)
382 no_self_repos_version = manifest_version.VersionInfo('13099.0.0')
383 reject_self_repo = root_version >= no_self_repos_version
384
Ningning Xia419e4eb2018-02-05 10:30:36 -0800385 overlay_ebuilds = _GetOverlayToEbuildsMap(options, overlays, package_list)
David James84e953c2013-04-23 18:44:06 -0700386
Ningning Xia783efc02018-01-24 13:39:51 -0800387 with parallel.Manager() as manager:
388 # Contains the array of packages we actually revved.
389 revved_packages = manager.list()
390 new_package_atoms = manager.list()
David Jamesa8457b52011-05-28 00:03:20 -0700391
Ningning Xia419e4eb2018-02-05 10:30:36 -0800392 inputs = [[options, manifest, overlays_per_project, overlay_tracking_branch,
Mike Frysinger62ff8d72020-05-19 03:06:51 -0400393 overlay_ebuilds, revved_packages, new_package_atoms,
394 reject_self_repo]
Mike Frysinger0bdbc102019-06-13 15:27:29 -0400395 for overlays_per_project in git_project_overlays.values()]
Ningning Xia419e4eb2018-02-05 10:30:36 -0800396 parallel.RunTasksInProcessPool(_CommitOverlays, inputs)
Chris Sosadad0d322011-01-31 16:37:33 -0800397
Don Garrett4fef8c32018-08-10 18:04:01 -0700398 chroot_path = os.path.join(options.buildroot, constants.DEFAULT_CHROOT_DIR)
Ningning Xia419e4eb2018-02-05 10:30:36 -0800399 if os.path.exists(chroot_path):
Don Garrett4fef8c32018-08-10 18:04:01 -0700400 CleanStalePackages(options.buildroot, options.boards.split(':'),
Ningning Xia419e4eb2018-02-05 10:30:36 -0800401 new_package_atoms)
Mike Nicholsf7f13a82019-01-11 17:11:04 +0000402 if options.drop_file:
403 osutils.WriteFile(options.drop_file, ' '.join(revved_packages))
Chris Sosadad0d322011-01-31 16:37:33 -0800404
Brian Harring609dc4e2012-05-07 02:17:44 -0700405
Ningning Xia419e4eb2018-02-05 10:30:36 -0800406def _GetOverlayToEbuildsMap(options, overlays, package_list):
407 """Get ebuilds for overlays.
David James15ed1302013-04-25 09:21:19 -0700408
Ningning Xia783efc02018-01-24 13:39:51 -0800409 Args:
Ningning Xia783efc02018-01-24 13:39:51 -0800410 options: The options object returned by the argument parser.
Ningning Xia419e4eb2018-02-05 10:30:36 -0800411 overlays: A list of overlays to work on.
412 package_list: A list of packages passed from commandline to work on.
413
414 Returns:
415 A dict mapping each overlay to a list of ebuilds belonging to it.
416 """
Don Garrett3dbb2932018-10-02 14:41:26 -0700417 root_version = manifest_version.VersionInfo.from_repo(options.buildroot)
418 subdir_removal = manifest_version.VersionInfo('10363.0.0')
419 require_subdir_support = root_version < subdir_removal
420
Ningning Xia419e4eb2018-02-05 10:30:36 -0800421 overlay_ebuilds = {}
Don Garrett3dbb2932018-10-02 14:41:26 -0700422 inputs = [[overlay, options.all, package_list, options.force,
423 require_subdir_support]
Ningning Xia419e4eb2018-02-05 10:30:36 -0800424 for overlay in overlays]
425 result = parallel.RunTasksInProcessPool(
426 portage_util.GetOverlayEBuilds, inputs)
427 for idx, ebuilds in enumerate(result):
428 overlay_ebuilds[overlays[idx]] = ebuilds
429
430 return overlay_ebuilds
431
432
433def _CommitOverlays(options, manifest, overlays, overlay_tracking_branch,
Mike Frysinger62ff8d72020-05-19 03:06:51 -0400434 overlay_ebuilds, revved_packages, new_package_atoms,
435 reject_self_repo=True):
Ningning Xia419e4eb2018-02-05 10:30:36 -0800436 """Commit uprevs for overlays in sequence.
437
438 Args:
439 options: The options object returned by the argument parser.
440 manifest: The manifest of the given source root.
441 overlays: A list over overlays to commit.
442 overlay_tracking_branch: A dict mapping from each overlay to its tracking
443 branch.
444 overlay_ebuilds: A dict mapping overlays to their ebuilds.
Ningning Xia783efc02018-01-24 13:39:51 -0800445 revved_packages: A shared list of revved packages.
446 new_package_atoms: A shared list of new package atoms.
Mike Frysinger62ff8d72020-05-19 03:06:51 -0400447 reject_self_repo: Whether to abort if the ebuild lives in the same git
448 repo as it is tracking for uprevs.
Ningning Xia783efc02018-01-24 13:39:51 -0800449 """
Ningning Xia419e4eb2018-02-05 10:30:36 -0800450 for overlay in overlays:
451 if not os.path.isdir(overlay):
452 logging.warning('Skipping %s, which is not a directory.', overlay)
453 continue
Ningning Xia783efc02018-01-24 13:39:51 -0800454
Ningning Xia419e4eb2018-02-05 10:30:36 -0800455 # Note we intentionally work from the non push tracking branch;
456 # everything built thus far has been against it (meaning, http mirrors),
457 # thus we should honor that. During the actual push, the code switches
458 # to the correct urls, and does an appropriate rebasing.
459 tracking_branch = overlay_tracking_branch[overlay]
Ningning Xia783efc02018-01-24 13:39:51 -0800460
Ningning Xia783efc02018-01-24 13:39:51 -0800461 existing_commit = git.GetGitRepoRevision(overlay)
Lann Martine0ef98c2018-06-11 13:12:24 -0600462
463 # Make sure we run in the top-level git directory in case we are
464 # adding/removing an overlay in existing_commit.
465 git_root = git.FindGitTopLevel(overlay)
466 if git_root is None:
467 cros_build_lib.Die('No git repo at overlay directory %s.', overlay)
468
Ningning Xia783efc02018-01-24 13:39:51 -0800469 work_branch = GitBranch(constants.STABLE_EBUILD_BRANCH, tracking_branch,
Lann Martine0ef98c2018-06-11 13:12:24 -0600470 cwd=git_root)
Ningning Xia783efc02018-01-24 13:39:51 -0800471 work_branch.CreateBranch()
472 if not work_branch.Exists():
473 cros_build_lib.Die('Unable to create stabilizing branch in %s' %
474 overlay)
475
476 # In the case of uprevving overlays that have patches applied to them,
477 # include the patched changes in the stabilizing branch.
Lann Martine0ef98c2018-06-11 13:12:24 -0600478 git.RunGit(git_root, ['rebase', existing_commit])
Ningning Xia783efc02018-01-24 13:39:51 -0800479
Ningning Xiadb884322018-01-26 16:27:06 -0800480 ebuilds = overlay_ebuilds.get(overlay, [])
Ningning Xia783efc02018-01-24 13:39:51 -0800481 if ebuilds:
Ningning Xia419e4eb2018-02-05 10:30:36 -0800482 with parallel.Manager() as manager:
483 # Contains the array of packages we actually revved.
484 messages = manager.list()
485 ebuild_paths_to_add = manager.list()
486 ebuild_paths_to_remove = manager.list()
Ningning Xia783efc02018-01-24 13:39:51 -0800487
Ningning Xia419e4eb2018-02-05 10:30:36 -0800488 inputs = [[overlay, ebuild, manifest, options, ebuild_paths_to_add,
489 ebuild_paths_to_remove, messages, revved_packages,
Mike Frysinger62ff8d72020-05-19 03:06:51 -0400490 new_package_atoms, reject_self_repo]
491 for ebuild in ebuilds]
Ningning Xia419e4eb2018-02-05 10:30:36 -0800492 parallel.RunTasksInProcessPool(_WorkOnEbuild, inputs)
Ningning Xia783efc02018-01-24 13:39:51 -0800493
Ningning Xia419e4eb2018-02-05 10:30:36 -0800494 if ebuild_paths_to_add:
495 logging.info('Adding new stable ebuild paths %s in overlay %s.',
496 ebuild_paths_to_add, overlay)
497 git.RunGit(overlay, ['add'] + list(ebuild_paths_to_add))
David James15ed1302013-04-25 09:21:19 -0700498
Ningning Xia419e4eb2018-02-05 10:30:36 -0800499 if ebuild_paths_to_remove:
500 logging.info('Removing old ebuild paths %s in overlay %s.',
501 ebuild_paths_to_remove, overlay)
502 git.RunGit(overlay, ['rm', '-f'] + list(ebuild_paths_to_remove))
503
504 if messages:
505 portage_util.EBuild.CommitChange('\n\n'.join(messages), overlay)
David James15ed1302013-04-25 09:21:19 -0700506
Ningning Xia783efc02018-01-24 13:39:51 -0800507
508def _WorkOnEbuild(overlay, ebuild, manifest, options, ebuild_paths_to_add,
509 ebuild_paths_to_remove, messages, revved_packages,
Mike Frysinger62ff8d72020-05-19 03:06:51 -0400510 new_package_atoms, reject_self_repo=True):
Ningning Xia783efc02018-01-24 13:39:51 -0800511 """Work on a single ebuild.
512
513 Args:
514 overlay: The overlay where the ebuild belongs to.
515 ebuild: The ebuild to work on.
516 manifest: The manifest of the given source root.
517 options: The options object returned by the argument parser.
518 ebuild_paths_to_add: New stable ebuild paths to add to git.
519 ebuild_paths_to_remove: Old ebuild paths to remove from git.
520 messages: A share list of commit messages.
521 revved_packages: A shared list of revved packages.
522 new_package_atoms: A shared list of new package atoms.
Mike Frysinger62ff8d72020-05-19 03:06:51 -0400523 reject_self_repo: Whether to abort if the ebuild lives in the same git
524 repo as it is tracking for uprevs.
Ningning Xia783efc02018-01-24 13:39:51 -0800525 """
526 if options.verbose:
527 logging.info('Working on %s, info %s', ebuild.package,
528 ebuild.cros_workon_vars)
Mike Frysinger00ba05a2020-06-12 02:44:02 -0400529 if not ebuild.cros_workon_vars:
530 logging.warning('%s: unable to parse workon settings', ebuild.ebuild_path)
531
Ningning Xia783efc02018-01-24 13:39:51 -0800532 try:
Don Garrett4fef8c32018-08-10 18:04:01 -0700533 result = ebuild.RevWorkOnEBuild(os.path.join(options.buildroot, 'src'),
Mike Frysinger62ff8d72020-05-19 03:06:51 -0400534 manifest, reject_self_repo=reject_self_repo)
Ningning Xia783efc02018-01-24 13:39:51 -0800535 if result:
536 new_package, ebuild_path_to_add, ebuild_path_to_remove = result
537
538 if ebuild_path_to_add:
539 ebuild_paths_to_add.append(ebuild_path_to_add)
540 if ebuild_path_to_remove:
541 ebuild_paths_to_remove.append(ebuild_path_to_remove)
542
543 messages.append(_GIT_COMMIT_MESSAGE % ebuild.package)
Sam McNallyeb5e2052018-09-05 16:34:55 +1000544
545 if options.list_revisions:
546 info = ebuild.GetSourceInfo(os.path.join(options.buildroot, 'src'),
Mike Frysinger62ff8d72020-05-19 03:06:51 -0400547 manifest, reject_self_repo=reject_self_repo)
Sam McNallyeb5e2052018-09-05 16:34:55 +1000548 srcdirs = [os.path.join(options.buildroot, 'src', srcdir)
549 for srcdir in ebuild.cros_workon_vars.localname]
550 old_commit_ids = dict(
551 zip(srcdirs, ebuild.cros_workon_vars.commit.split(',')))
552 git_log = []
553 for srcdir in info.srcdirs:
554 old_commit_id = old_commit_ids.get(srcdir)
555 new_commit_id = ebuild.GetCommitId(srcdir)
556 if not old_commit_id or old_commit_id == new_commit_id:
557 continue
558
559 logs = git.RunGit(srcdir, [
560 'log', '%s..%s' % (old_commit_id[:8], new_commit_id[:8]),
561 '--pretty=format:%h %<(63,trunc)%s'])
562 git_log.append('$ ' + logs.cmdstr)
563 git_log.extend(line.strip() for line in logs.output.splitlines())
564 if git_log:
565 messages.append('\n'.join(git_log))
566
Ningning Xia783efc02018-01-24 13:39:51 -0800567 revved_packages.append(ebuild.package)
568 new_package_atoms.append('=%s' % new_package)
David Burger8cf4a762020-03-09 10:33:38 -0600569 except portage_util.InvalidUprevSourceError as e:
570 logging.error('An error occurred while uprevving %s: %s',
571 ebuild.package, e)
572 raise
Alex Klein99920662019-10-14 15:30:15 -0600573 except portage_util.EbuildVersionError as e:
574 logging.warning('Unable to rev %s: %s', ebuild.package, e)
575 raise
Mike Frysingerb32cc472020-05-15 00:17:54 -0400576 except OSError:
Ningning Xia783efc02018-01-24 13:39:51 -0800577 logging.warning(
578 'Cannot rev %s\n'
579 'Note you will have to go into %s '
Ningning Xia419e4eb2018-02-05 10:30:36 -0800580 'and reset the git repo yourself.', ebuild.package, overlay)
Ningning Xia783efc02018-01-24 13:39:51 -0800581 raise