replace emerge.AtomSet with portage.sets.InternalPackageSet
authorMarius Mauch <genone@gentoo.org>
Mon, 16 Jul 2007 12:35:32 +0000 (12:35 -0000)
committerMarius Mauch <genone@gentoo.org>
Mon, 16 Jul 2007 12:35:32 +0000 (12:35 -0000)
svn path=/main/trunk/; revision=7279

pym/emerge/__init__.py
pym/portage/elog/mod_mail.py
pym/portage/sets/__init__.py

index 541be2c15537e59692d9f2e3b98e31c7bf8f27d4..ab9b683c6531bd59297081d9f008e83e167c6e68 100644 (file)
@@ -52,6 +52,7 @@ import portage.exception
 from portage.data import secpass
 from portage.util import normalize_path as normpath
 from portage.util import writemsg
+from portage.sets import InternalPackageSet
 
 from itertools import chain, izip
 from UserDict import DictMixin
@@ -566,7 +567,7 @@ def clean_world(vardb, cpv):
        """Remove a package from the world file when unmerged."""
        world_set = WorldSet(vardb.settings)
        world_set.lock()
-       world_set.load()
+       world_set.xload()
        worldlist = list(world_set)
        mykey = portage.cpv_getkey(cpv)
        newworldlist = []
@@ -591,74 +592,20 @@ def clean_world(vardb, cpv):
        world_set.save()
        world_set.unlock()
 
-class AtomSet(object):
-       def __init__(self, atoms=None):
-               self._atoms = {}
-               if atoms:
-                       self.update(atoms)
-       def clear(self):
-               self._atoms.clear()
-       def add(self, atom):
-               cp = portage.dep_getkey(atom)
-               cp_list = self._atoms.get(cp)
-               if cp_list is None:
-                       cp_list = []
-                       self._atoms[cp] = cp_list
-               if atom not in cp_list:
-                       cp_list.append(atom)
-       def update(self, atoms):
-               for atom in atoms:
-                       self.add(atom)
-       def __contains__(self, atom):
-               cp = portage.dep_getkey(atom)
-               if cp in self._atoms and atom in self._atoms[cp]:
-                       return True
-               return False
-       def findAtomForPackage(self, cpv, metadata):
-               """Return the best match for a given package from the arguments, or
-               None if there are no matches.  This matches virtual arguments against
-               the PROVIDE metadata.  This can raise an InvalidDependString exception
-               if an error occurs while parsing PROVIDE."""
-               cpv_slot = "%s:%s" % (cpv, metadata["SLOT"])
-               cp = portage.dep_getkey(cpv)
-               atoms = self._atoms.get(cp)
-               if atoms:
-                       best_match = portage.best_match_to_list(cpv_slot, atoms)
-                       if best_match:
-                               return best_match
-               if not metadata["PROVIDE"]:
-                       return None
-               provides = portage.flatten(portage.dep.use_reduce(
-                       portage.dep.paren_reduce(metadata["PROVIDE"]),
-                       uselist=metadata["USE"].split()))
-               for provide in provides:
-                       provided_cp = portage.dep_getkey(provide)
-                       atoms = self._atoms.get(provided_cp)
-                       if atoms:
-                               transformed_atoms = [atom.replace(provided_cp, cp) for atom in atoms]
-                               best_match = portage.best_match_to_list(cpv_slot, transformed_atoms)
-                               if best_match:
-                                       return atoms[transformed_atoms.index(best_match)]
-               return None
-       def __iter__(self):
-               for atoms in self._atoms.itervalues():
-                       for atom in atoms:
-                               yield atom
-
-class SystemSet(AtomSet):
+class SystemSet(InternalPackageSet):
        def __init__(self, settings, **kwargs):
-               AtomSet.__init__(self, **kwargs)
+               InternalPackageSet.__init__(self, **kwargs)
                self.update(getlist(settings, "system"))
 
