public inbox for gentoo-commits@lists.gentoo.org
 help / color / mirror / Atom feed
* [gentoo-commits] proj/portage:master commit in: bin/, pym/portage/, pym/portage/dep/, pym/portage/tests/dep/, pym/_emerge/
@ 2012-08-27 22:17 Zac Medico
  0 siblings, 0 replies; only message in thread
From: Zac Medico @ 2012-08-27 22:17 UTC (permalink / raw
  To: gentoo-commits

commit:     ac843c3df2210566b559dc57c5fb657e20933a58
Author:     Zac Medico <zmedico <AT> gentoo <DOT> org>
AuthorDate: Mon Aug 27 22:13:29 2012 +0000
Commit:     Zac Medico <zmedico <AT> gentoo <DOT> org>
CommitDate: Mon Aug 27 22:13:29 2012 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/portage.git;a=commit;h=ac843c3d

EAPI 5: REQUIRED_USE at-most-one-of ?? operator

See bug #354219 and the PMS patch:
http://git.overlays.gentoo.org/gitweb/?p=proj/pms.git;a=commit;h=1c2dff2df2305aff88a734e3a2716de1bb69f3b6

---
 bin/repoman                                        |    2 +-
 pym/_emerge/Package.py                             |    2 +-
 pym/portage/dep/__init__.py                        |   47 +++++++++++++------
 pym/portage/eapi.py                                |    6 ++-
 pym/portage/tests/dep/testCheckRequiredUse.py      |   16 ++++++-
 .../tests/dep/test_get_required_use_flags.py       |    4 +-
 6 files changed, 57 insertions(+), 20 deletions(-)

diff --git a/bin/repoman b/bin/repoman
index b50fac8..dd065c8 100755
--- a/bin/repoman
+++ b/bin/repoman
@@ -2028,7 +2028,7 @@ for x in effective_scanlist:
 					" 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(

diff --git a/pym/_emerge/Package.py b/pym/_emerge/Package.py
index 85fc597..2087cbf 100644
--- a/pym/_emerge/Package.py
+++ b/pym/_emerge/Package.py
@@ -228,7 +228,7 @@ class Package(Task):
 			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

diff --git a/pym/portage/dep/__init__.py b/pym/portage/dep/__init__.py
index e547deb..b7bb46f 100644
--- a/pym/portage/dep/__init__.py
+++ b/pym/portage/dep/__init__.py
@@ -2314,9 +2314,9 @@ def match_from_list(mydep, candidate_list):
 	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
 
@@ -2326,6 +2326,12 @@ def get_required_use_flags(required_use):
 	@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 = [[]]
@@ -2354,7 +2360,7 @@ def get_required_use_flags(required_use):
 				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
@@ -2366,15 +2372,14 @@ def get_required_use_flags(required_use):
 			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)
 
@@ -2429,7 +2434,7 @@ class _RequiredUseBranch(object):
 		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
@@ -2450,7 +2455,7 @@ class _RequiredUseBranch(object):
 	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'.
@@ -2466,6 +2471,12 @@ def check_required_use(required_use, use, iuse_match):
 	@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:]
@@ -2475,6 +2486,11 @@ def check_required_use(required_use, use, iuse_match):
 			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')
@@ -2492,6 +2508,8 @@ def check_required_use(required_use, use, iuse_match):
 			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)
 
@@ -2521,7 +2539,7 @@ def check_required_use(required_use, use, iuse_match):
 				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)
@@ -2550,7 +2568,7 @@ def check_required_use(required_use, use, iuse_match):
 						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(
@@ -2566,7 +2584,7 @@ def check_required_use(required_use, use, iuse_match):
 						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(
@@ -2576,7 +2594,7 @@ def check_required_use(required_use, use, iuse_match):
 						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(
@@ -2590,7 +2608,7 @@ def check_required_use(required_use, use, iuse_match):
 			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)
@@ -2600,8 +2618,7 @@ def check_required_use(required_use, use, iuse_match):
 			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)
 

diff --git a/pym/portage/eapi.py b/pym/portage/eapi.py
index a5ef301..b701d02 100644
--- a/pym/portage/eapi.py
+++ b/pym/portage/eapi.py
@@ -56,6 +56,9 @@ def eapi_has_dosed_dohard(eapi):
 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")
 
@@ -70,7 +73,7 @@ def eapi_allows_dots_in_use_flags(eapi):
 
 _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 = {}
@@ -97,6 +100,7 @@ def _get_eapi_attrs(eapi):
 		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)),

diff --git a/pym/portage/tests/dep/testCheckRequiredUse.py b/pym/portage/tests/dep/testCheckRequiredUse.py
index 54791e0..d85ad92 100644
--- a/pym/portage/tests/dep/testCheckRequiredUse.py
+++ b/pym/portage/tests/dep/testCheckRequiredUse.py
@@ -1,4 +1,4 @@
-# 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
@@ -18,6 +18,11 @@ class TestCheckRequiredUse(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),
@@ -102,6 +107,10 @@ class TestCheckRequiredUse(TestCase):
 			( "^^ ( || ( 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))
@@ -110,6 +119,11 @@ class TestCheckRequiredUse(TestCase):
 			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,

diff --git a/pym/portage/tests/dep/test_get_required_use_flags.py b/pym/portage/tests/dep/test_get_required_use_flags.py
index 06f8110..90e096c 100644
--- a/pym/portage/tests/dep/test_get_required_use_flags.py
+++ b/pym/portage/tests/dep/test_get_required_use_flags.py
@@ -1,4 +1,4 @@
-# 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
@@ -13,6 +13,8 @@ class TestCheckRequiredUse(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"]),


^ permalink raw reply related	[flat|nested] only message in thread

only message in thread, other threads:[~2012-08-27 22:17 UTC | newest]

Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2012-08-27 22:17 [gentoo-commits] proj/portage:master commit in: bin/, pym/portage/, pym/portage/dep/, pym/portage/tests/dep/, pym/_emerge/ Zac Medico

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox