def _update_package_cache(self): """Update the cache with fresh data from PackageKit """ # we are not ready if the cache is invalid if not self._pkgs_cache: self._ready = False # we never want source packages pfilter = 1 << packagekit.FilterEnum.NOT_SOURCE pathname = os.path.join(XAPIAN_BASE_PATH, "xapian") db = StoreDatabase(pathname, self) db.open() docs = db.get_docs_from_query("") wanted_pkgs = list() for doc in docs: wanted_pkgs.append(db.get_pkgname(doc)) if len(wanted_pkgs) is 0: LOG.warning("no packages to process!") return # we never want source packages pfilter = 1 << packagekit.FilterEnum.NOT_SOURCE # Start async update of package-cache, as the data which was # loaded before (from on-disk cache) might not be fully up-to-date pkDaemonConf = glib.KeyFile() ret = pkDaemonConf.load_from_file("/etc/PackageKit/PackageKit.conf", glib.KeyFileFlags.NONE) # set maxItems to 100 by default maxItems = 100 if ret: try: maxItems = pkDaemonConf.get_integer("Daemon", "MaximumItemsToResolve") except Exception as e: LOG.error("Unable to read PackageKit daemon config: %s", str(e)) maxItems = 100 LOG.debug("maximum packages to resolve %i", maxItems) helper = self.PkResolveHelper(0) #steps = len(wanted_pkgs) + 0.5 // 100 for i in xrange(0, len(wanted_pkgs), maxItems): helper.steps = helper.steps + 1 for i in xrange(0, len(wanted_pkgs), maxItems): res = self.pkclient.resolve_async(pfilter, wanted_pkgs[i:i+maxItems], None, # cancellable lambda prog, t, u: None, # progress callback None, # progress user data, self._on_packages_resolve_ready, helper )
def _get_apps_for_category(self, category): query = get_query_for_category(self.db, category) if not query: LOG.warn("_get_apps_for_category: received invalid category") return [] pathname = os.path.join(XAPIAN_BASE_PATH, "xapian") db = StoreDatabase(pathname, self.cache) db.open() docs = db.get_docs_from_query(query) #from the db docs, return a list of pkgnames applist = [] for doc in docs: applist.append(db.get_pkgname(doc)) return applist
def test_application_details(self): db = xapian.WritableDatabase(TEST_DB, xapian.DB_CREATE_OR_OVERWRITE) res = update_from_app_install_data(db, self.cache, datadir=os.path.join( DATA_DIR, "desktop")) self.assertTrue(res) db = StoreDatabase(TEST_DB, self.cache) db.open(use_axi=False, use_agent=False) self.assertEqual(len(db), 6) # test details app = Application("Ubuntu Software Center Test", "software-center") details = app.get_details(db) self.assertNotEqual(details, None) # mvo: disabled, we can reenable this once there is a static # apt rootdir and we do not rely on the test system to # have software-center from the main archive and not from # e.g. a custom repo like the ADT environment #self.assertEqual(details.component, "main") self.assertEqual(details.pkgname, "software-center") # get the first document for doc in db: if doc.get_data() == "Ubuntu Software Center Test": appdetails = AppDetails(db, doc=doc) break # test get_appname and get_pkgname self.assertEqual(db.get_appname(doc), "Ubuntu Software Center Test") self.assertEqual(db.get_pkgname(doc), "software-center") # test appdetails self.assertEqual(appdetails.name, "Ubuntu Software Center Test") self.assertEqual(appdetails.pkgname, "software-center") # FIXME: add a dekstop file with a real channel to test # and monkey-patch/modify the APP_INSTALL_CHANNELS_PATH self.assertEqual(appdetails.channelname, None) self.assertEqual(appdetails.channelfile, None) self.assertNotEqual(appdetails.pkg, None) # from the fake test/data/appdetails/var/lib/dpkg/status self.assertEqual(appdetails.pkg.is_installed, True) self.assertTrue(appdetails.pkg_state in (PkgStates.INSTALLED, PkgStates.UPGRADABLE)) # FIXME: test description for unavailable pkg self.assertTrue( appdetails.description.startswith( "Ubuntu Software Center lets you")) # FIXME: test appdetails.website self.assertEqual(appdetails.icon, "softwarecenter") # crude, crude self.assertTrue(len(appdetails.version) > 2) # FIXME: screenshots will only work on ubuntu self.assertTrue( re.match( "http://screenshots.ubuntu.com/screenshot-with-version/software-center/[\d.]+", appdetails.screenshot)) self.assertTrue( re.match( "http://screenshots.ubuntu.com/thumbnail-with-version/software-center/[\d.]+", appdetails.thumbnail)) # FIXME: add document that has a price self.assertEqual(appdetails.price, "Free") self.assertEqual(appdetails.raw_price, "") # mvo: disabled, we can reenable this once there is a static # apt rootdir and we do not rely on the test system to # have software-center from the main archive and not from # e.g. a custom repo like the ADT environment #self.assertEqual(appdetails.license, "Open source") # test lazy history loading for installation date self.ensure_installation_date_and_lazy_history_loading(appdetails) # test apturl replacements # $kernel app = Application("", "linux-headers-$kernel", "channel=$distro-partner") self.assertEqual(app.pkgname, 'linux-headers-' + os.uname()[2]) # $distro details = app.get_details(db) distro = softwarecenter.distro.get_distro().get_codename() self.assertEqual(app.request, 'channel=' + distro + '-partner')
def test_application_details(self): db = xapian.WritableDatabase("./data/test.db", xapian.DB_CREATE_OR_OVERWRITE) res = update_from_app_install_data(db, self.cache, datadir="./data/desktop") self.assertTrue(res) db = StoreDatabase("./data/test.db", self.cache) db.open(use_axi=False, use_agent=False) self.assertEqual(len(db), 5) # test details app = Application("Ubuntu Software Center Test", "software-center") details = app.get_details(db) self.assertNotEqual(details, None) self.assertEqual(details.component, "main") self.assertEqual(details.pkgname, "software-center") # get the first document for doc in db: if doc.get_data() == "Ubuntu Software Center Test": appdetails = AppDetails(db, doc=doc) break # test get_appname and get_pkgname self.assertEqual(db.get_appname(doc), "Ubuntu Software Center Test") self.assertEqual(db.get_pkgname(doc), "software-center") # test appdetails self.assertEqual(appdetails.name, "Ubuntu Software Center Test") self.assertEqual(appdetails.pkgname, "software-center") # FIXME: add a dekstop file with a real channel to test # and monkey-patch/modify the APP_INSTALL_CHANNELS_PATH self.assertEqual(appdetails.channelname, None) self.assertEqual(appdetails.channelfile, None) self.assertEqual(appdetails.component, "main") self.assertNotEqual(appdetails.pkg, None) # from the fake test/data/appdetails/var/lib/dpkg/status self.assertEqual(appdetails.pkg.is_installed, True) self.assertEqual(appdetails.pkg_state, PkgStates.INSTALLED) # FIXME: test description for unavailable pkg self.assertTrue( appdetails.description.startswith("Ubuntu Software Center lets you")) # FIXME: test appdetails.website self.assertEqual(appdetails.icon, "softwarecenter") # crude, crude self.assertTrue(len(appdetails.version) > 2) # FIXME: screenshots will only work on ubuntu self.assertTrue(re.match( "http://screenshots.ubuntu.com/screenshot-with-version/software-center/[\d.]+", appdetails.screenshot)) self.assertTrue(re.match( "http://screenshots.ubuntu.com/thumbnail-with-version/software-center/[\d.]+", appdetails.thumbnail)) # FIXME: add document that has a price self.assertEqual(appdetails.price, '') self.assertEqual(appdetails.license, "Open source") # test lazy history loading for installation date self.ensure_installation_date_and_lazy_history_loading(appdetails) # test apturl replacements # $kernel app = Application("", "linux-headers-$kernel", "channel=$distro-partner") self.assertEqual(app.pkgname, 'linux-headers-'+os.uname()[2]) # $distro details = app.get_details(db) from softwarecenter.distro import get_distro distro = get_distro().get_codename() self.assertEqual(app.request, 'channel=' + distro + '-partner')
class PkgListModel(QAbstractListModel): COLUMNS = ('_appname', '_pkgname', '_icon', '_summary', '_installed', '_description', '_ratings_total', '_ratings_average', '_installremoveprogress') def __init__(self, parent=None): super(PkgListModel, self).__init__() self._docs = [] roles = dict(enumerate(PkgListModel.COLUMNS)) self.setRoleNames(roles) self._query = "" self._category = "" pathname = os.path.join(XAPIAN_BASE_PATH, "xapian") self.cache = get_pkg_info() self.db = StoreDatabase(pathname, self.cache) self.db.open(use_axi=False) self.backend = get_install_backend() self.backend.connect("transaction-progress-changed", self._on_backend_transaction_progress_changed) self.reviews = get_review_loader(self.cache) # FIXME: get this from a parent self._catparser = CategoriesParser(self.db) self._categories = self._catparser.parse_applications_menu( '/usr/share/app-install') # QAbstractListModel code def rowCount(self, parent=QModelIndex()): return len(self._docs) def data(self, index, role): if not index.isValid(): return None doc = self._docs[index.row()] role = self.COLUMNS[role] pkgname = unicode(self.db.get_pkgname(doc)) appname = unicode(self.db.get_appname(doc)) if role == "_pkgname": return pkgname elif role == "_appname": return appname elif role == "_summary": return unicode(self.db.get_summary(doc)) elif role == "_installed": if not pkgname in self.cache: return False return self.cache[pkgname].is_installed elif role == "_description": if not pkgname in self.cache: return "" return self.cache[pkgname].description elif role == "_icon": iconname = self.db.get_iconname(doc) return self._findIcon(iconname) elif role == "_ratings_average": stats = self.reviews.get_review_stats(Application(appname, pkgname)) if stats: return stats.ratings_average return 0 elif role == "_ratings_total": stats = self.reviews.get_review_stats(Application(appname, pkgname)) if stats: return stats.ratings_total return 0 elif role == "_installremoveprogress": if pkgname in self.backend.pending_transactions: return self.backend.pending_transactions[pkgname].progress return -1 return None # helper def _on_backend_transaction_progress_changed(self, backend, pkgname, progress): column = self.COLUMNS.index("_installremoveprogress") # FIXME: instead of the entire model, just find the row that changed top = self.createIndex(0, column) bottom = self.createIndex(self.rowCount()-1, column) self.dataChanged.emit(top, bottom) def _findIcon(self, iconname): path = "/usr/share/icons/Humanity/categories/32/applications-other.svg" for ext in ["svg", "png", ".xpm"]: p = "/usr/share/app-install/icons/%s" % iconname if os.path.exists(p+ext): path = "file://%s" % p+ext break return path def clear(self): self.beginRemoveRows(QModelIndex(), 0, self.rowCount()-1) self._docs = [] self.endRemoveRows() def _runQuery(self, querystr): self.clear() docs = self.db.get_docs_from_query( str(querystr), start=0, end=500, category=self._category) self.beginInsertRows(QModelIndex(), len(docs), len(docs)) self._docs = docs self.endInsertRows() # install/remove interface (for qml) @Slot(str) def installPackage(self, pkgname): appname = "" iconname = "" self.backend.install(pkgname, appname, iconname) @Slot(str) def removePackage(self, pkgname): appname = "" iconname = "" self.backend.remove(pkgname, appname, iconname) # searchQuery property (for qml ) def getSearchQuery(self): return self._query def setSearchQuery(self, query): self._query = query self._runQuery(query) searchQueryChanged = QtCore.Signal() searchQuery = Property(unicode, getSearchQuery, setSearchQuery, notify=searchQueryChanged) # allow to refine searches for specific categories @Slot(str) def setCategory(self, catname): # empty category resets it if not catname: self._category = None else: # search for the category for cat in self._categories: if cat.name == catname: self._category = cat break else: raise Exception("Can not find category '%s'" % catname) # and trigger a query self._runQuery(self._query)
class PkgListModel(QAbstractListModel): COLUMNS = ('_appname', '_pkgname', '_icon', '_summary', '_installed', '_description', '_ratings_total', '_ratings_average', '_installremoveprogress') def __init__(self, parent=None): super(PkgListModel, self).__init__() self._docs = [] roles = dict(enumerate(PkgListModel.COLUMNS)) self.setRoleNames(roles) self._query = "" self._category = "" pathname = os.path.join(XAPIAN_BASE_PATH, "xapian") self.cache = get_pkg_info() self.db = StoreDatabase(pathname, self.cache) self.db.open(use_axi=False) self.backend = get_install_backend() self.backend.connect("transaction-progress-changed", self._on_backend_transaction_progress_changed) self.reviews = get_review_loader(self.cache) # FIXME: get this from a parent self._catparser = CategoriesParser(self.db) self._categories = self._catparser.parse_applications_menu( '/usr/share/app-install') # QAbstractListModel code def rowCount(self, parent=QModelIndex()): return len(self._docs) def data(self, index, role): if not index.isValid(): return None doc = self._docs[index.row()] role = self.COLUMNS[role] pkgname = unicode(self.db.get_pkgname(doc), "utf8", "ignore") appname = unicode(self.db.get_appname(doc), "utf8", "ignore") if role == "_pkgname": return pkgname elif role == "_appname": return appname elif role == "_summary": return unicode(self.db.get_summary(doc)) elif role == "_installed": if not pkgname in self.cache: return False return self.cache[pkgname].is_installed elif role == "_description": if not pkgname in self.cache: return "" return self.cache[pkgname].description elif role == "_icon": iconname = self.db.get_iconname(doc) return self._findIcon(iconname) elif role == "_ratings_average": stats = self.reviews.get_review_stats(Application( appname, pkgname)) if stats: return stats.ratings_average return 0 elif role == "_ratings_total": stats = self.reviews.get_review_stats(Application( appname, pkgname)) if stats: return stats.ratings_total return 0 elif role == "_installremoveprogress": if pkgname in self.backend.pending_transactions: return self.backend.pending_transactions[pkgname].progress return -1 return None # helper def _on_backend_transaction_progress_changed(self, backend, pkgname, progress): column = self.COLUMNS.index("_installremoveprogress") # FIXME: instead of the entire model, just find the row that changed top = self.createIndex(0, column) bottom = self.createIndex(self.rowCount() - 1, column) self.dataChanged.emit(top, bottom) def _findIcon(self, iconname): path = "/usr/share/icons/Humanity/categories/32/applications-other.svg" for ext in ["svg", "png", ".xpm"]: p = "/usr/share/app-install/icons/%s" % iconname if os.path.exists(p + ext): path = "file://%s" % p + ext break return path def clear(self): if self._docs == []: return self.beginRemoveRows(QModelIndex(), 0, self.rowCount() - 1) self._docs = [] self.endRemoveRows() def _runQuery(self, querystr): self.clear() docs = self.db.get_docs_from_query(str(querystr), start=0, end=500, category=self._category) self.beginInsertRows(QModelIndex(), 0, len(docs) - 1) self._docs = docs self.endInsertRows() # install/remove interface (for qml) @pyqtSlot(str) def installPackage(self, pkgname): appname = "" iconname = "" app = Application(appname, pkgname) self.backend.install(app, iconname) @pyqtSlot(str) def removePackage(self, pkgname): appname = "" iconname = "" app = Application(appname, pkgname) self.backend.remove(app, iconname) # searchQuery property (for qml ) def getSearchQuery(self): return self._query def setSearchQuery(self, query): self._query = query self._runQuery(query) searchQueryChanged = QtCore.pyqtSignal() searchQuery = QtCore.pyqtProperty(unicode, getSearchQuery, setSearchQuery, notify=searchQueryChanged) # allow to refine searches for specific categories @pyqtSlot(str) def setCategory(self, catname): # empty category resets it if not catname: self._category = None else: # search for the category for cat in self._categories: if cat.name == catname: self._category = cat break else: raise Exception("Can not find category '%s'" % catname) # and trigger a query self._runQuery(self._query)
def test_application_details(self): db = xapian.WritableDatabase(TEST_DB, xapian.DB_CREATE_OR_OVERWRITE) res = update_from_app_install_data(db, self.cache, datadir=os.path.join(DATA_DIR, "desktop")) self.assertTrue(res) db = StoreDatabase(TEST_DB, self.cache) db.open(use_axi=False, use_agent=False) self.assertEqual(len(db), 6) # test details app = Application("Ubuntu Software Center Test", "software-center") details = app.get_details(db) self.assertNotEqual(details, None) # mvo: disabled, we can reenable this once there is a static # apt rootdir and we do not rely on the test system to # have software-center from the main archive and not from # e.g. a custom repo like the ADT environment # self.assertEqual(details.component, "main") self.assertEqual(details.pkgname, "software-center") # get the first document for doc in db: if doc.get_data() == "Ubuntu Software Center Test": appdetails = AppDetails(db, doc=doc) break # test get_appname and get_pkgname self.assertEqual(db.get_appname(doc), "Ubuntu Software Center Test") self.assertEqual(db.get_pkgname(doc), "software-center") # test appdetails self.assertEqual(appdetails.name, "Ubuntu Software Center Test") self.assertEqual(appdetails.pkgname, "software-center") # FIXME: add a dekstop file with a real channel to test # and monkey-patch/modify the APP_INSTALL_CHANNELS_PATH self.assertEqual(appdetails.channelname, None) self.assertEqual(appdetails.channelfile, None) self.assertNotEqual(appdetails.pkg, None) # from the fake test/data/appdetails/var/lib/dpkg/status self.assertEqual(appdetails.pkg.is_installed, True) self.assertTrue(appdetails.pkg_state in (PkgStates.INSTALLED, PkgStates.UPGRADABLE)) # FIXME: test description for unavailable pkg self.assertTrue(appdetails.description.startswith("Ubuntu Software Center lets you")) # FIXME: test appdetails.website self.assertEqual(appdetails.icon, "softwarecenter") # crude, crude self.assertTrue(len(appdetails.version) > 2) # FIXME: screenshots will only work on ubuntu self.assertTrue( re.match( "http://screenshots.ubuntu.com/screenshot-with-version/software-center/[\d.]+", appdetails.screenshot ) ) self.assertTrue( re.match( "http://screenshots.ubuntu.com/thumbnail-with-version/software-center/[\d.]+", appdetails.thumbnail ) ) # FIXME: add document that has a price self.assertEqual(appdetails.price, "Free") self.assertEqual(appdetails.raw_price, "") # mvo: disabled, we can reenable this once there is a static # apt rootdir and we do not rely on the test system to # have software-center from the main archive and not from # e.g. a custom repo like the ADT environment # self.assertEqual(appdetails.license, "Open source") # test lazy history loading for installation date self.ensure_installation_date_and_lazy_history_loading(appdetails) # test apturl replacements # $kernel app = Application("", "linux-headers-$kernel", "channel=$distro-partner") self.assertEqual(app.pkgname, "linux-headers-" + os.uname()[2]) # $distro details = app.get_details(db) distro = softwarecenter.distro.get_distro().get_codename() self.assertEqual(app.request, "channel=" + distro + "-partner")