@@ -143,11 +143,11 @@ preserve.
import util
import struct
import urllib
import string
-import changegroup
+import changegroup, error
from i18n import _
_pack = struct.pack
_unpack = struct.unpack
@@ -728,11 +728,11 @@ def handlechangegroup(op, inpart):
while len(h) == 20:
heads.append(h)
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):
"""forward output captured on the server to the client"""
for line in inpart.read().splitlines():
@@ -92,5 +92,9 @@ class AmbiguousCommand(Exception):
class SignalInterrupt(KeyboardInterrupt):
"""Exception raised on SIGTERM and SIGHUP."""
class SignatureError(Exception):
pass
+
+class PushRaced(RuntimeError):
+ """An exception raised during unbundling that indicate a push race"""
+
@@ -6,11 +6,11 @@
# GNU General Public License version 2 or any later version.
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):
header = changegroup.readexactly(fh, 4)
@@ -706,13 +706,10 @@ def getbundle(repo, source, heads=None,
def _getbundleextrapart(bundler, repo, source, heads=None, common=None,
bundlecaps=None, **kwargs):
"""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
Used by peer for unbundling.
"""
@@ -720,12 +717,12 @@ def check_heads(repo, their_heads, conte
heads_hash = util.sha1(''.join(sorted(heads))).digest()
if not (their_heads == ['force'] or their_heads == heads or
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.
this function makes sure the repo is locked during the application and have
@@ -131,11 +131,11 @@ class localpeer(peer.peerrepository):
# This little dance should be dropped eventually when the API
# is finally improved.
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):
return self._repo.lock()
@@ -824,7 +824,7 @@ def unbundle(repo, proto, heads):
manargs, advargs))
return streamres(bundler.getchunks())
else:
sys.stderr.write("abort: %s\n" % inst)
return pushres(0)
- except exchange.PushRaced, exc:
+ except error.PushRaced, exc:
return pusherr(str(exc))
@@ -13,10 +13,11 @@ Create an extension to test bundle2 API
> from mercurial import util
> from mercurial import bundle2
> from mercurial import scmutil
> from mercurial import discovery
> from mercurial import changegroup
+ > from mercurial import error
> cmdtable = {}
> command = cmdutil.command(cmdtable)
>
> ELEPHANTSSONG = """Patali Dirapata, Cromda Cromda Ripalo, Pata Pata, Ko Ko Ko
> Bokoro Dipoulito, Rondi Rondi Pepino, Pata Pata, Ko Ko Ko
@@ -57,10 +58,11 @@ Create an extension to test bundle2 API
> @command('bundle2',
> [('', 'param', [], 'stream level parameter'),
> ('', '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):
> """write a bundle2 container on standard ouput"""
> bundler = bundle2.bundle20(ui)
@@ -73,10 +75,14 @@ Create an extension to test bundle2 API
>
> if opts['reply']:
> 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'])
> if revs:
> # very crude version of a changegroup part creation
@@ -130,10 +136,12 @@ Create an extension to test bundle2 API
> unbundler = bundle2.unbundle20(ui, sys.stdin)
> op = bundle2.processbundle(repo, unbundler, lambda: tr)
> 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()
> lock.release()
> remains = sys.stdin.read()
@@ -599,10 +607,19 @@ Unbundle the reply to get the output:
remote: debugreply: 'ping-pong'
remote: received ping request (id 6)
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
===================================
$ hg unbundle $TESTDIR/bundles/rebase.hg
adding changesets