Patchwork [7,of,7,stable] wireproto: properly report server Abort during 'getbundle'

login
register
mail settings
Submitter Pierre-Yves David
Date Feb. 10, 2017, 5:53 p.m.
Message ID <1631cecbc20e794f36d9.1486749188@nodosa.octopoid.net>
Download mbox | patch
Permalink /patch/18404/
State Accepted
Delegated to: Martin von Zweigbergk
Headers show

Comments

Pierre-Yves David - Feb. 10, 2017, 5:53 p.m.
# HG changeset patch
# User Pierre-Yves David <pierre-yves.david@ens-lyon.org>
# Date 1486747258 -3600
#      Fri Feb 10 18:20:58 2017 +0100
# Branch stable
# Node ID 1631cecbc20e794f36d93e5bb9fe96622781e8d4
# Parent  3b13a645b703c0eab4eb6cf73a19a1886fb6eab8
# EXP-Topic getbundleerror
wireproto: properly report server Abort during 'getbundle'

Previously Abort raised during 'getbundle' call poorly reported (HTTP-500 for
http, some scary messages for ssh). Abort error have been properly reported for
"push" for a long time, there is not reason to be different for 'getbundle'. We
properly catch such error and report them back the best way available. For
bundle, we issue a valid bundle2 reply (as expected by the client) with an
'error:abort' part. With bundle1 we do as best as we can depending of http or
ssh.

Patch

diff -r 3b13a645b703 -r 1631cecbc20e mercurial/wireproto.py
--- a/mercurial/wireproto.py	Fri Feb 10 18:17:20 2017 +0100
+++ b/mercurial/wireproto.py	Fri Feb 10 18:20:58 2017 +0100
@@ -839,7 +839,24 @@ 
             raise error.Abort(bundle2requiredmain,
                               hint=bundle2requiredhint)
 
-    chunks = exchange.getbundlechunks(repo, 'serve', **opts)
+    #chunks = exchange.getbundlechunks(repo, 'serve', **opts)
+    try:
+        chunks = exchange.getbundlechunks(repo, 'serve', **opts)
+    except error.Abort as exc:
+        # cleanly forward Abort error to the client
+        if not exchange.bundle2requested(opts.get('bundlecaps')):
+            if proto.name == 'http':
+                return ooberror(str(exc) + '\n')
+            raise # cannot do better for bundle1 + ssh
+        # bundle2 request expect a bundle2 reply
+        bundler = bundle2.bundle20(repo.ui)
+        manargs = [('message', str(exc))]
+        advargs = []
+        if exc.hint is not None:
+            advargs.append(('hint', exc.hint))
+        bundler.addpart(bundle2.bundlepart('error:abort',
+                                           manargs, advargs))
+        return streamres(gen=bundler.getchunks(), v1compressible=True)
     return streamres(gen=chunks, v1compressible=True)
 
 @wireprotocommand('heads')
diff -r 3b13a645b703 -r 1631cecbc20e tests/crashgetbundler.py
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/crashgetbundler.py	Fri Feb 10 18:20:58 2017 +0100
@@ -0,0 +1,14 @@ 
+from __future__ import absolute_import
+
+from mercurial.i18n import _
+from mercurial import (
+        changegroup,
+        error,
+        extensions
+    )
+
+def abort(orig, *args, **kwargs):
+    raise error.Abort(_('this is an exercise'))
+
+def uisetup(ui):
+    extensions.wrapfunction(changegroup, 'getbundler', abort)
diff -r 3b13a645b703 -r 1631cecbc20e tests/test-http-bundle1.t
--- a/tests/test-http-bundle1.t	Fri Feb 10 18:17:20 2017 +0100
+++ b/tests/test-http-bundle1.t	Fri Feb 10 18:20:58 2017 +0100
@@ -333,3 +333,15 @@ 
 check error log
 
   $ cat error.log
+
+Check error reporting while pulling/cloning
+
+  $ $RUNTESTDIR/killdaemons.py
+  $ hg -R test serve -p $HGPORT -d --pid-file=hg3.pid -E error.log --config extensions.crash=${TESTDIR}/crashgetbundler.py
+  $ cat hg3.pid >> $DAEMON_PIDS
+  $ hg clone http://localhost:$HGPORT/ abort-clone
+  requesting all changes
+  abort: remote error:
+  this is an exercise
+  [255]
+  $ cat error.log
diff -r 3b13a645b703 -r 1631cecbc20e tests/test-http.t
--- a/tests/test-http.t	Fri Feb 10 18:17:20 2017 +0100
+++ b/tests/test-http.t	Fri Feb 10 18:20:58 2017 +0100
@@ -321,3 +321,15 @@ 
 check error log
 
   $ cat error.log
+
+check abort error reporting while pulling/cloning
+
+  $ $RUNTESTDIR/killdaemons.py
+  $ hg -R test serve -p $HGPORT -d --pid-file=hg3.pid -E error.log --config extensions.crash=${TESTDIR}/crashgetbundler.py
+  $ cat hg3.pid >> $DAEMON_PIDS
+  $ hg clone http://localhost:$HGPORT/ abort-clone
+  requesting all changes
+  remote: abort: this is an exercise
+  abort: pull failed on remote
+  [255]
+  $ cat error.log
diff -r 3b13a645b703 -r 1631cecbc20e tests/test-ssh-bundle1.t
--- a/tests/test-ssh-bundle1.t	Fri Feb 10 18:17:20 2017 +0100
+++ b/tests/test-ssh-bundle1.t	Fri Feb 10 18:20:58 2017 +0100
@@ -543,3 +543,20 @@ 
   remote: abort: pretxnchangegroup.fail hook failed
   [1]
 
+abort during pull is properly reported as such
+
+  $ echo morefoo >> ../remote/foo
+  $ hg -R ../remote commit --message "more foo to be pulled"
+  $ cat >> ../remote/.hg/hgrc << EOF
+  > [extensions]
+  > crash = ${TESTDIR}/crashgetbundler.py
+  > EOF
+  $ hg --config ui.ssh="python $TESTDIR/dummyssh" pull
+  pulling from ssh://user@dummy/remote
+  searching for changes
+  adding changesets
+  remote: abort: this is an exercise
+  transaction abort!
+  rollback completed
+  abort: stream ended unexpectedly (got 0 bytes, expected 4)
+  [255]
diff -r 3b13a645b703 -r 1631cecbc20e tests/test-ssh.t
--- a/tests/test-ssh.t	Fri Feb 10 18:17:20 2017 +0100
+++ b/tests/test-ssh.t	Fri Feb 10 18:20:58 2017 +0100
@@ -548,3 +548,17 @@ 
   abort: push failed on remote
   [255]
 
+abort during pull is properly reported as such
+
+  $ echo morefoo >> ../remote/foo
+  $ hg -R ../remote commit --message "more foo to be pulled"
+  $ cat >> ../remote/.hg/hgrc << EOF
+  > [extensions]
+  > crash = ${TESTDIR}/crashgetbundler.py
+  > EOF
+  $ hg --config ui.ssh="python $TESTDIR/dummyssh" pull
+  pulling from ssh://user@dummy/remote
+  searching for changes
+  remote: abort: this is an exercise
+  abort: pull failed on remote
+  [255]