Beispiel #1
0
def get_dependency_solvers(block,
                           binaries_s_a,
                           provides_s_a,
                           *,
                           empty_set=frozenset(),
                           component=None):
    """Find the packages which satisfy a dependency block

    This method returns the list of packages which satisfy a dependency
    block (as returned by apt_pkg.parse_depends) in a package table
    for a given suite and architecture (a la self.binaries[suite][arch])

    If component was not specified, use all available (multiverse). This is to
    avoid britney pretending that a bunch of things are non-installable in
    release pocket, and start trading components-mismatches things.

    :param block: The dependency block as parsed by apt_pkg.parse_depends
    :param binaries_s_a: A dict mapping package names to the relevant BinaryPackage
    :param provides_s_a: A dict mapping package names to their providers (as generated by parse_provides)
    :param empty_set: Internal implementation detail / optimisation
    :return a list of package names solving the relation
    """
    packages = []

    # for every package, version and operation in the block
    for name, version, op in block:
        if ":" in name:
            name, archqual = name.split(":", 1)
        else:
            archqual = None

        # look for the package in unstable
        if name in binaries_s_a:
            package = binaries_s_a[name]
            # check the versioned dependency and architecture qualifier
            # (if present)
            if (op == '' and version == '') or apt_pkg.check_dep(
                    package.version, op, version):
                if archqual is None or (archqual == 'any'
                                        and package.multi_arch == 'allowed'):
                    if component is None or allowed_component(
                            component, get_component(package.section)):
                        packages.append(name)

        # look for the package in the virtual packages list and loop on them
        for prov, prov_version in provides_s_a.get(name, empty_set):
            assert prov in binaries_s_a
            # A provides only satisfies:
            # - an unversioned dependency (per Policy Manual §7.5)
            # - a dependency without an architecture qualifier
            #   (per analysis of apt code)
            if archqual is not None:
                # Punt on this case - these days, APT and dpkg might actually agree on
                # this.
                continue
            if (op == '' and version == '') or \
                    (prov_version != '' and apt_pkg.check_dep(prov_version, op, version)):
                packages.append(prov)

    return packages
Beispiel #2
0
    def _is_or_group_satisfied(self, or_group):
        """Return True if at least one dependency of the or-group is satisfied.

        This method gets an 'or_group' and analyzes if at least one dependency
        of this group is already satisfied.
        """
        self._dbg(2, "_checkOrGroup(): %s " % (or_group))

        for dep in or_group:
            depname = dep[0]
            ver = dep[1]
            oper = dep[2]

            # check for virtual pkgs
            if not depname in self._cache:
                if self._cache.is_virtual_package(depname):
                    self._dbg(3, "_isOrGroupSatisfied(): %s is virtual dep" %
                                 depname)
                    for pkg in self._cache.get_providing_packages(depname):
                        if pkg.is_installed:
                            return True
                continue

            inst = self._cache[depname].installed
            if inst is not None and apt_pkg.check_dep(inst.version, oper, ver):
                return True
        return False
Beispiel #3
0
 def _check_single_pkg_conflict(self, pkgname, ver, oper):
     """Return True if a pkg conflicts with a real installed/marked pkg."""
     # FIXME: deal with conflicts against its own provides
     #        (e.g. Provides: ftp-server, Conflicts: ftp-server)
     self._dbg(
         3, "_check_single_pkg_conflict() pkg='%s' ver='%s' oper='%s'" % (
             pkgname, ver, oper))
     pkg = self._cache[pkgname]
     if pkg.is_installed:
         pkgver = pkg.installed.version
     elif pkg.marked_install:
         pkgver = pkg.candidate.version
     else:
         return False
     #print "pkg: %s" % pkgname
     #print "ver: %s" % ver
     #print "pkgver: %s " % pkgver
     #print "oper: %s " % oper
     if (apt_pkg.check_dep(pkgver, oper, ver) and not
             self.replaces_real_pkg(pkgname, oper, ver)):
         self._failure_string += _("Conflicts with the installed package "
                                   "'%s'") % pkg.name
         self._dbg(3, "conflicts with installed pkg '%s'" % pkg.name)
         return True
     return False
 def _check_single_pkg_conflict(self, pkgname, ver, oper):
     # type: (str, str, str) -> bool
     """Return True if a pkg conflicts with a real installed/marked pkg."""
     # FIXME: deal with conflicts against its own provides
     #        (e.g. Provides: ftp-server, Conflicts: ftp-server)
     self._dbg(
         3, "_check_single_pkg_conflict() pkg='%s' ver='%s' oper='%s'" %
         (pkgname, ver, oper))
     pkg = self._cache[pkgname]
     if pkg.is_installed:
         assert pkg.installed is not None
         pkgver = pkg.installed.version
     elif pkg.marked_install:
         assert pkg.candidate is not None
         pkgver = pkg.candidate.version
     else:
         return False
     #print "pkg: %s" % pkgname
     #print "ver: %s" % ver
     #print "pkgver: %s " % pkgver
     #print "oper: %s " % oper
     if (apt_pkg.check_dep(pkgver, oper, ver)
             and not self.replaces_real_pkg(pkgname, oper, ver)):
         self._failure_string += _("Conflicts with the installed package "
                                   "'%s'") % pkg.name
         self._dbg(3, "conflicts with installed pkg '%s'" % pkg.name)
         return True
     return False
