예제 #1
0
class AptPackageInstaller(gobject.GObject):
    # This avoids kiwi dependency since this is used early on.
    __gsignals__ = {
        'auth-failed': (gobject.SIGNAL_RUN_LAST, None, ()),
        'done': (gobject.SIGNAL_RUN_LAST, None, (object,)),
        }

    def __init__(self, parent=None):
        gobject.GObject.__init__(self)
        self.client = AptClient()
        self.parent = parent

    def install(self, *packages):
        def reply(transaction):
            transaction.connect("finished", self._on_transaction__finished)
            self._transaction = transaction
            # dependencis not available on lucid
            for p in getattr(transaction, 'dependencies', []):
                if p:
                    self._confirm()
                    break
            else:
                self._install()
        self.client.install_packages(list(packages),
                                     reply_handler=reply,
                                     error_handler=self._error_handler)

    def _on_transaction__finished(self, transaction, exitcode):
        if exitcode not in [0, 'exit-success']:
            error = exitcode
        else:
            error = None
        self.emit('done', error)

    def _error_handler(self, error):
        try:
            raise error
        except NotAuthorizedError:
            # Silently ignore auth failures
            self.emit('auth-failed')
            return
        except TransactionFailed, error:
            pass
        except Exception, error:
            error = TransactionFailed(ERROR_UNKNOWN, str(error))
 def __init__(self):
     PackageInfo.__init__(self)
     self._cache = None
     self._ready = False
     self._timeout_id = None
     # setup monitor watch for install/remove changes
     self.apt_finished_stamp = Gio.File.new_for_path(
         self.APT_FINISHED_STAMP)
     self.apt_finished_monitor = self.apt_finished_stamp.monitor_file(
         0, None)
     self.apt_finished_monitor.connect("changed",
                                       self._on_apt_finished_stamp_changed)
     # this is fast, so ok
     self._language_packages = self._read_language_pkgs()
     # query the totalize on install using aptdaemon
     try:
         self.aptd_client = AptClient()
     except Exception as e:
         self.aptd_client = None
         logging.error("Can not get aptdaemon client: '%s', no "
                       "size information will be available " % e)
     self._aptd_trans = None
예제 #3
0
 def __init__(self):
     PackageInfo.__init__(self)
     self._cache = None
     self._ready = False
     self._timeout_id = None
     # setup monitor watch for install/remove changes
     self.apt_finished_stamp = Gio.File.new_for_path(
         self.APT_FINISHED_STAMP)
     self.apt_finished_monitor = self.apt_finished_stamp.monitor_file(0,
         None)
     self.apt_finished_monitor.connect(
         "changed", self._on_apt_finished_stamp_changed)
     # this is fast, so ok
     self._language_packages = self._read_language_pkgs()
     # query the totalize on install using aptdaemon
     try:
         self.aptd_client = AptClient()
     except Exception as e:
         self.aptd_client = None
         logging.error("Can not get aptdaemon client: '%s', no "
                       "size information will be available " % e)
     self._aptd_trans = None
예제 #4
0
    def __init__(self, replacement):
        GObject.GObject.__init__(self)

        self.replacement = replacement
        self.apt_client = AptClient()
예제 #5
0
class AptInstallation(GObject.GObject):

    __gsignals__ = {
        "finished": (GObject.SIGNAL_RUN_FIRST, GObject.TYPE_NONE, ())
    }

    def __init__(self, replacement):
        GObject.GObject.__init__(self)

        self.replacement = replacement
        self.apt_client = AptClient()

    def run(self):
        apt_cache = open_apt_cache()

        if not apt_cache.has_key(self.replacement["apt"]):
            self.do_update()
        else:
            self.do_install()

    def do_update(self):
        trans_update = self.apt_client.update_cache()
        trans_update.connect("finished", self.on_finished_update)

        dia = AptProgressDialog(trans_update)
        dia.run(close_on_finished=True,
                show_error=False,
                reply_handler=lambda: True,
                error_handler=self.on_error)
        return

    def on_finished_update(self, trans, exit):
        if exit == "exit-success":
            GLib.timeout_add(200, self.do_install)
        return True

    def do_install(self):
        trans_inst = self.apt_client.install_packages(
            package_names=[self.replacement["apt"]])
        trans_inst.connect("finished", self.on_finished_install)
        dia = AptProgressDialog(transaction=trans_inst)
        dia.connect("finished", self.on_install_dialog_finished)
        dia.run(close_on_finished=True,
                show_error=False,
                reply_handler=lambda: True,
                error_handler=self.on_error)
        return

    def on_install_dialog_finished(self, dia):
        if self.exit == "exit-success":
            try:
                replacement_desktop = Gio.DesktopAppInfo.new(
                    self.replacement["desktopLauncher"])
                launch_desktop_app(replacement_desktop)
            except:
                self.finished_dialog(
                    _("%s has been installed") % self.replacement["name"])

        self.emit("finished")

    def on_finished_install(self, trans, exit):
        self.exit = exit
        return

    def finished_dialog(self, message):
        dialog = Gtk.MessageDialog(message_type=Gtk.MessageType.INFO,
                                   buttons=Gtk.ButtonsType.OK,
                                   text=message)
        dialog.run()
        dialog.destroy()
        return

    def on_error(self, error):
        if isinstance(error, aptdaemon.errors.NotAuthorizedError):
            # Silently ignore auth failures
            return
        elif not isinstance(error, aptdaemon.errors.TransactionFailed):
            # Catch internal errors of the client
            error = aptdaemon.errors.TransactionFailed(ERROR_UNKNOWN,
                                                       str(error))
        dia = AptErrorDialog(error)
        dia.run()
        dia.hide()
예제 #6
0
    def __init__(self):
        super(PackageInstaller, self).__init__()

        self._client = AptClient()
예제 #7
0
class PackageInstaller(GObject.GObject):

    __gsignals__ = {
        'auth-failed': (GObject.SignalFlags.RUN_LAST, None, ()),
        'done': (GObject.SignalFlags.RUN_LAST, None, (object, )),
    }

    def __init__(self):
        super(PackageInstaller, self).__init__()

        self._client = AptClient()

    #
    #  Public API
    #

    def install(self, *packages):
        def reply(transaction):
            transaction.connect('finished', self._on_transaction__finished)
            self._transaction = transaction
            # dependencis not available on lucid
            for p in getattr(transaction, 'dependencies', []):
                if p:
                    self._confirm()
                    break
            else:
                self._install()

        self._client.install_packages(list(packages),
                                      reply_handler=reply,
                                      error_handler=self._error_handler)

    #
    #  Private
    #

    def _confirm(self):
        dia = AptConfirmDialog(self._transaction)
        response = dia.run()
        dia.destroy()
        if response == Gtk.ResponseType.OK:
            self._install()

    def _install(self):
        dialog = AptProgressDialog(self._transaction)
        dialog.run(close_on_finished=True,
                   show_error=True,
                   reply_handler=lambda: True,
                   error_handler=self._error_handler)

    def _error_handler(self, error):
        try:
            raise error
        except NotAuthorizedError:
            # Silently ignore auth failures
            sys.exit(11)
            return
        except TransactionFailed:
            pass
        except Exception as error:
            error = TransactionFailed(ERROR_UNKNOWN, str(error))

        dia = AptErrorDialog(error)
        dia.run()
        sys.exit(10)

    #
    #  Callbacks
    #

    def _on_transaction__finished(self, transaction, exitcode):
        sys.exit(0 if exitcode in [0, 'exit-success'] else 10)
예제 #8
0

