Gentoo Archives: gentoo-portage-dev

From: Zac Medico <zmedico@g.o>
To: gentoo-portage-dev@l.g.o
Cc: Zac Medico <zmedico@g.o>
Subject: [gentoo-portage-dev] [PATCH] depgraph: fix slot operator rebuild for llvm:0 to llvm:4 upgrade (bug 612772)
Date: Thu, 16 Mar 2017 03:23:57
Message-Id: 20170316032343.3060-1-zmedico@gentoo.org
1 Fix check_reverse_dependencies to ignore dependencies of parent packages
2 that could be uninstalled in order to solve a blocker conflict. This case
3 is similar to the one from bug 584626, except that the relevant parent
4 package is in an older slot which is blocked by a newer slot. In this
5 case, the _upgrade_available method returns False, because the package
6 in the older slot is the highest version version available for its
7 slot. Therefore, a new _in_blocker_conflict method is needed to detect
8 parent packages that cold be uninstalled. The included unit test fails
9 without this fix.
10
11 Since the _in_blocker_conflict method requires information that is
12 collected by the _validate_blockers method, the _validate_blockers
13 method now has to be called before the _process_slot_conflict and
14 _slot_operator_trigger_reinstalls methods.
15
16 X-Gentoo-bug: 612772
17 X-Gentoo-bug-url: https://bugs.gentoo.org/show_bug.cgi?id=612772
18 ---
19 pym/_emerge/depgraph.py | 59 ++++++++---
20 .../resolver/test_slot_operator_exclusive_slots.py | 109 +++++++++++++++++++++
21 2 files changed, 155 insertions(+), 13 deletions(-)
22 create mode 100644 pym/portage/tests/resolver/test_slot_operator_exclusive_slots.py
23
24 diff --git a/pym/_emerge/depgraph.py b/pym/_emerge/depgraph.py
25 index 1379b05..96b6d5f 100644
26 --- a/pym/_emerge/depgraph.py
27 +++ b/pym/_emerge/depgraph.py
28 @@ -387,7 +387,10 @@ class _dynamic_depgraph_config(object):
29 # Contains only unsolvable Package -> Blocker edges
30 self._unsolvable_blockers = digraph()
31 # Contains all Blocker -> Blocked Package edges
32 - self._blocked_pkgs = digraph()
33 + # Do not initialized this until the depgraph _validate_blockers
34 + # method is called, so that the _in_blocker_conflict method can
35 + # assert that _validate_blockers has been called first.
36 + self._blocked_pkgs = None
37 # Contains world packages that have been protected from
38 # uninstallation but may not have been added to the graph
39 # if the graph is not complete yet.
40 @@ -1466,9 +1469,22 @@ class depgraph(object):
41
42 self._solve_non_slot_operator_slot_conflicts()
43
44 + if not self._validate_blockers():
45 + # Blockers don't trigger the _skip_restart flag, since
46 + # backtracking may solve blockers when it solves slot
47 + # conflicts (or by blind luck).
48 + raise self._unknown_internal_error()
49 +
50 + # Both _process_slot_conflict and _slot_operator_trigger_reinstalls
51 + # can call _slot_operator_update_probe, which requires that
52 + # self._dynamic_config._blocked_pkgs has been initialized by a
53 + # call to the _validate_blockers method.
54 for conflict in self._dynamic_config._package_tracker.slot_conflicts():
55 self._process_slot_conflict(conflict)
56
57 + if self._dynamic_config._allow_backtracking:
58 + self._slot_operator_trigger_reinstalls()
59 +
60 def _process_slot_conflict(self, conflict):
61 """
62 Process slot conflict data to identify specific atoms which
63 @@ -1829,9 +1845,12 @@ class depgraph(object):
64 not self._frozen_config.excluded_pkgs.
65 findAtomForPackage(parent,
66 modified_use=self._pkg_use_enabled(parent)) and
67 - self._upgrade_available(parent)):
68 + (self._upgrade_available(parent) or
69 + (parent.installed and self._in_blocker_conflict(parent)))):
70 # This parent may be irrelevant, since an
71 - # update is available (see bug 584626).
72 + # update is available (see bug 584626), or
73 + # it could be uninstalled in order to solve
74 + # a blocker conflict (bug 612772).
75 continue
76
77 atom_set = InternalPackageSet(initial_atoms=(atom,),
78 @@ -2125,6 +2144,24 @@ class depgraph(object):
79
80 self._dynamic_config._need_restart = True
81
82 + def _in_blocker_conflict(self, pkg):
83 + """
84 + Check if pkg is involved in a blocker conflict. This method
85 + only works after the _validate_blockers method has been called.
86 + """
87 +
88 + if self._dynamic_config._blocked_pkgs is None:
89 + raise AssertionError(
90 + '_in_blocker_conflict called before _validate_blockers')
91 +
92 + if pkg in self._dynamic_config._blocked_pkgs:
93 + return True
94 +
95 + if pkg in self._dynamic_config._blocker_parents:
96 + return True
97 +
98 + return False
99 +
100 def _upgrade_available(self, pkg):
101 """
102 Detect cases where an upgrade of the given package is available
103 @@ -2925,7 +2962,8 @@ class depgraph(object):
104 self._dynamic_config._blocker_parents.discard(pkg)
105 self._dynamic_config._irrelevant_blockers.discard(pkg)
106 self._dynamic_config._unsolvable_blockers.discard(pkg)
107 - self._dynamic_config._blocked_pkgs.discard(pkg)
108 + if self._dynamic_config._blocked_pkgs is not None:
109 + self._dynamic_config._blocked_pkgs.discard(pkg)
110 self._dynamic_config._blocked_world_pkgs.pop(pkg, None)
111
112 for child in children:
113 @@ -6619,6 +6657,10 @@ class depgraph(object):
114 installed simultaneously. Also add runtime blockers from all installed
115 packages if any of them haven't been added already (bug 128809)."""
116
117 + # The _in_blocker_conflict method needs to assert that this method
118 + # has been called before it, by checking that it is not None.
119 + self._dynamic_config._blocked_pkgs = digraph()
120 +
121 if "--buildpkgonly" in self._frozen_config.myopts or \
122 "--nodeps" in self._frozen_config.myopts:
123 return True
124 @@ -7106,15 +7148,6 @@ class depgraph(object):
125
126 self._process_slot_conflicts()
127
128 - if self._dynamic_config._allow_backtracking:
129 - self._slot_operator_trigger_reinstalls()
130 -
131 - if not self._validate_blockers():
132 - # Blockers don't trigger the _skip_restart flag, since
133 - # backtracking may solve blockers when it solves slot
134 - # conflicts (or by blind luck).
135 - raise self._unknown_internal_error()
136 -
137 def _serialize_tasks(self):
138
139 debug = "--debug" in self._frozen_config.myopts
140 diff --git a/pym/portage/tests/resolver/test_slot_operator_exclusive_slots.py b/pym/portage/tests/resolver/test_slot_operator_exclusive_slots.py
141 new file mode 100644
142 index 0000000..2ab379c
143 --- /dev/null
144 +++ b/pym/portage/tests/resolver/test_slot_operator_exclusive_slots.py
145 @@ -0,0 +1,109 @@
146 +# Copyright 2017 Gentoo Foundation
147 +# Distributed under the terms of the GNU General Public License v2
148 +
149 +from portage.tests import TestCase
150 +from portage.tests.resolver.ResolverPlayground import (
151 + ResolverPlayground,
152 + ResolverPlaygroundTestCase,
153 +)
154 +
155 +class SlotOperatorExclusiveSlotsTestCase(TestCase):
156 +
157 + def testSlotOperatorExclusiveSlots(self):
158 +
159 + ebuilds = {
160 +
161 + "media-libs/mesa-17.0.1" : {
162 + "EAPI": "6",
163 + "SLOT": "0",
164 + "RDEPEND": "<sys-devel/llvm-5:="
165 + },
166 +
167 + "sys-devel/clang-4.0.0" : {
168 + "EAPI": "6",
169 + "SLOT": "4",
170 + "RDEPEND": ("~sys-devel/llvm-4.0.0:4= "
171 + "!sys-devel/llvm:0 !sys-devel/clang:0"),
172 + },
173 +
174 + "sys-devel/clang-3.9.1-r100" : {
175 + "EAPI": "6",
176 + "SLOT": "0/3.9.1",
177 + "RDEPEND": "~sys-devel/llvm-3.9.1",
178 + },
179 +
180 + "sys-devel/llvm-4.0.0" : {
181 + "EAPI": "6",
182 + "SLOT": "4",
183 + "RDEPEND": "!sys-devel/llvm:0",
184 + },
185 +
186 + "sys-devel/llvm-3.9.1" : {
187 + "EAPI": "6",
188 + "SLOT": "0/3.91",
189 + "RDEPEND": "!sys-devel/llvm:0",
190 + "PDEPEND": "=sys-devel/clang-3.9.1-r100",
191 + },
192 +
193 + }
194 +
195 + installed = {
196 +
197 + "media-libs/mesa-17.0.1" : {
198 + "EAPI": "6",
199 + "SLOT": "0",
200 + "RDEPEND": "<sys-devel/llvm-5:0/3.9.1="
201 + },
202 +
203 + "sys-devel/clang-3.9.1-r100" : {
204 + "EAPI": "6",
205 + "SLOT": "0/3.9.1",
206 + "RDEPEND": "~sys-devel/llvm-3.9.1",
207 + },
208 +
209 + "sys-devel/llvm-3.9.1" : {
210 + "EAPI": "6",
211 + "SLOT": "0/3.9.1",
212 + "RDEPEND": "!sys-devel/llvm:0",
213 + "PDEPEND": "=sys-devel/clang-3.9.1-r100",
214 + },
215 +
216 + }
217 +
218 + world = ["sys-devel/clang", "media-libs/mesa"]
219 +
220 + test_cases = (
221 +
222 + # Test bug #612772, where slot operator rebuilds are not
223 + # properly triggered (for things like mesa) during a
224 + # llvm:0 to llvm:4 upgrade with clang, resulting in
225 + # unsolved blockers.
226 + ResolverPlaygroundTestCase(
227 + ["@world"],
228 + options = {"--update": True, "--deep": True},
229 + success = True,
230 + ambiguous_merge_order = True,
231 + mergelist = [
232 + 'sys-devel/llvm-4.0.0',
233 + 'media-libs/mesa-17.0.1',
234 + (
235 + 'sys-devel/clang-4.0.0',
236 + '[uninstall]sys-devel/llvm-3.9.1',
237 + '!sys-devel/llvm:0',
238 + '[uninstall]sys-devel/clang-3.9.1-r100',
239 + '!sys-devel/clang:0',
240 + )
241 + ],
242 + ),
243 +
244 + )
245 +
246 + playground = ResolverPlayground(ebuilds=ebuilds,
247 + installed=installed, world=world)
248 + try:
249 + for test_case in test_cases:
250 + playground.run_TestCase(test_case)
251 + self.assertEqual(test_case.test_success, True,
252 + test_case.fail_msg)
253 + finally:
254 + playground.cleanup()
255 --
256 2.10.2

Replies