commit: c01f3fbd23def329eb1d1b0fc8f79959119a8a82 Author: Zac Medico <zmedico <AT> gentoo <DOT> org> AuthorDate: Wed Mar 8 22:25:56 2017 +0000 Commit: Zac Medico <zmedico <AT> gentoo <DOT> org> CommitDate: Thu Mar 9 19:33:54 2017 +0000 URL: https://gitweb.gentoo.org/proj/portage.git/commit/?id=c01f3fbd
depgraph: fix runtime package mask interaction with slot operator rebuilds (bug 612094) In some cases the backtracking runtime package mask can interact badly with slot operator rebuilds, preventing a solution from being found. This patch fixes the problem, which is demonstrated by the included unit test. X-Gentoo-bug: 612094 X-Gentoo-bug-url: https://bugs.gentoo.org/show_bug.cgi?id=612094 Acked-by: Brian Dolbec <dolsen <AT> gentoo.org> pym/_emerge/depgraph.py | 28 +++-- .../test_slot_operator_runtime_pkg_mask.py | 136 +++++++++++++++++++++ 2 files changed, 152 insertions(+), 12 deletions(-) diff --git a/pym/_emerge/depgraph.py b/pym/_emerge/depgraph.py index bb3e307f0..1379b0563 100644 --- a/pym/_emerge/depgraph.py +++ b/pym/_emerge/depgraph.py @@ -1597,9 +1597,6 @@ class depgraph(object): atom.package and atom.slot_operator_built): continue - if pkg not in conflict_pkgs: - continue - for other_pkg in slot_nodes: if other_pkg in conflict_pkgs: continue @@ -2569,18 +2566,25 @@ class depgraph(object): # runtime_pkg_mask, since that would trigger an # infinite backtracking loop. if self._dynamic_config._allow_backtracking: - if dep.parent in self._dynamic_config._runtime_pkg_mask: - if debug: - writemsg( - "!!! backtracking loop detected: %s %s\n" % \ - (dep.parent, - self._dynamic_config._runtime_pkg_mask[ - dep.parent]), noiselevel=-1) - elif dep.atom.package and dep.atom.slot_operator_built and \ - self._slot_operator_unsatisfied_probe(dep): + if (dep.parent not in self._dynamic_config._runtime_pkg_mask and + dep.atom.package and dep.atom.slot_operator_built and + self._slot_operator_unsatisfied_probe(dep)): self._slot_operator_unsatisfied_backtrack(dep) return 1 else: + # This is for backward-compatibility with previous + # behavior, so that installed packages with unsatisfied + # dependencies trigger an error message but do not + # cause the dependency calculation to fail. Only do + # this if the parent is already in the runtime package + # mask, since otherwise we need to backtrack. + if (dep.parent.installed and + dep.parent in self._dynamic_config._runtime_pkg_mask and + not any(self._iter_match_pkgs_any( + dep.parent.root_config, dep.atom))): + self._dynamic_config._initially_unsatisfied_deps.append(dep) + return 1 + # Do not backtrack if only USE have to be changed in # order to satisfy the dependency. Note that when # want_restart_for_use_change sets the need_restart diff --git a/pym/portage/tests/resolver/test_slot_operator_runtime_pkg_mask.py b/pym/portage/tests/resolver/test_slot_operator_runtime_pkg_mask.py new file mode 100644 index 000000000..0a5a7fa78 --- /dev/null +++ b/pym/portage/tests/resolver/test_slot_operator_runtime_pkg_mask.py @@ -0,0 +1,136 @@ +# 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 SlotOperatorRuntimePkgMaskTestCase(TestCase): + + def testSlotOperatorRuntimePkgMask(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:=", + "RDEPEND": "dev-libs/foo:=", + }, + + "app-misc/C-2" : { + "EAPI": "6", + "DEPEND": "dev-libs/foo:=", + "RDEPEND": "dev-libs/foo:=", + }, + + "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=", + "RDEPEND": "dev-libs/foo:0/1=", + }, + + "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 = ( + ResolverPlaygroundTestCase( + ["=app-misc/meta-pkg-2"], + 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()