Package rosmsg
[frames] | no frames]

Source Code for Package rosmsg

  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  """ 
 34  Implements rosmsg/rossrv command-line tools. 
 35   
 36  The code API of the rosmsg module is unstable.  
 37  """ 
 38   
 39  from __future__ import print_function 
 40   
 41  import collections 
 42  import inspect 
 43  import os 
 44  import sys 
 45  import yaml 
 46   
 47  from catkin.find_in_workspaces import find_in_workspaces 
 48   
 49  import rospkg 
 50  import genmsg 
 51   
 52  import roslib.message 
 53  import rosbag 
 54   
 55  from optparse import OptionParser 
 56   
 57  MODE_MSG = '.msg' 
 58  MODE_SRV = '.srv' 
 59   
60 -class ROSMsgException(Exception): pass
61 -class RosMsgProtoException(Exception): pass
62 -class RosMsgProtoArgsException(Exception): pass
63 64 # If flowtype chosen is default, instead use flow-style 65 # False except if meeting objects or arrays with more than 66 # this size of sub-elements 67 MAX_DEFAULT_NON_FLOW_ITEMS = 4 68 69 ## copied from the web, recipe for ordered yaml output ######
70 -def construct_ordered_mapping(self, node, deep=False):
71 if not isinstance(node, yaml.MappingNode): 72 raise yaml.constructor.ConstructorError(None, None, 73 "expected a mapping node, but found %s" % node.id, 74 node.start_mark) 75 mapping = collections.OrderedDict() 76 for key_node, value_node in node.value: 77 key = self.construct_object(key_node, deep=deep) 78 if not isinstance(key, collections.Hashable): 79 raise yaml.constructor.ConstructorError("while constructing a mapping", node.start_mark, 80 "found unhashable key", key_node.start_mark) 81 value = self.construct_object(value_node, deep=deep) 82 mapping[key] = value 83 return mapping
84
85 -def construct_yaml_map_with_ordered_dict(self, node):
86 data = collections.OrderedDict() 87 yield data 88 value = self.construct_mapping(node) 89 data.update(value)
90
91 -def represent_ordered_mapping(self, tag, mapping, flow_style=None):
92 value = [] 93 node = yaml.MappingNode(tag, value, flow_style=flow_style) 94 if self.alias_key is not None: 95 self.represented_objects[self.alias_key] = node 96 best_style = True 97 if hasattr(mapping, 'items'): 98 mapping = list(mapping.items()) 99 for item_key, item_value in mapping: 100 node_key = self.represent_data(item_key) 101 node_value = self.represent_data(item_value) 102 if not (isinstance(node_key, yaml.ScalarNode) and not node_key.style): 103 best_style = False 104 if not (isinstance(node_value, yaml.ScalarNode) and not node_value.style): 105 best_style = False 106 value.append((node_key, node_value)) 107 if flow_style is None: 108 if self.default_flow_style is not None: 109 node.flow_style = self.default_flow_style 110 else: 111 node.flow_style = best_style 112 return node
113 114 ## end recipe for ordered yaml output ###### 115 116
117 -def get_array_type_instance(field_type, default_package = None):
118 """ 119 returns a single instance of field_type, where field_type can be a 120 message or ros primitive or an flexible size array. 121 """ 122 field_type = field_type.strip().rstrip("[]") 123 if field_type == "empty": 124 return None 125 if not "/" in field_type: 126 # is either built-in, Header, or in same package 127 # it seems built-in types get a priority 128 if field_type in ['byte', 'int8', 'int16', 'int32', 'int64',\ 129 'char', 'uint8', 'uint16', 'uint32', 'uint64']: 130 return 0 131 elif field_type in ['float32', 'float64']: 132 return 0 133 elif field_type in ['string']: 134 return "" 135 elif field_type == 'bool': 136 return False 137 elif field_type == 'time': 138 field_type = "std_msgs/Time" 139 elif field_type == 'duration': 140 field_type = "std_msgs/Duration" 141 elif field_type == 'Header': 142 field_type = "std_msgs/Header" 143 else: 144 if default_package is None: 145 return None 146 field_type = default_package + "/" + field_type 147 msg_class = roslib.message.get_message_class(field_type) 148 if (msg_class == None): 149 # not important enough to raise exception? 150 return None 151 instance = msg_class() 152 return instance
153
154 -def get_yaml_for_msg(msg, prefix='', time_offset=None, current_time=None, field_filter=None, flow_style_ = None, fill_arrays_ = False):
155 """ 156 Builds a YAML string of message. 157 @param msg: A object, dict or array 158 @param flow_style_: if True, produces one line with brackets, if false uses multiple lines with indentation, if None uses both using heuristics 159 @param prefix: prefixes all lines with this string 160 @param fill_arrays_: if True, for all flexible size arrays an element will be generated 161 @param current_time: currently not used. Only provided for API compatibility. current_time passes in the current time with respect to the message. 162 @type current_time: Time 163 @param field_filter: filter the fields that are strified for Messages. 164 @type field_filter: fn(Message)->iter(str) 165 @type flow_style_: bool 166 @return: a string 167 """ 168 def object_representer(dumper, obj): 169 ndict = collections.OrderedDict() 170 index = 0 171 # allow caller to select which fields of message are strified 172 if field_filter != None: 173 fields = list(field_filter(obj)) 174 else: 175 fields = obj.__slots__ 176 for key in fields: 177 if not key.startswith('_'): 178 val = getattr(obj, key) 179 if type(val) == list and len(val) > MAX_DEFAULT_NON_FLOW_ITEMS: 180 dumper.default_flow_style = flow_style_ 181 if time_offset is not None and isinstance(val, Time): 182 ndict[key] = val-time_offset 183 # create initial array element (e.g. for code completion) 184 elif fill_arrays_ == True and val == []: 185 message_type = obj._slot_types[index] 186 if (obj._type != None) and "/" in obj._type: 187 def_pack = obj._type.split("/")[0] 188 instance = get_array_type_instance(message_type, default_package = def_pack) 189 if instance == None: 190 # not important enough to raise exception? 191 ndict[key] = val 192 else: 193 ndict[key] = [instance] 194 elif not inspect.ismethod(val) and not inspect.isfunction(val): 195 ndict[key] = val 196 index += 1 197 # as a hack, we improve the heuristics of pyyaml and say with less than 5 objects, no need for brackets 198 if len(ndict) > MAX_DEFAULT_NON_FLOW_ITEMS: 199 dumper.default_flow_style = flow_style_ 200 return dumper.represent_dict(ndict)
201 yaml.representer.SafeRepresenter.add_representer(None, object_representer) 202 203 # we force False over None here and set the style in dumper, to 204 # avoid unecessary outer brackets pyyaml chooses e.g. to 205 # represent msg Int32 as "{data: 0}" 206 initial_flow_style = False 207 if flow_style_ == True: 208 initial_flow_style = True 209 210 # need to set default flow style True for bash prototype 211 # means will generate one line with [] and {} brackets 212 # bash needs bracket notation for rostopic pub 213 txt = yaml.safe_dump(msg, 214 # None, True, False (None chooses a compromise) 215 default_flow_style = initial_flow_style, 216 # Can be None, '', '\'', '"', '|', '>'. 217 default_style = '', 218 #indent=2, #>=2, indentation depth 219 #line_break=?, 220 #allow_unicode=?, 221 #if true writes plenty of tags 222 #canonical = False, 223 #version={}?, 224 #width=40, 225 #encoding=?, 226 #tags={}?, 227 # when True, produces --- at start 228 #explicit_start=False, 229 # when True, produces ... at end 230 #explicit_end=False 231 ) 232 if prefix != None and prefix != '': 233 result = prefix + ("\n"+prefix).join(txt.splitlines()) 234 else: 235 result = txt.rstrip('\n') 236 return result 237 238
239 -def create_names_filter(names):
240 """ 241 returns a function to use as filter that returns all objects slots except those with names in list. 242 """ 243 return lambda obj : filter(lambda slotname : not slotname in names, obj.__slots__)
244 245
246 -def init_rosmsg_proto():
247 if "OrderedDict" in collections.__dict__: 248 yaml.constructor.BaseConstructor.construct_mapping = construct_ordered_mapping 249 yaml.constructor.Constructor.add_constructor( 250 'tag:yaml.org,2002:map', 251 construct_yaml_map_with_ordered_dict) 252 253 yaml.representer.BaseRepresenter.represent_mapping = represent_ordered_mapping 254 yaml.representer.Representer.add_representer(collections.OrderedDict, 255 yaml.representer.SafeRepresenter.represent_dict)
256
257 -def rosmsg_cmd_prototype(args):
258 init_rosmsg_proto() 259 parser = OptionParser(usage="usage: rosmsgproto msg/srv [options]", 260 description="Produces output or a msg or service request, intended for tab completion support.") 261 parser.add_option("-f","--flow_style", 262 dest="flow_style", type="int", default=None, action="store", 263 help="if 1 always use brackets, if 0 never use brackets. Default is a heuristic mix.") 264 parser.add_option("-e","--empty-arrays", 265 dest="empty_arrays", default=False, action="store_true", 266 help="if true flexible size arrays are not filled with default instance") 267 parser.add_option("-s","--silent", 268 dest="silent", default=False, action="store_true", 269 help="if true supresses all error messages") 270 parser.add_option("-p", "--prefix", metavar="prefix", default="", 271 help="prefix to print before each line, can be used for indent") 272 parser.add_option("-H","--no-hyphens", 273 dest="no_hyphens", default="", action="store_true", 274 help="if true output has no outer hyphens") 275 parser.add_option("-x", "--exclude-slots", metavar="exclude_slots", default="", 276 help="comma separated list of slot names not to print") 277 278 options, args = parser.parse_args(args) 279 280 try: 281 if len(args) < 2: 282 raise RosMsgProtoArgsException("Insufficient arguments") 283 mode = ".%s"%args[0] 284 message_type=args[1] 285 field_filter = None 286 if options.exclude_slots != None and options.exclude_slots.strip() != "": 287 field_filter = create_names_filter(options.exclude_slots.split(',')) 288 289 # possible extentions: options for 290 # - target language 291 # - initial values for standard types 292 # - get partial message (subtree) 293 294 # try to catch the user specifying code-style types and error 295 if '::' in message_type: 296 if not options.silent: 297 parser.error("rosmsgproto does not understand C++-style namespaces (i.e. '::').\nPlease refer to msg/srv types as 'package_name/Type'.") 298 elif '.' in message_type: 299 if not options.silent: 300 parser.error("invalid message type '%s'.\nPlease refer to msg/srv types as 'package_name/Type'." % message_type) 301 if not '/' in message_type: 302 # if only one such msg or srv exists, use it 303 results = [] 304 for found in rosmsg_search(rospkg.RosPack(), mode, message_type): 305 results.append(found) 306 if len(results) > 1: 307 raise RosMsgProtoException("Ambiguous message name %s"%message_type) 308 elif len(results) < 1: 309 raise RosMsgProtoException("Unknown message name %s"%message_type) 310 else: 311 message_type=results[0] 312 313 if mode == MODE_SRV: 314 msg_class = roslib.message.get_service_class(message_type) 315 if (msg_class == None): 316 raise RosMsgProtoException("Unknown service class: %s"%message_type) 317 instance = msg_class()._request_class() 318 elif mode == MODE_MSG: 319 msg_class = roslib.message.get_message_class(message_type) 320 if (msg_class == None): 321 raise RosMsgProtoException("Unknown message class: %s"%message_type) 322 instance = msg_class() 323 else: 324 raise RosMsgProtoException("Invalid mode: %s"%mode) 325 txt = get_yaml_for_msg(instance, 326 prefix = options.prefix, 327 flow_style_ = options.flow_style, 328 fill_arrays_ = not options.empty_arrays, 329 field_filter = field_filter) 330 331 if options.no_hyphens == True: 332 return txt 333 else: 334 return '"' + txt + '"' 335 336 except KeyError as e: 337 if not options.silent: 338 sys.stderr.write("Unknown message type: %s"%e, file=sys.stderr) 339 sys.exit(getattr(os, 'EX_USAGE', 1)) 340 # except rospkg.InvalidROSPkgException as e: 341 # if not options.silent: 342 # print(file=sys.stderr, "Invalid package: '%s'"%e) 343 # sys.exit(getattr(os, 'EX_USAGE', 1)) 344 except ValueError as e: 345 if not options.silent: 346 sys.stderr.write("Invalid type: '%s'"%e) 347 sys.exit(getattr(os, 'EX_USAGE', 1)) 348 except RosMsgProtoException as e: 349 if not options.silent: 350 sys.stderr.write(str(e)) 351 sys.exit(1) 352 except RosMsgProtoArgsException as e: 353 if not options.silent: 354 sys.stderr.write("%s"%e) 355 sys.exit(getattr(os, 'EX_USAGE', 1)) 356 except KeyboardInterrupt: 357 pass
358 359 #### Start of rosmsg #### 360 361 try: 362 from cStringIO import StringIO # Python 2.x 363 except ImportError: 364 from io import StringIO # Python 3.x
365 -def spec_to_str(msg_context, spec, buff=None, indent=''):
366 """ 367 Convert spec into a string representation. Helper routine for MsgSpec. 368 :param indent: internal use only, ``str`` 369 :param buff: internal use only, ``StringIO`` 370 :returns: string representation of spec, ``str`` 371 """ 372 if buff is None: 373 buff = StringIO() 374 for c in spec.constants: 375 buff.write("%s%s %s=%s\n"%(indent, c.type, c.name, c.val_text)) 376 for type_, name in zip(spec.types, spec.names): 377 buff.write("%s%s %s\n"%(indent, type_, name)) 378 base_type = genmsg.msgs.bare_msg_type(type_) 379 if not base_type in genmsg.msgs.BUILTIN_TYPES: 380 subspec = msg_context.get_registered(base_type) 381 spec_to_str(msg_context, subspec, buff, indent + ' ') 382 return buff.getvalue()
383
384 -def get_srv_text(type_, raw=False, rospack=None):
385 """ 386 Get .srv file for type_ as text 387 :param type_: service type, ``str`` 388 :param raw: if True, include comments and whitespace (default False), ``bool`` 389 :returns: text of .srv file, ``str`` 390 @raise ROSMsgException: if type_ is unknown 391 """ 392 if rospack is None: 393 rospack = rospkg.RosPack() 394 srv_search_path = {} 395 msg_search_path = {} 396 for p in rospack.list(): 397 package_paths = _get_package_paths(p, rospack) 398 msg_search_path[p] = [os.path.join(d, 'msg') for d in package_paths] 399 srv_search_path[p] = [os.path.join(d, 'srv') for d in package_paths] 400 401 #TODO: cache context somewhere 402 context = genmsg.MsgContext.create_default() 403 try: 404 spec = genmsg.load_srv_by_type(context, type_, srv_search_path) 405 genmsg.load_depends(context, spec, msg_search_path) 406 except Exception as e: 407 raise ROSMsgException("Unknown srv type [%s]: %s"%(type_, e)) 408 409 if raw: 410 return spec.text 411 else: 412 return spec_to_str(context, spec.request)+'---\n'+spec_to_str(context, spec.response)
413
414 -def get_msg_text(type_, raw=False, rospack=None):
415 """ 416 Get .msg file for type_ as text 417 :param type_: message type, ``str`` 418 :param raw: if True, include comments and whitespace (default False), ``bool`` 419 :returns: text of .msg file, ``str`` 420 :raises :exc:`ROSMsgException` If type_ is unknown 421 """ 422 if rospack is None: 423 rospack = rospkg.RosPack() 424 search_path = {} 425 for p in rospack.list(): 426 package_paths = _get_package_paths(p, rospack) 427 search_path[p] = [os.path.join(d, 'msg') for d in package_paths] 428 429 context = genmsg.MsgContext.create_default() 430 try: 431 spec = genmsg.load_msg_by_type(context, type_, search_path) 432 genmsg.load_depends(context, spec, search_path) 433 except Exception as e: 434 raise ROSMsgException("Unable to load msg [%s]: %s"%(type_, e)) 435 436 if raw: 437 return spec.text 438 else: 439 return spec_to_str(context, spec)
440
441 -def rosmsg_debug(rospack, mode, type_, raw=False):
442 """ 443 Prints contents of msg/srv file 444 :param mode: MODE_MSG or MODE_SRV, ``str`` 445 """ 446 if mode == MODE_SRV: 447 print(get_srv_text(type_, raw=raw, rospack=rospack)) 448 elif mode == MODE_MSG: 449 print(get_msg_text(type_, raw=raw, rospack=rospack)) 450 else: 451 raise ROSMsgException("Invalid mode for debug: %s"%mode)
452
453 -def list_srvs(package, rospack=None):
454 """ 455 List srvs contained in package 456 :param package: package name, ``str`` 457 :param rospack: an optional rospack instance to be reused, ``rospkg.RosPack`` 458 :returns: list of srvs in package, ``[str]`` 459 """ 460 return list_types(package, mode=MODE_SRV, rospack=rospack)
461
462 -def list_msgs(package, rospack=None):
463 """ 464 List msgs contained in package 465 :param package: package name, ``str`` 466 :param rospack: an optional rospack instance to be reused, ``rospkg.RosPack`` 467 :returns: list of msgs in package, ``[str]`` 468 """ 469 return list_types(package, rospack=rospack)
470
471 -def list_types(package, mode=MODE_MSG, rospack=None):
472 """ 473 Lists msg/srvs contained in package 474 :param package: package name, ``str`` 475 :param mode: MODE_MSG or MODE_SRV. Defaults to msgs, ``str`` 476 :param rospack: an optional rospack instance to be reused, ``rospkg.RosPack`` 477 :returns: list of msgs/srv in package, ``[str]`` 478 """ 479 if rospack is None: 480 rospack = rospkg.RosPack() 481 if mode == MODE_MSG: 482 subdir = 'msg' 483 elif mode == MODE_SRV: 484 subdir = 'srv' 485 else: 486 raise ValueError('Unknown mode for list_types: %s'%mode) 487 488 path = os.path.join(rospack.get_path(package), subdir) 489 490 return [genmsg.resource_name(package, t) for t in _list_types(path, subdir, mode)]
491
492 -def _msg_filter(ext):
493 def mfilter(f): 494 """ 495 Predicate for filtering directory list. matches message files 496 :param f: filename, ``str`` 497 """ 498 return os.path.isfile(f) and f.endswith(ext)
499 return mfilter 500
501 -def _list_types(path, subdir, ext):
502 """ 503 List all messages in the specified package 504 :param package str: name of package to search 505 :param include_depends bool: if True, will also list messages in package dependencies 506 :returns [str]: message type names 507 """ 508 types = _list_resources(path, _msg_filter(ext)) 509 result = [x[:-len(ext)] for x in types] 510 result.sort() 511 return result
512
513 -def _list_resources(path, rfilter=os.path.isfile):
514 """ 515 List resources in a package directory within a particular 516 subdirectory. This is useful for listing messages, services, etc... 517 :param rfilter: resource filter function that returns true if filename is the desired resource type, ``fn(filename)->bool`` 518 """ 519 resources = [] 520 if os.path.isdir(path): 521 resources = [f for f in os.listdir(path) if rfilter(os.path.join(path, f))] 522 else: 523 resources = [] 524 return resources
525
526 -def iterate_packages(rospack, mode):
527 """ 528 Iterator for packages that contain messages/services 529 :param mode: .msg or .srv, ``str`` 530 """ 531 if mode == MODE_MSG: 532 subdir = 'msg' 533 elif mode == MODE_SRV: 534 subdir = 'srv' 535 else: 536 raise ValueError('Unknown mode for iterate_packages: %s'%mode) 537 538 pkgs = rospack.list() 539 for p in pkgs: 540 package_paths = _get_package_paths(p, rospack) 541 for package_path in package_paths: 542 d = os.path.join(package_path, subdir) 543 if os.path.isdir(d): 544 yield p, d
545 546 _catkin_workspace_to_source_spaces = {} 547 _catkin_source_path_to_packages = {} 548
549 -def _get_package_paths(pkgname, rospack):
550 paths = [] 551 path = rospack.get_path(pkgname) 552 paths.append(path) 553 results = find_in_workspaces(search_dirs=['share'], project=pkgname, first_match_only=True, workspace_to_source_spaces=_catkin_workspace_to_source_spaces, source_path_to_packages=_catkin_source_path_to_packages) 554 if results and results[0] != path: 555 paths.append(results[0]) 556 return paths
557
558 -def rosmsg_search(rospack, mode, base_type):
559 """ 560 Iterator for all packages that contain a message matching base_type 561 562 :param base_type: message base type to match, e.g. 'String' would match std_msgs/String, ``str`` 563 """ 564 for p, path in iterate_packages(rospack, mode): 565 if os.path.isfile(os.path.join(path, "%s%s"%(base_type, mode))): 566 yield genmsg.resource_name(p, base_type)
567
568 -def _stdin_arg(parser, full):
569 options, args = parser.parse_args(sys.argv[2:]) 570 # read in args from stdin pipe if not present 571 if not args: 572 arg = None 573 while not arg: 574 arg = sys.stdin.readline().strip() 575 return options, arg 576 else: 577 if len(args) > 1: 578 parser.error("you may only specify one %s"%full) 579 return options, args[0]
580
581 -def rosmsg_cmd_show(mode, full):
582 cmd = "ros%s"%(mode[1:]) 583 parser = OptionParser(usage="usage: %s show [options] <%s>"%(cmd, full)) 584 parser.add_option("-r", "--raw", 585 dest="raw", default=False,action="store_true", 586 help="show raw message text, including comments") 587 parser.add_option("-b", "--bag", 588 dest="bag", default=None, 589 help="show message from .bag file", metavar="BAGFILE") 590 options, arg = _stdin_arg(parser, full) 591 if arg.endswith(mode): 592 arg = arg[:-(len(mode))] 593 594 # try to catch the user specifying code-style types and error 595 if '::' in arg: 596 parser.error(cmd+" does not understand C++-style namespaces (i.e. '::').\nPlease refer to msg/srv types as 'package_name/Type'.") 597 elif '.' in arg: 598 parser.error("invalid message type '%s'.\nPlease refer to msg/srv types as 'package_name/Type'." % arg) 599 if options.bag: 600 bag_file = options.bag 601 if not os.path.exists(bag_file): 602 raise ROSMsgException("ERROR: bag file [%s] does not exist"%bag_file) 603 for topic, msg, t in rosbag.Bag(bag_file).read_messages(raw=True): 604 datatype, _, _, _, pytype = msg 605 if datatype == arg: 606 print(get_msg_text(datatype, options.raw, pytype._full_text)) 607 break 608 else: 609 rospack = rospkg.RosPack() 610 if '/' in arg: #package specified 611 rosmsg_debug(rospack, mode, arg, options.raw) 612 else: 613 found_msgs = list(rosmsg_search(rospack, mode, arg)) 614 if not found_msgs: 615 print("Could not find msg '%s'" % arg, file=sys.stderr) 616 return 1 617 for found in found_msgs: 618 print("[%s]:"%found) 619 rosmsg_debug(rospack, mode, found, options.raw)
620
621 -def rosmsg_md5(mode, type_):
622 try: 623 if mode == MODE_MSG: 624 msg_class = roslib.message.get_message_class(type_) 625 else: 626 msg_class = roslib.message.get_service_class(type_) 627 except ImportError: 628 raise IOError("cannot load [%s]"%(type_)) 629 if msg_class is not None: 630 return msg_class._md5sum 631 else: 632 raise IOError("cannot load [%s]"%(type_))
633
634 -def rosmsg_cmd_md5(mode, full):
635 parser = OptionParser(usage="usage: ros%s md5 <%s>"%(mode[1:], full)) 636 options, arg = _stdin_arg(parser, full) 637 638 if '/' in arg: #package specified 639 try: 640 md5 = rosmsg_md5(mode, arg) 641 print(md5) 642 except IOError: 643 print("Cannot locate [%s]"%arg, file=sys.stderr) 644 else: 645 rospack = rospkg.RosPack() 646 matches = [m for m in rosmsg_search(rospack, mode, arg)] 647 for found in matches: 648 try: 649 md5 = rosmsg_md5(mode, found) 650 print("[%s]: %s"%(found, md5)) 651 except IOError: 652 print("Cannot locate [%s]"%found, file=sys.stderr) 653 if not matches: 654 print("No messages matching the name [%s]"%arg, file=sys.stderr)
655
656 -def rosmsg_cmd_package(mode, full):
657 parser = OptionParser(usage="usage: ros%s package <package>"%mode[1:]) 658 parser.add_option("-s", 659 dest="single_line", default=False,action="store_true", 660 help="list all msgs on a single line") 661 options, arg = _stdin_arg(parser, full) 662 joinstring='\n' 663 if options.single_line: 664 joinstring=' ' 665 print(joinstring.join(list_types(arg, mode=mode)))
666
667 -def rosmsg_cmd_packages(mode, full, argv=None):
668 if argv is None: 669 argv = sys.argv[1:] 670 parser = OptionParser(usage="usage: ros%s packages"%mode[1:]) 671 parser.add_option("-s", 672 dest="single_line", default=False,action="store_true", 673 help="list all packages on a single line") 674 options, args = parser.parse_args(argv[1:]) 675 rospack = rospkg.RosPack() 676 joinstring='\n' 677 if options.single_line: 678 joinstring=' ' 679 p1 = [p for p, _ in iterate_packages(rospack, mode)] 680 p1.sort() 681 print(joinstring.join(p1))
682
683 -def rosmsg_cmd_list(mode, full, argv=None):
684 if argv is None: 685 argv = sys.argv[1:] 686 parser = OptionParser(usage="usage: ros%s list"%mode[1:]) 687 options, args = parser.parse_args(argv[1:]) 688 if mode == MODE_MSG: 689 subdir = 'msg' 690 elif mode == MODE_SRV: 691 subdir = 'srv' 692 else: 693 raise ValueError('Unknown mode for iterate_packages: %s'%mode) 694 rospack = rospkg.RosPack() 695 packs = sorted([x for x in iterate_packages(rospack, mode)]) 696 for (p, direc) in packs: 697 for file in _list_types(direc, subdir, mode): 698 print( "%s/%s"%(p, file))
699 700
701 -def fullusage(mode):
702 """ 703 :param cmd: command name, ``str`` 704 :returns: usage text for cmd, ``str`` 705 """ 706 cmd = 'ros' + mode[1:] 707 if mode == MODE_MSG: 708 type_ = 'Message' 709 else: 710 type_ = 'Service' 711 type_lower = type_.lower() 712 return """%(cmd)s is a command-line tool for displaying information about ROS %(type_)s types. 713 714 Commands: 715 \t%(cmd)s show\tShow %(type_lower)s description 716 \t%(cmd)s list\tList all %(type_lower)ss 717 \t%(cmd)s md5\tDisplay %(type_lower)s md5sum 718 \t%(cmd)s package\tList %(type_lower)ss in a package 719 \t%(cmd)s packages\tList packages that contain %(type_lower)ss 720 721 Type %(cmd)s <command> -h for more detailed usage 722 """%locals()
723
724 -def rosmsgmain(mode=MODE_MSG):
725 """ 726 Main entry point for command-line tools (rosmsg/rossrv). 727 728 rosmsg can interact with either ros messages or ros services. The mode 729 param indicates which 730 :param mode: MODE_MSG or MODE_SRV, ``str`` 731 """ 732 try: 733 if mode == MODE_MSG: 734 ext, full = mode, "message type" 735 elif mode == MODE_SRV: 736 ext, full = mode, "service type" 737 else: 738 raise ROSMsgException("Invalid mode: %s"%mode) 739 if len(sys.argv) == 1: 740 print(fullusage(mode)) 741 sys.exit(0) 742 743 command = sys.argv[1] 744 if command == 'show': 745 sys.exit(rosmsg_cmd_show(ext, full)) 746 elif command == 'package': 747 rosmsg_cmd_package(ext, full) 748 elif command == 'packages': 749 rosmsg_cmd_packages(ext, full) 750 elif command == 'list': 751 rosmsg_cmd_list(ext, full) 752 elif command == 'md5': 753 rosmsg_cmd_md5(ext, full) 754 elif command == '--help': 755 print(fullusage(mode)) 756 sys.exit(0) 757 else: 758 print(fullusage(mode)) 759 sys.exit(getattr(os, 'EX_USAGE', 1)) 760 except KeyError as e: 761 print("Unknown message type: %s"%e, file=sys.stderr) 762 sys.exit(getattr(os, 'EX_USAGE', 1)) 763 except rospkg.ResourceNotFound as e: 764 print("Invalid package: %s"%e, file=sys.stderr) 765 sys.exit(getattr(os, 'EX_USAGE', 1)) 766 except ValueError as e: 767 print("Invalid type: '%s'"%e, file=sys.stderr) 768 sys.exit(getattr(os, 'EX_USAGE', 1)) 769 except ROSMsgException as e: 770 print(str(e), file=sys.stderr) 771 sys.exit(1) 772 except KeyboardInterrupt: 773 pass
774