def run(t):
    if WITH_GUI:
        dia = AptProgressDialog(t)
        dia.run()
        dia.destroy()
    else:
        t.run()


if __name__ == "__main__":
    #logging.basicConfig(level=logging.DEBUG)

    context = GObject.main_context_default()
    c = AptClient()
    for i in range(100):

        print "inst: 3dchess"
        t = c.install_packages(["3dchess"], exit_handler=exit_handler)
        run(t)
        active += 1

        print "inst: 2vcard"
        t = c.install_packages(["2vcard"], exit_handler=exit_handler)
        run(t)
        active += 1

        print "rm: 3dchess 2vcard"
        t = c.remove_packages(["3dchess", "2vcard"], exit_handler=exit_handler)
        run(t)
class AptCache(PackageInfo):
    """
    A apt cache that opens in the background and keeps the UI alive
    """

    # dependency types we are about
    DEPENDENCY_TYPES = ("PreDepends", "Depends")
    RECOMMENDS_TYPES = ("Recommends", )
    SUGGESTS_TYPES = ("Suggests", )
    ENHANCES_TYPES = ("Enhances", )
    PROVIDES_TYPES = ("Provides", )

    # stamp file to monitor (provided by update-notifier via
    # APT::Update::Post-Invoke-Success)
    APT_FINISHED_STAMP = "/var/lib/update-notifier/dpkg-run-stamp"

    LANGPACK_PKGDEPENDS = "/usr/share/language-selector/data/pkg_depends"

    def __init__(self):
        PackageInfo.__init__(self)
        self._cache = None
        self._ready = False
        self._timeout_id = None
        # setup monitor watch for install/remove changes
        self.apt_finished_stamp = Gio.File.new_for_path(
            self.APT_FINISHED_STAMP)
        self.apt_finished_monitor = self.apt_finished_stamp.monitor_file(
            0, None)
        self.apt_finished_monitor.connect("changed",
                                          self._on_apt_finished_stamp_changed)
        # this is fast, so ok
        self._language_packages = self._read_language_pkgs()
        # query the totalize on install using aptdaemon
        try:
            self.aptd_client = AptClient()
        except Exception as e:
            self.aptd_client = None
            logging.error("Can not get aptdaemon client: '%s', no "
                          "size information will be available " % e)
        self._aptd_trans = None

    @staticmethod
    def version_compare(a, b):
        return apt_pkg.version_compare(a, b)

    @staticmethod
    def upstream_version_compare(a, b):
        return apt_pkg.version_compare(apt_pkg.upstream_version(a),
                                       apt_pkg.upstream_version(b))

    @staticmethod
    def upstream_version(v):
        return apt_pkg.upstream_version(v)

    def is_installed(self, pkgname):
        # use the lowlevel cache here, twice as fast
        lowlevel_cache = self._cache._cache
        return (pkgname in lowlevel_cache
                and lowlevel_cache[pkgname].current_ver is not None)

    def is_upgradable(self, pkgname):
        # use the lowlevel cache here, twice as fast
        if not pkgname in self._cache:
            return False
        return self._cache[pkgname].is_upgradable

    def is_available(self, pkgname):
        return (pkgname in self._cache and self._cache[pkgname].candidate)

    def get_installed(self, pkgname):
        if (pkgname not in self._cache
                or not self._cache[pkgname].is_installed):
            return None
        return AptCacheVersion(self._cache[pkgname].installed)

    def get_candidate(self, pkgname):
        if (pkgname not in self._cache or not self._cache[pkgname].candidate):
            return None
        return AptCacheVersion(self._cache[pkgname].candidate)

    def get_versions(self, pkgname):
        if (pkgname not in self._cache or not self._cache[pkgname].candidate):
            return []
        return [AptCacheVersion(v) for v in self._cache[pkgname].versions]

    def get_section(self, pkgname):
        if (pkgname not in self._cache or not self._cache[pkgname].candidate):
            return ''
        return self._cache[pkgname].candidate.section

    def get_summary(self, pkgname):
        if (pkgname not in self._cache or not self._cache[pkgname].candidate):
            return ''
        return self._cache[pkgname].candidate.summary

    def get_description(self, pkgname):
        if (pkgname not in self._cache or not self._cache[pkgname].candidate):
            return ''
        return self._cache[pkgname].candidate.description

    def get_website(self, pkgname):
        if (pkgname not in self._cache or not self._cache[pkgname].candidate):
            return ''
        return self._cache[pkgname].candidate.homepage

    def get_installed_files(self, pkgname):
        if (pkgname not in self._cache):
            return []
        return self._cache[pkgname].installed_files

    def get_size(self, pkgname):
        if (pkgname not in self._cache or not self._cache[pkgname].candidate):
            return 0
        return self._cache[pkgname].candidate.size

    def get_installed_size(self, pkgname):
        if (pkgname not in self._cache or not self._cache[pkgname].candidate):
            return 0
        return self._cache[pkgname].candidate.installed_size

    @property
    def ready(self):
        return self._ready

    def get_license(self, name):
        return None

    def open(self, blocking=False):
        """ (re)open the cache, this sends cache-invalid, cache-ready signals
        """
        LOG.info("aptcache.open()")
        self._ready = False
        self.emit("cache-invalid")
        if blocking:
            progress = None
        else:
            progress = GtkMainIterationProgress()
        with ExecutionTime("open the apt cache (in event loop)"):
            if self._cache is None:
                self._cache = apt.Cache(progress)
            else:
                self._cache.open(progress)
        self._ready = True
        self.emit("cache-ready")
        if self._cache.broken_count > 0:
            self.emit("cache-broken")

    # implementation specific code

    # temporarily return a full apt.Package so that the tests and the
    # code keeps working for now, this needs to go away eventually
    # and get replaced with the abstract _Package class
    #def __getitem__(self, key):
    #    return self._cache[key]

    def __iter__(self):
        return self._cache.__iter__()

    def __contains__(self, k):
        return self._cache.__contains__(k)

    def _on_apt_finished_stamp_changed(self, monitor, afile, other_file,
                                       event):
        if not event == Gio.FileMonitorEvent.CHANGES_DONE_HINT:
            return
        if self._timeout_id:
            GLib.source_remove(self._timeout_id)
            self._timeout_id = None
        self._timeout_id = GLib.timeout_add_seconds(10, self.open)

    def _get_rdepends_by_type(self, pkg, type, onlyInstalled):
        rdeps = set()
        # make sure this is a apt.Package object
        try:
            pkg = self._cache[pkg.name]
        except KeyError:
            LOG.error("package %s not found in AptCache" % str(pkg))
            return rdeps
        for rdep in pkg._pkg.rev_depends_list:
            dep_type = rdep.dep_type_untranslated
            if dep_type in type:
                rdep_name = rdep.parent_pkg.name
                if (rdep_name in self._cache and
                    (not onlyInstalled or
                     (onlyInstalled and self._cache[rdep_name].is_installed))):
                    rdeps.add(rdep.parent_pkg.name)
        return rdeps

    def _installed_dependencies(self, pkg_name, all_deps=None):
        """ recursively return all installed dependencies of a given pkg """
        #print "_installed_dependencies", pkg_name, all_deps
        if not all_deps:
            all_deps = set()
        if pkg_name not in self._cache:
            return all_deps
        cur = self._cache[pkg_name]._pkg.current_ver
        if not cur:
            return all_deps
        for t in self.DEPENDENCY_TYPES + self.RECOMMENDS_TYPES:
            try:
                for dep in cur.depends_list[t]:
                    dep_name = dep[0].target_pkg.name
                    if not dep_name in all_deps:
                        all_deps.add(dep_name)
                        all_deps |= self._installed_dependencies(
                            dep_name, all_deps)
            except KeyError:
                pass
        return all_deps

    def get_installed_automatic_depends_for_pkg(self, pkg):
        """ Get the installed automatic dependencies for this given package
            only.

            Note that the package must be marked for removal already for
            this to work
            Not: unused
        """
        installed_auto_deps = set()
        deps = self._installed_dependencies(pkg.name)
        for dep_name in deps:
            try:
                pkg = self._cache[dep_name]
            except KeyError:
                continue
            else:
                if (pkg.is_installed and pkg.is_auto_removable):
                    installed_auto_deps.add(dep_name)
        return installed_auto_deps

    def get_all_origins(self):
        """
        return a set of the current channel origins from the apt.Cache itself
        """
        origins = set()
        for pkg in self._cache:
            if not pkg.candidate:
                continue
            for item in pkg.candidate.origins:
                context = GLib.main_context_default()
                while context.pending():
                    context.iteration()
                if item.origin:
                    origins.add(item.origin)
        return origins

    def get_origins(self, pkgname):
        """
        return package origins from apt.Cache
        """
        if not pkgname in self._cache or not self._cache[pkgname].candidate:
            return
        origins = set()
        for origin in self._cache[pkgname].candidate.origins:
            if origin.origin:
                origins.add(origin)
        return origins

    def get_origin(self, pkgname):
        """
        return a unique origin for the given package name. currently
        this will use
        """
        if not pkgname in self._cache or not self._cache[pkgname].candidate:
            return None
        origins = set([origin.origin for origin in self.get_origins(pkgname)])
        if len(origins) > 1:
            LOG.warn("more than one origin '%s'" % origins)
            return None
        if not origins:
            return None
        # we support only a single origin (but its fine if that is available
        # on multiple mirrors). lowercase as the server excepts it this way
        origin_str = origins.pop()
        return origin_str.lower()

    def component_available(self, distro_codename, component):
        """ check if the given component is enabled """
        # FIXME: test for more properties here?
        for it in self._cache._cache.file_list:
            if (it.component != "" and it.component == component
                    and it.archive != "" and it.archive == distro_codename):
                return True
        return False

    @convert_package_argument
    def _get_depends_by_type(self, pkg, types):
        version = pkg.installed
        if version is None:
            version = pkg.candidate
        return version.get_dependencies(*types)

    def _get_depends_by_type_str(self, pkg, *types):
        def not_in_list(list, item):
            for i in list:
                if i == item:
                    return False
            return True

        deps = self._get_depends_by_type(pkg, *types)
        deps_str = []
        for dep in deps:
            for dep_ in dep.or_dependencies:
                if not_in_list(deps_str, dep_.name):
                    deps_str.append(dep_.name)
        return deps_str

    # FIXME: there are cleaner ways to do this than below

    # pkg relations
    def _get_depends(self, pkg):
        return self._get_depends_by_type_str(pkg, self.DEPENDENCY_TYPES)

    def _get_recommends(self, pkg):
        return self._get_depends_by_type_str(pkg, self.RECOMMENDS_TYPES)

    def _get_suggests(self, pkg):
        return self._get_depends_by_type_str(pkg, self.SUGGESTS_TYPES)

    def _get_enhances(self, pkg):
        return self._get_depends_by_type_str(pkg, self.ENHANCES_TYPES)

    @convert_package_argument
    def _get_provides(self, pkg):
        # note: can use ._cand, because pkg has been converted to apt.Package
        provides_list = pkg.candidate._cand.provides_list
        provides = []
        for provided in provides_list:
            provides.append(provided[0])  # the package name
        return provides

    # reverse pkg relations
    def _get_rdepends(self, pkg):
        return self._get_rdepends_by_type(pkg, self.DEPENDENCY_TYPES, False)

    def _get_rrecommends(self, pkg):
        return self._get_rdepends_by_type(pkg, self.RECOMMENDS_TYPES, False)

    def _get_rsuggests(self, pkg):
        return self._get_rdepends_by_type(pkg, self.SUGGESTS_TYPES, False)

    def _get_renhances(self, pkg):
        return self._get_rdepends_by_type(pkg, self.ENHANCES_TYPES, False)

    @convert_package_argument
    def _get_renhances_lowlevel_apt_pkg(self, pkg):
        """ takes a apt_pkg.Package and returns a list of pkgnames that
            enhance this package - this is needed to support enhances
            for virtual packages
        """
        renhances = []
        for dep in pkg.rev_depends_list:
            if dep.dep_type_untranslated == "Enhances":
                renhances.append(dep.parent_pkg.name)
        return renhances

    def _get_rprovides(self, pkg):
        return self._get_rdepends_by_type(pkg, self.PROVIDES_TYPES, False)

    # installed reverse pkg relations
    def get_packages_removed_on_remove(self, pkg):
        return self._get_rdepends_by_type(pkg, self.DEPENDENCY_TYPES, True)

    def get_packages_removed_on_install(self, pkg):
        depends = set()
        deps_remove = self._try_install_and_get_all_deps_removed(pkg)
        for depname in deps_remove:
            if self._cache[depname].is_installed:
                depends.add(depname)
        return depends

    def _get_installed_rrecommends(self, pkg):
        return self._get_rdepends_by_type(pkg, self.RECOMMENDS_TYPES, True)

    def _get_installed_rsuggests(self, pkg):
        return self._get_rdepends_by_type(pkg, self.SUGGESTS_TYPES, True)

    def _get_installed_renhances(self, pkg):
        return self._get_rdepends_by_type(pkg, self.ENHANCES_TYPES, True)

    def _get_installed_rprovides(self, pkg):
        return self._get_rdepends_by_type(pkg, self.PROVIDES_TYPES, True)

    # language pack stuff
    def _is_language_pkg(self, addon):
        # a simple "addon in self._language_packages" is not enough
        for template in self._language_packages:
            if addon.startswith(template):
                return True
        return False

    def _read_language_pkgs(self):
        language_packages = set()
        if not os.path.exists(self.LANGPACK_PKGDEPENDS):
            return language_packages
        for line in open(self.LANGPACK_PKGDEPENDS):
            line = line.strip()
            if line.startswith('#'):
                continue
            try:
                (cat, code, dep_pkg, language_pkg) = line.split(':')
            except ValueError:
                continue
            language_packages.add(language_pkg)
        return language_packages

    # these are used for calculating the total size
    @convert_package_argument
    def _get_changes_without_applying(self, pkg):
        try:
            if pkg.installed is None:
                pkg.mark_install()
            else:
                pkg.mark_delete()
        except SystemError:
            # TODO: ideally we now want to display an error message
            #       and block the install button
            LOG.warning(
                "broken packages encountered while getting deps for %s" %
                pkg.name)
            return {}
        changes_tmp = self._cache.get_changes()
        changes = {}
        for change in changes_tmp:
            if change.marked_install or change.marked_reinstall:
                changes[change.name] = PkgStates.INSTALLING
            elif change.marked_delete:
                changes[change.name] = PkgStates.REMOVING
            elif change.marked_upgrade:
                changes[change.name] = PkgStates.UPGRADING
            else:
                changes[change.name] = PkgStates.UNKNOWN
        self._cache.clear()
        return changes

    def _try_install_and_get_all_deps_installed(self, pkg):
        """ Return all dependencies of pkg that will be marked for install """
        changes = self._get_changes_without_applying(pkg)
        installing_deps = []
        for change in changes.keys():
            if change != pkg.name and changes[change] == PkgStates.INSTALLING:
                installing_deps.append(change)
        return installing_deps

    def _try_install_and_get_all_deps_removed(self, pkg):
        """ Return all dependencies of pkg that will be marked for remove"""
        changes = self._get_changes_without_applying(pkg)
        removing_deps = []
        for change in changes.keys():
            if change != pkg.name and changes[change] == PkgStates.REMOVING:
                removing_deps.append(change)
        return removing_deps

    def _set_candidate_release(self, pkg, archive_suite):
        # Check if the package is provided in the release
        for version in pkg.versions:
            if [
                    origin for origin in version.origins
                    if origin.archive == archive_suite
            ]:
                break
        else:
            return False
        res = pkg._pcache._depcache.set_candidate_release(
            pkg._pkg, version._cand, archive_suite)
        return res

    # space calculation stuff
    def _on_total_size_calculation_done(self, trans, space):
        pkgname = trans.packages[0][0]
        self.emit("query-total-size-on-install-done", pkgname, trans.download,
                  trans.space)

    def _on_trans_simulate_error(self, error):
        LOG.exception("simulate failed")

    def _on_trans_commit_packages_ready(self, trans):
        trans.connect("space-changed", self._on_total_size_calculation_done)
        try:
            trans.simulate(reply_handler=lambda: True,
                           error_handler=self._on_trans_simulate_error)
        except:
            LOG.exception("simulate failed")

    def query_total_size_on_install(self,
                                    pkgname,
                                    addons_install=[],
                                    addons_remove=[],
                                    archive_suite=""):
        if not pkgname in self._cache:
            self.emit("query-total-size-on-install-done", pkgname, 0, 0)

        # ensure the syntax is right
        if archive_suite:
            pkgname = pkgname + "/" + archive_suite

        # and simulate the install/remove via aptdaemon
        install = [pkgname] + addons_install
        remove = addons_remove
        reinstall = purge = upgrade = downgrade = []

        if self._aptd_trans:
            self._aptd_trans.cancel()
            self._aptd_trans = None

        # do this async
        try:
            self.aptd_client.commit_packages(
                install,
                reinstall,
                remove,
                purge,
                upgrade,
                downgrade,
                # wait
                False,
                # reply and error handlers
                self._on_trans_commit_packages_ready,
                self._on_trans_simulate_error)
        except:
            LOG.exception("getting commit_packages trans failed for '%s'" %
                          pkgname)

    def get_all_deps_upgrading(self, pkg):
        # note: this seems not to be used anywhere
        changes = self._get_changes_without_applying(pkg)
        upgrading_deps = []
        for change in changes.keys():
            if change != pkg.name and changes[change] == PkgStates.UPGRADING:
                upgrading_deps.append(change)
        return upgrading_deps

    # determine the addons for a given package
    def get_addons(self, pkgname, ignore_installed=True):
        """ get the list of addons for the given pkgname

            The optional parameter "ignore_installed" controls if the output
            should be filtered and pkgs already installed should be ignored
            in the output (e.g. useful for testing).

            :return: a tuple of pkgnames (recommends, suggests)
        """
        logging.debug("get_addons for '%s'" % pkgname)

        def _addons_filter(addon):
            """ helper for get_addons that filters out unneeded ones """
            # we don't know about this one (perfectly legal for suggests)
            if not addon in self._cache:
                LOG.debug("not in cache %s" % addon)
                return False
            # can happen via "lonely" depends
            if addon == pkg.name:
                LOG.debug("circular %s" % addon)
                return False
            # child pkg is addon of parent pkg, not the other way around.
            if addon == '-'.join(pkgname.split('-')[:-1]):
                LOG.debug("child > parent %s" % addon)
                return False
            # get the pkg
            addon_pkg = self._cache[addon]
            # we don't care for essential or important (or references
            # to our self)
            if addon_pkg.essential or addon_pkg._pkg.important:
                LOG.debug("essential or important %s" % addon)
                return False
            # we have it in our dependencies already
            if addon in deps:
                LOG.debug("already a dependency %s" % addon)
                return False
            # its a language-pack, language-selector should deal with it
            if self._is_language_pkg(addon):
                LOG.debug("part of language pkg rdepends %s" % addon)
                return False
            # something on the system depends on it
            rdeps = self.get_packages_removed_on_remove(addon_pkg)
            if rdeps and ignore_installed:
                LOG.debug("already has a installed rdepends %s" % addon)
                return False
            # looks good
            return True

        #----------------------------------------------------------------

        def _addons_filter_slow(addon):
            """ helper for get_addons that filters out unneeded ones """
            # this addon would get installed anyway (e.g. via indirect
            # dependency) so it would be misleading to show it
            if addon in all_deps_if_installed:
                LOG.debug("would get installed automatically %s" % addon)
                return False
            return True

        #----------------------------------------------------------------
        # deb file, or pkg needing source, etc
        if not pkgname in self._cache or not self._cache[pkgname].candidate:
            return ([], [])

        # initial setup
        pkg = self._cache[pkgname]

        # recommended addons
        addons_rec = self._get_recommends(pkg)
        LOG.debug("recommends: %s" % addons_rec)
        # suggested addons and renhances
        addons_sug = self._get_suggests(pkg)
        LOG.debug("suggests: %s" % addons_sug)
        renhances = self._get_renhances(pkg)
        LOG.debug("renhances: %s" % renhances)
        addons_sug += renhances
        provides = self._get_provides(pkg)
        LOG.debug("provides: %s" % provides)
        for provide in provides:
            virtual_aptpkg_pkg = self._cache._cache[provide]
            renhances = self._get_renhances_lowlevel_apt_pkg(
                virtual_aptpkg_pkg)
            LOG.debug("renhances of %s: %s" % (provide, renhances))
            addons_sug += renhances
            context = GLib.main_context_default()
            while context.pending():
                context.iteration()

        # get more addons, the idea is that if a package foo-data
        # just depends on foo we want to get the info about
        # "recommends, suggests, enhances" for foo-data as well
        #
        # FIXME: find a good package where this is actually the case and
        #        replace the existing test
        #        (arduino-core -> avrdude -> avrdude-doc) with that
        # FIXME2: if it turns out we don't have good/better examples,
        #         kill it
        deps = self._get_depends(pkg)
        for dep in deps:
            if dep in self._cache:
                pkgdep = self._cache[dep]
                if len(self._get_rdepends(pkgdep)) == 1:
                    # pkg is the only known package that depends on pkgdep
                    pkgdep_rec = self._get_recommends(pkgdep)
                    LOG.debug("recommends from lonely dependency %s: %s" %
                              (pkgdep, pkgdep_rec))
                    addons_rec += pkgdep_rec
                    pkgdep_sug = self._get_suggests(pkgdep)
                    LOG.debug("suggests from lonely dependency %s: %s" %
                              (pkgdep, pkgdep_sug))
                    addons_sug += pkgdep_sug
                    pkgdep_enh = self._get_renhances(pkgdep)
                    LOG.debug("renhances from lonely dependency %s: %s" %
                              (pkgdep, pkgdep_enh))
                    addons_sug += pkgdep_enh

            context = GLib.main_context_default()
            while context.pending():
                context.iteration()

        # remove duplicates from suggests (sets are great!)
        addons_sug = list(set(addons_sug) - set(addons_rec))

        # filter out stuff we don't want
        addons_rec = filter(_addons_filter, addons_rec)
        addons_sug = filter(_addons_filter, addons_sug)

        # this is not integrated into the filter above, as it is quite
        # expensive to run this call, so we only run it if we actually have
        # addons
        if addons_rec or addons_sug:
            # now get all_deps if the package would be installed
            try:
                all_deps_if_installed = \
                    self._try_install_and_get_all_deps_installed(pkg)
            except:
                # if we have broken packages, then we return no addons
                LOG.warn(
                    "broken packages encountered while getting deps for %s" %
                    pkgname)
                return ([], [])
            # filter out stuff we don't want
            addons_rec = filter(_addons_filter_slow, addons_rec)
            addons_sug = filter(_addons_filter_slow, addons_sug)

        return (addons_rec, addons_sug)
