Patchwork [5,of,5,chg-tests-fix,V2] dispatch: handle IOError related to flushing of streams in `dispatch()`

login
register
mail settings
Submitter Pulkit Goyal
Date Dec. 8, 2020, 1:42 p.m.
Message ID <7c101117c91ed36ca721.1607434944@DESKTOP-STQPTJK>
Download mbox | patch
Permalink /patch/47839/
State New
Headers show

Comments

Pulkit Goyal - Dec. 8, 2020, 1:42 p.m.
# HG changeset patch
# User Pulkit Goyal <7895pulkit@gmail.com>
# Date 1606996129 -19800
#      Thu Dec 03 17:18:49 2020 +0530
# Node ID 7c101117c91ed36ca721b19f6292b6ec1d4c0cb4
# Parent  fa86da45f79d6e89860b4fc7026246811b2b221d
# EXP-Topic chg-test
dispatch: handle IOError related to flushing of streams in `dispatch()`

After dispatch, without chg we had handling of flushing of streams and
exception handling related to it. The exception handling part is important
because there can be exceptions when flushing fout or ferr.

This error handling was missing from commandserver. Due to this, `test-basic.t`
was failing on python3+chg.

Failure can be seen at
https://foss.heptapod.net/octobus/mercurial-devel/-/jobs/128399

This patch fixes the issue by moving StdioError related handling inside
`dispatch()`.

Thanks to Yuya who recommended moving inside `dispatch.dispatch()` rather than
patching `commandserver.py`.

Differential Revision: https://phab.mercurial-scm.org/D9517

Patch

diff -r fa86da45f79d -r 7c101117c91e mercurial/dispatch.py
--- a/mercurial/dispatch.py	Wed Dec 02 14:27:45 2020 +0530
+++ b/mercurial/dispatch.py	Thu Dec 03 17:18:49 2020 +0530
@@ -104,43 +104,43 @@ 
                 raise exc
 
 
+def flushstdio(ui, err):
+    status = None
+    # In all cases we try to flush stdio streams.
+    if util.safehasattr(ui, b'fout'):
+        assert ui is not None  # help pytype
+        assert ui.fout is not None  # help pytype
+        try:
+            ui.fout.flush()
+        except IOError as e:
+            err = e
+            status = -1
+
+    if util.safehasattr(ui, b'ferr'):
+        assert ui is not None  # help pytype
+        assert ui.ferr is not None  # help pytype
+        try:
+            if err is not None and err.errno != errno.EPIPE:
+                ui.ferr.write(
+                    b'abort: %s\n' % encoding.strtolocal(err.strerror)
+                )
+            ui.ferr.flush()
+        # There's not much we can do about an I/O error here. So (possibly)
+        # change the status code and move on.
+        except IOError:
+            status = -1
+
+    return status
+
+
 def run():
     """run the command in sys.argv"""
     try:
         initstdio()
         with tracing.log('parse args into request'):
             req = request(pycompat.sysargv[1:])
-        err = None
-        try:
-            status = dispatch(req)
-        except error.StdioError as e:
-            err = e
-            status = -1
 
-        # In all cases we try to flush stdio streams.
-        if util.safehasattr(req.ui, b'fout'):
-            assert req.ui is not None  # help pytype
-            assert req.ui.fout is not None  # help pytype
-            try:
-                req.ui.fout.flush()
-            except IOError as e:
-                err = e
-                status = -1
-
-        if util.safehasattr(req.ui, b'ferr'):
-            assert req.ui is not None  # help pytype
-            assert req.ui.ferr is not None  # help pytype
-            try:
-                if err is not None and err.errno != errno.EPIPE:
-                    req.ui.ferr.write(
-                        b'abort: %s\n' % encoding.strtolocal(err.strerror)
-                    )
-                req.ui.ferr.flush()
-            # There's not much we can do about an I/O error here. So (possibly)
-            # change the status code and move on.
-            except IOError:
-                status = -1
-
+        status = dispatch(req)
         _silencestdio()
     except KeyboardInterrupt:
         # Catch early/late KeyboardInterrupt as last ditch. Here nothing will
@@ -232,7 +232,21 @@ 
 
 def dispatch(req):
     """run the command specified in req.args; returns an integer status code"""
-    with tracing.log('dispatch.dispatch'):
+    err = None
+    try:
+        status = _rundispatch(req)
+    except error.StdioError as e:
+        err = e
+        status = -1
+
+    ret = flushstdio(req.ui, err)
+    if ret:
+        status = ret
+    return status
+
+
+def _rundispatch(req):
+    with tracing.log('dispatch._rundispatch'):
         if req.ferr:
             ferr = req.ferr
         elif req.ui:
