00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038 """
00039 Implements exchange part of app_manager, which handles listing of
00040 avialable and removable applications.
00041 """
00042
00043 import subprocess
00044 import os
00045 import sys
00046 import yaml
00047 import rospy
00048 from std_msgs.msg import String
00049 from app_manager.msg import ExchangeApp, Icon
00050
00051 class Exchange():
00052 def __init__(self, url, directory, on_error = lambda(x): None):
00053 self._url = url
00054 self._directory = directory
00055 self._on_error = on_error
00056 self._installed_apps = []
00057 self._available_apps = []
00058 self._debs = {}
00059
00060 self._exchange_local = os.path.join(self._directory, "exchange.yaml")
00061 d = os.path.join(self._directory, "installed")
00062 if (not os.path.exists(d)):
00063 os.mkdir(d)
00064 self._exchange_file = os.path.join(d, "app_exchange.installed")
00065 print "Directory:", self._directory
00066 print "Local path:", self._exchange_local
00067 print "Local file:", self._exchange_file
00068 print subprocess.Popen(["whoami"], stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()
00069
00070 def get_installed_version(self, deb):
00071 data = subprocess.Popen(["dpkg", "-l", deb], stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()
00072 val = (data[0] or '').strip()
00073 for i in val.split('\n'):
00074 if (i.find(deb) > 0 and i.find("ii") == 0):
00075 return [s for s in i.strip().split(" ") if s][2]
00076 self._on_error("Failed to get installed version: " + str(data))
00077 return "FAILED"
00078
00079 def get_available_version(self, deb):
00080 data = subprocess.Popen(["apt-cache", "showpkg", deb], stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()
00081 val = (data[0] or '').strip()
00082 nearing = False
00083 for i in val.split('\n'):
00084 if (nearing):
00085 return i.strip().split(" ")[0].strip()
00086 if (i.strip() == "Versions:"):
00087 nearing = True
00088 self._on_error("Failed to get available version: " + str(data))
00089 return "FAILED"
00090
00091 def is_installed(self, deb):
00092 data = subprocess.Popen(["dpkg", "-l", deb], stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()
00093 val = (data[0] or '').strip()
00094 for i in val.split("\n"):
00095 if (i.find(deb) > 0):
00096 return (i.find("ii") == 0)
00097 self._on_error("Error getting installed packages: " + str(data))
00098 return False
00099
00100 def get_installed_apps(self):
00101 return self._installed_apps
00102
00103 def get_available_apps(self):
00104 return self._available_apps
00105
00106 def get_app_details(self, name):
00107 local_path = os.path.join(self._directory, name)
00108 if (not os.path.exists(local_path)):
00109 os.makedirs(local_path)
00110 data = subprocess.Popen(["wget", "-O", os.path.join(local_path, "app.yaml"), (self._url.strip('/') + "/" + name + ".yaml")], stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()
00111 val = (data[0] or '').strip()
00112 print val
00113 try:
00114 data = yaml.load(open(os.path.join(local_path, "app.yaml")))
00115 icon_url = data["icon_url"]
00116 icon_format = data["icon_format"]
00117 val = (subprocess.Popen(["wget", "-O", os.path.join(local_path, "icon" + icon_format), icon_url], stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()[0] or '').strip()
00118 print val
00119 except:
00120 print "No icon"
00121 self.update_local()
00122 for i in self._available_apps:
00123 if (i.name == name):
00124 return i
00125 for i in self._installed_apps:
00126 if (i.name == name):
00127 return i
00128 self._on_error("Problem getting app details: " + str(data))
00129 return None
00130
00131 def install_app(self, app):
00132 deb = False
00133 for i in self._available_apps:
00134 if (i.name == app):
00135 if (deb):
00136 return False
00137 deb = self._debs[i.name]
00138 for i in self._installed_apps:
00139 if (i.name == app):
00140 if (deb):
00141 return False
00142 deb = self._debs[i.name]
00143 if (deb == False):
00144 self._on_error("No debian found for install")
00145 return False
00146 print "install app"
00147 p = subprocess.Popen(["sudo", "rosget", "install", deb], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
00148
00149
00150 pub = rospy.Publisher('install_status', String)
00151 l1 = []
00152 for line in iter(p.stdout.readline, ''):
00153 if line.rstrip() != '':
00154 pub.publish(line.rstrip())
00155 l1.append(line)
00156 else:
00157 break
00158 l2 = []
00159 for line in iter(p.stderr.readline, ''):
00160 if line.rstrip() != '':
00161 pub.publish(line.rstrip())
00162 l2.append(line)
00163 else:
00164 break
00165
00166 data = (''.join(l1), ''.join(l2))
00167 val = (data[0] or '').strip()
00168 print val
00169 self.update_local()
00170 for i in self._installed_apps:
00171 if (i.name == app):
00172 return True
00173 self._on_error("Invalid return for install: " + str(data))
00174 return False
00175
00176 def uninstall_app(self, app):
00177 deb = False
00178 for i in self._installed_apps:
00179 if (i.name == app):
00180 if (deb):
00181 return False
00182 deb = self._debs[i.name]
00183 if (deb == False):
00184 self._on_error("No debian found for uninstall")
00185 return False
00186 print "uninstall app"
00187 data = subprocess.Popen(["sudo", "rosget", "remove", deb], stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()
00188 val = (data[0] or '').strip()
00189 self.update_local()
00190 for i in self._available_apps:
00191 if (i.name == app):
00192 return True
00193 self._on_error("Invalid return for uninstall: " + str(data))
00194 return False
00195
00196 def update(self):
00197
00198 val = (subprocess.Popen(["wget", "-O", self._exchange_local, self._url + "/applications.yaml"], stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()[0] or '').strip()
00199 if (val != "" or not os.path.exists(self._exchange_local)):
00200 print sys.stderr >> val
00201 print sys.stderr >> "Wget failed"
00202 return False
00203
00204 p = subprocess.Popen(["sudo", "rosget", "update"], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
00205 data = p.communicate()
00206 val = (data[0] or '').strip()
00207 if (p.returncode != 0):
00208 self._on_error("Invalid return of update: " + str(data))
00209 self.update_local()
00210 if (p.returncode != 0):
00211 return False
00212 return True
00213
00214 def update_local(self):
00215 installed_apps = []
00216 file_apps = []
00217 available_apps = []
00218 try:
00219 exchange_data = yaml.load(open(self._exchange_local))
00220 except:
00221 return
00222 if (not exchange_data):
00223 return
00224 for app in exchange_data['apps']:
00225 appc = ExchangeApp()
00226 appc.name = app['app']
00227 appc.display_name = app['display']
00228 deb = app['debian']
00229 self._debs[app['app']] = deb
00230 appc.latest_version = self.get_available_version(deb)
00231 appc.hidden = False
00232 try:
00233 if(app['hidden']):
00234 appc.hidden = True
00235 except:
00236 pass
00237
00238 local_path = os.path.join(self._directory, app['app'])
00239 if (os.path.exists(local_path)):
00240 format = ""
00241 if (os.path.exists(os.path.join(local_path, "app.yaml"))):
00242 print local_path
00243 data = yaml.load(open(os.path.join(local_path, "app.yaml")))
00244 try:
00245 appc.description = data['description']
00246 except:
00247 if (appc.hidden):
00248 appc.description = "Descriptionless hidden app"
00249 else:
00250 appc.description = "No description set, likely an error in the yaml file"
00251 try:
00252 format = data['icon_format']
00253 except:
00254 pass
00255 if (os.path.exists(os.path.join(local_path, "icon" + format)) and format != ""):
00256 icon = Icon()
00257 icon.format = format.strip(".")
00258 if (icon.format == "jpg"): icon.format = "jpeg"
00259 icon.data = open(os.path.join(local_path, "icon" + format), "rb").read()
00260 appc.icon = icon
00261 if (self.is_installed(deb)):
00262 appc.version = self.get_installed_version(deb)
00263 installed_apps.append(appc)
00264 file_apps.append(app)
00265 else:
00266 available_apps.append(appc)
00267
00268 f = open(self._exchange_file, "w")
00269 yaml.dump({"apps": file_apps}, f)
00270 f.close()
00271 self._installed_apps = installed_apps
00272 self._available_apps = available_apps
00273
00274