Mercurial > hg
changeset 21177:952af771bc17 stable
bundle2: gracefully handle abort during unbundle
Clients expect a bundle2 reply to their bundle2 submission. So we
catch the Abort error and turn it into a bundle2 containing a part
transporting the exception data. The unbundling of this reply will
raise the error again.
author | Pierre-Yves David <pierre-yves.david@fb.com> |
---|---|
date | Mon, 21 Apr 2014 15:48:52 -0700 |
parents | 70fcb0a71445 |
children | 9a813e703172 |
files | mercurial/bundle2.py mercurial/wireproto.py tests/test-bundle2.t |
diffstat | 3 files changed, 95 insertions(+), 2 deletions(-) [+] |
line wrap: on
line diff
--- a/mercurial/bundle2.py Tue Apr 22 11:22:41 2014 -0700 +++ b/mercurial/bundle2.py Mon Apr 21 15:48:52 2014 -0700 @@ -743,3 +743,9 @@ if op.reply is None: op.reply = bundle20(op.ui, caps) +@parthandler('b2x:error:abort') +def handlereplycaps(op, inpart): + """Used to transmit abort error over the wire""" + manargs = dict(inpart.mandatoryparams) + advargs = dict(inpart.advisoryparams) + raise util.Abort(manargs['message'], hint=advargs.get('hint'))
--- a/mercurial/wireproto.py Tue Apr 22 11:22:41 2014 -0700 +++ b/mercurial/wireproto.py Mon Apr 21 15:48:52 2014 -0700 @@ -808,7 +808,17 @@ # We did not change it to minimise code change. # This need to be moved to something proper. # Feel free to do it. - sys.stderr.write("abort: %s\n" % inst) - return pushres(0) + if getattr(inst, 'duringunbundle2', False): + bundler = bundle2.bundle20(repo.ui) + manargs = [('message', str(inst))] + advargs = [] + if inst.hint is not None: + advargs.append(('hint', inst.hint)) + bundler.addpart(bundle2.bundlepart('B2X:ERROR:ABORT', + manargs, advargs)) + return streamres(bundler.getchunks()) + else: + sys.stderr.write("abort: %s\n" % inst) + return pushres(0) except exchange.PushRaced, exc: return pusherr(str(exc))
--- a/tests/test-bundle2.t Tue Apr 22 11:22:41 2014 -0700 +++ b/tests/test-bundle2.t Mon Apr 21 15:48:52 2014 -0700 @@ -883,3 +883,80 @@ date: Sat Apr 30 15:24:48 2011 +0200 summary: A + +Error Handling +============== + +Check that errors are properly returned to the client during push. + +Setting up + + $ cat > failpush.py << EOF + > """A small extension that makes push fails when using bundle2 + > + > used to test error handling in bundle2 + > """ + > + > from mercurial import util + > from mercurial import bundle2 + > from mercurial import exchange + > from mercurial import extensions + > + > def _pushbundle2failpart(orig, pushop, bundler): + > extradata = orig(pushop, bundler) + > part = bundle2.bundlepart('test:abort') + > bundler.addpart(part) + > return extradata + > + > @bundle2.parthandler("test:abort") + > def handleabort(op, part): + > raise util.Abort('Abandon ship!', hint="don't panic") + > + > def uisetup(ui): + > extensions.wrapfunction(exchange, '_pushbundle2extraparts', _pushbundle2failpart) + > + > EOF + + $ cd main + $ hg up tip + 3 files updated, 0 files merged, 1 files removed, 0 files unresolved + $ echo 'I' > I + $ hg add I + $ hg ci -m 'I' + $ hg id + e7ec4e813ba6 tip + $ cd .. + + $ cat << EOF >> $HGRCPATH + > [extensions] + > failpush=$TESTTMP/failpush.py + > EOF + + $ "$TESTDIR/killdaemons.py" $DAEMON_PIDS + $ hg -R other serve -p $HGPORT2 -d --pid-file=other.pid -E other-error.log + $ cat other.pid >> $DAEMON_PIDS + +Doing the actual push: Abort error + + $ hg -R main push other -r e7ec4e813ba6 + pushing to other + searching for changes + abort: Abandon ship! + (don't panic) + [255] + + $ hg -R main push ssh://user@dummy/other -r e7ec4e813ba6 + pushing to ssh://user@dummy/other + searching for changes + abort: Abandon ship! + (don't panic) + [255] + + $ hg -R main push http://localhost:$HGPORT2/ -r e7ec4e813ba6 + pushing to http://localhost:$HGPORT2/ + searching for changes + abort: Abandon ship! + (don't panic) + [255] + +