summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--pym/_emerge/resolver/circular_dependency.py44
-rw-r--r--pym/portage/tests/resolver/test_circular_dependencies.py15
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)