diff options
-rw-r--r-- | pym/_emerge/resolver/circular_dependency.py | 44 | ||||
-rw-r--r-- | pym/portage/tests/resolver/test_circular_dependencies.py | 15 |
2 files changed, 46 insertions, 13 deletions
diff --git a/pym/_emerge/resolver/circular_dependency.py b/pym/_emerge/resolver/circular_dependency.py index 5029a7050..dbb1adf49 100644 --- a/pym/_emerge/resolver/circular_dependency.py +++ b/pym/_emerge/resolver/circular_dependency.py @@ -3,8 +3,10 @@ from __future__ import print_function +from itertools import chain + from portage.util import writemsg -from portage.dep import use_reduce, extract_affecting_use +from portage.dep import use_reduce, extract_affecting_use, check_required_use, get_required_use_flags from portage.output import colorize from _emerge.DepPrioritySatisfiedRange import DepPrioritySatisfiedRange @@ -118,9 +120,21 @@ class circular_dependency_handler(object): # Make sure we don't want to change a flag that is # a) in use.mask or use.force # b) changed by autounmask + usemask, useforce = self._get_use_mask_and_force(parent) autounmask_changes = self._get_autounmask_changes(parent) - affecting_use.difference_update(usemask, useforce, autounmask_changes) + untouchable_flags = frozenset(chain(usemask, useforce, autounmask_changes)) + + affecting_use.difference_update(untouchable_flags) + + #If any of the flags we're going to touch is in REQUIRED_USE, add all + #other flags in REQUIRED_USE to affecting_use, to not lose any solution. + required_use_flags = get_required_use_flags(parent.metadata["REQUIRED_USE"]) + + if affecting_use.intersection(required_use_flags): + affecting_use.update(required_use_flags) + affecting_use.difference_update(untouchable_flags) + affecting_use = tuple(affecting_use) if not affecting_use: @@ -160,17 +174,21 @@ class circular_dependency_handler(object): uselist=current_use, flat=True) if parent_atom not in reduced_dep: - #we found a valid solution - solution = set() - use = self.depgraph._pkg_use_enabled(parent) - for flag, state in zip(affecting_use, use_state): - if state == "enabled" and \ - flag not in use: - solution.add((flag, True)) - elif state == "disabled" and \ - flag in use: - solution.add((flag, False)) - solutions.add(frozenset(solution)) + #We found an assignment that removes the atom from 'dep'. + #Make sure it doesn't conflict with REQUIRED_USE. + required_use = parent.metadata["REQUIRED_USE"] + + if check_required_use(required_use, current_use, parent.iuse.is_valid_flag): + use = self.depgraph._pkg_use_enabled(parent) + solution = set() + for flag, state in zip(affecting_use, use_state): + if state == "enabled" and \ + flag not in use: + solution.add((flag, True)) + elif state == "disabled" and \ + flag in use: + solution.add((flag, False)) + solutions.add(frozenset(solution)) if not _next_use_state(use_state): break diff --git a/pym/portage/tests/resolver/test_circular_dependencies.py b/pym/portage/tests/resolver/test_circular_dependencies.py index 73cb95a63..e70298642 100644 --- a/pym/portage/tests/resolver/test_circular_dependencies.py +++ b/pym/portage/tests/resolver/test_circular_dependencies.py @@ -24,6 +24,11 @@ class CircularDependencyTestCase(TestCase): "dev-libs/W-1": { "DEPEND": "dev-libs/Z[foo] dev-libs/Y", "EAPI": 2 }, "dev-libs/W-2": { "DEPEND": "dev-libs/Z[foo=] dev-libs/Y", "IUSE": "+foo", "EAPI": 2 }, "dev-libs/W-3": { "DEPEND": "dev-libs/Z[bar] dev-libs/Y", "EAPI": 2 }, + + #~ "app-misc/A-1": { "DEPEND": "foo? ( =app-misc/B-1 )", "IUSE": "+foo bar", "REQUIRED_USE": "^^ ( foo bar )", "EAPI": 4 }, + #~ "app-misc/A-2": { "DEPEND": "foo? ( =app-misc/B-2 ) bar? ( =app-misc/B-2 )", "IUSE": "+foo bar", "REQUIRED_USE": "^^ ( foo bar )", "EAPI": 4 }, + #~ "app-misc/B-1": { "DEPEND": "=app-misc/A-1" }, + #~ "app-misc/B-2": { "DEPEND": "=app-misc/A-2" }, } test_cases = ( @@ -58,6 +63,16 @@ class CircularDependencyTestCase(TestCase): circular_dependency_solutions = { "dev-libs/Y-1": frozenset([frozenset([("foo", False)])])}, use_changes = { "dev-libs/Z-3": {"bar": True}}, success = False), + + #Conflict with REQUIRED_USE + #~ ResolverPlaygroundTestCase( + #~ ["=app-misc/B-1"], + #~ circular_dependency_solutions = { "app-misc/B-1": frozenset([frozenset([("foo", False), ("bar", True)])])}, + #~ success = False), + #~ ResolverPlaygroundTestCase( + #~ ["=app-misc/B-2"], + #~ circular_dependency_solutions = {}, + #~ success = False), ) playground = ResolverPlayground(ebuilds=ebuilds) |