* Add support for Package instances and USE deps in match_from_list().
authorZac Medico <zmedico@gentoo.org>
Sun, 25 May 2008 21:34:21 +0000 (21:34 -0000)
committerZac Medico <zmedico@gentoo.org>
Sun, 25 May 2008 21:34:21 +0000 (21:34 -0000)
* Add USE dep matching support to depgraph._iter_atoms_for_pkg().

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

pym/_emerge/__init__.py
pym/portage/dep.py
pym/portage/sets/base.py

index 2616c1be75f91ab23f956446afe0e9a756087f41..1d3fc5f76e5b8ecae220a4349e83c06f2a6606e6 100644 (file)
@@ -1268,7 +1268,8 @@ class Package(Task):
        __slots__ = ("built", "cpv", "depth",
                "installed", "metadata", "onlydeps", "operation",
                "root", "type_name",
-               "category", "cp", "cpv_slot", "pf", "pv_split", "slot_atom")
+               "category", "cp", "cpv_slot", "cpv_split",
+               "pf", "pv_split", "slot", "slot_atom", "use")
 
        metadata_keys = [
                "CHOST", "COUNTER", "DEPEND", "EAPI", "IUSE", "KEYWORDS",
@@ -1277,11 +1278,43 @@ class Package(Task):
 
        def __init__(self, **kwargs):
                Task.__init__(self, **kwargs)
+               self.metadata = self._metadata_wrapper(self, self.metadata)
                self.cp = portage.cpv_getkey(self.cpv)
-               self.slot_atom = "%s:%s" % (self.cp, self.metadata["SLOT"])
-               self.cpv_slot = "%s:%s" % (self.cpv, self.metadata["SLOT"])
+               self.slot = self.metadata["SLOT"]
+               self.slot_atom = portage.dep.Atom("%s:%s" % \
+                       (self.cp, self.metadata["SLOT"]))
+
+               # This used to be "%s:%s" % (self.cpv, self.slot) but now
+               # is's just a reference to self since match_from_list()
+               # now supports Package references.
+               self.cpv_slot = self
+
                self.category, self.pf = portage.catsplit(self.cpv)
-               self.pv_split = portage.catpkgsplit(self.cpv)[1:]
+               self.cpv_split = portage.catpkgsplit(self.cpv)
+               self.pv_split = self.cpv_split[1:]
+               self.use = self._use(self.metadata["USE"].split())
+
+       class _use(object):
+               def __init__(self, use):
+                       self.enabled = frozenset(use)
+
+       class _metadata_wrapper(dict):
+               """
+               Detect metadata updates and synchronize Package attributes.
+               """
+               def __init__(self, pkg, metadata):
+                       dict.__init__(self, metadata.iteritems())
+                       self._pkg = pkg
+
+               def __setitem__(self, k, v):
+                       dict.__setitem__(self, k, v)
+                       if k == "USE":
+                               self._pkg.use = self._pkg._use(v.split())
+
+       def _metadata_setitem(self, k, v):
+               self._metadata_setitem_orig(k, v)
+               if k == "USE":
+                       self.use = self._use(self)
 
        def _get_hash_key(self):
                hash_key = getattr(self, "_hash_key", None)
@@ -3035,18 +3068,7 @@ class depgraph(object):
                                                        installed=installed, metadata=metadata,
                                                        onlydeps=onlydeps, root=root, type_name=pkg_type)
                                                self._pkg_cache[pkg] = pkg
-                                       myarg = None
-                                       if root == self.target_root:
-                                               try:
-                                                       myarg = self._iter_atoms_for_pkg(pkg).next()
-                                               except StopIteration:
-                                                       pass
-                                               except portage.exception.InvalidDependString:
-                                                       if not installed:
-                                                               # masked by corruption
-                                                               continue
-                                       if not installed and myarg:
-                                               found_available_arg = True
+
                                        if not installed or (installed and matched_packages):
                                                # Only enforce visibility on installed packages
                                                # if there is at least one other visible package
@@ -3085,6 +3107,22 @@ class depgraph(object):
                                                # it's expensive.
                                                pkgsettings.setcpv(cpv, mydb=pkg.metadata)
                                                pkg.metadata["USE"] = pkgsettings["PORTAGE_USE"]
+
+                                       myarg = None
+                                       if root == self.target_root:
+                                               try:
+                                                       # Ebuild USE must have been calculated prior
+                                                       # to this point, in case atoms have USE deps.
+                                                       myarg = self._iter_atoms_for_pkg(pkg).next()
+                                               except StopIteration:
+                                                       pass
+                                               except portage.exception.InvalidDependString:
+                                                       if not installed:
+                                                               # masked by corruption
+                                                               continue
+                                       if not installed and myarg:
+                                               found_available_arg = True
+
                                        if atom.use and not pkg.built:
                                                use = pkg.metadata["USE"].split()
                                                if atom.use.enabled.difference(use):
index 75d4f4c471dfad96c61c898a1276a9d0828b22dd..ae6363d0746fbd97eddb00bc4fa9c7882c1e7317 100644 (file)
@@ -759,6 +759,9 @@ def match_from_list(mydep, candidate_list):
        @return: A list of package atoms that match the given package atom
        """
 
+       if not candidate_list:
+               return []
+
        from portage.util import writemsg
        if "!" == mydep[:1]:
                mydep = mydep[1:]
@@ -791,13 +794,21 @@ def match_from_list(mydep, candidate_list):
 
        if operator is None:
                for x in candidate_list:
-                       if dep_getkey(x) != mycpv:
+                       cp = getattr(x, "cp", None)
+                       if cp is None:
+                               cp = dep_getkey(x)
+                       if cp != mycpv:
                                continue
                        mylist.append(x)
 
        elif operator == "=": # Exact match
-               mylist = [cpv for cpv in candidate_list if \
-                       cpvequal(remove_slot(cpv), mycpv)]
+               for x in candidate_list:
+                       xcpv = getattr(x, "cpv", None)
+                       if xcpv is None:
+                               xcpv = dep_getcpv(x)
+                       if not cpvequal(xcpv, mycpv):
+                               continue
+                       mylist.append(x)
 
        elif operator == "=*": # glob match
                # XXX: Nasty special casing for leading zeros
@@ -809,7 +820,9 @@ def match_from_list(mydep, candidate_list):
                        myver = "0"+myver
                mycpv = mysplit[0]+"/"+mysplit[1]+"-"+myver
                for x in candidate_list:
-                       xs = catpkgsplit(remove_slot(x))
+                       xs = getattr(x, "cpv_split", None)
+                       if xs is None:
+                               xs = catpkgsplit(remove_slot(x))
                        myver = xs[2].lstrip("0")
                        if not myver or not myver[0].isdigit():
                                myver = "0"+myver
@@ -819,7 +832,9 @@ def match_from_list(mydep, candidate_list):
 
        elif operator == "~": # version, any revision, match
                for x in candidate_list:
-                       xs = catpkgsplit(remove_slot(x))
+                       xs = getattr(x, "cpv_split", None)
+                       if xs is None:
+                               xs = catpkgsplit(remove_slot(x))
                        if xs is None:
                                raise InvalidData(x)
                        if not cpvequal(xs[0]+"/"+xs[1]+"-"+xs[2], mycpv_cps[0]+"/"+mycpv_cps[1]+"-"+mycpv_cps[2]):
@@ -831,8 +846,13 @@ def match_from_list(mydep, candidate_list):
        elif operator in [">", ">=", "<", "<="]:
                mysplit = ["%s/%s" % (cat, pkg), ver, rev]
                for x in candidate_list:
+                       xs = getattr(x, "cpv_split", None)
+                       if xs is None:
+                               xs = catpkgsplit(remove_slot(x))
+                       xcat, xpkg, xver, xrev = xs
+                       xs = ["%s/%s" % (xcat, xpkg), xver, xrev]
                        try:
-                               result = pkgcmp(pkgsplit(remove_slot(x)), mysplit)
+                               result = pkgcmp(xs, mysplit)
                        except ValueError: # pkgcmp may return ValueError during int() conversion
                                writemsg("\nInvalid package name: %s\n" % x, noiselevel=-1)
                                raise
@@ -859,9 +879,26 @@ def match_from_list(mydep, candidate_list):
                candidate_list = mylist
                mylist = []
                for x in candidate_list:
-                       xslot = dep_getslot(x)
+                       xslot = getattr(x, "slot", None)
+                       if xslot is None and isinstance(x, basestring):
+                               xslot = dep_getslot(x)
                        if xslot is not None and xslot != slot:
                                continue
                        mylist.append(x)
 
+       if mydep.use:
+               candidate_list = mylist
+               mylist = []
+               for x in candidate_list:
+                       # Note: IUSE intersection is neglected here since there
+                       # is currently no way to access implicit IUSE. However, IUSE
+                       # filtering can be added elsewhere in the chain.
+                       use = getattr(x, "use", None)
+                       if use is not None:
+                               if mydep.use.enabled.difference(use.enabled):
+                                       continue
+                               if mydep.use.disabled.intersection(use.enabled):
+                                       continue
+                       mylist.append(x)
+
        return mylist
index ac77e95c3597bd7bd863f11e796c3a3f653d5f72..3f85965bcf9b86d0b246acd99d9c2dcf24afe638 100644 (file)
@@ -108,7 +108,7 @@ class PackageSet(object):
                atoms = list(self.iterAtomsForPackage(pkg))
                if not atoms:
                        return None
-               return best_match_to_list(pkg.cpv_slot, atoms)
+               return best_match_to_list(pkg, atoms)
 
        def iterAtomsForPackage(self, pkg):
                """
@@ -116,7 +116,7 @@ class PackageSet(object):
                arguments against the PROVIDE metadata.  This will raise an
                InvalidDependString exception if PROVIDE is invalid.
                """
-               cpv_slot_list = ["%s:%s" % (pkg.cpv, pkg.metadata["SLOT"])]
+               cpv_slot_list = [pkg]
                cp = cpv_getkey(pkg.cpv)
                self._load() # make sure the atoms are loaded
                atoms = self._atommap.get(cp)