Implement use dependency defaults
authorSebastian Luther <SebastianLuther@gmx.de>
Wed, 24 Mar 2010 07:22:58 +0000 (08:22 +0100)
committerZac Medico <zmedico@gentoo.org>
Sat, 14 Aug 2010 03:16:40 +0000 (20:16 -0700)
bin/repoman
pym/_emerge/Package.py
pym/_emerge/depgraph.py
pym/_emerge/resolver/slot_collision.py
pym/portage/dbapi/__init__.py
pym/portage/dep/__init__.py
pym/portage/dep/dep_check.py
pym/portage/eapi.py
pym/portage/tests/dep/testAtom.py
pym/portage/tests/dep/test_match_from_list.py
pym/portage/tests/resolver/test_use_dep_defaults.py [new file with mode: 0644]

index 71fb58ac30d0817589417ee82e3f70bf8a442d1d..97566d3f1595b8db2494b8ef09c9f7defba40055 100755 (executable)
@@ -1619,6 +1619,8 @@ for x in scanlist:
                                        myteststr = mydepstr[len(token):]
                                else:
                                        myteststr = mydepstr
+                               myteststr = myteststr.replace("(+)", "")
+                               myteststr = myteststr.replace("(-)", "")
                                if myteststr.endswith(" "+token):
                                        myteststr = myteststr[:-len(token)]
                                while myteststr.find(" "+token+" ") != -1:
index 90a5d03eb3efaa131c423b6d9f472368c685a6ef..0cc36e18f3e20527e5da63c8bcdfa158fbfcb289 100644 (file)
@@ -48,7 +48,7 @@ class Package(Task):
                        # Avoid an InvalidAtom exception when creating slot_atom.
                        # This package instance will be masked due to empty SLOT.
                        slot = '0'
-               if (self.iuse.enabled or self.iuse.enabled) and \
+               if (self.iuse.enabled or self.iuse.disabled) and \
                        not eapi_has_iuse_defaults(self.metadata["EAPI"]):
                        self._invalid_metadata('IUSE.invalid',
                                "IUSE contains defaults, but EAPI doesn't allow them")
index 56ea1bd1944aaf9a41b91447c89ac683f18807f9..e3a47e8a70ce5a8885d17713005c85a867be8f54 100644 (file)
@@ -2078,7 +2078,7 @@ class depgraph(object):
                                                masked_pkg_instances.add(pkg)
                                        if atom.unevaluated_atom.use:
                                                if not pkg.iuse.is_valid_flag(atom.unevaluated_atom.use.required) \
-                                                       or atom.violated_conditionals(self._pkg_use_enabled(pkg)).use:
+                                                       or atom.violated_conditionals(self._pkg_use_enabled(pkg), pkg.iuse.all).use:
                                                        missing_use.append(pkg)
                                                        if not mreasons:
                                                                continue
@@ -2097,14 +2097,22 @@ class depgraph(object):
                missing_iuse_reasons = []
                for pkg in missing_use:
                        use = self._pkg_use_enabled(pkg)
-                       missing_iuse = pkg.iuse.get_missing_iuse(atom.use.required)
+                       missing_iuse = []
+                       for x in pkg.iuse.get_missing_iuse(atom.use.required):
+                               #FIXME: If a use flag occures more then it might be possible that
+                               #one has a default one doesn't.
+                               if x not in atom.use.missing_enabled and \
+                                       x not in atom.use.missing_disabled:
+                                       missing_iuse.append(x)
+
                        mreasons = []
                        if missing_iuse:
                                mreasons.append("Missing IUSE: %s" % " ".join(missing_iuse))
                                missing_iuse_reasons.append((pkg, mreasons))
                        else:
-                               need_enable = sorted(atom.use.enabled.difference(use))
-                               need_disable = sorted(atom.use.disabled.intersection(use))
+                               need_enable = sorted(atom.use.enabled.difference(use).intersection(pkg.iuse.all))
+                               need_disable = sorted(atom.use.disabled.intersection(use).intersection(pkg.iuse.all))
+
                                if need_enable or need_disable:
                                        changes = []
                                        changes.extend(colorize("red", "+" + x) \
@@ -2118,7 +2126,7 @@ class depgraph(object):
                                # Lets see if the violated use deps are conditional.
                                # If so, suggest to change them on the parent.
                                mreasons = []
-                               violated_atom = atom.unevaluated_atom.violated_conditionals(self._pkg_use_enabled(pkg), myparent.use.enabled)
+                               violated_atom = atom.unevaluated_atom.violated_conditionals(self._pkg_use_enabled(pkg), pkg.iuse.all, myparent.use.enabled)
                                if not (violated_atom.use.enabled or violated_atom.use.disabled):
                                        #all violated use deps are conditional
                                        changes = []
@@ -2625,7 +2633,13 @@ class depgraph(object):
                                                found_available_arg = True
 
                                        if atom.use:
-                                               missing_iuse = pkg.iuse.get_missing_iuse(atom.use.required)
+                                               missing_iuse = []
+                                               for x in pkg.iuse.get_missing_iuse(atom.use.required):
+                                                       #FIXME: If a use flag occures more then it might be possible that
+                                                       #one has a default one doesn't.
+                                                       if x not in atom.use.missing_enabled and \
+                                                               x not in atom.use.missing_disabled:
+                                                               missing_iuse.append(x)
                                                if missing_iuse:
                                                        # Don't add this to packages_with_invalid_use_config
                                                        # since IUSE cannot be adjusted by the user.
@@ -2641,11 +2655,13 @@ class depgraph(object):
                                                else:
                                                        use = self._pkg_use_enabled(pkg)
 
-                                               if atom.use.enabled.difference(use):
+                                               if atom.use.enabled.difference(use) and \
+                                                       atom.use.enabled.difference(use).difference(atom.use.missing_enabled.difference(pkg.iuse.all)):
                                                        if not pkg.built:
                                                                packages_with_invalid_use_config.append(pkg)
                                                        continue
-                                               if atom.use.disabled.intersection(use):
+                                               if atom.use.disabled.intersection(use) or \
+                                                       atom.use.disabled.difference(pkg.iuse.all).difference(atom.use.missing_disabled):
                                                        if not pkg.built:
                                                                packages_with_invalid_use_config.append(pkg)
                                                        continue
index 8b499ec00267e3b44599e7bdc8b55a97872ec29e..b11fcb0c7e7f60fb8909786237609d9db6f2fdb8 100644 (file)
@@ -211,7 +211,8 @@ class slot_conflict_handler(object):
                                                                collision_reasons[("version", sub_type)] = atoms
                                                        elif not atom_set.findAtomForPackage(other_pkg):
                                                                #Use conditionals not met.
-                                                               violated_atom = atom.violated_conditionals(other_pkg.use.enabled, ppkg.use.enabled)
+                                                               violated_atom = atom.violated_conditionals(other_pkg.use.enabled, \
+                                                                       other_pkg.iuse.all, ppkg.use.enabled)
                                                                for flag in violated_atom.use.enabled.union(violated_atom.use.disabled):
                                                                        atoms = collision_reasons.get(("use", flag), set())
                                                                        atoms.add((ppkg, atom, other_pkg))
@@ -251,7 +252,7 @@ class slot_conflict_handler(object):
                                                        conditional_matches = set()
                                                        for ppkg, atom, other_pkg in parents:
                                                                violated_atom = atom.unevaluated_atom.violated_conditionals( \
-                                                                       other_pkg.use.enabled, ppkg.use.enabled)
+                                                                       other_pkg.use.enabled, other_pkg.iuse.all, ppkg.use.enabled)
                                                                if use in violated_atom.use.enabled.union(violated_atom.use.disabled):
                                                                        hard_matches.add((ppkg, atom))
                                                                else:
@@ -456,9 +457,10 @@ class slot_conflict_handler(object):
                                if ppkg.installed:
                                        #We cannot assume that it's possible to reinstall the package. Do not
                                        #check if some of its atom has use.conditional
-                                       violated_atom = atom.violated_conditionals(pkg.use.enabled, ppkg.use.enabled)
+                                       violated_atom = atom.violated_conditionals(pkg.use.enabled, pkg.iuse.all, ppkg.use.enabled)
                                else:
-                                       violated_atom = atom.unevaluated_atom.violated_conditionals(pkg.use.enabled, ppkg.use.enabled)
+                                       violated_atom = atom.unevaluated_atom.violated_conditionals(pkg.use.enabled, \
+                                               pkg.iuse.all, ppkg.use.enabled)
 
                                if pkg.installed and (violated_atom.use.enabled or violated_atom.use.disabled):
                                        #We can't change USE of an installed package (only of an ebuild, but that is already
index 4799b25825088fba3b540c80da1a7bc0d60b1d34..505a4b15887e073cec0598fed377901729602a5c 100644 (file)
@@ -156,15 +156,17 @@ class dbapi(object):
                        iuse = frozenset(x.lstrip('+-') for x in iuse.split())
                        missing_iuse = False
                        for x in atom.use.required:
-                               if x not in iuse and iuse_implicit_re.match(x) is None:
+                               if x not in iuse and x not in atom.use.missing_enabled \
+                                       and x not in atom.use.missing_disabled and iuse_implicit_re.match(x) is None:
                                        missing_iuse = True
                                        break
                        if missing_iuse:
                                continue
                        if not self._use_mutable:
-                               if atom.use.enabled.difference(use):
+                               if atom.use.enabled.difference(use).difference(atom.use.missing_enabled):
                                        continue
-                               if atom.use.disabled.intersection(use):
+                               if atom.use.disabled.intersection(use) or \
+                                       atom.use.disabled.difference(iuse).difference(atom.use.missing_disabled):
                                        continue
                        else:
                                # Check masked and forced flags for repoman.
index 4c15b787cb3121f55f9e07a9d9a678376cb19df2..6c12c96d263ba3434b5471f8a2a2ec53c8478150 100644 (file)
@@ -332,8 +332,15 @@ def use_reduce(depstr, uselist=[], masklist=[], matchall=False, excludeall=[], i
                else:
                        if need_bracket or "(" in token or ")" in token or "|" in token or \
                                (need_simple_token and "/" in token):
-                               raise portage.exception.InvalidDependString(
-                                       _("malformed syntax: '%s'") % depstr)
+                               if not (need_bracket or "|" in token or (need_simple_token and "/" in token)):
+                                       #We have '(' and/or ')' in token. Make sure it's not a use dep default
+                                       tmp = token.replace("(+)", "").replace("(-)", "")
+                                       if "(" in tmp or ")" in tmp:
+                                               raise portage.exception.InvalidDependString(
+                                                       _("malformed syntax: '%s'") % depstr)
+                               else:
+                                       raise portage.exception.InvalidDependString(
+                                               _("malformed syntax: '%s'") % depstr)
 
                        if token[-1] == "?":
                                need_bracket = True
@@ -403,17 +410,21 @@ def flatten(mylist):
 
 class _use_dep(object):
 
-       __slots__ = ("__weakref__", "conditional",
+       __slots__ = ("__weakref__", "conditional", "missing_enabled", "missing_disabled",
                "disabled", "enabled", "tokens", "required")
 
        _conditionals_class = portage.cache.mappings.slot_dict_class(
                ("disabled", "enabled", "equal", "not_equal"), prefix="")
 
-       _valid_use_re = re.compile(r'^[^-?!=][^?!=]*$')
+       _valid_use_re = re.compile(r'^[A-Za-z0-9][A-Za-z0-9+_@-]*$')
 
        def __init__(self, use):
                enabled_flags = []
                disabled_flags = []
+               missing_enabled = []
+               missing_disabled = []
+               no_default = []
+
                conditional = self._conditionals_class()
                for k in conditional.allowed_keys:
                        conditional[k] = []
@@ -421,37 +432,61 @@ class _use_dep(object):
                for x in use:
                        last_char = x[-1:]
                        first_char = x[:1]
+                       flag = x
+                       default = ""
+                       if last_char in ("?", "="):
+                               flag = flag[:-1]
+                       if first_char in ("-", "!"):
+                               flag = flag[1:]
+
+                       if flag[-3:] in ("(+)", "(-)"):
+                               default = flag[-3:]
+                               flag = flag[:-3]
 
                        if "?" == last_char:
                                if "!" == first_char:
                                        conditional.disabled.append(
-                                               self._validate_flag(x, x[1:-1]))
+                                               self._validate_flag(x, flag))
                                elif first_char in ("-", "=", "?"):
                                        raise InvalidAtom(_("Invalid use dep: '%s'") % (x,))
                                else:
                                        conditional.enabled.append(
-                                               self._validate_flag(x, x[:-1]))
+                                               self._validate_flag(x, flag))
 
                        elif "=" == last_char:
                                if "!" == first_char:
                                        conditional.not_equal.append(
-                                               self._validate_flag(x, x[1:-1]))
+                                               self._validate_flag(x, flag))
                                elif first_char in ("-", "=", "?"):
                                        raise InvalidAtom(_("Invalid use dep: '%s'") % (x,))
                                else:
                                        conditional.equal.append(
-                                               self._validate_flag(x, x[:-1]))
+                                               self._validate_flag(x, flag))
 
                        elif last_char in ("!", "-"):
                                raise InvalidAtom(_("Invalid use dep: '%s'") % (x,))
 
                        else:
                                if "-" == first_char:
-                                       disabled_flags.append(self._validate_flag(x, x[1:]))
+                                       disabled_flags.append(self._validate_flag(x, flag))
                                elif first_char in ("!", "=", "?"):
                                        raise InvalidAtom(_("Invalid use dep: '%s'") % (x,))
                                else:
-                                       enabled_flags.append(self._validate_flag(x, x))
+                                       enabled_flags.append(self._validate_flag(x, flag))
+
+                       if default:
+                               if default == "(+)":
+                                       if flag in missing_disabled or flag in no_default:
+                                               raise InvalidAtom(_("Invalid use dep: '%s'") % (x,))
+                                       missing_enabled.append(flag)
+                               else:
+                                       if flag in missing_enabled or flag in no_default:
+                                               raise InvalidAtom(_("Invalid use dep: '%s'") % (x,))
+                                       missing_disabled.append(flag)
+                       else:
+                               if flag in missing_enabled or flag in missing_disabled:
+                                       raise InvalidAtom(_("Invalid use dep: '%s'") % (x,))
+                               no_default.append(flag)
 
                self.tokens = use
                if not isinstance(self.tokens, tuple):
@@ -465,6 +500,8 @@ class _use_dep(object):
 
                self.enabled = frozenset(enabled_flags)
                self.disabled = frozenset(disabled_flags)
+               self.missing_enabled = frozenset(missing_enabled)
+               self.missing_disabled = frozenset(missing_disabled)
                self.conditional = None
 
                for v in conditional.values():
@@ -493,6 +530,22 @@ class _use_dep(object):
        def __repr__(self):
                return "portage.dep._use_dep(%s)" % repr(self.tokens)
 
+       
+       def _append_use_default(self, output, flag):
+               default = None
+               if flag in self.missing_enabled:
+                       default = "(+)"
+               elif flag in self.missing_disabled:
+                       default = "(-)"
+
+               if not default:
+                       return output
+
+               if output[-1] in ("=", "?"):
+                       return output[:-1] + default + output[-1]
+               else:
+                       return output + default
+
        def evaluate_conditionals(self, use):
                """
                Create a new instance with conditionals evaluated.
@@ -524,37 +577,114 @@ class _use_dep(object):
                tokens = []
 
                conditional = self.conditional
-               tokens.extend(self.enabled)
-               tokens.extend("-" + x for x in self.disabled)
-               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(self._append_use_default(x, x) for x in self.enabled)
+               tokens.extend(self._append_use_default("-" + x, x) for x in self.disabled)
+               tokens.extend(self._append_use_default(x, x) for x in conditional.enabled if x in use)
+               tokens.extend(self._append_use_default("-" + x, 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)
+               tokens.extend(self._append_use_default(x, x) for x in conditional.equal if x in use)
+               tokens.extend(self._append_use_default("-" + x, x) for x in conditional.equal if x not in use)
+               tokens.extend(self._append_use_default("-" + x, x) for x in conditional.not_equal if x in use)
+               tokens.extend(self._append_use_default(x, x) for x in conditional.not_equal if x not in use)
 
                return _use_dep(tokens)
 
-       def violated_conditionals(self, other_use, parent_use=None):
+       def violated_conditionals(self, other_use, iuse, parent_use=None):
                """
                Create a new instance with satisfied use deps removed.
                """
                tokens = []
 
                conditional = self.conditional
-               tokens.extend(x for x in self.enabled if x not in other_use)
-               tokens.extend("-" + x for x in self.disabled if x in other_use)
-               if conditional:
-                       if parent_use is None:
-                               raise InvalidAtom("violated_conditionals needs 'parent_use'" + \
-                                       " parameter for conditional flags.")
-                       tokens.extend(x + "?" for x in conditional.enabled if x in parent_use and not x in other_use)
-                       tokens.extend("!" + x + "?" for x in conditional.disabled if x not in parent_use and x in other_use)
-                       tokens.extend(x + "=" for x in conditional.equal if x in parent_use and x not in other_use)
-                       tokens.extend(x + "=" for x in conditional.equal if x not in parent_use and x in other_use)
-                       tokens.extend("!" + x + "=" for x in conditional.not_equal if x in parent_use and x in other_use)
-                       tokens.extend("!" + x + "=" for x in conditional.not_equal if x not in parent_use and x not in other_use)
+
+               for x in self.enabled:
+                       if x not in other_use:
+                               if x in iuse:
+                                       tokens.append(self._append_use_default(x, x))
+                               else:
+                                       if x in self.missing_disabled:
+                                               tokens.append(self._append_use_default(x, x))
+
+               for x in self.disabled:
+                       if x not in other_use:
+                               if x not in iuse:
+                                       if x in self.missing_enabled:
+                                               tokens.append(self._append_use_default("-" + x, x))
+                       else:
+                               tokens.append(self._append_use_default("-" + x, x))
+
+               if not conditional:
+                       return _use_dep(tokens)
+
+               if parent_use is None:
+                       raise InvalidAtom("violated_conditionals needs 'parent_use'" + \
+                               " parameter for conditional flags.")
+
+               for x in conditional.enabled:
+                       if x not in parent_use:
+                               continue
+
+                       if x not in other_use:
+                               if x in iuse:
+                                       tokens.append(self._append_use_default(x + "?", x))
+                               else:
+                                       if x in self.missing_disabled:
+                                               tokens.append(self._append_use_default(x + "?", x))
+
+               for x in conditional.disabled:
+                       if x in parent_use:
+                               continue
+
+                       if x not in other_use:
+                               if x not in iuse:
+                                       if x in self.missing_enabled:
+                                               tokens.append(self._append_use_default("!" + x + "?", x))
+                       else:
+                               tokens.append(self._append_use_default("!" + x + "?", x))
+
+               for x in conditional.equal:
+                       if x not in parent_use:
+                               continue
+
+                       if x not in other_use:
+                               if x in iuse:
+                                       tokens.append(self._append_use_default(x + "=", x))
+                               else:
+                                       if x in self.missing_disabled:
+                                               tokens.append(self._append_use_default(x + "=", x))
+
+               for x in conditional.equal:
+                       if x in parent_use:
+                               continue
+
+                       if x not in other_use:
+                               if x not in iuse:
+                                       if x in self.missing_enabled:
+                                               tokens.append(self._append_use_default(x + "=", x))
+                       else:
+                               tokens.append(self._append_use_default(x + "=", x))
+
+               for x in conditional.not_equal:
+                       if x in parent_use:
+                               continue
+
+                       if x not in other_use:
+                               if x in iuse:
+                                       tokens.append(self._append_use_default("!" + x + "=", x))
+                               else:
+                                       if x in self.missing_disabled:
+                                               tokens.append(self._append_use_default("!" + x + "=", x))
+
+               for x in conditional.not_equal:
+                       if x not in parent_use:
+                               continue
+
+                       if x not in other_use:
+                               if x not in iuse:
+                                       if x in self.missing_enabled:
+                                               tokens.append(self._append_use_default("!" + x + "=", x))
+                       else:
+                               tokens.append(self._append_use_default("!" + x + "=", x))
 
                return _use_dep(tokens)
 
@@ -571,15 +701,15 @@ class _use_dep(object):
                tokens = []
 
                conditional = self.conditional
-               tokens.extend(self.enabled)
-               tokens.extend("-" + x for x in self.disabled)
-               tokens.extend(x for x in conditional.enabled if x not in use_mask)
-               tokens.extend("-" + x for x in conditional.disabled if x not in use_force)
+               tokens.extend(self._append_use_default(x, x) for x in self.enabled)
+               tokens.extend(self._append_use_default("-" + x, x) for x in self.disabled)
+               tokens.extend(self._append_use_default(x, x) for x in conditional.enabled if x not in use_mask)
+               tokens.extend(self._append_use_default("-" + x, x) for x in conditional.disabled if x not in use_force)
 
-               tokens.extend(x for x in conditional.equal if x not in use_mask)
-               tokens.extend("-" + x for x in conditional.equal if x not in use_force)
-               tokens.extend("-" + x for x in conditional.not_equal if x not in use_mask)
-               tokens.extend(x for x in conditional.not_equal if x not in use_force)
+               tokens.extend(self._append_use_default(x, x) for x in conditional.equal if x not in use_mask)
+               tokens.extend(self._append_use_default("-" + x, x) for x in conditional.equal if x not in use_force)
+               tokens.extend(self._append_use_default("-" + x, x) for x in conditional.not_equal if x not in use_mask)
+               tokens.extend(self._append_use_default(x, x) for x in conditional.not_equal if x not in use_force)
 
                return _use_dep(tokens)
 
@@ -744,7 +874,7 @@ class Atom(_atom_base):
                atom += str(self.use.evaluate_conditionals(use))
                return Atom(atom, unevaluated_atom=self)
 
-       def violated_conditionals(self, other_use, parent_use=None):
+       def violated_conditionals(self, other_use, iuse, parent_use=None):
                """
                Create an atom instance with any USE conditional removed, that is
                satisfied by other_use.
@@ -760,7 +890,7 @@ class Atom(_atom_base):
                atom = remove_slot(self)
                if self.slot:
                        atom += ":%s" % self.slot
-               atom += str(self.use.violated_conditionals(other_use, parent_use))
+               atom += str(self.use.violated_conditionals(other_use, iuse, parent_use))
                return Atom(atom, unevaluated_atom=self)
 
        def _eval_qa_conditionals(self, use_mask, use_force):
@@ -1341,19 +1471,35 @@ def match_from_list(mydep, candidate_list):
                        use = getattr(x, "use", None)
                        if use is not None:
                                is_valid_flag = x.iuse.is_valid_flag
