[prev in list] [next in list] [prev in thread] [next in thread] 

List:       gentoo-portage-dev
Subject:    [gentoo-portage-dev] [PATCH] _solve_non_slot_operator_slot_conflicts: fix bug #510270
From:       Zac Medico <zmedico () gentoo ! org>
Date:       2014-09-16 18:37:34
Message-ID: 5418836E.2040705 () gentoo ! org
[Download RAW message or body]

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(+)
 create mode 100644 pym/portage/tests/resolver/test_autounmask_use_breakage.py

diff --git a/pym/_emerge/depgraph.py b/pym/_emerge/depgraph.py
index cc87d9f..b31f90c 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()
-- 
1.8.5.5


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic