1 |
When there are autounmask USE changes, avoid unnecessary rebuilds |
2 |
by accepting binary packages that were rejected due to the preexisting |
3 |
USE configuration. This reuses the prune_rebuilds backtracker support |
4 |
which was added for bug 439688. |
5 |
|
6 |
X-Gentoo-bug: 619626 |
7 |
X-Gentoo-bug-url: https://bugs.gentoo.org/show_bug.cgi?id=619626 |
8 |
--- |
9 |
[PATCH v2] |
10 |
* Ensure that it won't try to prune rebuilds more than once. |
11 |
* Simplify boolean logic at the beginning of the |
12 |
_ignored_binaries_autounmask_backtrack method, as suggested |
13 |
by Brian Dolbec. |
14 |
|
15 |
pym/_emerge/depgraph.py | 89 ++++++++++++++++++---- |
16 |
.../tests/resolver/test_autounmask_binpkg_use.py | 64 ++++++++++++++++ |
17 |
2 files changed, 138 insertions(+), 15 deletions(-) |
18 |
create mode 100644 pym/portage/tests/resolver/test_autounmask_binpkg_use.py |
19 |
|
20 |
diff --git a/pym/_emerge/depgraph.py b/pym/_emerge/depgraph.py |
21 |
index 726835dd4..f47ce559c 100644 |
22 |
--- a/pym/_emerge/depgraph.py |
23 |
+++ b/pym/_emerge/depgraph.py |
24 |
@@ -5,6 +5,7 @@ from __future__ import division, print_function, unicode_literals |
25 |
|
26 |
import collections |
27 |
import errno |
28 |
+import functools |
29 |
import io |
30 |
import logging |
31 |
import stat |
32 |
@@ -856,17 +857,11 @@ class depgraph(object): |
33 |
for parent in self._forced_rebuilds[root][child]: |
34 |
writemsg_stdout(" %s\n" % (parent,), noiselevel=-1) |
35 |
|
36 |
- def _show_ignored_binaries(self): |
37 |
+ def _eliminate_ignored_binaries(self): |
38 |
""" |
39 |
- Show binaries that have been ignored because their USE didn't |
40 |
- match the user's config. |
41 |
+ Eliminate any package from self._dynamic_config.ignored_binaries |
42 |
+ for which a more optimal alternative exists. |
43 |
""" |
44 |
- if not self._dynamic_config.ignored_binaries \ |
45 |
- or '--quiet' in self._frozen_config.myopts: |
46 |
- return |
47 |
- |
48 |
- ignored_binaries = {} |
49 |
- |
50 |
for pkg in list(self._dynamic_config.ignored_binaries): |
51 |
|
52 |
for selected_pkg in self._dynamic_config._package_tracker.match( |
53 |
@@ -885,10 +880,67 @@ class depgraph(object): |
54 |
self._dynamic_config.ignored_binaries.pop(pkg) |
55 |
break |
56 |
|
57 |
- else: |
58 |
- for reason, info in self._dynamic_config.\ |
59 |
- ignored_binaries[pkg].items(): |
60 |
- ignored_binaries.setdefault(reason, {})[pkg] = info |
61 |
+ def _ignored_binaries_autounmask_backtrack(self): |
62 |
+ """ |
63 |
+ Check if there are ignored binaries that would have been |
64 |
+ accepted with the current autounmask USE changes. |
65 |
+ |
66 |
+ @rtype: bool |
67 |
+ @return: True if there are unnecessary rebuilds that |
68 |
+ can be avoided by backtracking |
69 |
+ """ |
70 |
+ if not all([ |
71 |
+ self._dynamic_config._allow_backtracking, |
72 |
+ self._dynamic_config._needed_use_config_changes, |
73 |
+ self._dynamic_config.ignored_binaries]): |
74 |
+ return False |
75 |
+ |
76 |
+ self._eliminate_ignored_binaries() |
77 |
+ |
78 |
+ # _eliminate_ignored_binaries may have eliminated |
79 |
+ # all of the ignored binaries |
80 |
+ if not self._dynamic_config.ignored_binaries: |
81 |
+ return False |
82 |
+ |
83 |
+ use_changes = collections.defaultdict( |
84 |
+ functools.partial(collections.defaultdict, dict)) |
85 |
+ for pkg, (new_use, changes) in self._dynamic_config._needed_use_config_changes.items(): |
86 |
+ if pkg in self._dynamic_config.digraph: |
87 |
+ use_changes[pkg.root][pkg.slot_atom] = (pkg, new_use) |
88 |
+ |
89 |
+ for pkg in self._dynamic_config.ignored_binaries: |
90 |
+ selected_pkg, new_use = use_changes[pkg.root].get( |
91 |
+ pkg.slot_atom, (None, None)) |
92 |
+ if new_use is None: |
93 |
+ continue |
94 |
+ |
95 |
+ if new_use != pkg.use.enabled: |
96 |
+ continue |
97 |
+ |
98 |
+ if selected_pkg > pkg: |
99 |
+ continue |
100 |
+ |
101 |
+ return True |
102 |
+ |
103 |
+ return False |
104 |
+ |
105 |
+ def _show_ignored_binaries(self): |
106 |
+ """ |
107 |
+ Show binaries that have been ignored because their USE didn't |
108 |
+ match the user's config. |
109 |
+ """ |
110 |
+ if not self._dynamic_config.ignored_binaries \ |
111 |
+ or '--quiet' in self._frozen_config.myopts: |
112 |
+ return |
113 |
+ |
114 |
+ self._eliminate_ignored_binaries() |
115 |
+ |
116 |
+ ignored_binaries = {} |
117 |
+ |
118 |
+ for pkg in self._dynamic_config.ignored_binaries: |
119 |
+ for reason, info in self._dynamic_config.\ |
120 |
+ ignored_binaries[pkg].items(): |
121 |
+ ignored_binaries.setdefault(reason, {})[pkg] = info |
122 |
|
123 |
if self._dynamic_config.myparams.get( |
124 |
"binpkg_respect_use") in ("y", "n"): |
125 |
@@ -4245,6 +4297,13 @@ class depgraph(object): |
126 |
self._dynamic_config._skip_restart = True |
127 |
return False, myfavorites |
128 |
|
129 |
+ if (not self._dynamic_config._prune_rebuilds and |
130 |
+ self._ignored_binaries_autounmask_backtrack()): |
131 |
+ config = self._dynamic_config._backtrack_infos.setdefault("config", {}) |
132 |
+ config["prune_rebuilds"] = True |
133 |
+ self._dynamic_config._need_restart = True |
134 |
+ return False, myfavorites |
135 |
+ |
136 |
# Any failures except those due to autounmask *alone* should return |
137 |
# before this point, since the success_without_autounmask flag that's |
138 |
# set below is reserved for cases where there are *zero* other |
139 |
@@ -6224,10 +6283,10 @@ class depgraph(object): |
140 |
iuses = pkg.iuse.all |
141 |
old_use = self._pkg_use_enabled(pkg) |
142 |
if myeb: |
143 |
- pkgsettings.setcpv(myeb) |
144 |
+ now_use = self._pkg_use_enabled(myeb) |
145 |
else: |
146 |
pkgsettings.setcpv(pkg) |
147 |
- now_use = pkgsettings["PORTAGE_USE"].split() |
148 |
+ now_use = pkgsettings["PORTAGE_USE"].split() |
149 |
forced_flags = set() |
150 |
forced_flags.update(pkgsettings.useforce) |
151 |
forced_flags.update(pkgsettings.usemask) |
152 |
diff --git a/pym/portage/tests/resolver/test_autounmask_binpkg_use.py b/pym/portage/tests/resolver/test_autounmask_binpkg_use.py |
153 |
new file mode 100644 |
154 |
index 000000000..1ca4bf3d9 |
155 |
--- /dev/null |
156 |
+++ b/pym/portage/tests/resolver/test_autounmask_binpkg_use.py |
157 |
@@ -0,0 +1,64 @@ |
158 |
+# Copyright 2017 Gentoo Foundation |
159 |
+# Distributed under the terms of the GNU General Public License v2 |
160 |
+ |
161 |
+from portage.tests import TestCase |
162 |
+from portage.tests.resolver.ResolverPlayground import ResolverPlayground, ResolverPlaygroundTestCase |
163 |
+ |
164 |
+class AutounmaskBinpkgUseTestCase(TestCase): |
165 |
+ |
166 |
+ def testAutounmaskBinpkgUse(self): |
167 |
+ ebuilds = { |
168 |
+ "dev-libs/A-1": { |
169 |
+ "EAPI": "6", |
170 |
+ "DEPEND": "dev-libs/B[foo]", |
171 |
+ "RDEPEND": "dev-libs/B[foo]", |
172 |
+ }, |
173 |
+ "dev-libs/B-1": { |
174 |
+ "EAPI": "6", |
175 |
+ "IUSE": "foo", |
176 |
+ }, |
177 |
+ } |
178 |
+ binpkgs = { |
179 |
+ "dev-libs/A-1": { |
180 |
+ "EAPI": "6", |
181 |
+ "DEPEND": "dev-libs/B[foo]", |
182 |
+ "RDEPEND": "dev-libs/B[foo]", |
183 |
+ }, |
184 |
+ "dev-libs/B-1": { |
185 |
+ "EAPI": "6", |
186 |
+ "IUSE": "foo", |
187 |
+ "USE": "foo", |
188 |
+ }, |
189 |
+ } |
190 |
+ installed = { |
191 |
+ } |
192 |
+ |
193 |
+ test_cases = ( |
194 |
+ # Bug 619626: Test for unnecessary rebuild due |
195 |
+ # to rejection of binary packages that would |
196 |
+ # be acceptable after appplication of autounmask |
197 |
+ # USE changes. |
198 |
+ ResolverPlaygroundTestCase( |
199 |
+ ["dev-libs/A"], |
200 |
+ all_permutations = True, |
201 |
+ success = True, |
202 |
+ options = { |
203 |
+ "--usepkg": True, |
204 |
+ }, |
205 |
+ mergelist = [ |
206 |
+ "[binary]dev-libs/B-1", |
207 |
+ "[binary]dev-libs/A-1", |
208 |
+ ], |
209 |
+ use_changes = {"dev-libs/B-1": {"foo": True}} |
210 |
+ ), |
211 |
+ ) |
212 |
+ |
213 |
+ playground = ResolverPlayground(ebuilds=ebuilds, |
214 |
+ binpkgs=binpkgs, installed=installed, debug=False) |
215 |
+ try: |
216 |
+ for test_case in test_cases: |
217 |
+ playground.run_TestCase(test_case) |
218 |
+ self.assertEqual(test_case.test_success, True, test_case.fail_msg) |
219 |
+ finally: |
220 |
+ playground.debug = False |
221 |
+ playground.cleanup() |
222 |
-- |
223 |
2.13.0 |