-                               missing_iuse = False
-                               for y in mydep.use.required:
-                                       if not is_valid_flag(y):
-                                               missing_iuse = True
-                                               break
-                               if missing_iuse:
-                                       continue
-                               if mydep.use.enabled.difference(use.enabled):
+                               use_config_mismatch = False
+
+                               for y in mydep.use.enabled:
+                                       if is_valid_flag(y):
+                                               if y not in use.enabled:
+                                                       use_config_mismatch = True
+                                                       break   
+                                       else:
+                                               if y not in mydep.use.missing_enabled:
+                                                       use_config_mismatch = True
+                                                       break
+
+                               if use_config_mismatch:
                                        continue
-                               if mydep.use.disabled.intersection(use.enabled):
+
+                               for y in mydep.use.disabled:
+                                       if is_valid_flag(y):
+                                               if y in use.enabled:
+                                                       use_config_mismatch = True
+                                                       break
+                                       else:
+                                               if y not in mydep.use.missing_disabled:
+                                                       use_config_mismatch = True
+                                                       break
+
+                               if use_config_mismatch:
                                        continue
-                       mylist.append(x)
 
+                       mylist.append(x)
        return mylist
 
 def check_required_use(required_use, use, iuse):
index be24ad81a1ea48281e87b3b79882aa26447b540f..28d5771a7e7afb303359403ee5e422d56c7d5c31 100644 (file)
@@ -8,7 +8,8 @@ import logging
 import portage
 from portage.dep import Atom, dep_opconvert, match_from_list, \
        remove_slot, use_reduce
-from portage.eapi import eapi_has_strong_blocks, eapi_has_use_deps, eapi_has_slot_deps
+from portage.eapi import eapi_has_strong_blocks, eapi_has_use_deps, eapi_has_slot_deps, \
+       eapi_has_use_dep_defaults
 from portage.exception import InvalidAtom, InvalidDependString, ParseError
 from portage.localization import _
 from portage.util import writemsg, writemsg_level
