Add portage.dep.get_required_use_flags to extract the use flags used in a REQUIRED_US...
authorSebastian Luther <SebastianLuther@gmx.de>
Fri, 20 Aug 2010 07:19:17 +0000 (09:19 +0200)
committerZac Medico <zmedico@gentoo.org>
Fri, 20 Aug 2010 12:15:54 +0000 (05:15 -0700)
pym/portage/dep/__init__.py
pym/portage/tests/dep/test_get_required_use_flags.py [new file with mode: 0644]

index de688a16e3af6820a7a87207ab764ddad0bc38e3..5fa0f79fa22f05cc7cd5f810c52ff0d95e67d8cf 100644 (file)
@@ -1659,13 +1659,90 @@ def match_from_list(mydep, candidate_list):
                        mylist.append(x)
        return mylist
 
+
+def get_required_use_flags(required_use):
+       """
+       Returns a set of use flags that are used in the given REQUIRED_USE string
+
+       @param required_use: REQUIRED_USE string
+       @type required_use: String
+       @rtype: Set
+       @return: Set of use flags that are used in the given REQUIRED_USE string
+       """
+
+       mysplit = required_use.split()
+       level = 0
+       stack = [[]]
+       need_bracket = False
+
+       used_flags = set()
+
+       def register_token(token):
+               if token.endswith("?"):
+                       token = token[:-1]
+               if token.startswith("!"):
+                       token = token[1:]
+               used_flags.add(token)
+
+       for token in mysplit:
+               if token == "(":
+                       need_bracket = False
+                       stack.append([])
+                       level += 1
+               elif token == ")":
+                       if need_bracket:
+                               raise portage.exception.InvalidDependString(
+                                       _("malformed syntax: '%s'") % required_use)
+                       if level > 0:
+                               level -= 1
+                               l = stack.pop()
+                               ignore = False
+                               if stack[level]:
+                                       if stack[level][-1] in ("||", "^^") or \
+                                               (not isinstance(stack[level][-1], bool) and \
+                                               stack[level][-1][-1] == "?"):
+                                               ignore = True
+                                               stack[level].pop()
+                                               stack[level].append(True)
+
+                               if l and not ignore:
+                                       stack[level].append(all(x for x in l))
+                       else:
+                               raise portage.exception.InvalidDependString(
+                                       _("malformed syntax: '%s'") % required_use)
+               elif token in ("||", "^^"):
+                       if need_bracket:
+                               raise portage.exception.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:
+                               raise portage.exception.InvalidDependString(
+                                       _("malformed syntax: '%s'") % required_use)
+
+                       if token[-1] == "?":
+                               need_bracket = True
+                               stack[level].append(token)
+                       else:
+                               stack[level].append(True)
+                       
+                       register_token(token)
+
+       if level != 0 or need_bracket:
+               raise portage.exception.InvalidDependString(
+                       _("malformed syntax: '%s'") % required_use)
+
+       return frozenset(used_flags)
+
 def check_required_use(required_use, use, iuse_match):
        """
        Checks if the use flags listed in 'use' satisfy all
        constraints specified in 'constraints'.
 
-       @param constraints: REQUIRED_USE string
-       @type constraints: String
+       @param required_use: REQUIRED_USE string
+       @type required_use: String
        @param use: Enabled use flags
        @param use: List
        @param iuse_match: Callable that takes a single flag argument and returns
diff --git a/pym/portage/tests/dep/test_get_required_use_flags.py b/pym/portage/tests/dep/test_get_required_use_flags.py
new file mode 100644 (file)
index 0000000..06f8110
--- /dev/null
@@ -0,0 +1,42 @@
+# Copyright 2010 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from portage.tests import TestCase
+from portage.dep import get_required_use_flags
+from portage.exception import InvalidDependString
+
+class TestCheckRequiredUse(TestCase):
+
+       def testCheckRequiredUse(self):
+               test_cases = (
+                       ("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"]),
+
+                       ("( ^^ ( a ( b ) ( || ( ( d e ) ( f ) ) ) ) )", ["a", "b", "d", "e", "f"]),
+
+                       ("a? ( ^^ ( b c ) )", ["a", "b", "c"]),
+                       ("a? ( ^^ ( !b !d? ( c ) ) )", ["a", "b", "c", "d"]),
+               )
+
+               test_cases_xfail = (
+                       ("^^ ( || ( a b ) ^^ ( b c )"),
+                       ("^^( || ( a b ) ^^ ( b c ) )"),
+                       ("^^ || ( a b ) ^^ ( b c )"),
+                       ("^^ ( ( || ) ( a b ) ^^ ( b c ) )"),
+                       ("^^ ( || ( a b ) ) ^^ ( b c ) )"),
+               )
+
+               for required_use, expected in test_cases:
+                       result = get_required_use_flags(required_use)
+                       expected = set(expected)
+                       self.assertEqual(result, expected, \
+                               "REQUIRED_USE: '%s', expected: '%s', got: '%s'" % (required_use, expected, result))
+
+               for required_use in test_cases_xfail:
+                       self.assertRaisesMsg("REQUIRED_USE: '%s'" % (required_use,), \
+                               InvalidDependString, get_required_use_flags, required_use)