When disjunctive dependencies are queued, group together disjunctions
from the same dependency string so that any overlap between them will
trigger expansion to DNF.

Bug: https://bugs.gentoo.org/701996
Signed-off-by: Zac Medico <zmed...@gentoo.org>
---
 lib/_emerge/depgraph.py                       |  8 +++-
 .../test_virtual_minimize_children.py         | 39 +++++++++++++++++++
 2 files changed, 45 insertions(+), 2 deletions(-)

diff --git a/lib/_emerge/depgraph.py b/lib/_emerge/depgraph.py
index f80b077bc..78226a3ea 100644
--- a/lib/_emerge/depgraph.py
+++ b/lib/_emerge/depgraph.py
@@ -3850,10 +3850,11 @@ class depgraph(object):
                Yields non-disjunctive deps. Raises InvalidDependString when
                necessary.
                """
+               disjunctions = []
                for x in dep_struct:
                        if isinstance(x, list):
                                if x and x[0] == "||":
-                                       self._queue_disjunction(pkg, dep_root, 
dep_priority, [x])
+                                       disjunctions.append(x)
                                else:
                                        for y in self._queue_disjunctive_deps(
                                                pkg, dep_root, dep_priority, x):
@@ -3863,10 +3864,13 @@ class depgraph(object):
                                # or whatever other metadata gets implemented 
for this
                                # purpose.
                                if x.cp.startswith('virtual/'):
-                                       self._queue_disjunction(pkg, dep_root, 
dep_priority, [x])
+                                       disjunctions.append(x)
                                else:
                                        yield x
 
+               if disjunctions:
+                       self._queue_disjunction(pkg, dep_root, dep_priority, 
disjunctions)
+
        def _queue_disjunction(self, pkg, dep_root, dep_priority, dep_struct):
                self._dynamic_config._dep_disjunctive_stack.append(
                        (pkg, dep_root, dep_priority, dep_struct))
diff --git a/lib/portage/tests/resolver/test_virtual_minimize_children.py 
b/lib/portage/tests/resolver/test_virtual_minimize_children.py
index b566cb592..720fbe57b 100644
--- a/lib/portage/tests/resolver/test_virtual_minimize_children.py
+++ b/lib/portage/tests/resolver/test_virtual_minimize_children.py
@@ -285,3 +285,42 @@ class VirtualMinimizeChildrenTestCase(TestCase):
                finally:
                        playground.debug = False
                        playground.cleanup()
+
+
+       def testVirtualWine(self):
+               ebuilds = {
+                       'virtual/wine-0-r6': {
+                               'RDEPEND': '|| ( app-emulation/wine-staging 
app-emulation/wine-any ) '
+                                       '|| ( app-emulation/wine-vanilla 
app-emulation/wine-staging app-emulation/wine-any )'
+                       },
+                       'app-emulation/wine-staging-4': {},
+                       'app-emulation/wine-any-4': {},
+                       'app-emulation/wine-vanilla-4': {},
+               }
+
+               test_cases = (
+                       # Test bug 701996, where separate disjunctions where not
+                       # converted to DNF, causing both wine-vanilla and
+                       # wine-staging to be pulled in.
+                       ResolverPlaygroundTestCase(
+                               [
+                                       'virtual/wine',
+                               ],
+                               success=True,
+                               mergelist=(
+                                       'app-emulation/wine-staging-4',
+                                       'virtual/wine-0-r6',
+                               ),
+                       ),
+               )
+
+               playground = ResolverPlayground(debug=False, ebuilds=ebuilds)
+
+               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.debug = False
+                       playground.cleanup()
-- 
2.21.0


Reply via email to