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