diff --git a/launch/launch/actions/execute_process.py b/launch/launch/actions/execute_process.py
index 5eba900ca..ce511d9d1 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 342f2490e..73b638760 100644
--- a/launch_xml/test/launch_xml/test_executable.py
+++ b/launch_xml/test/launch_xml/test_executable.py
@@ -16,9 +16,7 @@
import io
import os
-from pathlib import Path
import sys
-import textwrap
from launch import LaunchService
from launch.actions import Shutdown
@@ -26,15 +24,27 @@
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
@@ -50,20 +60,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)