commit: beecd610f21497609679a08f867fd88090c71fb7 Author: Zac Medico <zmedico <AT> gentoo <DOT> org> AuthorDate: Fri Sep 19 09:16:32 2014 +0000 Commit: Zac Medico <zmedico <AT> gentoo <DOT> org> CommitDate: Fri Sep 19 09:16:32 2014 +0000 URL: http://sources.gentoo.org/gitweb/?p=proj/portage.git;a=commit;h=beecd610
_backtrack_depgraph: fix bug #523048 This fixes _backtrack_depgraph to immediately report necessary REQUIRED_USE changes instead of discarding the graph. This is accomplished by replacing the depgraph.success_without_autounmask method with a new need_config_change method that accounts for both autounmask and REQUIRED_USE changes. X-Gentoo-Bug: 523048 X-Gentoo-Bug-URL: https://bugs.gentoo.org/show_bug.cgi?id=523048 Acked-by: Brian Dolbec <dolsen <AT> gentoo.org> Acked-by: Alexander Berntsen <bernalex <AT> gentoo.org> --- pym/_emerge/depgraph.py | 11 ++-- pym/portage/tests/resolver/ResolverPlayground.py | 19 +++++- .../resolver/test_slot_operator_required_use.py | 72 ++++++++++++++++++++++ 3 files changed, 95 insertions(+), 7 deletions(-) diff --git a/pym/_emerge/depgraph.py b/pym/_emerge/depgraph.py index 6332733..e7ae720 100644 --- a/pym/_emerge/depgraph.py +++ b/pym/_emerge/depgraph.py @@ -421,6 +421,7 @@ class _dynamic_depgraph_config(object): self._buildpkgonly_deps_unsatisfied = False self._autounmask = depgraph._frozen_config.myopts.get('--autounmask') != 'n' self._success_without_autounmask = False + self._required_use_unsatisfied = False self._traverse_ignored_deps = False self._complete_mode = False self._slot_operator_deps = {} @@ -2461,6 +2462,7 @@ class depgraph(object): self._dynamic_config._unsatisfied_deps_for_display.append( ((pkg.root, atom), {"myparent" : dep.parent, "show_req_use" : pkg})) + self._dynamic_config._required_use_unsatisfied = True self._dynamic_config._skip_restart = True return 0 @@ -8390,8 +8392,9 @@ class depgraph(object): return self._dynamic_config._need_restart and \ not self._dynamic_config._skip_restart - def success_without_autounmask(self): - return self._dynamic_config._success_without_autounmask + def need_config_change(self): + return self._dynamic_config._success_without_autounmask or \ + self._dynamic_config._required_use_unsatisfied def autounmask_breakage_detected(self): try: @@ -8665,7 +8668,7 @@ def _backtrack_depgraph(settings, trees, myopts, myparams, myaction, myfiles, sp backtrack_parameters=backtrack_parameters) success, favorites = mydepgraph.select_files(myfiles) - if success or mydepgraph.success_without_autounmask(): + if success or mydepgraph.need_config_change(): break elif not allow_backtracking: break @@ -8677,7 +8680,7 @@ def _backtrack_depgraph(settings, trees, myopts, myparams, myaction, myfiles, sp else: break - if not (success or mydepgraph.success_without_autounmask()) and backtracked: + if not (success or mydepgraph.need_config_change()) and backtracked: if debug: writemsg_level( diff --git a/pym/portage/tests/resolver/ResolverPlayground.py b/pym/portage/tests/resolver/ResolverPlayground.py index d74a410..2d16251 100644 --- a/pym/portage/tests/resolver/ResolverPlayground.py +++ b/pym/portage/tests/resolver/ResolverPlayground.py @@ -674,7 +674,8 @@ class ResolverPlaygroundTestCase(object): expected = x break elif key in ("unstable_keywords", "needed_p_mask_changes", - "unsatisfied_deps") and expected is not None: + "unsatisfied_deps", "required_use_unsatisfied") and \ + expected is not None: expected = set(expected) elif key == "forced_rebuilds" and expected is not None: @@ -692,11 +693,14 @@ class ResolverPlaygroundTestCase(object): class ResolverPlaygroundResult(object): checks = ( - "success", "mergelist", "use_changes", "license_changes", "unstable_keywords", "slot_collision_solutions", - "circular_dependency_solutions", "needed_p_mask_changes", "unsatisfied_deps", "forced_rebuilds" + "success", "mergelist", "use_changes", "license_changes", + "unstable_keywords", "slot_collision_solutions", + "circular_dependency_solutions", "needed_p_mask_changes", + "unsatisfied_deps", "forced_rebuilds", "required_use_unsatisfied" ) optional_checks = ( "forced_rebuilds", + "required_use_unsatisfied", "unsatisfied_deps" ) @@ -714,6 +718,7 @@ class ResolverPlaygroundResult(object): self.circular_dependency_solutions = None self.unsatisfied_deps = frozenset() self.forced_rebuilds = None + self.required_use_unsatisfied = None if self.depgraph._dynamic_config._serialized_tasks_cache is not None: self.mergelist = [] @@ -783,6 +788,14 @@ class ResolverPlaygroundResult(object): for child_dict in self.depgraph._forced_rebuilds.values() for child, parents in child_dict.items()) + required_use_unsatisfied = [] + for pargs, kwargs in \ + self.depgraph._dynamic_config._unsatisfied_deps_for_display: + if "show_req_use" in kwargs: + required_use_unsatisfied.append(pargs[1]) + if required_use_unsatisfied: + self.required_use_unsatisfied = set(required_use_unsatisfied) + class ResolverPlaygroundDepcleanResult(object): checks = ( diff --git a/pym/portage/tests/resolver/test_slot_operator_required_use.py b/pym/portage/tests/resolver/test_slot_operator_required_use.py new file mode 100644 index 0000000..9cc6dba --- /dev/null +++ b/pym/portage/tests/resolver/test_slot_operator_required_use.py @@ -0,0 +1,72 @@ +# Copyright 2014 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 SlotOperatorRequiredUseTestCase(TestCase): + + def testSlotOperatorRequiredUse(self): + + ebuilds = { + + "app-misc/A-1" : { + "EAPI": "5", + "SLOT": "0/1" + }, + + "app-misc/A-2" : { + "EAPI": "5", + "SLOT": "0/2" + }, + + "app-misc/B-0" : { + "EAPI": "5", + "RDEPEND": "app-misc/A:=", + "IUSE": "x y", + "REQUIRED_USE": "|| ( x y )" + }, + + } + + installed = { + + "app-misc/A-1" : { + "EAPI": "5", + "SLOT": "0/1" + }, + + "app-misc/B-0" : { + "EAPI": "5", + "RDEPEND": "app-misc/A:0/1=", + "IUSE": "x y", + "USE": "x" + }, + + } + + world = ["app-misc/B"] + + test_cases = ( + + # bug 523048 + # Ensure that unsatisfied REQUIRED_USE is reported when + # it blocks necessary slot-operator rebuilds. + ResolverPlaygroundTestCase( + ["app-misc/A"], + success = False, + required_use_unsatisfied = ['app-misc/B:0'] + ), + + ) + + 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()
