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
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
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
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
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
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)
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
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
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 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
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
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"))
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]
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])
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
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