Package roslib :: Module packages
[frames] | no frames]

Source Code for Module roslib.packages

  1  # Software License Agreement (BSD License) 
  2  # 
  3  # Copyright (c) 2008, 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: packages.py 14579 2011-08-05 17:31:05Z kwc $ 
 34  # $Author: kwc $ 
 35   
 36  """ 
 37  Python utilities for manipulating ROS packages. 
 38  See: U{http://ros.org/wiki/Packages} 
 39   
 40  Warning: while most of this API is stable, some parts are still fairly 
 41  experimental and incomplete. In particular, the L{ROSPackages} class 
 42  in very experimental. 
 43  """ 
 44   
 45  from __future__ import with_statement 
 46   
 47  import os 
 48  import sys 
 49  import stat 
 50  import string 
 51   
 52  from subprocess import Popen, PIPE 
 53   
 54  import roslib.exceptions 
 55  import roslib.manifest 
 56  import roslib.names 
 57  import roslib.rosenv 
 58  import roslib.os_detect 
 59   
 60  MSG_DIR = 'msg' 
 61  SRV_DIR = 'srv' 
 62  SRC_DIR = 'src' 
 63   
 64  # aliases 
 65  ROS_PACKAGE_PATH = roslib.rosenv.ROS_PACKAGE_PATH 
 66  ROS_ROOT = roslib.rosenv.ROS_ROOT 
 67   