예제 #10
0
 def __init__(self, parent=None):
     gobject.GObject.__init__(self)
     self.client = AptClient()
     self.parent = parent
예제 #11
0
    def __init__(self):
        super(PackageInstaller, self).__init__()

        self._client = AptClient()
예제 #12
0
class PackageInstaller(GObject.GObject):

    __gsignals__ = {
        'auth-failed': (GObject.SignalFlags.RUN_LAST, None, ()),
        'done': (GObject.SignalFlags.RUN_LAST, None, (object, )),
    }

    def __init__(self):
        super(PackageInstaller, self).__init__()

        self._client = AptClient()

    #
    #  Public API
    #

    def install(self, *packages):
        def reply(transaction):
            transaction.connect('finished', self._on_transaction__finished)
            self._transaction = transaction
            # dependencis not available on lucid
            for p in getattr(transaction, 'dependencies', []):
                if p:
                    self._confirm()
                    break
            else:
                self._install()

        self._client.install_packages(list(packages),
                                      reply_handler=reply,
                                      error_handler=self._error_handler)

    #
    #  Private
    #

    def _confirm(self):
        dia = AptConfirmDialog(self._transaction)
        response = dia.run()
        dia.destroy()
        if response == Gtk.ResponseType.OK:
            self._install()

    def _install(self):
        dialog = AptProgressDialog(self._transaction)
        dialog.run(close_on_finished=True,
                   show_error=True,
                   reply_handler=lambda: True,
                   error_handler=self._error_handler)

    def _error_handler(self, error):
        try:
            raise error
        except NotAuthorizedError:
            # Silently ignore auth failures
            sys.exit(11)
            return
        except TransactionFailed as error:
            pass
        except Exception as error:
            error = TransactionFailed(ERROR_UNKNOWN, str(error))

        dia = AptErrorDialog(error)
        dia.run()
        sys.exit(10)

    #
    #  Callbacks
    #

    def _on_transaction__finished(self, transaction, exitcode):
        sys.exit(0 if exitcode in [0, 'exit-success'] else 10)
예제 #13
0
class AptCache(PackageInfo):
    """
    A apt cache that opens in the background and keeps the UI alive
    """

    # dependency types we are about
    DEPENDENCY_TYPES = ("PreDepends", "Depends")
    RECOMMENDS_TYPES = ("Recommends",)
    SUGGESTS_TYPES = ("Suggests",)
    ENHANCES_TYPES = ("Enhances",)
    PROVIDES_TYPES = ("Provides",)

    # stamp file to monitor (provided by update-notifier via
    # APT::Update::Post-Invoke-Success)
    APT_FINISHED_STAMP = "/var/lib/update-notifier/dpkg-run-stamp"

    LANGPACK_PKGDEPENDS = "/usr/share/language-selector/data/pkg_depends"

    def __init__(self):
        PackageInfo.__init__(self)
        self._cache = None
        self._ready = False
        self._timeout_id = None
        # setup monitor watch for install/remove changes
        self.apt_finished_stamp = Gio.File.new_for_path(
            self.APT_FINISHED_STAMP)
        self.apt_finished_monitor = self.apt_finished_stamp.monitor_file(0,
            None)
        self.apt_finished_monitor.connect(
            "changed", self._on_apt_finished_stamp_changed)
        # this is fast, so ok
        self._language_packages = self._read_language_pkgs()
        # query the totalize on install using aptdaemon
        try:
            self.aptd_client = AptClient()
        except Exception as e:
            self.aptd_client = None
            logging.error("Can not get aptdaemon client: '%s', no "
                          "size information will be available " % e)
        self._aptd_trans = None

    @staticmethod
    def version_compare(a, b):
        return apt_pkg.version_compare(a, b)

    @staticmethod
    def upstream_version_compare(a, b):
        return apt_pkg.version_compare(apt_pkg.upstream_version(a),
                                       apt_pkg.upstream_version(b))

    @staticmethod
    def upstream_version(v):
        return apt_pkg.upstream_version(v)

    def is_installed(self, pkgname):
        # use the lowlevel cache here, twice as fast
        lowlevel_cache = self._cache._cache
        return (pkgname in lowlevel_cache and
                lowlevel_cache[pkgname].current_ver is not None)

    def is_upgradable(self, pkgname):
        # use the lowlevel cache here, twice as fast
        if not pkgname in self._cache:
            return False
        return self._cache[pkgname].is_upgradable

    def is_available(self, pkgname):
        return (pkgname in self._cache and
                    self._cache[pkgname].candidate)

    def get_installed(self, pkgname):
        if (pkgname not in self._cache or
                not self._cache[pkgname].is_installed):
            return None
        return AptCacheVersion(self._cache[pkgname].installed)

    def get_candidate(self, pkgname):
        if (pkgname not in self._cache or
                not self._cache[pkgname].candidate):
            return None
        return AptCacheVersion(self._cache[pkgname].candidate)

    def get_versions(self, pkgname):
        if (pkgname not in self._cache or
                not self._cache[pkgname].candidate):
            return []
        return [AptCacheVersion(v) for v in self._cache[pkgname].versions]

    def get_section(self, pkgname):
        if (pkgname not in self._cache or
                not self._cache[pkgname].candidate):
            return ''
        return self._cache[pkgname].candidate.section

    def get_summary(self, pkgname):
        if (pkgname not in self._cache or
                not self._cache[pkgname].candidate):
            return ''
        return self._cache[pkgname].candidate.summary

    def get_description(self, pkgname):
        if (pkgname not in self._cache or
                not self._cache[pkgname].candidate):
            return ''
        return self._cache[pkgname].candidate.description

    def get_website(self, pkgname):
        if (pkgname not in self._cache or
                not self._cache[pkgname].candidate):
            return ''
        return self._cache[pkgname].candidate.homepage

    def get_installed_files(self, pkgname):
        if (pkgname not in self._cache):
            return []
        return self._cache[pkgname].installed_files

    def get_size(self, pkgname):
        if (pkgname not in self._cache or
                not self._cache[pkgname].candidate):
            return 0
        return self._cache[pkgname].candidate.size

    def get_installed_size(self, pkgname):
        if (pkgname not in self._cache or
                not self._cache[pkgname].candidate):
            return 0
        return self._cache[pkgname].candidate.installed_size

    @property
    def ready(self):
        return self._ready

    def get_license(self, name):
        return None

    def open(self, blocking=False):
        """ (re)open the cache, this sends cache-invalid, cache-ready signals
        """
        LOG.info("aptcache.open()")
        self._ready = False
        self.emit("cache-invalid")
        if blocking:
            progress = None
        else:
            progress = GtkMainIterationProgress()
        with ExecutionTime("open the apt cache (in event loop)"):
            if self._cache is None:
                self._cache = apt.Cache(progress)
            else:
                self._cache.open(progress)
        self._ready = True
        self.emit("cache-ready")
        if self._cache.broken_count > 0:
            self.emit("cache-broken")

    # implementation specific code

    # temporarily return a full apt.Package so that the tests and the
    # code keeps working for now, this needs to go away eventually
    # and get replaced with the abstract _Package class
    #def __getitem__(self, key):
    #    return self._cache[key]

    def __iter__(self):
        return self._cache.__iter__()

    def __contains__(self, k):
        return self._cache.__contains__(k)

    def _on_apt_finished_stamp_changed(self, monitor, afile, other_file,
                                       event):
        if not event == Gio.FileMonitorEvent.CHANGES_DONE_HINT:
            return
        if self._timeout_id:
            GLib.source_remove(self._timeout_id)
            self._timeout_id = None
        self._timeout_id = GLib.timeout_add_seconds(10, self.open)

    def _get_rdepends_by_type(self, pkg, type, onlyInstalled):
        rdeps = set()
        # make sure this is a apt.Package object
        try:
            pkg = self._cache[pkg.name]
        except KeyError:
            LOG.error("package %s not found in AptCache" % str(pkg))
            return rdeps
        for rdep in pkg._pkg.rev_depends_list:
            dep_type = rdep.dep_type_untranslated
            if dep_type in type:
                rdep_name = rdep.parent_pkg.name
                if (rdep_name in self._cache and
                        (not onlyInstalled or (
                            onlyInstalled and
                            self._cache[rdep_name].is_installed))):
                    rdeps.add(rdep.parent_pkg.name)
        return rdeps

    def _installed_dependencies(self, pkg_name, all_deps=None):
        """ recursively return all installed dependencies of a given pkg """
        #print "_installed_dependencies", pkg_name, all_deps
        if not all_deps:
            all_deps = set()
        if pkg_name not in self._cache:
            return all_deps
        cur = self._cache[pkg_name]._pkg.current_ver
        if not cur:
            return all_deps
        for t in self.DEPENDENCY_TYPES + self.RECOMMENDS_TYPES:
            try:
                for dep in cur.depends_list[t]:
                    dep_name = dep[0].target_pkg.name
                    if not dep_name in all_deps:
                        all_deps.add(dep_name)
                        all_deps |= self._installed_dependencies(dep_name,
                            all_deps)
            except KeyError:
                pass
        return all_deps

    def get_installed_automatic_depends_for_pkg(self, pkg):
        """ Get the installed automatic dependencies for this given package
            only.

            Note that the package must be marked for removal already for
            this to work
            Not: unused
        """
        installed_auto_deps = set()
        deps = self._installed_dependencies(pkg.name)
        for dep_name in deps:
            try:
                pkg = self._cache[dep_name]
            except KeyError:
                continue
            else:
                if (pkg.is_installed and
                        pkg.is_auto_removable):
                    installed_auto_deps.add(dep_name)
        return installed_auto_deps

    def get_all_origins(self):
        """
        return a set of the current channel origins from the apt.Cache itself
        """
        origins = set()
        for pkg in self._cache:
            if not pkg.candidate:
                continue
            for item in pkg.candidate.origins:
                context = GLib.main_context_default()
                while context.pending():
                    context.iteration()
                if item.origin:
                    origins.add(item.origin)
        return origins

    def get_origins(self, pkgname):
        """
        return package origins from apt.Cache
        """
        if not pkgname in self._cache or not self._cache[pkgname].candidate:
            return
        origins = set()
        for origin in self._cache[pkgname].candidate.origins:
            if origin.origin:
                origins.add(origin)
        return origins

    def get_origin(self, pkgname):
        """
        return a unique origin for the given package name. currently
        this will use
        """
        if not pkgname in self._cache or not self._cache[pkgname].candidate:
            return None
        origins = set([origin.origin for origin in self.get_origins(pkgname)])
        if len(origins) > 1:
            LOG.warn("more than one origin '%s'" % origins)
            return None
        if not origins:
            return None
        # we support only a single origin (but its fine if that is available
        # on multiple mirrors). lowercase as the server excepts it this way
        origin_str = origins.pop()
        return origin_str.lower()

    def component_available(self, distro_codename, component):
        """ check if the given component is enabled """
        # FIXME: test for more properties here?
        for it in self._cache._cache.file_list:
            if (it.component != "" and
                    it.component == component and
                    it.archive != "" and
                    it.archive == distro_codename):
                return True
        return False

    @convert_package_argument
    def _get_depends_by_type(self, pkg, types):
        version = pkg.installed
        if version is None:
            version = pkg.candidate
        return version.get_dependencies(*types)

    def _get_depends_by_type_str(self, pkg, *types):
        def not_in_list(list, item):
            for i in list:
                if i == item:
                    return False
            return True
        deps = self._get_depends_by_type(pkg, *types)
        deps_str = []
        for dep in deps:
            for dep_ in dep.or_dependencies:
                if not_in_list(deps_str, dep_.name):
                    deps_str.append(dep_.name)
        return deps_str

    # FIXME: there are cleaner ways to do this than below

    # pkg relations
    def _get_depends(self, pkg):
        return self._get_depends_by_type_str(pkg, self.DEPENDENCY_TYPES)

    def _get_recommends(self, pkg):
        return self._get_depends_by_type_str(pkg, self.RECOMMENDS_TYPES)

    def _get_suggests(self, pkg):
        return self._get_depends_by_type_str(pkg, self.SUGGESTS_TYPES)

    def _get_enhances(self, pkg):
        return self._get_depends_by_type_str(pkg, self.ENHANCES_TYPES)

    @convert_package_argument
    def _get_provides(self, pkg):
        # note: can use ._cand, because pkg has been converted to apt.Package
        provides_list = pkg.candidate._cand.provides_list
        provides = []
        for provided in provides_list:
            provides.append(provided[0])  # the package name
        return provides

    # reverse pkg relations
    def _get_rdepends(self, pkg):
        return self._get_rdepends_by_type(pkg, self.DEPENDENCY_TYPES, False)

    def _get_rrecommends(self, pkg):
        return self._get_rdepends_by_type(pkg, self.RECOMMENDS_TYPES, False)

    def _get_rsuggests(self, pkg):
        return self._get_rdepends_by_type(pkg, self.SUGGESTS_TYPES, False)

    def _get_renhances(self, pkg):
        return self._get_rdepends_by_type(pkg, self.ENHANCES_TYPES, False)

    @convert_package_argument
    def _get_renhances_lowlevel_apt_pkg(self, pkg):
        """ takes a apt_pkg.Package and returns a list of pkgnames that
            enhance this package - this is needed to support enhances
            for virtual packages
        """
        renhances = []
        for dep in pkg.rev_depends_list:
            if dep.dep_type_untranslated == "Enhances":
                renhances.append(dep.parent_pkg.name)
        return renhances

    def _get_rprovides(self, pkg):
        return self._get_rdepends_by_type(pkg, self.PROVIDES_TYPES, False)

    # installed reverse pkg relations
    def get_packages_removed_on_remove(self, pkg):
        return self._get_rdepends_by_type(pkg, self.DEPENDENCY_TYPES, True)

    def get_packages_removed_on_install(self, pkg):
        depends = set()
        deps_remove = self._try_install_and_get_all_deps_removed(pkg)
        for depname in deps_remove:
            if self._cache[depname].is_installed:
                depends.add(depname)
        return depends

    def _get_installed_rrecommends(self, pkg):
        return self._get_rdepends_by_type(pkg, self.RECOMMENDS_TYPES, True)

    def _get_installed_rsuggests(self, pkg):
        return self._get_rdepends_by_type(pkg, self.SUGGESTS_TYPES, True)

    def _get_installed_renhances(self, pkg):
        return self._get_rdepends_by_type(pkg, self.ENHANCES_TYPES, True)

    def _get_installed_rprovides(self, pkg):
        return self._get_rdepends_by_type(pkg, self.PROVIDES_TYPES, True)

    # language pack stuff
    def _is_language_pkg(self, addon):
        # a simple "addon in self._language_packages" is not enough
        for template in self._language_packages:
            if addon.startswith(template):
                return True
        return False

    def _read_language_pkgs(self):
        language_packages = set()
        if not os.path.exists(self.LANGPACK_PKGDEPENDS):
            return language_packages
        for line in open(self.LANGPACK_PKGDEPENDS):
            line = line.strip()
            if line.startswith('#'):
                continue
            try:
                (cat, code, dep_pkg, language_pkg) = line.split(':')
            except ValueError:
                continue
            language_packages.add(language_pkg)
        return language_packages

    # these are used for calculating the total size
    @convert_package_argument
    def _get_changes_without_applying(self, pkg):
        try:
            if pkg.installed is None:
                pkg.mark_install()
            else:
                pkg.mark_delete()
        except SystemError:
            # TODO: ideally we now want to display an error message
            #       and block the install button
            LOG.warning("broken packages encountered while getting deps for %s"
                      % pkg.name)
            return {}
        changes_tmp = self._cache.get_changes()
        changes = {}
        for change in changes_tmp:
            if change.marked_install or change.marked_reinstall:
                changes[change.name] = PkgStates.INSTALLING
            elif change.marked_delete:
                changes[change.name] = PkgStates.REMOVING
            elif change.marked_upgrade:
                changes[change.name] = PkgStates.UPGRADING
            else:
                changes[change.name] = PkgStates.UNKNOWN
        self._cache.clear()
        return changes

    def _try_install_and_get_all_deps_installed(self, pkg):
        """ Return all dependencies of pkg that will be marked for install """
        changes = self._get_changes_without_applying(pkg)
        installing_deps = []
        for change in changes.keys():
            if change != pkg.name and changes[change] == PkgStates.INSTALLING:
                installing_deps.append(change)
        return installing_deps

    def _try_install_and_get_all_deps_removed(self, pkg):
        """ Return all dependencies of pkg that will be marked for remove"""
        changes = self._get_changes_without_applying(pkg)
        removing_deps = []
        for change in changes.keys():
            if change != pkg.name and changes[change] == PkgStates.REMOVING:
                removing_deps.append(change)
        return removing_deps

    def _set_candidate_release(self, pkg, archive_suite):
        # Check if the package is provided in the release
        for version in pkg.versions:
            if [origin for origin in version.origins
                    if origin.archive == archive_suite]:
                break
        else:
            return False
        res = pkg._pcache._depcache.set_candidate_release(
            pkg._pkg, version._cand, archive_suite)
        return res

    # space calculation stuff
    def _on_total_size_calculation_done(self, trans, space):
        # ensure trans contains the data we expect, see LP: #1225885
        if trans.packages and trans.packages[0]:
            pkgname = trans.packages[0][0]
            self.emit(
                "query-total-size-on-install-done",
                pkgname, trans.download, trans.space)
            

    def _on_trans_simulate_error(self, error):
        LOG.exception("simulate failed")

    def _on_trans_commit_packages_ready(self, trans):
        trans.connect("space-changed", self._on_total_size_calculation_done)
        try:
            trans.simulate(reply_handler=lambda: True,
                           error_handler=self._on_trans_simulate_error)
        except:
            LOG.exception("simulate failed")

    def query_total_size_on_install(self, pkgname,
                                    addons_install=[], addons_remove=[],
                                    archive_suite=""):
        if not pkgname in self._cache:
            self.emit("query-total-size-on-install-done", pkgname, 0, 0)

        # ensure the syntax is right
        if archive_suite:
            pkgname = pkgname + "/" + archive_suite

        # and simulate the install/remove via aptdaemon
        install = [pkgname] + addons_install
        remove = addons_remove
        reinstall = purge = upgrade = downgrade = []

        if self._aptd_trans:
            self._aptd_trans.cancel()
            self._aptd_trans = None

        # do this async
        try:
            self.aptd_client.commit_packages(
                install, reinstall, remove, purge, upgrade, downgrade,
                # wait
                False,
                # reply and error handlers
                self._on_trans_commit_packages_ready,
                self._on_trans_simulate_error)
        except:
            LOG.exception(
                "getting commit_packages trans failed for '%s'" % pkgname)

    def get_all_deps_upgrading(self, pkg):
        # note: this seems not to be used anywhere
        changes = self._get_changes_without_applying(pkg)
        upgrading_deps = []
        for change in changes.keys():
            if change != pkg.name and changes[change] == PkgStates.UPGRADING:
                upgrading_deps.append(change)
        return upgrading_deps

    # determine the addons for a given package
    def get_addons(self, pkgname, ignore_installed=True):
        """ get the list of addons for the given pkgname

            The optional parameter "ignore_installed" controls if the output
            should be filtered and pkgs already installed should be ignored
            in the output (e.g. useful for testing).

            :return: a tuple of pkgnames (recommends, suggests)
        """
        logging.debug("get_addons for '%s'" % pkgname)

        def _addons_filter(addon):
            """ helper for get_addons that filters out unneeded ones """
            # we don't know about this one (perfectly legal for suggests)
            if not addon in self._cache:
                LOG.debug("not in cache %s" % addon)
                return False
            # can happen via "lonely" depends
            if addon == pkg.name:
                LOG.debug("circular %s" % addon)
                return False
            # child pkg is addon of parent pkg, not the other way around.
            if addon == '-'.join(pkgname.split('-')[:-1]):
                LOG.debug("child > parent %s" % addon)
                return False
            # get the pkg
            addon_pkg = self._cache[addon]
            # we don't care for essential or important (or references
            # to our self)
            if addon_pkg.essential or addon_pkg._pkg.important:
                LOG.debug("essential or important %s" % addon)
                return False
            # we have it in our dependencies already
            if addon in deps:
                LOG.debug("already a dependency %s" % addon)
                return False
            # its a language-pack, language-selector should deal with it
            if self._is_language_pkg(addon):
                LOG.debug("part of language pkg rdepends %s" % addon)
                return False
            # something on the system depends on it
            rdeps = self.get_packages_removed_on_remove(addon_pkg)
            if rdeps and ignore_installed:
                LOG.debug("already has a installed rdepends %s" % addon)
                return False
            # looks good
            return True
        #----------------------------------------------------------------

        def _addons_filter_slow(addon):
            """ helper for get_addons that filters out unneeded ones """
            # this addon would get installed anyway (e.g. via indirect
            # dependency) so it would be misleading to show it
            if addon in all_deps_if_installed:
                LOG.debug("would get installed automatically %s" % addon)
                return False
            return True
        #----------------------------------------------------------------
        # deb file, or pkg needing source, etc
        if not pkgname in self._cache or not self._cache[pkgname].candidate:
            return ([], [])

        # initial setup
        pkg = self._cache[pkgname]

        # recommended addons
        addons_rec = self._get_recommends(pkg)
        LOG.debug("recommends: %s" % addons_rec)
        # suggested addons and renhances
        addons_sug = self._get_suggests(pkg)
        LOG.debug("suggests: %s" % addons_sug)
        renhances = self._get_renhances(pkg)
        LOG.debug("renhances: %s" % renhances)
        addons_sug += renhances
        provides = self._get_provides(pkg)
        LOG.debug("provides: %s" % provides)
        for provide in provides:
            virtual_aptpkg_pkg = self._cache._cache[provide]
            renhances = self._get_renhances_lowlevel_apt_pkg(
                virtual_aptpkg_pkg)
            LOG.debug("renhances of %s: %s" % (provide, renhances))
            addons_sug += renhances
            context = GLib.main_context_default()
            while context.pending():
                context.iteration()

        # get more addons, the idea is that if a package foo-data
        # just depends on foo we want to get the info about
        # "recommends, suggests, enhances" for foo-data as well
        #
        # FIXME: find a good package where this is actually the case and
        #        replace the existing test
        #        (arduino-core -> avrdude -> avrdude-doc) with that
        # FIXME2: if it turns out we don't have good/better examples,
        #         kill it
        deps = self._get_depends(pkg)
        for dep in deps:
            if dep in self._cache:
                pkgdep = self._cache[dep]
                if len(self._get_rdepends(pkgdep)) == 1:
                    # pkg is the only known package that depends on pkgdep
                    pkgdep_rec = self._get_recommends(pkgdep)
                    LOG.debug("recommends from lonely dependency %s: %s" % (
                            pkgdep, pkgdep_rec))
                    addons_rec += pkgdep_rec
                    pkgdep_sug = self._get_suggests(pkgdep)
                    LOG.debug("suggests from lonely dependency %s: %s" % (
                            pkgdep, pkgdep_sug))
                    addons_sug += pkgdep_sug
                    pkgdep_enh = self._get_renhances(pkgdep)
                    LOG.debug("renhances from lonely dependency %s: %s" % (
                            pkgdep, pkgdep_enh))
                    addons_sug += pkgdep_enh

            context = GLib.main_context_default()
            while context.pending():
                context.iteration()

        # remove duplicates from suggests (sets are great!)
        addons_sug = list(set(addons_sug) - set(addons_rec))

        # filter out stuff we don't want
        addons_rec = filter(_addons_filter, addons_rec)
        addons_sug = filter(_addons_filter, addons_sug)

        # this is not integrated into the filter above, as it is quite
        # expensive to run this call, so we only run it if we actually have
        # addons
        if addons_rec or addons_sug:
            # now get all_deps if the package would be installed
            try:
                all_deps_if_installed = \
                    self._try_install_and_get_all_deps_installed(pkg)
            except:
                # if we have broken packages, then we return no addons
                LOG.warn(
                    "broken packages encountered while getting deps for %s" %
                    pkgname)
                return ([], [])
            # filter out stuff we don't want
            addons_rec = filter(_addons_filter_slow, addons_rec)
            addons_sug = filter(_addons_filter_slow, addons_sug)

        return (addons_rec, addons_sug)
