commit:     38d9d0d3aa260c29b0a49ad0933e425e8e729b07
Author:     Zac Medico <zmedico <AT> gentoo <DOT> org>
AuthorDate: Tue Sep 16 17:57:49 2014 +0000
Commit:     Brian Dolbec <brian.dolbec <AT> gmail <DOT> com>
CommitDate: Tue Sep 16 20:25:13 2014 +0000
URL:        
http://sources.gentoo.org/gitweb/?p=proj/portage.git;a=commit;h=38d9d0d3

_solve_..slot_conflicts: fix bug #510270

This fixes an IndexError in _solve_non_slot_operator_slot_conflicts
which occurs when none of the conflict packages matched a particular
atom. This typically means that autounmask broke a USE-dep, but it could
also be due to the slot not matching due to multislot (bug #220341).
Either way, don't try to solve this conflict. Instead, force all of the
associated conflict nodes into the graph so that they are protected from
removal by the conflict solver.

X-Gentoo-Bug: 510270
X-Gentoo-Bug-URL: https://bugs.gentoo.org/show_bug.cgi?id=510270

---
 pym/_emerge/depgraph.py                            | 14 +++++
 pym/portage/tests/resolver/ResolverPlayground.py   |  9 ++++
 .../tests/resolver/test_autounmask_use_breakage.py | 63 ++++++++++++++++++++++
 3 files changed, 86 insertions(+)

diff --git a/pym/_emerge/depgraph.py b/pym/_emerge/depgraph.py
index cc87d9f..d85494a 100644
--- a/pym/_emerge/depgraph.py
+++ b/pym/_emerge/depgraph.py
@@ -1059,6 +1059,7 @@ class depgraph(object):
                        def __str__(self):
                                return "(%s)" % ",".join(str(pkg) for pkg in 
self)
 
+               non_matching_forced = set()
                for conflict in conflicts:
                        if debug:
                                writemsg_level("   conflict:\n", 
level=logging.DEBUG, noiselevel=-1)
@@ -1105,6 +1106,18 @@ class depgraph(object):
                                        continue
                                elif len(matched) == 1:
                                        conflict_graph.add(matched[0], parent)
+                               elif len(matched) == 0:
+                                       # This typically means that autounmask 
broke a
+                                       # USE-dep, but it could also be due to 
the slot
+                                       # not matching due to multislot (bug 
#220341).
+                                       # Either way, don't try to solve this 
conflict.
+                                       # Instead, force them all into the 
graph so that
+                                       # they are protected from removal.
+                                       non_matching_forced.update(conflict)
+                                       if debug:
+                                               for pkg in conflict:
+                                                       writemsg_level("        
 non-match: %s\n" % pkg,
+                                                               
level=logging.DEBUG, noiselevel=-1)
                                else:
                                        # More than one packages matched, but 
not all.
                                        conflict_graph.add(or_tuple(matched), 
parent)
@@ -1125,6 +1138,7 @@ class depgraph(object):
                # Now select required packages. Collect them in the
                # 'forced' set.
                forced = set([non_conflict_node])
+               forced.update(non_matching_forced)
                unexplored = set([non_conflict_node])
                # or_tuples get special handling. We first explore
                # all packages in the hope of having forced one of

diff --git a/pym/portage/tests/resolver/ResolverPlayground.py 
b/pym/portage/tests/resolver/ResolverPlayground.py
index 77a5b5c..b1974d7 100644
--- a/pym/portage/tests/resolver/ResolverPlayground.py
+++ b/pym/portage/tests/resolver/ResolverPlayground.py
@@ -549,6 +549,7 @@ class ResolverPlaygroundTestCase(object):
                self.all_permutations = kwargs.pop("all_permutations", False)
                self.ignore_mergelist_order = 
kwargs.pop("ignore_mergelist_order", False)
                self.ambiguous_merge_order = 
kwargs.pop("ambiguous_merge_order", False)
+               self.ambiguous_slot_collision_solutions = 
kwargs.pop("ambiguous_slot_collision_solutions", False)
                self.check_repo_names = kwargs.pop("check_repo_names", False)
                self.merge_order_assertions = 
kwargs.pop("merge_order_assertions", False)
 
@@ -664,6 +665,14 @@ class ResolverPlaygroundTestCase(object):
                                                                        
str((node1, node2))) + \
                                                                        ", got: 
" + str(got))
 
+                       elif key == "slot_collision_solutions" and \
+                               self.ambiguous_slot_collision_solutions:
+                               # Tests that use all_permutations can have 
multiple
+                               # outcomes here.
+                               for x in expected:
+                                       if x == got:
+                                               expected = x
+                                               break
                        elif key in ("unstable_keywords", 
"needed_p_mask_changes",
                                "unsatisfied_deps") and expected is not None:
                                expected = set(expected)

diff --git a/pym/portage/tests/resolver/test_autounmask_use_breakage.py 
b/pym/portage/tests/resolver/test_autounmask_use_breakage.py
new file mode 100644
index 0000000..3654aa6
--- /dev/null
+++ b/pym/portage/tests/resolver/test_autounmask_use_breakage.py
@@ -0,0 +1,63 @@
+# 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 AutounmaskUseBreakageTestCase(TestCase):
+
+       def testAutounmaskUseBreakage(self):
+
+               ebuilds = {
+
+                       "app-misc/A-0" : {
+                               "EAPI": "5",
+                               "RDEPEND": "app-misc/D[-foo]",
+                       },
+
+                       "app-misc/B-0" : {
+                               "EAPI": "5",
+                               "RDEPEND": "app-misc/D[foo]"
+                       },
+
+                       "app-misc/C-0" : {
+                               "EAPI": "5",
+                               "RDEPEND": ">=app-misc/D-1"
+                       },
+
+                       "app-misc/D-0" : {
+                               "EAPI": "5",
+                               "IUSE": "foo"
+                       },
+
+                       "app-misc/D-1" : {
+                               "EAPI": "5",
+                               "IUSE": "bar"
+                       },
+
+               }
+
+               test_cases = (
+
+                       # Bug 510270
+                       # _solve_non_slot_operator_slot_conflicts throws
+                       # IndexError: tuple index out of range
+                       # due to autounmask USE breakage.
+                       ResolverPlaygroundTestCase(
+                               ["app-misc/C", "app-misc/B", "app-misc/A"],
+                               all_permutations = True,
+                               success = False,
+                               ambiguous_slot_collision_solutions = True,
+                               slot_collision_solutions = [None, []]
+                       ),
+
+               )
+
+               playground = ResolverPlayground(ebuilds=ebuilds, 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()

Reply via email to