Implement new conditional USE dep syntax:
authorZac Medico <zmedico@gentoo.org>
Mon, 28 Jul 2008 05:52:08 +0000 (05:52 -0000)
committerZac Medico <zmedico@gentoo.org>
Mon, 28 Jul 2008 05:52:08 +0000 (05:52 -0000)
Conditional evaluation behavior:

parent state   conditional   result

 x              x?            x
-x              x?
 x             -x?
-x             -x?           -x

 x              x=            x
-x              x=           -x
 x             x!=           -x
-x             x!=            x

Conditional syntax examples:

compact form         equivalent expanded form

 foo[bar?]           foo  bar? (  foo[bar] )
foo[-bar?]           foo !bar? ( foo[-bar] )
 foo[bar=]           foo  bar? (  foo[bar] ) !bar? ( foo[-bar] )
 foo[bar!=]          foo  bar? ( foo[-bar] ) !bar? (  foo[bar] )

svn path=/main/trunk/; revision=11231

pym/portage/dep.py
pym/portage/tests/dep/test_isvalidatom.py

index 15000dd841b883b3e6836ed367828e6805294bac..aa1057d82e914bcd7c917e2a4f6c5f48a6555760 100644 (file)
@@ -24,6 +24,7 @@ from itertools import chain
 import portage.exception
 from portage.exception import InvalidData, InvalidAtom
 from portage.versions import catpkgsplit, catsplit, pkgcmp, pkgsplit, ververify
+import portage.cache.mappings
 
 def cpvequal(cpv1, cpv2):
        """
@@ -343,54 +344,101 @@ class _use_dep(object):
        __slots__ = ("__weakref__", "conditional", "conditional_disabled",
                "conditional_enabled", "disabled", "enabled", "tokens", "required")
 
+       _conditionals_class = portage.cache.mappings.slot_dict_class(
+               ("disabled", "enabled", "equal", "not_equal"), prefix="")
+
        def __init__(self, use):
                enabled_flags = []
                disabled_flags = []
-               conditional_enabled = []
-               conditional_disabled = []
+               conditional = self._conditionals_class()
+               for k in conditional.allowed_keys:
+                       conditional[k] = []
+
                for x in use:
-                       if "-" == x[:1]:
-                               if "?" == x[-1:]:
-                                       conditional_disabled.append(x[1:-1])
+                       last_char = x[-1:]
+                       if "?" == last_char:
+                               if "-" == x[:1]:
+                                       conditional.disabled.append(x[1:-1])
                                else:
-                                       disabled_flags.append(x[1:])
+                                       conditional.enabled.append(x[:-1])
+                       elif "=" == last_char:
+                               if "-" == x[:1]:
+                                       raise InvalidAtom("Invalid use dep: '%s'" % (x,))
+                               if "!" == x[-2:-1]:
+                                       conditional.not_equal.append(x[:-2])
+                               else:
+                                       conditional.equal.append(x[:-1])
                        else:
-                               if "?" == x[-1:]:
-                                       conditional_enabled.append(x[:-1])
+                               if "-" == x[:1]:
+                                       disabled_flags.append(x[1:])
                                else:
                                        enabled_flags.append(x)
+
                self.tokens = use
                if not isinstance(self.tokens, tuple):
                        self.tokens = tuple(self.tokens)
+
+               self.required = frozenset(chain(
+                       enabled_flags,
+                       disabled_flags,
+                       *conditional.values()
+               ))
+
                self.enabled = frozenset(enabled_flags)
                self.disabled = frozenset(disabled_flags)
-               self.conditional_enabled = frozenset(conditional_enabled)
-               self.conditional_disabled = frozenset(conditional_disabled)
-               self.conditional = self.conditional_enabled.union(
-                       self.conditional_disabled)
-               self.required = frozenset(chain(self.enabled, self.disabled,
-                       self.conditional_enabled, self.conditional_disabled))
+               self.conditional = None
+
+               for v in conditional.itervalues():
+                       if v:
+                               for k, v in conditional.iteritems():
+                                       conditional[k] = frozenset(v)
+                               self.conditional = conditional
+                               break
 
        def __str__(self):
                return "".join("[%s]" % x for x in self.tokens)
 
        def evaluate_conditionals(self, use):
                """
-               Create a new instance with conditionals evaluated as follows:
+               Create a new instance with conditionals evaluated.
+
+               Conditional evaluation behavior:
+
+                       parent state   conditional   result
+
+                        x              x?            x
+                       -x              x?
+                        x             -x?
+                       -x             -x?           -x
+
+                        x              x=            x
+                       -x              x=           -x
+                        x             x!=           -x
+                       -x             x!=            x
+
+               Conditional syntax examples:
+
+                       compact form         equivalent expanded form
+
+                        foo[bar?]           foo  bar? (  foo[bar] )
+                       foo[-bar?]           foo !bar? ( foo[-bar] )
+                        foo[bar=]           foo  bar? (  foo[bar] ) !bar? ( foo[-bar] )
+                        foo[bar!=]          foo  bar? ( foo[-bar] ) !bar? (  foo[bar] )
 
-               parent state   conditional   result
-                x              x?            x
-               -x              x?           -x
-                x             -x?           -x
-               -x             -x?            x
                """
                tokens = []
+
+               conditional = self.conditional
                tokens.extend(self.enabled)
                tokens.extend("-" + x for x in self.disabled)
-               tokens.extend(self.conditional_enabled.intersection(use))
-               tokens.extend("-" + x for x in self.conditional_enabled.difference(use))
-               tokens.extend("-" + x for x in self.conditional_disabled.intersection(use))
-               tokens.extend(self.conditional_disabled.difference(use))
+               tokens.extend(x for x in conditional.enabled if x in use)
+               tokens.extend("-" + x for x in conditional.disabled if x not in use)
+
+               tokens.extend(x for x in conditional.equal if x in use)
+               tokens.extend("-" + x for x in conditional.equal if x not in use)
+               tokens.extend("-" + x for x in conditional.not_equal if x in use)
+               tokens.extend(x for x in conditional.not_equal if x not in use)
+
                return _use_dep(tokens)
 
 class _AtomCache(type):
@@ -655,7 +703,9 @@ def isvalidatom(atom, allow_blockers=False):
                atom = atom[1:]
 
        try:
-               dep_getusedeps(atom)
+               use = dep_getusedeps(atom)
+               if use:
+                       use = _use_dep(use)
        except InvalidAtom:
                return 0
 
index d2210b8e93151cb06fd9e2c0491d202768e27c07..397ce997b6b1d17fa4fc36b5a960c1e9dd3490ea 100644 (file)
@@ -25,6 +25,11 @@ class IsValidAtom(TestCase):
                          ( "sys-apps/portage:foo", True ),
                          ( "sys-apps/portage-2.1:foo", False ),
                          ( "sys-apps/portage-2.1:", False ),
+                         ( "=sys-apps/portage-2.2*:foo[bar?,-baz?,doc!=,build=]", True ),
+                         ( "=sys-apps/portage-2.2*:foo[build=]", True ),
+                         ( "=sys-apps/portage-2.2*:foo[doc!=]", True ),
+                         ( "=sys-apps/portage-2.2*:foo[-doc!=]", False ),
+                         ( "=sys-apps/portage-2.2*:foo[-doc=]", False ),
                          ( "=sys-apps/portage-2.2*:foo[bar][-baz][doc?][-build?]", True ),
                          ( "=sys-apps/portage-2.2*:foo[bar,-baz,doc?,-build?]", True ),
                          ( "=sys-apps/portage-2.2*:foo[bar,-baz,doc?,-build?,]", False ),