[core/input] Invoke commands in a subshell
add shell capability to util.cli and make sure that the input module uses that to reliably spawn whatever command the user wants to run. see #628
This commit is contained in:
parent
06fa453d71
commit
eea3c758de
3 changed files with 8 additions and 3 deletions
|
@ -38,7 +38,7 @@ def __event_id(obj_id, button):
|
||||||
|
|
||||||
def __execute(cmd):
|
def __execute(cmd):
|
||||||
try:
|
try:
|
||||||
util.cli.execute(cmd, wait=False)
|
util.cli.execute(cmd, wait=False, shell=True)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logging.error("failed to invoke callback: {}".format(e))
|
logging.error("failed to invoke callback: {}".format(e))
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,7 @@ def execute(
|
||||||
include_stderr=False,
|
include_stderr=False,
|
||||||
env=None,
|
env=None,
|
||||||
return_exitcode=False,
|
return_exitcode=False,
|
||||||
|
shell=False,
|
||||||
):
|
):
|
||||||
"""Executes a commandline utility and returns its output
|
"""Executes a commandline utility and returns its output
|
||||||
|
|
||||||
|
@ -20,13 +21,14 @@ def execute(
|
||||||
:param include_stderr: set to True to include stderr output in the return value, defaults to False
|
:param include_stderr: set to True to include stderr output in the return value, defaults to False
|
||||||
:param env: provide a dict here to specify a custom execution environment, defaults to None
|
:param env: provide a dict here to specify a custom execution environment, defaults to None
|
||||||
:param return_exitcode: set to True to return a pair, where the first member is the exit code and the message the second, defaults to False
|
:param return_exitcode: set to True to return a pair, where the first member is the exit code and the message the second, defaults to False
|
||||||
|
:param shell: set to True to run command in a separate shell, defaults to False
|
||||||
|
|
||||||
:raises RuntimeError: the command either didn't exist or didn't exit cleanly, and ignore_errors was set to False
|
:raises RuntimeError: the command either didn't exist or didn't exit cleanly, and ignore_errors was set to False
|
||||||
|
|
||||||
:return: output of cmd, or stderr, if ignore_errors is True and the command failed; or a tuple of exitcode and the previous, if return_exitcode is set to True
|
:return: output of cmd, or stderr, if ignore_errors is True and the command failed; or a tuple of exitcode and the previous, if return_exitcode is set to True
|
||||||
:rtype: string or tuple (if return_exitcode is set to True)
|
:rtype: string or tuple (if return_exitcode is set to True)
|
||||||
"""
|
"""
|
||||||
args = shlex.split(cmd)
|
args = cmd if shell else shlex.split(cmd)
|
||||||
logging.debug(cmd)
|
logging.debug(cmd)
|
||||||
try:
|
try:
|
||||||
proc = subprocess.Popen(
|
proc = subprocess.Popen(
|
||||||
|
@ -34,6 +36,7 @@ def execute(
|
||||||
stdout=subprocess.PIPE,
|
stdout=subprocess.PIPE,
|
||||||
stderr=subprocess.STDOUT if include_stderr else subprocess.PIPE,
|
stderr=subprocess.STDOUT if include_stderr else subprocess.PIPE,
|
||||||
env=env,
|
env=env,
|
||||||
|
shell=shell,
|
||||||
)
|
)
|
||||||
except FileNotFoundError as e:
|
except FileNotFoundError as e:
|
||||||
raise RuntimeError("{} not found".format(cmd))
|
raise RuntimeError("{} not found".format(cmd))
|
||||||
|
|
|
@ -70,7 +70,9 @@ class config(unittest.TestCase):
|
||||||
self.inputObject, self.someEvent["button"], self.someCommand
|
self.inputObject, self.someEvent["button"], self.someCommand
|
||||||
)
|
)
|
||||||
core.input.trigger(self.someEvent)
|
core.input.trigger(self.someEvent)
|
||||||
cli.execute.assert_called_once_with(self.someCommand, wait=False)
|
cli.execute.assert_called_once_with(
|
||||||
|
self.someCommand, wait=False, shell=True
|
||||||
|
)
|
||||||
|
|
||||||
def test_non_existent_callback(self):
|
def test_non_existent_callback(self):
|
||||||
with unittest.mock.patch("core.input.util.cli") as cli:
|
with unittest.mock.patch("core.input.util.cli") as cli:
|
||||||
|
|
Loading…
Reference in a new issue