jp (shell): use of subprocess instead of running commands in the same process:
when a command is calling host.quit() in a D-Bus callback, GLib mainloop is exiting and quit the whole process without (apparently?) any way to block it. Couldn't find a good way to avoid that, so subprocess are now used as a workaround, instead of launching commands in the same process. When we'll get rid of python-dbus, there may be an other way. Execuring external commands is now possible through the shell/! command.
This commit is contained in:
parent
783d14bfc7
commit
62c17395bd
2 changed files with 47 additions and 20 deletions
|
|
@ -165,9 +165,6 @@ class Jp(object):
|
|||
|
||||
self.bridge = bridge_module.Bridge()
|
||||
self.bridge.bridgeConnect(callback=self._bridgeCb, errback=self._bridgeEb)
|
||||
# _no_exit is used in shell mode because SystemExit can't
|
||||
# catched in some cases
|
||||
self._no_exit = False
|
||||
|
||||
def _bridgeCb(self):
|
||||
self.parser = argparse.ArgumentParser(formatter_class=argparse.RawDescriptionHelpFormatter,
|
||||
|
|
@ -445,8 +442,7 @@ class Jp(object):
|
|||
callback(*args, **kwargs)
|
||||
|
||||
self.stop_loop()
|
||||
if not self._no_exit:
|
||||
sys.exit(errcode)
|
||||
sys.exit(errcode)
|
||||
|
||||
def check_jids(self, jids):
|
||||
"""Check jids validity, transform roster name to corresponding jids
|
||||
|
|
|
|||
|
|
@ -20,11 +20,13 @@
|
|||
|
||||
import base
|
||||
import cmd
|
||||
import sys
|
||||
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 shlex
|
||||
import subprocess
|
||||
|
||||
__commands__ = ["Shell"]
|
||||
INTRO = _(u"""Welcome to {app_name} shell, the Salut à Toi shell !
|
||||
|
|
@ -98,7 +100,7 @@ class Shell(base.CommandBase, cmd.Cmd):
|
|||
# else USE args would not work correctly (only for current parser)
|
||||
cmd_args = []
|
||||
for arg in args:
|
||||
if arg.startswith(u'-'):
|
||||
if arg.startswith('-'):
|
||||
break
|
||||
try:
|
||||
parser = self.get_cmd_choices(arg, parser)
|
||||
|
|
@ -131,6 +133,43 @@ class Shell(base.CommandBase, cmd.Cmd):
|
|||
opt_args.append(value)
|
||||
return cmd_args + opt_args + pos_args
|
||||
|
||||
def run_cmd(self, args, external=False):
|
||||
"""run command and retur exit code
|
||||
|
||||
@param args[list[string]]: arguments of the command
|
||||
must not include program name
|
||||
@param external(bool): True if it's an external command (i.e. not jp)
|
||||
@return (int): exit code (0 success, any other int failure)
|
||||
"""
|
||||
# FIXME: we have to use subprocess
|
||||
# and relaunch whole python for now
|
||||
# because if host.quit() is called in D-Bus callback
|
||||
# GLib quit the whole app without possibility to stop it
|
||||
# didn't found a nice way to work around it so far
|
||||
# Situation should be better when we'll move away from python-dbus
|
||||
if self.verbose:
|
||||
self.disp(_(u"COMMAND {external}=> {args}").format(
|
||||
external = _(u'(external) ') if external else u'',
|
||||
args=u' '.join(self.format_args(args))))
|
||||
if not external:
|
||||
args = sys.argv[0:1] + args
|
||||
ret_code= subprocess.call(args)
|
||||
# XXX: below is a way to launch the command without creating a new process
|
||||
# may be used when a solution to the aforementioned issue is there
|
||||
# try:
|
||||
# self.host.run(args)
|
||||
# except SystemExit as e:
|
||||
# ret_code = e.code
|
||||
# except Exception as e:
|
||||
# self.disp(A.color(C.A_FAILURE, u'command failed with an exception: {msg}'.format(msg=e)), error=True)
|
||||
# ret_code = 1
|
||||
# else:
|
||||
# ret_code = 0
|
||||
|
||||
if ret_code != 0:
|
||||
self.disp(A.color(C.A_FAILURE, u'command failed with an error code of {err_no}'.format(err_no=ret_code)), error=True)
|
||||
return ret_code
|
||||
|
||||
def default(self, args):
|
||||
"""called when no shell command is recognized
|
||||
|
||||
|
|
@ -187,27 +226,19 @@ class Shell(base.CommandBase, cmd.Cmd):
|
|||
except SystemExit:
|
||||
pass
|
||||
|
||||
def do_shell(self, args):
|
||||
"""launch an external command (you can use ![command] too)"""
|
||||
args = self.parse_args(args)
|
||||
self.run_cmd(args, external=True)
|
||||
|
||||
def do_do(self, args):
|
||||
"""lauch a command"""
|
||||
# we don't want host to really exit
|
||||
# we want to stay in the loop
|
||||
self.host._no_exit = True
|
||||
args = self.parse_args(args)
|
||||
# args may be modified by use_args
|
||||
# to remove subparsers from it
|
||||
use_args = self.get_use_args(args)
|
||||
cmd_args = self.path + use_args + args
|
||||
if self.verbose:
|
||||
self.disp(u"COMMAND => {args}".format(args=u' '.join(self.format_args(cmd_args))))
|
||||
try:
|
||||
self.host.run(cmd_args)
|
||||
except SystemExit as e:
|
||||
if e.code != 0:
|
||||
self.disp(A.color(C.A_FAILURE, u'command failed with an error code of {err_no}'.format(err_no=e.code)), error=True)
|
||||
except Exception as e:
|
||||
self.disp(A.color(C.A_FAILURE, u'command failed with an exception: {msg}'.format(msg=e)), error=True)
|
||||
finally:
|
||||
self.host._no_exit = False
|
||||
self.run_cmd(cmd_args)
|
||||
|
||||
def do_use(self, args):
|
||||
"""fix an argument"""
|
||||
|
|
|
|||
Loading…
Reference in a new issue