Mercurial > libervia-backend
diff sat_frontends/jp/cmd_input.py @ 3040:fee60f17ebac
jp: jp asyncio port:
/!\ this commit is huge. Jp is temporarily not working with `dbus` bridge /!\
This patch implements the port of jp to asyncio, so it is now correctly using the bridge
asynchronously, and it can be used with bridges like `pb`. This also simplify the code,
notably for things which were previously implemented with many callbacks (like pagination
with RSM).
During the process, some behaviours have been modified/fixed, in jp and backends, check
diff for details.
author | Goffi <goffi@goffi.org> |
---|---|
date | Wed, 25 Sep 2019 08:56:41 +0200 |
parents | ab2696e34d29 |
children | 9d0df638c8b4 |
line wrap: on
line diff
--- a/sat_frontends/jp/cmd_input.py Wed Sep 25 08:53:38 2019 +0200 +++ b/sat_frontends/jp/cmd_input.py Wed Sep 25 08:56:41 2019 +0200 @@ -18,14 +18,16 @@ # along with this program. If not, see <http://www.gnu.org/licenses/>. +import subprocess +import argparse +import sys +import shlex +import asyncio from . import base from sat.core.i18n import _ from sat.core import exceptions from sat_frontends.jp.constants import Const as C from sat.tools.common.ansi import ANSI as A -import subprocess -import argparse -import sys __commands__ = ["Input"] OPT_STDIN = "stdin" @@ -105,10 +107,10 @@ help=_("don't actually run commands but echo what would be launched"), ) self.parser.add_argument( - "--log", type=argparse.FileType("wb"), help=_("log stdout to FILE") + "--log", type=argparse.FileType("w"), help=_("log stdout to FILE") ) self.parser.add_argument( - "--log-err", type=argparse.FileType("wb"), help=_("log stderr to FILE") + "--log-err", type=argparse.FileType("w"), help=_("log stderr to FILE") ) self.parser.add_argument("command", nargs=argparse.REMAINDER) @@ -166,15 +168,15 @@ for v in value: if arg_type == OPT_STDIN: - self._stdin.append(v.encode("utf-8")) + self._stdin.append(v) elif arg_type == OPT_SHORT: self._opts.append("-{}".format(arg_name)) - self._opts.append(v.encode("utf-8")) + self._opts.append(v) elif arg_type == OPT_LONG: self._opts.append("--{}".format(arg_name)) - self._opts.append(v.encode("utf-8")) + self._opts.append(v) elif arg_type == OPT_POS: - self._pos.append(v.encode("utf-8")) + self._pos.append(v) elif arg_type == OPT_IGNORE: pass else: @@ -184,7 +186,7 @@ ).format(type_=arg_type, name=arg_name) ) - def runCommand(self): + async def runCommand(self): """run requested command with parsed arguments""" if self.args_idx != len(self.args.arguments): self.disp( @@ -200,7 +202,10 @@ if self.args.debug: self.disp( A.color( - C.A_SUBHEADER, _("values: "), A.RESET, ", ".join(self._values_ori) + C.A_SUBHEADER, + _("values: "), + A.RESET, + ", ".join([shlex.quote(a) for a in self._values_ori]) ), 2, ) @@ -209,34 +214,39 @@ self.disp(A.color(C.A_SUBHEADER, "--- STDIN ---")) self.disp(stdin) self.disp(A.color(C.A_SUBHEADER, "-------------")) + self.disp( "{indent}{prog} {static} {options} {positionals}".format( indent=4 * " ", prog=sys.argv[0], static=" ".join(self.args.command), - options=" ".join([o for o in self._opts]), - positionals=" ".join([p for p in self._pos]), + options=" ".join(shlex.quote(o) for o in self._opts), + positionals=" ".join(shlex.quote(p) for p in self._pos), ) ) self.disp("\n") else: self.disp(" (" + ", ".join(self._values_ori) + ")", 2, no_lf=True) args = [sys.argv[0]] + self.args.command + self._opts + self._pos - p = subprocess.Popen( - args, + p = await asyncio.create_subprocess_exec( + *args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, ) - (stdout, stderr) = p.communicate(stdin) + stdout, stderr = await p.communicate(stdin.encode('utf-8')) log = self.args.log log_err = self.args.log_err log_tpl = "{command}\n{buff}\n\n" if log: - log.write(log_tpl.format(command=" ".join(args), buff=stdout)) + log.write(log_tpl.format( + command=" ".join(shlex.quote(a) for a in args), + buff=stdout.decode('utf-8', 'replace'))) if log_err: - log_err.write(log_tpl.format(command=" ".join(args), buff=stderr)) - ret = p.wait() + log_err.write(log_tpl.format( + command=" ".join(shlex.quote(a) for a in args), + buff=stderr.decode('utf-8', 'replace'))) + ret = p.returncode if ret == 0: self.disp(A.color(C.A_SUCCESS, _("OK"))) else: @@ -307,21 +317,25 @@ super(Csv, self).filter(filter_type, filter_arg, value) - def start(self): + async def start(self): import csv + if self.args.encoding: + sys.stdin.reconfigure(encoding=self.args.encoding, errors="replace") reader = csv.reader(sys.stdin) for idx, row in enumerate(reader): try: if idx < self.args.row: continue for value in row: - self.addValue(value.decode(self.args.encoding)) - self.runCommand() + self.addValue(value) + await self.runCommand() except exceptions.CancelError: # this row has been cancelled, we skip it continue + self.host.quit() + class Input(base.CommandBase): subcommands = (Csv,)