Mercurial > public > mercurial-scm > hg
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 |