Fix _complete_graph to trigger rebuilds of parent packages when they
pull in installed packages that had already been scheduled for rebuild
by the previous calculation.

X-Gentoo-bug: 614390
X-Gentoo-bug-url: https://bugs.gentoo.org/show_bug.cgi?id=614390
---
 pym/_emerge/depgraph.py                            |  15 +++
 .../resolver/test_slot_operator_complete_graph.py  | 141 +++++++++++++++++++++
 2 files changed, 156 insertions(+)
 create mode 100644 
pym/portage/tests/resolver/test_slot_operator_complete_graph.py

diff --git a/pym/_emerge/depgraph.py b/pym/_emerge/depgraph.py
index 04e724d..8a614c4 100644
--- a/pym/_emerge/depgraph.py
+++ b/pym/_emerge/depgraph.py
@@ -6649,6 +6649,21 @@ class depgraph(object):
                                # will be appropriately reported as a slot 
collision
                                # (possibly solvable via backtracking).
                                pkg = matches[-1] # highest match
+
+                               if (self._dynamic_config._allow_backtracking and
+                                       not self._want_installed_pkg(pkg) and 
(dep.atom.soname or (
+                                       dep.atom.package and 
dep.atom.slot_operator_built))):
+                                       # If pkg was already scheduled for 
rebuild by the previous
+                                       # calculation, then pulling in the 
installed instance will
+                                       # trigger a slot conflict that may go 
unsolved. Therefore,
+                                       # trigger a rebuild of the parent if 
appropriate.
+                                       dep.child = pkg
+                                       new_dep = 
self._slot_operator_update_probe(dep)
+                                       if new_dep is not None:
+                                               
self._slot_operator_update_backtrack(
+                                                       dep, new_dep=new_dep)
+                                               continue
+
                                if not self._add_pkg(pkg, dep):
                                        return 0
                                if not 
self._create_graph(allow_unsatisfied=True):
diff --git a/pym/portage/tests/resolver/test_slot_operator_complete_graph.py 
b/pym/portage/tests/resolver/test_slot_operator_complete_graph.py
new file mode 100644
index 0000000..1d59bce
--- /dev/null
+++ b/pym/portage/tests/resolver/test_slot_operator_complete_graph.py
@@ -0,0 +1,141 @@
+# 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 SlotOperatorCompleteGraphTestCase(TestCase):
+
+       def testSlotOperatorCompleteGraph(self):
+
+               ebuilds = {
+                       "app-misc/meta-pkg-2" : {
+                               "EAPI": "6",
+                               "DEPEND": "=app-misc/B-2 =app-misc/C-1  
=app-misc/D-1 =dev-libs/foo-2",
+                               "RDEPEND": "=app-misc/B-2 =app-misc/C-1 
=app-misc/D-1 =dev-libs/foo-2",
+                       },
+
+                       "app-misc/meta-pkg-1" : {
+                               "EAPI": "6",
+                               "DEPEND": "=app-misc/B-1 =app-misc/C-1  
=app-misc/D-1 =dev-libs/foo-1",
+                               "RDEPEND": "=app-misc/B-1 =app-misc/C-1 
=app-misc/D-1 =dev-libs/foo-1",
+                       },
+
+                       "app-misc/B-1" : {
+                               "EAPI": "6",
+                               "DEPEND": "dev-libs/foo:=",
+                               "RDEPEND": "dev-libs/foo:=",
+                       },
+
+                       "app-misc/B-2" : {
+                               "EAPI": "6",
+                               "DEPEND": "dev-libs/foo:=",
+                               "RDEPEND": "dev-libs/foo:=",
+                       },
+
+                       "app-misc/C-1" : {
+                               "EAPI": "6",
+                               "DEPEND": "dev-libs/foo:= app-misc/B",
+                               "RDEPEND": "dev-libs/foo:= app-misc/B",
+                       },
+
+                       "app-misc/C-2" : {
+                               "EAPI": "6",
+                               "DEPEND": "dev-libs/foo:= app-misc/B",
+                               "RDEPEND": "dev-libs/foo:= app-misc/B",
+                       },
+
+                       "app-misc/D-1" : {
+                               "EAPI": "6",
+                               "DEPEND": "dev-libs/foo:=",
+                               "RDEPEND": "dev-libs/foo:=",
+                       },
+
+                       "app-misc/D-2" : {
+                               "EAPI": "6",
+                               "DEPEND": "dev-libs/foo:=",
+                               "RDEPEND": "dev-libs/foo:=",
+                       },
+
+                       "dev-libs/foo-1" : {
+                               "EAPI": "6",
+                               "SLOT": "0/1",
+                       },
+
+                       "dev-libs/foo-2" : {
+                               "EAPI": "6",
+                               "SLOT": "0/2",
+                       },
+               }
+
+               installed = {
+                       "app-misc/meta-pkg-1" : {
+                               "EAPI": "6",
+                               "DEPEND": "=app-misc/B-1 =app-misc/C-1  
=app-misc/D-1 =dev-libs/foo-1",
+                               "RDEPEND": "=app-misc/B-1 =app-misc/C-1 
=app-misc/D-1 =dev-libs/foo-1",
+                       },
+
+                       "app-misc/B-1" : {
+                               "EAPI": "6",
+                               "DEPEND": "dev-libs/foo:0/1=",
+                               "RDEPEND": "dev-libs/foo:0/1=",
+                       },
+
+                       "app-misc/C-1" : {
+                               "EAPI": "6",
+                               "DEPEND": "dev-libs/foo:0/1= app-misc/B",
+                               "RDEPEND": "dev-libs/foo:0/1= app-misc/B",
+                       },
+
+                       "app-misc/D-1" : {
+                               "EAPI": "6",
+                               "DEPEND": "dev-libs/foo:0/1=",
+                               "RDEPEND": "dev-libs/foo:0/1=",
+                       },
+
+                       "dev-libs/foo-1" : {
+                               "EAPI": "6",
+                               "SLOT": "0/1",
+                       },
+               }
+
+               world = (
+                       "app-misc/meta-pkg",
+               )
+
+               test_cases = (
+                       # Test bug 614390, where the depgraph._complete_graph
+                       # method pulled in an installed package that had been
+                       # scheduled for rebuild by the previous calculation,
+                       # triggering an unsolved slot conflict and preventing
+                       # slot operator rebuilds.
+                       ResolverPlaygroundTestCase(
+                               ["=app-misc/meta-pkg-2", "app-misc/C"],
+                               options = {
+                                       "--backtrack": 5,
+                               },
+                               success = True,
+                               ambiguous_merge_order = True,
+                               mergelist = [
+                                       'dev-libs/foo-2',
+                                       ('app-misc/D-1', 'app-misc/C-1', 
'app-misc/B-2'),
+                                       'app-misc/meta-pkg-2',
+                               ]
+                       ),
+               )
+
+               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:
+                       # Disable debug so that cleanup works.
+                       playground.debug = False
+                       playground.cleanup()
-- 
2.10.2


Reply via email to