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

Source Code for Module roshlaunch.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: node_args.py 10269 2010-07-07 00:07:15Z kwc $ 
 34   
 35  """ 
 36  Utility module of roslaunch that computes the command-line arguments 
 37  for a node. 
 38  """ 
 39   
 40  import logging 
 41  import os 
 42  import shlex 
 43  import sys 
 44  import time 
 45   
 46  import roslib.packages 
 47  import roslib.rosenv 
 48  import roslib.substitution_args 
 49  from roslib.scriptutil import script_resolve_name 
 50   
 51  from roslaunch.core import setup_env, local_machine, RLException 
 52  from roslaunch.config import load_config_default 
 53  import roslaunch.xmlloader 
 54   
55 -class NodeParamsException(Exception):
56 """ 57 Exception to indicate that node parameters were invalid 58 """ 59 pass
60
61 -def get_node_list(config):
62 """ 63 @param config: roslaunch config 64 @type config: ROSLaunchConfig 65 @return: list of node names in config 66 @rtype: [str] 67 """ 68 l = [_resolved_name(node) for node in config.nodes] + [_resolved_name(test) for test in config.tests] 69 # filter out unnamed nodes 70 return [x for x in l if x]
71 88 107
108 -def _resolved_name(node):
109 if node.name: 110 # $(anon id) passthrough 111 if node.name.startswith('$'): 112 return node.name 113 else: 114 return roslib.names.ns_join(node.namespace, node.name) 115 else: 116 return None
117 138
139 -def get_node_args(node_name, roslaunch_files):
140 """ 141 Get the node arguments for a node in roslaunch_files. 142 143 @param node_name: name of node in roslaunch_files. 144 @type node_name: str 145 @param roslaunch_files: roslaunch file names 146 @type roslaunch_files: [str] 147 @return: list of command-line arguments used to launch node_name 148 @rtype: [str] 149 @raise RLException: if node args cannot be retrieved 150 """ 151 152 # we have to create our own XmlLoader so that we can use the same 153 # resolution context for substitution args 154 155 loader = roslaunch.xmlloader.XmlLoader(resolve_anon=False) 156 config = load_config_default(roslaunch_files, None, loader=loader, verbose=False, assign_machines=False) 157 (node_name) = roslib.substitution_args.resolve_args((node_name), resolve_anon=False) 158 node_name = script_resolve_name('roslaunch', node_name) if not node_name.startswith('$') else node_name 159 160 node = [n for n in config.nodes if _resolved_name(n) == node_name] + \ 161 [n for n in config.tests if _resolved_name(n) == node_name] 162 if not node: 163 node_list = get_node_list(config) 164 node_list_str = '\n'.join([" * %s"%x for x in node_list]) 165 raise RLException("ERROR: Cannot find node named [%s] in [%s].\nNode names are:\n%s"%(node_name, ', '.join(roslaunch_files), node_list_str)) 166 elif len(node) > 1: 167 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))) 168 node = node[0] 169 170 master_uri = roslib.rosenv.get_master_uri() 171 machine = local_machine() 172 173 # don't use create_local_process_env, which merges the env with the full env of the shell 174 env = setup_env(node, machine, master_uri) 175 to_remove = [] 176 for k in env.iterkeys(): 177 if env[k] == os.environ.get(k, None): 178 to_remove.append(k) 179 for k in to_remove: 180 del env[k] 181 182 # resolve node name for generating args 183 args = create_local_process_args(node, machine) 184 # join environment vars are bash prefix args 185 return ["%s=%s"%(k, v) for k, v in env.iteritems()] + args
186
187 -def create_local_process_env(node, machine, master_uri, env=os.environ):
188 """ 189 Setup environment for locally launched process. The local 190 environment includes the default os environment, with any 191 ROS-specific environment variables overriding this enviornment. 192 @return: environment variables 193 @rtype: dict 194 """ 195 196 # #1029: generate environment for the node. unset 197 # #ROS-related environment vars before 198 # update() so that extra environment variables don't end 199 # up in the call. 200 full_env = env.copy() 201 202 for evar in [ 203 roslib.rosenv.ROS_MASTER_URI, 204 roslib.rosenv.ROS_ROOT, 205 roslib.rosenv.ROS_PACKAGE_PATH, 206 roslib.rosenv.ROS_IP, 207 'PYTHONPATH', 208 roslib.rosenv.ROS_NAMESPACE]: 209 if evar in full_env: 210 del full_env[evar] 211 212 proc_env = setup_env(node, machine, master_uri) 213 214 # #2372: add ROS_ROOT/bin to path if it is not present 215 rosroot_bin = os.path.join(roslib.rosenv.get_ros_root(), 'bin') 216 path = os.environ.get('PATH', '') 217 if not rosroot_bin in path.split(os.pathsep): 218 proc_env['PATH'] = path + os.pathsep + rosroot_bin 219 220 full_env.update(proc_env) 221 return full_env
222
223 -def _launch_prefix_args(node):
224 if node.launch_prefix: 225 prefix = node.launch_prefix 226 if type(prefix) == unicode: 227 prefix = prefix.encode('UTF-8') 228 return shlex.split(prefix) 229 else: 230 return []
231
232 -def create_local_process_args(node, machine):
233 """ 234 Subroutine for creating node arguments. 235 @return: arguments for node process 236 @rtype: [str] 237 @raise NodeParamsException: if args cannot be constructed for Node 238 as specified (e.g. the node type does not exist) 239 """ 240 if not node.name: 241 raise ValueError("node name must be defined") 242 243 # - Construct rosrun command 244 remap_args = ["%s:=%s"%(src,dst) for src, dst in node.remap_args] 245 resolve_dict = {} 246 247 #resolve args evaluates substitution commands 248 #shlex parses a command string into a list of args 249 # - for the local process args, we *do* resolve the anon tag so that the user can execute 250 # - the node name and args must be resolved together in case the args refer to the anon node name 251 (node_name) = roslib.substitution_args.resolve_args((node.name), context=resolve_dict, resolve_anon=True) 252 node.name = node_name 253 remap_args.append('__name:=%s'%node_name) 254 255 resolved = roslib.substitution_args.resolve_args(node.args, context=resolve_dict, resolve_anon=True) 256 if type(resolved) == unicode: 257 resolved = resolved.encode('UTF-8') #attempt to force to string for shlex/subprocess 258 args = shlex.split(resolved) + remap_args 259 260 start_t = time.time() 261 try: 262 cmd = roslib.packages.find_node(node.package, node.type,\ 263 machine.ros_root, machine.ros_package_path) 264 except roslib.packages.ROSPkgException, e: 265 # multiple nodes, invalid package 266 raise NodeParamsException(str(e)) 267 end_t = time.time() 268 logging.getLogger('roslaunch.node_args').info('find_node(%s, %s, %s, %s) took %ss'%(node.package, node.type, machine.ros_root, machine.ros_package_path, (end_t - start_t))) 269 if not cmd: 270 raise NodeParamsException("Cannot locate node of type [%s] in package [%s]"%(node.type, node.package)) 271 return _launch_prefix_args(node) + [cmd] + args
272