def unpack_cmg(self, cmg_path, location): try: cmg_path = os.path.expanduser(cmg_path) cmg_path = os.path.expandvars(cmg_path) cmg_path = os.path.abspath(cmg_path) if not location: location = os.path.splitext(cmg_path)[0] print location location = os.path.expanduser(location) location = os.path.expandvars(location) location = os.path.abspath(location) if not os.path.exists(location): print "Extract to : " + location ex = KlikExecute(self) ex.extract_all(KlikCmg(self, cmg_path), location) else: print "Sorry %s already exists" % location except Exception, inst: if isinstance(inst, ExecuteException): print "Error occured : " + str(inst) else: traceback.print_exc()
def load_items(self, desktop_files): self.item_store.clear() for item in desktop_files: cmg = KlikCmg(self.klik, item.get("X-CMG")) name = item.get("Name").strip() if item.get("Comment") != None: name = xml.sax.saxutils.escape( name) + '\n<small><i>' + xml.sax.saxutils.escape( item.get("Comment").strip()) + '</i></small>' else: name = xml.sax.saxutils.escape( name) + '\n<small><i></i></small>' icon = cmg.scan_cmg_icons(item)[0] if icon[0] == "/": temp_path = tempfile.mktemp() cmg.extract_file(icon, temp_path) icon = temp_path pixbuf = utils.getIcon(icon) if pixbuf == None: pixbuf = utils.getIcon("application-default-icon") if name != '': self.item_store.append((pixbuf, name, item)) self.window.show() gtk.main() return self.result
def cmg_is_not_registered(cmg_path): # Returns: True if there are NO .desktop files registered # that correspond with `cmg_path` # TODO: overkill, speed up not creating objects cmg = KlikCmg(self.base, cmg_path) return not glob.glob( os.path.join(self.base.xdg.get_xdg_apps_path(), cmg.get_unique_id()) + "*")
def unregister(self, cmg_list): apps_to_notify = set() cmg_list = filter(self.__is_valid_cmg_name, cmg_list) for cmg_path in cmg_list: # Make sure CMG path is absolute if cmg_path[0] != "/": cmg_path = os.path.abspath(cmg_path) print _("Unregistering %s") % cmg_path cmg = KlikCmg(self.base, cmg_path) package_id_prefix = cmg.get_unique_id() # Look for .desktop files owned by the CMG, and xdg-uninstall them menu_entries = glob.glob( os.path.join(self.base.xdg.get_xdg_apps_path(), package_id_prefix + "*")) if menu_entries: (old_paths, old_versions) = self.__get_collision_status(menu_entries[0]) for file in menu_entries: self.base.xdg.desktop_uninstall(file, noupdate=True) apps_to_notify.add(" - " + self.__get_app_name(file)) # If unregistering this package ends with a collision situation, # remove extra info from the menu entry that is left. (paths, versions, colliding_entries) = self.__check_already_registered(cmg_path) if old_paths and not paths: map(self.__del_path, colliding_entries) if old_versions and not versions: map(self.__del_version, colliding_entries) # Look for icons owned by the CMG, and xdg-uninstall them self.base.xdg.icon_uninstall(package_id_prefix, uninstall_all=True) self.base.xdg.desktop_update() # Notification self.notify_event( _("The following menu items have been removed:") + "\n\n%s", apps_to_notify)
def register_icon(icon_path): # Tries to register the given icon, considering the different possible natures of icons: # 1.- Themed # 2.- Inside CMG # 3.- Already in the filesystem # If path is not in a filesystem, icon is themed: skip processing if icon_path[0] != "/": return True # icon_path[2:] to avoid `extension = .DirIcon` extension = os.path.splitext(icon_path[2:])[1] temp_icon_path = os.path.join(build_path, package_id + extension) # Try to extract icon from CMG cmg = KlikCmg(self.base, cmg_path) if cmg.extract_file(icon_path, temp_icon_path): if not extension: # Guess image type extension = "." + klik.utils.images.guess_type( temp_icon_path) shutil.move(temp_icon_path, temp_icon_path + extension) temp_icon_path += extension # If image was not in CMG, try to get it from filesystem else: try: shutil.copy(icon_path, temp_icon_path) except IOError: return False # Try to guess icon size and theme regexp_result = regexp_icon.search(icon_path) if not temp_icon_path.endswith( ".svg"): # FIXME: xdg-utils do not support SVG icons if regexp_result: theme, size = regexp_result.groups() self.base.xdg.icon_install(temp_icon_path, theme, size, noupdate=True) else: self.base.xdg.icon_install(temp_icon_path, noupdate=True) os.remove(temp_icon_path) return True
def execute_cmg_shell(self, cmg_path): cmg = KlikCmg(self, cmg_path) return cmg.execute_shell()
def is_valid_cmg(self, filename): return KlikCmg(self, filename).is_valid_cmg()
def sync(self, apps_dirs): # Perform some cleanup, registering and unregistering packages as needed, # trying to leave the system as consistent as possible. # # apps_dirs: List of Application directories. The goal of the function is to # register every .cmg in that directory and unregister any previous # registered .cmg that is currently not in that directory. # Make sure paths are absolute apps_dirs = map(os.path.abspath, apps_dirs) # List of valid CMGs in all Applications directories. registered_cmgs = map(lambda x: glob.glob(x + "/*"), apps_dirs) # list of lists registered_cmgs = reduce(list.__add__, registered_cmgs) # flat list registered_cmgs = filter(lambda x: KlikCmg(self.base, x).is_valid_cmg, registered_cmgs) # list of valid CMGs registered_cmgs = set(registered_cmgs) # for faster lookups ### Register non-registered packages existent in any of the Application directories def cmg_is_not_registered(cmg_path): # Returns: True if there are NO .desktop files registered # that correspond with `cmg_path` # TODO: overkill, speed up not creating objects cmg = KlikCmg(self.base, cmg_path) return not glob.glob( os.path.join(self.base.xdg.get_xdg_apps_path(), cmg.get_unique_id()) + "*") cmgs_to_register = filter(cmg_is_not_registered, registered_cmgs) if cmgs_to_register: self.register(cmgs_to_register) ### Unregister packages that left litter in .desktop or icon directories def purge_dir(data_dir): # For each file in `data_dir`, look if the associated CMG is registered. # If not, unregister the associated CMG to remove all the litter it left # # data_dir: Path of directory with registered files (.desktop's, icons, etc) # Returns: Set of packages that need unregistration. if not os.path.isdir(data_dir): return set() packages_to_unregister = set() for filename in os.listdir(data_dir): if self.__is_valid_menu_entry(filename): cmg_path = self.__get_cmg_path(filename) if cmg_path not in registered_cmgs: packages_to_unregister.add(cmg_path) return packages_to_unregister packages_to_unregister = set() # Orphan .desktop files packages_to_unregister.update( purge_dir(self.base.xdg.get_xdg_apps_path())) # Orphan icon files for icon_path in self.base.xdg.get_xdg_icon_paths(): packages_to_unregister.update(purge_dir(icon_path)) if packages_to_unregister: self.unregister(packages_to_unregister)
def __is_valid_cmg_name(self, path): # If the file exists, returns true if it's a valid CMG # Otherwise, returns true if the name is valid return KlikCmg(self.base, path).is_valid_cmg() or path.lower().endswith(".cmg")
def register(self, cmg_list, command_options=set()): regexp_icon = re.compile("icons/([a-z]+)/([0-9]+)x") def register_icon(icon_path): # Tries to register the given icon, considering the different possible natures of icons: # 1.- Themed # 2.- Inside CMG # 3.- Already in the filesystem # If path is not in a filesystem, icon is themed: skip processing if icon_path[0] != "/": return True # icon_path[2:] to avoid `extension = .DirIcon` extension = os.path.splitext(icon_path[2:])[1] temp_icon_path = os.path.join(build_path, package_id + extension) # Try to extract icon from CMG cmg = KlikCmg(self.base, cmg_path) if cmg.extract_file(icon_path, temp_icon_path): if not extension: # Guess image type extension = "." + klik.utils.images.guess_type( temp_icon_path) shutil.move(temp_icon_path, temp_icon_path + extension) temp_icon_path += extension # If image was not in CMG, try to get it from filesystem else: try: shutil.copy(icon_path, temp_icon_path) except IOError: return False # Try to guess icon size and theme regexp_result = regexp_icon.search(icon_path) if not temp_icon_path.endswith( ".svg"): # FIXME: xdg-utils do not support SVG icons if regexp_result: theme, size = regexp_result.groups() self.base.xdg.icon_install(temp_icon_path, theme, size, noupdate=True) else: self.base.xdg.icon_install(temp_icon_path, noupdate=True) os.remove(temp_icon_path) return True def is_already_registered(cmg_path): if "f" in command_options: return False any_version = len( glob.glob( self.__get_menu_entry_mask(cmg_path, check_version=False, check_path=False))) same_version = len( glob.glob( self.__get_menu_entry_mask(cmg_path, check_version=True, check_path=False))) return any_version - same_version > 0 # some distros do not have .local/share/applications by default #os.mkdir( self.base.xdg.get_xdg_apps_path() ) apps_to_notify = set() notify_icon = None cmg_list = filter(lambda x: KlikCmg(self.base, x).is_valid_cmg(), cmg_list) for cmg_path in cmg_list: # Make sure CMG path is absolute if cmg_path[0] != "/": cmg_path = os.path.abspath(cmg_path) print _("Registering %s") % cmg_path if is_already_registered(cmg_path): print "\t", _("Package already registered") continue cmg = KlikCmg(self.base, cmg_path) build_path = tempfile.mkdtemp( '.register.' + cmg.get_unique_id(), self.base.settings.temp_directory_path) self.base.temp_paths.append(build_path) # Registering one menu entry per desktop object found/created for do in cmg.get_desktop_objects(): # Package ID is the CMG name escaped with the specific .desktop name... package_id = cmg.get_unique_id(do.get("Name")) # Convert execution command command = do.get("Exec") or "" do.set("Exec", "klik run %s '%s'" % (command, cmg.path)) do.set("X-CMG", cmg.path) # Icons: each menu entry can have many icons, in different sizes and themes icon_list = cmg.scan_cmg_icons(do) icon_list = filter(register_icon, icon_list) if icon_list: # At least one valid icon could be installed if (icon_list[0][0] == "/"): # Icon is not themed do.set("Icon", package_id) else: # No valid icon for this entry, fallback to klik themed icon do.set("Icon", "application-x-application-cmg") # Write .desktop file temp_desktop_path = os.path.join(build_path, package_id + ".desktop") temp_desktop_file = open(temp_desktop_path, "w") do.write(temp_desktop_file) temp_desktop_file.close() # Register .desktop file and remove temporal file self.base.xdg.desktop_install(temp_desktop_path, noupdate=True) os.remove(temp_desktop_path) # Checking if the CMG is already registered, with the # same version or with a different one. (paths, versions, colliding_entries) = self.__check_already_registered(cmg_path) if paths: map(self.__add_path, colliding_entries) if versions: map(self.__add_version, colliding_entries) apps_to_notify.add(" - " + do.get("Name")) notify_icon = do.get("Icon") os.rmdir(build_path) self.base.xdg.icon_update() self.base.xdg.desktop_update() # Notification self.notify_event( _("The following menu items have been added") + ":\n\n%s\n\n" + ngettext( "To uninstall remove the file from your application folder", "To uninstall remove the files from your application folder", len(apps_to_notify)) + ".\n", apps_to_notify, notify_icon)
relative_path = os.path.join(root_directory, recipe.icon[1:].replace("file://", "")) self.events.print_to_stdout( relative_path ) if os.path.isfile( relative_path): shutil.copy(relative_path, icon_path) else: # maybe a url then ? try: urllib.urlretrieve(recipe.icon, icon_path) except ExecuteException, text: pass # postflight self.__execute_accepted_commands(root_directory, recipe.postflight) return KlikCmg(self.klik, self.pack(root_directory, app_path, build_path=build_path)) def pack(self, root_directory, app_path, build_path=None): recipe_path = os.path.join(root_directory, "recipe.xml") recipe = None cmg_path = None # Load the recipe file if os.path.isfile( recipe_path ): recipe = KlikRecipe( recipe_path ) else: raise ExecuteException( _("No recipe file found") ) return