# HG changeset patch # User Pierre-Yves David # Date 1398131949 25200 # Node ID 28d76afa15681d7c43e57cffca64430fefb32cd8 # Parent 4345274adc4b17c129ab1eeba427bba03b1dab29 bundle2: fix raising errors during heads checking If the heads on the server differ from the ones reported seen by the client at bundle time, we raise a PushRaced exception. However, the part raising the exception was broken. To fix it, we move the PushRaced class in the error module so it can be accessible everywhere without an import cycle. A test is also added to prevent regression. diff -r 4345274adc4b -r 28d76afa1568 mercurial/bundle2.py --- a/mercurial/bundle2.py Mon Apr 21 16:02:03 2014 -0700 +++ b/mercurial/bundle2.py Mon Apr 21 18:59:09 2014 -0700 @@ -145,7 +145,7 @@ import urllib import string -import changegroup +import changegroup, error from i18n import _ _pack = struct.pack @@ -730,7 +730,7 @@ h = inpart.read(20) assert not h if heads != op.repo.heads(): - raise exchange.PushRaced() + raise error.PushRaced() @parthandler('b2x:output') def handleoutput(op, inpart): diff -r 4345274adc4b -r 28d76afa1568 mercurial/error.py --- a/mercurial/error.py Mon Apr 21 16:02:03 2014 -0700 +++ b/mercurial/error.py Mon Apr 21 18:59:09 2014 -0700 @@ -94,3 +94,7 @@ class SignatureError(Exception): pass + +class PushRaced(RuntimeError): + """An exception raised during unbundling that indicate a push race""" + diff -r 4345274adc4b -r 28d76afa1568 mercurial/exchange.py --- a/mercurial/exchange.py Mon Apr 21 16:02:03 2014 -0700 +++ b/mercurial/exchange.py Mon Apr 21 18:59:09 2014 -0700 @@ -8,7 +8,7 @@ from i18n import _ from node import hex, nullid import errno, urllib -import util, scmutil, changegroup, base85 +import util, scmutil, changegroup, base85, error import discovery, phases, obsolete, bookmarks, bundle2 def readbundle(ui, fh, fname, vfs=None): @@ -708,9 +708,6 @@ """hook function to let extensions add parts to the requested bundle""" pass -class PushRaced(RuntimeError): - """An exception raised during unbundling that indicate a push race""" - def check_heads(repo, their_heads, context): """check if the heads of a repo have been modified @@ -722,8 +719,8 @@ their_heads == ['hashed', heads_hash]): # someone else committed/pushed/unbundled while we # were transferring data - raise PushRaced('repository changed while %s - ' - 'please try again' % context) + raise error.PushRaced('repository changed while %s - ' + 'please try again' % context) def unbundle(repo, cg, heads, source, url): """Apply a bundle to a repo. diff -r 4345274adc4b -r 28d76afa1568 mercurial/localrepo.py --- a/mercurial/localrepo.py Mon Apr 21 16:02:03 2014 -0700 +++ b/mercurial/localrepo.py Mon Apr 21 18:59:09 2014 -0700 @@ -133,7 +133,7 @@ stream = util.chunkbuffer(ret.getchunks()) ret = bundle2.unbundle20(self.ui, stream) return ret - except exchange.PushRaced, exc: + except error.PushRaced, exc: raise error.ResponseError(_('push failed:'), exc.message) def lock(self): diff -r 4345274adc4b -r 28d76afa1568 mercurial/wireproto.py --- a/mercurial/wireproto.py Mon Apr 21 16:02:03 2014 -0700 +++ b/mercurial/wireproto.py Mon Apr 21 18:59:09 2014 -0700 @@ -826,5 +826,5 @@ else: sys.stderr.write("abort: %s\n" % inst) return pushres(0) - except exchange.PushRaced, exc: + except error.PushRaced, exc: return pusherr(str(exc)) diff -r 4345274adc4b -r 28d76afa1568 tests/test-bundle2.t --- a/tests/test-bundle2.t Mon Apr 21 16:02:03 2014 -0700 +++ b/tests/test-bundle2.t Mon Apr 21 18:59:09 2014 -0700 @@ -15,6 +15,7 @@ > from mercurial import scmutil > from mercurial import discovery > from mercurial import changegroup + > from mercurial import error > cmdtable = {} > command = cmdutil.command(cmdtable) > @@ -59,6 +60,7 @@ > ('', 'unknown', False, 'include an unknown mandatory part in the bundle'), > ('', 'parts', False, 'include some arbitrary parts to the bundle'), > ('', 'reply', False, 'produce a reply bundle'), + > ('', 'pushrace', False, 'includes a check:head part with unknown nodes'), > ('r', 'rev', [], 'includes those changeset in the bundle'),], > '[OUTPUTFILE]') > def cmdbundle2(ui, repo, path=None, **opts): @@ -75,6 +77,10 @@ > capsstring = 'ping-pong\nelephants=babar,celeste\ncity%3D%21=celeste%2Cville' > bundler.addpart(bundle2.bundlepart('b2x:replycaps', data=capsstring)) > + > if opts['pushrace']: + > dummynode = '01234567890123456789' + > bundler.addpart(bundle2.bundlepart('b2x:check:heads', data=dummynode)) + > > revs = opts['rev'] > if 'rev' in opts: > revs = scmutil.revrange(repo, opts['rev']) @@ -132,6 +138,8 @@ > tr.close() > except KeyError, exc: > raise util.Abort('missing support for %s' % exc) + > except error.PushRaced, exc: + > raise util.Abort('push race') > finally: > if tr is not None: > tr.release() @@ -601,6 +609,15 @@ remote: replying to ping request (id 6) 0 unread bytes +Test push race detection + + $ hg bundle2 --pushrace ../part-race.hg2 + + $ hg unbundle2 < ../part-race.hg2 + 0 unread bytes + abort: push race + [255] + Support for changegroup ===================================