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 13547 2011-03-28 15:57:13Z 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 if ros_package_path is not None: 188 ros_package_path = roslib.rosenv.resolve_paths(ros_package_path) 189 penv[ROS_PACKAGE_PATH] = ros_package_path 190 elif ROS_PACKAGE_PATH in os.environ: 191 # record setting for _pkg_dir_cache 192 ros_package_path = os.environ[ROS_PACKAGE_PATH] 193 194 # update cache if we haven't. NOTE: we only get one cache 195 if not _pkg_dir_cache: 196 _read_rospack_cache(_pkg_dir_cache, ros_root, ros_package_path) 197 198 # now that we've resolved the args, check the cache 199 if package in _pkg_dir_cache: 200 dir_, rr, rpp = _pkg_dir_cache[package] 201 if rr == ros_root and rpp == ros_package_path: 202 if os.path.isfile(os.path.join(dir_, MANIFEST_FILE)): 203 return dir_ 204 else: 205 # invalidate cache 206 _invalidate_cache(_pkg_dir_cache) 207 208 rpout, rperr = Popen([rospack, 'find', package], \ 209 stdout=PIPE, stderr=PIPE, env=penv).communicate() 210 211 pkg_dir = (rpout or '').strip() 212 if not pkg_dir: 213 raise InvalidROSPkgException("Cannot locate installation of package %s: %s. ROS_ROOT[%s] ROS_PACKAGE_PATH[%s]"%(package, rperr.strip(), ros_root, ros_package_path)) 214 215 if not os.path.exists(pkg_dir): 216 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)) 217 elif not os.path.isdir(pkg_dir): 218 raise InvalidROSPkgException("Package %s is invalid: file [%s] is in the way"%(package, pkg_dir)) 219 # don't update cache: this should only be updated from 220 # rospack_cache as it will corrupt list_pkgs() otherwise. 221 #_pkg_dir_cache[package] = (pkg_dir, ros_root, ros_package_path) 222 return pkg_dir 223 except OSError, e: 224 if required: 225 raise InvalidROSPkgException("Environment configuration is invalid: cannot locate rospack (%s)"%e) 226 return None 227 except Exception, e: 228 if required: 229 raise 230 return None
231
232 -def _get_pkg_subdir_by_dir(package_dir, subdir, required=True, env=None):
233 """ 234 @param required: if True, will attempt to create the subdirectory 235 if it does not exist. An exception will be raised if this fails. 236 @type required: bool 237 @param package_dir: directory of package 238 @type package_dir: str 239 @param subdir: name of subdirectory to locate 240 @type subdir: str 241 @param env: override os.environ dictionary 242 @type env: dict 243 @param required: if True, directory must exist 244 @type required: bool 245 @return: Package subdirectory if package exist, otherwise None. 246 @rtype: str 247 @raise InvalidROSPkgException: if required is True and directory does not exist 248 """ 249 if env is None: 250 env = os.environ 251 try: 252 if not package_dir: 253 raise Exception("Cannot create a '%(subdir)s' directory in %(package_dir)s: package %(package) cannot be located"%locals()) 254 dir = os.path.join(package_dir, subdir) 255 if required and os.path.isfile(dir): 256 raise Exception("""Package '%(package)s' is improperly configured: 257 file %(dir)s is preventing the creation of a directory"""%locals()) 258 elif required and not os.path.isdir(dir): 259 try: 260 os.makedirs(dir) #lazy create 261 except error: 262 raise Exception("""Package '%(package)s' is improperly configured: 263 Cannot create a '%(subdir)s' directory in %(package_dir)s. 264 Please check permissions and try again. 265 """%locals()) 266 return dir 267 except Exception, e: 268 if required: 269 raise 270 return None
271
272 -def get_pkg_subdir(package, subdir, required=True, env=None):
273 """ 274 @param required: if True, will attempt to create the subdirectory 275 if it does not exist. An exception will be raised if this fails. 276 @type required: bool 277 @param package: name of package 278 @type package: str 279 @param env: override os.environ dictionary 280 @type env: dict 281 @param required: if True, directory must exist 282 @type required: bool 283 @return: Package subdirectory if package exist, otherwise None. 284 @rtype: str 285 @raise InvalidROSPkgException: if required is True and directory does not exist 286 """ 287 if env is None: 288 env = os.environ 289 pkg_dir = get_pkg_dir(package, required, ros_root=env[ROS_ROOT]) 290 return _get_pkg_subdir_by_dir(pkg_dir, subdir, required, env)
291 292 # 293 # Map ROS resources to files 294 # 295
296 -def resource_file(package, subdir, resource_name):
297 """ 298 @param subdir: name of subdir -- these should be one of the 299 string constants, e.g. MSG_DIR 300 @type subdir: str 301 @return: path to resource in the specified subdirectory of the 302 package, or None if the package does not exists 303 @rtype: str 304 @raise roslib.packages.InvalidROSPkgException: If package does not exist 305 """ 306 d = get_pkg_subdir(package, subdir, False) 307 if d is None: 308 raise InvalidROSPkgException(package) 309 return os.path.join(d, resource_name)
310
311 -def _update_rospack_cache():
312 """ 313 Internal routine to update global package directory cache 314 315 @return: True if cache is valid 316 @rtype: bool 317 """ 318 cache = _pkg_dir_cache 319 if cache: 320 return True 321 ros_root = os.environ[ROS_ROOT] 322 ros_package_path = os.environ.get(ROS_PACKAGE_PATH, '') 323 return _read_rospack_cache(cache, ros_root, ros_package_path)
324
325 -def _invalidate_cache(cache):
326 # I've only made this a separate routine because roslib.packages should really be using 327 # the roslib.stacks cache implementation instead with the separate cache marker 328 cache.clear()
329
330 -def _read_rospack_cache(cache, ros_root, ros_package_path):
331 """ 332 Read in rospack_cache data into cache. On-disk cache specifies a 333 ROS_ROOT and ROS_PACKAGE_PATH, which must match the requested 334 environment. 335 336 @param cache: empty dictionary to store package list in. 337 If no cache argument provided, list_pkgs() will use internal _pkg_dir_cache 338 and will return cached answers if available. 339 The format of the cache is {package_name: dir_path, ros_root, ros_package_path}. 340 @type cache: {str: str, str, str} 341 @param ros_package_path: ROS_ROOT value 342 @type ros_root: str 343 @param ros_package_path: ROS_PACKAGE_PATH value or '' if not specified 344 @type ros_package_path: str 345 @return: True if on-disk cache matches and was loaded, false otherwise 346 @rtype: bool 347 """ 348 try: 349 with open(os.path.join(roslib.rosenv.get_ros_home(), 'rospack_cache')) as f: 350 for l in f.readlines(): 351 l = l[:-1] 352 if not len(l): 353 continue 354 if l[0] == '#': 355 # check that the cache matches our env 356 if l.startswith('#ROS_ROOT='): 357 if not l[len('#ROS_ROOT='):] == ros_root: 358 return False 359 elif l.startswith('#ROS_PACKAGE_PATH='): 360 if not l[len('#ROS_PACKAGE_PATH='):] == ros_package_path: 361 return False 362 else: 363 cache[os.path.basename(l)] = l, ros_root, ros_package_path 364 return True 365 except: 366 pass
367
368 -def list_pkgs(pkg_dirs=None, cache=None):
369 """ 370 List packages in ROS_ROOT and ROS_PACKAGE_PATH. 371 372 If no cache and pkg_dirs arguments are provided, list_pkgs() will 373 use internal _pkg_dir_cache and will return cached answers if 374 available. 375 376 NOTE: use of pkg_dirs argument is DEPRECATED. Use 377 list_pkgs_by_path() instead, which has clearer meaning with the 378 cache. 379 380 @param pkg_dirs: (optional) list of paths to search for packages 381 @type pkg_dirs: [str] 382 383 @param cache: Empty dictionary to store package list in. 384 The format of the cache is {package_name: dir_path, ros_root, ros_package_path}. 385 @type cache: {str: str, str, str} 386 @return: complete list of package names in ROS environment 387 @rtype: [str] 388 """ 389 if pkg_dirs is None: 390 pkg_dirs = get_package_paths(True) 391 if cache is None: 392 # if cache is not specified, we use global cache instead 393 394 # TODO: this cache can be out-of-date if rospack has not 395 # been run recently. Figure out correct approach for 396 # out-of-date cache. 397 398 # TODO: we don't have any logic go populate user-specified 399 # cache in most optimal way 400 cache = _pkg_dir_cache 401 if cache: 402 return cache.keys() 403 if _update_rospack_cache(): 404 return cache.keys() 405 else: 406 import warnings 407 warnings.warn("pkg_dirs argument is deprecated. Please use list_pkgs_by_path() instead", DeprecationWarning, stacklevel=2) 408 packages = [] 409 for pkg_root in pkg_dirs: 410 list_pkgs_by_path(pkg_root, packages, cache=cache) 411 return packages
412
413 -def list_pkgs_by_path(path, packages=None, cache=None):
414 """ 415 List ROS packages within the specified path. 416 417 Optionally, a cache dictionary can be provided, which will be 418 updated with the package->path mappings. list_pkgs_by_path() does 419 NOT returned cached results -- it only updates the cache. 420 421 @param path: path to list packages in 422 @type path: str 423 @param packages: list of packages to append to. If package is 424 already present in packages, it will be ignored. 425 @type packages: [str] 426 @param cache: (optional) package path cache to update. Maps package name to directory path. 427 @type cache: {str: str} 428 @return: complete list of package names in ROS environment. Same as packages parameter. 429 @rtype: [str] 430 """ 431 if packages is None: 432 packages = [] 433 # record settings for cache 434 ros_root = os.environ[ROS_ROOT] 435 ros_package_path = os.environ.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 dir = get_pkg_dir(pkg, required=True, \ 480 ros_root=ros_root, ros_package_path=ros_package_path) 481 482 #UNIXONLY: (partial) slowly supporting Windows here 483 if sys.platform in ['win32', 'cygwin']: 484 # Windows logic requires more file patterns to resolve and is 485 # not case-sensitive, so leave it separate 486 487 # in the near-term, just hack in support for .exe/.bat. In the long 488 # term this needs to: 489 # 490 # * parse PATHEXT to generate matches 491 # * perform case-insensitive compares against potential 492 # matches, in path-ext order 493 494 # - We still have to look for bare node_type as user may have 495 # specified extension manually 496 node_type = node_type.lower() 497 matches = [node_type, node_type+'.exe', node_type+'.bat'] 498 for p, dirs, files in os.walk(dir): 499 # case insensitive 500 files = [f.lower() for f in files] 501 for m in matches: 502 if m in files: 503 test_path = os.path.join(p, m) 504 s = os.stat(test_path) 505 if (s.st_mode & (stat.S_IRUSR | stat.S_IXUSR) == 506 (stat.S_IRUSR | stat.S_IXUSR)): 507 return test_path 508 if '.svn' in dirs: 509 dirs.remove('.svn') 510 elif '.git' in dirs: 511 dirs.remove('.git') 512 else: 513 #TODO: this could just execute find_resource with a filter_fn 514 for p, dirs, files in os.walk(dir): 515 if node_type in files: 516 test_path = os.path.join(p, node_type) 517 s = os.stat(test_path) 518 if (s.st_mode & (stat.S_IRUSR | stat.S_IXUSR) == 519 (stat.S_IRUSR | stat.S_IXUSR)): 520 return test_path 521 if '.svn' in dirs: 522 dirs.remove('.svn') 523 elif '.git' in dirs: 524 dirs.remove('.git')
525
526 -def find_resource(pkg, resource_name, filter_fn=None, ros_root=None, ros_package_path=None):
527 """ 528 Locate the file named resource_name in package, optionally 529 matching specified filter 530 @param filter: function that takes in a path argument and 531 returns True if the it matches the desired resource 532 @type filter: fn(str) 533 @param ros_root: if specified, override ROS_ROOT 534 @type ros_root: str 535 @param ros_package_path: if specified, override ROS_PACKAGE_PATH 536 @type ros_package_path: str 537 @return: lists of matching paths for resource 538 @rtype: [str] 539 @raise roslib.packages.InvalidROSPkgException: If package does not exist 540 """ 541 dir = get_pkg_dir(pkg, required=True, \ 542 ros_root=ros_root, ros_package_path=ros_package_path) 543 #UNIXONLY 544 matches = [] 545 node_exe = None 546 for p, dirs, files in os.walk(dir): 547 if resource_name in files: 548 test_path = os.path.join(p, resource_name) 549 if filter_fn is not None: 550 if filter_fn(test_path): 551 matches.append(test_path) 552 else: 553 matches.append(test_path) 554 if '.svn' in dirs: 555 dirs.remove('.svn') 556 elif '.git' in dirs: 557 dirs.remove('.git') 558 return matches
559
560 -def rosdeps_of(packages):
561 """ 562 Collect all rosdeps of specified packages into a dictionary. 563 @param packages: package names 564 @type packages: [str] 565 @return: dictionary mapping package names to list of rosdep names. 566 @rtype: {str: [str]} 567 """ 568 if not type(packages) in [list, tuple]: 569 raise TypeError("packages must be list or tuple") 570 _update_rospack_cache() 571 from roslib.manifest import load_manifest 572 manifests = [load_manifest(p) for p in packages] 573 import itertools 574 map = {} 575 for pkg, m in itertools.izip(packages, manifests): 576 map[pkg] = [d.name for d in m.rosdeps] 577 return map
578
579 -def _safe_load_manifest(p):
580 """ 581 Calls roslib.manifest.load_manifest and returns None if the calls raises an Exception (i.e. invalid package) 582 """ 583 try: 584 return roslib.manifest.load_manifest(p) 585 except: 586 return roslib.manifest.Manifest()
587
588 -class ROSPackages(object):
589 """ 590 UNSTABLE/EXPERIMENTAL 591 592 Utility class for querying properties about ROS packages. This 593 should be used when querying properties about multiple 594 packages. ROSPackages caches information about packages, which 595 enables it to have higher performance than alternatives like 596 shelling out to rospack. 597 598 Example:: 599 rp = ROSPackages() 600 d = rp.depends1(['roscpp', 'rospy']) 601 print d['roscpp'] 602 d = rp.rosdeps(['roscpp', 'rospy']) 603 print d['rospy'] 604 """ 605
606 - def __init__(self):
607 self.manifests = {} 608 self._depends_cache = {} 609 self._rosdeps_cache = {}
610
611 - def load_manifests(self, packages):
612 """ 613 Load manifests for specified packages into 'manifests' attribute. 614 615 616 @param packages: package names 617 @type packages: [str] 618 """ 619 620 if not type(packages) in [list, tuple]: 621 raise TypeError("packages must be list or tuple") 622 623 # load any manifests that we haven't already 624 to_load = [p for p in packages if not p in self.manifests] 625 if to_load: 626 _update_rospack_cache() 627 self.manifests.update(dict([(p, _safe_load_manifest(p)) for p in to_load]))
628
629 - def depends1(self, packages):
630 """ 631 Collect all direct dependencies of specified packages into a 632 dictionary. 633 634 @param packages: package names 635 @type packages: [str] 636 @return: dictionary mapping package names to list of dependent package names. 637 @rtype: {str: [str]} 638 """ 639 self.load_manifests(packages) 640 map = {} 641 manifests = self.manifests 642 for pkg in packages: 643 map[pkg] = [d.package for d in manifests[pkg].depends] 644 return map
645
646 - def depends(self, packages):
647 """ 648 Collect all dependencies of specified packages into a 649 dictionary. 650 651 @param packages: package names 652 @type packages: [str] 653 @return: dictionary mapping package names to list of dependent package names. 654 @rtype: {str: [str]} 655 """ 656 657 self.load_manifests(packages) 658 map = {} 659 for pkg in packages: 660 if pkg in self._depends_cache: 661 map[pkg] = self._depends_cache[pkg] 662 else: 663 # this will cache for future reference 664 map[pkg] = self._depends(pkg) 665 return map
666
667 - def _depends(self, package):
668 """ 669 Compute recursive dependencies of a single package and cache 670 the result in self._depends_cache. 671 672 This is an internal routine. It assumes that 673 load_manifests() has already been invoked for package. 674 675 @param package: package name 676 @type package: str 677 @return: list of rosdeps 678 @rtype: [str] 679 """ 680 681 if package in self._depends_cache: 682 return self._depends_cache[package] 683 684 # assign key before recursive call to prevent infinite case 685 self._depends_cache[package] = s = set() 686 687 manifests = self.manifests 688 # take the union of all dependencies 689 pkgs = [p.package for p in manifests[package].depends] 690 self.load_manifests(pkgs) 691 for p in pkgs: 692 s.update(self._depends(p)) 693 # add in our own deps 694 s.update(pkgs) 695 # cache the return value as a list 696 s = list(s) 697 self._depends_cache[package] = s 698 return s
699
700 - def rosdeps0(self, packages):
701 """ 702 Collect rosdeps of specified packages into a dictionary. 703 @param packages: package names 704 @type packages: [str] 705 @return: dictionary mapping package names to list of rosdep names. 706 @rtype: {str: [str]} 707 """ 708 709 self.load_manifests(packages) 710 map = {} 711 manifests = self.manifests 712 for pkg in packages: 713 map[pkg] = [d.name for d in manifests[pkg].rosdeps] 714 return map
715
716 - def rosdeps(self, packages):
717 """ 718 Collect all (recursive) dependencies of specified packages 719 into a dictionary. 720 721 @param packages: package names 722 @type packages: [str] 723 @return: dictionary mapping package names to list of dependent package names. 724 @rtype: {str: [str]} 725 """ 726 727 self.load_manifests(packages) 728 map = {} 729 for pkg in packages: 730 if pkg in self._rosdeps_cache: 731 map[pkg] = self._rosdeps_cache[pkg] 732 else: 733 # this will cache for future reference 734 map[pkg] = self._rosdeps(pkg) 735 return map
736
737 - def _rosdeps(self, package):
738 """ 739 Compute recursive rosdeps of a single package and cache the 740 result in self._rosdeps_cache. 741 742 This is an internal routine. It assumes that 743 load_manifests() has already been invoked for package. 744 745 @param package: package name 746 @type package: str 747 @return: list of rosdeps 748 @rtype: [str] 749 """ 750 751 if package in self._rosdeps_cache: 752 return self._rosdeps_cache[package] 753 # set the key before recursive call to prevent infinite case 754 self._rosdeps_cache[package] = s = set() 755 756 manifests = self.manifests 757 # take the union of all dependencies 758 pkgs = [p.package for p in manifests[package].depends] 759 self.load_manifests(pkgs) 760 for p in pkgs: 761 s.update(self._rosdeps(p)) 762 # add in our own deps 763 s.update([d.name for d in manifests[package].rosdeps]) 764 # cache the return value as a list 765 s = list(s) 766 self._rosdeps_cache[package] = s 767 return s
768
769 -def _platform_supported(file, os, version):
770 m = roslib.manifest.parse_file(file) 771 for p in m.platforms: 772 if os == p.os and version == p.version: 773 return True 774 return False
775
776 -def platform_supported(pkg, os, version):
777 """ 778 Return whether the platform defined by os and version is marked as supported in the package 779 @param pkg The package to test for support 780 @param os The os name to test for support 781 @param version The os version to test for support 782 """ 783 return _platform_supported(roslib.manifest.manifest_file(pkg), os, version)
784
785 -def current_platform_supported(pkg):
786 """ 787 Return whether the current running platform is marked as supported in the package 788 @param pkg The package to test for support 789 """ 790 os_detector = roslib.os_detect.OSDetect() 791 return platform_supported(pkg, os_detector.get_name(), os_detector.get_version())
792