exchange.py
Go to the documentation of this file.
00001 #! /usr/bin/python
00002 # Software License Agreement (BSD License)
00003 #
00004 # Copyright (c) 2011, Willow Garage, Inc.
00005 # All rights reserved.
00006 #
00007 # Redistribution and use in source and binary forms, with or without
00008 # modification, are permitted provided that the following conditions
00009 # are met:
00010 #
00011 #  * Redistributions of source code must retain the above copyright
00012 #    notice, this list of conditions and the following disclaimer.
00013 #  * Redistributions in binary form must reproduce the above
00014 #    copyright notice, this list of conditions and the following
00015 #    disclaimer in the documentation and/or other materials provided
00016 #    with the distribution.
00017 #  * Neither the name of Willow Garage, Inc. nor the names of its
00018 #    contributors may be used to endorse or promote products derived
00019 #    from this software without specific prior written permission.
00020 #
00021 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00022 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00023 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00024 # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
00025 # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00026 # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00027 # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00028 # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
00029 # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00030 # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
00031 # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00032 # POSSIBILITY OF SUCH DAMAGE.
00033 #
00034 # Revision $Id: topics.py 11753 2010-10-25 06:23:19Z kwc $
00035 
00036 # author: pratkanis
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 .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 #Somehow a dupe
00137                 deb = self._debs[i.name]
00138         for i in self._installed_apps:
00139             if (i.name == app):
00140                 if (deb):
00141                     return False #Somehow a dupe                                                                                                                                                                                              
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         #data = p.communicate()
00149         #data = "test string"
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 #Somehow a dupe 
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         #Call server
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) #Should remove debian tag?
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     


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