Beispiel #5
0
    def replaces_real_pkg(self, pkgname, oper, ver):
        # type: (str, str, str) -> bool
        """Return True if a given non-virtual package is replaced.

        Return True if the deb packages replaces a real (not virtual)
        packages named (pkgname, oper, ver).
        """
        self._dbg(3, "replaces_real_pkg() %s %s %s" % (pkgname, oper, ver))
        pkg = self._cache[pkgname]
        pkgver = None  # type: Optional[str]
        if pkg.is_installed:
            assert pkg.installed is not None
            pkgver = pkg.installed.version
        elif pkg.marked_install:
            assert pkg.candidate is not None
            pkgver = pkg.candidate.version
        else:
            pkgver = None
        for or_group in self.replaces:
            for (name, ver, oper) in or_group:
                if (name == pkgname and (pkgver is None or
                        apt_pkg.check_dep(pkgver, oper, ver))):
                    self._dbg(3, "we have a replaces in our package for the "
                                 "conflict against '%s'" % (pkgname))
                    return True
        return False
    def replaces_real_pkg(self, pkgname, oper, ver):
        # type: (str, str, str) -> bool
        """Return True if a given non-virtual package is replaced.

        Return True if the deb packages replaces a real (not virtual)
        packages named (pkgname, oper, ver).
        """
        self._dbg(3, "replaces_real_pkg() %s %s %s" % (pkgname, oper, ver))
        pkg = self._cache[pkgname]
        pkgver = None  # type: Optional[str]
        if pkg.is_installed:
            assert pkg.installed is not None
            pkgver = pkg.installed.version
        elif pkg.marked_install:
            assert pkg.candidate is not None
            pkgver = pkg.candidate.version
        else:
            pkgver = None
        for or_group in self.replaces:
            for (name, ver, oper) in or_group:
                if (name == pkgname and
                    (pkgver is None or apt_pkg.check_dep(pkgver, oper, ver))):
                    self._dbg(
                        3, "we have a replaces in our package for the "
                        "conflict against '%s'" % (pkgname))
                    return True
        return False
Beispiel #7
0
    def _is_or_group_satisfied(self, or_group):
        """Return True if at least one dependency of the or-group is satisfied.

        This method gets an 'or_group' and analyzes if at least one dependency
        of this group is already satisfied.
        """
        self._dbg(2, "_checkOrGroup(): %s " % (or_group))

        for dep in or_group:
            depname = dep[0]
            ver = dep[1]
            oper = dep[2]

            # check for virtual pkgs
            if not depname in self._cache:
                if self._cache.is_virtual_package(depname):
                    self._dbg(
                        3,
                        "_isOrGroupSatisfied(): %s is virtual dep" % depname)
                    for pkg in self._cache.get_providing_packages(depname):
                        if pkg.is_installed:
                            return True
                continue

            inst = self._cache[depname].installed
            if inst is not None and apt_pkg.check_dep(inst.version, oper, ver):
                return True
        return False
