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] depgraph: prune unnecessary rebuilds for --autounmask-continue (bug 619626)
Date: Thu, 01 Jun 2017 08:31:29
Message-Id: 20170601083102.21310-1-zmedico@gentoo.org
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

Replies