1 |
commit: c9ed39f98c62760333c9fe4d4ef5b8caa06a9e16 |
2 |
Author: Zac Medico <zmedico <AT> gentoo <DOT> org> |
3 |
AuthorDate: Thu Feb 3 23:29:50 2011 +0000 |
4 |
Commit: Fabian Groffen <grobian <AT> gentoo <DOT> org> |
5 |
CommitDate: Thu Feb 3 23:29:50 2011 +0000 |
6 |
URL: http://git.overlays.gentoo.org/gitweb/?p=proj/portage.git;a=commit;h=c9ed39f9 |
7 |
|
8 |
REQUIRED_USE: display unsatisfied part |
9 |
|
10 |
This will fix bug #353234. |
11 |
|
12 |
--- |
13 |
pym/_emerge/depgraph.py | 15 ++++- |
14 |
pym/portage/dep/__init__.py | 92 +++++++++++++++++++++++-- |
15 |
pym/portage/tests/dep/testCheckRequiredUse.py | 37 +++++++++- |
16 |
3 files changed, 136 insertions(+), 8 deletions(-) |
17 |
|
18 |
diff --git a/pym/_emerge/depgraph.py b/pym/_emerge/depgraph.py |
19 |
index 8f04c44..811eda6 100644 |
20 |
--- a/pym/_emerge/depgraph.py |
21 |
+++ b/pym/_emerge/depgraph.py |
22 |
@@ -2593,9 +2593,22 @@ class depgraph(object): |
23 |
noiselevel=-1) |
24 |
writemsg_stdout("\n The following REQUIRED_USE flag constraints " + \ |
25 |
"are unsatisfied:\n", noiselevel=-1) |
26 |
+ reduced_noise = check_required_use( |
27 |
+ pkg.metadata["REQUIRED_USE"], |
28 |
+ self._pkg_use_enabled(pkg), |
29 |
+ pkg.iuse.is_valid_flag).tounicode() |
30 |
writemsg_stdout(" %s\n" % \ |
31 |
- human_readable_required_use(pkg.metadata["REQUIRED_USE"]), |
32 |
+ human_readable_required_use(reduced_noise), |
33 |
noiselevel=-1) |
34 |
+ normalized_required_use = \ |
35 |
+ " ".join(pkg.metadata["REQUIRED_USE"].split()) |
36 |
+ if reduced_noise != normalized_required_use: |
37 |
+ writemsg_stdout("\n The above constraints " + \ |
38 |
+ "are a subset of the following complete expression:\n", |
39 |
+ noiselevel=-1) |
40 |
+ writemsg_stdout(" %s\n" % \ |
41 |
+ human_readable_required_use(normalized_required_use), |
42 |
+ noiselevel=-1) |
43 |
writemsg_stdout("\n", noiselevel=-1) |
44 |
|
45 |
elif show_missing_use: |
46 |
|
47 |
diff --git a/pym/portage/dep/__init__.py b/pym/portage/dep/__init__.py |
48 |
index ad68815..7e9a18a 100644 |
49 |
--- a/pym/portage/dep/__init__.py |
50 |
+++ b/pym/portage/dep/__init__.py |
51 |
@@ -2062,6 +2062,63 @@ def get_required_use_flags(required_use): |
52 |
|
53 |
return frozenset(used_flags) |
54 |
|
55 |
+class _RequiredUseLeaf(object): |
56 |
+ |
57 |
+ __slots__ = ('_satisfied', '_token') |
58 |
+ |
59 |
+ def __init__(self, token, satisfied): |
60 |
+ self._token = token |
61 |
+ self._satisfied = satisfied |
62 |
+ |
63 |
+ def tounicode(self): |
64 |
+ return self._token |
65 |
+ |
66 |
+class _RequiredUseBranch(object): |
67 |
+ |
68 |
+ __slots__ = ('_children', '_operator', '_parent', '_satisfied') |
69 |
+ |
70 |
+ def __init__(self, operator=None, parent=None): |
71 |
+ self._children = [] |
72 |
+ self._operator = operator |
73 |
+ self._parent = parent |
74 |
+ self._satisfied = False |
75 |
+ |
76 |
+ def __bool__(self): |
77 |
+ return self._satisfied |
78 |
+ |
79 |
+ def tounicode(self): |
80 |
+ |
81 |
+ tokens = [] |
82 |
+ if self._operator is not None: |
83 |
+ tokens.append(self._operator) |
84 |
+ |
85 |
+ if self._parent is not None: |
86 |
+ tokens.append("(") |
87 |
+ |
88 |
+ complex_nesting = False |
89 |
+ node = self |
90 |
+ while node != None and not complex_nesting: |
91 |
+ if node._operator in ("||", "^^"): |
92 |
+ complex_nesting = True |
93 |
+ else: |
94 |
+ node = node._parent |
95 |
+ |
96 |
+ if complex_nesting: |
97 |
+ for child in self._children: |
98 |
+ tokens.append(child.tounicode()) |
99 |
+ else: |
100 |
+ for child in self._children: |
101 |
+ if not child._satisfied: |
102 |
+ tokens.append(child.tounicode()) |
103 |
+ |
104 |
+ if self._parent is not None: |
105 |
+ tokens.append(")") |
106 |
+ |
107 |
+ return " ".join(tokens) |
108 |
+ |
109 |
+ if sys.hexversion < 0x3000000: |
110 |
+ __nonzero__ = __bool__ |
111 |
+ |
112 |
def check_required_use(required_use, use, iuse_match): |
113 |
""" |
114 |
Checks if the use flags listed in 'use' satisfy all |
115 |
@@ -2108,10 +2165,17 @@ def check_required_use(required_use, use, iuse_match): |
116 |
mysplit = required_use.split() |
117 |
level = 0 |
118 |
stack = [[]] |
119 |
+ tree = _RequiredUseBranch() |
120 |
+ node = tree |
121 |
need_bracket = False |
122 |
|
123 |
for token in mysplit: |
124 |
if token == "(": |
125 |
+ if not need_bracket: |
126 |
+ child = _RequiredUseBranch(parent=node) |
127 |
+ node._children.append(child) |
128 |
+ node = child |
129 |
+ |
130 |
need_bracket = False |
131 |
stack.append([]) |
132 |
level += 1 |
133 |
@@ -2127,18 +2191,27 @@ def check_required_use(required_use, use, iuse_match): |
134 |
if stack[level][-1] in ("||", "^^"): |
135 |
ignore = True |
136 |
op = stack[level].pop() |
137 |
- stack[level].append(is_satisfied(op, l)) |
138 |
+ satisfied = is_satisfied(op, l) |
139 |
+ stack[level].append(satisfied) |
140 |
+ node._satisfied = satisfied |
141 |
elif not isinstance(stack[level][-1], bool) and \ |
142 |
stack[level][-1][-1] == "?": |
143 |
if is_active(stack[level][-1][:-1]): |
144 |
op = stack[level].pop() |
145 |
- stack[level].append(is_satisfied(op, l)) |
146 |
+ satisfied = is_satisfied(op, l) |
147 |
+ stack[level].append(satisfied) |
148 |
+ node._satisfied = satisfied |
149 |
else: |
150 |
stack[level].pop() |
151 |
+ node._satisfied = True |
152 |
ignore = True |
153 |
|
154 |
if l and not ignore: |
155 |
- stack[level].append(all(x for x in l)) |
156 |
+ satisfied = False not in l |
157 |
+ stack[level].append(satisfied) |
158 |
+ node._satisfied = satisfied |
159 |
+ |
160 |
+ node = node._parent |
161 |
else: |
162 |
raise InvalidDependString( |
163 |
_("malformed syntax: '%s'") % required_use) |
164 |
@@ -2148,6 +2221,9 @@ def check_required_use(required_use, use, iuse_match): |
165 |
_("malformed syntax: '%s'") % required_use) |
166 |
need_bracket = True |
167 |
stack[level].append(token) |
168 |
+ child = _RequiredUseBranch(operator=token, parent=node) |
169 |
+ node._children.append(child) |
170 |
+ node = child |
171 |
else: |
172 |
if need_bracket or "(" in token or ")" in token or \ |
173 |
"|" in token or "^" in token: |
174 |
@@ -2157,14 +2233,20 @@ def check_required_use(required_use, use, iuse_match): |
175 |
if token[-1] == "?": |
176 |
need_bracket = True |
177 |
stack[level].append(token) |
178 |
+ child = _RequiredUseBranch(operator=token, parent=node) |
179 |
+ node._children.append(child) |
180 |
+ node = child |
181 |
else: |
182 |
- stack[level].append(is_active(token)) |
183 |
+ satisfied = is_active(token) |
184 |
+ stack[level].append(satisfied) |
185 |
+ node._children.append(_RequiredUseLeaf(token, satisfied)) |
186 |
|
187 |
if level != 0 or need_bracket: |
188 |
raise InvalidDependString( |
189 |
_("malformed syntax: '%s'") % required_use) |
190 |
|
191 |
- return (False not in stack[0]) |
192 |
+ tree._satisfied = False not in stack[0] |
193 |
+ return tree |
194 |
|
195 |
def extract_affecting_use(mystr, atom): |
196 |
""" |
197 |
|
198 |
diff --git a/pym/portage/tests/dep/testCheckRequiredUse.py b/pym/portage/tests/dep/testCheckRequiredUse.py |
199 |
index 4b67d62..0f7a299 100644 |
200 |
--- a/pym/portage/tests/dep/testCheckRequiredUse.py |
201 |
+++ b/pym/portage/tests/dep/testCheckRequiredUse.py |
202 |
@@ -1,4 +1,4 @@ |
203 |
-# Copyright 2010 Gentoo Foundation |
204 |
+# Copyright 2010-2011 Gentoo Foundation |
205 |
# Distributed under the terms of the GNU General Public License v2 |
206 |
|
207 |
from portage.tests import TestCase |
208 |
@@ -103,9 +103,42 @@ class TestCheckRequiredUse(TestCase): |
209 |
) |
210 |
|
211 |
for required_use, use, iuse, expected in test_cases: |
212 |
- self.assertEqual(check_required_use(required_use, use, iuse.__contains__), \ |
213 |
+ self.assertEqual(bool(check_required_use(required_use, use, iuse.__contains__)), \ |
214 |
expected, required_use + ", USE = " + " ".join(use)) |
215 |
|
216 |
for required_use, use, iuse in test_cases_xfail: |
217 |
self.assertRaisesMsg(required_use + ", USE = " + " ".join(use), \ |
218 |
InvalidDependString, check_required_use, required_use, use, iuse.__contains__) |
219 |
+ |
220 |
+ def testCheckRequiredUseFilterSatisfied(self): |
221 |
+ """ |
222 |
+ Test filtering of satisfied parts of REQUIRED_USE, |
223 |
+ in order to reduce noise for bug #353234. |
224 |
+ """ |
225 |
+ test_cases = ( |
226 |
+ ( |
227 |
+ "bindist? ( !amr !faac !win32codecs ) cdio? ( !cdparanoia !cddb ) dvdnav? ( dvd )", |
228 |
+ ("cdio", "cdparanoia"), |
229 |
+ "cdio? ( !cdparanoia )" |
230 |
+ ), |
231 |
+ ( |
232 |
+ "|| ( !amr !faac !win32codecs ) cdio? ( !cdparanoia !cddb ) ^^ ( foo bar )", |
233 |
+ ["cdio", "cdparanoia", "foo"], |
234 |
+ "cdio? ( !cdparanoia )" |
235 |
+ ), |
236 |
+ ( |
237 |
+ "^^ ( || ( a b ) c )", |
238 |
+ ("a", "b", "c"), |
239 |
+ "^^ ( || ( a b ) c )" |
240 |
+ ), |
241 |
+ ( |
242 |
+ "^^ ( || ( ( a b ) ) ( c ) )", |
243 |
+ ("a", "b", "c"), |
244 |
+ "^^ ( || ( ( a b ) ) ( c ) )" |
245 |
+ ) |
246 |
+ ) |
247 |
+ for required_use, use, expected in test_cases: |
248 |
+ result = check_required_use(required_use, use, lambda k: True).tounicode() |
249 |
+ self.assertEqual(result, expected, |
250 |
+ "REQUIRED_USE = '%s', USE = '%s', '%s' != '%s'" % \ |
251 |
+ (required_use, " ".join(use), result, expected)) |