wireprotov1peer: don't raise internal errors in some cases
authorValentin Gatien-Baron <vgatien-baron@janestreet.com>
Thu, 25 Feb 2021 10:08:33 -0500
changeset 46672 aa2e38147e8b
parent 46671 fa30292b680b
child 46673 c7f6c3027af2
wireprotov1peer: don't raise internal errors in some cases Specifically, when the peer is closed in the middle of a batch of rpcs. Differential Revision: https://phab.mercurial-scm.org/D10074
mercurial/scmutil.py
mercurial/wireprotov1peer.py
tests/test-ssh-batch.t
--- a/mercurial/scmutil.py	Thu Feb 25 10:00:08 2021 -0500
+++ b/mercurial/scmutil.py	Thu Feb 25 10:08:33 2021 -0500
@@ -201,7 +201,9 @@
         msg = inst.args[1]
         if isinstance(msg, type(u'')):
             msg = pycompat.sysbytes(msg)
-        if not isinstance(msg, bytes):
+        if msg is None:
+            ui.error(b"\n")
+        elif not isinstance(msg, bytes):
             ui.error(b" %r\n" % (msg,))
         elif not msg:
             ui.error(_(b" empty string\n"))
--- a/mercurial/wireprotov1peer.py	Thu Feb 25 10:00:08 2021 -0500
+++ b/mercurial/wireprotov1peer.py	Thu Feb 25 10:08:33 2021 -0500
@@ -310,7 +310,7 @@
                 if not f.done():
                     f.set_exception(
                         error.ResponseError(
-                            _(b'unfulfilled batch command response')
+                            _(b'unfulfilled batch command response'), None
                         )
                     )
 
@@ -322,16 +322,27 @@
         for command, f, batchable, fremote in states:
             # Grab raw result off the wire and teach the internal future
             # about it.
-            remoteresult = next(wireresults)
-            fremote.set(remoteresult)
+            try:
+                remoteresult = next(wireresults)
+            except StopIteration:
+                # This can happen in particular because next(batchable)
+                # in the previous iteration can call peer._abort, which
+                # may close the peer.
+                f.set_exception(
+                    error.ResponseError(
+                        _(b'unfulfilled batch command response'), None
+                    )
+                )
+            else:
+                fremote.set(remoteresult)
 
-            # And ask the coroutine to decode that value.
-            try:
-                result = next(batchable)
-            except Exception:
-                pycompat.future_set_exception_info(f, sys.exc_info()[1:])
-            else:
-                f.set_result(result)
+                # And ask the coroutine to decode that value.
+                try:
+                    result = next(batchable)
+                except Exception:
+                    pycompat.future_set_exception_info(f, sys.exc_info()[1:])
+                else:
+                    f.set_result(result)
 
 
 @interfaceutil.implementer(
--- a/tests/test-ssh-batch.t	Thu Feb 25 10:00:08 2021 -0500
+++ b/tests/test-ssh-batch.t	Thu Feb 25 10:08:33 2021 -0500
@@ -9,5 +9,7 @@
 fails (thus causing the sshpeer to be stopped), the errors from the
 further lookups don't result in tracebacks.
 
-  $ hg pull -r b0 -r nosuchbookmark $(for i in $($TESTDIR/seq.py 1 20); do echo -r b$i; done) -e "\"$PYTHON\" \"$TESTDIR/dummyssh\"" ssh://user@dummy/$(pwd)/../a |& tail -n 1
-  StopIteration
+  $ hg pull -r b0 -r nosuchbookmark $(for i in $($TESTDIR/seq.py 1 20); do echo -r b$i; done) -e "\"$PYTHON\" \"$TESTDIR/dummyssh\"" ssh://user@dummy/$(pwd)/../a
+  pulling from ssh://user@dummy/$TESTTMP/b/../a
+  abort: unknown revision 'nosuchbookmark'
+  [255]