Beispiel #8
0
 def check_breaks_existing_packages(self):
     """
     check if installing the package would break exsisting
     package on the system, e.g. system has:
     smc depends on smc-data (= 1.4)
     and user tries to installs smc-data 1.6
     """
     # show progress information as this step may take some time
     debver = self.sections["Version"]
     debarch = self.sections["Architecture"]
     # store what we provide so that we can later check against that
     provides = [ x[0][0] for x in self.provides]
     for (i, pkg) in enumerate(self.cache):
         if not pkg.is_installed:
             continue
         # check if the exising dependencies are still satisfied with the package
         ver = pkg._pkg.current_ver
         for dep_or in pkg.installed.dependencies:
             for dep in dep_or.or_dependencies:
                 if dep.name == self.pkgname:
                     if not apt_pkg.check_dep(debver, dep.relation, dep.version):
                         failure_string = "Breaks existing package <b>%(pkgname)s</b> with dependency:<br>     <b>%(depname)s</b> (%(deprelation)s%(depversion)s)" % {
                             'pkgname' : pkg.name,
                             'depname' : dep.name,
                             'deprelation' : dep.relation,
                             'depversion' : dep.version}
                         return failure_string
         # now check if there are conflicts against this package on the existing system
         if "Conflicts" in ver.depends_list:
             for conflicts_ver_list in ver.depends_list["Conflicts"]:
                 for c_or in conflicts_ver_list:
                     if c_or.target_pkg.name == self.pkgname and c_or.target_pkg.architecture == debarch:
                         if apt_pkg.check_dep(debver, c_or.comp_type, c_or.target_ver):
                             failure_string = "Breaks existing package <b>%(pkgname)s</b> conflict:<br>     <b>%(targetpkg)s</b> (%(comptype)s%(targetver)s)" % {
                                 'pkgname' : pkg.name,
                                 'targetpkg' : c_or.target_pkg.name,
                                 'comptype' : c_or.comp_type,
                                 'targetver' : c_or.target_ver }
                             return failure_string
                     if (c_or.target_pkg.name in provides and self.pkgname != pkg.name):
                         failure_string = "Breaks existing package <b>%(pkgname)s</b> that conflict:<br>     <b>%(targetpkg)s</b><br><br>But the <b>%(debfile)s</b> provides it via:<br>     <b>%(provides)s</b>" % {
                             'provides' : ",".join(provides),
                             'debfile'  : self.filename,
                             'targetpkg' : c_or.target_pkg.name,
                             'pkgname' : pkg.name }
                         return failure_string
     return True
    def mark_install(self, pstr):
        deps = apt_pkg.parse_depends(pstr)
        have_version = False
        for ord in deps:
            if have_version:
                break

            print pstr, ord
            for d in ord:
                name = d[0]
                version_num = d[1]
                version_op = d[2]

                p = self.cache[name]
                if not p:
                    logging.error("Could not find package %s in cache", name)
                    continue

                if len(version_num) > 0:
                    highest_v = None
                    highest_vnum = 0

                    for version in p.versions:
                        if apt_pkg.check_dep(version.version, version_op, version_num):
                            have_version = True
                            logging.info("package: %s, version: %s, priority: %s/%d",
                                    name, version.version, version.priority, version.policy_priority)

                            if (version.policy_priority > highest_vnum):
                                highest_vnum = version.policy_priority
                                highest_v = version

                    if not have_version:
                        logging.error("Could not required version of the package %s, must be %s %s",
                                name, version_op, version_num)
                        # going for the next ORed version if any
                        continue

                    p.candidate = highest_v
                    logging.info("package %s, selected version: %s, priority: %s/%d",
                            name, p.candidate.version, p.candidate.priority, p.candidate.policy_priority)

                logging.info("Going to install package %s", name)
                p.mark_install(auto_fix=True, auto_inst=True)
                have_version = True

                # do not run for the subsequent ORed packages
                break

        if not have_version:
            logging.fatal("Could not find suitable package %s", pstr)
Beispiel #10
0
 def _check_dependencies(self, target, deps):
     """Return True if any of the dependencies in deps match target."""
     # TODO: handle virtual packages
     for dep_or in deps:
         if not dep_or:
             continue
         match = True
         for base_dep in dep_or:
             if (base_dep.name != target.package.shortname or
                 not apt_pkg.check_dep(
                     target.version, base_dep.relation, base_dep.version)):
                 match = False
         if match:
             return True
     return False
 def _check_dependencies(self, target, deps):
     """Return True if any of the dependencies in deps match target."""
     # TODO: handle virtual packages
     for dep_or in deps:
         if not dep_or:
             continue
         match = True
         for base_dep in dep_or:
             if (base_dep.name != target.package.shortname
                     or not apt_pkg.check_dep(target.version,
                                              base_dep.relation,
                                              base_dep.version)):
                 match = False
         if match:
             return True
     return False
    def _is_or_group_satisfied(self, or_group):
        # type: (List[Tuple[str, str, str]]) -> bool
        """Return True if at least one dependency of the or-group is satisfied.

        This method gets an 'or_group' and analyzes if at least one dependency
        of this group is already satisfied.
        """
        self._dbg(2, "_checkOrGroup(): %s " % (or_group))

        for dep in or_group:
            depname = dep[0]
            ver = dep[1]
            oper = dep[2]

            # multiarch
            depname = self._maybe_append_multiarch_suffix(depname)

            # check for virtual pkgs
            if depname not in self._cache:
                if self._cache.is_virtual_package(depname):
                    self._dbg(
                        3, "_is_or_group_satisfied(): %s is virtual dep" %
                        depname)
                    for pkg in self._cache.get_providing_packages(depname):
                        if pkg.is_installed:
                            return True
                continue
            # check real dependency
            inst = self._cache[depname].installed
            if inst is not None and apt_pkg.check_dep(inst.version, oper, ver):
                return True

            # if no real dependency is installed, check if there is
            # a package installed that provides this dependency
            # (e.g. scrollkeeper dependecies are provided by rarian-compat)
            # but only do that if there is no version required in the
            # dependency (we do not supprot versionized dependencies)
            if not oper:
                for ppkg in self._cache.get_providing_packages(
                        depname, include_nonvirtual=True):
                    if ppkg.is_installed:
                        self._dbg(
                            3, "found installed '%s' that provides '%s'" %
                            (ppkg.name, depname))
                        return True
        return False
