noiselevel=-1)
writemsg_stdout("\n The following REQUIRED_USE flag constraints " + \
"are unsatisfied:\n", noiselevel=-1)
+ reduced_noise = check_required_use(
+ pkg.metadata["REQUIRED_USE"],
+ self._pkg_use_enabled(pkg),
+ pkg.iuse.is_valid_flag).tounicode()
writemsg_stdout(" %s\n" % \
- human_readable_required_use(pkg.metadata["REQUIRED_USE"]),
+ human_readable_required_use(reduced_noise),
noiselevel=-1)
+ normalized_required_use = \
+ " ".join(pkg.metadata["REQUIRED_USE"].split())
+ if reduced_noise != normalized_required_use:
+ writemsg_stdout("\n The above constraints " + \
+ "are a subset of the following complete expression:\n",
+ noiselevel=-1)
+ writemsg_stdout(" %s\n" % \
+ human_readable_required_use(normalized_required_use),
+ noiselevel=-1)
writemsg_stdout("\n", noiselevel=-1)
elif show_missing_use:
return frozenset(used_flags)
+class _RequiredUseLeaf(object):
+
+ __slots__ = ('_satisfied', '_token')
+
+ def __init__(self, token, satisfied):
+ self._token = token
+ self._satisfied = satisfied
+
+ def tounicode(self):
+ return self._token
+
+class _RequiredUseBranch(object):
+
+ __slots__ = ('_children', '_operator', '_parent', '_satisfied')
+
+ def __init__(self, operator=None, parent=None):
+ self._children = []
+ self._operator = operator
+ self._parent = parent
+ self._satisfied = False
+
+ def __bool__(self):
+ return self._satisfied
+
+ def tounicode(self):
+
+ tokens = []
+ if self._operator is not None:
+ tokens.append(self._operator)
+
+ if self._parent is not None:
+ tokens.append("(")
+
+ complex_nesting = False
+ node = self
+ while node != None and not complex_nesting:
+ if node._operator in ("||", "^^"):
+ complex_nesting = True
+ else:
+ node = node._parent
+
+ if complex_nesting:
+ for child in self._children:
+ tokens.append(child.tounicode())
+ else:
+ for child in self._children:
+ if not child._satisfied:
+ tokens.append(child.tounicode())
+
+ if self._parent is not None:
+ tokens.append(")")
+
+ return " ".join(tokens)
+
+ if sys.hexversion < 0x3000000:
+ __nonzero__ = __bool__
+
def check_required_use(required_use, use, iuse_match):
"""
Checks if the use flags listed in 'use' satisfy all
mysplit = required_use.split()
level = 0
stack = [[]]
+ tree = _RequiredUseBranch()
+ node = tree
need_bracket = False
for token in mysplit:
if token == "(":
+ if not need_bracket:
+ child = _RequiredUseBranch(parent=node)
+ node._children.append(child)
+ node = child
+
need_bracket = False
stack.append([])
level += 1
if stack[level][-1] in ("||", "^^"):
ignore = True
op = stack[level].pop()
- stack[level].append(is_satisfied(op, l))
+ satisfied = is_satisfied(op, l)
+ stack[level].append(satisfied)
+ node._satisfied = satisfied
elif not isinstance(stack[level][-1], bool) and \
stack[level][-1][-1] == "?":
if is_active(stack[level][-1][:-1]):
op = stack[level].pop()
- stack[level].append(is_satisfied(op, l))
+ satisfied = is_satisfied(op, l)
+ stack[level].append(satisfied)
+ node._satisfied = satisfied
else:
stack[level].pop()
+ node._satisfied = True
ignore = True
if l and not ignore:
- stack[level].append(all(x for x in l))
+ satisfied = False not in l
+ stack[level].append(satisfied)
+ node._satisfied = satisfied
+
+ node = node._parent
else:
raise InvalidDependString(
_("malformed syntax: '%s'") % required_use)
_("malformed syntax: '%s'") % required_use)
need_bracket = True
stack[level].append(token)
+ child = _RequiredUseBranch(operator=token, parent=node)
+ node._children.append(child)
+ node = child
else:
if need_bracket or "(" in token or ")" in token or \
"|" in token or "^" in token:
if token[-1] == "?":
need_bracket = True
stack[level].append(token)
+ child = _RequiredUseBranch(operator=token, parent=node)
+ node._children.append(child)
+ node = child
else:
- stack[level].append(is_active(token))
+ satisfied = is_active(token)
+ stack[level].append(satisfied)
+ node._children.append(_RequiredUseLeaf(token, satisfied))
if level != 0 or need_bracket:
raise InvalidDependString(
_("malformed syntax: '%s'") % required_use)
- return (False not in stack[0])
+ tree._satisfied = False not in stack[0]
+ return tree
def extract_affecting_use(mystr, atom):
"""
-# Copyright 2010 Gentoo Foundation
+# Copyright 2010-2011 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2
from portage.tests import TestCase
)
for required_use, use, iuse, expected in test_cases:
- self.assertEqual(check_required_use(required_use, use, iuse.__contains__), \
+ self.assertEqual(bool(check_required_use(required_use, use, iuse.__contains__)), \
expected, required_use + ", USE = " + " ".join(use))
for required_use, use, iuse in test_cases_xfail:
self.assertRaisesMsg(required_use + ", USE = " + " ".join(use), \
InvalidDependString, check_required_use, required_use, use, iuse.__contains__)
+
+ def testCheckRequiredUseFilterSatisfied(self):
+ """
+ Test filtering of satisfied parts of REQUIRED_USE,
+ in order to reduce noise for bug #353234.
+ """
+ test_cases = (
+ (
+ "bindist? ( !amr !faac !win32codecs ) cdio? ( !cdparanoia !cddb ) dvdnav? ( dvd )",
+ ("cdio", "cdparanoia"),
+ "cdio? ( !cdparanoia )"
+ ),
+ (
+ "|| ( !amr !faac !win32codecs ) cdio? ( !cdparanoia !cddb ) ^^ ( foo bar )",
+ ["cdio", "cdparanoia", "foo"],
+ "cdio? ( !cdparanoia )"
+ ),
+ (
+ "^^ ( || ( a b ) c )",
+ ("a", "b", "c"),
+ "^^ ( || ( a b ) c )"
+ ),
+ (
+ "^^ ( || ( ( a b ) ) ( c ) )",
+ ("a", "b", "c"),
+ "^^ ( || ( ( a b ) ) ( c ) )"
+ )
+ )
+ for required_use, use, expected in test_cases:
+ result = check_required_use(required_use, use, lambda k: True).tounicode()
+ self.assertEqual(result, expected,
+ "REQUIRED_USE = '%s', USE = '%s', '%s' != '%s'" % \
+ (required_use, " ".join(use), result, expected))