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


Reply via email to