Beispiel #13
0
    def _is_or_group_satisfied(self, or_group):
        # type: (List[Tuple[str, str, str]]) -> bool
        """Return True if at least one dependency of the or-group is satisfied.

        This method gets an 'or_group' and analyzes if at least one dependency
        of this group is already satisfied.
        """
        self._dbg(2, "_checkOrGroup(): %s " % (or_group))

        for dep in or_group:
            depname = dep[0]
            ver = dep[1]
            oper = dep[2]

            # multiarch
            depname = self._maybe_append_multiarch_suffix(depname)

            # check for virtual pkgs
            if depname not in self._cache:
                if self._cache.is_virtual_package(depname):
                    self._dbg(
                        3, "_is_or_group_satisfied(): %s is virtual dep" %
                        depname)
                    for pkg in self._cache.get_providing_packages(depname):
                        if pkg.is_installed:
                            return True
                continue
            # check real dependency
            inst = self._cache[depname].installed
            if inst is not None and apt_pkg.check_dep(inst.version, oper, ver):
                return True

            # if no real dependency is installed, check if there is
            # a package installed that provides this dependency
            # (e.g. scrollkeeper dependecies are provided by rarian-compat)
            # but only do that if there is no version required in the
            # dependency (we do not supprot versionized dependencies)
            if not oper:
                for ppkg in self._cache.get_providing_packages(
                    depname, include_nonvirtual=True):
                    if ppkg.is_installed:
                        self._dbg(
                            3, "found installed '%s' that provides '%s'" % (
                                ppkg.name, depname))
                        return True
        return False
Beispiel #14
0
    def _satisfy_or_group(self, or_group):
        # type: (List[Tuple[str, str, str]]) -> bool
        """Try to satisfy the or_group."""
        for dep in or_group:
            depname, ver, oper = dep

            # multiarch
            depname = self._maybe_append_multiarch_suffix(depname)

            # if we don't have it in the cache, it may be virtual
            if depname not in self._cache:
                if not self._cache.is_virtual_package(depname):
                    continue
                providers = self._cache.get_providing_packages(depname)
                # if a package just has a single virtual provider, we
                # just pick that (just like apt)
                if len(providers) != 1:
                    continue
                depname = providers[0].name

            # now check if we can satisfy the deps with the candidate(s)
            # in the cache
            pkg = self._cache[depname]
            cand = self._cache._depcache.get_candidate_ver(pkg._pkg)
            if not cand:
                continue
            if not apt_pkg.check_dep(cand.ver_str, oper, ver):
                continue

            # check if we need to install it
            self._dbg(2, "Need to get: %s" % depname)
            self._need_pkgs.append(depname)
            return True

        # if we reach this point, we failed
        or_str = ""
        for dep in or_group:
            or_str += dep[0]
            if ver and oper:
                or_str += " (%s %s)" % (dep[2], dep[1])
            if dep != or_group[len(or_group) - 1]:
                or_str += "|"
        self._failure_string += _(
            "Dependency is not satisfiable: %s\n") % or_str
        return False
    def _satisfy_or_group(self, or_group):
        # type: (List[Tuple[str, str, str]]) -> bool
        """Try to satisfy the or_group."""
        for dep in or_group:
            depname, ver, oper = dep

            # multiarch
            depname = self._maybe_append_multiarch_suffix(depname)

            # if we don't have it in the cache, it may be virtual
            if depname not in self._cache:
                if not self._cache.is_virtual_package(depname):
                    continue
                providers = self._cache.get_providing_packages(depname)
                # if a package just has a single virtual provider, we
                # just pick that (just like apt)
                if len(providers) != 1:
                    continue
                depname = providers[0].name

            # now check if we can satisfy the deps with the candidate(s)
            # in the cache
            pkg = self._cache[depname]
            cand = self._cache._depcache.get_candidate_ver(pkg._pkg)
            if not cand:
                continue
            if not apt_pkg.check_dep(cand.ver_str, oper, ver):
                continue

            # check if we need to install it
            self._dbg(2, "Need to get: %s" % depname)
            self._need_pkgs.append(depname)
            return True

        # if we reach this point, we failed
        or_str = ""
        for dep in or_group:
            or_str += dep[0]
            if ver and oper:
                or_str += " (%s %s)" % (dep[2], dep[1])
            if dep != or_group[len(or_group) - 1]:
                or_str += "|"
        self._failure_string += _(
            "Dependency is not satisfiable: %s\n") % or_str
        return False
Beispiel #16
0
    def check_single_pkg_conflict(self, pkgname, ver, oper):
        """Return True if a pkg conflicts with a real installed/marked pkg."""
        # FIXME: deal with conflicts against its own provides
        #        (e.g. Provides: ftp-server, Conflicts: ftp-server)
        pkg = self.cache[pkgname]
        if pkg.is_installed:
            pkgver = pkg.installed.version
        elif pkg.marked_install:
            pkgver = pkg.candidate.version
        else:
            return False

        if (apt_pkg.check_dep(pkgver, oper, ver) and not
            self.replaces_real_pkg(pkgname, oper, ver)):
            #~ self.failure_string += _("Conflicts with the installed package "
                                      #~ "'%s'") % pkg.name
            return True
        return False
