comparison mercurial/dispatch.py @ 46086:ac9de799d390

commandserver: handle IOError related to flushing of streams After dispatch, without chg we have 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. One such case is in `test-basic.t` which was failing on python3+chg without this patch as this handling was missing from chg. Failure can be seen at https://foss.heptapod.net/octobus/mercurial-devel/-/jobs/128399 Honestly I am not sure which one of `chgserver.py` or `commandserver.py` the change should go in. Differential Revision: https://phab.mercurial-scm.org/D9517
author Pulkit Goyal <7895pulkit@gmail.com>
date Thu, 03 Dec 2020 17:18:49 +0530
parents 7e1b4154cdca
children 49b6910217f9
comparison
equal deleted inserted replaced
46085:e0866c047e64 46086:ac9de799d390
102 finally: 102 finally:
103 if exc is not None: 103 if exc is not None:
104 raise exc 104 raise exc
105 105
106 106
107 def closestdio(ui, err):
108 status = None
109 # In all cases we try to flush stdio streams.
110 if util.safehasattr(ui, b'fout'):
111 assert ui is not None # help pytype
112 assert ui.fout is not None # help pytype
113 try:
114 ui.fout.flush()
115 except IOError as e:
116 err = e
117 status = -1
118
119 if util.safehasattr(ui, b'ferr'):
120 assert ui is not None # help pytype
121 assert ui.ferr is not None # help pytype
122 try:
123 if err is not None and err.errno != errno.EPIPE:
124 ui.ferr.write(
125 b'abort: %s\n' % encoding.strtolocal(err.strerror)
126 )
127 ui.ferr.flush()
128 # There's not much we can do about an I/O error here. So (possibly)
129 # change the status code and move on.
130 except IOError:
131 status = -1
132
133 return status
134
135
107 def run(): 136 def run():
108 """run the command in sys.argv""" 137 """run the command in sys.argv"""
109 try: 138 try:
110 initstdio() 139 initstdio()
111 with tracing.log('parse args into request'): 140 with tracing.log('parse args into request'):
115 status = dispatch(req) 144 status = dispatch(req)
116 except error.StdioError as e: 145 except error.StdioError as e:
117 err = e 146 err = e
118 status = -1 147 status = -1
119 148
120 # In all cases we try to flush stdio streams. 149 ret = closestdio(req.ui, err)
121 if util.safehasattr(req.ui, b'fout'): 150 if ret:
122 assert req.ui is not None # help pytype 151 status = ret
123 assert req.ui.fout is not None # help pytype
124 try:
125 req.ui.fout.flush()
126 except IOError as e:
127 err = e
128 status = -1
129
130 if util.safehasattr(req.ui, b'ferr'):
131 assert req.ui is not None # help pytype
132 assert req.ui.ferr is not None # help pytype
133 try:
134 if err is not None and err.errno != errno.EPIPE:
135 req.ui.ferr.write(
136 b'abort: %s\n' % encoding.strtolocal(err.strerror)
137 )
138 req.ui.ferr.flush()
139 # There's not much we can do about an I/O error here. So (possibly)
140 # change the status code and move on.
141 except IOError:
142 status = -1
143
144 _silencestdio() 152 _silencestdio()
145 except KeyboardInterrupt: 153 except KeyboardInterrupt:
146 # Catch early/late KeyboardInterrupt as last ditch. Here nothing will 154 # Catch early/late KeyboardInterrupt as last ditch. Here nothing will
147 # be printed to console to avoid another IOError/KeyboardInterrupt. 155 # be printed to console to avoid another IOError/KeyboardInterrupt.
148 status = -1 156 status = -1