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