Beispiel #17
0
    def is_or_group_satisfied(self, or_group):
        """Return True if at least one dependency of the or-group is satisfied.

        This method gets an 'or_group' and analyzes if at least one dependency
        of this group is already satisfied.
        """

        for dep in or_group:
            depname = dep[0]
            ver = dep[1]
            oper = dep[2]

            # multiarch
            depname = self.maybe_append_multiarch_suffix(depname)

            # check for virtual pkgs
            if not depname in self.cache:
                if self.cache.is_virtual_package(depname):
                    for pkg in self.cache.get_providing_packages(depname):
                        if pkg.is_installed:
                            return True
                continue
            # check real dependency
            inst = self.cache[depname].installed
            if inst is not None and apt_pkg.check_dep(inst.version, oper, ver):
                return True

            # if no real dependency is installed, check if there is
            # a package installed that provides this dependency
            # (e.g. scrollkeeper dependecies are provided by rarian-compat)
            # but only do that if there is no version required in the
            # dependency (we do not supprot versionized dependencies)
            if not oper:
                for ppkg in self.cache.get_providing_packages(depname, include_nonvirtual=True):
                    if ppkg.is_installed:
                        return True
        return False
Beispiel #18
0
    def test_check_dep(self):
        "dependencies: Test apt_pkg.check_dep()"
        self.assertFalse(apt_pkg.check_dep("1", "<<", "0"))
        self.assertFalse(apt_pkg.check_dep("1", "<<", "1"))
        self.assertTrue(apt_pkg.check_dep("1", "<<", "2"))

        self.assertFalse(apt_pkg.check_dep("1", "<", "0"))
        self.assertFalse(apt_pkg.check_dep("1", "<", "1"))
        self.assertTrue(apt_pkg.check_dep("1", "<", "2"))

        self.assertFalse(apt_pkg.check_dep("1", "<=", "0"))
        self.assertTrue(apt_pkg.check_dep("1", "<=", "1"))
        self.assertTrue(apt_pkg.check_dep("1", "<=", "2"))

        self.assertFalse(apt_pkg.check_dep("0", "=", "1"))
        self.assertTrue(apt_pkg.check_dep("1", "=", "1"))
        self.assertFalse(apt_pkg.check_dep("2", "=", "1"))

        self.assertFalse(apt_pkg.check_dep("0", ">=", "1"))
        self.assertTrue(apt_pkg.check_dep("1", ">=", "1"))
        self.assertTrue(apt_pkg.check_dep("2", ">=", "1"))

        self.assertFalse(apt_pkg.check_dep("0", ">", "1"))
        self.assertFalse(apt_pkg.check_dep("1", ">", "1"))
        self.assertTrue(apt_pkg.check_dep("2", ">", "1"))

        self.assertFalse(apt_pkg.check_dep("0", ">>", "1"))
        self.assertFalse(apt_pkg.check_dep("1", ">>", "1"))
        self.assertTrue(apt_pkg.check_dep("2", ">>", "1"))
Beispiel #19
0
    def fetch(self, names):
        """
        Fetch packages

        Fetch specified and all dependent packages.
        """

        # There may be more than one revision specification for a package.
        # We store them in a list for each package, and we store each list
        # in a ordered dict indexed by the package name. An orderd dict is
        # used to ensure the packages are processed in the specified order.

        depends = collections.OrderedDict()
        for package_name in names:
            pkg = apt_pkg.parse_depends(package_name)[0][0]
            if pkg[0] not in depends:
                depends[pkg[0]] = []
            depends[pkg[0]].append(pkg)

        for package_name in depends.keys():
            try:
                pkg = self._cache[package_name]
            except KeyError:
                msg = "Can't find %s in package cache" % package_name
                raise OpxPackagesError, OpxPackagesError(
                    msg), sys.exc_info()[2]

            # find a version that satisfies the revision specification
            found = False
            for v in pkg.versions:
                satisfied = True

                for dep in depends[package_name]:
                    dep_version = dep[1]
                    dep_relation = dep[2]

                    if not apt_pkg.check_dep(v.version, dep_relation,
                                             dep_version):
                        satisfied = False
                        break

                if satisfied:
                    found = True

                    pkg.candidate = v
                    if self._default_solver:
                        # Use default apt_pkg solver
                        try:
                            pkg.mark_install(auto_inst=True,
                                             auto_fix=True,
                                             from_user=False)
                        except SystemError as ex:
                            raise OpxPackagesError, OpxPackagesError(
                                ex), sys.exc_info()[2]

                        if pkg.marked_keep and not pkg.is_installed:
                            self._dump_package(pkg._pkg)
                            msg = "Could not install %s due to version conflicts" % package_name
                            raise OpxPackagesError(msg)
                    else:
                        # Use modified solver for handling semantic versioning
                        self._fetch_package(pkg._pkg)

                    break

            if not found:
                raise OpxPackagesError(
                    "Failed to locate %s that satisfies revision specifications"
                    % package_name)

        if self._depcache.broken_count:
            logger.info("Attempting to fix %s broken packages",
                        self._depcache.broken_count)
            try:
                self._depcache.fix_broken()
            except SystemError:
                raise OpxPackagesError("We have broken dependencies")

        # Fetch packages
        try:
            self._cache.fetch_archives()
        except apt.cache.FetchFailedException as ex:
            # re-raise exception
            msg = "Fetch failed"
            raise OpxPackagesError, OpxPackagesError(msg), sys.exc_info()[2]
        except apt.cache.FetchCancelledException as ex:
            # re-raise exception
            msg = "Fetch cancelled"
            raise OpxPackagesError, OpxPackagesError(msg), sys.exc_info()[2]
Beispiel #20
0
def get_dependency_solvers(block, binaries_s_a, provides_s_a, *, build_depends=False, empty_set=frozenset()):
    """Find the packages which satisfy a dependency block

    This method returns the list of packages which satisfy a dependency
    block (as returned by apt_pkg.parse_depends) in a package table
    for a given suite and architecture (a la self.binaries[suite][arch])

    It can also handle build-dependency relations if the named parameter
    "build_depends" is set to True.  In this case, block should be based
    on the return value from apt_pkg.parse_src_depends.

    :param block: The dependency block as parsed by apt_pkg.parse_depends (or apt_pkg.parse_src_depends
      if the "build_depends" is True)
    :param binaries_s_a: A dict mapping package names to the relevant BinaryPackage
    :param provides_s_a: A dict mapping package names to their providers (as generated by parse_provides)
    :param build_depends: If True, treat the "block" parameter as a build-dependency relation rather than
      a regular dependency relation.
    :param empty_set: Internal implementation detail / optimisation
    :return a list of package names solving the relation
    """
    packages = []

    # for every package, version and operation in the block
    for name, version, op in block:
        if ":" in name:
            name, archqual = name.split(":", 1)
        else:
            archqual = None

        # look for the package in unstable
        if name in binaries_s_a:
            package = binaries_s_a[name]
            # check the versioned dependency and architecture qualifier
            # (if present)
            if (op == '' and version == '') or apt_pkg.check_dep(package.version, op, version):
                if archqual is None:
                    packages.append(package)
                elif build_depends and archqual == 'native':
                    # Multi-arch handling for build-dependencies
                    # - :native is ok always (since dpkg 1.19.1)
                    packages.append(package)

                # Multi-arch handling for both build-dependencies and regular dependencies
                # - :any is ok iff the target has "M-A: allowed"
                if archqual == 'any' and package.multi_arch == 'allowed':
                    packages.append(package)

        # look for the package in the virtual packages list and loop on them
        for prov, prov_version in provides_s_a.get(name, empty_set):
            assert prov in binaries_s_a
            # A provides only satisfies:
            # - an unversioned dependency (per Policy Manual §7.5)
            # - a dependency without an architecture qualifier
            #   (per analysis of apt code)
            if archqual is not None:
                # Punt on this case - these days, APT and dpkg might actually agree on
                # this.
                continue
            if (op == '' and version == '') or \
                    (prov_version != '' and apt_pkg.check_dep(prov_version, op, version)):
                packages.append(binaries_s_a[prov])

    return packages
 def check_breaks_existing_packages(self):
     # type: () -> bool
     """
     check if installing the package would break exsisting
     package on the system, e.g. system has:
     smc depends on smc-data (= 1.4)
     and user tries to installs smc-data 1.6
     """
     # show progress information as this step may take some time
     size = float(len(self._cache))
     steps = max(int(size / 50), 1)
     debver = self._sections["Version"]
     debarch = self._sections["Architecture"]
     # store what we provide so that we can later check against that
     provides = [x[0][0] for x in self.provides]
     for (i, pkg) in enumerate(self._cache):
         if i % steps == 0:
             self._cache.op_progress.update(float(i) / size * 100.0)
         if not pkg.is_installed:
             continue
         assert pkg.installed is not None
         # check if the exising dependencies are still satisfied
         # with the package
         ver = pkg._pkg.current_ver
         for dep_or in pkg.installed.dependencies:
             for dep in dep_or.or_dependencies:
                 if dep.name == self.pkgname:
                     if not apt_pkg.check_dep(debver, dep.relation,
                                              dep.version):
                         self._dbg(2, "would break (depends) %s" % pkg.name)
                         # TRANSLATORS: the first '%s' is the package that
                         # breaks, the second the dependency that makes it
                         # break, the third the relation (e.g. >=) and the
                         # latest the version for the releation
                         self._failure_string += _(
                             "Breaks existing package '%(pkgname)s' "
                             "dependency %(depname)s "
                             "(%(deprelation)s %(depversion)s)") % {
                                 'pkgname': pkg.name,
                                 'depname': dep.name,
                                 'deprelation': dep.relation,
                                 'depversion': dep.version
                             }
                         self._cache.op_progress.done()
                         return False
         # now check if there are conflicts against this package on
         # the existing system
         if "Conflicts" in ver.depends_list:
             for conflicts_ver_list in ver.depends_list["Conflicts"]:
                 for c_or in conflicts_ver_list:
                     if (c_or.target_pkg.name == self.pkgname
                             and c_or.target_pkg.architecture == debarch):
                         if apt_pkg.check_dep(debver, c_or.comp_type,
                                              c_or.target_ver):
                             self._dbg(
                                 2, "would break (conflicts) %s" % pkg.name)
                             # TRANSLATORS: the first '%s' is the package
                             # that conflicts, the second the packagename
                             # that it conflicts with (so the name of the
                             # deb the user tries to install), the third is
                             # the relation (e.g. >=) and the last is the
                             # version for the relation
                             self._failure_string += _(
                                 "Breaks existing package '%(pkgname)s' "
                                 "conflict: %(targetpkg)s "
                                 "(%(comptype)s %(targetver)s)") % {
                                     'pkgname': pkg.name,
                                     'targetpkg': c_or.target_pkg.name,
                                     'comptype': c_or.comp_type,
                                     'targetver': c_or.target_ver
                                 }
                             self._cache.op_progress.done()
                             return False
                     if (c_or.target_pkg.name in provides
                             and self.pkgname != pkg.name):
                         self._dbg(2,
                                   "would break (conflicts) %s" % provides)
                         self._failure_string += _(
                             "Breaks existing package '%(pkgname)s' "
                             "that conflict: '%(targetpkg)s'. But the "
                             "'%(debfile)s' provides it via: "
                             "'%(provides)s'") % {
                                 'provides': ",".join(provides),
                                 'debfile': self.filename,
                                 'targetpkg': c_or.target_pkg.name,
                                 'pkgname': pkg.name
                             }
                         self._cache.op_progress.done()
                         return False
     self._cache.op_progress.done()
     return True
 def check_req_version(version_str, req_version):
     print("[buildpkg::get_pkgversion_to_install] Test '{} {} {}'".format(
         version_str, req_version[0], req_version[1]))
     return apt_pkg.check_dep(version_str, req_version[0], req_version[1])
