Mercurial > libervia-backend
comparison libervia/backend/tools/common/async_process.py @ 4251:601e72332907
tools (common/async_process): show command and arguments used in error message in case a failure.
author | Goffi <goffi@goffi.org> |
---|---|
date | Fri, 31 May 2024 11:08:23 +0200 |
parents | 730f542e4ad0 |
children | 0d7bb4df2343 |
comparison
equal
deleted
inserted
replaced
4250:4b6b812f485a | 4251:601e72332907 |
---|---|
18 # along with this program. If not, see <http://www.gnu.org/licenses/>. | 18 # along with this program. If not, see <http://www.gnu.org/licenses/>. |
19 | 19 |
20 """tools to launch process in a async way (using Twisted)""" | 20 """tools to launch process in a async way (using Twisted)""" |
21 | 21 |
22 import os.path | 22 import os.path |
23 from typing import Any | |
23 from twisted.internet import defer, reactor, protocol | 24 from twisted.internet import defer, reactor, protocol |
24 from twisted.python.failure import Failure | 25 from twisted.python.failure import Failure |
25 from libervia.backend.core.i18n import _ | 26 from libervia.backend.core.i18n import _ |
26 from libervia.backend.core import exceptions | 27 from libervia.backend.core import exceptions |
27 from libervia.backend.core.log import getLogger | 28 from libervia.backend.core.log import getLogger |
44 """ | 45 """ |
45 self._stdin = stdin | 46 self._stdin = stdin |
46 self._deferred = deferred | 47 self._deferred = deferred |
47 self.data = [] | 48 self.data = [] |
48 self.err_data = [] | 49 self.err_data = [] |
50 self.cmd_args: list[str]|None = None | |
51 self.cmd_kwargs: dict[str, Any]|None = None | |
49 | 52 |
50 @property | 53 @property |
51 def command_name(self): | 54 def command_name(self): |
52 """returns command name or empty string if it can't be guessed""" | 55 """returns command name or empty string if it can't be guessed""" |
53 if self.name is not None: | 56 if self.name is not None: |
81 # is not working properly | 84 # is not working properly |
82 self._deferred.callback(data) | 85 self._deferred.callback(data) |
83 else: | 86 else: |
84 err_data = b''.join(self.err_data) | 87 err_data = b''.join(self.err_data) |
85 | 88 |
86 msg = (_("Can't complete {name} command (error code: {code}):\n" | 89 assert self.cmd_args is not None |
87 "stderr:\n{stderr}\n{stdout}\n") | 90 assert self.cmd_kwargs is not None |
88 .format(name = self.command_name, | 91 msg = ( |
89 code = reason.value.exitCode, | 92 _( |
90 stderr= err_data.decode(errors='replace'), | 93 "Can't complete {name} command (error code: {code}):\n" |
91 stdout = "stdout: " + data.decode(errors='replace') | 94 "Executed command: {command}\n" |
92 if data else '', | 95 "Keyword arguments:\n" |
93 )) | 96 "{command_kw}\n\n" |
97 "stderr:\n{stderr}\n{stdout}\n" | |
98 ) | |
99 .format( | |
100 name = self.command_name, | |
101 code = reason.value.exitCode, | |
102 command = " ".join(self.cmd_args), | |
103 command_kw = "\n".join( | |
104 f" - {k} = {v!r}" for k,v in self.cmd_kwargs.items() | |
105 ), | |
106 stderr= err_data.decode(errors='replace'), | |
107 stdout = "stdout: " + data.decode(errors='replace') | |
108 if data else '', | |
109 ) | |
110 ) | |
94 self._deferred.errback(Failure(exceptions.CommandException( | 111 self._deferred.errback(Failure(exceptions.CommandException( |
95 msg, data, err_data))) | 112 msg, data, err_data))) |
96 | 113 |
97 @classmethod | 114 @classmethod |
98 def run(cls, *args, **kwargs): | 115 def run(cls, *args, **kwargs): |
129 name = os.path.splitext(os.path.basename(command))[0] | 146 name = os.path.splitext(os.path.basename(command))[0] |
130 prot.name = name | 147 prot.name = name |
131 else: | 148 else: |
132 command = cls.command | 149 command = cls.command |
133 cmd_args = [command] + args | 150 cmd_args = [command] + args |
151 prot.cmd_args = cmd_args | |
152 prot.cmd_kwargs = kwargs | |
134 if "env" not in kwargs: | 153 if "env" not in kwargs: |
135 # we pass parent environment by default | 154 # we pass parent environment by default |
136 # FIXME: `None` doesn't seem to work, despite what documentation says, to be | 155 # FIXME: `None` doesn't seem to work, despite what documentation says, to be |
137 # checked and reported upstream if confirmed. | 156 # checked and reported upstream if confirmed. |
138 kwargs["env"] = os.environ | 157 kwargs["env"] = os.environ |