From 6daad27044b9603ce43f8e55a83c9bcda9360774 Mon Sep 17 00:00:00 2001 From: Sean Yen Date: Tue, 18 Sep 2018 14:38:23 -0700 Subject: [PATCH 1/7] Use non-posix way to split command string. --- tools/roslaunch/src/roslaunch/loader.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/roslaunch/src/roslaunch/loader.py b/tools/roslaunch/src/roslaunch/loader.py index 025aeba624..91b07296ea 100644 --- a/tools/roslaunch/src/roslaunch/loader.py +++ b/tools/roslaunch/src/roslaunch/loader.py @@ -491,7 +491,8 @@ def param_value(self, verbose, name, ptype, value, textfile, binfile, command): print("... executing command param [%s]" % command) import subprocess, shlex #shlex rocks try: - p = subprocess.Popen(shlex.split(command), stdout=subprocess.PIPE) + os_posix = os.name == "posix" + p = subprocess.Popen(shlex.split(command, posix=os_posix), stdout=subprocess.PIPE) c_value = p.communicate()[0] if not isinstance(c_value, str): c_value = c_value.decode('utf-8') From e4caa3e71921953e201134d1de3abbfb1239708a Mon Sep 17 00:00:00 2001 From: Sean Yen Date: Wed, 19 Sep 2018 21:55:45 -0700 Subject: [PATCH 2/7] Use shell feature for roslaunch command. --- tools/roslaunch/src/roslaunch/loader.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/roslaunch/src/roslaunch/loader.py b/tools/roslaunch/src/roslaunch/loader.py index 91b07296ea..13c2f9a211 100644 --- a/tools/roslaunch/src/roslaunch/loader.py +++ b/tools/roslaunch/src/roslaunch/loader.py @@ -492,7 +492,7 @@ def param_value(self, verbose, name, ptype, value, textfile, binfile, command): import subprocess, shlex #shlex rocks try: os_posix = os.name == "posix" - p = subprocess.Popen(shlex.split(command, posix=os_posix), stdout=subprocess.PIPE) + p = subprocess.Popen(shlex.split(command, posix=os_posix), stdout=subprocess.PIPE, shell=not os_posix) c_value = p.communicate()[0] if not isinstance(c_value, str): c_value = c_value.decode('utf-8') From ccba8e7e3abdf6e0b9e0a90ab70e02d456af747a Mon Sep 17 00:00:00 2001 From: "Sean Yen [MSFT]" Date: Wed, 17 Oct 2018 11:26:42 -0700 Subject: [PATCH 3/7] Resolved the merge again. --- tools/roslaunch/src/roslaunch/loader.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tools/roslaunch/src/roslaunch/loader.py b/tools/roslaunch/src/roslaunch/loader.py index 13c2f9a211..e70bc73be9 100644 --- a/tools/roslaunch/src/roslaunch/loader.py +++ b/tools/roslaunch/src/roslaunch/loader.py @@ -492,7 +492,9 @@ def param_value(self, verbose, name, ptype, value, textfile, binfile, command): import subprocess, shlex #shlex rocks try: os_posix = os.name == "posix" - p = subprocess.Popen(shlex.split(command, posix=os_posix), stdout=subprocess.PIPE, shell=not os_posix) + if os_posix: + command = shlex.split(command) + p = subprocess.Popen(command, stdout=subprocess.PIPE, shell=not os_posix) c_value = p.communicate()[0] if not isinstance(c_value, str): c_value = c_value.decode('utf-8') From 6e8959e165a6a74fa8430f54e704c275f9516438 Mon Sep 17 00:00:00 2001 From: James Xu Date: Thu, 21 Feb 2019 23:10:17 -0800 Subject: [PATCH 4/7] rework shell=True for Windows change (#51) * rework shell=True for Windows change * remove .exe handling, prepend python for python scripts instead * update Windows search logic * move comments around and remove unnecessary comments * minor refactor * file is a keyword in python2, rename as f * remove unnecessary \ at the end of line --- tools/roslaunch/src/roslaunch/loader.py | 42 ++++++++++++++++++++++--- 1 file changed, 38 insertions(+), 4 deletions(-) diff --git a/tools/roslaunch/src/roslaunch/loader.py b/tools/roslaunch/src/roslaunch/loader.py index e70bc73be9..4f5e200d09 100644 --- a/tools/roslaunch/src/roslaunch/loader.py +++ b/tools/roslaunch/src/roslaunch/loader.py @@ -491,10 +491,44 @@ def param_value(self, verbose, name, ptype, value, textfile, binfile, command): print("... executing command param [%s]" % command) import subprocess, shlex #shlex rocks try: - os_posix = os.name == "posix" - if os_posix: - command = shlex.split(command) - p = subprocess.Popen(command, stdout=subprocess.PIPE, shell=not os_posix) + if os.name == 'nt': + # Python scripts in ROS tend to omit .py extension since they could become executable with shebang line + # special handle the use of Python scripts in Windows environment: + # 1. search for a wrapper executable (of the same name) under the same directory with stat.S_IXUSR flag + # 2. if no wrapper is present, prepend command with 'python' executable + + cl = shlex.split(command, posix=False) # use non-posix method on Windows + if os.path.isabs(cl[0]): + # trying to launch an executable from a specific location(package), e.g. xacro + import stat + rx_flag = stat.S_IRUSR | stat.S_IXUSR + if os.path.exists(cl[0]) and os.stat(cl[0]).st_mode & rx_flag == rx_flag: + pass + else: + d = os.path.dirname(cl[0]) + files_of_same_name = [ + os.path.join(d, f) for f in os.listdir(d) + if os.path.splitext(f)[0].lower() == os.path.splitext(os.path.basename(cl[0]))[0].lower() + ] if os.path.exists(d) else [] + executable_command = None + for f in files_of_same_name: + if os.stat(f).st_mode & rx_flag == rx_flag: + # found an executable wrapper of the desired Python script + executable_command = f + + if not executable_command: + for f in files_of_same_name: + mode = os.stat(f).st_mode + if (mode & stat.S_IRUSR == stat.S_IRUSR) and (mode & stat.S_IXUSR != stat.S_IXUSR): + # when there is read permission but not execute permission, this is typically a Python script (in ROS) + if os.path.splitext(f)[1].lower() in ['.py', '']: + executable_command = ' '.join(['python', f]) + if executable_command: + command = command.replace(cl[0], executable_command, 1) + # no need to call shlex.split() on Windows, underlying CreateProcess() operates on strings + p = subprocess.Popen(command, stdout=subprocess.PIPE) + else: + p = subprocess.Popen(shlex.split(command), stdout=subprocess.PIPE) c_value = p.communicate()[0] if not isinstance(c_value, str): c_value = c_value.decode('utf-8') From b078a145b27650750eccacb0cbcd8d98eb639954 Mon Sep 17 00:00:00 2001 From: James Xu Date: Tue, 26 Feb 2019 10:12:25 -0800 Subject: [PATCH 5/7] use sys.executable to launch Python interpreter --- tools/roslaunch/src/roslaunch/loader.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/roslaunch/src/roslaunch/loader.py b/tools/roslaunch/src/roslaunch/loader.py index 4f5e200d09..7559253fe8 100644 --- a/tools/roslaunch/src/roslaunch/loader.py +++ b/tools/roslaunch/src/roslaunch/loader.py @@ -38,6 +38,7 @@ import errno import os +import sys from copy import deepcopy import yaml @@ -522,7 +523,7 @@ def param_value(self, verbose, name, ptype, value, textfile, binfile, command): if (mode & stat.S_IRUSR == stat.S_IRUSR) and (mode & stat.S_IXUSR != stat.S_IXUSR): # when there is read permission but not execute permission, this is typically a Python script (in ROS) if os.path.splitext(f)[1].lower() in ['.py', '']: - executable_command = ' '.join(['python', f]) + executable_command = ' '.join([sys.executable, f]) if executable_command: command = command.replace(cl[0], executable_command, 1) # no need to call shlex.split() on Windows, underlying CreateProcess() operates on strings From 22e1573141e9d17fe8f09209b6f5f2b6856c72fd Mon Sep 17 00:00:00 2001 From: James Xu Date: Tue, 26 Feb 2019 10:14:05 -0800 Subject: [PATCH 6/7] follow inline comment style in PEP8 --- tools/roslaunch/src/roslaunch/loader.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/roslaunch/src/roslaunch/loader.py b/tools/roslaunch/src/roslaunch/loader.py index 7559253fe8..5b04969aad 100644 --- a/tools/roslaunch/src/roslaunch/loader.py +++ b/tools/roslaunch/src/roslaunch/loader.py @@ -498,7 +498,7 @@ def param_value(self, verbose, name, ptype, value, textfile, binfile, command): # 1. search for a wrapper executable (of the same name) under the same directory with stat.S_IXUSR flag # 2. if no wrapper is present, prepend command with 'python' executable - cl = shlex.split(command, posix=False) # use non-posix method on Windows + cl = shlex.split(command, posix=False) # use non-posix method on Windows if os.path.isabs(cl[0]): # trying to launch an executable from a specific location(package), e.g. xacro import stat From 8c3f549c1714601078537350c5a0fbcebe668319 Mon Sep 17 00:00:00 2001 From: Dirk Thomas Date: Fri, 15 Mar 2019 16:18:48 -0700 Subject: [PATCH 7/7] invert logic --- tools/roslaunch/src/roslaunch/loader.py | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/tools/roslaunch/src/roslaunch/loader.py b/tools/roslaunch/src/roslaunch/loader.py index 5b04969aad..a7671c64d9 100644 --- a/tools/roslaunch/src/roslaunch/loader.py +++ b/tools/roslaunch/src/roslaunch/loader.py @@ -492,7 +492,9 @@ def param_value(self, verbose, name, ptype, value, textfile, binfile, command): print("... executing command param [%s]" % command) import subprocess, shlex #shlex rocks try: - if os.name == 'nt': + if os.name != 'nt': + command = shlex.split(command) + else: # Python scripts in ROS tend to omit .py extension since they could become executable with shebang line # special handle the use of Python scripts in Windows environment: # 1. search for a wrapper executable (of the same name) under the same directory with stat.S_IXUSR flag @@ -503,9 +505,7 @@ def param_value(self, verbose, name, ptype, value, textfile, binfile, command): # trying to launch an executable from a specific location(package), e.g. xacro import stat rx_flag = stat.S_IRUSR | stat.S_IXUSR - if os.path.exists(cl[0]) and os.stat(cl[0]).st_mode & rx_flag == rx_flag: - pass - else: + if not os.path.exists(cl[0]) or os.stat(cl[0]).st_mode & rx_flag != rx_flag: d = os.path.dirname(cl[0]) files_of_same_name = [ os.path.join(d, f) for f in os.listdir(d) @@ -526,10 +526,7 @@ def param_value(self, verbose, name, ptype, value, textfile, binfile, command): executable_command = ' '.join([sys.executable, f]) if executable_command: command = command.replace(cl[0], executable_command, 1) - # no need to call shlex.split() on Windows, underlying CreateProcess() operates on strings - p = subprocess.Popen(command, stdout=subprocess.PIPE) - else: - p = subprocess.Popen(shlex.split(command), stdout=subprocess.PIPE) + p = subprocess.Popen(command, stdout=subprocess.PIPE) c_value = p.communicate()[0] if not isinstance(c_value, str): c_value = c_value.decode('utf-8')