예제 #14
0
 def __init__(self):
     self.apt_client = AptClient()
     self.apt_transaction = None
     self.packages = []
     self.loop = None
#!/usr/bin/python
import aptdaemon, sys, gettext
from aptdaemon.client import AptClient

# i18n
gettext.install("tuquito-software-manager", "/usr/share/tuquito/locale")

if len(sys.argv) == 3:
    operation = sys.argv[1]
    package = sys.argv[2]
    aptd_client = AptClient()
    if operation == "install":
        transaction = aptd_client.install_packages([package])
        transaction.set_meta_data(tuquito_label=_("Installing %s") % package)
    elif operation == "remove":
        transaction = aptd_client.remove_packages([package])
        transaction.set_meta_data(tuquito_label=_("Removing %s") % package)
    else:
        print "Invalid operation: %s" % operation
        sys.exit(1)
    transaction.set_meta_data(mintinstall_pkgname=package)
    transaction.run()
예제 #16
0
class AptPackageInstaller(gobject.GObject):
    # This avoids kiwi dependency since this is used early on.
    __gsignals__ = {
        'auth-failed': (gobject.SIGNAL_RUN_LAST, None, ()),
        'done': (gobject.SIGNAL_RUN_LAST, None, (object,)),
    }

    def __init__(self, parent=None):
        gobject.GObject.__init__(self)
        self.client = AptClient()
        self.parent = parent

    def install(self, *packages):
        def reply(transaction):
            transaction.connect("finished", self._on_transaction__finished)
            self._transaction = transaction
            # dependencis not available on lucid
            for p in getattr(transaction, 'dependencies', []):
                if p:
                    self._confirm()
                    break
            else:
                self._install()
        self.client.install_packages(list(packages),
                                     reply_handler=reply,
                                     error_handler=self._error_handler)

    def _on_transaction__finished(self, transaction, exitcode):
        if exitcode not in [0, 'exit-success']:
            error = exitcode
        else:
            error = None
        self.emit('done', error)

    def _error_handler(self, error):
        try:
            raise error
        except NotAuthorizedError:
            # Silently ignore auth failures
            self.emit('auth-failed')
            return
        except TransactionFailed as error:
            pass
        except Exception as error:
            error = TransactionFailed(ERROR_UNKNOWN, str(error))
        dia = AptErrorDialog(error)
        dia.run()
        dia.destroy()

    def _confirm(self):
        from aptdaemon.gtkwidgets import AptConfirmDialog
        dia = AptConfirmDialog(self._transaction,
                               parent=self.parent)
        response = dia.run()
        dia.destroy()
        if response == gtk.RESPONSE_OK:
            self._install()

    def _install(self):
        def reply():
            return True
        dialog = AptProgressDialog(self._transaction,
                                   parent=self.parent)
        dialog.run(close_on_finished=True,
                   show_error=True,
                   reply_handler=reply,
                   error_handler=self._error_handler)