Beispiel #23
0
    def test_check_dep(self):
        "dependencies: Test apt_pkg.check_dep()"
        self.assertFalse(apt_pkg.check_dep("1", "<<", "0"))
        self.assertFalse(apt_pkg.check_dep("1", "<<", "1"))
        self.assertTrue(apt_pkg.check_dep("1", "<<", "2"))

        self.assertFalse(apt_pkg.check_dep("1", "<", "0"))
        self.assertFalse(apt_pkg.check_dep("1", "<", "1"))
        self.assertTrue(apt_pkg.check_dep("1", "<", "2"))

        self.assertFalse(apt_pkg.check_dep("1", "<=", "0"))
        self.assertTrue(apt_pkg.check_dep("1", "<=", "1"))
        self.assertTrue(apt_pkg.check_dep("1", "<=", "2"))

        self.assertFalse(apt_pkg.check_dep("0", "=", "1"))
        self.assertTrue(apt_pkg.check_dep("1", "=", "1"))
        self.assertFalse(apt_pkg.check_dep("2", "=", "1"))

        self.assertFalse(apt_pkg.check_dep("0", ">=", "1"))
        self.assertTrue(apt_pkg.check_dep("1", ">=", "1"))
        self.assertTrue(apt_pkg.check_dep("2", ">=", "1"))

        self.assertFalse(apt_pkg.check_dep("0", ">", "1"))
        self.assertFalse(apt_pkg.check_dep("1", ">", "1"))
        self.assertTrue(apt_pkg.check_dep("2", ">", "1"))

        self.assertFalse(apt_pkg.check_dep("0", ">>", "1"))
        self.assertFalse(apt_pkg.check_dep("1", ">>", "1"))
        self.assertTrue(apt_pkg.check_dep("2", ">>", "1"))
