slot_operator_replace_installed: check available
authorZac Medico <zmedico@gentoo.org>
Thu, 14 Feb 2013 04:45:40 +0000 (20:45 -0800)
committerZac Medico <zmedico@gentoo.org>
Thu, 14 Feb 2013 04:45:40 +0000 (20:45 -0800)
This fixes a case where it could try to pull in an unavailable SLOT.

pym/_emerge/depgraph.py
pym/portage/tests/resolver/test_regular_slot_change_without_revbump.py [new file with mode: 0644]

index e0ea895a76e74ae012e10a06fb51767682fb7a63..bab1c32aa362d905ea4952bdae5bd26c2f9c14da 100644 (file)
@@ -1104,7 +1104,9 @@ class depgraph(object):
                # trigger replacement of installed packages if necessary
                reinstalls = set()
                if child.installed:
-                       reinstalls.add((child.root, child.slot_atom))
+                       replacement_atom = self._replace_installed_atom(child)
+                       if replacement_atom is not None:
+                               reinstalls.add((child.root, replacement_atom))
                if reinstalls:
                        config.setdefault("slot_operator_replace_installed",
                                set()).update(reinstalls)
@@ -1145,9 +1147,13 @@ class depgraph(object):
                # trigger replacement of installed packages if necessary
                abi_reinstalls = set()
                if dep.parent.installed:
-                       abi_reinstalls.add((dep.parent.root, dep.parent.slot_atom))
+                       replacement_atom = self._replace_installed_atom(dep.parent)
+                       if replacement_atom is not None:
+                               abi_reinstalls.add((dep.parent.root, replacement_atom))
                if new_child_slot is None and child.installed:
-                       abi_reinstalls.add((child.root, child.slot_atom))
+                       replacement_atom = self._replace_installed_atom(child)
+                       if replacement_atom is not None:
+                               abi_reinstalls.add((child.root, replacement_atom))
                if abi_reinstalls:
                        config.setdefault("slot_operator_replace_installed",
                                set()).update(abi_reinstalls)
@@ -1363,7 +1369,9 @@ class depgraph(object):
                # trigger replacement of installed packages if necessary
                reinstalls = set()
                if parent.installed:
-                       reinstalls.add((parent.root, parent.slot_atom))
+                       replacement_atom = self._replace_installed_atom(parent)
+                       if replacement_atom is not None:
+                               reinstalls.add((parent.root, replacement_atom))
                if reinstalls:
                        config.setdefault("slot_operator_replace_installed",
                                set()).update(reinstalls)
@@ -1421,6 +1429,37 @@ class depgraph(object):
                                        continue
                        yield pkg
 
+       def _replace_installed_atom(self, inst_pkg):
+               """
+               Given an installed package, generate an atom suitable for
+               slot_operator_replace_installed backtracking info. The replacement
+               SLOT may differ from the installed SLOT, so first search by cpv.
+               """
+               built_pkgs = []
+               for pkg in self._iter_similar_available(inst_pkg,
+                       Atom("=%s" % inst_pkg.cpv)):
+                       if not pkg.built:
+                               return pkg.slot_atom
+                       elif not pkg.installed:
+                               # avoid using SLOT from a built instance
+                               built_pkgs.append(pkg)
+
+               for pkg in self._iter_similar_available(inst_pkg, inst_pkg.slot_atom):
+                       if not pkg.built:
+                               return pkg.slot_atom
+                       elif not pkg.installed:
+                               # avoid using SLOT from a built instance
+                               built_pkgs.append(pkg)
+
+               if built_pkgs:
+                       best_version = None
+                       for pkg in built_pkgs:
+                               if best_version is None or pkg > best_version:
+                                       best_version = pkg
+                       return best_version.slot_atom
+
+               return None
+
        def _slot_operator_trigger_reinstalls(self):
                """
                Search for packages with slot-operator deps on older slots, and schedule
diff --git a/pym/portage/tests/resolver/test_regular_slot_change_without_revbump.py b/pym/portage/tests/resolver/test_regular_slot_change_without_revbump.py
new file mode 100644 (file)
index 0000000..415277b
--- /dev/null
@@ -0,0 +1,59 @@
+# Copyright 2013 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 RegularSlotChangeWithoutRevBumpTestCase(TestCase):
+
+       def testRegularSlotChangeWithoutRevBumpTestCase(self):
+
+               ebuilds = {
+                       "dev-libs/boost-1.52.0" : {
+                               "SLOT": "0"
+                       },
+                       "app-office/libreoffice-4.0.0.2" : {
+                               "EAPI": "5",
+                               "DEPEND": ">=dev-libs/boost-1.46:=",
+                               "RDEPEND": ">=dev-libs/boost-1.46:=",
+                       },
+               }
+
+               binpkgs = {
+                       "dev-libs/boost-1.52.0" : {
+                               "SLOT": "1.52"
+                       },
+               }
+
+               installed = {
+                       "dev-libs/boost-1.52.0" : {
+                               "SLOT": "1.52"
+                       },
+               }
+
+               world = []
+
+               test_cases = (
+                       # Test that @__auto_slot_operator_replace_installed__
+                       # pulls in the available slot, even though it's
+                       # different from the installed slot (0 instead of 1.52).
+                       ResolverPlaygroundTestCase(
+                               ["app-office/libreoffice"],
+                               options = {"--oneshot": True, "--usepkg": True},
+                               success = True,
+                               mergelist = [
+                                       'dev-libs/boost-1.52.0',
+                                       'app-office/libreoffice-4.0.0.2'
+                               ]
+                       ),
+               )
+
+               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()