예제 #17
0
#!/usr/bin/python
import aptdaemon, sys, gettext
from aptdaemon.client import AptClient

# i18n
gettext.install("mintinstall", "/usr/share/linuxmint/locale")

if len(sys.argv) == 3:
    operation = sys.argv[1]
    package = sys.argv[2]
    aptd_client = AptClient()
    if operation == "install":
        transaction = aptd_client.install_packages([package])    
        transaction.set_meta_data(mintinstall_label=_("Installing %s") % package)        
    elif operation == "remove":
        transaction = aptd_client.remove_packages([package])    
        transaction.set_meta_data(mintinstall_label=_("Removing %s") % package)
    else:
        print "Invalid operation: %s" % operation
        sys.exit(1)        
    transaction.set_meta_data(mintinstall_pkgname=package)
    transaction.run()
    active -= 1
    return True

def run(t):
    if WITH_GUI:
        dia = AptProgressDialog(t)
        dia.run()
        dia.destroy()
    else:
        t.run()

if __name__ == "__main__":
    #logging.basicConfig(level=logging.DEBUG)

    context = GObject.main_context_default()
    c = AptClient()
    for i in range(100):
        
        print "inst: 3dchess"
        t = c.install_packages(["3dchess"], exit_handler=exit_handler)
        run(t)
        active += 1

        print "inst: 2vcard"
        t = c.install_packages(["2vcard"], exit_handler=exit_handler)
        run(t)
        active += 1
        
        print "rm: 3dchess 2vcard"
        t = c.remove_packages(["3dchess","2vcard"], exit_handler=exit_handler)
        run(t)
예제 #19
0
#!/usr/bin/env python2
# -*- coding: utf-8 -*-
# vim:fenc=utf-8
#
# Copyright © 2016 Johnathan "Shaggytwodope" Jenkins <*****@*****.**>
#
# Distributed under terms of the GPL2 license.

import sys
from gi.repository import GLib
from aptdaemon.client import AptClient

loop = GLib.MainLoop()
aptclient = AptClient()


def on_finished_update(trans, exit):
    if exit == "exit-success":
        print("successful cache update")
        loop.quit()
        sys.exit(0)
    else:
        print("error updating cache")
        sys.exit(1)
    return True


def do_update():
    trans_update = aptclient.update_cache()
    trans_update.connect("finished", on_finished_update)
    trans_update.run()