diff options
-rw-r--r-- | pym/_emerge/depgraph.py | 109 | ||||
-rw-r--r-- | pym/portage/tests/resolver/test_slot_abi_downgrade.py | 225 |
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() |