68 -class ROSPkgException(roslib.exceptions.ROSLibException):
69 """ 70 Base class of package-related errors. 71 """ 72 pass
73 -class InvalidROSPkgException(ROSPkgException):
74 """ 75 Exception that indicates that a ROS package does not exist 76 """ 77 pass
78 -class MultipleNodesException(ROSPkgException):
79 """ 80 Exception that indicates that multiple ROS nodes by the same name are in the same package. 81 """ 82 pass
83 84 # TODO: go through the code and eliminate unused methods -- there's far too many combos here 85 86 MANIFEST_FILE = 'manifest.xml' 87 88 # 89 # Map package/directory structure 90 # 91
92 -def is_pkg_dir(d):
93 """ 94 @param d: directory location 95 @type d: str 96 @return: True if d is the root directory of a ROS Package 97 @rtype: bool 98 """ 99 return os.path.isfile(os.path.join(d, MANIFEST_FILE))
100
101 -def get_package_paths(ros_root_required=True, env=None):
102 """ 103 Get the paths to search for packages 104 105 @param ros_root_required: if True, raise exception if 106 environment is invalid (i.e. ROS_ROOT is not set properly) 107 @type ros_root_required: bool 108 @param env: override os.environ dictionary 109 @type env: dict 110 @raise roslib.rosenv.ROSEnvException: if ros_root_required is True 111 and ROS_ROOT is not set 112 """ 113 if env is None: 114 env = os.environ 115 rpp = roslib.rosenv.get_ros_package_path(required=False, env=env) 116 if rpp: 117 paths = [x for x in rpp.split(os.pathsep) if x] 118 else: 119 paths = [] 120 rr_path = roslib.rosenv.get_ros_root(required=ros_root_required, env=env) 121 if rr_path: 122 return paths + [rr_path] 123 else: 124 return paths
125
126 -def get_dir_pkg(d):
127 """ 128 Get the package that the directory is contained within. This is 129 determined by finding the nearest parent manifest.xml file. This 130 isn't 100% reliable, but symlinks can full any heuristic that 131 relies on ROS_ROOT. 132 @param d: directory path 133 @type d: str 134 @return: (package_directory, package) of the specified directory, or None,None if not in a package 135 @rtype: (str, str) 136 """ 137 #TODO: the realpath is going to create issues with symlinks, most likely 138 139 parent = os.path.dirname(os.path.realpath(d)) 140 #walk up until we hit ros root or ros/pkg 141 while not os.path.exists(os.path.join(d, MANIFEST_FILE)) and parent != d: 142 d = parent 143 parent = os.path.dirname(d) 144 if os.path.exists(os.path.join(d, MANIFEST_FILE)): 145 pkg = os.path.basename(os.path.abspath(d)) 146 return d, pkg 147 return None, None
148 149 _pkg_dir_cache = {} 150
151 -def get_pkg_dir(package, required=True, ros_root=None, ros_package_path=None):
152 """ 153 Locate directory package is stored in. This routine uses an 154 internal cache. 155 156 NOTE: cache does *not* rebuild if packages are relocated after 157 this process is initiated. 158 159 @param package: package name 160 @type package: str 161 @param required: if True, an exception will be raised if the 162 package directory cannot be located. 163 @type required: bool 164 @param ros_root: if specified, override ROS_ROOT 165 @type ros_root: str 166 @param ros_package_path: if specified, override ROS_PACKAGE_PATH 167 @type ros_package_path: str 168 @return: directory containing package or None if package cannot be found and required is False. 169 @rtype: str 170 @raise InvalidROSPkgException: if required is True and package cannot be located 171 """ 172 173 #UNIXONLY 174 #TODO: replace with non-rospack-based solution (e.g. os.walk()) 175 try: 176 penv = os.environ.copy() 177 if ros_root: 178 ros_root = roslib.rosenv.resolve_path(ros_root) 179 penv[ROS_ROOT] = ros_root 180 elif ROS_ROOT in os.environ: 181 # record setting for _pkg_dir_cache 182 ros_root = os.environ[ROS_ROOT] 183 if ros_root: 184 rospack = os.path.join(ros_root, 'bin', 'rospack') 185 else: 186 rospack = 'rospack' 187 188 if 'ROS_BUILD' in os.environ: 189 rospack = os.path.join(os.environ['ROS_BUILD'], 'bin', 'rospack') 190 191 if ros_package_path is not None: 192 ros_package_path = roslib.rosenv.resolve_paths(ros_package_path) 193 penv[ROS_PACKAGE_PATH] = ros_package_path 194 elif ROS_PACKAGE_PATH in os.environ: 195 # record setting for _pkg_dir_cache 196 ros_package_path = os.environ[ROS_PACKAGE_PATH] 197 198 # update cache if we haven't. NOTE: we only get one cache 199 if not _pkg_dir_cache: 200 _read_rospack_cache(_pkg_dir_cache, ros_root, ros_package_path) 201 202 # now that we've resolved the args, check the cache 203 if package in _pkg_dir_cache: 204 dir_, rr, rpp = _pkg_dir_cache[package] 205 if rr == ros_root and rpp == ros_package_path: 206 if os.path.isfile(os.path.join(dir_, MANIFEST_FILE)): 207 return dir_ 208 else: 209 # invalidate cache 210 _invalidate_cache(_pkg_dir_cache) 211 212 rpout, rperr = Popen([rospack, 'find', package], \ 213 stdout=PIPE, stderr=PIPE, env=penv).communicate() 214 215 pkg_dir = (rpout or '').strip() 216 #python3.1 popen returns as bytes 217 if (isinstance(pkg_dir, bytes)): 218 pkg_dir = pkg_dir.decode() 219 if not pkg_dir: 220 raise InvalidROSPkgException("Cannot locate installation of package %s: %s. ROS_ROOT[%s] ROS_PACKAGE_PATH[%s]"%(package, rperr.strip(), ros_root, ros_package_path)) 221 222 if not os.path.exists(pkg_dir): 223 raise InvalidROSPkgException("Cannot locate installation of package %s: [%s] is not a valid path. ROS_ROOT[%s] ROS_PACKAGE_PATH[%s]"%(package, pkg_dir, ros_root, ros_package_path)) 224 elif not os.path.isdir(pkg_dir): 225 raise InvalidROSPkgException("Package %s is invalid: file [%s] is in the way"%(package, pkg_dir)) 226 # don't update cache: this should only be updated from 227 # rospack_cache as it will corrupt list_pkgs() otherwise. 228 #_pkg_dir_cache[package] = (pkg_dir, ros_root, ros_package_path) 229 return pkg_dir 230 except OSError as e: 231 if required: 232 raise InvalidROSPkgException("Environment configuration is invalid: cannot locate rospack (%s)"%e) 233 return None 234 except Exception as e: 235 if required: 236 raise 237 return None
238
239 -def _get_pkg_subdir_by_dir(package_dir, subdir, required=True, env=None):
240 """ 241 @param required: if True, will attempt to create the subdirectory 242 if it does not exist. An exception will be raised if this fails. 243 @type required: bool 244 @param package_dir: directory of package 245 @type package_dir: str 246 @param subdir: name of subdirectory to locate 247 @type subdir: str 248 @param env: override os.environ dictionary 249 @type env: dict 250 @param required: if True, directory must exist 251 @type required: bool 252 @return: Package subdirectory if package exist, otherwise None. 253 @rtype: str 254 @raise InvalidROSPkgException: if required is True and directory does not exist 255 """ 256 if env is None: 257 env = os.environ 258 try: 259 if not package_dir: 260 raise Exception("Cannot create a '%(subdir)s' directory in %(package_dir)s: package %(package) cannot be located"%locals()) 261 d = os.path.join(package_dir, subdir) 262 if required and os.path.isfile(d): 263 raise Exception("""Package '%(package)s' is improperly configured: 264 file %(d)s is preventing the creation of a directory"""%locals()) 265 elif required and not os.path.isdir(d): 266 try: 267 os.makedirs(d) #lazy create 268 except error: 269 raise Exception("""Package '%(package)s' is improperly configured: 270 Cannot create a '%(subdir)s' directory in %(package_dir)s. 271 Please check permissions and try again. 272 """%locals()) 273 return d 274 except Exception as e: 275 if required: 276 raise 277 return None
278
279 -def get_pkg_subdir(package, subdir, required=True, env=None):
280 """ 281 @param required: if True, will attempt to create the subdirectory 282 if it does not exist. An exception will be raised if this fails. 283 @type required: bool 284 @param package: name of package 285 @type package: str 286 @param env: override os.environ dictionary 287 @type env: dict 288 @param required: if True, directory must exist 289 @type required: bool 290 @return: Package subdirectory if package exist, otherwise None. 291 @rtype: str 292 @raise InvalidROSPkgException: if required is True and directory does not exist 293 """ 294 if env is None: 295 env = os.environ 296 pkg_dir = get_pkg_dir(package, required, ros_root=env[ROS_ROOT]) 297 return _get_pkg_subdir_by_dir(pkg_dir, subdir, required, env)
298 299 # 300 # Map ROS resources to files 301 # 302
303 -def resource_file(package, subdir, resource_name):
304 """ 305 @param subdir: name of subdir -- these should be one of the 306 string constants, e.g. MSG_DIR 307 @type subdir: str 308 @return: path to resource in the specified subdirectory of the 309 package, or None if the package does not exists 310 @rtype: str 311 @raise roslib.packages.InvalidROSPkgException: If package does not exist 312 """ 313 d = get_pkg_subdir(package, subdir, False) 314 if d is None: 315 raise InvalidROSPkgException(package) 316 return os.path.join(d, resource_name)
317
318 -def _update_rospack_cache(env=None):
319 """ 320 Internal routine to update global package directory cache 321 322 @return: True if cache is valid 323 @rtype: bool 324 """ 325 if env is None: 326 env = os.environ 327 cache = _pkg_dir_cache 328 if cache: 329 return True 330 ros_root = env[ROS_ROOT] 331 ros_package_path = env.get(ROS_PACKAGE_PATH, '') 332 return _read_rospack_cache(cache, ros_root, ros_package_path)
333
334 -def _invalidate_cache(cache):
335 # I've only made this a separate routine because roslib.packages should really be using 336 # the roslib.stacks cache implementation instead with the separate cache marker 337 cache.clear()
338
339 -def _read_rospack_cache(cache, ros_root, ros_package_path):
340 """ 341 Read in rospack_cache data into cache. On-disk cache specifies a 342 ROS_ROOT and ROS_PACKAGE_PATH, which must match the requested 343 environment. 344 345 @param cache: empty dictionary to store package list in. 346 If no cache argument provided, list_pkgs() will use internal _pkg_dir_cache 347 and will return cached answers if available. 348 The format of the cache is {package_name: dir_path, ros_root, ros_package_path}. 349 @type cache: {str: str, str, str} 350 @param ros_package_path: ROS_ROOT value 351 @type ros_root: str 352 @param ros_package_path: ROS_PACKAGE_PATH value or '' if not specified 353 @type ros_package_path: str 354 @return: True if on-disk cache matches and was loaded, false otherwise 355 @rtype: bool 356 """ 357 try: 358 with open(os.path.join(roslib.rosenv.get_ros_home(), 'rospack_cache')) as f: 359 for l in f.readlines(): 360 l = l[:-1] 361 if not len(l): 362 continue 363 if l[0] == '#': 364 # check that the cache matches our env 365 if l.startswith('#ROS_ROOT='): 366 if not l[len('#ROS_ROOT='):] == ros_root: 367 return False 368 elif l.startswith('#ROS_PACKAGE_PATH='): 369 if not l[len('#ROS_PACKAGE_PATH='):] == ros_package_path: 370 return False 371 else: 372 cache[os.path.basename(l)] = l, ros_root, ros_package_path 373 return True 374 except: 375 pass
376
377 -def list_pkgs(cache=None, env=None):
378 """ 379 List packages in ROS_ROOT and ROS_PACKAGE_PATH. 380 381 If no cache and pkg_dirs arguments are provided, list_pkgs() will 382 use internal _pkg_dir_cache and will return cached answers if 383 available. 384 385 @param cache: Empty dictionary to store package list in. 386 The format of the cache is {package_name: dir_path, ros_root, ros_package_path}. 387 @type cache: {str: str, str, str} 388 @return: complete list of package names in ROS environment 389 @rtype: [str] 390 """ 391 pkg_dirs = get_package_paths(True, env=env) 392 if cache is None: 393 # if cache is not specified, we use global cache instead 394 395 # TODO: this cache can be out-of-date if rospack has not 396 # been run recently. Figure out correct approach for 397 # out-of-date cache. 398 399 # TODO: we don't have any logic go populate user-specified 400 # cache in most optimal way 401 cache = _pkg_dir_cache 402 if cache: 403 return list(cache.keys()) #py3k 404 if _update_rospack_cache(env=env): 405 return list(cache.keys()) #py3k 406 packages = [] 407 for pkg_root in pkg_dirs: 408 list_pkgs_by_path(pkg_root, packages, cache=cache, env=env) 409 return packages
410
411 -def list_pkgs_by_path(path, packages=None, cache=None, env=None):
412 """ 413 List ROS packages within the specified path. 414 415 Optionally, a cache dictionary can be provided, which will be 416 updated with the package->path mappings. list_pkgs_by_path() does 417 NOT returned cached results -- it only updates the cache. 418 419 @param path: path to list packages in 420 @type path: str 421 @param packages: list of packages to append to. If package is 422 already present in packages, it will be ignored. 423 @type packages: [str] 424 @param cache: (optional) package path cache to update. Maps package name to directory path. 425 @type cache: {str: str} 426 @return: complete list of package names in ROS environment. Same as packages parameter. 427 @rtype: [str] 428 """ 429 if packages is None: 430 packages = [] 431 if env is None: 432 env = os.environ 433 # record settings for cache 434 ros_root = env[ROS_ROOT] 435 ros_package_path = env.get(ROS_PACKAGE_PATH, '') 436 437 path = os.path.abspath(path) 438 for d, dirs, files in os.walk(path, topdown=True): 439 if MANIFEST_FILE in files: 440 package = os.path.basename(d) 441 if package not in packages: 442 packages.append(package) 443 if cache is not None: 444 cache[package] = d, ros_root, ros_package_path 445 del dirs[:] 446 continue #leaf 447 elif 'rospack_nosubdirs' in files: 448 del dirs[:] 449 continue #leaf 450 #small optimization 451 elif '.svn' in dirs: 452 dirs.remove('.svn') 453 elif '.git' in dirs: 454 dirs.remove('.git') 455 456 for sub_d in dirs: 457 # followlinks=True only available in Python 2.6, so we 458 # have to implement manually 459 sub_p = os.path.join(d, sub_d) 460 if os.path.islink(sub_p): 461 packages.extend(list_pkgs_by_path(sub_p, cache=cache)) 462 463 return packages
464
465 -def find_node(pkg, node_type, ros_root=None, ros_package_path=None):
466 """ 467 Locate the executable that implements the node 468 469 @param node_type: type of node 470 @type node_type: str 471 @param ros_root: if specified, override ROS_ROOT 472 @type ros_root: str 473 @param ros_package_path: if specified, override ROS_PACKAGE_PATH 474 @type ros_package_path: str 475 @return: path to node or None if node is not in the package 476 @rtype: str 477 @raise roslib.packages.InvalidROSPkgException: If package does not exist 478 """ 479 480 if 'ROS_BUILD' in os.environ: 481 tst = os.path.join(os.environ['ROS_BUILD'], 'bin', node_type) 482 if os.path.isfile(tst): 483 return tst 484 485 d = get_pkg_dir(pkg, required=True, \ 486 ros_root=ros_root, ros_package_path=ros_package_path) 487 488 #UNIXONLY: (partial) slowly supporting Windows here 489 if sys.platform in ['win32', 'cygwin']: 490 # Windows logic requires more file patterns to resolve and is 491 # not case-sensitive, so leave it separate 492 493 # in the near-term, just hack in support for .exe/.bat. In the long 494 # term this needs to: 495 # 496 # * parse PATHEXT to generate matches 497 # * perform case-insensitive compares against potential 498 # matches, in path-ext order 499 500 # - We still have to look for bare node_type as user may have 501 # specified extension manually 502 node_type = node_type.lower() 503 matches = [node_type, node_type+'.exe', node_type+'.bat'] 504 for p, dirs, files in os.walk(d): 505 # case insensitive 506 files = [f.lower() for f in files] 507 for m in matches: 508 if m in files: 509 test_path = os.path.join(p, m) 510 s = os.stat(test_path) 511 if (s.st_mode & (stat.S_IRUSR | stat.S_IXUSR) == 512 (stat.S_IRUSR | stat.S_IXUSR)): 513 return test_path 514 if '.svn' in dirs: 515 dirs.remove('.svn') 516 elif '.git' in dirs: 517 dirs.remove('.git') 518 else: 519 #TODO: this could just execute find_resource with a filter_fn 520 for p, dirs, files in os.walk(d): 521 if node_type in files: 522 test_path = os.path.join(p, node_type) 523 s = os.stat(test_path) 524 if (s.st_mode & (stat.S_IRUSR | stat.S_IXUSR) == 525 (stat.S_IRUSR | stat.S_IXUSR)): 526 return test_path 527 if '.svn' in dirs: 528 dirs.remove('.svn') 529 elif '.git' in dirs: 530 dirs.remove('.git')
531
532 -def find_resource(pkg, resource_name, filter_fn=None, ros_root=None, ros_package_path=None):
533 """ 534 Locate the file named resource_name in package, optionally 535 matching specified filter 536 @param filter: function that takes in a path argument and 537 returns True if the it matches the desired resource 538 @type filter: fn(str) 539 @param ros_root: if specified, override ROS_ROOT 540 @type ros_root: str 541 @param ros_package_path: if specified, override ROS_PACKAGE_PATH 542 @type ros_package_path: str 543 @return: lists of matching paths for resource 544 @rtype: [str] 545 @raise roslib.packages.InvalidROSPkgException: If package does not exist 546 """ 547 d = get_pkg_dir(pkg, required=True, \ 548 ros_root=ros_root, ros_package_path=ros_package_path) 549 #UNIXONLY 550 matches = [] 551 node_exe = None 552 for p, dirs, files in os.walk(d): 553 if resource_name in files: 554 test_path = os.path.join(p, resource_name) 555 if filter_fn is not None: 556 if filter_fn(test_path): 557 matches.append(test_path) 558 else: 559 matches.append(test_path) 560 if '.svn' in dirs: 561 dirs.remove('.svn') 562 elif '.git' in dirs: 563 dirs.remove('.git') 564 return matches
565
566 -def rosdeps_of(packages):
567 """ 568 Collect all rosdeps of specified packages into a dictionary. 569 @param packages: package names 570 @type packages: [str] 571 @return: dictionary mapping package names to list of rosdep names. 572 @rtype: {str: [str]} 573 """ 574 if not type(packages) in [list, tuple]: 575 raise TypeError("packages must be list or tuple") 576 _update_rospack_cache() 577 from roslib.manifest import load_manifest 578 manifests = [load_manifest(p) for p in packages] 579 map = {} 580 for pkg, m in zip(packages, manifests): #py3k 581 map[pkg] = [d.name for d in m.rosdeps] 582 return map
583
584 -def _safe_load_manifest(p):
585 """ 586 Calls roslib.manifest.load_manifest and returns None if the calls raises an Exception (i.e. invalid package) 587 """ 588 try: 589 return roslib.manifest.load_manifest(p) 590 except: 591 return roslib.manifest.Manifest()
592
593 -class ROSPackages(object):
594 """ 595 UNSTABLE/EXPERIMENTAL 596 597 Utility class for querying properties about ROS packages. This 598 should be used when querying properties about multiple 599 packages. ROSPackages caches information about packages, which 600 enables it to have higher performance than alternatives like 601 shelling out to rospack. 602 603 Example:: 604 rp = ROSPackages() 605 d = rp.depends1(['roscpp', 'rospy']) 606 print d['roscpp'] 607 d = rp.rosdeps(['roscpp', 'rospy']) 608 print d['rospy'] 609 """ 610
611 - def __init__(self):
612 self.manifests = {} 613 self._depends_cache = {} 614 self._rosdeps_cache = {}
615
616 - def load_manifests(self, packages):
617 """ 618 Load manifests for specified packages into 'manifests' attribute. 619 620 621 @param packages: package names 622 @type packages: [str] 623 """ 624 625 if not type(packages) in [list, tuple]: 626 raise TypeError("packages must be list or tuple") 627 628 # load any manifests that we haven't already 629 to_load = [p for p in packages if not p in self.manifests] 630 if to_load: 631 _update_rospack_cache() 632 self.manifests.update(dict([(p, _safe_load_manifest(p)) for p in to_load]))
633
634 - def depends1(self, packages):
635 """ 636 Collect all direct dependencies of specified packages into a 637 dictionary. 638 639 @param packages: package names 640 @type packages: [str] 641 @return: dictionary mapping package names to list of dependent package names. 642 @rtype: {str: [str]} 643 """ 644 self.load_manifests(packages) 645 map = {} 646 manifests = self.manifests 647 for pkg in packages: 648 map[pkg] = [d.package for d in manifests[pkg].depends] 649 return map
650
651 - def depends(self, packages):
652 """ 653 Collect all dependencies of specified packages into a 654 dictionary. 655 656 @param packages: package names 657 @type packages: [str] 658 @return: dictionary mapping package names to list of dependent package names. 659 @rtype: {str: [str]} 660 """ 661 662 self.load_manifests(packages) 663 map = {} 664 for pkg in packages: 665 if pkg in self._depends_cache: 666 map[pkg] = self._depends_cache[pkg] 667 else: 668 # this will cache for future reference 669 map[pkg] = self._depends(pkg) 670 return map
671
672 - def _depends(self, package):
673 """ 674 Compute recursive dependencies of a single package and cache 675 the result in self._depends_cache. 676 677 This is an internal routine. It assumes that 678 load_manifests() has already been invoked for package. 679 680 @param package: package name 681 @type package: str 682 @return: list of rosdeps 683 @rtype: [str] 684 """ 685 686 if package in self._depends_cache: 687 return self._depends_cache[package] 688 689 # assign key before recursive call to prevent infinite case 690 self._depends_cache[package] = s = set() 691 692 manifests = self.manifests 693 # take the union of all dependencies 694 pkgs = [p.package for p in manifests[package].depends] 695 self.load_manifests(pkgs) 696 for p in pkgs: 697 s.update(self._depends(p)) 698 # add in our own deps 699 s.update(pkgs) 700 # cache the return value as a list 701 s = list(s) 702 self._depends_cache[package] = s 703 return s
704
705 - def rosdeps0(self, packages):
706 """ 707 Collect rosdeps of specified packages into a dictionary. 708 @param packages: package names 709 @type packages: [str] 710 @return: dictionary mapping package names to list of rosdep names. 711 @rtype: {str: [str]} 712 """ 713 714 self.load_manifests(packages) 715 map = {} 716 manifests = self.manifests 717 for pkg in packages: 718 map[pkg] = [d.name for d in manifests[pkg].rosdeps] 719 return map
720
721 - def rosdeps(self, packages):
722 """ 723 Collect all (recursive) dependencies of specified packages 724 into a dictionary. 725 726 @param packages: package names 727 @type packages: [str] 728 @return: dictionary mapping package names to list of dependent package names. 729 @rtype: {str: [str]} 730 """ 731 732 self.load_manifests(packages) 733 map = {} 734 for pkg in packages: 735 if pkg in self._rosdeps_cache: 736 map[pkg] = self._rosdeps_cache[pkg] 737 else: 738 # this will cache for future reference 739 map[pkg] = self._rosdeps(pkg) 740 return map
741
742 - def _rosdeps(self, package):
743 """ 744 Compute recursive rosdeps of a single package and cache the 745 result in self._rosdeps_cache. 746 747 This is an internal routine. It assumes that 748 load_manifests() has already been invoked for package. 749 750 @param package: package name 751 @type package: str 752 @return: list of rosdeps 753 @rtype: [str] 754 """ 755 756 if package in self._rosdeps_cache: 757 return self._rosdeps_cache[package] 758 # set the key before recursive call to prevent infinite case 759 self._rosdeps_cache[package] = s = set() 760 761 manifests = self.manifests 762 # take the union of all dependencies 763 pkgs = [p.package for p in manifests[package].depends] 764 self.load_manifests(pkgs) 765 for p in pkgs: 766 s.update(self._rosdeps(p)) 767 # add in our own deps 768 s.update([d.name for d in manifests[package].rosdeps]) 769 # cache the return value as a list 770 s = list(s) 771 self._rosdeps_cache[package] = s 772 return s
773
774 -def _platform_supported(file, os, version):
775 m = roslib.manifest.parse_file(file) 776 for p in m.platforms: 777 if os == p.os and version == p.version: 778 return True 779 return False
780
781 -def platform_supported(pkg, os, version):
782 """ 783 Return whether the platform defined by os and version is marked as supported in the package 784 @param pkg The package to test for support 785 @param os The os name to test for support 786 @param version The os version to test for support 787 """ 788 return _platform_supported(roslib.manifest.manifest_file(pkg), os, version)
789
790 -def current_platform_supported(pkg):
791 """ 792 Return whether the current running platform is marked as supported in the package 793 @param pkg The package to test for support 794 """ 795 os_detector = roslib.os_detect.OSDetect() 796 return platform_supported(pkg, os_detector.get_name(), os_detector.get_version())
797