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