Package roslaunch :: Module node_args
[frames] | no frames]

Source Code for Module roslaunch.node_args

  1  # Software License Agreement (BSD License) 
  2  # 
  3  # Copyright (c) 2009, Willow Garage, Inc. 
  4  # All rights reserved. 
  5  # 
  6  # Redistribution and use in source and binary forms, with or without 
  7  # modification, are permitted provided that the following conditions 
  8  # are met: 
  9  # 
 10  #  * Redistributions of source code must retain the above copyright 
 11  #    notice, this list of conditions and the following disclaimer. 
 12  #  * Redistributions in binary form must reproduce the above 
 13  #    copyright notice, this list of conditions and the following 
 14  #    disclaimer in the documentation and/or other materials provided 
 15  #    with the distribution. 
 16  #  * Neither the name of Willow Garage, Inc. nor the names of its 
 17  #    contributors may be used to endorse or promote products derived 
 18  #    from this software without specific prior written permission. 
 19  # 
 20  # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
 21  # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
 22  # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
 23  # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 
 24  # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 
 25  # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 
 26  # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
 27  # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
 28  # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
 29  # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 
 30  # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
 31  # POSSIBILITY OF SUCH DAMAGE. 
 32  # 
 33  # Revision $Id$ 
 34   
 35  from __future__ import print_function 
 36   
 37  """ 
 38  Utility module of roslaunch that computes the command-line arguments 
 39  for a node. 
 40  """ 
 41   
 42  import logging 
 43  import os 
 44  import shlex 
 45  import sys 
 46  import time 
 47   
 48  import rospkg 
 49  import rosgraph 
 50  import rosgraph.names 
 51  from rosgraph.names import script_resolve_name 
 52   
 53  import roslib.packages 
 54   
 55  from . import substitution_args 
 56   
 57  from roslaunch.core import setup_env, local_machine, RLException 
 58  from roslaunch.config import load_config_default 
 59  import roslaunch.xmlloader 
 60   
