Another slot operator bug (bug 486580, try 2)
authorSebastian Luther <SebastianLuther@gmx.de>
Thu, 28 Nov 2013 10:34:09 +0000 (11:34 +0100)
committerBrian Dolbec <dolsen@gentoo.org>
Sun, 1 Dec 2013 09:41:25 +0000 (01:41 -0800)
This time rebuilds are scheduled properly, but we
might still forget to install the package that caused
the rebuild.

URL: https://bugs.gentoo.org/486580

pym/_emerge/depgraph.py
pym/portage/tests/resolver/test_slot_conflict_rebuild.py

index b02d3473d9c5138e9dc62ee3a5c3a769aced7564..622d288415342a774e9436b83d39e4c185cb2974 100644 (file)
@@ -2266,6 +2266,36 @@ class depgraph(object):
                finally:
                        self._dynamic_config._autounmask = _autounmask_backup
 
+       def _ignore_dependency(self, atom, pkg, child, dep, mypriority, recurse_satisfied):
+               """
+               In some cases, dep_check will return deps that shouldn't
+               be proccessed any further, so they are identified and
+               discarded here. Try to discard as few as possible since
+               discarded dependencies reduce the amount of information
+               available for optimization of merge order.
+               Don't ignore dependencies if pkg has a slot operator dependency on the child
+               and the child has changed slot/sub_slot.
+               """
+               slot_operator_rebuild = False
+               if atom.slot_operator == '=' and \
+                       (pkg.root, pkg.slot_atom) in self._dynamic_config._slot_operator_replace_installed and \
+                       mypriority.satisfied and \
+                       mypriority.satisfied is not child and \
+                       mypriority.satisfied.installed and \
+                       not child.installed and \
+                       (child.slot != mypriority.satisfied.slot or child.sub_slot != mypriority.satisfied.sub_slot):
+                       slot_operator_rebuild = True
+
+               return not atom.blocker and \
+                       not recurse_satisfied and \
+                       mypriority.satisfied and \
+                       mypriority.satisfied.visible and \
+                       dep.child is not None and \
+                       not dep.child.installed and \
+                       self._dynamic_config._slot_pkg_map[dep.child.root].get(
+                       dep.child.slot_atom) is None and \
+                       not slot_operator_rebuild
+
        def _wrapped_add_pkg_dep_string(self, pkg, dep_root, dep_priority,
                dep_string, allow_unsatisfied):
                depth = pkg.depth + 1
@@ -2355,14 +2385,7 @@ class depgraph(object):
                        # discarded dependencies reduce the amount of information
                        # available for optimization of merge order.
                        ignored = False
-                       if not atom.blocker and \
-                               not recurse_satisfied and \
-                               mypriority.satisfied and \
-                               mypriority.satisfied.visible and \
-                               dep.child is not None and \
-                               not dep.child.installed and \
-                               self._dynamic_config._slot_pkg_map[dep.child.root].get(
-                               dep.child.slot_atom) is None:
+                       if self._ignore_dependency(atom, pkg, child, dep, mypriority, recurse_satisfied):
                                myarg = None
                                try:
                                        myarg = next(self._iter_atoms_for_pkg(dep.child), None)
@@ -2465,14 +2488,7 @@ class depgraph(object):
                                        collapsed_parent=pkg, collapsed_priority=dep_priority)
 
                                ignored = False
-                               if not atom.blocker and \
-                                       not recurse_satisfied and \
-                                       mypriority.satisfied and \
-                                       mypriority.satisfied.visible and \
-                                       dep.child is not None and \
-                                       not dep.child.installed and \
-                                       self._dynamic_config._slot_pkg_map[dep.child.root].get(
-                                       dep.child.slot_atom) is None:
+                               if self._ignore_dependency(atom, pkg, child, dep, mypriority, recurse_satisfied):
                                        myarg = None
                                        try:
                                                myarg = next(self._iter_atoms_for_pkg(dep.child), None)
index 74f5cc146c09d50550420e49d427a0d1156565fe..e3c517d0cc5247ee99ddafe534c3a39f26ed44ee 100644 (file)
@@ -181,6 +181,69 @@ class SlotConflictRebuildTestCase(TestCase):
                finally:
                        playground.cleanup()
 
+       def testSlotConflictForgottenChild(self):
+               """
+               Similar to testSlotConflictMassRebuild above, but this time the rebuilds are scheduled,
+               but the package causing the rebuild (the child) is not installed.
+               """
+               ebuilds = {
+
+                       "app-misc/A-2" : {
+                               "EAPI": "5",
+                               "DEPEND": "app-misc/B:= app-misc/C",
+                               "RDEPEND": "app-misc/B:= app-misc/C",
+                       },
+
+                       "app-misc/B-2" : {
+                               "EAPI": "5",
+                               "SLOT": "2"
+                       },
+
+                       "app-misc/C-1": {
+                               "EAPI": "5",
+                               "DEPEND": "app-misc/B:=",
+                               "RDEPEND": "app-misc/B:="
+                       },
+               }
+
+               installed = {
+                       "app-misc/A-1" : {
+                               "EAPI": "5",
+                               "DEPEND": "app-misc/B:1/1= app-misc/C",
+                               "RDEPEND": "app-misc/B:1/1= app-misc/C",
+                       },
+
+                       "app-misc/B-1" : {
+                               "EAPI": "5",
+                               "SLOT": "1"
+                       },
+
+                       "app-misc/C-1": {
+                               "EAPI": "5",
+                               "DEPEND": "app-misc/B:1/1=",
+                               "RDEPEND": "app-misc/B:1/1="
+                       },
+               }
+
+               test_cases = (
+                       ResolverPlaygroundTestCase(
+                               ["app-misc/A"],
+                               success = True,
+                               mergelist = ['app-misc/B-2', 'app-misc/C-1', 'app-misc/A-2']),
+               )
+
+               world = []
+
+               playground = ResolverPlayground(ebuilds=ebuilds,
+                       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 testSlotConflictDepChange(self):
                """
                Bug 490362