diff options
Diffstat (limited to 'sugar_network/client/packagekit.py')
-rw-r--r-- | sugar_network/client/packagekit.py | 255 |
1 files changed, 78 insertions, 177 deletions
diff --git a/sugar_network/client/packagekit.py b/sugar_network/client/packagekit.py index 8c624c6..782f09e 100644 --- a/sugar_network/client/packagekit.py +++ b/sugar_network/client/packagekit.py @@ -1,5 +1,4 @@ -# Copyright (C) 2010-2012 Aleksey Lim -# Copyright (C) 2010 Thomas Leonard +# Copyright (C) 2010-2013 Aleksey Lim # # 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 @@ -15,155 +14,96 @@ # along with this program. If not, see <http://www.gnu.org/licenses/>. import os -import locale import logging -from ConfigParser import ConfigParser -from os.path import exists -from gettext import gettext as _ -import dbus -import gobject -from dbus.mainloop.glib import threads_init, DBusGMainLoop +from sugar_network.toolkit import lsb_release, gbus, enforce -from sugar_network.toolkit import pipe, enforce +_PK_MAX_RESOLVE = 100 +_PK_MAX_INSTALL = 2500 -_PK_CONFILE = '/etc/PackageKit/PackageKit.conf' +_PMS_PATHS = { + 'Debian': '/var/lib/dpkg/status', + 'Fedora': '/var/lib/rpm/Packages', + 'Ubuntu': '/var/lib/dpkg/status', + } -_logger = logging.getLogger('client.packagekit') +_logger = logging.getLogger('packagekit') +_pms_path = _PMS_PATHS.get(lsb_release.distributor_id()) -_pk = None -_pk_max_resolve = 100 -_pk_max_install = 2500 +def mtime(): + if _pms_path: + return os.stat(_pms_path).st_mtime -def resolve(names): - enforce(_get_pk() is not None, 'Cannot connect to PackageKit') - pipe.feedback('resolve', - message=_('Resolving %s package name(s)') % len(names)) - _logger.debug('Resolve names %r', names) +def resolve(names): result = {} - mainloop = gobject.MainLoop() while names: - chunk = names[:min(len(names), _pk_max_resolve)] + chunk = names[:min(len(names), _PK_MAX_RESOLVE)] del names[:len(chunk)] - transaction = _Transaction(mainloop.quit) - transaction.resolve(chunk) - mainloop.run() + _logger.debug('Resolve %r', chunk) - missed = set(chunk) - set([i['name'] for i in transaction.packages]) - enforce(not missed, - 'Failed to resolve %s package(s)', ', '.join(missed)) - for pkg in transaction.packages: - result[pkg['name']] = pkg + resp = gbus.call(_pk, 'Resolve', 'none', chunk) + missed = set(chunk) - set(resp.packages.keys()) + enforce(not missed, 'Failed to resolve %s', ', '.join(missed)) + result.update(resp.packages) return result def install(packages): - enforce(_get_pk() is not None, 'Cannot connect to PackageKit') - ids = [i['pk_id'] for i in packages] - pipe.feedback('install', - message=_('Installing %s package(s)') % len(packages)) - _logger.debug('Ask PackageKit to install %r packages', ids) - - mainloop = gobject.MainLoop() while ids: - chunk = ids[:min(len(ids), _pk_max_install)] + chunk = ids[:min(len(ids), _PK_MAX_INSTALL)] del ids[:len(chunk)] - transaction = _Transaction(mainloop.quit) - transaction.install(chunk) - mainloop.run() + _logger.debug('Install %r', chunk) - enforce(transaction.error_code is None or - transaction.error_code in ('package-already-installed', - 'all-packages-already-installed'), - 'PackageKit install failed: %s (%s)', - transaction.error_details, transaction.error_code) + resp = gbus.call(_pk, 'InstallPackages', True, chunk) + enforce(resp.error_code in ( + 'package-already-installed', + 'all-packages-already-installed', None), + 'Installation failed: %s (%s)', + resp.error_details, resp.error_code) -class _Transaction(object): +class _Response(object): - def __init__(self, finished_cb): - self._finished_cb = finished_cb + def __init__(self): self.error_code = None self.error_details = None - self.packages = [] - - self._object = dbus.SystemBus().get_object( - 'org.freedesktop.PackageKit', _get_pk().GetTid(), False) - self._proxy = dbus.Interface(self._object, - 'org.freedesktop.PackageKit.Transaction') - self._props = dbus.Interface(self._object, dbus.PROPERTIES_IFACE) - - self._signals = [] - for signal, cb in [ - ('Finished', self.__finished_cb), - ('ErrorCode', self.__error_code_cb), - ('Package', self.__package_cb), - ]: - self._signals.append(self._proxy.connect_to_signal(signal, cb)) - - defaultlocale = locale.getdefaultlocale()[0] - if defaultlocale is not None: - self._compat_call([ - ('SetLocale', defaultlocale), - ('SetHints', ['locale=%s' % defaultlocale]), - ]) - - def resolve(self, names): - self._proxy.Resolve('none', names) - - def install(self, names): - _auth_wrapper('org.freedesktop.packagekit.package-install', - self._compat_call, [ - ('InstallPackages', names), - ('InstallPackages', True, names), - ]) - - def get_percentage(self): - if self._object is None: - return None - try: - return self._props.Get('org.freedesktop.PackageKit.Transaction', - 'Percentage') - except Exception: - result, __, __, __ = self._proxy.GetProgress() - return result - - def _compat_call(self, calls): - for call in calls: - method = call[0] - args = call[1:] - try: - dbus_method = self._proxy.get_dbus_method(method) - return dbus_method(*args) - except dbus.exceptions.DBusException, e: - if e.get_dbus_name() not in [ - 'org.freedesktop.DBus.Error.UnknownMethod', - 'org.freedesktop.DBus.Error.InvalidArgs']: - raise - raise Exception('Cannot call %r DBus method' % calls) - - def __finished_cb(self, status, runtime): + self.packages = {} + + +def _pk(result, op, *args): + import dbus + + bus = dbus.SystemBus() + pk = dbus.Interface( + bus.get_object( + 'org.freedesktop.PackageKit', '/org/freedesktop/PackageKit', + False), + 'org.freedesktop.PackageKit') + txn = dbus.Interface( + bus.get_object('org.freedesktop.PackageKit', pk.GetTid(), False), + 'org.freedesktop.PackageKit.Transaction') + resp = _Response() + signals = [] + + def Finished_cb(status, runtime): _logger.debug('Transaction finished: %s', status) - for i in self._signals: + for i in signals: i.remove() - self._finished_cb() - self._props = None - self._proxy = None - self._object = None + result.set(resp) - def __error_code_cb(self, code, details): - self.error_code = code - self.error_details = details + def ErrorCode_cb(code, details): + resp.error_code = code + resp.error_details = details - def __package_cb(self, status, pk_id, summary): + def Package_cb(status, pk_id, summary): from sugar_network.client import solver package_name, version, arch, __ = pk_id.split(';') @@ -171,6 +111,8 @@ class _Transaction(object): if not clean_version: _logger.warn('Cannot parse distribution version "%s" ' 'for package "%s"', version, package_name) + if package_name in resp.packages: + return package = { 'pk_id': str(pk_id), 'version': clean_version, @@ -178,73 +120,32 @@ class _Transaction(object): 'arch': solver.canonicalize_machine(arch), 'installed': (status == 'installed'), } - _logger.debug('Resolved PackageKit name: %r', package) - self.packages.append(package) - + _logger.debug('Found: %r', package) + resp.packages[package_name] = package -def _get_pk(): - global _pk, _pk_max_resolve, _pk_max_install + for signal, cb in [ + ('Finished', Finished_cb), + ('ErrorCode', ErrorCode_cb), + ('Package', Package_cb), + ]: + signals.append(txn.connect_to_signal(signal, cb)) - if _pk is not None: - if _pk is False: - return None - else: - return _pk - - gobject.threads_init() - threads_init() - DBusGMainLoop(set_as_default=True) + op = txn.get_dbus_method(op) try: - bus = dbus.SystemBus() - pk_object = bus.get_object('org.freedesktop.PackageKit', - '/org/freedesktop/PackageKit', False) - _pk = dbus.Interface(pk_object, 'org.freedesktop.PackageKit') - _logger.info('PackageKit dbus service found') - except Exception, error: - _pk = False - _logger.info('PackageKit dbus service not found: %s', error) - return None - - if exists(_PK_CONFILE): - conf = ConfigParser() - conf.read(_PK_CONFILE) - if conf.has_option('Daemon', 'MaximumItemsToResolve'): - _pk_max_resolve = \ - int(conf.get('Daemon', 'MaximumItemsToResolve')) - if conf.has_option('Daemon', 'MaximumPackagesToProcess'): - _pk_max_install = \ - int(conf.get('Daemon', 'MaximumPackagesToProcess')) - - return _pk - - -def _auth_wrapper(iface, method, *args): - _logger.info('Obtain authentication for %s', iface) - - def obtain(): - pk_auth = dbus.SessionBus().get_object( + op(*args) + except dbus.exceptions.DBusException, error: + if error.get_dbus_name() != \ + 'org.freedesktop.PackageKit.Transaction.RefusedByPolicy': + raise + iface, auth = error.get_dbus_message().split() + if not auth.startswith('auth_'): + raise + auth = dbus.SessionBus().get_object( 'org.freedesktop.PolicyKit.AuthenticationAgent', '/', 'org.freedesktop.PolicyKit.AuthenticationAgent') - pk_auth.ObtainAuthorization(iface, dbus.UInt32(0), + auth.ObtainAuthorization(iface, dbus.UInt32(0), dbus.UInt32(os.getpid()), timeout=300) - - try: - # PK on f11 needs to obtain authentication at first - obtain() - return method(*args) - except Exception: - # It seems doesn't work for recent PK - try: - return method(*args) - except dbus.exceptions.DBusException, e: - if e.get_dbus_name() != \ - 'org.freedesktop.PackageKit.Transaction.RefusedByPolicy': - raise - iface, auth = e.get_dbus_message().split() - if not auth.startswith('auth_'): - raise - obtain() - return method(*args) + op(*args) if __name__ == '__main__': |