def __init__(self): xdg = XdgUtils() # Can we use a custom glib loader? self.glibc_loader = os.path.exists("/lib/ld-klik2.so.2") # Attempt to load version from svnversion file svnversion_path = os.path.join(sys.path[0], os.pardir, "share", "klik", "svnversion") if os.path.exists(svnversion_path): f = open(svnversion_path, "r") self.version = self.version + "." + f.readline().strip() + "svn" f.close() # default destination self.destination = xdg.get_desktop_dir() # Hardcoded default values self.desktop_icon_size = 48 self.debug = False self.temp_cache_downloads = False self.application_folders = [self.destination] self.application_folder_notify = True self.always_show_app_chooser = False self.default_jail_type = 0 # Load global, override code system_settings_path = os.path.join(sys.path[0], os.pardir, "share", "klik", "settings.xml") self.__load_file(system_settings_path) # Load user, overides global user_settings_directory = os.path.expanduser("~/.klik") user_settings_path = os.path.join(user_settings_directory, "settings.xml") self.__load_file(user_settings_path) # Remove duplicates in application folders list set = {} self.application_folders = [ set.setdefault(x, x) for x in self.application_folders if x not in set ] # If user settings file doesn't exist, create it if not os.path.isdir(user_settings_directory): os.mkdir(user_settings_directory) if not os.path.exists(user_settings_path): shutil.copy(system_settings_path, user_settings_path) if os.getenv("KLIK_DEBUG") != None: self.debug = (os.getenv("KLIK_DEBUG") == "1")
def __init__(self, klikbase): # Objects we will use self.klik = klikbase self.xdg = XdgUtils() self.args = None self.recipe = None # Current install status # 0 - not started, 1 - downloading, 2 - compiling cmg, 3 -complete self.install_status = 0 # Load glade file self.gladefile = os.path.join(self.klik.sys_path, os.pardir, "share", "klik", "klik.glade") self.wtree = gtk.glade.XML(self.gladefile) self.window = self.wtree.get_widget("download_prompt") self.window.set_icon_from_file( os.path.join(self.klik.sys_path, os.pardir, "share", "klik", "klik-window.png")) dic = { "on_button_cancel_clicked": self.on_button_cancel_clicked, "on_download_prompt_destroy": self.on_download_prompt_destroy } self.wtree.signal_autoconnect(dic) # Initialize download prompt self.download_prompt = DownloadPrompt(self) self.progress_dialog = ProgressDialog(self) self.feedback_dialog = FeedbackDialog(self)
def __init__(self, sys_path=sys.path[0]): self.sys_path = sys_path self.events = KlikBaseEvents() self.create = KlikCreate(self) self.settings = KlikSettings() self.xdg = XdgUtils() self.notify = Notify() self.create.events.on_download_progress += self.__download_progress self.create.events.print_to_stdout += self.print_to_stdout self.current_progress_percentage = 0 self.current_progress_text = "" self.temp_paths = [] # Insure temp path exists if not os.path.exists(self.settings.temp_directory_path): os.mkdir(self.settings.temp_directory_path)
def __init__(self): xdg = XdgUtils() # Attempt to load version from svnversion file svnversion_path = os.path.join(sys.path[0] , os.pardir, "share", "klik", "svnversion") if os.path.exists(svnversion_path): f = open(svnversion_path, "r") self.version = self.version + "." + f.readline().strip() + "svn" f.close() # default destination self.destination = xdg.get_desktop_dir() # Hardcoded default values self.desktop_icon_size = 48 self.debug = False self.temp_cache_downloads = False self.application_folders = [self.destination] self.application_folder_notify = True self.always_show_app_chooser = False self.default_jail_type = 0 # Load global, override code system_settings_path = os.path.join(sys.path[0], os.pardir, "share", "klik", "settings.xml") self.__load_file( system_settings_path ) # Load user, overides global user_settings_directory = os.path.expanduser("~/.klik") user_settings_path = os.path.join(user_settings_directory, "settings.xml") self.__load_file( user_settings_path ) # Remove duplicates in application folders list set = {} self.application_folders = [set.setdefault(x,x) for x in self.application_folders if x not in set] # if user settings file dosnt exist create it if os.path.exists(system_settings_path) and not os.path.exists(user_settings_path): if not os.path.isdir(user_settings_directory): os.mkdir(user_settings_directory) shutil.copy(system_settings_path, user_settings_path)
def __init__(self, sys_path=sys.path[0]): self.sys_path = sys_path self.events = KlikBaseEvents() self.create = KlikCreate(self) self.settings = KlikSettings() self.xdg = XdgUtils() self.notify = Notify() self.create.events.on_download_progress += self.__download_progress self.create.events.print_to_stdout += self.print_to_stdout self.current_progress_percentage = 0 self.current_progress_text = "" self.temp_paths = [] # Insure temp path exists if not os.path.exists( self.settings.temp_directory_path ): os.mkdir(self.settings.temp_directory_path)
from optparse import OptionParser opt = OptionParser() opt.add_option("--prefix", metavar="<dir>", dest="prefix", default="/opt/klik") (options, args) = opt.parse_args() klik_install_path = options.prefix klik_files_path = sys.path[0] sys.path.insert(1, klik_files_path + "/klikclient/lib") # XDG UTILS from klik.utils.xdg import XdgUtils xdg = XdgUtils( os.path.join(sys.path[0], "klikclient", "lib", "klik", "utils", "xdg-utils"), "SYSTEM") # Check for root if xdg.is_root() == False: print("You must be root in order to run " + sys.argv[0] + ", exiting") sys.exit(1) else: print "Privileged mode detected ..." # Remove sub folders print "" print "Remove klik sub folders ..." path = os.path.join(klik_install_path, "share/klik") if not os.path.exists(path): shutil.rmtree(path, True)
class KlikBase(object): def __init__(self, sys_path=sys.path[0]): self.sys_path = sys_path self.events = KlikBaseEvents() self.create = KlikCreate(self) self.settings = KlikSettings() self.xdg = XdgUtils() self.notify = Notify() self.create.events.on_download_progress += self.__download_progress self.create.events.print_to_stdout += self.print_to_stdout self.current_progress_percentage = 0 self.current_progress_text = "" self.temp_paths = [] # Insure temp path exists if not os.path.exists(self.settings.temp_directory_path): os.mkdir(self.settings.temp_directory_path) # Custom print method so we can capture stdout def print_to_stdout(self, obj, no_new_line=False): if no_new_line: sys.stdout.write(obj) sys.stdout.flush() self.events.print_to_stdout(obj) else: print obj self.events.print_to_stdout(obj + "\n") def post_feedback(self, recipe, workingyesno, errorreport, librarytrace, md5sum, comment): content = [] content.append("package=" + urllib.quote(recipe.name)) # content.append("version=" + urllib.quote(recipe.version)) content.append("workingyesno=" + urllib.quote(str(workingyesno))) # content.append("systeminformation=" + urllib.quote(self.system_info())) # content.append("comment=" + urllib.quote(comment)) # # f1 = file(os.path.join(path_1, os.listdir(path_1)[0]) ,'rb') # md5.new(f1.read()).digest() # f1.close() # only post error info on a failure if not workingyesno: content.append("errorreport=" + urllib.quote(errorreport)) content.append("librarytrace=" + urllib.quote(librarytrace)) content.append("recipe=" + urllib.quote(recipe.original_xml)) #content.append("md5sum=" + urllib.quote( librarytrace )) url_parts = urlparse.urlparse(self.settings.default_feedback_url) body = "&".join(content) h = httplib.HTTP(url_parts[1]) h.putrequest('POST', url_parts[2]) h.putheader('content-type', "application/x-www-form-urlencoded") h.putheader('content-length', str(len(body))) h.endheaders() try: h.send(body) #h.getreply() #print h.file.read() except: pass def check_for_updated_recipe(self, recipe): try: new_recipe = self.get_recipe(recipe.source_uri) # Has the recipe changed old_md5_hash = md5.new(recipe.original_xml).hexdigest() new_md5_hash = md5.new(new_recipe.original_xml).hexdigest() if not old_md5_hash == new_md5_hash: # Should we also check application version numbers? # A recipe might change just to fix a run time error etc... return True, new_recipe except: pass # If we cant get a recipe always return false return False, None def get_recipe(self, application_name): # Get information about users system plat = platform.system() + " " + platform.machine() pyvers = "Python/" + platform.python_version() useragent = "klik/%s (%s; %s; %s; %s;) %s (%s)" % ( self.settings.version, self.xdg.get_is_terminal(), plat, self.xdg.get_lang(), self.xdg.get_desktop_enviroment() + "+" + "+".join(self.xdg.get_installed_libs()), pyvers, self.xdg.get_distribution()) # Convert to lower case for comparing application_name = application_name.lower() # Download Recipe if application_name.startswith("http://"): url = application_name else: # Strip klik protocol if application_name.startswith("klik2://"): application_name = application_name[8:] elif application_name.startswith("klik2:"): application_name = application_name[6:] if application_name.startswith("klik://"): application_name = application_name[7:] elif application_name.startswith("klik:"): application_name = application_name[5:] url = self.settings.default_download_url + application_name print "Recipe URL: " + url try: request = urllib2.Request(url) request.add_header('User-Agent', useragent) opener = urllib2.build_opener() data = opener.open(request).read() except: raise SafeException( "Error occurred while attempting to download recipe") # Load Recipe print "" print "Parsing recipe..." recipe = KlikRecipe() recipe.load_from_string(data) self.print_recipe(recipe) return recipe def print_recipe(self, recipe): print "" print "Application details" print "===================" print u"Name: %s" % recipe.name print u"Version: %s" % recipe.version trusted, text = recipe.is_trusted() if trusted == True: print "Trusted Contact : " + text else: print "Trust Level : UNTRUSTED - This recipe has not been signed by someone you trust" print u"Summary: %s" % recipe.summary print u"Description: %s" % recipe.description print "" def load_recipe(self, recipe_path): recipe = KlikRecipe() recipe.load_from_file(recipe_path) return recipe def create_cmg(self, recipe_object): return self.create.create(recipe_object, self.settings.destination) def execute_cmg(self, command, cmg_path, args, capture_error=False, force_prompt=False): ex = KlikExecute(self) desktop_object = None cmg_version = self.is_valid_cmg(cmg_path) if cmg_version == 2: # CLI should add commands to line if force_prompt or command == None or command.strip() == "": # Need to check recipe command # Parse out command and parameters recipe = self.extract_recipe(cmg_path) parse_count = 0 parse_args = len(args) == 0 p = re.compile("(('[^']+')|(\"[^\"]+\")|([^\s]+))+") for r in re.finditer(p, recipe.command): if parse_count == 0: command = r.group(0) elif parse_args: args.append(r.group(0)) parse_count = parse_count + 1 # look at desktop files if force_prompt or command == None or command.strip( ) == "" or self.settings.always_show_app_chooser: desktop_objects = self.get_desktop_objects(cmg_path, False) if force_prompt or self.xdg.get_is_x_display( ) and len(desktop_objects) > 1: desktop_object = None # if self.xdg.get_desktop_enviroment() == "GNOME" and : if self.xdg.get_is_gtk_installed(): # this dialouge will return the selected desktop object from klik.gtk.multiple import MultipleApplications ma = MultipleApplications(self) desktop_object = ma.load_items(desktop_objects) # QT ? if desktop_object != None: exec_array = desktop_object.get_exec_array() command = exec_array[0] else: return 1, "User Cancelled" else: if len(desktop_objects) > 0: desktop_object = desktop_objects[0] exec_array = desktop_object.get_exec_array() command = exec_array[0] return ex.execute(command, cmg_path, args, capture_error, cmg_version) def check_for_missing_library(self, command, cmg_path): ex = KlikExecute(self) return ex.check_for_missing_library(command, cmg_path) def create_jailed_cmg(self, cmg_path, jail_type="data"): sandbox = KlikSandBox(cmg_path) sandbox.create_jail(jail_type) return def extract_recipe(self, cmg_path): temp_path = tempfile.mktemp() self.extract_file(cmg_path, "/recipe.xml", temp_path) try: recipe = self.load_recipe(temp_path) os.remove(temp_path) return recipe except: # no recipe pass return None def extract_file(self, cmg_path, file_path_from, file_path_to): if self.is_klik1_cmg(cmg_path): if file_path_from[0] == "/": file_path_from = file_path_from[1:] temp_path = tempfile.mkdtemp('.extract.' + os.environ["USER"], self.settings.temp_directory_path) try: try: subprocess.Popen([ "/opt/klik/bin/fusecram", "-n", "-p", cmg_path, temp_path, "-s" ]).wait() shutil.copy(os.path.join(temp_path, file_path_from), file_path_to) except IOError: return False finally: subprocess.Popen(["fusermount", "-u", temp_path]).wait() else: subprocess.Popen([ "cmginfo", "-f", cmg_path, "-e", file_path_from, "-o", file_path_to ]).wait() return os.path.exists(file_path_to) def open_application_folder(self, index=0): self.xdg.open(self.settings.application_folders[index]) def is_valid_cmg(self, path): if os.path.isfile(path): mtype, entype = mimetypes.guess_type(path) if mtype in ["application/x-extension-cmg"]: return 2 else: if self.is_klik2_cmg(path): return 2 if self.is_klik1_cmg(path): return 1 return 1 def is_klik2_cmg(self, path): # Klik2 Compatability.... f = open(path, "r") f.seek(22) # Go to the 22nd byte in the file magic = str(f.read(28)).strip() test = magic.startswith( "# Compressed Application Ima" ) or magic.startswith("# KLIK2 ISO") or magic.startswith( "Compressed Application Image") or magic.startswith("KLIK2 ISO") return test def is_klik1_cmg(self, path): # Klik1 Compatability.... f = open(path, "r") f.seek(16) # Go to the 16th byte in the file test = (str(f.read(16)).strip() == "Compressed ROMFS") f.close() return test def is_valid_recipe(self, filename): mtype, entype = mimetypes.guess_type(filename) if mtype in [ "text/xml", "application/xml", "application/x-extension-cmg-recipe" ]: return True if mtype == None: return filename.endswith(".recipe") or filename.endswith(".xml") return False def find_sub_directories(self, path, cmg_path): directories = [] p = subprocess.Popen(["cmginfo", "-f", cmg_path, "-l", path, "-v"], stdout=subprocess.PIPE) for line in p.stdout: line = line.strip() if line[0] == "d": directories.append(line[2:]) p.stdout.close() return directories # Return all the files in a given CMG that match pre and post text def find_files(self, cmg_path, pre_text=None, post_text=None, omit_extension=False): if omit_extension: # If post text contains a file extension, remove it if post_text: post_text = os.path.splitext(post_text)[0] files = [] p = subprocess.Popen(["isoinfo", "-R", "-f", "-i", cmg_path], stdout=subprocess.PIPE) #p = subprocess.Popen(["cmginfo", cmg_path], stdout=subprocess.PIPE) - this is WAY to slow for file in p.stdout: file = file.strip() if post_text != None: if omit_extension: file_ends = file.endswith(post_text, 0, -4) else: file_ends = file.endswith(post_text) if (pre_text == None or file.startswith(pre_text)) and (post_text == None or file_ends): files.append(file) p.stdout.close() return files def scan_cmg_icons(self, cmg_path, do): # Returns a list of icons for a .desktop entry icon = do.get("Icon") if not icon: # No icon specifyed, fallback to CMG icon return ["/.DirIcon"] else: # Check if the icon belongs to the default theme theme_icon = None if icon[0] != "/" and self.xdg.get_is_gtk_installed(): try: # never rely on gtk import gtk.utils theme_icon = gtk.utils.find_icon_from_theme(icon) except: pass if theme_icon: return [theme_icon] if not theme_icon: # If icon doesn't belong to a theme, search it in the CMG icon_files = self.find_files(cmg_path, "/usr/share/icons/", icon, omit_extension=True) if icon_files: return icon_files else: # Icon doesn't exist, fallback to CMG icon return ["/.DirIcon"] # Get desktop objects set to execute cmg def get_desktop_objects(self, cmg_path, fix_exec=True): # Search application .desktop files desktop_files = self.find_files(cmg_path, "/usr/share/applications/", ".desktop") desktop_objects = [] for file in desktop_files: # Extract and parse the .desktop file temp_path = tempfile.mktemp() if not self.extract_file(cmg_path, file, temp_path): print "\t!! Couldn't extract", file else: do = DesktopParser(temp_path) command = do.get("Exec") if do.get("Type") == "Application" and command != None: # Parse command and change it to point to CMG if fix_exec: do.set("Exec", "klik exec \"" + cmg_path + "\" " + command) else: do.set("Exec", command) do.set("X-CMG", cmg_path) desktop_objects.append(do) os.remove(temp_path) # Attempt to generate desktop files from debian menu if len(desktop_objects) == 0: menu_files = self.find_files(cmg_path, "/usr/share/menu/") for menu_file in menu_files: # Extract and parse the .desktop file temp_path = tempfile.mktemp() if not self.extract_file(cmg_path, menu_file, temp_path): print "\t!! Couldn't extract", menu_file else: for mo in MenuParser(temp_path).menu_objects: do = DesktopParser() do.set("Type", "Application") if fix_exec: do.set( "Exec", "klik exec \"" + cmg_path + "\" " + mo.command) else: do.set("Exec", mo.command) do.set("X-CMG", cmg_path) do.set("Name", mo.title.capitalize()) #do.set("Terminal", recipe.require_terminal) do.set("Icon", mo.icon) do.set("Categories", mo.freedesktop_category) desktop_objects.append(do) # Couldn't find any desktop file, build a basic one if len(desktop_objects) == 0: # With klik2 packages, extract information from recipe # With klik1 packages, make up information cmg_version = self.is_valid_cmg(cmg_path) recipe = None if cmg_version == 2: recipe = self.extract_recipe(cmg_path) do = DesktopParser() if fix_exec or (cmg_version == 1): do.set("Exec", "klik \"" + cmg_path + "\"") # dont need to not fix this one.. else: if recipe.command: do.set("Exec", recipe.command) else: do.set("Exec", recipe.name) if recipe: name = recipe.name.capitalize() terminal = recipe.require_terminal else: name = os.path.splitext( os.path.split(cmg_path)[1])[0].capitalize() terminal = False do.set("Name", name) do.set("Terminal", terminal) do.set("Type", "Application") do.set("Icon", "/.DirIcon") do.set("X-CMG", cmg_path) # Debtags / categories if recipe and recipe.debtags.has_key("use"): category = klik.utils.freedesktop.get_freedesktop_category_from_debtag( recipe.debtags["use"]) if category != None: do.set("Categories", category) desktop_objects.append(do) return desktop_objects def extract_icon(self, cmg_path, file_path_to, image_size): if self.extract_file(cmg_path, "/.DirIcon", file_path_to): # Check image size if image_size > -1: try: from klik.utils.images import Images img = Images() # NOTE : image_size is the thumbnail size NOT the icon size.... img.check_image_size(file_path_to, self.settings.desktop_icon_size) except Exception, text: pass return True return False
opt = OptionParser() opt.add_option("--prefix", metavar="<dir>", dest="prefix", default = "/opt/klik") (options, args) = opt.parse_args() klik_install_path = options.prefix klik_files_path = sys.path[0] sys.path.insert(1, klik_files_path + "/klikclient/lib") # XDG UTILS from klik.utils.xdg import XdgUtils xdg = XdgUtils( os.path.join(sys.path[0], "klikclient", "lib", "klik", "utils", "xdg-utils") ) # Check for root if xdg.is_root() == False: print ("You must be root in order to run "+sys.argv[0]+", exiting") sys.exit(1) def check_command_exists( command ): path = Popen(["which", command], stdout=PIPE, stderr=open(os.devnull, "w")).communicate()[0].strip() if path != "": print " - %s: found at %s " % (command, path) else: print " - %s: NOT FOUND" % (command) print ""
class KlikBase (object): def __init__(self, sys_path=sys.path[0]): self.sys_path = sys_path self.events = KlikBaseEvents() self.create = KlikCreate(self) self.settings = KlikSettings() self.xdg = XdgUtils() self.notify = Notify() self.create.events.on_download_progress += self.__download_progress self.create.events.print_to_stdout += self.print_to_stdout self.current_progress_percentage = 0 self.current_progress_text = "" self.temp_paths = [] # Insure temp path exists if not os.path.exists( self.settings.temp_directory_path ): os.mkdir(self.settings.temp_directory_path) # Custom print method so we can capture stdout def print_to_stdout(self, obj, no_new_line=False): if no_new_line: sys.stdout.write( obj ) sys.stdout.flush() self.events.print_to_stdout( obj ) else: print obj self.events.print_to_stdout( obj + "\n") def post_feedback(self, recipe, workingyesno, errorreport, librarytrace, md5sum, comment): content = [] content.append("package=" + urllib.quote( recipe.name )) # content.append("version=" + urllib.quote( recipe.version )) content.append("workingyesno=" + urllib.quote( str(workingyesno) )) # content.append("systeminformation=" + urllib.quote( self.system_info() )) # content.append("comment=" + urllib.quote( comment )) # # f1 = file(os.path.join(path_1, os.listdir(path_1)[0]) ,'rb') # md5.new(f1.read()).digest() # f1.close() # only post error info on a failure if not workingyesno: content.append("errorreport=" + urllib.quote( errorreport )) content.append("librarytrace=" + urllib.quote( librarytrace )) content.append("recipe=" + urllib.quote( recipe.original_xml )) #content.append("md5sum=" + urllib.quote( librarytrace )) url_parts = urlparse.urlparse(self.settings.default_feedback_url) body = "&".join(content) h = httplib.HTTP(url_parts[1]) h.putrequest('POST', url_parts[2]) h.putheader('content-type', "application/x-www-form-urlencoded") h.putheader('content-length', str(len(body))) h.endheaders() try: h.send(body) #h.getreply() #print h.file.read() except: pass def check_for_updated_recipe(self, recipe): try: new_recipe = self.get_recipe(recipe.source_uri) # Has the recipe changed old_md5_hash = md5.new(recipe.original_xml).hexdigest() new_md5_hash = md5.new(new_recipe.original_xml).hexdigest() if not old_md5_hash == new_md5_hash: # Should we also check application version numbers? # A recipe might change just to fix a run time error etc... return True, new_recipe except: pass # If we cant get a recipe always return false return False, None def get_recipe(self, application_name ): # Get information about users system plat = platform.system() + " " + platform.machine() pyvers = "Python/"+ platform.python_version() useragent = "klik/%s (%s; %s; %s; %s;) %s (%s)" % (self.settings.version, self.xdg.get_is_terminal(), plat, self.xdg.get_lang(), self.xdg.get_desktop_enviroment()+"+"+ "+".join(self.xdg.get_installed_libs()), pyvers, self.xdg.get_distribution()) # Convert to lower case for comparing application_name = application_name.lower() # Download Recipe if application_name.startswith("http://"): url = application_name else: # Strip klik protocol if application_name.startswith("klik2://"): application_name = application_name[8:] elif application_name.startswith("klik2:"): application_name = application_name[6:] if application_name.startswith("klik://"): application_name = application_name[7:] elif application_name.startswith("klik:"): application_name = application_name[5:] url = self.settings.default_download_url + application_name print "Recipe URL: " + url try: request = urllib2.Request(url) request.add_header('User-Agent',useragent) opener = urllib2.build_opener() data = opener.open(request).read() except: raise SafeException("Error occurred while attempting to download recipe") # Load Recipe print "" print "Parsing recipe..." recipe = KlikRecipe() recipe.load_from_string( data ) self.print_recipe(recipe) return recipe def print_recipe(self, recipe): print "" print "Application details" print "===================" print u"Name: %s" % recipe.name print u"Version: %s" % recipe.version trusted, text = recipe.is_trusted() if trusted == True: print "Trusted Contact : " + text else: print "Trust Level : UNTRUSTED - This recipe has not been signed by someone you trust" print u"Summary: %s" % recipe.summary print u"Description: %s" % recipe.description print "" def load_recipe(self, recipe_path): recipe = KlikRecipe() recipe.load_from_file( recipe_path ) return recipe def create_cmg(self, recipe_object ): return self.create.create( recipe_object, self.settings.destination ) def execute_cmg(self, command, cmg_path, args, capture_error=False, force_prompt=False ): ex = KlikExecute(self) desktop_object = None cmg_version = self.is_valid_cmg(cmg_path) if cmg_version == 2: # CLI should add commands to line if force_prompt or command == None or command.strip() == "": # Need to check recipe command # Parse out command and parameters recipe = self.extract_recipe(cmg_path) parse_count = 0 parse_args = len(args) == 0 p = re.compile("(('[^']+')|(\"[^\"]+\")|([^\s]+))+") for r in re.finditer(p, recipe.command): if parse_count == 0: command = r.group(0) elif parse_args: args.append(r.group(0)) parse_count = parse_count + 1 # look at desktop files if force_prompt or command == None or command.strip() == "" or self.settings.always_show_app_chooser: desktop_objects = self.get_desktop_objects(cmg_path, False) if force_prompt or self.xdg.get_is_x_display() and len(desktop_objects) > 1: desktop_object = None # if self.xdg.get_desktop_enviroment() == "GNOME" and : if self.xdg.get_is_gtk_installed(): # this dialouge will return the selected desktop object from klik.gtk.multiple import MultipleApplications ma = MultipleApplications(self) desktop_object = ma.load_items( desktop_objects ) # QT ? if desktop_object != None: exec_array = desktop_object.get_exec_array() command = exec_array[0] else: return 1, "User Cancelled" else: if len(desktop_objects) > 0: desktop_object = desktop_objects[0] exec_array = desktop_object.get_exec_array() command = exec_array[0] return ex.execute( command, cmg_path, args, capture_error, cmg_version ) def check_for_missing_library(self, command, cmg_path): ex = KlikExecute(self) return ex.check_for_missing_library( command, cmg_path ) def create_jailed_cmg(self, cmg_path, jail_type="data"): sandbox = KlikSandBox(cmg_path) sandbox.create_jail( jail_type ) return def extract_recipe(self, cmg_path): temp_path = tempfile.mktemp() self.extract_file(cmg_path, "/recipe.xml", temp_path) try: recipe = self.load_recipe( temp_path ) os.remove(temp_path) return recipe except: # no recipe pass return None def extract_file(self, cmg_path, file_path_from, file_path_to): if self.is_klik1_cmg( cmg_path ): if file_path_from[0] == "/": file_path_from = file_path_from[1:] temp_path = tempfile.mkdtemp( '.extract.' + os.environ["USER"], self.settings.temp_directory_path ) try: try: subprocess.Popen(["/opt/klik/bin/fusecram", "-n", "-p", cmg_path, temp_path, "-s"]).wait() shutil.copy( os.path.join(temp_path, file_path_from), file_path_to ) except IOError: return False finally: subprocess.Popen(["fusermount", "-u", temp_path]).wait() else: subprocess.Popen(["cmginfo", "-f", cmg_path, "-e", file_path_from, "-o", file_path_to]).wait() return os.path.exists( file_path_to ) def open_application_folder(self, index=0): self.xdg.open(self.settings.application_folders[index]) def is_valid_cmg(self, path): if os.path.isfile( path ): mtype, entype = mimetypes.guess_type(path) if mtype in ["application/x-extension-cmg"]: return 2 else: if self.is_klik2_cmg( path ): return 2 if self.is_klik1_cmg( path ): return 1 return 1 def is_klik2_cmg(self, path): # Klik2 Compatability.... f = open(path, "r") f.seek(22) # Go to the 22nd byte in the file magic = str(f.read(28)).strip() test = magic.startswith( "# Compressed Application Ima" ) or magic.startswith( "# KLIK2 ISO" ) or magic.startswith( "Compressed Application Image" ) or magic.startswith( "KLIK2 ISO") return test def is_klik1_cmg(self, path): # Klik1 Compatability.... f = open(path, "r") f.seek(16) # Go to the 16th byte in the file test = ( str(f.read(16)).strip() == "Compressed ROMFS" ) f.close() return test def is_valid_recipe(self, filename): mtype, entype = mimetypes.guess_type(filename) if mtype in [ "text/xml", "application/xml", "application/x-extension-cmg-recipe" ]: return True if mtype == None: return filename.endswith(".recipe") or filename.endswith(".xml") return False def find_sub_directories(self, path, cmg_path): directories = [] p = subprocess.Popen(["cmginfo", "-f", cmg_path, "-l", path, "-v"], stdout=subprocess.PIPE) for line in p.stdout: line = line.strip() if line[0] == "d": directories.append( line[2:] ) p.stdout.close() return directories # Return all the files in a given CMG that match pre and post text def find_files(self, cmg_path, pre_text=None, post_text=None, omit_extension=False): if omit_extension: # If post text contains a file extension, remove it if post_text: post_text = os.path.splitext( post_text )[0] files = [] p = subprocess.Popen(["isoinfo", "-R", "-f", "-i", cmg_path], stdout=subprocess.PIPE) #p = subprocess.Popen(["cmginfo", cmg_path], stdout=subprocess.PIPE) - this is WAY to slow for file in p.stdout: file = file.strip() if post_text != None: if omit_extension: file_ends = file.endswith(post_text, 0, -4) else: file_ends = file.endswith(post_text) if (pre_text == None or file.startswith(pre_text)) and (post_text == None or file_ends): files.append( file ) p.stdout.close() return files def scan_cmg_icons(self, cmg_path, do): # Returns a list of icons for a .desktop entry icon = do.get( "Icon" ) if not icon: # No icon specifyed, fallback to CMG icon return ["/.DirIcon"] else: # Check if the icon belongs to the default theme theme_icon = None if icon[0] != "/" and self.xdg.get_is_gtk_installed(): try: # never rely on gtk import gtk.utils theme_icon = gtk.utils.find_icon_from_theme( icon ) except: pass if theme_icon: return [theme_icon] if not theme_icon: # If icon doesn't belong to a theme, search it in the CMG icon_files = self.find_files( cmg_path, "/usr/share/icons/", icon, omit_extension=True ) if icon_files: return icon_files else: # Icon doesn't exist, fallback to CMG icon return ["/.DirIcon"] # Get desktop objects set to execute cmg def get_desktop_objects(self, cmg_path, fix_exec=True): # Search application .desktop files desktop_files = self.find_files(cmg_path, "/usr/share/applications/", ".desktop") desktop_objects = [] for file in desktop_files: # Extract and parse the .desktop file temp_path = tempfile.mktemp() if not self.extract_file( cmg_path, file, temp_path ): print "\t!! Couldn't extract", file else: do = DesktopParser( temp_path ) command = do.get("Exec") if do.get("Type") == "Application" and command != None: # Parse command and change it to point to CMG if fix_exec: do.set( "Exec", "klik exec \"" + cmg_path + "\" " + command ) else: do.set( "Exec", command ) do.set( "X-CMG", cmg_path ) desktop_objects.append( do ) os.remove( temp_path ) # Attempt to generate desktop files from debian menu if len(desktop_objects) == 0: menu_files = self.find_files(cmg_path, "/usr/share/menu/") for menu_file in menu_files: # Extract and parse the .desktop file temp_path = tempfile.mktemp() if not self.extract_file( cmg_path, menu_file, temp_path ): print "\t!! Couldn't extract", menu_file else: for mo in MenuParser( temp_path ).menu_objects: do = DesktopParser() do.set("Type", "Application") if fix_exec: do.set("Exec", "klik exec \"" + cmg_path + "\" " + mo.command) else: do.set("Exec", mo.command) do.set( "X-CMG", cmg_path ) do.set("Name", mo.title.capitalize()) #do.set("Terminal", recipe.require_terminal) do.set("Icon", mo.icon) do.set("Categories", mo.freedesktop_category) desktop_objects.append( do ) # Couldn't find any desktop file, build a basic one if len(desktop_objects) == 0: # With klik2 packages, extract information from recipe # With klik1 packages, make up information cmg_version = self.is_valid_cmg(cmg_path) recipe = None if cmg_version == 2: recipe = self.extract_recipe( cmg_path ) do = DesktopParser() if fix_exec or (cmg_version == 1): do.set("Exec", "klik \"" + cmg_path + "\"") # dont need to not fix this one.. else: if recipe.command: do.set("Exec", recipe.command) else: do.set("Exec", recipe.name) if recipe: name = recipe.name.capitalize() terminal = recipe.require_terminal else: name = os.path.splitext( os.path.split( cmg_path )[1] )[0].capitalize() terminal = False do.set("Name", name) do.set("Terminal", terminal) do.set("Type", "Application") do.set("Icon", "/.DirIcon") do.set("X-CMG", cmg_path) # Debtags / categories if recipe and recipe.debtags.has_key("use"): category = klik.utils.freedesktop.get_freedesktop_category_from_debtag( recipe.debtags["use"] ) if category != None: do.set("Categories", category) desktop_objects.append( do ) return desktop_objects def extract_icon(self, cmg_path, file_path_to, image_size): if self.extract_file(cmg_path, "/.DirIcon", file_path_to): # Check image size if image_size > -1: try: from klik.utils.images import Images img = Images() # NOTE : image_size is the thumbnail size NOT the icon size.... img.check_image_size(file_path_to, self.settings.desktop_icon_size) except Exception, text: pass return True return False