Beispiel #24
0
 def check_breaks_existing_packages(self):
     """
     check if installing the package would break exsisting
     package on the system, e.g. system has:
     smc depends on smc-data (= 1.4)
     and user tries to installs smc-data 1.6
     """
     # show progress information as this step may take some time
     size = float(len(self._cache))
     steps = max(int(size / 50), 1)
     debver = self._sections["Version"]
     debarch = self._sections["Architecture"]
     # store what we provide so that we can later check against that
     provides = [x[0][0] for x in self.provides]
     for (i, pkg) in enumerate(self._cache):
         if i % steps == 0:
             self._cache.op_progress.update(float(i) / size * 100.0)
         if not pkg.is_installed:
             continue
         # check if the exising dependencies are still satisfied
         # with the package
         ver = pkg._pkg.current_ver
         for dep_or in pkg.installed.dependencies:
             for dep in dep_or.or_dependencies:
                 if dep.name == self.pkgname:
                     if not apt_pkg.check_dep(
                             debver, dep.relation, dep.version):
                         self._dbg(2, "would break (depends) %s" % pkg.name)
                         # TRANSLATORS: the first '%s' is the package that
                         # breaks, the second the dependency that makes it
                         # break, the third the relation (e.g. >=) and the
                         # latest the version for the releation
                         self._failure_string += _(
                             "Breaks existing package '%(pkgname)s' "
                             "dependency %(depname)s "
                             "(%(deprelation)s %(depversion)s)") % {
                                 'pkgname': pkg.name,
                                 'depname': dep.name,
                                 'deprelation': dep.relation,
                                 'depversion': dep.version}
                         self._cache.op_progress.done()
                         return False
         # now check if there are conflicts against this package on
         # the existing system
         if "Conflicts" in ver.depends_list:
             for conflicts_ver_list in ver.depends_list["Conflicts"]:
                 for c_or in conflicts_ver_list:
                     if (c_or.target_pkg.name == self.pkgname and
                             c_or.target_pkg.architecture == debarch):
                         if apt_pkg.check_dep(
                                 debver, c_or.comp_type, c_or.target_ver):
                             self._dbg(
                                 2, "would break (conflicts) %s" % pkg.name)
                             # TRANSLATORS: the first '%s' is the package
                             # that conflicts, the second the packagename
                             # that it conflicts with (so the name of the
                             # deb the user tries to install), the third is
                             # the relation (e.g. >=) and the last is the
                             # version for the relation
                             self._failure_string += _(
                                 "Breaks existing package '%(pkgname)s' "
                                 "conflict: %(targetpkg)s "
                                 "(%(comptype)s %(targetver)s)") % {
                                     'pkgname': pkg.name,
                                     'targetpkg': c_or.target_pkg.name,
                                     'comptype': c_or.comp_type,
                                     'targetver': c_or.target_ver}
                             self._cache.op_progress.done()
                             return False
                     if (c_or.target_pkg.name in provides and
                             self.pkgname != pkg.name):
                         self._dbg(
                             2, "would break (conflicts) %s" % provides)
                         self._failure_string += _(
                             "Breaks existing package '%(pkgname)s' "
                             "that conflict: '%(targetpkg)s'. But the "
                             "'%(debfile)s' provides it via: "
                             "'%(provides)s'") % {
                                 'provides': ",".join(provides),
                                 'debfile': self.filename,
                                 'targetpkg': c_or.target_pkg.name,
                                 'pkgname': pkg.name}
                         self._cache.op_progress.done()
                         return False
     self._cache.op_progress.done()
     return True
Beispiel #25
0
def get_dependency_solvers(block,
                           binaries_s_a,
                           provides_s_a,
                           *,
                           build_depends=False,
                           empty_set=frozenset()):
    """Find the packages which satisfy a dependency block

    This method returns the list of packages which satisfy a dependency
    block (as returned by apt_pkg.parse_depends) in a package table
    for a given suite and architecture (a la self.binaries[suite][arch])

    It can also handle build-dependency relations if the named parameter
    "build_depends" is set to True.  In this case, block should be based
    on the return value from apt_pkg.parse_src_depends.

    :param block: The dependency block as parsed by apt_pkg.parse_depends (or apt_pkg.parse_src_depends
      if the "build_depends" is True)
    :param binaries_s_a: A dict mapping package names to the relevant BinaryPackage
    :param provides_s_a: A dict mapping package names to their providers (as generated by parse_provides)
    :param build_depends: If True, treat the "block" parameter as a build-dependency relation rather than
      a regular dependency relation.
    :param empty_set: Internal implementation detail / optimisation
    :return a list of package names solving the relation
    """
    packages = []

    # for every package, version and operation in the block
    for name, version, op in block:
        if ":" in name:
            name, archqual = name.split(":", 1)
        else:
            archqual = None

        # look for the package in unstable
        if name in binaries_s_a:
            package = binaries_s_a[name]
            # check the versioned dependency and architecture qualifier
            # (if present)
            if (op == '' and version == '') or apt_pkg.check_dep(
                    package.version, op, version):
                if archqual is None:
                    packages.append(package)
                elif build_depends and archqual == 'native':
                    # Multi-arch handling for build-dependencies
                    # - :native is ok always (since dpkg 1.19.1)
                    packages.append(package)

                # Multi-arch handling for both build-dependencies and regular dependencies
                # - :any is ok iff the target has "M-A: allowed"
                if archqual == 'any' and package.multi_arch == 'allowed':
                    packages.append(package)

        # look for the package in the virtual packages list and loop on them
        for prov, prov_version in provides_s_a.get(name, empty_set):
            assert prov in binaries_s_a
            # A provides only satisfies:
            # - an unversioned dependency (per Policy Manual §7.5)
            # - a dependency without an architecture qualifier
            #   (per analysis of apt code)
            if archqual is not None:
                # Punt on this case - these days, APT and dpkg might actually agree on
                # this.
                continue
            if (op == '' and version == '') or \
                    (prov_version != '' and apt_pkg.check_dep(prov_version, op, version)):
                packages.append(binaries_s_a[prov])

    return packages