Gentoo Archives: gentoo-commits

From: Zac Medico <zmedico@g.o>
To: gentoo-commits@l.g.o
Subject: [gentoo-commits] proj/portage:master commit in: lib/portage/tests/resolver/, lib/portage/dep/, lib/_emerge/
Date: Tue, 28 Jan 2020 04:57:03
Message-Id: 1580095082.f7d83d75c6b05a16ef07473917082dbd0cd9955c.zmedico@gentoo
1 commit: f7d83d75c6b05a16ef07473917082dbd0cd9955c
2 Author: Zac Medico <zmedico <AT> gentoo <DOT> org>
3 AuthorDate: Sun Jan 26 01:44:14 2020 +0000
4 Commit: Zac Medico <zmedico <AT> gentoo <DOT> org>
5 CommitDate: Mon Jan 27 03:18:02 2020 +0000
6 URL: https://gitweb.gentoo.org/proj/portage.git/commit/?id=f7d83d75
7
8 dep_zapdeps: adjust || preference for slot upgrades (bug 706278)
9
10 Prefer choices that include a slot upgrade when appropriate, like for
11 the || ( llvm:10 ... llvm:7 ) case reported in bug 706278. In order
12 to avoid pulling in inappropriate slot upgrades, like those which
13 should only be pulled in with --update and --deep, add a want_update
14 flag to each choice which is True for choices that pull in a new slot
15 for which an update is desirable.
16
17 Mark the test case for bug 480736 as todo, since the "undesirable"
18 slot upgrade which triggers a blocker conflict in this test case is
19 practically indistinguishable from a desirable slot upgrade. This
20 particular blocker conflict is no longer relevant, since current
21 versions of media-libs/libpostproc are no longer compatible with
22 any available media-video/ffmpeg slot. In order to solve this test
23 case, some fancy backtracking (like for bug 382421) will be required.
24
25 Bug: https://bugs.gentoo.org/706278
26 Bug: https://bugs.gentoo.org/480736
27 Signed-off-by: Zac Medico <zmedico <AT> gentoo.org>
28
29 lib/_emerge/depgraph.py | 16 ++++-
30 lib/portage/dep/dep_check.py | 79 ++++++++++++----------
31 lib/portage/tests/resolver/test_or_choices.py | 9 +++
32 .../tests/resolver/test_or_upgrade_installed.py | 3 +-
33 4 files changed, 67 insertions(+), 40 deletions(-)
34
35 diff --git a/lib/_emerge/depgraph.py b/lib/_emerge/depgraph.py
36 index bf8882774..cae1c4470 100644
37 --- a/lib/_emerge/depgraph.py
38 +++ b/lib/_emerge/depgraph.py
39 @@ -95,6 +95,14 @@ if sys.hexversion >= 0x3000000:
40 else:
41 _unicode = unicode
42
43 +# Exposes a depgraph interface to dep_check.
44 +_dep_check_graph_interface = collections.namedtuple('_dep_check_graph_interface',(
45 + # Indicates a removal action, like depclean or prune.
46 + 'removal_action',
47 + # Checks if update is desirable for a given package.
48 + 'want_update_pkg',
49 +))
50 +
51 class _scheduler_graph_config(object):
52 def __init__(self, trees, pkg_cache, graph, mergelist):
53 self.trees = trees
54 @@ -510,6 +518,10 @@ class _dynamic_depgraph_config(object):
55 soname_deps=depgraph._frozen_config.soname_deps_enabled)
56 # Track missed updates caused by solved conflicts.
57 self._conflict_missed_update = collections.defaultdict(dict)
58 + dep_check_iface = _dep_check_graph_interface(
59 + removal_action="remove" in myparams,
60 + want_update_pkg=depgraph._want_update_pkg,
61 + )
62
63 for myroot in depgraph._frozen_config.trees:
64 self.sets[myroot] = _depgraph_sets()
65 @@ -530,7 +542,7 @@ class _dynamic_depgraph_config(object):
66 self._graph_trees[myroot]["vartree"] = graph_tree
67 self._graph_trees[myroot]["graph_db"] = graph_tree.dbapi
68 self._graph_trees[myroot]["graph"] = self.digraph
69 - self._graph_trees[myroot]["want_update_pkg"] = depgraph._want_update_pkg
70 + self._graph_trees[myroot]["graph_interface"] = dep_check_iface
71 self._graph_trees[myroot]["downgrade_probe"] = depgraph._downgrade_probe
72 def filtered_tree():
73 pass
74 @@ -558,7 +570,7 @@ class _dynamic_depgraph_config(object):
75 self._filtered_trees[myroot]["graph"] = self.digraph
76 self._filtered_trees[myroot]["vartree"] = \
77 depgraph._frozen_config.trees[myroot]["vartree"]
78 - self._filtered_trees[myroot]["want_update_pkg"] = depgraph._want_update_pkg
79 + self._filtered_trees[myroot]["graph_interface"] = dep_check_iface
80 self._filtered_trees[myroot]["downgrade_probe"] = depgraph._downgrade_probe
81
82 dbs = []
83
84 diff --git a/lib/portage/dep/dep_check.py b/lib/portage/dep/dep_check.py
85 index 321d961dd..a7ae2cfa4 100644
86 --- a/lib/portage/dep/dep_check.py
87 +++ b/lib/portage/dep/dep_check.py
88 @@ -296,7 +296,7 @@ def dep_eval(deplist):
89
90 class _dep_choice(SlotObject):
91 __slots__ = ('atoms', 'slot_map', 'cp_map', 'all_available',
92 - 'all_installed_slots', 'new_slot_count')
93 + 'all_installed_slots', 'new_slot_count', 'want_update', 'all_in_graph')
94
95 def dep_zapdeps(unreduced, reduced, myroot, use_binaries=0, trees=None,
96 minimize_slots=False):
97 @@ -331,9 +331,9 @@ def dep_zapdeps(unreduced, reduced, myroot, use_binaries=0, trees=None,
98 # c) contains masked installed packages
99 # d) is the first item
100
101 - preferred_installed = []
102 preferred_in_graph = []
103 - preferred_any_slot = []
104 + preferred_installed = preferred_in_graph
105 + preferred_any_slot = preferred_in_graph
106 preferred_non_installed = []
107 unsat_use_in_graph = []
108 unsat_use_installed = []
109 @@ -347,8 +347,6 @@ def dep_zapdeps(unreduced, reduced, myroot, use_binaries=0, trees=None,
110 # for correct ordering in cases like || ( foo[a] foo[b] ).
111 choice_bins = (
112 preferred_in_graph,
113 - preferred_installed,
114 - preferred_any_slot,
115 preferred_non_installed,
116 unsat_use_in_graph,
117 unsat_use_installed,
118 @@ -365,7 +363,7 @@ def dep_zapdeps(unreduced, reduced, myroot, use_binaries=0, trees=None,
119 graph_db = trees[myroot].get("graph_db")
120 graph = trees[myroot].get("graph")
121 pkg_use_enabled = trees[myroot].get("pkg_use_enabled")
122 - want_update_pkg = trees[myroot].get("want_update_pkg")
123 + graph_interface = trees[myroot].get("graph_interface")
124 downgrade_probe = trees[myroot].get("downgrade_probe")
125 circular_dependency = trees[myroot].get("circular_dependency")
126 vardb = None
127 @@ -506,14 +504,24 @@ def dep_zapdeps(unreduced, reduced, myroot, use_binaries=0, trees=None,
128 if current_higher or (all_match_current and not all_match_previous):
129 cp_map[avail_pkg.cp] = avail_pkg
130
131 - new_slot_count = (len(slot_map) if graph_db is None else
132 - sum(not graph_db.match_pkgs(slot_atom) for slot_atom in slot_map
133 - if not slot_atom.cp.startswith("virtual/")))
134 + want_update = False
135 + if graph_interface is None or graph_interface.removal_action:
136 + new_slot_count = len(slot_map)
137 + else:
138 + new_slot_count = 0
139 + for slot_atom, avail_pkg in slot_map.items():
140 + if graph_interface.want_update_pkg(parent, avail_pkg):
141 + want_update = True
142 + if (not slot_atom.cp.startswith("virtual/")
143 + and not graph_db.match_pkgs(slot_atom)):
144 + new_slot_count += 1
145
146 this_choice = _dep_choice(atoms=atoms, slot_map=slot_map,
147 cp_map=cp_map, all_available=all_available,
148 all_installed_slots=False,
149 - new_slot_count=new_slot_count)
150 + new_slot_count=new_slot_count,
151 + all_in_graph=False,
152 + want_update=want_update)
153 if all_available:
154 # The "all installed" criterion is not version or slot specific.
155 # If any version of a package is already in the graph then we
156 @@ -567,6 +575,8 @@ def dep_zapdeps(unreduced, reduced, myroot, use_binaries=0, trees=None,
157 graph_db.match_pkgs(atom)):
158 all_in_graph = False
159 break
160 + this_choice.all_in_graph = all_in_graph
161 +
162 circular_atom = None
163 if not (parent is None or priority is None) and \
164 (parent.onlydeps or
165 @@ -607,27 +617,8 @@ def dep_zapdeps(unreduced, reduced, myroot, use_binaries=0, trees=None,
166 elif all_installed:
167 if all_installed_slots:
168 preferred_installed.append(this_choice)
169 - elif parent is None or want_update_pkg is None:
170 - preferred_any_slot.append(this_choice)
171 else:
172 - # When appropriate, prefer a slot that is not
173 - # installed yet for bug #478188.
174 - want_update = True
175 - for slot_atom, avail_pkg in slot_map.items():
176 - if avail_pkg in graph:
177 - continue
178 - # New-style virtuals have zero cost to install.
179 - if slot_atom.startswith("virtual/") or \
180 - vardb.match(slot_atom):
181 - continue
182 - if not want_update_pkg(parent, avail_pkg):
183 - want_update = False
184 - break
185 -
186 - if want_update:
187 - preferred_installed.append(this_choice)
188 - else:
189 - preferred_any_slot.append(this_choice)
190 + preferred_any_slot.append(this_choice)
191 else:
192 preferred_non_installed.append(this_choice)
193 else:
194 @@ -676,10 +667,6 @@ def dep_zapdeps(unreduced, reduced, myroot, use_binaries=0, trees=None,
195 if len(choices) < 2:
196 continue
197
198 - sort_keys = []
199 - # Prefer choices with all_installed_slots for bug #480736.
200 - sort_keys.append(lambda x: not x.all_installed_slots)
201 -
202 if minimize_slots:
203 # Prefer choices having fewer new slots. When used with DNF form,
204 # this can eliminate unecessary packages that depclean would
205 @@ -694,15 +681,35 @@ def dep_zapdeps(unreduced, reduced, myroot, use_binaries=0, trees=None,
206 # contribute to outcomes that appear to be random. Meanwhile,
207 # the order specified in the ebuild is without variance, so it
208 # does not have this problem.
209 - sort_keys.append(lambda x: x.new_slot_count)
210 + choices.sort(key=operator.attrgetter('new_slot_count'))
211
212 - choices.sort(key=lambda x: tuple(f(x) for f in sort_keys))
213 for choice_1 in choices[1:]:
214 cps = set(choice_1.cp_map)
215 for choice_2 in choices:
216 if choice_1 is choice_2:
217 # choice_1 will not be promoted, so move on
218 break
219 + if (
220 + # For removal actions, prefer choices where all packages
221 + # have been pulled into the graph.
222 + (graph_interface and graph_interface.removal_action and
223 + choice_1.all_in_graph and not choice_2.all_in_graph)
224 +
225 + # Prefer choices where all_installed_slots is True, except
226 + # in cases where we want to upgrade to a new slot as in
227 + # bug 706278. Don't compare new_slot_count here since that
228 + # would aggressively override the preference order defined
229 + # in the ebuild, breaking the test case for bug 645002.
230 + or (choice_1.all_installed_slots and
231 + not choice_2.all_installed_slots and
232 + not choice_2.want_update)
233 + ):
234 + # promote choice_1 in front of choice_2
235 + choices.remove(choice_1)
236 + index_2 = choices.index(choice_2)
237 + choices.insert(index_2, choice_1)
238 + break
239 +
240 intersecting_cps = cps.intersection(choice_2.cp_map)
241 if not intersecting_cps:
242 continue
243
244 diff --git a/lib/portage/tests/resolver/test_or_choices.py b/lib/portage/tests/resolver/test_or_choices.py
245 index c0316bfb3..a50ad0151 100644
246 --- a/lib/portage/tests/resolver/test_or_choices.py
247 +++ b/lib/portage/tests/resolver/test_or_choices.py
248 @@ -288,6 +288,15 @@ class OrChoicesTestCase(TestCase):
249 class OrChoicesLibpostprocTestCase(TestCase):
250
251 def testOrChoicesLibpostproc(self):
252 + # This test case is expected to fail after the fix for bug 706278,
253 + # since the "undesirable" slot upgrade which triggers a blocker conflict
254 + # in this test case is practically indistinguishable from a desirable
255 + # slot upgrade. This particular blocker conflict is no longer relevant,
256 + # since current versions of media-libs/libpostproc are no longer
257 + # compatible with any available media-video/ffmpeg slot. In order to
258 + # solve this test case, some fancy backtracking (like for bug 382421)
259 + # will be required.
260 + self.todo = True
261
262 ebuilds = {
263 "media-video/ffmpeg-0.10" : {
264
265 diff --git a/lib/portage/tests/resolver/test_or_upgrade_installed.py b/lib/portage/tests/resolver/test_or_upgrade_installed.py
266 index c3efebf55..3889d53dc 100644
267 --- a/lib/portage/tests/resolver/test_or_upgrade_installed.py
268 +++ b/lib/portage/tests/resolver/test_or_upgrade_installed.py
269 @@ -213,8 +213,7 @@ class OrUpgradeInstalledTestCase(TestCase):
270 ['@world'],
271 options={'--update': True, '--deep': True},
272 success=True,
273 - mergelist=[],
274 - #mergelist=['sys-devel/llvm-9'],
275 + mergelist=['sys-devel/llvm-9', 'media-libs/mesa-19.2.8'],
276 ),
277 )