$search
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: topics.py 11753 2010-10-25 06:23:19Z kwc $ 00034 00035 # author: kwc 00036 00037 """ 00038 Implements applist part of app_manager, which handles listing of 00039 currently installed applications. 00040 """ 00041 00042 import os 00043 import sys 00044 import yaml 00045 00046 from .app import load_AppDefinition_by_name 00047 from .msg import App, ClientApp, KeyValue, Icon 00048 from .exceptions import AppException, InvalidAppException 00049 00050 def get_default_applist_directory(): 00051 """ 00052 Default directory where applist configuration is stored. 00053 """ 00054 return "/etc/robot/apps" 00055 00056 def dict_to_KeyValue(d): 00057 l = [] 00058 for k, v in d.iteritems(): 00059 l.append(KeyValue(k, str(v))) 00060 return l 00061 00062 def read_Icon_file(filename): 00063 icon = Icon() 00064 if filename == None or filename == "": 00065 return icon 00066 basename, extension = os.path.splitext(filename) 00067 if extension.lower() == ".jpg" or extension.lower() == ".jpeg": 00068 icon.format = "jpeg" 00069 elif extension.lower() == ".png": 00070 icon.format = "png" 00071 else: 00072 icon.format = "" 00073 return icon 00074 icon.data = open(filename, "rb").read() 00075 return icon 00076 00077 def AppDefinition_to_App(app_definition): 00078 a = App(name=app_definition.name, display_name=app_definition.display_name, icon=read_Icon_file(app_definition.icon)) 00079 a.client_apps = [] 00080 for c in app_definition.clients: 00081 a.client_apps.append(ClientApp(c.client_type, 00082 dict_to_KeyValue(c.manager_data), 00083 dict_to_KeyValue(c.app_data))) 00084 return a 00085 00086 class InstalledFile(object): 00087 """ 00088 Models data stored in a .installed file. These files are used to 00089 track installation of apps. 00090 """ 00091 00092 def __init__(self, filename): 00093 self.filename = filename 00094 # list of App 00095 self.available_apps = [] 00096 00097 self._file_mtime = None 00098 self.update() 00099 00100 def _load(self): 00101 available_apps = [] 00102 with open(self.filename) as f: 00103 installed_data = yaml.load(f) 00104 for reqd in ['apps']: 00105 if not reqd in installed_data: 00106 raise InvalidAppException("installed file [%s] is missing required key [%s]"%(self.filename, reqd)) 00107 for app in installed_data['apps']: 00108 for areqd in ['app']: 00109 if not areqd in app: 00110 raise InvalidAppException("installed file [%s] app definition is missing required key [%s]"%(self.filename, areqd)) 00111 available_apps.append(load_AppDefinition_by_name(app['app'])) 00112 00113 self.available_apps = available_apps 00114 00115 def update(self): 00116 """ 00117 Update app list 00118 """ 00119 s = os.stat(self.filename) 00120 if s.st_mtime != self._file_mtime: 00121 self._load() 00122 self._file_mtime = s.st_mtime 00123 00124 class AppList(object): 00125 00126 def __init__(self, applist_directories): 00127 self.applist_directories = applist_directories 00128 self.installed_files = {} 00129 self.invalid_installed_files = [] 00130 self.app_list = [] 00131 00132 self._applist_directory_mtime = None 00133 self.update() 00134 00135 def _load(self): 00136 app_list = [] 00137 invalid_installed_files = [] 00138 00139 dir_list = [] 00140 for i in self.applist_directories: 00141 for k in os.listdir(i): 00142 dir_list.append(k) 00143 00144 00145 for f in set(self.installed_files.keys()) - set(dir_list): 00146 print "deleting installation data for [%s]"%(f) 00147 del self.installed_files[f] 00148 00149 for i in self.applist_directories: 00150 for f in os.listdir(i): 00151 print f 00152 if not f.endswith('.installed'): 00153 continue 00154 try: 00155 if f in self.installed_files: 00156 installed_file = self.installed_files[f] 00157 installed_file.update() 00158 else: 00159 print "loading installation data for [%s]"%(f) 00160 filename = os.path.join(i, f) 00161 installed_file = InstalledFile(filename) 00162 self.installed_files[f] = installed_file 00163 00164 app_list.extend(installed_file.available_apps) 00165 00166 except AppException as ae: 00167 print >> sys.stderr, "ERROR: %s"%(str(ae)) 00168 invalid_installed_files.append((filename, ae)) 00169 except Exception as e: 00170 print >> sys.stderr, "ERROR: %s"%(str(e)) 00171 invalid_installed_files.append((filename, e)) 00172 00173 self.app_list = app_list 00174 self.invalid_installed_files = invalid_installed_files 00175 00176 def get_app_list(self): 00177 return [AppDefinition_to_App(ad) for ad in self.app_list] 00178 00179 def add_directory(self, directory): 00180 self.applist_directories.append(directory) 00181 00182 def update(self): 00183 """ 00184 Update app list 00185 """ 00186 00187 bad = True 00188 #TODO: this detects when the directories are actually modified. 00189 #It does not work because os.stat(i).st_mtime does not change if 00190 #only a file is modified. 00191 #s = [] 00192 #for i in self.applist_directories: 00193 # s.append(os.stat(i).st_mtime) 00194 # 00195 #bad = True 00196 #if self._applist_directory_mtime != None: 00197 # if len(s) == len(self._applist_directory_mtime): 00198 # bad = False 00199 # for i in range(0, len(s)): 00200 # if s[i] != self._applist_directory_mtime[i]: 00201 # bad = True 00202 00203 if (bad): 00204 self._load() 00205 #self._applist_directory_mtime = s