61 -class NodeParamsException(Exception):
62 """ 63 Exception to indicate that node parameters were invalid 64 """ 65 pass
66
67 -def get_node_list(config):
68 """ 69 @param config: roslaunch config 70 @type config: ROSLaunchConfig 71 @return: list of node names in config 72 @rtype: [str] 73 """ 74 l = [_resolved_name(node) for node in config.nodes] + [_resolved_name(test) for test in config.tests] 75 # filter out unnamed nodes 76 return [x for x in l if x]
77 94 118
119 -def _resolved_name(node):
120 if node.name: 121 # $(anon id) passthrough 122 if node.name.startswith('$'): 123 return node.name 124 else: 125 return rosgraph.names.ns_join(node.namespace, node.name) 126 else: 127 return None
128 149
150 -def get_node_args(node_name, roslaunch_files):
151 """ 152 Get the node arguments for a node in roslaunch_files. 153 154 @param node_name: name of node in roslaunch_files. 155 @type node_name: str 156 @param roslaunch_files: roslaunch file names 157 @type roslaunch_files: [str] 158 @return: list of command-line arguments used to launch node_name 159 @rtype: [str] 160 @raise RLException: if node args cannot be retrieved 161 """ 162 163 # we have to create our own XmlLoader so that we can use the same 164 # resolution context for substitution args 165 166 loader = roslaunch.xmlloader.XmlLoader(resolve_anon=False) 167 config = load_config_default(roslaunch_files, None, loader=loader, verbose=False, assign_machines=False) 168 (node_name) = substitution_args.resolve_args((node_name), resolve_anon=False) 169 node_name = script_resolve_name('roslaunch', node_name) if not node_name.startswith('$') else node_name 170 171 node = [n for n in config.nodes if _resolved_name(n) == node_name] + \ 172 [n for n in config.tests if _resolved_name(n) == node_name] 173 if not node: 174 node_list = get_node_list(config) 175 node_list_str = '\n'.join([" * %s"%x for x in node_list]) 176 raise RLException("ERROR: Cannot find node named [%s] in [%s].\nNode names are:\n%s"%(node_name, ', '.join(roslaunch_files), node_list_str)) 177 elif len(node) > 1: 178 raise RLException("ERROR: multiple nodes named [%s] in [%s].\nPlease fix the launch files as duplicate names are not allowed."%(node_name, ', '.join(roslaunch_files))) 179 node = node[0] 180 181 master_uri = rosgraph.get_master_uri() 182 machine = local_machine() 183 env = setup_env(node, machine, master_uri) 184 185 # remove setting identical to current environment for easier debugging 186 to_remove = [] 187 for k in env.keys(): 188 if env[k] == os.environ.get(k, None): 189 to_remove.append(k) 190 for k in to_remove: 191 del env[k] 192 193 # resolve node name for generating args 194 args = create_local_process_args(node, machine) 195 if sys.platform == "win32": 196 # set command can be used with environment variables that contain space without double quotes 197 # https://ss64.com/nt/set.html 198 return ["set %s=%s&&"%(k, v) for k, v in env.items()] + args 199 else: 200 # sys.platform.startswith('linux') 201 # join environment vars are bash prefix args, wrap with double quotes for variables that contains space 202 return ['%s="%s"'%(k, v) for k, v in env.items()] + args
203
204 -def _launch_prefix_args(node):
205 if node.launch_prefix: 206 prefix = node.launch_prefix 207 try: 208 if type(prefix) == unicode: 209 prefix = prefix.encode('UTF-8') 210 except NameError: 211 pass 212 os_posix = os.name == "posix" 213 return shlex.split(prefix, posix=os_posix) 214 else: 215 return []
216 217 _rospack = None 218 219
220 -def create_local_process_args(node, machine, env=None):
221 """ 222 Subroutine for creating node arguments. 223 224 :param env: override os.environ. Warning, this does not override 225 substitution args in node configuration (for now), ``dict`` 226 :returns: arguments for node process, ``[str]`` 227 :raises: :exc:`NodeParamsException` If args cannot be constructed for Node 228 as specified (e.g. the node type does not exist) 229 """ 230 global _rospack 231 if not node.name: 232 raise ValueError("node name must be defined") 233 # create rospack instance if no cached value is available or for custom environments 234 if not _rospack or env is not None: 235 rospack = rospkg.RosPack(rospkg.get_ros_paths(env=env)) 236 # cache rospack instance for default environment 237 if env is None: 238 _rospack = rospack 239 else: 240 rospack = _rospack 241 242 # - Construct rosrun command 243 remap_args = ["%s:=%s"%(src,dst) for src, dst in node.remap_args] 244 resolve_dict = {} 245 246 #resolve args evaluates substitution commands 247 #shlex parses a command string into a list of args 248 # - for the local process args, we *do* resolve the anon tag so that the user can execute 249 # - the node name and args must be resolved together in case the args refer to the anon node name 250 (node_name) = substitution_args.resolve_args((node.name), context=resolve_dict, resolve_anon=True) 251 node.name = node_name 252 remap_args.append('__name:=%s'%node_name) 253 254 resolved = substitution_args.resolve_args(node.args, context=resolve_dict, resolve_anon=True) 255 try: 256 if type(resolved) == unicode: 257 resolved = resolved.encode('UTF-8') #attempt to force to string for shlex/subprocess 258 except NameError: 259 pass 260 os_posix = os.name == "posix" 261 args = shlex.split(resolved, posix=os_posix) + remap_args 262 try: 263 #TODO:fuerte: pass through rospack and catkin cache 264 matches = roslib.packages.find_node(node.package, node.type, rospack=rospack) 265 except rospkg.ResourceNotFound as e: 266 # multiple nodes, invalid package 267 raise NodeParamsException(str(e)) 268 if not matches: 269 raise NodeParamsException("Cannot locate node of type [%s] in package [%s]. Make sure file exists in package path and permission is set to executable (chmod +x)"%(node.type, node.package)) 270 else: 271 # old behavior was to take first, do we want to change this in Fuerte-style? 272 cmd = matches[0] 273 if not cmd: 274 raise NodeParamsException("Cannot locate node of type [%s] in package [%s]"%(node.type, node.package)) 275 cmd = [cmd] 276 277 # Python scripts in ROS tend to omit .py extension since they could become executable 278 # by adding a shebang line (#!/usr/bin/env python) in Linux environments 279 # special handle this case by executing the script with the Python executable in Windows environment 280 if sys.platform in ['win32'] and os.path.splitext(cmd[0])[1].lower() in ['.py', '']: 281 cmd = ['python'] + cmd 282 return _launch_prefix_args(node) + cmd + args
283