# # vim: ts=4 et sts=4 # # Copyright (C) 2007 Ali Sabil # Copyright (C) 2007 Tom Parker # # Licensed under the GNU General Public License Version 2 # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. import sys import os import re from packagekit.backend import * import apt_pkg import warnings warnings.filterwarnings(action='ignore', category=FutureWarning) import apt _HYPHEN_PATTERN = re.compile(r'(\s|_)+') class Package(object): def __init__(self, pkg, backend): self._pkg = pkg @property def id(self): return self._pkg.id @property def name(self): return self._pkg.name @property def summary(self): return self._pkg.summary @property def description(self): return self._pkg.description @property def architecture(self): return self._pkg.architecture @property def section(self): return self._pkg.section @property def group(self): section = self.section.split('/')[-1].lower() #if section in (): # return GROUP_ACCESSIBILITY if section in ('utils',): return "accessories" #if section in (): # return GROUP_EDUCATION if section in ('games',): return "games" if section in ('graphics',): return "graphics" if section in ('net', 'news', 'web', 'comm'): return "internet" if section in ('editors', 'tex'): return "office" if section in ('misc',): return "other" if section in ('devel', 'libdevel', 'interpreters', 'perl', 'python'): return "programming" if section in ('sound',): return "multimedia" if section in ('base', 'admin'): return "system" return "unknown" @property def installed_version(self): return self._pkg.installedVersion @property def candidate_version(self): return self._pkg.candidateVersion @property def is_installed(self): return self._pkg.isInstalled @property def is_upgradable(self): return self._pkg.isUpgradable @property def is_development(self): name = self.name.lower() section = self.section.split('/')[-1].lower() return name.endswith('-dev') or name.endswith('-dbg') or \ section in ('devel', 'libdevel') @property def is_gui(self): section = self.section.split('/')[-1].lower() return section in ('x11', 'gnome', 'kde') def match_name(self, name): needle = name.strip().lower() haystack = self.name.lower() needle = _HYPHEN_PATTERN.sub('-', needle) haystack = _HYPHEN_PATTERN.sub('-', haystack) if haystack.find(needle) >= 0: return True return False def match_details(self, details): if self.match_name(details): return True needle = details.strip().lower() haystack = self.description.lower() if haystack.find(needle) >= 0: return True return False def match_group(self, name): needle = name.strip().lower() haystack = self.group if haystack.startswith(needle): return True return False class PackageKitProgress(apt.progress.OpProgress, apt.progress.FetchProgress): def __init__(self, backend): self._backend = backend apt.progress.OpProgress.__init__(self) apt.progress.FetchProgress.__init__(self) # OpProgress callbacks def update(self, percent): pass def done(self): pass # FetchProgress callbacks def pulse(self): apt.progress.FetchProgress.pulse(self) self._backend.percentage(self.percent) return True def stop(self): self._backend.percentage(100) def mediaChange(self, medium, drive): self._backend.error(ERROR_INTERNAL_ERROR, "Medium change needed") class PackageKitAptBackend(PackageKitBaseBackend): def __init__(self, args): PackageKitBaseBackend.__init__(self, args) self._apt_cache = apt.Cache(PackageKitProgress(self)) def search_name(self, filters, key): ''' Implement the {backend}-search-name functionality ''' self.allow_interrupt(True) for package in self._do_search(filters, lambda pkg: pkg.match_name(key)): self._emit_package(package) def search_details(self, filters, key): ''' Implement the {backend}-search-details functionality ''' self.allow_interrupt(True) for package in self._do_search(filters, lambda pkg: pkg.match_details(key)): self._emit_package(package) def search_group(self, filters, key): ''' Implement the {backend}-search-group functionality ''' self.allow_interrupt(True) for package in self._do_search(filters, lambda pkg: pkg.match_group(key)): self._emit_package(package) def search_file(self, filters, key): ''' Implement the {backend}-search-file functionality ''' self.allow_interrupt(True) self.percentage(None) self.error(ERROR_NOT_SUPPORTED, "This function is not implemented in this backend") def refresh_cache(self): ''' Implement the {backend}-refresh_cache functionality ''' try: res = self._apt_cache.update(PackageKitProgress(self)) except Exception, error_message: self.error(ERROR_INTERNAL_ERROR, "Failed to fetch the following items:\n%s" % error_message) return res def get_description(self, package): ''' Implement the {backend}-get-description functionality ''' name, version, arch, data = self.get_package_from_id(package) pkg = Package(self._apt_cache[name], self) description = re.sub('\s+', ' ', pkg.description).strip() self.description(package, 'unknown', pkg.group, description, '', 0, '') def resolve(self, name): ''' Implement the {backend}-resolve functionality ''' pkg = Package(self._apt_cache[name], self) self._emit_package(pkg) def get_depends(self,package): ''' Implement the {backend}-get-depends functionality ''' name, version, arch, data = self.get_package_from_id(package) pkg = Package(self._apt_cache[name], self) print dir(pkg) print dir(pkg._depcache) raise Exception ### Helpers ### def _emit_package(self, package): id = self.get_package_id(package.name, package.installed_version or package.candidate_version, package.architecture, "") if package.is_installed: status = INFO_INSTALLED else: status = INFO_AVAILABLE summary = package.summary self.package(id, status, summary) def _do_search(self, filters, condition): filters = filters.split(';') size = len(self._apt_cache) percentage = 0 for i, pkg in enumerate(self._apt_cache): new_percentage = i / float(size) * 100 if new_percentage - percentage >= 5: percentage = new_percentage self.percentage(percentage) package = Package(pkg, self) if package.installed_version is None and \ package.candidate_version is None: continue if not condition(package): continue if not self._do_filtering(package, filters): continue yield package self.percentage(100) def _do_filtering(self, package, filters): if len(filters) == 0 or filters == ['none']: return True if (FILTER_INSTALLED in filters) and (not package.is_installed): return False if (FILTER_NOT_INSTALLED in filters) and package.is_installed: return False if (FILTER_GUI in filters) and (not package.is_gui): return False if (FILTER_NOT_GUI in filters) and package.is_gui: return False if (FILTER_DEVELOPMENT in filters) and (not package.is_development): return False if (FILTER_NOT_DEVELOPMENT in filters) and package.is_development: return False return True