Prefer to install a new package rather than to downgrade an installed package. If the installed package should be downgraded due to it being masked, then allow the downgrade.
Bug: https://bugs.gentoo.org/635540 --- pym/portage/dep/dep_check.py | 11 ++- .../tests/resolver/test_or_downgrade_installed.py | 97 ++++++++++++++++++++++ 2 files changed, 107 insertions(+), 1 deletion(-) create mode 100644 pym/portage/tests/resolver/test_or_downgrade_installed.py diff --git a/pym/portage/dep/dep_check.py b/pym/portage/dep/dep_check.py index 35caecc74..2c69c1c48 100644 --- a/pym/portage/dep/dep_check.py +++ b/pym/portage/dep/dep_check.py @@ -323,8 +323,10 @@ def dep_zapdeps(unreduced, reduced, myroot, use_binaries=0, trees=None): want_update_pkg = trees[myroot].get("want_update_pkg") downgrade_probe = trees[myroot].get("downgrade_probe") vardb = None + vardb_match_pkgs = None if "vartree" in trees[myroot]: vardb = trees[myroot]["vartree"].dbapi + vardb_match_pkgs = getattr(vardb, 'match_pkgs', None) if use_binaries: mydbapi = trees[myroot]["bintree"].dbapi else: @@ -355,6 +357,7 @@ def dep_zapdeps(unreduced, reduced, myroot, use_binaries=0, trees=None): all_use_satisfied = True all_use_unmasked = True conflict_downgrade = False + installed_downgrade = False slot_atoms = collections.defaultdict(list) slot_map = {} cp_map = {} @@ -419,6 +422,12 @@ def dep_zapdeps(unreduced, reduced, myroot, use_binaries=0, trees=None): avail_pkg = avail_pkg_use avail_slot = Atom("%s:%s" % (atom.cp, avail_pkg.slot)) + if vardb_match_pkgs is not None: + inst_pkg = vardb_match_pkgs(avail_slot) + if (inst_pkg and avail_pkg < inst_pkg[-1] and + not downgrade_probe(inst_pkg[-1])): + installed_downgrade = True + slot_map[avail_slot] = avail_pkg slot_atoms[avail_slot].append(atom) highest_cpv = cp_map.get(avail_pkg.cp) @@ -487,7 +496,7 @@ def dep_zapdeps(unreduced, reduced, myroot, use_binaries=0, trees=None): unsat_use_installed.append(this_choice) else: unsat_use_non_installed.append(this_choice) - elif conflict_downgrade: + elif conflict_downgrade or installed_downgrade: other.append(this_choice) else: all_in_graph = True diff --git a/pym/portage/tests/resolver/test_or_downgrade_installed.py b/pym/portage/tests/resolver/test_or_downgrade_installed.py new file mode 100644 index 000000000..22307a5bc --- /dev/null +++ b/pym/portage/tests/resolver/test_or_downgrade_installed.py @@ -0,0 +1,97 @@ +# Copyright 2017 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 OrDowngradeInstalledTestCase(TestCase): + + def testOrDowngradeInstalled(self): + ebuilds = { + 'net-misc/foo-1': { + 'EAPI': '6', + 'RDEPEND': '|| ( sys-libs/glibc[rpc(-)] net-libs/libtirpc )' + }, + 'net-libs/libtirpc-1': { + 'EAPI': '6', + }, + 'sys-libs/glibc-2.26': { + 'EAPI': '6', + 'IUSE': '' + }, + 'sys-libs/glibc-2.24': { + 'EAPI': '6', + 'IUSE': '+rpc' + }, + } + + installed = { + 'sys-libs/glibc-2.26': { + 'EAPI': '6', + 'IUSE': '' + }, + } + + world = ['sys-libs/glibc'] + + test_cases = ( + # Test bug 635540, where we need to install libtirpc + # rather than downgrade glibc. + ResolverPlaygroundTestCase( + ['net-misc/foo'], + success=True, + mergelist=[ + 'net-libs/libtirpc-1', + 'net-misc/foo-1', + ], + ), + ) + + playground = ResolverPlayground(debug=False, + ebuilds=ebuilds, installed=installed, world=world) + + 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.debug = False + playground.cleanup() + + # In some cases it's necessary to downgrade due to + # the installed package being masked (glibc is a + # not an ideal example because it's usually not + # practical to downgrade it). + user_config = { + "package.mask" : ( + ">=sys-libs/glibc-2.26", + ), + } + + test_cases = ( + ResolverPlaygroundTestCase( + ['net-misc/foo'], + success=True, + mergelist=[ + 'sys-libs/glibc-2.24', + 'net-misc/foo-1', + ], + ), + ) + + playground = ResolverPlayground(debug=False, + ebuilds=ebuilds, installed=installed, world=world, + user_config=user_config) + + 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.debug = False + playground.cleanup() -- 2.13.5