From eea3c758dedc1f5c24da3e6a7108019bbb252a39 Mon Sep 17 00:00:00 2001 From: tobi-wan-kenobi Date: Sat, 16 May 2020 11:41:34 +0200 Subject: [PATCH] [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 --- bumblebee_status/core/input.py | 2 +- bumblebee_status/util/cli.py | 5 ++++- tests/core/test_input.py | 4 +++- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/bumblebee_status/core/input.py b/bumblebee_status/core/input.py index 66519d5..71d481e 100644 --- a/bumblebee_status/core/input.py +++ b/bumblebee_status/core/input.py @@ -38,7 +38,7 @@ def __event_id(obj_id, button): def __execute(cmd): try: - util.cli.execute(cmd, wait=False) + util.cli.execute(cmd, wait=False, shell=True) except Exception as e: logging.error("failed to invoke callback: {}".format(e)) diff --git a/bumblebee_status/util/cli.py b/bumblebee_status/util/cli.py index 209291f..2b07c75 100644 --- a/bumblebee_status/util/cli.py +++ b/bumblebee_status/util/cli.py @@ -11,6 +11,7 @@ def execute( include_stderr=False, env=None, return_exitcode=False, + shell=False, ): """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 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 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 :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) """ - args = shlex.split(cmd) + args = cmd if shell else shlex.split(cmd) logging.debug(cmd) try: proc = subprocess.Popen( @@ -34,6 +36,7 @@ def execute( stdout=subprocess.PIPE, stderr=subprocess.STDOUT if include_stderr else subprocess.PIPE, env=env, + shell=shell, ) except FileNotFoundError as e: raise RuntimeError("{} not found".format(cmd)) diff --git a/tests/core/test_input.py b/tests/core/test_input.py index 667184a..ba5641e 100644 --- a/tests/core/test_input.py +++ b/tests/core/test_input.py @@ -70,7 +70,9 @@ class config(unittest.TestCase): self.inputObject, self.someEvent["button"], self.someCommand ) 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): with unittest.mock.patch("core.input.util.cli") as cli: