[PATCH 2 of 2] bundle2: abort when a mandatory pushkey part fails
Augie Fackler
raf at durin42.com
Mon Jun 8 09:35:44 CDT 2015
On Sat, Jun 06, 2015 at 01:57:21PM -0700, Pierre-Yves David wrote:
> # HG changeset patch
> # User Pierre-Yves David <pierre-yves.david at fb.com>
> # Date 1432729720 25200
> # Wed May 27 05:28:40 2015 -0700
> # Node ID 40c4968954f175698a21ddb11aaa3db4c72c3887
> # Parent 1965f29f800fc0761ae9053165d9c2c75943d21f
> bundle2: abort when a mandatory pushkey part fails
queued, thanks!
>
> So far result of a pushkey operation had no consequence on the transaction
> (beside the change). We makes it respect the 'mandatory' flag of part so that
> failed pushkey call abort the whole transaction. This will allow rejecting
> changes (primary target: changesets) regarding phases or bookmark criteria in
> the future (when we will push such data in a mandatory part).
>
> We currently raise an abort error because all clients supports it. We'll
> introduce a more precise error in the next changesets.
>
> diff --git a/mercurial/bundle2.py b/mercurial/bundle2.py
> --- a/mercurial/bundle2.py
> +++ b/mercurial/bundle2.py
> @@ -1327,10 +1327,13 @@ def handlepushkey(op, inpart):
> op.records.add('pushkey', record)
> if op.reply is not None:
> rpart = op.reply.newpart('reply:pushkey')
> rpart.addparam('in-reply-to', str(inpart.id), mandatory=False)
> rpart.addparam('return', '%i' % ret, mandatory=False)
> + if inpart.mandatory and not ret:
> + raise util.Abort(_('failed to update value for "%s/%s"')
> + % (namespace, key))
>
> @parthandler('reply:pushkey', ('return', 'in-reply-to'))
> def handlepushkeyreply(op, inpart):
> """retrieve the result of a pushkey request"""
> ret = int(inpart.params['return'])
> 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
> @@ -715,5 +715,147 @@ Check output capture control.
> remote: transaction abort!
> remote: Cleaning up the mess...
> remote: rollback completed
> abort: pretxnchangegroup hook exited with status 1
> [255]
> +
> +Check abort from mandatory pushkey
> +
> + $ cat > mandatorypart.py << EOF
> + > from mercurial import exchange
> + > from mercurial import pushkey
> + > from mercurial import node
> + > @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)))
> + > EOF
> + $ cat >> $HGRCPATH << EOF
> + > [hooks]
> + > pretxnchangegroup=
> + > pretxnclose.failpush=
> + > prepushkey.failpush = sh -c "echo 'do not push the key !'; false"
> + > [extensions]
> + > mandatorypart=$TESTTMP/mandatorypart.py
> + > EOF
> + $ "$TESTDIR/killdaemons.py" $DAEMON_PIDS # reload http config
> + $ hg -R other serve -p $HGPORT2 -d --pid-file=other.pid -E other-error.log
> + $ cat other.pid >> $DAEMON_PIDS
> +
> +(Failure from a hook)
> +
> + $ hg -R main push other -r e7ec4e813ba6
> + pushing to other
> + searching for changes
> + adding changesets
> + adding manifests
> + adding file changes
> + added 1 changesets with 1 changes to 1 files
> + 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"
> + [255]
> + $ hg -R main push ssh://user@dummy/other -r e7ec4e813ba6
> + pushing to ssh://user@dummy/other
> + searching for changes
> + remote: adding changesets
> + remote: adding manifests
> + remote: adding file changes
> + remote: added 1 changesets with 1 changes to 1 files
> + remote: do not push the key !
> + remote: pushkey-abort: prepushkey.failpush hook exited with status 1
> + remote: transaction abort!
> + remote: Cleaning up the mess...
> + remote: rollback completed
> + abort: failed to update value for "phases/cd010b8cd998f3981a5a8115f94f8da4ab506089"
> + [255]
> + $ hg -R main push http://localhost:$HGPORT2/ -r e7ec4e813ba6
> + pushing to http://localhost:$HGPORT2/
> + searching for changes
> + remote: adding changesets
> + remote: adding manifests
> + remote: adding file changes
> + remote: added 1 changesets with 1 changes to 1 files
> + remote: do not push the key !
> + remote: pushkey-abort: prepushkey.failpush hook exited with status 1
> + remote: transaction abort!
> + remote: Cleaning up the mess...
> + remote: rollback completed
> + abort: failed to update value for "phases/cd010b8cd998f3981a5a8115f94f8da4ab506089"
> + [255]
> +
> +(Failure from a the pushkey)
> +
> + $ cat > mandatorypart.py << EOF
> + > from mercurial import exchange
> + > from mercurial import pushkey
> + > from mercurial import node
> + > @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)))
> + > EOF
> + $ cat >> $HGRCPATH << EOF
> + > [hooks]
> + > prepushkey.failpush =
> + > EOF
> + $ "$TESTDIR/killdaemons.py" $DAEMON_PIDS # reload http config
> + $ hg -R other serve -p $HGPORT2 -d --pid-file=other.pid -E other-error.log
> + $ cat other.pid >> $DAEMON_PIDS
> +
> + $ hg -R main push other -r e7ec4e813ba6
> + pushing to other
> + searching for changes
> + adding changesets
> + adding manifests
> + adding file changes
> + added 1 changesets with 1 changes to 1 files
> + transaction abort!
> + Cleaning up the mess...
> + rollback completed
> + pushkey: lock state after "phases"
> + lock: free
> + wlock: free
> + abort: failed to update value for "phases/cd010b8cd998f3981a5a8115f94f8da4ab506089"
> + [255]
> + $ hg -R main push ssh://user@dummy/other -r e7ec4e813ba6
> + pushing to ssh://user@dummy/other
> + searching for changes
> + remote: adding changesets
> + remote: adding manifests
> + remote: adding file changes
> + remote: added 1 changesets with 1 changes to 1 files
> + remote: transaction abort!
> + remote: Cleaning up the mess...
> + remote: rollback completed
> + remote: pushkey: lock state after "phases"
> + remote: lock: free
> + remote: wlock: free
> + abort: failed to update value for "phases/cd010b8cd998f3981a5a8115f94f8da4ab506089"
> + [255]
> + $ hg -R main push http://localhost:$HGPORT2/ -r e7ec4e813ba6
> + pushing to http://localhost:$HGPORT2/
> + searching for changes
> + remote: adding changesets
> + remote: adding manifests
> + remote: adding file changes
> + remote: added 1 changesets with 1 changes to 1 files
> + remote: transaction abort!
> + remote: Cleaning up the mess...
> + remote: rollback completed
> + remote: pushkey: lock state after "phases"
> + remote: lock: free
> + remote: wlock: free
> + abort: failed to update value for "phases/cd010b8cd998f3981a5a8115f94f8da4ab506089"
> + [255]
> +
> _______________________________________________
> Mercurial-devel mailing list
> Mercurial-devel at selenic.com
> https://selenic.com/mailman/listinfo/mercurial-devel
More information about the Mercurial-devel
mailing list