[PATCH 2 of 5] push: catch and process PushkeyFailed error
Pierre-Yves David
pierre-yves.david at ens-lyon.org
Mon Jun 8 12:29:16 CDT 2015
# HG changeset patch
# User Pierre-Yves David <pierre-yves.david at fb.com>
# Date 1433547011 25200
# Fri Jun 05 16:30:11 2015 -0700
# Node ID b715c2156629ecf7622bec3196ca8c35d7f173b4
# Parent 3dde3db78235e4aaa2e184e2dac73e9a8d27d74c
push: catch and process PushkeyFailed error
We add a way to register 'pushkey failure callback" that will be used if the
push is aborted by a pushkey failure. Part generator adding mandatory pushkey
parts should register a failure callback for all of them. The callback will be
in charge of generating a meaningful abort if this part fails.
If no callback is registered the error is propagated.
catch PushkeyFailed error in exchange
diff --git a/mercurial/exchange.py b/mercurial/exchange.py
--- a/mercurial/exchange.py
+++ b/mercurial/exchange.py
@@ -115,10 +115,13 @@ class pushoperation(object):
self.outobsmarkers = set()
# outgoing bookmarks
self.outbookmarks = []
# transaction manager
self.trmanager = None
+ # map { pushkey partid -> callback handling failure}
+ # used to handle exception from mandatory pushkey part failure
+ self.pkfailcb = {}
@util.propertycache
def futureheads(self):
"""future remote heads if the changeset push succeeds"""
return self.outgoing.missingheads
@@ -621,20 +624,26 @@ def _pushbundle2(pushop):
# do not push if nothing to push
if bundler.nbparts <= 1:
return
stream = util.chunkbuffer(bundler.getchunks())
try:
- reply = pushop.remote.unbundle(stream, ['force'], 'push')
- except error.BundleValueError, exc:
- raise util.Abort('missing support for %s' % exc)
- try:
- trgetter = None
- if pushback:
- trgetter = pushop.trmanager.transaction
- op = bundle2.processbundle(pushop.repo, reply, trgetter)
- except error.BundleValueError, exc:
- raise util.Abort('missing support for %s' % exc)
+ try:
+ reply = pushop.remote.unbundle(stream, ['force'], 'push')
+ except error.BundleValueError, exc:
+ raise util.Abort('missing support for %s' % exc)
+ try:
+ trgetter = None
+ if pushback:
+ trgetter = pushop.trmanager.transaction
+ op = bundle2.processbundle(pushop.repo, reply, trgetter)
+ except error.BundleValueError, exc:
+ raise util.Abort('missing support for %s' % exc)
+ except error.PushkeyFailed, exc:
+ partid = int(exc.partid)
+ if partid not in pushop.pkfailcb:
+ raise
+ pushop.pkfailcb[partid](pushop, exc)
for rephand in replyhandlers:
rephand(op)
def _pushchangeset(pushop):
"""Make the actual push of changeset bundle to remote repo"""
diff --git a/tests/test-bundle2-exchange.t b/tests/test-bundle2-exchange.t
--- a/tests/test-bundle2-exchange.t
+++ b/tests/test-bundle2-exchange.t
@@ -722,18 +722,22 @@ Check abort from mandatory pushkey
$ cat > mandatorypart.py << EOF
> from mercurial import exchange
> from mercurial import pushkey
> from mercurial import node
+ > from mercurial import error
> @exchange.b2partsgenerator('failingpuskey')
> def addfailingpushey(pushop, bundler):
> enc = pushkey.encode
> part = bundler.newpart('pushkey')
> part.addparam('namespace', enc('phases'))
> part.addparam('key', enc(pushop.repo['cd010b8cd998'].hex()))
> part.addparam('old', enc(str(0))) # successful update
> part.addparam('new', enc(str(0)))
+ > def fail(pushop, exc):
+ > raise error.Abort('Correct phase push failed (because hooks)')
+ > pushop.pkfailcb[part.id] = fail
> EOF
$ cat >> $HGRCPATH << EOF
> [hooks]
> pretxnchangegroup=
> pretxnclose.failpush=
@@ -757,11 +761,11 @@ Check abort from mandatory pushkey
do not push the key !
pushkey-abort: prepushkey.failpush hook exited with status 1
transaction abort!
Cleaning up the mess...
rollback completed
- abort: failed to update value for "phases/cd010b8cd998f3981a5a8115f94f8da4ab506089"
+ abort: Correct phase push failed (because hooks)
[255]
$ hg -R main push ssh://user@dummy/other -r e7ec4e813ba6
pushing to ssh://user@dummy/other
searching for changes
remote: adding changesets
@@ -794,18 +798,22 @@ Check abort from mandatory pushkey
$ cat > mandatorypart.py << EOF
> from mercurial import exchange
> from mercurial import pushkey
> from mercurial import node
+ > from mercurial import error
> @exchange.b2partsgenerator('failingpuskey')
> def addfailingpushey(pushop, bundler):
> enc = pushkey.encode
> part = bundler.newpart('pushkey')
> part.addparam('namespace', enc('phases'))
> part.addparam('key', enc(pushop.repo['cd010b8cd998'].hex()))
> part.addparam('old', enc(str(4))) # will fail
> part.addparam('new', enc(str(3)))
+ > def fail(pushop, exc):
+ > raise error.Abort('Clown phase push failed')
+ > pushop.pkfailcb[part.id] = fail
> EOF
$ cat >> $HGRCPATH << EOF
> [hooks]
> prepushkey.failpush =
> EOF
@@ -824,11 +832,11 @@ Check abort from mandatory pushkey
Cleaning up the mess...
rollback completed
pushkey: lock state after "phases"
lock: free
wlock: free
- abort: failed to update value for "phases/cd010b8cd998f3981a5a8115f94f8da4ab506089"
+ abort: Clown phase push failed
[255]
$ hg -R main push ssh://user@dummy/other -r e7ec4e813ba6
pushing to ssh://user@dummy/other
searching for changes
remote: adding changesets
More information about the Mercurial-devel
mailing list