app.py
Go to the documentation of this file.
00001 # Software License Agreement (BSD License)
00002 #
00003 # Copyright (c) 2011, Willow Garage, Inc.
00004 # All rights reserved.
00005 #
00006 # Redistribution and use in source and binary forms, with or without
00007 # modification, are permitted provided that the following conditions
00008 # are met:
00009 #
00010 #  * Redistributions of source code must retain the above copyright
00011 #    notice, this list of conditions and the following disclaimer.
00012 #  * Redistributions in binary form must reproduce the above
00013 #    copyright notice, this list of conditions and the following
00014 #    disclaimer in the documentation and/or other materials provided
00015 #    with the distribution.
00016 #  * Neither the name of Willow Garage, Inc. nor the names of its
00017 #    contributors may be used to endorse or promote products derived
00018 #    from this software without specific prior written permission.
00019 #
00020 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00021 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00022 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00023 # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
00024 # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00025 # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00026 # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00027 # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
00028 # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00029 # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
00030 # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00031 # POSSIBILITY OF SUCH DAMAGE.
00032 #
00033 # Revision $Id: app.py 14667 2011-08-12 23:55:04Z pratkanis $
00034 
00035 # author: leibs, kwc
00036 
00037 import os
00038 import errno
00039 import yaml
00040 
00041 import roslib.names
00042 from roslib.packages import InvalidROSPkgException
00043 from .exceptions import AppException, InvalidAppException, NotFoundException, InternalAppException
00044 
00045 class Interface(object):
00046     def __init__(self, subscribed_topics, published_topics):
00047         self.subscribed_topics = subscribed_topics
00048         self.published_topics = published_topics
00049 
00050     def __eq__(self, other):
00051         if not isinstance(other, Interface):
00052             return False
00053         return self.subscribed_topics == other.subscribed_topics and \
00054                self.published_topics == other.published_topics
00055                
00056 class Client(object):
00057     __slots__ = ['client_type', 'manager_data', 'app_data']
00058     def __init__(self, client_type, manager_data, app_data):
00059         self.client_type = client_type
00060         self.manager_data = manager_data
00061         self.app_data = app_data
00062         
00063     def as_dict(self):
00064         return {'client_type': self.client_type, 'manager_data': self.manager_data, 'app_data': self.app_data}
00065     
00066     def __eq__(self, other):
00067         if not isinstance(other, Client):
00068             return False
00069         return self.client_type == other.client_type and \
00070                self.manager_data == other.manager_data and \
00071                self.app_data == other.app_data
00072 
00073     def __repr__(self):
00074         return yaml.dump(self.as_dict())
00075                
00076 class AppDefinition(object):
00077     __slots__ = ['name', 'display_name', 'description', 'platform',
00078                  'launch', 'interface', 'clients', 'icon']
00079     def __init__(self, name, display_name, description, platform,
00080                  launch, interface, clients, icon=None):
00081         self.name = name
00082         self.display_name = display_name
00083         self.description = description
00084         self.platform=platform
00085         self.launch = launch
00086         self.interface = interface
00087         self.clients = clients
00088         self.icon = icon
00089 
00090     def __repr__(self):
00091         d = {}
00092         for s in self.__slots__:
00093             if s == 'clients':
00094                 d[s] = [c.as_dict() for c in self.clients]
00095             else:
00096                 d[s] = getattr(self, s)
00097         return yaml.dump(d)
00098     #    return "name: %s\ndisplay: %s\ndescription: %s\nplatform: %s\nlaunch: %s\ninterface: %s\nclients: %s"%(self.name, self.display_name, self.description, self.platform, self.launch, self.interface, self.clients)
00099     
00100     def __eq__(self, other):
00101         if not isinstance(other, AppDefinition):
00102             return False
00103         return self.name == other.name and \
00104                self.display_name == other.display_name and \
00105                self.description == other.description and \
00106                self.platform == other.platform and \
00107                self.launch == other.launch and \
00108                self.interface == other.interface and \
00109                self.clients == other.clients and \
00110                self.icon == other.icon
00111                
00112 def find_resource(resource):
00113     """
00114     @return: filepath of resource.  Does not validate if filepath actually exists.
00115     
00116     @raise ValueError: if resource is not a valid resource name.
00117     @raise roslib.packages.InvalidROSPkgException: if package referred
00118         to in resource name cannot be found.
00119     @raise NotFoundException: if resource does not exist.
00120     """
00121     p, a = roslib.names.package_resource_name(resource)
00122     if not p:
00123         raise ValueError("Resource is missing package name: %s"%(resource))
00124     matches = roslib.packages.find_resource(p, a)
00125     # TODO: convert ValueError to better type for better error messages
00126     if len(matches) == 1:
00127         return matches[0]
00128     elif not matches:
00129         raise NotFoundException("No resource [%s]"%(resource))        
00130     else:
00131         raise ValueError("Multiple resources named [%s]"%(resource))        
00132 
00133 def load_Interface_from_file(filename):
00134     """
00135     @raise IOError: I/O error reading file (e.g. does not exist)
00136     @raise InvalidAppException: if app file is invalid
00137     """
00138     with open(filename,'r') as f:
00139         y = yaml.load(f.read())
00140         y = y or {} #coerce to dict
00141         try:
00142             subscribed_topics = y.get('subscribed_topics', {})
00143             published_topics = y.get('published_topics', {})
00144         except KeyError:
00145             raise InvalidAppException("Malformed interface, missing keys")
00146     return Interface(published_topics=published_topics, subscribed_topics=subscribed_topics)
00147 
00148 def _AppDefinition_load_icon_entry(app_data, appfile="UNKNOWN"):
00149     """
00150     @raise InvalidAppExcetion: if app definition is invalid.
00151     """
00152     # load/validate launch entry
00153     try:
00154         icon_resource = app_data.get('icon', '')
00155         if icon_resource == '':
00156             return None
00157         icon_filename = find_resource(icon_resource)
00158         if not icon_filename or not os.path.exists(icon_filename):
00159             return None
00160         return icon_filename
00161     except ValueError as e:
00162         raise InvalidAppException("Malformed appfile [%s]: bad icon entry: %s"%(appfile, e))
00163     except NotFoundException:
00164         # TODO: make this a soft fail?
00165         raise InvalidAppException("App file [%s] refers to icon that cannot be found"%(appfile))
00166     except InvalidROSPkgException as e:
00167         raise InvalidAppException("App file [%s] refers to package that is not installed: %s"%(appfile, str(e)))
00168 
00169 def _AppDefinition_load_launch_entry(app_data, appfile="UNKNOWN"):
00170     """
00171     @raise InvalidAppExcetion: if app definition is invalid.
00172     """
00173     # load/validate launch entry
00174     try:
00175         launch = find_resource(app_data['launch'])
00176         if not os.path.exists(launch):
00177             raise InvalidAppException("Malformed appfile [%s]: refers to launch that does not exist."%(appfile))
00178         return launch
00179     except ValueError as e:
00180         raise InvalidAppException("Malformed appfile [%s]: bad launch entry: %s"%(appfile, e))
00181     except NotFoundException:
00182         raise InvalidAppException("App file [%s] refers to launch that is not installed"%(appfile))
00183     except InvalidROSPkgException as e:
00184         raise InvalidAppException("App file [%s] refers to package that is not installed: %s"%(appfile, str(e)))
00185 
00186 def _AppDefinition_load_interface_entry(app_data, appfile="UNKNOWN"):
00187     """
00188     @raise InvalidAppExcetion: if app definition is invalid.
00189     """
00190     # load/validate interface entry
00191     try:
00192         return load_Interface_from_file(find_resource(app_data['interface']))
00193     except IOError as e:
00194         if e.errno == errno.ENOENT:
00195             raise InvalidAppException("Malformed appfile [%s]: refers to interface file that does not exist"%(appfile))
00196         else:
00197             raise InvalidAppException("Error with appfile [%s]: cannot read interface file"%(appfile))
00198     except ValueError:
00199         raise InvalidAppException("Malformed appfile [%s]: bad interface entry"%(appfile))
00200     except InvalidROSPkgException as e:
00201         raise InvalidAppException("App file [%s] refers to package that is not installed: %s"%(appfile, str(e)))
00202     
00203 def _AppDefinition_load_clients_entry(app_data, appfile="UNKNOWN"):
00204     """
00205     @raise InvalidAppExcetion: if app definition is invalid.
00206     """
00207     clients_data = app_data.get('clients', [])
00208     clients = []
00209     for c in clients_data:
00210         for reqd in ['type', 'manager']:
00211             if not reqd in c:
00212                 raise InvalidAppException("Malformed appfile [%s], missing required key [%s]"%(appfile, reqd))
00213         client_type = c['type']
00214         manager_data = c['manager']
00215         if not type(manager_data) == dict:
00216             raise InvalidAppException("Malformed appfile [%s]: manager data must be a map"%(appfile))
00217 
00218         if client_type == 'web':
00219             if manager_data.has_key('path'):
00220                 url = find_resource(manager_data['path'])
00221                 # newurl = url.replace('/opt/ros/electric/stacks','')
00222                 with open('/etc/ros/app_platform/apache2_config.yaml','r') as f:
00223                     y = yaml.load(f.read())
00224                     y = y or {} #coerce to dict
00225                     for key,value in  y["aliases"].iteritems():
00226                         newurl = url.replace(value, '')     
00227                         if newurl != url:
00228                             manager_data['path'] = '/' + key + newurl
00229                             break
00230 
00231         app_data = c.get('app', {})
00232         if not type(app_data) == dict:
00233             raise InvalidAppException("Malformed appfile [%s]: app data must be a map"%(appfile))
00234 
00235         clients.append(Client(client_type, manager_data, app_data))
00236     return clients
00237 
00238 def load_AppDefinition_from_file(appfile, appname):
00239     """
00240     @raise InvalidAppExcetion: if app definition is invalid.
00241     @raise IOError: I/O error reading appfile (e.g. file does not exist).
00242     """
00243     with open(appfile,'r') as f:
00244         app_data = yaml.load(f.read())
00245         for reqd in ['launch', 'interface', 'platform']:
00246             if not reqd in app_data:
00247                 raise InvalidAppException("Malformed appfile [%s], missing required key [%s]"%(appfile, reqd))
00248 
00249         display_name = app_data.get('display', appname)
00250         description = app_data.get('description', '')        
00251         platform = app_data['platform']
00252 
00253 
00254         launch = _AppDefinition_load_launch_entry(app_data, appfile)
00255         interface = _AppDefinition_load_interface_entry(app_data, appfile)
00256         clients = _AppDefinition_load_clients_entry(app_data, appfile)
00257         icon = _AppDefinition_load_icon_entry(app_data, appfile)
00258 
00259     return AppDefinition(appname, display_name, description, platform,
00260                          launch, interface, clients, icon)
00261     
00262 def load_AppDefinition_by_name(appname):
00263     """
00264     @raise InvalidAppExcetion: if app definition is invalid.
00265     @raise NotFoundExcetion: if app definition is not installed.
00266     @raise ValueError: if appname is invalid.
00267     """
00268     if not appname:
00269         raise ValueError("app name is empty")
00270 
00271     try:
00272         appfile = find_resource(appname + '.app')
00273     except InvalidROSPkgException as e:
00274         raise NotFoundException("Cannot locate app file for %s: package is not installed."%(appname))
00275 
00276     try:
00277         return load_AppDefinition_from_file(appfile, appname)
00278     except IOError as e:
00279         if e.errno == errno.ENOENT:
00280             raise NotFoundException("Cannot locate app file for %s."%(appname))
00281         else:
00282             raise InternalAppException("I/O error loading AppDefinition file: %s."%(e.errno))


app_manager
Author(s): Jeremy Leibs, Ken Conley
autogenerated on Mon Dec 2 2013 11:36:52