1# Copyright (c) 2011, Willow Garage, Inc. 2# All rights reserved. 3# 4# Redistribution and use in source and binary forms, with or without 5# modification, are permitted provided that the following conditions are met: 6# 7# * Redistributions of source code must retain the above copyright 8# notice, this list of conditions and the following disclaimer. 9# * Redistributions in binary form must reproduce the above copyright 10# notice, this list of conditions and the following disclaimer in the 11# documentation and/or other materials provided with the distribution. 12# * Neither the name of the Willow Garage, Inc. nor the names of its 13# contributors may be used to endorse or promote products derived from 14# this software without specific prior written permission. 15# 16# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 20# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26# POSSIBILITY OF SUCH DAMAGE. 27 28# Author Ken Conley/kwc@willowgarage.com 29 30""" 31Underlying model of rosdep data. The basic data model of rosdep is to 32store a dictionary of data indexed by view name (i.e. ROS stack name). 33This data includes a dictionary mapping rosdep dependency names to 34rules and the view dependencies. 35 36This is a lower-level representation. Higher-level representation can 37combine these rosdep dependency maps and view dependencies together 38into a combined view on which queries can be made. 39""" 40 41 42class RosdepDatabaseEntry(object): 43 """ 44 Stores rosdep data and metadata for a single view. 45 """ 46 47 def __init__(self, rosdep_data, view_dependencies, origin): 48 """ 49 :param rosdep_data: raw rosdep dictionary map for view 50 :param view_dependencies: list of view dependency names 51 :param origin: name of where data originated, e.g. filename 52 """ 53 assert isinstance(rosdep_data, dict), 'RosdepDatabaseEntry() rosdep_data is not a dict: %s' % rosdep_data 54 self.rosdep_data = rosdep_data 55 self.view_dependencies = view_dependencies 56 self.origin = origin 57 58 59class RosdepDatabase(object): 60 """ 61 Stores loaded rosdep data for multiple views. 62 """ 63 64 def __init__(self): 65 self._rosdep_db = {} # {view_name: RosdepDatabaseEntry} 66 67 def is_loaded(self, view_name): 68 """ 69 :param view_name: name of view to check, ``str`` 70 :returns: ``True`` if *view_name* has been loaded into this 71 database. 72 """ 73 return view_name in self._rosdep_db 74 75 def mark_loaded(self, view_name): 76 """ 77 If view is not already loaded, this will mark it as such. This in effect sets the data for the view to be empty. 78 79 :param view_name: name of view to mark as loaded 80 """ 81 self.set_view_data(view_name, {}, [], None) 82 83 def set_view_data(self, view_name, rosdep_data, view_dependencies, origin): 84 """ 85 Set data associated with view. This will create a new 86 :class:`RosdepDatabaseEntry`. 87 88 :param rosdep_data: rosdep data map to associated with view. 89 This will be copied. 90 :param origin: origin of view data, e.g. filepath of ``rosdep.yaml`` 91 """ 92 self._rosdep_db[view_name] = RosdepDatabaseEntry(rosdep_data.copy(), view_dependencies, origin) 93 94 def get_view_names(self): 95 """ 96 :returns: list of view names that are loaded into this database. 97 """ 98 return self._rosdep_db.keys() 99 100 def get_view_data(self, view_name): 101 """ 102 :returns: :class:`RosdepDatabaseEntry` of given view. 103 104 :raises: :exc:`KeyError` if no entry for *view_name* 105 """ 106 return self._rosdep_db[view_name] 107 108 def get_view_dependencies(self, view_name): 109 """ 110 :raises: :exc:`KeyError` if *view_name* is not an entry, or if 111 all of view's dependencies have not been properly loaded. 112 """ 113 entry = self.get_view_data(view_name) 114 dependencies = entry.view_dependencies[:] 115 # compute full set of dependencies by iterating over 116 # dependencies in reverse order and prepending. 117 for s in reversed(entry.view_dependencies): 118 dependencies = self.get_view_dependencies(s) + dependencies 119 # make unique preserving order 120 unique_deps = [] 121 for d in dependencies: 122 if d not in unique_deps: 123 unique_deps.append(d) 124 return unique_deps 125