@@ -75,6 +76,10 @@ def _expand_new_virtuals(mysplit, edebug, mydbapi, mysettings, myroot="/",
                                if x.slot and not eapi_has_slot_deps(eapi):
                                        raise ParseError(
                                                _("invalid atom: '%s'") % (x,))
+                               if x.use and (x.use.missing_enabled or x.use.missing_disabled) \
+                                       and not eapi_has_use_dep_defaults(eapi):
+                                       raise ParseError(
+                                               _("invalid atom: '%s'") % (x,))
 
                if repoman:
                        x = x._eval_qa_conditionals(use_mask, use_force)
index a288b1964299266da70d9e9a0039afdd058c7cb4..eb2809ee83b72fb8e825cce31519b3a562d5fe9f 100644 (file)
@@ -42,3 +42,6 @@ def eapi_has_dosed_dohard(eapi):
 
 def eapi_has_required_use(eapi):
        return eapi not in ("0", "1", "2", "3")
+
+def eapi_has_use_dep_defaults(eapi):
+       return eapi not in ("0", "1", "2", "3")
index 7d5ae3e79b10ffb5277c6dcb64bfcf25a4532d83..fecf2bfa0c909f46106d5a32136d9e60a96d27a1 100644 (file)
@@ -1,5 +1,4 @@
-# test_isvalidatom.py -- Portage Unit Testing Functionality
-# Copyright 2006 Gentoo Foundation
+# Copyright 2006, 2010 Gentoo Foundation
 # Distributed under the terms of the GNU General Public License v2
 
 from portage.tests import TestCase
@@ -7,37 +6,43 @@ from portage.dep import Atom
 from portage.exception import InvalidAtom
 
 class TestAtom(TestCase):
-       """ A simple testcase for isvalidatom
-       """
 
        def testAtom(self):
 
-               tests = [
-                         ( "=sys-apps/portage-2.1-r1:0[doc,a=,!b=,c?,!d?,-e]",
+               tests = (
+                       ( "=sys-apps/portage-2.1-r1:0[doc,a=,!b=,c?,!d?,-e]",
                                ('=',  'sys-apps/portage', '2.1-r1', '0', '[doc,a=,!b=,c?,!d?,-e]'), False ),
-                         ( "=sys-apps/portage-2.1-r1*:0[doc]",
+                       ( "=sys-apps/portage-2.1-r1*:0[doc]",
                                ('=*',  'sys-apps/portage', '2.1-r1', '0', '[doc]'), False ),
-                         ( "sys-apps/portage:0[doc]",
+                       ( "sys-apps/portage:0[doc]",
                                (None,  'sys-apps/portage', None, '0', '[doc]'), False ),
-                         ( "sys-apps/portage:0[doc]",
+                       ( "sys-apps/portage:0[doc]",
                                (None,  'sys-apps/portage', None, '0', '[doc]'), False ),
-                         ( "*/*",
+                       ( "*/*",
                                (None,  '*/*', None, None, None), True ),
-                         ( "sys-apps/*",
+                       ( "sys-apps/*",
                                (None,  'sys-apps/*', None, None, None), True ),
-                         ( "*/portage",
+                       ( "*/portage",
                                (None,  '*/portage', None, None, None), True ),
-                         ( "s*s-*/portage:1",
+                       ( "s*s-*/portage:1",
                                (None,  's*s-*/portage', None, '1', None), True ),
-                         ( "*/po*ge:2",
+                       ( "*/po*ge:2",
                                (None,  '*/po*ge', None, '2', None), True ),
-                         ( "!dev-libs/A",
+                       ( "!dev-libs/A",
                                (None,  'dev-libs/A', None, None, None), True ),
-                          ( "!!dev-libs/A",
+                       ( "!!dev-libs/A",
                                (None,  'dev-libs/A', None, None, None), True ),
-               ]
+                       ( "!!dev-libs/A",
+                               (None,  'dev-libs/A', None, None, None), True ),
+                       ( "dev-libs/A[foo(+)]",
+                               (None,  'dev-libs/A', None, None, "[foo(+)]"), True ),
+                       ( "dev-libs/A[a(+),b(-)=,!c(+)=,d(-)?,!e(+)?,-f(-)]",
+                               (None,  'dev-libs/A', None, None, "[a(+),b(-)=,!c(+)=,d(-)?,!e(+)?,-f(-)]"), True ),
+                       ( "dev-libs/A:2[a(+),b(-)=,!c(+)=,d(-)?,!e(+)?,-f(-)]",
+                               (None,  'dev-libs/A', None, "2", "[a(+),b(-)=,!c(+)=,d(-)?,!e(+)?,-f(-)]"), True ),
+               )
                
-               tests_xfail = [
+               tests_xfail = (
                        ( Atom("sys-apps/portage"), False ),
                        ( "cat/pkg[a!]", False ),
                        ( "cat/pkg[a-]", False ),
@@ -64,90 +69,157 @@ class TestAtom(TestCase):
                        ( "*/portage", False ),
                        ( "*/**", True ),
                        ( "*/portage[use]", True ),
-                       ( "*/portage:slot", True )
-               ]
+                       ( "cat/pkg[a()]", False ),
+                       ( "cat/pkg[a(]", False ),
+                       ( "cat/pkg[a)]", False ),
+                       ( "cat/pkg[a(,b]", False ),
+                       ( "cat/pkg[a),b]", False ),
+                       ( "cat/pkg[a(*)]", False ),
+                       ( "cat/pkg[a(*)]", True ),
+                       ( "cat/pkg[a(+-)]", False ),
+                       ( "cat/pkg[a()]", False ),
+                       ( "cat/pkg[(+)a]", False ),
+                       ( "cat/pkg[a=(+)]", False ),
+                       ( "cat/pkg[!(+)a=]", False ),
+                       ( "cat/pkg[!a=(+)]", False ),
+                       ( "cat/pkg[a?(+)]", False ),
+                       ( "cat/pkg[!a?(+)]", False ),
+                       ( "cat/pkg[!(+)a?]", False ),
+                       ( "cat/pkg[-(+)a]", False ),
+                       ( "cat/pkg[a(+),-a]", False ),
+                       ( "cat/pkg[a(-),-a]", False ),
+                       ( "cat/pkg[-a,a(+)]", False ),
+                       ( "cat/pkg[-a,a(-)]", False ),
+                       ( "cat/pkg[-a(+),a(-)]", False ),
+                       ( "cat/pkg[-a(-),a(+)]", False ),
+               )
 
                for atom, parts, allow_wildcard in tests:
                        a = Atom(atom, allow_wildcard=allow_wildcard)
                        op, cp, ver, slot, use = parts
                        self.assertEqual( op, a.operator,
-                               msg="Atom('%s').operator == '%s'" % ( atom, a.operator ) )
+                               msg="Atom('%s').operator = %s == '%s'" % ( atom, a.operator, op ) )
                        self.assertEqual( cp, a.cp,
-                               msg="Atom('%s').cp == '%s'" % ( atom, a.cp ) )
+                               msg="Atom('%s').cp = %s == '%s'" % ( atom, a.cp, cp ) )
                        if ver is not None:
                                cpv = "%s-%s" % (cp, ver)
                        else:
                                cpv = cp
                        self.assertEqual( cpv, a.cpv,
-                               msg="Atom('%s').cpv == '%s'" % ( atom, a.cpv ) )
+                               msg="Atom('%s').cpv = %s == '%s'" % ( atom, a.cpv, cpv ) )
                        self.assertEqual( slot, a.slot,
-                               msg="Atom('%s').slot == '%s'" % ( atom, a.slot ) )
+                               msg="Atom('%s').slot = %s == '%s'" % ( atom, a.slot, slot ) )
                        if a.use:
-                               expected_use = str(a.use)
+                               returned_use = str(a.use)
                        else:
-                               expected_use = None
-                       self.assertEqual( use, expected_use,
-                               msg="Atom('%s').use == '%s'" % ( atom, a.use ) )
+                               returned_use = None
+                       self.assertEqual( use, returned_use,
+                               msg="Atom('%s').use = %s == '%s'" % ( atom, returned_use, use ) )
 
                for atom, allow_wildcard in tests_xfail:
-                       self.assertRaisesMsg(atom, (InvalidAtom, TypeError), Atom, atom)
+                       self.assertRaisesMsg(atom, (InvalidAtom, TypeError), Atom, atom, allow_wildcard=allow_wildcard)
+
+       def test_intersects(self):
+               test_cases = (
+                       ("dev-libs/A", "dev-libs/A", True),
+                       ("dev-libs/A", "dev-libs/B", False),
+                       ("dev-libs/A", "sci-libs/A", False),
+                       ("dev-libs/A[foo]", "sci-libs/A[bar]", False),
+                       ("dev-libs/A[foo(+)]", "sci-libs/A[foo(-)]", False),
+                       ("=dev-libs/A-1", "=dev-libs/A-1-r1", False),
+                       ("~dev-libs/A-1", "=dev-libs/A-1", False),
+                       ("=dev-libs/A-1:1", "=dev-libs/A-1", True),
+                       ("=dev-libs/A-1:1", "=dev-libs/A-1:1", True),
+                       ("=dev-libs/A-1:1", "=dev-libs/A-1:2", False),
+               )
+
+               for atom, other, expected_result in test_cases:
+                       self.assertEqual(Atom(atom).intersects(Atom(other)), expected_result, \
+                               "%s and %s should intersect: %s" % (atom, other, expected_result))
 
        def test_violated_conditionals(self):
                test_cases = (
-                       ("dev-libs/A", ["foo"], None, "dev-libs/A"),
-                       ("dev-libs/A[foo]", [], None, "dev-libs/A[foo]"),
-                       ("dev-libs/A[foo]", ["foo"], None, "dev-libs/A"),
-                       ("dev-libs/A[foo]", [], [], "dev-libs/A[foo]"),
-                       ("dev-libs/A[foo]", ["foo"], [], "dev-libs/A"),
+                       ("dev-libs/A", ["foo"], ["foo"], None, "dev-libs/A"),
+                       ("dev-libs/A[foo]", [], ["foo"], None, "dev-libs/A[foo]"),
+                       ("dev-libs/A[foo]", ["foo"], ["foo"], None, "dev-libs/A"),
+                       ("dev-libs/A[foo]", [], ["foo"], [], "dev-libs/A[foo]"),
+                       ("dev-libs/A[foo]", ["foo"], ["foo"], [], "dev-libs/A"),
 
-                       ("dev-libs/A:0[foo]", ["foo"], [], "dev-libs/A:0"),
+                       ("dev-libs/A:0[foo]", ["foo"], ["foo"], [], "dev-libs/A:0"),
 
-                       ("dev-libs/A[foo,-bar]", [], None, "dev-libs/A[foo]"),
-                       ("dev-libs/A[-foo,bar]", [], None, "dev-libs/A[bar]"),
+                       ("dev-libs/A[foo,-bar]", [], ["foo", "bar"], None, "dev-libs/A[foo]"),
+                       ("dev-libs/A[-foo,bar]", [], ["foo", "bar"], None, "dev-libs/A[bar]"),
 
-                       ("dev-libs/A[a,b=,!c=,d?,!e?,-f]", [], [], "dev-libs/A[a,!c=]"),
-                       
-                       ("dev-libs/A[a,b=,!c=,d?,!e?,-f]", ["a"], [], "dev-libs/A[!c=]"),
-                       ("dev-libs/A[a,b=,!c=,d?,!e?,-f]", ["b"], [], "dev-libs/A[a,b=,!c=]"),
-                       ("dev-libs/A[a,b=,!c=,d?,!e?,-f]", ["c"], [], "dev-libs/A[a]"),
-                       ("dev-libs/A[a,b=,!c=,d?,!e?,-f]", ["d"], [], "dev-libs/A[a,!c=]"),
-                       ("dev-libs/A[a,b=,!c=,d?,!e?,-f]", ["e"], [], "dev-libs/A[a,!e?,!c=]"),
-                       ("dev-libs/A[a,b=,!c=,d?,!e?,-f]", ["f"], [], "dev-libs/A[a,-f,!c=]"),
-                       
-                       ("dev-libs/A[a,b=,!c=,d?,!e?,-f]", ["a"], ["a"], "dev-libs/A[!c=]"),
-                       ("dev-libs/A[a,b=,!c=,d?,!e?,-f]", ["b"], ["b"], "dev-libs/A[a,!c=]"),
-                       ("dev-libs/A[a,b=,!c=,d?,!e?,-f]", ["c"], ["c"], "dev-libs/A[a,!c=]"),
-                       ("dev-libs/A[a,b=,!c=,d?,!e?,-f]", ["d"], ["d"], "dev-libs/A[a,!c=]"),
-                       ("dev-libs/A[a,b=,!c=,d?,!e?,-f]", ["e"], ["e"], "dev-libs/A[a,!c=]"),
-                       ("dev-libs/A[a,b=,!c=,d?,!e?,-f]", ["f"], ["f"], "dev-libs/A[a,-f,!c=]"),
+                       ("dev-libs/A[a,b=,!c=,d?,!e?,-f]", [], ["a", "b", "c", "d", "e", "f"], [], "dev-libs/A[a,!c=]"),
+
+                       ("dev-libs/A[a,b=,!c=,d?,!e?,-f]", ["a"], ["a", "b", "c", "d", "e", "f"], [], "dev-libs/A[!c=]"),
+                       ("dev-libs/A[a,b=,!c=,d?,!e?,-f]", ["b"], ["a", "b", "c", "d", "e", "f"], [], "dev-libs/A[a,b=,!c=]"),
+                       ("dev-libs/A[a,b=,!c=,d?,!e?,-f]", ["c"], ["a", "b", "c", "d", "e", "f"], [], "dev-libs/A[a]"),
+                       ("dev-libs/A[a,b=,!c=,d?,!e?,-f]", ["d"], ["a", "b", "c", "d", "e", "f"], [], "dev-libs/A[a,!c=]"),
+                       ("dev-libs/A[a,b=,!c=,d?,!e?,-f]", ["e"], ["a", "b", "c", "d", "e", "f"], [], "dev-libs/A[a,!e?,!c=]"),
+                       ("dev-libs/A[a,b=,!c=,d?,!e?,-f]", ["f"], ["a", "b", "c", "d", "e", "f"], [], "dev-libs/A[a,-f,!c=]"),
+
+                       ("dev-libs/A[a,b=,!c=,d?,!e?,-f]", ["a"], ["a", "b", "c", "d", "e", "f"], ["a"], "dev-libs/A[!c=]"),
+                       ("dev-libs/A[a,b=,!c=,d?,!e?,-f]", ["b"], ["a", "b", "c", "d", "e", "f"], ["b"], "dev-libs/A[a,!c=]"),
+                       ("dev-libs/A[a,b=,!c=,d?,!e?,-f]", ["c"], ["a", "b", "c", "d", "e", "f"], ["c"], "dev-libs/A[a,!c=]"),
+                       ("dev-libs/A[a,b=,!c=,d?,!e?,-f]", ["d"], ["a", "b", "c", "d", "e", "f"], ["d"], "dev-libs/A[a,!c=]"),
+                       ("dev-libs/A[a,b=,!c=,d?,!e?,-f]", ["e"], ["a", "b", "c", "d", "e", "f"], ["e"], "dev-libs/A[a,!c=]"),
+                       ("dev-libs/A[a,b=,!c=,d?,!e?,-f]", ["f"], ["a", "b", "c", "d", "e", "f"], ["f"], "dev-libs/A[a,-f,!c=]"),
+
+                       ("dev-libs/A[a(+),b(-)=,!c(+)=,d(-)?,!e(+)?,-f(-)]", ["a"], ["a", "b", "c", "d", "e", "f"], ["a"], "dev-libs/A[!c(+)=]"),
+                       ("dev-libs/A[a(-),b(+)=,!c(-)=,d(+)?,!e(-)?,-f(+)]", ["b"], ["a", "b", "c", "d", "e", "f"], ["b"], "dev-libs/A[a(-),!c(-)=]"),
+                       ("dev-libs/A[a(+),b(-)=,!c(+)=,d(-)?,!e(+)?,-f(-)]", ["c"], ["a", "b", "c", "d", "e", "f"], ["c"], "dev-libs/A[a(+),!c(+)=]"),
+                       ("dev-libs/A[a(-),b(+)=,!c(-)=,d(+)?,!e(-)?,-f(+)]", ["d"], ["a", "b", "c", "d", "e", "f"], ["d"], "dev-libs/A[a(-),!c(-)=]"),
+                       ("dev-libs/A[a(+),b(-)=,!c(+)=,d(-)?,!e(+)?,-f(-)]", ["e"], ["a", "b", "c", "d", "e", "f"], ["e"], "dev-libs/A[a(+),!c(+)=]"),
+                       ("dev-libs/A[a(-),b(+)=,!c(-)=,d(+)?,!e(-)?,-f(+)]", ["f"], ["a", "b", "c", "d", "e", "f"], ["f"], "dev-libs/A[a(-),-f(+),!c(-)=]"),
+
+                       ("dev-libs/A[a(+),b(+)=,!c(+)=,d(-)?,!e(+)?,-f(-)]", ["a"], ["a"], ["a"], "dev-libs/A[!e(+)?,b(+)=]"),
+                       ("dev-libs/A[a(-),b(+)=,!c(-)=,d(+)?,!e(-)?,-f(+)]", ["b"], ["b"], ["b"], "dev-libs/A[a(-),-f(+),!c(-)=]"),
+                       ("dev-libs/A[a(+),b(-)=,!c(+)=,d(-)?,!e(+)?,-f(-)]", ["c"], ["c"], ["c"], "dev-libs/A[!e(+)?,!c(+)=]"),
+                       ("dev-libs/A[a(-),b(+)=,!c(-)=,d(+)?,!e(-)?,-f(+)]", ["d"], ["d"], ["d"], "dev-libs/A[a(-),-f(+),b(+)=,!c(-)=]"),
+                       ("dev-libs/A[a(+),b(-)=,!c(+)=,d(-)?,!e(+)?,-f(-)]", ["e"], ["e"], ["e"], "dev-libs/A"),
+                       ("dev-libs/A[a(-),b(+)=,!c(-)=,d(+)?,!e(-)?,-f(+)]", ["f"], ["f"], ["f"], "dev-libs/A[a(-),-f(+),b(+)=,!c(-)=]"),
+
+                       #Some more test cases to trigger all remaining code paths
+                       ("dev-libs/B[x?]", [], ["x"], ["x"], "dev-libs/B[x?]"),
+                       ("dev-libs/B[x(+)?]", [], [], ["x"], "dev-libs/B"),
+                       ("dev-libs/B[x(-)?]", [], [], ["x"], "dev-libs/B[x(-)?]"),
+
+                       ("dev-libs/C[x=]", [], ["x"], ["x"], "dev-libs/C[x=]"),
+                       ("dev-libs/C[x(+)=]", [], [], ["x"], "dev-libs/C"),
+                       ("dev-libs/C[x(-)=]", [], [], ["x"], "dev-libs/C[x(-)=]"),
+
+                       ("dev-libs/D[!x=]", [], ["x"], ["x"], "dev-libs/D"),
+                       ("dev-libs/D[!x(+)=]", [], [], ["x"], "dev-libs/D[!x(+)=]"),
+                       ("dev-libs/D[!x(-)=]", [], [], ["x"], "dev-libs/D"),
                )
                
                test_cases_xfail = (
-                       ("dev-libs/A[a,b=,!c=,d?,!e?,-f]", [], None),
+                       ("dev-libs/A[a,b=,!c=,d?,!e?,-f]", [], ["a", "b", "c", "d", "e", "f"], None),
                )
                
-               for atom, other_use, parent_use, expected_violated_atom in test_cases:
+               for atom, other_use, iuse, parent_use, expected_violated_atom in test_cases:
                        a = Atom(atom)
-                       violated_atom = a.violated_conditionals(other_use, parent_use)
+                       violated_atom = a.violated_conditionals(other_use, iuse, parent_use)
                        if parent_use is None:
-                               fail_msg = "Atom: %s, other_use: %s, parent_use: %s, got: %s, expected: %s" % \
-                                       (atom, " ".join(other_use), "None", str(violated_atom), expected_violated_atom)
+                               fail_msg = "Atom: %s, other_use: %s, iuse: %s, parent_use: %s, got: %s, expected: %s" % \
+                                       (atom, " ".join(other_use), " ".join(iuse), "None", str(violated_atom), expected_violated_atom)
                        else:
-                               fail_msg = "Atom: %s, other_use: %s, parent_use: %s, got: %s, expected: %s" % \
-                                       (atom, " ".join(other_use), " ".join(parent_use), str(violated_atom), expected_violated_atom)
+                               fail_msg = "Atom: %s, other_use: %s, iuse: %s, parent_use: %s, got: %s, expected: %s" % \
+                                       (atom, " ".join(other_use), " ".join(iuse), " ".join(parent_use), str(violated_atom), expected_violated_atom)
                        self.assertEqual(str(violated_atom), expected_violated_atom, fail_msg)
 
-               for atom, other_use, parent_use in test_cases_xfail:
+               for atom, other_use, iuse, parent_use in test_cases_xfail:
                        a = Atom(atom)
                        self.assertRaisesMsg(atom, InvalidAtom, \
-                               a.violated_conditionals, other_use, parent_use)
+                               a.violated_conditionals, other_use, iuse, parent_use)
 
        def test_evaluate_conditionals(self):
                test_cases = (
                        ("dev-libs/A[foo]", [], "dev-libs/A[foo]"),
                        ("dev-libs/A[foo]", ["foo"], "dev-libs/A[foo]"),
 
-                       ("dev-libs/A:0[foo]", ["foo"], "dev-libs/A:0[foo]"),
+                       ("dev-libs/A:0[foo=]", ["foo"], "dev-libs/A:0[foo]"),
 
                        ("dev-libs/A[foo,-bar]", [], "dev-libs/A[foo,-bar]"),
                        ("dev-libs/A[-foo,bar]", [], "dev-libs/A[-foo,bar]"),
@@ -159,8 +231,43 @@ class TestAtom(TestCase):
                        ("dev-libs/A[a,b=,!c=,d?,!e?,-f]", ["d"], "dev-libs/A[a,-f,d,-e,-b,c]"),
                        ("dev-libs/A[a,b=,!c=,d?,!e?,-f]", ["e"], "dev-libs/A[a,-f,-b,c]"),
                        ("dev-libs/A[a,b=,!c=,d?,!e?,-f]", ["f"], "dev-libs/A[a,-f,-e,-b,c]"),
+                       ("dev-libs/A[a(-),b(+)=,!c(-)=,d(+)?,!e(-)?,-f(+)]", ["d"], "dev-libs/A[a(-),-f(+),d(+),-e(-),-b(+),c(-)]"),
+                       ("dev-libs/A[a(+),b(-)=,!c(+)=,d(-)?,!e(+)?,-f(-)]", ["f"], "dev-libs/A[a(+),-f(-),-e(+),-b(-),c(+)]"),
                )
-               
-               
+
                for atom, use, expected_atom in test_cases:
-                       self.assertEqual(str(Atom(atom).evaluate_conditionals(use)), expected_atom)
+                       a = Atom(atom)
+                       b = a.evaluate_conditionals(use)
+                       self.assertEqual(str(b), expected_atom)
+                       self.assertEqual(str(b.unevaluated_atom), atom)
+
+       def test__eval_qa_conditionals(self):
+               test_cases = (
+                       ("dev-libs/A[foo]", [], [], "dev-libs/A[foo]"),
+                       ("dev-libs/A[foo]", ["foo"], [], "dev-libs/A[foo]"),
+                       ("dev-libs/A[foo]", [], ["foo"], "dev-libs/A[foo]"),
+
+                       ("dev-libs/A:0[foo]", [], [], "dev-libs/A:0[foo]"),
+                       ("dev-libs/A:0[foo]", ["foo"], [], "dev-libs/A:0[foo]"),
+                       ("dev-libs/A:0[foo]", [], ["foo"], "dev-libs/A:0[foo]"),
+                       ("dev-libs/A:0[foo=]", [], ["foo"], "dev-libs/A:0[foo]"),
+
+                       ("dev-libs/A[foo,-bar]", ["foo"], ["bar"], "dev-libs/A[foo,-bar]"),
+                       ("dev-libs/A[-foo,bar]", ["foo", "bar"], [], "dev-libs/A[-foo,bar]"),
+
+                       ("dev-libs/A[a,b=,!c=,d?,!e?,-f]", ["a", "b", "c"], [], "dev-libs/A[a,-f,d,-e,-b,c]"),
+                       ("dev-libs/A[a,b=,!c=,d?,!e?,-f]", [], ["a", "b", "c"], "dev-libs/A[a,-f,d,-e,b,-c]"),
+                       ("dev-libs/A[a,b=,!c=,d?,!e?,-f]", ["d", "e", "f"], [], "dev-libs/A[a,-f,-e,b,-b,-c,c]"),
+                       ("dev-libs/A[a,b=,!c=,d?,!e?,-f]", [], ["d", "e", "f"], "dev-libs/A[a,-f,d,b,-b,-c,c]"),
+                       
+                       ("dev-libs/A[a(-),b(+)=,!c(-)=,d(+)?,!e(-)?,-f(+)]", \
+                               ["a", "b", "c", "d", "e", "f"], [], "dev-libs/A[a(-),-f(+),-e(-),-b(+),c(-)]"),
+                       ("dev-libs/A[a(+),b(-)=,!c(+)=,d(-)?,!e(+)?,-f(-)]", \
+                               [], ["a", "b", "c", "d", "e", "f"], "dev-libs/A[a(+),-f(-),d(-),b(-),-c(+)]"),
+               )
+
+               for atom, use_mask, use_force, expected_atom in test_cases:
+                       a = Atom(atom)
+                       b = a._eval_qa_conditionals(use_mask, use_force)
+                       self.assertEqual(str(b), expected_atom)
+                       self.assertEqual(str(b.unevaluated_atom), atom)
index e5a418cd8d22cca7763b5d027d6590ae92609271..dac05567c53b0a87a64b415bf57ea8ebc31e2938 100644 (file)
@@ -1,26 +1,94 @@
-# test_match_from_list.py -- Portage Unit Testing Functionality
-# Copyright 2006 Gentoo Foundation
+# Copyright 2006, 2010 Gentoo Foundation
 # Distributed under the terms of the GNU General Public License v2
 
 from portage.tests import TestCase
-from portage.dep import match_from_list
+from portage.dep import Atom, match_from_list
+from portage.versions import catpkgsplit
+
+class Package(object):
+       """
+       Provides a minimal subset of attributes of _emerge.Package.Package
+       """
+       def __init__(self, atom):
+               atom = Atom(atom)
+               self.cp = atom.cp
+               self.cpv = atom.cpv
+               self.cpv_split = catpkgsplit(self.cpv)
+               self.slot = atom.slot
+               if atom.use:
+                       self.use = self._use_class(atom.use.enabled)
+                       self.iuse = self._iuse_class(atom.use.required)
+               else:
+                       self.use = self._use_class([])
+                       self.iuse = self._iuse_class([])
+
+       class _use_class(object):
+               def __init__(self, use):
+                       self.enabled = frozenset(use)
+
+       class _iuse_class(object):
+               def __init__(self, iuse):
+                       self.all = frozenset(iuse)
+
+               def is_valid_flag(self, flags):
+                       if isinstance(flags, basestring):
+                               flags = [flags]
+                       missing_iuse = []
+                       for flag in flags:
+                               if not flag in self.all:
+                                       return False
+                       return True
 
 class Test_match_from_list(TestCase):
 
        def testMatch_from_list(self):
-               tests = [ ("=sys-apps/portage-45*", ["sys-apps/portage-045"], ["sys-apps/portage-045"] ),
-                                       ("=sys-fs/udev-1*", ["sys-fs/udev-123"], ["sys-fs/udev-123"]),
-                                       ("=sys-fs/udev-4*", ["sys-fs/udev-456"], ["sys-fs/udev-456"] ),
-                                       ("*/*", ["sys-fs/udev-456"], ["sys-fs/udev-456"] ),
-                                       ("sys-fs/*", ["sys-fs/udev-456"], ["sys-fs/udev-456"] ),
-                                       ("*/udev", ["sys-fs/udev-456"], ["sys-fs/udev-456"] ),
-                                       ("=sys-apps/portage-2*", ["sys-apps/portage-2.1"], ["sys-apps/portage-2.1"] ),
-                                       ("=sys-apps/portage-2.1*", ["sys-apps/portage-2.1.2"], ["sys-apps/portage-2.1.2"] ),
-                                       ("dev-libs/*", ["sys-apps/portage-2.1.2"], [] ),
-                                       ("*/tar", ["sys-apps/portage-2.1.2"], [] ),
-                                       ("*/*", ["dev-libs/A-1", "dev-libs/B-1"], ["dev-libs/A-1", "dev-libs/B-1"] ),
-                                       ("dev-libs/*", ["dev-libs/A-1", "sci-libs/B-1"], ["dev-libs/A-1"] )
-                               ]
-
-               for atom, cpv_list, result in tests:
-                       self.assertEqual( match_from_list( atom, cpv_list ), result )
+               tests = (
+                       ("=sys-apps/portage-45*", [], [] ),
+                       ("=sys-apps/portage-45*", ["sys-apps/portage-045"], ["sys-apps/portage-045"] ),
+                       ("!=sys-apps/portage-45*", ["sys-apps/portage-045"], ["sys-apps/portage-045"] ),
+                       ("!!=sys-apps/portage-45*", ["sys-apps/portage-045"], ["sys-apps/portage-045"] ),
+                       ("=sys-apps/portage-045", ["sys-apps/portage-045"], ["sys-apps/portage-045"] ),
+                       ("=sys-apps/portage-045", ["sys-apps/portage-046"], [] ),
+                       ("~sys-apps/portage-045", ["sys-apps/portage-045-r1"], ["sys-apps/portage-045-r1"] ),
+                       ("~sys-apps/portage-045", ["sys-apps/portage-046-r1"], [] ),
+                       ("<=sys-apps/portage-045", ["sys-apps/portage-045"], ["sys-apps/portage-045"] ),
+                       ("<=sys-apps/portage-045", ["sys-apps/portage-046"], [] ),
+                       ("<sys-apps/portage-046", ["sys-apps/portage-045"], ["sys-apps/portage-045"] ),
+                       ("<sys-apps/portage-046", ["sys-apps/portage-046"], [] ),
+                       (">=sys-apps/portage-045", ["sys-apps/portage-045"], ["sys-apps/portage-045"] ),
+                       (">=sys-apps/portage-047", ["sys-apps/portage-046-r1"], [] ),
+                       (">sys-apps/portage-044", ["sys-apps/portage-045"], ["sys-apps/portage-045"] ),
+                       (">sys-apps/portage-047", ["sys-apps/portage-046-r1"], [] ),
+                       ("sys-apps/portage:0", [Package("=sys-apps/portage-045:0")], ["sys-apps/portage-045"] ),
+                       ("sys-apps/portage:0", [Package("=sys-apps/portage-045:1")], [] ),
+                       ("=sys-fs/udev-1*", ["sys-fs/udev-123"], ["sys-fs/udev-123"]),
+                       ("=sys-fs/udev-4*", ["sys-fs/udev-456"], ["sys-fs/udev-456"] ),
+                       ("*/*", ["sys-fs/udev-456"], ["sys-fs/udev-456"] ),
+                       ("sys-fs/*", ["sys-fs/udev-456"], ["sys-fs/udev-456"] ),
+                       ("*/udev", ["sys-fs/udev-456"], ["sys-fs/udev-456"] ),
+                       ("=sys-apps/portage-2*", ["sys-apps/portage-2.1"], ["sys-apps/portage-2.1"] ),
+                       ("=sys-apps/portage-2.1*", ["sys-apps/portage-2.1.2"], ["sys-apps/portage-2.1.2"] ),
+                       ("dev-libs/*", ["sys-apps/portage-2.1.2"], [] ),
+                       ("*/tar", ["sys-apps/portage-2.1.2"], [] ),
+                       ("*/*", ["dev-libs/A-1", "dev-libs/B-1"], ["dev-libs/A-1", "dev-libs/B-1"] ),
+                       ("dev-libs/*", ["dev-libs/A-1", "sci-libs/B-1"], ["dev-libs/A-1"] ),
+                       
+                       ("dev-libs/A[foo]", [Package("=dev-libs/A-1[foo]"), Package("=dev-libs/A-2[-foo]")], ["dev-libs/A-1"] ),
+                       ("dev-libs/A[-foo]", [Package("=dev-libs/A-1[foo]"), Package("=dev-libs/A-2[-foo]")], ["dev-libs/A-2"] ),
+                       ("dev-libs/A[-foo]", [Package("=dev-libs/A-1[foo]"), Package("=dev-libs/A-2")], [] ),
+                       ("dev-libs/A[foo,bar]", [Package("=dev-libs/A-1[foo]"), Package("=dev-libs/A-2[-foo]")], [] ),
+                       ("dev-libs/A[foo,bar]", [Package("=dev-libs/A-1[foo]"), Package("=dev-libs/A-2[-foo,bar]")], [] ),
+                       ("dev-libs/A[foo,bar]", [Package("=dev-libs/A-1[foo]"), Package("=dev-libs/A-2[foo,bar]")], ["dev-libs/A-2"] ),
+                       ("dev-libs/A[foo,bar(+)]", [Package("=dev-libs/A-1[-foo]"), Package("=dev-libs/A-2[foo]")], ["dev-libs/A-2"] ),
+                       ("dev-libs/A[foo,bar(-)]", [Package("=dev-libs/A-1[-foo]"), Package("=dev-libs/A-2[foo]")], [] ),
+                       ("dev-libs/A[foo,-bar(-)]", [Package("=dev-libs/A-1[-foo,bar]"), Package("=dev-libs/A-2[foo]")], ["dev-libs/A-2"] ),
+               )
+
+               for atom, cpv_list, expected_result in tests:
+                       result = []
+                       for pkg in match_from_list( atom, cpv_list ):
+                               if isinstance(pkg, Package):
+                                       result.append(pkg.cpv)
+                               else:
+                                       result.append(pkg)
+                       self.assertEqual( result, expected_result )
diff --git a/pym/portage/tests/resolver/test_use_dep_defaults.py b/pym/portage/tests/resolver/test_use_dep_defaults.py
new file mode 100644 (file)
index 0000000..8f41e40
--- /dev/null
@@ -0,0 +1,40 @@
+# Copyright 2010 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from portage.tests import TestCase
+from portage.tests.resolver.ResolverPlayground import ResolverPlayground, ResolverPlaygroundTestCase
+
+class UseDepDefaultsTestCase(TestCase):
+
+       def testUseDepDefaultse(self):
+               pass
+               #~ ebuilds = {
+                       #~ "dev-libs/A-1": { "DEPEND": "dev-libs/B[foo]", "RDEPEND": "dev-libs/B[foo]", "EAPI": 2 },
+                       #~ "dev-libs/A-2": { "DEPEND": "dev-libs/B[foo(+)]", "RDEPEND": "dev-libs/B[foo(+)]", "EAPI": 4 },
+                       #~ "dev-libs/A-3": { "DEPEND": "dev-libs/B[foo(-)]", "RDEPEND": "dev-libs/B[foo(-)]", "EAPI": 4 },
+                       #~ "dev-libs/B-1": { "IUSE": "+foo", "EAPI": 1 },
+                       #~ "dev-libs/B-2": {},
+                       #~ }
+#~ 
+               #~ test_cases = (
+                       #~ ResolverPlaygroundTestCase(
+                               #~ ["=dev-libs/A-1"],
+                               #~ success = True,
+                               #~ mergelist = ["dev-libs/B-1", "dev-libs/A-1"]),
+                       #~ ResolverPlaygroundTestCase(
+                               #~ ["=dev-libs/A-2"],
+                               #~ success = True,
+                               #~ mergelist = ["dev-libs/B-2", "dev-libs/A-2"]),
+                       #~ ResolverPlaygroundTestCase(
+                               #~ ["=dev-libs/A-3"],
+                               #~ success = True,
+                               #~ mergelist = ["dev-libs/B-1", "dev-libs/A-3"]),
+                       #~ )
+#~ 
+               #~ playground = ResolverPlayground(ebuilds=ebuilds)
+               #~ try:
+                       #~ for test_case in test_cases:
+                               #~ playground.run_TestCase(test_case)
+                               #~ self.assertEqual(test_case.test_success, True, test_case.fail_msg)
+               #~ finally:
+                       #~ playground.cleanup()