Gentoo Archives: gentoo-portage-dev

From: Zac Medico <zmedico@g.o>
To: gentoo-portage-dev@l.g.o
Subject: [gentoo-portage-dev] [PATCH] _solve_non_slot_operator_slot_conflicts: fix bug #510270
Date: Tue, 16 Sep 2014 18:37:39
Message-Id: 5418836E.2040705@gentoo.org
1 This fixes an IndexError in _solve_non_slot_operator_slot_conflicts
2 which occurs when none of the conflict packages matched a particular
3 atom. This typically means that autounmask broke a USE-dep, but it could
4 also be due to the slot not matching due to multislot (bug #220341).
5 Either way, don't try to solve this conflict. Instead, force all of the
6 associated conflict nodes into the graph so that they are protected from
7 removal by the conflict solver.
8
9 X-Gentoo-Bug: 510270
10 X-Gentoo-Bug-URL: https://bugs.gentoo.org/show_bug.cgi?id=510270
11 ---
12 pym/_emerge/depgraph.py | 14 +++++
13 pym/portage/tests/resolver/ResolverPlayground.py | 9 ++++
14 .../tests/resolver/test_autounmask_use_breakage.py | 63 ++++++++++++++++++++++
15 3 files changed, 86 insertions(+)
16 create mode 100644 pym/portage/tests/resolver/test_autounmask_use_breakage.py
17
18 diff --git a/pym/_emerge/depgraph.py b/pym/_emerge/depgraph.py
19 index cc87d9f..b31f90c 100644
20 --- a/pym/_emerge/depgraph.py
21 +++ b/pym/_emerge/depgraph.py
22 @@ -1059,6 +1059,7 @@ class depgraph(object):
23 def __str__(self):
24 return "(%s)" % ",".join(str(pkg) for pkg in self)
25
26 + non_matching_forced = set()
27 for conflict in conflicts:
28 if debug:
29 writemsg_level(" conflict:\n", level=logging.DEBUG, noiselevel=-1)
30 @@ -1105,6 +1106,18 @@ class depgraph(object):
31 continue
32 elif len(matched) == 1:
33 conflict_graph.add(matched[0], parent)
34 + elif len(matched) == 0:
35 + # This typically means that autounmask broke a
36 + # USE-dep, but it could also be due to the slot
37 + # not matching due to multislot (bug #220341).
38 + # Either way, don't try to solve this conflict.
39 + # Instead, force them all into the graph so that
40 + # they are protected from removal.
41 + non_matching_forced.update(conflict)
42 + if debug:
43 + for pkg in conflict:
44 + writemsg_level(" non-match: %s\n" % pkg,
45 + level=logging.DEBUG, noiselevel=-1)
46 else:
47 # More than one packages matched, but not all.
48 conflict_graph.add(or_tuple(matched), parent)
49 @@ -1125,6 +1138,7 @@ class depgraph(object):
50 # Now select required packages. Collect them in the
51 # 'forced' set.
52 forced = set([non_conflict_node])
53 + forced.update(non_matching_forced)
54 unexplored = set([non_conflict_node])
55 # or_tuples get special handling. We first explore
56 # all packages in the hope of having forced one of
57 diff --git a/pym/portage/tests/resolver/ResolverPlayground.py b/pym/portage/tests/resolver/ResolverPlayground.py
58 index 77a5b5c..b1974d7 100644
59 --- a/pym/portage/tests/resolver/ResolverPlayground.py
60 +++ b/pym/portage/tests/resolver/ResolverPlayground.py
61 @@ -549,6 +549,7 @@ class ResolverPlaygroundTestCase(object):
62 self.all_permutations = kwargs.pop("all_permutations", False)
63 self.ignore_mergelist_order = kwargs.pop("ignore_mergelist_order", False)
64 self.ambiguous_merge_order = kwargs.pop("ambiguous_merge_order", False)
65 + self.ambiguous_slot_collision_solutions = kwargs.pop("ambiguous_slot_collision_solutions", False)
66 self.check_repo_names = kwargs.pop("check_repo_names", False)
67 self.merge_order_assertions = kwargs.pop("merge_order_assertions", False)
68
69 @@ -664,6 +665,14 @@ class ResolverPlaygroundTestCase(object):
70 str((node1, node2))) + \
71 ", got: " + str(got))
72
73 + elif key == "slot_collision_solutions" and \
74 + self.ambiguous_slot_collision_solutions:
75 + # Tests that use all_permutations can have multiple
76 + # outcomes here.
77 + for x in expected:
78 + if x == got:
79 + expected = x
80 + break
81 elif key in ("unstable_keywords", "needed_p_mask_changes",
82 "unsatisfied_deps") and expected is not None:
83 expected = set(expected)
84 diff --git a/pym/portage/tests/resolver/test_autounmask_use_breakage.py b/pym/portage/tests/resolver/test_autounmask_use_breakage.py
85 new file mode 100644
86 index 0000000..3654aa6
87 --- /dev/null
88 +++ b/pym/portage/tests/resolver/test_autounmask_use_breakage.py
89 @@ -0,0 +1,63 @@
90 +# Copyright 2014 Gentoo Foundation
91 +# Distributed under the terms of the GNU General Public License v2
92 +
93 +from portage.tests import TestCase
94 +from portage.tests.resolver.ResolverPlayground import (ResolverPlayground,
95 + ResolverPlaygroundTestCase)
96 +
97 +class AutounmaskUseBreakageTestCase(TestCase):
98 +
99 + def testAutounmaskUseBreakage(self):
100 +
101 + ebuilds = {
102 +
103 + "app-misc/A-0" : {
104 + "EAPI": "5",
105 + "RDEPEND": "app-misc/D[-foo]",
106 + },
107 +
108 + "app-misc/B-0" : {
109 + "EAPI": "5",
110 + "RDEPEND": "app-misc/D[foo]"
111 + },
112 +
113 + "app-misc/C-0" : {
114 + "EAPI": "5",
115 + "RDEPEND": ">=app-misc/D-1"
116 + },
117 +
118 + "app-misc/D-0" : {
119 + "EAPI": "5",
120 + "IUSE": "foo"
121 + },
122 +
123 + "app-misc/D-1" : {
124 + "EAPI": "5",
125 + "IUSE": "bar"
126 + },
127 +
128 + }
129 +
130 + test_cases = (
131 +
132 + # Bug 510270
133 + # _solve_non_slot_operator_slot_conflicts throws
134 + # IndexError: tuple index out of range
135 + # due to autounmask USE breakage.
136 + ResolverPlaygroundTestCase(
137 + ["app-misc/C", "app-misc/B", "app-misc/A"],
138 + all_permutations = True,
139 + success = False,
140 + ambiguous_slot_collision_solutions = True,
141 + slot_collision_solutions = [None, []]
142 + ),
143 +
144 + )
145 +
146 + playground = ResolverPlayground(ebuilds=ebuilds, debug=False)
147 + try:
148 + for test_case in test_cases:
149 + playground.run_TestCase(test_case)
150 + self.assertEqual(test_case.test_success, True, test_case.fail_msg)
151 + finally:
152 + playground.cleanup()
153 --
154 1.8.5.5