" not supported with EAPI='%s'" % (eapi,))
try:
portage.dep.check_required_use(required_use, (),
- pkg.iuse.is_valid_flag)
+ pkg.iuse.is_valid_flag, eapi=eapi)
except portage.exception.InvalidDependString as e:
stats["REQUIRED_USE.syntax"] = stats["REQUIRED_USE.syntax"] + 1
fails["REQUIRED_USE.syntax"].append(
else:
try:
check_required_use(v, (),
- self.iuse.is_valid_flag)
+ self.iuse.is_valid_flag, eapi=eapi)
except InvalidDependString as e:
# Force unicode format string for python-2.x safety,
# ensuring that PortageException.__unicode__() is used
return mylist
def human_readable_required_use(required_use):
- return required_use.replace("^^", "exactly-one-of").replace("||", "any-of")
+ return required_use.replace("^^", "exactly-one-of").replace("||", "any-of").replace("??", "at-most-one-of")
-def get_required_use_flags(required_use):
+def get_required_use_flags(required_use, eapi=None):
"""
Returns a set of use flags that are used in the given REQUIRED_USE string
@return: Set of use flags that are used in the given REQUIRED_USE string
"""
+ eapi_attrs = _get_eapi_attrs(eapi)
+ if eapi_attrs.required_use_at_most_one_of:
+ valid_operators = ("||", "^^", "??")
+ else:
+ valid_operators = ("||", "^^")
+
mysplit = required_use.split()
level = 0
stack = [[]]
l = stack.pop()
ignore = False
if stack[level]:
- if stack[level][-1] in ("||", "^^") or \
+ if stack[level][-1] in valid_operators or \
(not isinstance(stack[level][-1], bool) and \
stack[level][-1][-1] == "?"):
ignore = True
else:
raise InvalidDependString(
_("malformed syntax: '%s'") % required_use)
- elif token in ("||", "^^"):
+ elif token in valid_operators:
if need_bracket:
raise InvalidDependString(
_("malformed syntax: '%s'") % required_use)
need_bracket = True
stack[level].append(token)
else:
- if need_bracket or "(" in token or ")" in token or \
- "|" in token or "^" in token:
+ if need_bracket:
raise InvalidDependString(
_("malformed syntax: '%s'") % required_use)
complex_nesting = False
node = self
while node != None and not complex_nesting:
- if node._operator in ("||", "^^"):
+ if node._operator in ("||", "^^", "??"):
complex_nesting = True
else:
node = node._parent
if sys.hexversion < 0x3000000:
__nonzero__ = __bool__
-def check_required_use(required_use, use, iuse_match):
+def check_required_use(required_use, use, iuse_match, eapi=None):
"""
Checks if the use flags listed in 'use' satisfy all
constraints specified in 'constraints'.
@return: Indicates if REQUIRED_USE constraints are satisfied
"""
+ eapi_attrs = _get_eapi_attrs(eapi)
+ if eapi_attrs.required_use_at_most_one_of:
+ valid_operators = ("||", "^^", "??")
+ else:
+ valid_operators = ("||", "^^")
+
def is_active(token):
if token.startswith("!"):
flag = token[1:]
is_negated = False
if not flag or not iuse_match(flag):
+ if not eapi_attrs.required_use_at_most_one_of and flag == "?":
+ msg = _("Operator '??' is not supported with EAPI '%s'") \
+ % (eapi,)
+ e = InvalidData(msg, category='EAPI.incompatible')
+ raise InvalidDependString(msg, errors=(e,))
msg = _("USE flag '%s' is not in IUSE") \
% (flag,)
e = InvalidData(msg, category='IUSE.missing')
return (True in argument)
elif operator == "^^":
return (argument.count(True) == 1)
+ elif operator == "??":
+ return (argument.count(True) <= 1)
elif operator[-1] == "?":
return (False not in argument)
l = stack.pop()
op = None
if stack[level]:
- if stack[level][-1] in ("||", "^^"):
+ if stack[level][-1] in valid_operators:
op = stack[level].pop()
satisfied = is_satisfied(op, l)
stack[level].append(satisfied)
stack[level].append(satisfied)
if len(node._children) <= 1 or \
- node._parent._operator not in ("||", "^^"):
+ node._parent._operator not in valid_operators:
last_node = node._parent._children.pop()
if last_node is not node:
raise AssertionError(
raise AssertionError(
"node is not last child of parent")
- elif len(node._children) == 1 and op in ("||", "^^"):
+ elif len(node._children) == 1 and op in valid_operators:
last_node = node._parent._children.pop()
if last_node is not node:
raise AssertionError(
node._children[0]._parent = node._parent
node = node._children[0]
if node._operator is None and \
- node._parent._operator not in ("||", "^^"):
+ node._parent._operator not in valid_operators:
last_node = node._parent._children.pop()
if last_node is not node:
raise AssertionError(
else:
raise InvalidDependString(
_("malformed syntax: '%s'") % required_use)
- elif token in ("||", "^^"):
+ elif token in valid_operators:
if need_bracket:
raise InvalidDependString(
_("malformed syntax: '%s'") % required_use)
node._children.append(child)
node = child
else:
- if need_bracket or "(" in token or ")" in token or \
- "|" in token or "^" in token:
+ if need_bracket:
raise InvalidDependString(
_("malformed syntax: '%s'") % required_use)
def eapi_has_required_use(eapi):
return eapi not in ("0", "1", "2", "3")
+def eapi_has_required_use_at_most_one_of(eapi):
+ return eapi not in ("0", "1", "2", "3", "4", "4-python", "4-slot-abi")
+
def eapi_has_use_dep_defaults(eapi):
return eapi not in ("0", "1", "2", "3")
_eapi_attrs = collections.namedtuple('_eapi_attrs',
'dots_in_PN dots_in_use_flags iuse_defaults '
- 'repo_deps required_use slot_abi slot_deps '
+ 'repo_deps required_use required_use_at_most_one_of slot_abi slot_deps '
'src_uri_arrows strong_blocks use_deps use_dep_defaults')
_eapi_attrs_cache = {}
iuse_defaults = (eapi is None or eapi_has_iuse_defaults(eapi)),
repo_deps = (eapi is None or eapi_has_repo_deps(eapi)),
required_use = (eapi is None or eapi_has_required_use(eapi)),
+ required_use_at_most_one_of = (eapi is None or eapi_has_required_use_at_most_one_of(eapi)),
slot_deps = (eapi is None or eapi_has_slot_deps(eapi)),
slot_abi = (eapi is None or eapi_has_slot_abi(eapi)),
src_uri_arrows = (eapi is None or eapi_has_src_uri_arrows(eapi)),
-# Copyright 2010-2011 Gentoo Foundation
+# Copyright 2010-2012 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2
from portage.tests import TestCase
( "^^ ( a b )", ["a"], ["a", "b"], True),
( "^^ ( a b )", ["b"], ["a", "b"], True),
( "^^ ( a b )", ["a", "b"], ["a", "b"], False),
+ ( "?? ( a b )", ["a", "b"], ["a", "b"], False),
+ ( "?? ( a b )", ["a"], ["a", "b"], True),
+ ( "?? ( a b )", ["b"], ["a", "b"], True),
+ ( "?? ( a b )", [], ["a", "b"], True),
+ ( "?? ( )", [], [], True),
( "^^ ( || ( a b ) c )", [], ["a", "b", "c"], False),
( "^^ ( || ( a b ) c )", ["a"], ["a", "b", "c"], True),
( "^^ ( || ( a b ) ) ^^ ( b c ) )", [], ["a", "b", "c"]),
)
+ test_cases_xfail_eapi = (
+ ( "?? ( a b )", [], ["a", "b"], "4"),
+ )
+
for required_use, use, iuse, expected in test_cases:
self.assertEqual(bool(check_required_use(required_use, use, iuse.__contains__)), \
expected, required_use + ", USE = " + " ".join(use))
self.assertRaisesMsg(required_use + ", USE = " + " ".join(use), \
InvalidDependString, check_required_use, required_use, use, iuse.__contains__)
+ for required_use, use, iuse, eapi in test_cases_xfail_eapi:
+ self.assertRaisesMsg(required_use + ", USE = " + " ".join(use), \
+ InvalidDependString, check_required_use, required_use, use,
+ iuse.__contains__, eapi=eapi)
+
def testCheckRequiredUseFilterSatisfied(self):
"""
Test filtering of satisfied parts of REQUIRED_USE,
-# Copyright 2010 Gentoo Foundation
+# Copyright 2010-2012 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2
from portage.tests import TestCase
("|| ( a b c )", ["a", "b", "c"]),
("^^ ( a b c )", ["a", "b", "c"]),
+ ("?? ( a b c )", ["a", "b", "c"]),
+ ("?? ( )", []),
("|| ( a b ^^ ( d e f ) )", ["a", "b", "d", "e", "f"]),
("^^ ( a b || ( d e f ) )", ["a", "b", "d", "e", "f"]),