Package rosh :: Package impl :: Module packages
[frames] | no frames]

Source Code for Module rosh.impl.packages

  1  # Software License Agreement (BSD License) 
  2  # 
  3  # Copyright (c) 2010, 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 11672 2010-10-22 00:18:14Z kwc $ 
 34   
 35  from __future__ import with_statement 
 36   
 37  import os 
 38  import stat 
 39  import sys 
 40   
 41  import roslib.manifest 
 42  import roslib.packages 
 43  import roslib.stack_manifest 
 44  import roslib.stacks 
 45   
 46  # TODO: get rid of Namespace and Concept entirely as that really doesn't apply here and just requires workarounds 
 47  from rosh.impl.namespace import Namespace, Concept, ResourceList 
 48  # TODO: enable packages.std_msgs.msgs.String 
 49  from rosh.impl.msg import Msgs 
 50   
51 -class ManifestResource(object):
52
53 - def __init__(self, name, config):
54 """ 55 ctor. 56 @param config: Namespace configuration instance with additional 'listener' attribute. 57 @type config: L{NamespaceConfig} 58 """ 59 self.name = name 60 # this is an artifact of "Concepts" having a 'root' with an 61 # empty key, which is non-sensical in this implementation. 62 # this could be resolved by not reusing the Namespace/Concept 63 # code directly 64 if not name: 65 return 66 self._config = config 67 68 self.path = self._get_path() 69 self.manifest = self._get_manifest(self.path)
70
71 - def _get_path(self):
72 raise NotImplemented
73
74 - def _get_manifest(self, path):
75 raise NotImplemented
76
77 - def _get_depends1(self):
78 # we do a str(x) to flatten into str form instead of 79 # StackDepend vs. Depend, which have different attributes 80 return ResourceList(self._config, [str(x) for x in self.manifest.depends], self.__class__)
81 82 depends1 = property(_get_depends1) 83
84 - def __repr__(self):
85 return self.__str__()
86
87 - def __str__(self):
88 return self.name
89
90 -class AttrDict(object):
91 - def __init__(self, d):
92 self.__dict__.update(d)
93
94 -class Package(ManifestResource):
95 - def __init__(self, name, config):
96 super(Package, self).__init__(name, config)
97
98 - def _get_path(self):
99 return roslib.packages.get_pkg_dir(self.name)
100
101 - def _get_manifest(self, path):
102 return roslib.manifest.parse_file(os.path.join(path, roslib.manifest.MANIFEST_FILE))
103
104 - def _get_msgs(self):
105 try: 106 # test if there are, in fact, msg files 107 if self.name in self._config.ctx.msg: 108 # if so, retrieve from msg 109 return self._config.ctx.msg[self.name] 110 except AttributeError: 111 # msg property is not guaranteed to exist 112 pass 113 return None
114
115 - def _get_srvs(self):
116 try: 117 # test if there are, in fact, srv files 118 if self.name in self._config.ctx.srv: 119 # if so, retrieve from msg 120 return self._config.ctx.srv[self.name] 121 except AttributeError: 122 # srv property doesn't exist if we are not online 123 pass 124 return None
125 126 #TODO: can we make nodes and launches plugins on top of packages, 127 #that way rosh can be provided in the separated ROS stack.
128 - def _get_nodes(self):
129 paths = list_resources_by_dir(self.path, node_filter) 130 node_types = [os.path.basename(p) for p in paths] 131 d = dict([(launchablekey(t), LaunchableNode(self._config.ctx, self.name, t)) for t in node_types]) 132 return AttrDict(d)
133
134 - def _get_launches(self):
135 paths = list_resources_by_dir(self.path, launch_filter) 136 launch_types = [os.path.basename(p) for p in paths] 137 d = dict([(launchablekey(t), LaunchableLaunch(self._config.ctx, self.name, t)) for t in launch_types]) 138 return AttrDict(d)
139 140 # use singular to match 'msg' global 141 msg = property(_get_msgs) 142 srv = property(_get_srvs) 143 nodes = property(_get_nodes) 144 launches = property(_get_launches)
145
146 -def launchablekey(k):
147 return k.replace('.', '_')
148 149 try: 150 import roslaunch 151 except ImportError: 152 print >> sys.stderr, "cannot import roslaunch, launching is disabled"
153 - class FakeLaunch(object):
154 - def Node(self):
155 raise Exception("cannot import roslaunch, launching is disabled")
156 roslaunch = FakeLaunch() 157
158 -class LaunchableNode(object):
159 - def __init__(self, ctx, package, type_):
160 self.ctx = ctx 161 self.package = package 162 self.type = type_
163 - def __call__(self, *args, **kwds):
164 # launch returns list of Nodes that were launched, so unwrap 165 return self.ctx.launch(self.as_Node(), args=args, remap=kwds)[0]
166
167 - def as_Node(self):
168 return roslaunch.Node(self.package, self.type)
169 - def __str__(self):
170 return launchablekey(self.type)
171 - def _launch(self):
172 return self.ctx.launch(self.as_Node())
173 174
175 -class LaunchableFile(object):
176 - def __init__(self, ctx, launch_file):
177 self.ctx = ctx 178 self.launch_file = launch_file
179 - def __call__(self):
180 raise NotImplemented
181 - def __str__(self):
182 return launchablekey(self.launch_file)
183 - def _launch(self):
184 raise NotImplemented
185
186 -def node_filter(path, filename):
187 """ 188 Node file filter function for list_resources. Filter functions 189 return the resource path if the filter matches, None otherwise. 190 191 @return: resource path (if match) or None 192 """ 193 path = os.path.join(path, filename) 194 s = os.stat(path) 195 if (s.st_mode & stat.S_IRWXU == stat.S_IRWXU): 196 return path
197
198 -def launch_filter(path, filename):
199 """ 200 roslaunch file filter function for list_resources. Filter 201 functions return the resource path if the filter matches, None 202 otherwise. 203 204 @return: resource path (if match) or None 205 """ 206 if filename.endswith('.launch') or filename.endswith('.test'): 207 return os.path.join(path, filename)
208 209 # TODO: move into roslib for ROS 1.4. Right now rosh is targetting ROS 1.2 compatibility
210 -def list_resources(pkg, filter_fn):
211 return list_resources_by_dir(roslib.packages.get_pkg_dir(pkg), filter_fn)
212 -def list_resources_by_dir(pkg_dir, filter_fn):
213 resources = [] 214 for p, dirs, files in os.walk(pkg_dir): 215 for f in files: 216 resource_path = filter_fn(p, f) 217 if resource_path is not None: 218 resources.append(resource_path) 219 if '.svn' in dirs: 220 dirs.remove('.svn') 221 elif '.git' in dirs: 222 dirs.remove('.git') 223 return resources
224
225 -class Stack(ManifestResource):
226 - def __init__(self, name, config):
227 super(Stack, self).__init__(name, config)
228
229 - def _get_path(self):
230 return roslib.stacks.get_stack_dir(self.name)
231
232 - def _get_manifest(self, path):
233 return roslib.stack_manifest.parse_file(os.path.join(path, roslib.stack_manifest.STACK_FILE))
234
235 - def _get_packages(self):
236 # we have to use the config from packages in order to get access to its cache 237 return ResourceList(self._config.ctx.packages._config, roslib.stacks.packages_of(self.name), Package)
238 239 packages = property(_get_packages)
240
241 -class ManifestResources(Concept):
242 - def __init__(self, ctx, lock, impl_class, list_fn):
243 super(ManifestResources, self).__init__(ctx, lock, impl_class) 244 245 # lazy init for performance reasons 246 self._list_cache = None 247 self._list_fn = list_fn 248 self._impl_class = impl_class
249
250 - def _getAttributeNames(self):
251 if self._list_cache is None: 252 self._list_cache = self._list_fn() 253 return self._list_cache
254
255 - def __getattribute__(self, key):
256 if key.startswith('_') or key == 'trait_names': 257 return object.__getattribute__(self, key) 258 else: 259 return self.__getitem__(key)
260
261 - def __iter__(self):
262 return (getattr(self, k) for k in self._getAttributeNames())
263
264 - def _get_entry(self, key):
265 # generate cache on demand 266 if self._list_cache is None: 267 self._list_cache = self._list_fn() 268 269 # in the future we could try and do a redectect, but not high 270 # priority nor common 271 if not key in self._list_cache: 272 raise AttributeError(key) 273 cache = self._config.cache 274 with self._config.lock: 275 if key in cache: 276 obj = cache[key] 277 else: 278 # create a new instance of ourselves. This requires 279 # subclasses to have same constructor args. 280 obj = self._impl_class(key, self._config) 281 cache[key] = obj 282 return obj
283
284 - def __getitem__(self, key):
285 """ 286 Dictionary-style accessor 287 """ 288 if key in self._config.cache: 289 return self._config.cache[key] 290 else: 291 val = self._get_entry(key) 292 return val
293
294 -class Packages(ManifestResources):
295
296 - def __init__(self, ctx, lock,):
297 super(Packages, self).__init__(ctx, lock, Package, roslib.packages.list_pkgs)
298
299 -class Stacks(ManifestResources):
300
301 - def __init__(self, ctx, lock):
302 super(Stacks, self).__init__(ctx, lock, Stack, roslib.stacks.list_stacks)
303