exchange: drop support for lock-based unbundling (BC)
Locking over the wire protocol and the "addchangegroup" wire
protocol command has been deprecated since
e8c4f3d3df8c, which was
first part of Mercurial 0.9.1.
Support for handling these commands from sshserver was dropped in
9f6e0e7ef828 in 2015, effectively locking out pre 0.9.1 clients
from new servers.
However, client-side code for calling lock and addchangegroup is
still present in exchange.py and the various peer classes to
facilitate pushing to pre 0.9.1 servers.
The lock-based pushing mechanism is extremely brittle. 0.9.1 was
released in July 2006 and I highly doubt anyone is still running
such an ancient version of Mercurial on a server. I'm about to
refactor the peer API and I don't think it is worth keeping
support for this ancient protocol feature. So, this commit removes
client support for the lock-based pushing mechanism. This means
modern clients will no longer be able to push to pre 0.9.1 servers.
Differential Revision: https://phab.mercurial-scm.org/D264
--- a/mercurial/exchange.py Fri Aug 04 15:49:36 2017 -0400
+++ b/mercurial/exchange.py Sun Aug 06 17:44:56 2017 -0700
@@ -433,16 +433,13 @@
" %s") % (', '.join(sorted(missing)))
raise error.Abort(msg)
- # there are two ways to push to remote repo:
- #
- # addchangegroup assumes local user can lock remote
- # repo (local filesystem, old ssh servers).
- #
- # unbundle assumes local user cannot lock remote repo (new ssh
- # servers, http servers).
-
if not pushop.remote.canpush():
raise error.Abort(_("destination does not support push"))
+
+ if not pushop.remote.capable('unbundle'):
+ raise error.Abort(_('cannot push: destination does not support the '
+ 'unbundle wire protocol command'))
+
# get local lock as we might write phase data
localwlock = locallock = None
try:
@@ -468,21 +465,14 @@
'push-response',
pushop.remote.url())
pushop.repo.checkpush(pushop)
- lock = None
- unbundle = pushop.remote.capable('unbundle')
- if not unbundle:
- lock = pushop.remote.lock()
- try:
- _pushdiscovery(pushop)
- if not _forcebundle1(pushop):
- _pushbundle2(pushop)
- _pushchangeset(pushop)
- _pushsyncphase(pushop)
- _pushobsolete(pushop)
- _pushbookmark(pushop)
- finally:
- if lock is not None:
- lock.release()
+ _pushdiscovery(pushop)
+ if not _forcebundle1(pushop):
+ _pushbundle2(pushop)
+ _pushchangeset(pushop)
+ _pushsyncphase(pushop)
+ _pushobsolete(pushop)
+ _pushbookmark(pushop)
+
if pushop.trmanager:
pushop.trmanager.close()
finally:
@@ -958,9 +948,12 @@
pushop.stepsdone.add('changesets')
if not _pushcheckoutgoing(pushop):
return
+
+ # Should have verified this in push().
+ assert pushop.remote.capable('unbundle')
+
pushop.repo.prepushoutgoinghooks(pushop)
outgoing = pushop.outgoing
- unbundle = pushop.remote.capable('unbundle')
# TODO: get bundlecaps from remote
bundlecaps = None
# create a changegroup from local
@@ -979,24 +972,18 @@
bundlecaps=bundlecaps)
# apply changegroup to remote
- if unbundle:
- # local repo finds heads on server, finds out what
- # revs it must push. once revs transferred, if server
- # finds it has different heads (someone else won
- # commit/push race), server aborts.
- if pushop.force:
- remoteheads = ['force']
- else:
- remoteheads = pushop.remoteheads
- # ssh: return remote's addchangegroup()
- # http: return remote's addchangegroup() or 0 for error
- pushop.cgresult = pushop.remote.unbundle(cg, remoteheads,
- pushop.repo.url())
+ # local repo finds heads on server, finds out what
+ # revs it must push. once revs transferred, if server
+ # finds it has different heads (someone else won
+ # commit/push race), server aborts.
+ if pushop.force:
+ remoteheads = ['force']
else:
- # we return an integer indicating remote head count
- # change
- pushop.cgresult = pushop.remote.addchangegroup(cg, 'push',
- pushop.repo.url())
+ remoteheads = pushop.remoteheads
+ # ssh: return remote's addchangegroup()
+ # http: return remote's addchangegroup() or 0 for error
+ pushop.cgresult = pushop.remote.unbundle(cg, remoteheads,
+ pushop.repo.url())
def _pushsyncphase(pushop):
"""synchronise phase information locally and remotely"""
--- a/mercurial/httppeer.py Fri Aug 04 15:49:36 2017 -0400
+++ b/mercurial/httppeer.py Sun Aug 06 17:44:56 2017 -0700
@@ -132,9 +132,6 @@
(' '.join(self.caps or ['none'])))
return self.caps
- def lock(self):
- raise error.Abort(_('operation not supported over http'))
-
def _callstream(self, cmd, _compressible=False, **args):
if cmd == 'pushkey':
args['data'] = ''
--- a/mercurial/localrepo.py Fri Aug 04 15:49:36 2017 -0400
+++ b/mercurial/localrepo.py Sun Aug 06 17:44:56 2017 -0700
@@ -237,9 +237,6 @@
except error.PushRaced as exc:
raise error.ResponseError(_('push failed:'), str(exc))
- def lock(self):
- return self._repo.lock()
-
def pushkey(self, namespace, key, old, new):
return self._repo.pushkey(namespace, key, old, new)
--- a/mercurial/sshpeer.py Fri Aug 04 15:49:36 2017 -0400
+++ b/mercurial/sshpeer.py Sun Aug 06 17:44:56 2017 -0700
@@ -17,21 +17,6 @@
wireproto,
)
-class remotelock(object):
- def __init__(self, repo):
- self.repo = repo
- def release(self):
- self.repo.unlock()
- self.repo = None
- def __enter__(self):
- return self
- def __exit__(self, exc_type, exc_val, exc_tb):
- if self.repo:
- self.release()
- def __del__(self):
- if self.repo:
- self.release()
-
def _serverquote(s):
if not s:
return s
@@ -337,33 +322,4 @@
self.pipeo.flush()
self.readerr()
- def lock(self):
- self._call("lock")
- return remotelock(self)
-
- def unlock(self):
- self._call("unlock")
-
- def addchangegroup(self, cg, source, url, lock=None):
- '''Send a changegroup to the remote server. Return an integer
- similar to unbundle(). DEPRECATED, since it requires locking the
- remote.'''
- d = self._call("addchangegroup")
- if d:
- self._abort(error.RepoError(_("push refused: %s") % d))
- for d in iter(lambda: cg.read(4096), ''):
- self.pipeo.write(d)
- self.readerr()
-
- self.pipeo.flush()
-
- self.readerr()
- r = self._recv()
- if not r:
- return 1
- try:
- return int(r)
- except ValueError:
- self._abort(error.ResponseError(_("unexpected response:"), r))
-
instance = sshpeer