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 v2] depgraph: prune unnecessary rebuilds for --autounmask-continue (bug 619626)
Date: Thu, 01 Jun 2017 15:50:54
Message-Id: 20170601155035.25333-1-zmedico@gentoo.org
In Reply to: [gentoo-portage-dev] [PATCH] depgraph: prune unnecessary rebuilds for --autounmask-continue (bug 619626) by Zac Medico
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

Replies