rebase: scope parent change into a changing_parents context
If we are actually altering the working copy (i.e. we are not in memory), we
should properly scope the working copy update.
# Copyright 2017 Facebook, Inc.
#
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
from mercurial.i18n import _
from mercurial.node import hex
from mercurial import (
bundle2,
changegroup,
error,
extensions,
revsetlang,
util,
)
from . import common
isremotebooksenabled = common.isremotebooksenabled
scratchbranchparttype = b'b2x:infinitepush'
def getscratchbranchparts(repo, peer, outgoing, ui, bookmark):
if not outgoing.missing:
raise error.Abort(_(b'no commits to push'))
if scratchbranchparttype not in bundle2.bundle2caps(peer):
raise error.Abort(
_(b'no server support for %r') % scratchbranchparttype
)
_validaterevset(
repo, revsetlang.formatspec(b'%ln', outgoing.missing), bookmark
)
supportedversions = changegroup.supportedoutgoingversions(repo)
# Explicitly avoid using '01' changegroup version in infinitepush to
# support general delta
supportedversions.discard(b'01')
cgversion = min(supportedversions)
_handlelfs(repo, outgoing.missing)
cg = changegroup.makestream(repo, outgoing, cgversion, b'push')
params = {}
params[b'cgversion'] = cgversion
if bookmark:
params[b'bookmark'] = bookmark
# 'prevbooknode' is necessary for pushkey reply part
params[b'bookprevnode'] = b''
bookmarks = repo._bookmarks
if bookmark in bookmarks:
params[b'bookprevnode'] = hex(bookmarks[bookmark])
# Do not send pushback bundle2 part with bookmarks if remotenames extension
# is enabled. It will be handled manually in `_push()`
if not isremotebooksenabled(ui):
params[b'pushbackbookmarks'] = b'1'
parts = []
# .upper() marks this as a mandatory part: server will abort if there's no
# handler
parts.append(
bundle2.bundlepart(
scratchbranchparttype.upper(),
advisoryparams=params.items(),
data=cg,
)
)
return parts
def _validaterevset(repo, revset, bookmark):
"""Abort if the revs to be pushed aren't valid for a scratch branch."""
if not repo.revs(revset):
raise error.Abort(_(b'nothing to push'))
if bookmark:
# Allow bundle with many heads only if no bookmark is specified
heads = repo.revs(b'heads(%r)', revset)
if len(heads) > 1:
raise error.Abort(
_(b'cannot push more than one head to a scratch branch')
)
def _handlelfs(repo, missing):
"""Special case if lfs is enabled
If lfs is enabled then we need to call prepush hook
to make sure large files are uploaded to lfs
"""
try:
lfsmod = extensions.find(b'lfs')
lfsmod.wrapper.uploadblobsfromrevs(repo, missing)
except KeyError:
# Ignore if lfs extension is not enabled
return
class copiedpart:
"""a copy of unbundlepart content that can be consumed later"""
def __init__(self, part):
# copy "public properties"
self.type = part.type
self.id = part.id
self.mandatory = part.mandatory
self.mandatoryparams = part.mandatoryparams
self.advisoryparams = part.advisoryparams
self.params = part.params
self.mandatorykeys = part.mandatorykeys
# copy the buffer
self._io = util.stringio(part.read())
def consume(self):
return
def read(self, size=None):
if size is None:
return self._io.read()
else:
return self._io.read(size)