bundleparts.py
126 lines
| 3.6 KiB
| text/x-python
|
PythonLexer
|
r37204 | # 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 _ | ||||
|
r46729 | from mercurial.node import hex | ||
|
r37204 | |||
from mercurial import ( | ||||
bundle2, | ||||
changegroup, | ||||
error, | ||||
extensions, | ||||
revsetlang, | ||||
util, | ||||
) | ||||
from . import common | ||||
isremotebooksenabled = common.isremotebooksenabled | ||||
|
r43347 | scratchbranchparttype = b'b2x:infinitepush' | ||
|
r37204 | |||
|
r43346 | |||
|
r37220 | def getscratchbranchparts(repo, peer, outgoing, ui, bookmark): | ||
|
r37204 | if not outgoing.missing: | ||
|
r43347 | raise error.Abort(_(b'no commits to push')) | ||
|
r37204 | |||
if scratchbranchparttype not in bundle2.bundle2caps(peer): | ||||
|
r43347 | raise error.Abort( | ||
_(b'no server support for %r') % scratchbranchparttype | ||||
) | ||||
|
r37204 | |||
|
r43346 | _validaterevset( | ||
|
r43347 | repo, revsetlang.formatspec(b'%ln', outgoing.missing), bookmark | ||
|
r43346 | ) | ||
|
r37204 | |||
supportedversions = changegroup.supportedoutgoingversions(repo) | ||||
# Explicitly avoid using '01' changegroup version in infinitepush to | ||||
# support general delta | ||||
|
r43347 | supportedversions.discard(b'01') | ||
|
r37204 | cgversion = min(supportedversions) | ||
_handlelfs(repo, outgoing.missing) | ||||
|
r43347 | cg = changegroup.makestream(repo, outgoing, cgversion, b'push') | ||
|
r37204 | |||
params = {} | ||||
|
r43347 | params[b'cgversion'] = cgversion | ||
|
r37204 | if bookmark: | ||
|
r43347 | params[b'bookmark'] = bookmark | ||
|
r37204 | # 'prevbooknode' is necessary for pushkey reply part | ||
|
r43347 | params[b'bookprevnode'] = b'' | ||
|
r37471 | bookmarks = repo._bookmarks | ||
if bookmark in bookmarks: | ||||
|
r46729 | params[b'bookprevnode'] = hex(bookmarks[bookmark]) | ||
|
r37204 | |||
# Do not send pushback bundle2 part with bookmarks if remotenames extension | ||||
# is enabled. It will be handled manually in `_push()` | ||||
if not isremotebooksenabled(ui): | ||||
|
r43347 | params[b'pushbackbookmarks'] = b'1' | ||
|
r37204 | |||
parts = [] | ||||
# .upper() marks this as a mandatory part: server will abort if there's no | ||||
# handler | ||||
|
r43346 | parts.append( | ||
bundle2.bundlepart( | ||||
scratchbranchparttype.upper(), | ||||
|
r49768 | advisoryparams=params.items(), | ||
|
r43346 | data=cg, | ||
) | ||||
) | ||||
|
r37204 | |||
return parts | ||||
|
r43346 | |||
|
r37204 | def _validaterevset(repo, revset, bookmark): | ||
"""Abort if the revs to be pushed aren't valid for a scratch branch.""" | ||||
if not repo.revs(revset): | ||||
|
r43347 | raise error.Abort(_(b'nothing to push')) | ||
|
r37204 | if bookmark: | ||
# Allow bundle with many heads only if no bookmark is specified | ||||
|
r43347 | heads = repo.revs(b'heads(%r)', revset) | ||
|
r37204 | if len(heads) > 1: | ||
raise error.Abort( | ||||
|
r43347 | _(b'cannot push more than one head to a scratch branch') | ||
|
r43346 | ) | ||
|
r37204 | |||
def _handlelfs(repo, missing): | ||||
|
r46554 | """Special case if lfs is enabled | ||
|
r37204 | |||
If lfs is enabled then we need to call prepush hook | ||||
to make sure large files are uploaded to lfs | ||||
|
r46554 | """ | ||
|
r37204 | try: | ||
|
r43347 | lfsmod = extensions.find(b'lfs') | ||
|
r37204 | lfsmod.wrapper.uploadblobsfromrevs(repo, missing) | ||
except KeyError: | ||||
# Ignore if lfs extension is not enabled | ||||
return | ||||
|
r43346 | |||
|
r49801 | class copiedpart: | ||
|
r37204 | """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) | ||||