diff --git a/launch/launch/actions/execute_process.py b/launch/launch/actions/execute_process.py index 51aee8bb2..4b8819fad 100644 --- a/launch/launch/actions/execute_process.py +++ b/launch/launch/actions/execute_process.py @@ -14,6 +14,7 @@ """Module for the ExecuteProcess action.""" +import platform import shlex from typing import Dict from typing import Iterable @@ -34,6 +35,8 @@ from ..substitution import Substitution from ..substitutions import TextSubstitution +g_is_windows = 'win' in platform.system().lower() + @expose_action('executable') class ExecuteProcess(ExecuteLocal): @@ -266,7 +269,7 @@ def _append_arg(): for sub in parser.parse_substitution(cmd): if isinstance(sub, TextSubstitution): try: - tokens = shlex.split(sub.text) + tokens = shlex.split(sub.text, posix=(not g_is_windows)) except Exception: logger = launch.logging.get_logger(cls.__name__) logger.error(f"Failed to parse token '{sub.text}' of cmd '{cmd}'") diff --git a/launch/launch/descriptions/executable.py b/launch/launch/descriptions/executable.py index 3d1d0640b..930801921 100644 --- a/launch/launch/descriptions/executable.py +++ b/launch/launch/descriptions/executable.py @@ -18,6 +18,7 @@ """Module for a description of an Executable.""" import os +import platform import re import shlex import threading @@ -37,6 +38,7 @@ _executable_process_counter_lock = threading.Lock() _executable_process_counter = 0 # in Python3, this number is unbounded (no rollover) +g_is_windows = 'win' in platform.system().lower() class Executable: @@ -179,7 +181,9 @@ def prepare(self, context: LaunchContext, action: Action): # Apply if filter regex matches (empty regex matches all strings) should_apply_prefix = re.match(prefix_filter, os.path.basename(cmd[0])) is not None if should_apply_prefix: - cmd = shlex.split(perform_substitutions(context, self.__prefix)) + cmd + cmd = shlex.split( + perform_substitutions(context, self.__prefix), posix=(not g_is_windows) + ) + cmd self.__final_cmd = cmd name = os.path.basename(cmd[0]) if self.__name is None \ else perform_substitutions(context, self.__name) diff --git a/launch/launch/substitutions/command.py b/launch/launch/substitutions/command.py index 0aed7a9d6..6d0ddc840 100644 --- a/launch/launch/substitutions/command.py +++ b/launch/launch/substitutions/command.py @@ -14,7 +14,7 @@ """Module for the Command substitution.""" -import os +import platform import shlex import subprocess from typing import List @@ -30,6 +30,8 @@ from ..some_substitutions_type import SomeSubstitutionsType from ..substitution import Substitution +g_is_windows = 'win' in platform.system().lower() + @expose_substitution('command') class Command(Substitution): @@ -94,10 +96,7 @@ def perform(self, context: LaunchContext) -> Text: from ..utilities import perform_substitutions # import here to avoid loop command_str = perform_substitutions(context, self.command) command: Union[str, List[str]] - if os.name != 'nt': - command = shlex.split(command_str) - else: - command = command_str + command = shlex.split(command_str, posix=(not g_is_windows)) on_stderr = perform_substitutions(context, self.on_stderr) if on_stderr not in ('fail', 'ignore', 'warn', 'capture'): raise SubstitutionFailure( diff --git a/launch_xml/test/launch_xml/executable.xml b/launch_xml/test/launch_xml/executable.xml deleted file mode 100644 index 3195dd1ad..000000000 --- a/launch_xml/test/launch_xml/executable.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/launch_xml/test/launch_xml/test_executable.py b/launch_xml/test/launch_xml/test_executable.py index 2299fc255..020dc39dd 100644 --- a/launch_xml/test/launch_xml/test_executable.py +++ b/launch_xml/test/launch_xml/test_executable.py @@ -16,24 +16,34 @@ import io import os -from pathlib import Path import sys -import textwrap from launch import LaunchService from launch.frontend import Parser import pytest +test_executable_xml = f""" + + + + + +""" + def test_executable(): """Parse node xml example.""" - xml_file = str(Path(__file__).parent / 'executable.xml') - root_entity, parser = Parser.load(xml_file) + root_entity, parser = Parser.load(io.StringIO(test_executable_xml)) ld = parser.parse_description(root_entity) executable = ld.entities[0] cmd = [i[0].perform(None) for i in executable.cmd] - assert cmd == ['ls', '-l', '-a', '-s'] + assert cmd == [sys.executable, '--version'] assert executable.cwd[0].perform(None) == '/' assert executable.name[0].perform(None) == 'my_ls' assert executable.shell is True @@ -49,20 +59,21 @@ def test_executable(): ls = LaunchService() ls.include_launch_description(ld) assert 0 == ls.run() + assert executable.return_code == 0 + + +test_executable_wrong_subtag_xml = """ + + + + + + +""" def test_executable_wrong_subtag(): - xml_file = \ - """\ - - - - - - - """ # noqa, line too long - xml_file = textwrap.dedent(xml_file) - root_entity, parser = Parser.load(io.StringIO(xml_file)) + root_entity, parser = Parser.load(io.StringIO(test_executable_wrong_subtag_xml)) with pytest.raises(ValueError) as excinfo: parser.parse_description(root_entity) assert '`executable`' in str(excinfo.value)