-class WorldSet(AtomSet):
+class WorldSet(InternalPackageSet):
        def __init__(self, settings, **kwargs):
-               AtomSet.__init__(self, **kwargs)
+               InternalPackageSet.__init__(self, **kwargs)
                self.world_file = os.path.join(settings["ROOT"], portage.WORLD_FILE)
                self._lock = None
        def _ensure_dirs(self):
                portage.util.ensure_dirs(os.path.dirname(self.world_file),
                        gid=portage.portage_gid, mode=02750, mask=02)
-       def load(self):
+       def xload(self):
                self.clear()
                self.update(portage.util.grabfile_package(self.world_file))
        def save(self):
@@ -681,7 +628,7 @@ class RootConfig(object):
                self.root = self.settings["ROOT"]
                self.sets = {}
                world_set = WorldSet(self.settings)
-               world_set.load()
+               world_set.xload()
                self.sets["world"] = world_set
                system_set = SystemSet(self.settings)
                self.sets["system"] = system_set
@@ -1144,10 +1091,10 @@ class depgraph(object):
                # contains all sets added to the graph
                self._sets = {}
                # contains atoms given as arguments
-               self._sets["args"] = AtomSet()
+               self._sets["args"] = InternalPackageSet()
                # contains all atoms from all sets added to the graph, including
                # atoms given as arguments
-               self._set_atoms = AtomSet()
+               self._set_atoms = InternalPackageSet()
                # contains all nodes pulled in by self._set_atoms
                self._set_nodes = set()
                self.blocker_digraph = digraph()
@@ -2588,8 +2535,7 @@ class depgraph(object):
                if verbosity is None:
                        verbosity = ("--quiet" in self.myopts and 1 or \
                                "--verbose" in self.myopts and 3 or 2)
-               favorites_set = AtomSet()
-               favorites_set.update(favorites)
+               favorites_set = InternalPackageSet(favorites)
                changelogs=[]
                p=[]
                blockers = []
@@ -3069,10 +3015,10 @@ class depgraph(object):
                                pkg_system = False
                                pkg_world = False
                                try:
-                                       pkg_system = system_set.findAtomForPackage(pkg_key, metadata)
-                                       pkg_world  = world_set.findAtomForPackage(pkg_key, metadata)
+                                       pkg_system = system_set.containsCPV(pkg_key)
+                                       pkg_world  = world_set.containsCPV(pkg_key)
                                        if not pkg_world and myroot == self.target_root and \
-                                               favorites_set.findAtomForPackage(pkg_key, metadata):
+                                               favorites_set.containsCPV(pkg_key):
                                                # Maybe it will be added to world now.
                                                if create_world_atom(pkg_key, metadata,
                                                        favorites_set, root_config):
@@ -3278,7 +3224,7 @@ class depgraph(object):
                root_config = self.roots[self.target_root]
                world_set = root_config.sets["world"]
                world_set.lock()
-               world_set.load()
+               world_set.xload()
                args_set = self._sets["args"]
                portdb = self.trees[self.target_root]["porttree"].dbapi
                added_favorites = set()
@@ -3537,7 +3483,7 @@ class MergeTask(object):
 
                root_config = RootConfig(self.trees[self.target_root])
                system_set = root_config.sets["system"]
-               args_set = AtomSet(favorites)
+               args_set = InternalPackageSet(favorites)
                world_set = root_config.sets["world"]
                if "--resume" not in self.myopts:
                        mymergelist = mylist
@@ -3634,7 +3580,7 @@ class MergeTask(object):
                        #buildsyspkg: Check if we need to _force_ binary package creation
                        issyspkg = ("buildsyspkg" in myfeat) \
                                        and x[0] != "blocks" \
-                                       and system_set.findAtomForPackage(pkg_key, metadata) \
+                                       and system_set.containsCPV(pkg_key) \
                                        and "--buildpkg" not in self.myopts
                        if x[0] in ["ebuild","blocks"]:
                                if x[0] == "blocks" and "--fetchonly" not in self.myopts:
@@ -3826,9 +3772,9 @@ class MergeTask(object):
                                self.trees[x[1]]["vartree"].inject(x[2])
                                myfavkey = portage.cpv_getkey(x[2])
                                if not fetchonly and not pretend and \
-                                       args_set.findAtomForPackage(pkg_key, metadata):
+                                       args_set.containsCPV(pkg_key):
                                        world_set.lock()
-                                       world_set.load()
+                                       world_set.xload()
                                        myfavkey = create_world_atom(pkg_key, metadata,
                                                args_set, root_config)
                                        if myfavkey:
@@ -5352,7 +5298,7 @@ def action_depclean(settings, trees, ldpath_mtimes,
        system_set = SystemSet(settings)
        syslist = list(system_set)
        world_set = WorldSet(settings)
-       world_set.load()
+       world_set.xload()
        worldlist = list(world_set)
        fakedb = portage.fakedbapi(settings=settings)
        myvarlist = vardb.cpv_all()
index d0d2b33ac32edc4377f67ed57894ff6ae35a2dbd..c9fa5b5639b1bb874db7c4217ae1ba8ac6b0a09d 100644 (file)
@@ -16,6 +16,21 @@ def process(mysettings, key, logentries, fulltext):
        mysubject = mysubject.replace("${PACKAGE}", key)
        mysubject = mysubject.replace("${HOST}", socket.getfqdn())
 
+       # look at the phases listed in our logentries to figure out what action was performed
+       action = "merged"
+       for phase in logentries.keys():
+               # if we found a *rm phase assume that the package was unmerged
+               if phase in ["postrm", "prerm"]:
+                       action = "unmerged"
+       # if we think that the package was unmerged, make sure there was no unexpected
+       # phase recorded to avoid misinformation
+       if action == "unmerged":
+               for phase in logentries.keys():
+                       if phase not in ["postrm", "prerm", "other"]:
+                               action = "unknown"
+
+       mysubject = mysubject.replace("${ACTION}", action)
+
        mymessage = portage.mail.create_message(myfrom, myrecipient, mysubject, fulltext)
        portage.mail.send_mail(mysettings, mymessage)
 
index e2087d816a5ef5ded1efa2f917d48102dd2cf8c7..a7428c092a6c81ef9fadce4834937e75553b791c 100644 (file)
@@ -6,7 +6,8 @@ import os
 
 from portage.const import PRIVATE_PATH, USER_CONFIG_PATH
 from portage.exception import InvalidAtom
-from portage.dep import isvalidatom, match_from_list, dep_getkey
+from portage.dep import isvalidatom, match_from_list, best_match_to_list, dep_getkey, use_reduce, paren_reduce
+from portage import flatten
 
 OPERATIONS = ["merge", "unmerge"]
 DEFAULT_SETS = ["world", "system", "everything", "security"] \
@@ -18,13 +19,22 @@ class PackageSet(object):
        # package sets, the latter doesn't make sense for some sets like "system"
        # or "security" and therefore isn't supported by them.
        _operations = ["merge"]
+       _atommap = {}
        description = "generic package set"
        
        def __init__(self, name):
-               self._name = name
+               self.name = name
                self._atoms = set()
+               self._atommap = {}
                self._loaded = False
        
+       def __contains__(self, atom):
+               return atom in self.getAtoms()
+       
+       def __iter__(self):
+               for x in self.getAtoms():
+                       yield x
+       
        def supportsOperation(self, op):
                if not op in OPERATIONS:
                        raise ValueError(op)
@@ -44,10 +54,8 @@ class PackageSet(object):
                        elif not isvalidatom(a):
                                raise InvalidAtom(a)
                self._atoms = atoms
-       
-       def getName(self):
-               return self._name
-       
+               self._updateAtomMap()
+
        def load(self):
                # This method must be overwritten by subclasses
                # Editable sets should use the value of self._mtime to determine if they
@@ -56,7 +64,7 @@ class PackageSet(object):
 
        def containsCPV(self, cpv):
                for a in self.getAtoms():
-                       if match_from_list(a, cpv):
+                       if match_from_list(a, [cpv]):
                                return True
                return False
        
@@ -66,30 +74,69 @@ class PackageSet(object):
                else:
                        return ""
        
+       def _updateAtomMap(self):
+               for a in self.getAtoms():
+                       cp = dep_getkey(a)
+                       self._atommap.setdefault(cp, set())
+                       self._atommap[cp].add(a)
+       
+       # Not sure if this one should really be in PackageSet
+       def findAtomForPackage(self, cpv, metadata):
+               """Return the best match for a given package from the arguments, or
+               None if there are no matches.  This matches virtual arguments against
+               the PROVIDE metadata.  This can raise an InvalidDependString exception
+               if an error occurs while parsing PROVIDE."""
+               cpv_slot = "%s:%s" % (cpv, metadata["SLOT"])
+               cp = dep_getkey(cpv)
+               atoms = self._atommap.get(cp)
+               if atoms:
+                       best_match = best_match_to_list(cpv_slot, atoms)
+                       if best_match:
+                               return best_match
+               if not metadata["PROVIDE"]:
+                       return None
+               provides = flatten(use_reduce(paren_reduce(metadata["PROVIDE"]),
+                                                               uselist=metadata["USE"].split()))
+               for provide in provides:
+                       provided_cp = dep_getkey(provide)
+                       atoms = self._atommap.get(provided_cp)
+                       if atoms:
+                               atoms = list(atoms)
+                               transformed_atoms = [atom.replace(provided_cp, cp) for atom in atoms]
+                               best_match = best_match_to_list(cpv_slot, transformed_atoms)
+                               if best_match:
+                                       return atoms[transformed_atoms.index(best_match)]
+               return None
 
 class EditablePackageSet(PackageSet):
        def getAtoms(self):
                self.load()
                return self._atoms
 
-       def updateAtoms(self, atoms):
+       def update(self, atoms):
                self.load()
                self._atoms.update(atoms)
+               self._updateAtomMap()
                self.write()
        
-       def addAtom(self, atom):
-               self.updateAtoms([atom])
+       def add(self, atom):
+               self.update([atom])
+
+       def replace(self, atoms):
+               self._setAtoms(atoms)
+               self.write()
 
-       def removeAtom(self, atom):
+       def remove(self, atom):
                self.load()
                self._atoms.discard(atom)
+               self._updateAtomMap()
                self.write()
 
        def removePackageAtoms(self, cp):
                self.load()
                for a in self.getAtoms():
                        if dep_getkey(a) == cp:
-                               self._atoms.discard(a)
+                               self.remove(a)
                self.write()
 
        def write(self):
@@ -98,7 +145,14 @@ class EditablePackageSet(PackageSet):
 
 
 class InternalPackageSet(EditablePackageSet):
-       _operations = ["merge", "unmerge"]
+       def __init__(self, initial_atoms=None):
+               super(InternalPackageSet, self).__init__("")
+               if initial_atoms != None:
+                       self.update(initial_atoms)
+
+       def clear(self):
+               self._atoms.clear()
+               self._updateAtomMap()
        
        def load(self):
                pass
@@ -172,9 +226,9 @@ if __name__ == "__main__":
                        elif s != "*":
                                print "ERROR: could not create set '%s'" % s
                if not "*" in sys.argv:
-                       l = [s for s in l if s.getName() in sys.argv[1:]]
+                       l = [s for s in l if s.name in sys.argv[1:]]
        for x in l:
-               print x.getName()+":"
+               print x.name+":"
                print "DESCRIPTION = %s" % x.getMetadata("Description")
                for n in sorted(x.getAtoms()):
                        print "- "+n