# HG changeset patch # User Gregory Szorc # Date 1502066696 25200 # Node ID fda0867cfe03ebf457c12b7e0ff1b174aeb67759 # Parent 970967e0a917d73ae76870c1533b8a32bdbf7285 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 diff -r 970967e0a917 -r fda0867cfe03 mercurial/exchange.py --- 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""" diff -r 970967e0a917 -r fda0867cfe03 mercurial/httppeer.py --- 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'] = '' diff -r 970967e0a917 -r fda0867cfe03 mercurial/localrepo.py --- 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) diff -r 970967e0a917 -r fda0867cfe03 mercurial/sshpeer.py --- 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