diff -r fa86da45f79d -r 7c101117c91e tests/test-devel-warnings.t
--- a/tests/test-devel-warnings.t	Wed Dec 02 14:27:45 2020 +0530
+++ b/tests/test-devel-warnings.t	Thu Dec 03 17:18:49 2020 +0530
@@ -104,6 +104,7 @@ 
    */hg:* in <module> (glob) (?)
    */mercurial/dispatch.py:* in run (glob)
    */mercurial/dispatch.py:* in dispatch (glob)
+   */mercurial/dispatch.py:* in _rundispatch (glob)
    */mercurial/dispatch.py:* in _runcatch (glob)
    */mercurial/dispatch.py:* in _callcatch (glob)
    */mercurial/scmutil.py* in callcatch (glob)
@@ -120,6 +121,7 @@ 
    */hg:* in <module> (glob) (?)
    */mercurial/dispatch.py:* in run (glob)
    */mercurial/dispatch.py:* in dispatch (glob)
+   */mercurial/dispatch.py:* in _rundispatch (glob)
    */mercurial/dispatch.py:* in _runcatch (glob)
    */mercurial/dispatch.py:* in _callcatch (glob)
    */mercurial/scmutil.py:* in callcatch (glob)
@@ -142,6 +144,7 @@ 
    */mercurial/commandserver.py:* in runcommand (glob)
    */mercurial/commandserver.py:* in _dispatchcommand (glob)
    */mercurial/dispatch.py:* in dispatch (glob)
+   */mercurial/dispatch.py:* in _rundispatch (glob)
    */mercurial/dispatch.py:* in _runcatch (glob)
    */mercurial/dispatch.py:* in _callcatch (glob)
    */mercurial/scmutil.py:* in callcatch (glob)
@@ -184,6 +187,7 @@ 
    */hg:* in <module> (glob) (?)
    */mercurial/dispatch.py:* in run (glob)
    */mercurial/dispatch.py:* in dispatch (glob)
+   */mercurial/dispatch.py:* in _rundispatch (glob)
    */mercurial/dispatch.py:* in _runcatch (glob)
    */mercurial/dispatch.py:* in _callcatch (glob)
    */mercurial/scmutil.py* in callcatch (glob)
@@ -201,6 +205,7 @@ 
    */hg:* in <module> (glob)
    */mercurial/dispatch.py:* in run (glob)
    */mercurial/dispatch.py:* in dispatch (glob)
+   */mercurial/dispatch.py:* in _rundispatch (glob)
    */mercurial/dispatch.py:* in _runcatch (glob)
    */mercurial/dispatch.py:* in _callcatch (glob)
    */mercurial/scmutil.py:* in callcatch (glob)
@@ -223,6 +228,7 @@ 
    */mercurial/commandserver.py:* in runcommand (glob)
    */mercurial/commandserver.py:* in _dispatchcommand (glob)
    */mercurial/dispatch.py:* in dispatch (glob)
+   */mercurial/dispatch.py:* in _rundispatch (glob)
    */mercurial/dispatch.py:* in _runcatch (glob)
    */mercurial/dispatch.py:* in _callcatch (glob)
    */mercurial/scmutil.py:* in callcatch (glob)
@@ -247,6 +253,7 @@ 
    */hg:* in <module> (glob) (?)
    */mercurial/dispatch.py:* in run (glob)
    */mercurial/dispatch.py:* in dispatch (glob)
+   */mercurial/dispatch.py:* in _rundispatch (glob)
    */mercurial/dispatch.py:* in _runcatch (glob)
    */mercurial/dispatch.py:* in _callcatch (glob)
    */mercurial/scmutil.py* in callcatch (glob)
@@ -271,6 +278,7 @@ 
    */hg:* in <module> (glob)
    */mercurial/dispatch.py:* in run (glob)
    */mercurial/dispatch.py:* in dispatch (glob)
+   */mercurial/dispatch.py:* in _rundispatch (glob)
    */mercurial/dispatch.py:* in _runcatch (glob)
    */mercurial/dispatch.py:* in _callcatch (glob)
    */mercurial/scmutil.py:* in callcatch (glob)
@@ -293,6 +301,7 @@ 
    */mercurial/commandserver.py:* in runcommand (glob)
    */mercurial/commandserver.py:* in _dispatchcommand (glob)
    */mercurial/dispatch.py:* in dispatch (glob)
+   */mercurial/dispatch.py:* in _rundispatch (glob)
    */mercurial/dispatch.py:* in _runcatch (glob)
    */mercurial/dispatch.py:* in _callcatch (glob)
    */mercurial/scmutil.py:* in callcatch (glob)