Gentoo Archives: gentoo-commits

From: Zac Medico <zmedico@g.o>
To: gentoo-commits@l.g.o
Subject: [gentoo-commits] proj/portage:master commit in: lib/portage/tests/resolver/, lib/portage/dep/, lib/_emerge/, ...
Date: Mon, 23 Dec 2019 22:47:53
Message-Id: 1577139795.85f0dd173ab75bcc39c3616b5a3a967bdc88cf73.zmedico@gentoo
1 commit: 85f0dd173ab75bcc39c3616b5a3a967bdc88cf73
2 Author: Zac Medico <zmedico <AT> gentoo <DOT> org>
3 AuthorDate: Fri Dec 20 06:58:58 2019 +0000
4 Commit: Zac Medico <zmedico <AT> gentoo <DOT> org>
5 CommitDate: Mon Dec 23 22:23:15 2019 +0000
6 URL: https://gitweb.gentoo.org/proj/portage.git/commit/?id=85f0dd17
7
8 emerge --with-test-deps: allow circular deps
9
10 When USE=test is not enabled, allow circular test dependencies
11 by treating them like PDEPEND. When USE=test is enabled, circular
12 dependencies are still not allowed, as shown in unit tests.
13
14 Suggested-by: Michał Górny <mgorny <AT> gentoo.org>
15 Bug: https://bugs.gentoo.org/703348
16 Signed-off-by: Zac Medico <zmedico <AT> gentoo.org>
17
18 lib/_emerge/depgraph.py | 19 ++++--
19 lib/portage/dep/__init__.py | 44 +++++++++++++-
20 lib/portage/tests/dep/test_use_reduce.py | 72 ++++++++++++++++++++++-
21 lib/portage/tests/resolver/test_with_test_deps.py | 39 +++++++++++-
22 4 files changed, 166 insertions(+), 8 deletions(-)
23
24 diff --git a/lib/_emerge/depgraph.py b/lib/_emerge/depgraph.py
25 index 1a5448c8f..83631fe70 100644
26 --- a/lib/_emerge/depgraph.py
27 +++ b/lib/_emerge/depgraph.py
28 @@ -3325,10 +3325,6 @@ class depgraph(object):
29 pkg.iuse.is_valid_flag("test") and \
30 self._is_argument(pkg)
31
32 - if with_test_deps:
33 - use_enabled = set(use_enabled)
34 - use_enabled.add("test")
35 -
36 if not pkg.built and \
37 "--buildpkgonly" in self._frozen_config.myopts and \
38 "deep" not in self._dynamic_config.myparams:
39 @@ -3430,6 +3426,21 @@ class depgraph(object):
40 noiselevel=-1, level=logging.DEBUG)
41
42 try:
43 + if (with_test_deps and 'test' not in use_enabled and
44 + pkg.iuse.is_valid_flag('test')):
45 + test_deps = portage.dep.use_reduce(dep_string,
46 + uselist=use_enabled | {'test'},
47 + is_valid_flag=pkg.iuse.is_valid_flag,
48 + opconvert=True, token_class=Atom,
49 + eapi=pkg.eapi,
50 + subset={'test'})
51 +
52 + if test_deps and not self._add_pkg_dep_string(
53 + pkg, dep_root, self._priority(runtime_post=True),
54 + test_deps,
55 + allow_unsatisfied):
56 + return 0
57 +
58 dep_string = portage.dep.use_reduce(dep_string,
59 uselist=use_enabled,
60 is_valid_flag=pkg.iuse.is_valid_flag,
61
62 diff --git a/lib/portage/dep/__init__.py b/lib/portage/dep/__init__.py
63 index f08f6ba4c..72988357a 100644
64 --- a/lib/portage/dep/__init__.py
65 +++ b/lib/portage/dep/__init__.py
66 @@ -405,7 +405,8 @@ def paren_enclose(mylist, unevaluated_atom=False, opconvert=False):
67 return " ".join(mystrparts)
68
69 def use_reduce(depstr, uselist=(), masklist=(), matchall=False, excludeall=(), is_src_uri=False, \
70 - eapi=None, opconvert=False, flat=False, is_valid_flag=None, token_class=None, matchnone=False):
71 + eapi=None, opconvert=False, flat=False, is_valid_flag=None, token_class=None, matchnone=False,
72 + subset=None):
73 """
74 Takes a dep string and reduces the use? conditionals out, leaving an array
75 with subarrays. All redundant brackets are removed.
76 @@ -434,6 +435,8 @@ def use_reduce(depstr, uselist=(), masklist=(), matchall=False, excludeall=(), i
77 @type token_class: Class
78 @param matchnone: Treat all conditionals as inactive. Used by digestgen().
79 @type matchnone: Bool
80 + @param subset: Select a subset of dependencies conditional on the given flags
81 + @type subset: Sequence
82 @rtype: List
83 @return: The use reduced depend array
84 """
85 @@ -491,6 +494,45 @@ def use_reduce(depstr, uselist=(), masklist=(), matchall=False, excludeall=(), i
86 return (flag in uselist and not is_negated) or \
87 (flag not in uselist and is_negated)
88
89 + if subset:
90 + def select_subset(dep_struct, disjunction, selected):
91 + result = []
92 + stack = list(dep_struct)
93 + stack.reverse()
94 + while stack:
95 + token = stack.pop()
96 + try:
97 + conditional = token.endswith('?')
98 + except AttributeError:
99 + if disjunction:
100 + children = select_subset(token, False, selected)
101 + if children:
102 + result.append(children)
103 + else:
104 + result.extend(select_subset(token, False, selected))
105 + else:
106 + if conditional:
107 + children = stack.pop()
108 + if is_active(token):
109 + if disjunction:
110 + children = select_subset(children, False, selected or token[:-1] in subset)
111 + if children:
112 + result.append(children)
113 + else:
114 + result.extend(select_subset(children, False, selected or token[:-1] in subset))
115 + elif token == '||':
116 + children = select_subset(stack.pop(), True, selected)
117 + if children:
118 + if disjunction:
119 + result.extend(children)
120 + else:
121 + result.append(token)
122 + result.append(children)
123 + elif selected:
124 + result.append(token)
125 + return result
126 + depstr = paren_enclose(select_subset(paren_reduce(depstr, _deprecation_warn=False), False, False))
127 +
128 def missing_white_space_check(token, pos):
129 """
130 Used to generate good error messages for invalid tokens.
131
132 diff --git a/lib/portage/tests/dep/test_use_reduce.py b/lib/portage/tests/dep/test_use_reduce.py
133 index 4f65567cf..d9ee5a309 100644
134 --- a/lib/portage/tests/dep/test_use_reduce.py
135 +++ b/lib/portage/tests/dep/test_use_reduce.py
136 @@ -9,7 +9,7 @@ class UseReduceTestCase(object):
137 def __init__(self, deparray, uselist=[], masklist=[],
138 matchall=0, excludeall=[], is_src_uri=False,
139 eapi='0', opconvert=False, flat=False, expected_result=None,
140 - is_valid_flag=None, token_class=None):
141 + is_valid_flag=None, token_class=None, subset=None):
142 self.deparray = deparray
143 self.uselist = uselist
144 self.masklist = masklist
145 @@ -21,13 +21,15 @@ class UseReduceTestCase(object):
146 self.flat = flat
147 self.is_valid_flag = is_valid_flag
148 self.token_class = token_class
149 + self.subset = subset
150 self.expected_result = expected_result
151
152 def run(self):
153 try:
154 return use_reduce(self.deparray, self.uselist, self.masklist,
155 self.matchall, self.excludeall, self.is_src_uri, self.eapi,
156 - self.opconvert, self.flat, self.is_valid_flag, self.token_class)
157 + self.opconvert, self.flat, self.is_valid_flag, self.token_class,
158 + subset=self.subset)
159 except InvalidDependString as e:
160 raise InvalidDependString("%s: %s" % (e, self.deparray))
161
162 @@ -50,6 +52,72 @@ class UseReduce(TestCase):
163 uselist=["a", "b", "c", "d"],
164 expected_result=["A", "B"]
165 ),
166 + UseReduceTestCase(
167 + "a? ( A ) b? ( B ) !c? ( C ) !d? ( D )",
168 + uselist=["a", "b", "c", "d"],
169 + subset=["b"],
170 + expected_result=["B"]
171 + ),
172 + UseReduceTestCase(
173 + "bar? ( || ( foo bar? ( baz ) ) )",
174 + uselist=["bar"],
175 + subset=["bar"],
176 + expected_result=['||', ['foo', 'baz']]
177 + ),
178 + UseReduceTestCase(
179 + "bar? ( foo bar? ( baz ) foo )",
180 + uselist=["bar"],
181 + subset=["bar"],
182 + expected_result=['foo', 'baz', 'foo']
183 + ),
184 + UseReduceTestCase(
185 + "|| ( ( a b ) ( c d ) )",
186 + uselist=[],
187 + subset=["bar"],
188 + expected_result=[]
189 + ),
190 + UseReduceTestCase(
191 + "|| ( ( a b ) ( bar? ( c d ) e f ) )",
192 + uselist=["bar"],
193 + subset=["bar"],
194 + expected_result=['c', 'd']
195 + ),
196 + UseReduceTestCase(
197 + "( a b ) ( c d bar? ( e f baz? ( g h ) ) )",
198 + uselist=["bar"],
199 + subset=["bar"],
200 + expected_result=['e', 'f']
201 + ),
202 + UseReduceTestCase(
203 + "( a b ) ( c d bar? ( e f baz? ( g h ) ) )",
204 + uselist=["bar", "baz"],
205 + subset=["bar"],
206 + expected_result=['e', 'f', 'g', 'h']
207 + ),
208 + UseReduceTestCase(
209 + "( bar? ( a b ) ( bar? ( c d ) ) ) ( e f )",
210 + uselist=["bar"],
211 + subset=["bar"],
212 + expected_result=['a', 'b', 'c', 'd']
213 + ),
214 + UseReduceTestCase(
215 + "|| ( foo bar? ( baz ) )",
216 + uselist=["bar"],
217 + subset=["bar"],
218 + expected_result=["baz"]
219 + ),
220 + UseReduceTestCase(
221 + "|| ( || ( bar? ( a || ( b c || ( d e ) ) ) ) )",
222 + uselist=["bar"],
223 + subset=["bar"],
224 + expected_result=['a', '||', ['b', 'c', 'd', 'e']]
225 + ),
226 + UseReduceTestCase(
227 + "|| ( || ( bar? ( a || ( ( b c ) ( d e ) ) ) ) )",
228 + uselist=["bar"],
229 + subset=["bar"],
230 + expected_result=['a', '||', [['b', 'c'], ['d', 'e']]]
231 + ),
232 UseReduceTestCase(
233 "a? ( A ) b? ( B ) !c? ( C ) !d? ( D )",
234 uselist=["a", "b", "c"],
235
236 diff --git a/lib/portage/tests/resolver/test_with_test_deps.py b/lib/portage/tests/resolver/test_with_test_deps.py
237 index 5bfc6a8a2..d88e3cb6e 100644
238 --- a/lib/portage/tests/resolver/test_with_test_deps.py
239 +++ b/lib/portage/tests/resolver/test_with_test_deps.py
240 @@ -21,7 +21,27 @@ class WithTestDepsTestCase(TestCase):
241 },
242 "app-misc/C-0": {
243 "EAPI": "5",
244 - }
245 + },
246 + "app-misc/D-0": {
247 + "EAPI": "5",
248 + "IUSE": "test",
249 + "DEPEND": "test? ( app-misc/E )"
250 + },
251 + "app-misc/E-0": {
252 + "EAPI": "5",
253 + "IUSE": "test",
254 + "DEPEND": "test? ( app-misc/D )"
255 + },
256 + "app-misc/F-0": {
257 + "EAPI": "5",
258 + "IUSE": "+test",
259 + "DEPEND": "test? ( app-misc/G )"
260 + },
261 + "app-misc/G-0": {
262 + "EAPI": "5",
263 + "IUSE": "+test",
264 + "DEPEND": "test? ( app-misc/F )"
265 + },
266 }
267
268 test_cases = (
269 @@ -32,6 +52,23 @@ class WithTestDepsTestCase(TestCase):
270 success = True,
271 options = { "--onlydeps": True, "--with-test-deps": True },
272 mergelist = ["app-misc/B-0"]),
273 +
274 + # Test that --with-test-deps allows circular dependencies.
275 + ResolverPlaygroundTestCase(
276 + ['app-misc/D'],
277 + success = True,
278 + options = {'--with-test-deps': True},
279 + mergelist = [('app-misc/D-0', 'app-misc/E-0')],
280 + ambiguous_merge_order=True),
281 +
282 + # Test that --with-test-deps does not allow circular dependencies
283 + # when USE=test is explicitly enabled.
284 + ResolverPlaygroundTestCase(
285 + ['app-misc/F'],
286 + success = False,
287 + options = {'--with-test-deps': True},
288 + circular_dependency_solutions = {'app-misc/G-0': {frozenset({('test', False)})}, 'app-misc/F-0': {frozenset({('test', False)})}},
289 + )
290 )
291
292 playground = ResolverPlayground(ebuilds=ebuilds, debug=False)