summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--pym/_emerge/depgraph.py109
-rw-r--r--pym/portage/tests/resolver/test_slot_abi_downgrade.py225
2 files changed, 298 insertions, 36 deletions
diff --git a/pym/_emerge/depgraph.py b/pym/_emerge/depgraph.py
index 480cb902a..f819aef3d 100644
--- a/pym/_emerge/depgraph.py
+++ b/pym/_emerge/depgraph.py
@@ -24,7 +24,8 @@ from portage.dep import Atom, best_match_to_list, extract_affecting_use, \
_repo_separator
from portage.dep._slot_abi import ignore_built_slot_abi_deps
from portage.eapi import eapi_has_strong_blocks, eapi_has_required_use
-from portage.exception import InvalidAtom, InvalidDependString, PortageException
+from portage.exception import (InvalidAtom, InvalidDependString,
+ PackageNotFound, PortageException)
from portage.output import colorize, create_color_func, \
darkgreen, green
bad = create_color_func("BAD")
@@ -1047,6 +1048,7 @@ class depgraph(object):
return None
debug = "--debug" in self._frozen_config.myopts
+ want_downgrade = None
for replacement_parent in self._iter_similar_available(dep.parent,
dep.parent.slot_atom):
@@ -1087,10 +1089,13 @@ class depgraph(object):
if pkg.slot != dep.child.slot:
continue
if pkg < dep.child:
+ if want_downgrade is None:
+ want_downgrade = self._downgrade_probe(dep.child)
# be careful not to trigger a rebuild when
# the only version available with a
# different slot_abi is an older version
- continue
+ if not want_downgrade:
+ continue
if debug:
msg = []
@@ -1122,12 +1127,33 @@ class depgraph(object):
return None
+ def _downgrade_probe(self, pkg):
+ """
+ Detect cases where a downgrade of the given package is considered
+ desirable due to the current version being masked or unavailable.
+ """
+ available_pkg = None
+ for available_pkg in self._iter_similar_available(pkg,
+ pkg.slot_atom):
+ if available_pkg >= pkg:
+ # There's an available package of the same or higher
+ # version, so downgrade seems undesirable.
+ return False
+
+ return available_pkg is not None
+
def _iter_similar_available(self, graph_pkg, atom):
"""
Given a package that's in the graph, do a rough check to
see if a similar package is available to install. The given
graph_pkg itself may be yielded only if it's not installed.
"""
+
+ usepkgonly = "--usepkgonly" in self._frozen_config.myopts
+ useoldpkg_atoms = self._frozen_config.useoldpkg_atoms
+ use_ebuild_visibility = self._frozen_config.myopts.get(
+ '--use-ebuild-visibility', 'n') != 'n'
+
for pkg in self._iter_match_pkgs_any(
graph_pkg.root_config, atom):
if pkg.cp != graph_pkg.cp:
@@ -1142,6 +1168,14 @@ class depgraph(object):
continue
if not self._pkg_visibility_check(pkg):
continue
+ if pkg.built:
+ if self._equiv_binary_installed(pkg):
+ continue
+ if not (not use_ebuild_visibility and
+ (usepkgonly or useoldpkg_atoms.findAtomForPackage(
+ pkg, modified_use=self._pkg_use_enabled(pkg)))) and \
+ not self._equiv_ebuild_visible(pkg):
+ continue
yield pkg
def _slot_abi_trigger_reinstalls(self):
@@ -3811,6 +3845,38 @@ class depgraph(object):
return not arg
+ def _equiv_ebuild_visible(self, pkg, autounmask_level=None):
+ try:
+ pkg_eb = self._pkg(
+ pkg.cpv, "ebuild", pkg.root_config, myrepo=pkg.repo)
+ except portage.exception.PackageNotFound:
+ pkg_eb_visible = False
+ for pkg_eb in self._iter_match_pkgs(pkg.root_config,
+ "ebuild", Atom("=%s" % (pkg.cpv,))):
+ if self._pkg_visibility_check(pkg_eb, autounmask_level):
+ pkg_eb_visible = True
+ break
+ if not pkg_eb_visible:
+ return False
+ else:
+ if not self._pkg_visibility_check(pkg_eb, autounmask_level):
+ return False
+
+ return True
+
+ def _equiv_binary_installed(self, pkg):
+ build_time = pkg.metadata.get('BUILD_TIME')
+ if not build_time:
+ return False
+
+ try:
+ inst_pkg = self._pkg(pkg.cpv, "installed",
+ pkg.root_config, installed=True)
+ except PackageNotFound:
+ return False
+
+ return build_time == inst_pkg.metadata.get('BUILD_TIME')
+
class _AutounmaskLevel(object):
__slots__ = ("allow_use_changes", "allow_unstable_keywords", "allow_license_changes", \
"allow_missing_keywords", "allow_unmasks")
@@ -4241,22 +4307,9 @@ class depgraph(object):
if not use_ebuild_visibility and (usepkgonly or useoldpkg):
if pkg.installed and pkg.masks:
continue
- else:
- try:
- pkg_eb = self._pkg(
- pkg.cpv, "ebuild", root_config, myrepo=pkg.repo)
- except portage.exception.PackageNotFound:
- pkg_eb_visible = False
- for pkg_eb in self._iter_match_pkgs(pkg.root_config,
- "ebuild", Atom("=%s" % (pkg.cpv,))):
- if self._pkg_visibility_check(pkg_eb, autounmask_level):
- pkg_eb_visible = True
- break
- if not pkg_eb_visible:
- continue
- else:
- if not self._pkg_visibility_check(pkg_eb, autounmask_level):
- continue
+ elif not self._equiv_ebuild_visible(pkg,
+ autounmask_level=autounmask_level):
+ continue
# Calculation of USE for unbuilt ebuilds is relatively
# expensive, so it is only performed lazily, after the
@@ -7137,24 +7190,8 @@ class _dep_check_composite_db(dbapi):
if not avoid_update:
if not use_ebuild_visibility and usepkgonly:
return False
- else:
- try:
- pkg_eb = self._depgraph._pkg(
- pkg.cpv, "ebuild", pkg.root_config,
- myrepo=pkg.repo)
- except portage.exception.PackageNotFound:
- pkg_eb_visible = False
- for pkg_eb in self._depgraph._iter_match_pkgs(
- pkg.root_config, "ebuild",
- Atom("=%s" % (pkg.cpv,))):
- if self._depgraph._pkg_visibility_check(pkg_eb):
- pkg_eb_visible = True
- break
- if not pkg_eb_visible:
- return False
- else:
- if not self._depgraph._pkg_visibility_check(pkg_eb):
- return False
+ elif not self._depgraph._equiv_ebuild_visible(pkg):
+ return False
in_graph = self._depgraph._dynamic_config._slot_pkg_map[
self._root].get(pkg.slot_atom)
diff --git a/pym/portage/tests/resolver/test_slot_abi_downgrade.py b/pym/portage/tests/resolver/test_slot_abi_downgrade.py
new file mode 100644
index 000000000..45a7555c2
--- /dev/null
+++ b/pym/portage/tests/resolver/test_slot_abi_downgrade.py
@@ -0,0 +1,225 @@
+# Copyright 2012 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from portage.tests import TestCase
+from portage.tests.resolver.ResolverPlayground import (ResolverPlayground,
+ ResolverPlaygroundTestCase)
+
+class SlotAbiDowngradeTestCase(TestCase):
+
+ def __init__(self, *args, **kwargs):
+ super(SlotAbiDowngradeTestCase, self).__init__(*args, **kwargs)
+
+ def testSubSlot(self):
+ ebuilds = {
+ "dev-libs/icu-4.8" : {
+ "EAPI": "4-slot-abi",
+ "SLOT": "0/48"
+ },
+ "dev-libs/libxml2-2.7.8" : {
+ "EAPI": "4-slot-abi",
+ "DEPEND": "dev-libs/icu:=",
+ "RDEPEND": "dev-libs/icu:="
+ },
+ }
+ binpkgs = {
+ "dev-libs/icu-49" : {
+ "EAPI": "4-slot-abi",
+ "SLOT": "0/49"
+ },
+ "dev-libs/icu-4.8" : {
+ "EAPI": "4-slot-abi",
+ "SLOT": "0/48"
+ },
+ "dev-libs/libxml2-2.7.8" : {
+ "EAPI": "4-slot-abi",
+ "DEPEND": "dev-libs/icu:0/49=",
+ "RDEPEND": "dev-libs/icu:0/49="
+ },
+ }
+ installed = {
+ "dev-libs/icu-49" : {
+ "EAPI": "4-slot-abi",
+ "SLOT": "0/49"
+ },
+ "dev-libs/libxml2-2.7.8" : {
+ "EAPI": "4-slot-abi",
+ "DEPEND": "dev-libs/icu:0/49=",
+ "RDEPEND": "dev-libs/icu:0/49="
+ },
+ }
+
+ world = ["dev-libs/libxml2"]
+
+ test_cases = (
+
+ ResolverPlaygroundTestCase(
+ ["dev-libs/icu"],
+ options = {"--oneshot": True},
+ success = True,
+ mergelist = ["dev-libs/icu-4.8", "dev-libs/libxml2-2.7.8" ]),
+
+ ResolverPlaygroundTestCase(
+ ["dev-libs/icu"],
+ options = {"--oneshot": True, "--ignore-built-slot-abi-deps": "y"},
+ success = True,
+ mergelist = ["dev-libs/icu-4.8"]),
+
+ ResolverPlaygroundTestCase(
+ ["dev-libs/icu"],
+ options = {"--oneshot": True, "--usepkg": True},
+ success = True,
+ mergelist = ["[binary]dev-libs/icu-4.8", "dev-libs/libxml2-2.7.8" ]),
+
+ ResolverPlaygroundTestCase(
+ ["dev-libs/icu"],
+ options = {"--oneshot": True, "--usepkgonly": True},
+ success = True,
+ mergelist = ["[binary]dev-libs/icu-49"]),
+
+ ResolverPlaygroundTestCase(
+ ["@world"],
+ options = {"--update": True, "--deep": True},
+ success = True,
+ mergelist = ["dev-libs/icu-4.8", "dev-libs/libxml2-2.7.8" ]),
+
+ ResolverPlaygroundTestCase(
+ ["@world"],
+ options = {"--update": True, "--deep": True, "--ignore-built-slot-abi-deps": "y"},
+ success = True,
+ mergelist = ["dev-libs/icu-4.8"]),
+
+ ResolverPlaygroundTestCase(
+ ["@world"],
+ options = {"--update": True, "--deep": True, "--usepkg": True},
+ success = True,
+ mergelist = ["[binary]dev-libs/icu-4.8", "dev-libs/libxml2-2.7.8" ]),
+
+ ResolverPlaygroundTestCase(
+ ["@world"],
+ options = {"--update": True, "--deep": True, "--usepkgonly": True},
+ success = True,
+ mergelist = []),
+
+ )
+
+ playground = ResolverPlayground(ebuilds=ebuilds, binpkgs=binpkgs,
+ installed=installed, world=world, debug=False)
+ try:
+ for test_case in test_cases:
+ playground.run_TestCase(test_case)
+ self.assertEqual(test_case.test_success, True, test_case.fail_msg)
+ finally:
+ playground.cleanup()
+
+ def testWholeSlotSubSlotMix(self):
+ ebuilds = {
+ "dev-libs/glib-1.2.10" : {
+ "SLOT": "1"
+ },
+ "dev-libs/glib-2.30.2" : {
+ "EAPI": "4-slot-abi",
+ "SLOT": "2/2.30"
+ },
+ "dev-libs/dbus-glib-0.98" : {
+ "EAPI": "4-slot-abi",
+ "DEPEND": "dev-libs/glib:2=",
+ "RDEPEND": "dev-libs/glib:2="
+ },
+ }
+ binpkgs = {
+ "dev-libs/glib-1.2.10" : {
+ "SLOT": "1"
+ },
+ "dev-libs/glib-2.30.2" : {
+ "EAPI": "4-slot-abi",
+ "SLOT": "2/2.30"
+ },
+ "dev-libs/glib-2.32.3" : {
+ "EAPI": "4-slot-abi",
+ "SLOT": "2/2.32"
+ },
+ "dev-libs/dbus-glib-0.98" : {
+ "EAPI": "4-slot-abi",
+ "DEPEND": "dev-libs/glib:2/2.32=",
+ "RDEPEND": "dev-libs/glib:2/2.32="
+ },
+ }
+ installed = {
+ "dev-libs/glib-1.2.10" : {
+ "EAPI": "4-slot-abi",
+ "SLOT": "1"
+ },
+ "dev-libs/glib-2.32.3" : {
+ "EAPI": "4-slot-abi",
+ "SLOT": "2/2.32"
+ },
+ "dev-libs/dbus-glib-0.98" : {
+ "EAPI": "4-slot-abi",
+ "DEPEND": "dev-libs/glib:2/2.32=",
+ "RDEPEND": "dev-libs/glib:2/2.32="
+ },
+ }
+
+ world = ["dev-libs/glib:1", "dev-libs/dbus-glib"]
+
+ test_cases = (
+
+ ResolverPlaygroundTestCase(
+ ["dev-libs/glib"],
+ options = {"--oneshot": True},
+ success = True,
+ mergelist = ["dev-libs/glib-2.30.2", "dev-libs/dbus-glib-0.98" ]),
+
+ ResolverPlaygroundTestCase(
+ ["dev-libs/glib"],
+ options = {"--oneshot": True, "--ignore-built-slot-abi-deps": "y"},
+ success = True,
+ mergelist = ["dev-libs/glib-2.30.2"]),
+
+ ResolverPlaygroundTestCase(
+ ["dev-libs/glib"],
+ options = {"--oneshot": True, "--usepkg": True},
+ success = True,
+ mergelist = ["[binary]dev-libs/glib-2.30.2", "dev-libs/dbus-glib-0.98" ]),
+
+ ResolverPlaygroundTestCase(
+ ["dev-libs/glib"],
+ options = {"--oneshot": True, "--usepkgonly": True},
+ success = True,
+ mergelist = ["[binary]dev-libs/glib-2.32.3"]),
+
+ ResolverPlaygroundTestCase(
+ ["@world"],
+ options = {"--update": True, "--deep": True},
+ success = True,
+ mergelist = ["dev-libs/glib-2.30.2", "dev-libs/dbus-glib-0.98" ]),
+
+ ResolverPlaygroundTestCase(
+ ["@world"],
+ options = {"--update": True, "--deep": True, "--ignore-built-slot-abi-deps": "y"},
+ success = True,
+ mergelist = ["dev-libs/glib-2.30.2"]),
+
+ ResolverPlaygroundTestCase(
+ ["@world"],
+ options = {"--update": True, "--deep": True, "--usepkg": True},
+ success = True,
+ mergelist = ["[binary]dev-libs/glib-2.30.2", "dev-libs/dbus-glib-0.98" ]),
+
+ ResolverPlaygroundTestCase(
+ ["@world"],
+ options = {"--update": True, "--deep": True, "--usepkgonly": True},
+ success = True,
+ mergelist = []),
+
+ )
+
+ playground = ResolverPlayground(ebuilds=ebuilds, binpkgs=binpkgs,
+ installed=installed, world=world, debug=False)
+ try:
+ for test_case in test_cases:
+ playground.run_TestCase(test_case)
+ self.assertEqual(test_case.test_success, True, test_case.fail_msg)
+ finally:
+ playground.cleanup()