Merged from trunk 7137:7161
authorFabian Groffen <grobian@gentoo.org>
Thu, 5 Jul 2007 19:19:41 +0000 (19:19 -0000)
committerFabian Groffen <grobian@gentoo.org>
Thu, 5 Jul 2007 19:19:41 +0000 (19:19 -0000)
   +------------------------------------------------------------------------+
   | 7138    | In depgraph.select_files(), unify favorites handling with    |
   | zmedico | the other args handling.                                     |
   |---------+--------------------------------------------------------------|
   | 7139    | Fix --oneshot handling from the previous commit.             |
   | zmedico |                                                              |
   |---------+--------------------------------------------------------------|
   | 7140    | Use depgraph._args_nodes to simplify                         |
   | zmedico | depgraph.saveNomergeFavorites().                             |
   |---------+--------------------------------------------------------------|
   | 7142    | Record a slot atom in the world file for any atom that is    |
   | zmedico | precise enough to identify a specific slot. Make depclean    |
   |         | clean unnecessary slots of system and world packages. For    |
   |         | update and depclean, world atoms can be greedy with slots    |
   |         | while system atoms can not.                                  |
   |---------+--------------------------------------------------------------|
   | 7144    | Fix greedy atoms logic for system mode.                      |
   | zmedico |                                                              |
   |---------+--------------------------------------------------------------|
   | 7146    | For bug #183861, allow a color class in color.map to specify |
   | zmedico | a space separated list of attributes so that any combination |
   |         | of foreground, background, and other attributes is possible. |
   |         | Thanks to Arfrever Frehtes Taifersar Arahesis                |
   |         | <Arfrever.FTA@GMail.Com> for this patch.                     |
   |---------+--------------------------------------------------------------|
   | 7147    | Add a "onerror" callback to parse_color_map() for handling   |
   | zmedico | each ParseError that would otherwise be raised.              |
   |---------+--------------------------------------------------------------|
   | 7148    | Fix broken code concatenation logic in parse_color_map().    |
   | zmedico |                                                              |
   |---------+--------------------------------------------------------------|
   | 7149    | Make the color class handling for package sets more          |
   | zmedico | consistent as suggested in comment #2 of bug #183861.        |
   |---------+--------------------------------------------------------------|
   | 7150    | Document the additional color classes for bug #183861.       |
   | zmedico |                                                              |
   |---------+--------------------------------------------------------------|
   | 7153    | Replace sys.exit() with return in depgraph.display() and     |
   | zmedico | action_build().                                              |
   |---------+--------------------------------------------------------------|
   | 7155    | Add note about repo name warnings                            |
   | genone  |                                                              |
   |---------+--------------------------------------------------------------|
   | 7157    | Remove fallback imports for set(), and note minimum          |
   | genone  | requirement of python-2.4                                    |
   |---------+--------------------------------------------------------------|
   | 7159    | Remove redundant config update notification (bug #184116)    |
   | genone  |                                                              |
   |---------+--------------------------------------------------------------|
   | 7161    | Move depgraph._args_atoms to depgraph._sets["args"] and move |
   | zmedico | depgraph._args_nodes to self._set_nodes.                     |
   +------------------------------------------------------------------------+

svn path=/main/branches/prefix/; revision=7163

13 files changed:
RELEASE-NOTES
man/color.map.5
pym/emerge/__init__.py
pym/portage/__init__.py
pym/portage/cache/metadata_overlay.py
pym/portage/cache/util.py
pym/portage/cache/volatile.py
pym/portage/data.py
pym/portage/dbapi/vartree.py
pym/portage/getbinpkg.py
pym/portage/manifest.py
pym/portage/output.py
pym/portage/util.py

index faa5803163c2976a8fd6779837ba73c8b7b0600d..030ebfd1f6cca202f372d54efc3f3787c5baf005 100644 (file)
@@ -4,12 +4,11 @@ Features/major bugfixes are listed in NEWS
 portage-2.2
 ==================================
 
+* Portage now requires >=python-2.4, but doesn't need pycrypto anymore if 
+  >=python-2.5 is installed and openssl supports the rmd160 hash.
 * The python namespace for portage has been sanitized, all portage related code
   is now contained within the portage namespace. External script should be updated
   accordingly, though links exist for backward compability.
-* The "save_summary" and "echo" elog modules are now enabled by default. Setting
-  PORTAGE_ELOG_SYSTEM in make.conf will override this, so if you don't want elog
-  set PORTAGE_ELOG_SYSTEM="" in make.conf
 * -* support in package.keywords was changed as it was inconsistent with 
   ACCEPT_KEYWORDS behavior (also see http://dev.gentoo.org/~genone/docs/KEYWORDS.stupid).
   Previously having -* in package.keywords matched packages with KEYWORDS="-*", 
@@ -17,15 +16,27 @@ portage-2.2
   used in ACCEPT_KEYWORDS.
   For packages that don't specify any other KEYWORDS you can use the new ** token
   as documented in portage(5) to disable KEYWORDS filtering completely.
+* Portage now warns if a ebild repository does not have a name, as several new
+  features in 2.2 make use of or require named repositories. The repository name
+  is stored in profiles/repo_name in each repository.
 
 portage-2.1.3
 ==================================
 
+* The "save_summary" and "echo" elog modules are now enabled by default. Setting
+  PORTAGE_ELOG_SYSTEM in make.conf will override this, so if you don't want elog
+  set PORTAGE_ELOG_SYSTEM="" in make.conf
 * The unmerge process will remove any file that is not claimed by another
   package in the same slot and is not protected by CONFIG_PROTECT, even if the
   modification time or checksum differs from the file that was originally
   installed.  The old behavior is still available by adding -unmerge-orphans
   to FEATURES.
+* The world file now supports slot atoms such as 'sys-devel/gcc:3.4'. In some
+  cases, emerge --depclean may remove slots that it would not have removed
+  in the past. The emerge --noreplace command can be used to add an atom to the
+  world file and prevent matching packages from being removed.  A slot atom
+  will be recorded in the world file for any atom that is precise enough to
+  identify a specific slot.
 
 portage-2.1.2
 ==================================
index f7627610006775fc463aebb9c46c5956fbbfd553..10fa1a09a9a4a0e97588e78063c263f4606ca5ed 100644 (file)
@@ -39,10 +39,18 @@ arguments.
 Defines color used for packages planned to be merged and belonging to
 system set.
 .TP
+\fBPKG_MERGE_ARG_SYSTEM\fR = \fI"0x55FF55"\fR
+Defines color used for system packages planned to be merged and given as
+command line arguments.
+.TP
 \fBPKG_MERGE_WORLD\fR = \fI"0x55FF55"\fR
 Defines color used for packages planned to be merged and belonging to
 world set.
 .TP
+\fBPKG_MERGE_ARG_WORLD\fR = \fI"0x55FF55"\fR
+Defines color used for world packages planned to be merged and given as
+command line arguments.
+.TP
 \fBPKG_NOMERGE\fR = \fI"0x0000AA"\fR
 Defines color used for packages not planned to be merged.
 .TP
@@ -54,10 +62,18 @@ line arguments.
 Defines color used for packages not planned to be merged and belonging to
 system set.
 .TP
+\fBPKG_NOMERGE_ARG_SYSTEM\fR = \fI"0x5555FF"\fR
+Defines color used for system packages not planned to be merged and given as
+command line arguments.
+.TP
 \fBPKG_NOMERGE_WORLD\fR = \fI"0x5555FF"\fR
 Defines color used for packages not planned to be merged and belonging to
 world set.
 .TP
+\fBPKG_NOMERGE_ARG_WORLD\fR = \fI"0x5555FF"\fR
+Defines color used for world packages not planned to be merged and given as
+command line arguments.
+.TP
 \fBSECURITY_WARN\fR = \fI"0xFF5555"\fR
 Defines color used for security warnings.
 .TP
index 7252ab0ab73369c85722c35411de76aec8c92c11..a4e23aa9988365a1a226936355e303c7882bc2db 100644 (file)
@@ -52,8 +52,6 @@ from portage.data import secpass
 from portage.util import normalize_path as normpath
 from portage.util import writemsg
 
-if not hasattr(__builtins__, "set"):
-       from sets import Set as set
 from itertools import chain, izip
 from UserDict import DictMixin
 
@@ -631,6 +629,8 @@ class AtomSet(object):
                        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()))
@@ -675,6 +675,49 @@ class WorldSet(AtomSet):
                portage.locks.unlockfile(self._lock)
                self._lock = None
 
+class RootConfig(object):
+       """This is used internally by depgraph to track information about a
+       particular $ROOT."""
+       def __init__(self, trees):
+               self.trees = trees
+               self.settings = trees["vartree"].settings
+               self.root = self.settings["ROOT"]
+               self.sets = {}
+               world_set = WorldSet(self.settings)
+               world_set.load()
+               self.sets["world"] = world_set
+               system_set = SystemSet(self.settings)
+               self.sets["system"] = system_set
+
+def create_world_atom(pkg_key, metadata, args_set, world_set, portdb):
+       """Create a new atom for the world file if one does not exist.  If the
+       argument atom is precise enough to identify a specific slot then a slot
+       atom will be returned. The system set is not used in deciding which
+       atoms to store since system atoms can only match one slot while world
+       atoms can be greedy with respect to slots."""
+       arg_atom = args_set.findAtomForPackage(pkg_key, metadata)
+       cp = portage.dep_getkey(arg_atom)
+       new_world_atom = cp
+       if arg_atom != cp:
+               # If the user gave a specific atom, store it as a
+               # slot atom in the world file.
+               slot_atom = "%s:%s" % (cp, metadata["SLOT"])
+               # First verify the slot is in the portage tree to avoid
+               # adding a bogus slot like that produced by multislot.
+               if portdb.match(slot_atom):
+                       # Now verify that the argument is precise enough to identify a
+                       # specific slot.
+                       matches = portdb.match(arg_atom)
+                       matched_slots = set()
+                       for cpv in matches:
+                               matched_slots.add(portdb.aux_get(cpv, ["SLOT"])[0])
+                       if len(matched_slots) == 1:
+                               new_world_atom = slot_atom
+       if new_world_atom == world_set.findAtomForPackage(pkg_key, metadata):
+               # Both atoms would be identical, so there's nothing to add.
+               return None
+       return new_world_atom
+
 def filter_iuse_defaults(iuse):
        for flag in iuse:
                if flag.startswith("+") or flag.startswith("-"):
@@ -785,7 +828,7 @@ class FakeVartree(portage.vartree):
                        if os.access(vdb_path, os.W_OK):
                                vdb_lock = portage.locks.lockdir(vdb_path)
                        mykeys = ["SLOT", "COUNTER", "PROVIDE", "USE", "IUSE",
-                               "DEPEND", "RDEPEND", "PDEPEND", "repository"]
+                               "RESTRICT", "DEPEND", "RDEPEND", "PDEPEND", "repository"]
                        real_dbapi = real_vartree.dbapi
                        slot_counters = {}
                        for cpv in real_dbapi.cpv_all():
@@ -1026,9 +1069,10 @@ class depgraph(object):
                self._slot_node_map = {}
                self.mydbapi = {}
                self._mydbapi_keys = ["SLOT", "DEPEND", "RDEPEND", "PDEPEND",
-                       "USE", "IUSE", "PROVIDE", "repository"]
+                       "USE", "IUSE", "PROVIDE", "RESTRICT", "repository"]
                self.useFlags = {}
                self.trees = {}
+               self.roots = {}
                for myroot in trees:
                        self.trees[myroot] = {}
                        for tree in ("porttree", "bintree"):
@@ -1041,6 +1085,7 @@ class depgraph(object):
                        self.pkg_node_map[myroot] = {}
                        self._slot_node_map[myroot] = {}
                        vardb = self.trees[myroot]["vartree"].dbapi
+                       self.roots[myroot] = RootConfig(self.trees[myroot])
                        # This fakedbapi instance will model the state that the vdb will
                        # have after new packages have been installed.
                        fakedb = portage.fakedbapi(settings=self.pkgsettings[myroot])
@@ -1069,10 +1114,15 @@ class depgraph(object):
                self._parent_child_digraph = digraph()
                self.orderedkeys=[]
                self.outdatedpackages=[]
-               self._args_atoms = AtomSet()
-               self._args_nodes = set()
+               # contains all sets added to the graph
                self._sets = {}
-               self._sets_nodes = {}
+               # contains atoms given as arguments
+               self._sets["args"] = AtomSet()
+               # contains all atoms from all sets added to the graph, including
+               # atoms given as arguments
+               self._set_atoms = AtomSet()
+               # contains all nodes pulled in by self._set_atoms
+               self._set_nodes = set()
                self.blocker_digraph = digraph()
                self.blocker_parents = {}
                self._unresolved_blocker_parents = {}
@@ -1212,7 +1262,7 @@ class depgraph(object):
 
                if not arg and myroot == self.target_root:
                        try:
-                               arg = self._args_atoms.findAtomForPackage(mykey, metadata)
+                               arg = self._set_atoms.findAtomForPackage(mykey, metadata)
                        except portage.exception.InvalidDependString, e:
                                if mytype != "installed":
                                        show_invalid_depstring_notice(tuple(mybigkey+["merge"]),
@@ -1322,18 +1372,7 @@ class depgraph(object):
                                        priority=priority)
 
                if arg:
-                       self._args_nodes.add(jbigkey)
-                       try:
-                               for set_name, atom_set in self._sets.iteritems():
-                                       atom = atom_set.findAtomForPackage(mykey, metadata)
-                                       if atom:
-                                               self._sets_nodes[set_name].add(jbigkey)
-                       except portage.exception.InvalidDependString, e:
-                               if mytype != "installed":
-                                       show_invalid_depstring_notice(jbigkey,
-                                               metadata["PROVIDE"], str(e))
-                                       return 0
-                               del e
+                       self._set_nodes.add(jbigkey)
 
                # Do this even when addme is False (--onlydeps) so that the
                # parent/child relationship is always known in case
@@ -1452,8 +1491,7 @@ class depgraph(object):
                                if not self.create(["binary", myroot, mykey],
                                        None, "--onlydeps" not in self.myopts):
                                        return (0,myfavorites)
-                               elif not "--oneshot" in self.myopts:
-                                       myfavorites.append("="+mykey)
+                               arg_atoms.append((x, "="+mykey))
                        elif ext==".ebuild":
                                x = os.path.realpath(x)
                                mykey=os.path.basename(os.path.normpath(x+"/../.."))+"/"+os.path.splitext(os.path.basename(x))[0]
@@ -1475,8 +1513,7 @@ class depgraph(object):
                                if not self.create(["ebuild", myroot, mykey],
                                        None, "--onlydeps" not in self.myopts):
                                        return (0,myfavorites)
-                               elif not "--oneshot" in self.myopts:
-                                       myfavorites.append("="+mykey)
+                               arg_atoms.append((x, "="+mykey))
                        else:
                                if not is_valid_package_atom(x):
                                        portage.writemsg("\n\n!!! '%s' is not a valid package atom.\n" % x,
@@ -1491,16 +1528,12 @@ class depgraph(object):
                                                        settings=pkgsettings)
                                        if (mykey and not mykey.startswith("null/")) or \
                                                "--usepkgonly" in self.myopts:
-                                               if "--oneshot" not in self.myopts:
-                                                       myfavorites.append(mykey)
                                                arg_atoms.append((x, mykey))
                                                continue
 
                                        mykey = portage.dep_expand(x,
                                                mydb=portdb, settings=pkgsettings)
                                        arg_atoms.append((x, mykey))
-                                       if "--oneshot" not in self.myopts:
-                                               myfavorites.append(mykey)
                                except ValueError, errpkgs:
                                        print "\n\n!!! The short ebuild name \"" + x + "\" is ambiguous.  Please specify"
                                        print "!!! one of the following fully-qualified ebuild names instead:\n"
@@ -1558,10 +1591,17 @@ class depgraph(object):
                                                        greedy_atoms.append((myarg, myslot_atom))
                        arg_atoms = greedy_atoms
 
+               oneshot = "--oneshot" in self.myopts or "--onlydeps" in self.myopts
                """ These are used inside self.create() in order to ensure packages
                that happen to match arguments are not incorrectly marked as nomerge."""
+               args_set = self._sets["args"]
                for myarg, myatom in arg_atoms:
-                       self._args_atoms.add(myatom)
+                       if myatom in args_set:
+                               continue
+                       args_set.add(myatom)
+                       self._set_atoms.add(myatom)
+                       if not oneshot:
+                               myfavorites.append(myatom)
                for myarg, myatom in arg_atoms:
                                try:
                                        self.mysd = self.select_dep(myroot, myatom, arg=myarg)
@@ -1664,7 +1704,7 @@ class depgraph(object):
                if not mymerge and arg:
                        # A provided package has been specified on the command line.  The
                        # package will not be merged and a warning will be displayed.
-                       if depstring in self._args_atoms:
+                       if depstring in self._set_atoms:
                                self._pprovided_args.append((arg, depstring))
 
                if myparent:
@@ -2380,24 +2420,15 @@ class depgraph(object):
                        return [x for x in mylist \
                                if x in matches or not portdb.cpv_exists(x)]
                world_problems = False
-               if mode=="system":
-                       system_set = SystemSet(self.settings)
-                       mylist = list(system_set)
-                       self._sets["system"] = system_set
-                       self._sets_nodes["system"] = set()
-               else:
-                       #world mode
-                       world_set = WorldSet(self.settings)
-                       world_set.load()
-                       worldlist = list(world_set)
-                       self._sets["world"] = world_set
-                       self._sets_nodes["world"] = set()
-                       system_set = SystemSet(self.settings)
-                       mylist = list(system_set)
-                       self._sets["system"] = system_set
-                       self._sets_nodes["system"] = set()
 
-                       for x in worldlist:
+               root_config = self.roots[self.target_root]
+               world_set = root_config.sets["world"]
+               system_set = root_config.sets["system"]
+               mylist = list(system_set)
+               self._sets["system"] = system_set
+               if mode == "world":
+                       self._sets["world"] = world_set
+                       for x in world_set:
                                if not portage.isvalidatom(x):
                                        world_problems = True
                                        continue
@@ -2422,9 +2453,12 @@ class depgraph(object):
                        mykey = portage.dep_getkey(atom)
                        if True:
                                newlist.append(atom)
-                               """Make sure all installed slots are updated when possible.
-                               Do this with --emptytree also, to ensure that all slots are
-                               remerged."""
+                               if mode == "system" or atom not in world_set:
+                                       # only world is greedy for slots, not system
+                                       continue
+                               # Make sure all installed slots are updated when possible.
+                               # Do this with --emptytree also, to ensure that all slots are
+                               # remerged.
                                myslots = set()
                                for cpv in vardb.match(mykey):
                                        myslots.add(vardb.aux_get(cpv, ["SLOT"])[0])
@@ -2467,7 +2501,7 @@ class depgraph(object):
                mylist = newlist
 
                for myatom in mylist:
-                       self._args_atoms.add(myatom)
+                       self._set_atoms.add(myatom)
 
                missing_atoms = []
                for mydep in mylist:
@@ -2494,10 +2528,14 @@ class depgraph(object):
 
                return 1
 
-       def display(self,mylist,verbosity=None):
+       def display(self, mylist, favorites=[], verbosity=None):
                if verbosity is None:
                        verbosity = ("--quiet" in self.myopts and 1 or \
                                "--verbose" in self.myopts and 3 or 2)
+               if "--resume" in self.myopts and favorites:
+                       self._sets["args"].update(favorites)
+               favorites_set = AtomSet()
+               favorites_set.update(favorites)
                changelogs=[]
                p=[]
                blockers = []
@@ -2605,7 +2643,7 @@ class depgraph(object):
                                                # Do not traverse to parents if this node is an
                                                # an argument or a direct member of a set that has
                                                # been specified as an argument (system or world).
-                                               if current_node not in self._args_nodes:
+                                               if current_node not in self._set_nodes:
                                                        parent_nodes = mygraph.parent_nodes(current_node)
                                                if parent_nodes:
                                                        child_nodes = set(mygraph.child_nodes(current_node))
@@ -2718,6 +2756,19 @@ class depgraph(object):
                                        else:
                                                # An ebuild "nomerge" node, so USE come from the vardb.
                                                mydbapi = vartree.dbapi
+                               # reuse cached metadata from when the depgraph was built
+                               if "--resume" in self.myopts:
+                                       # Populate the fakedb with relevant metadata, just like
+                                       # would have happened when the depgraph was originally
+                                       # built.
+                                       metadata = dict(izip(self._mydbapi_keys,
+                                               mydbapi.aux_get(pkg_key, self._mydbapi_keys)))
+                                       self.mydbapi[myroot].cpv_inject(pkg_key, metadata=metadata)
+                               else:
+                                       metadata = dict(izip(self._mydbapi_keys,
+                                               self.mydbapi[myroot].aux_get(
+                                               pkg_key, self._mydbapi_keys)))
+                               mydbapi = self.mydbapi[myroot] # use the cached metadata
                                if pkg_key not in self.useFlags[myroot]:
                                        """If this is a --resume then the USE flags need to be
                                        fetched from the appropriate locations here."""
@@ -2733,7 +2784,7 @@ class depgraph(object):
                                                restrict = mydbapi.aux_get(pkg_key, ["RESTRICT"])[0]
                                                show_invalid_depstring_notice(x, restrict, str(e))
                                                del e
-                                               sys.exit(1)
+                                               return 1
                                        restrict = []
                                if "ebuild" == pkg_type and x[3] != "nomerge" and \
                                        "fetch" in restrict:
@@ -2886,7 +2937,7 @@ class depgraph(object):
                                                        src_uri = portdb.aux_get(pkg_key, ["SRC_URI"])[0]
                                                        show_invalid_depstring_notice(x, src_uri, str(e))
                                                        del e
-                                                       sys.exit(1)
+                                                       return 1
                                                if myfilesdict is None:
                                                        myfilesdict="[empty/missing/bad digest]"
                                                else:
@@ -2962,42 +3013,57 @@ class depgraph(object):
                                        myoldbest=blue("["+myoldbest+"]")
 
                                pkg_cp = xs[0]
-                               pkg_arg    = False
-                               pkg_world  = False
+                               root_config = self.roots[myroot]
+                               system_set = root_config.sets["system"]
+                               world_set  = root_config.sets["world"]
+                               args_set = self._sets["args"]
+
+                               pkg_arg = False
                                pkg_system = False
-                               pkg_node = tuple(x)
-                               if pkg_node in self._args_nodes:
-                                       pkg_arg = True
-                                       world_nodes = self._sets_nodes.get("world")
-                                       if world_nodes and pkg_node in world_nodes:
-                                               pkg_world = True
-                                       if world_nodes is None:
-                                               # Don't colorize system package when in "world" mode.
-                                               system_nodes = self._sets_nodes.get("system")
-                                               if system_nodes and pkg_node in system_nodes:
-                                                       pkg_system = True
+                               pkg_world = False
+                               try:
+                                       if myroot == self.target_root:
+                                               pkg_arg = args_set.findAtomForPackage(pkg_key, metadata)
+                                       pkg_system = system_set.findAtomForPackage(pkg_key, metadata)
+                                       pkg_world  = world_set.findAtomForPackage(pkg_key, metadata)
+                                       if not pkg_world and myroot == self.target_root:
+                                               # Maybe it will be added to world now.
+                                               pkg_world = favorites_set.findAtomForPackage(pkg_key, metadata)
+                               except portage.exception.InvalidDependString:
+                                       # This is reported elsewhere if relevant.
+                                       pass
 
                                def pkgprint(pkg):
                                        if pkg_merge:
                                                if pkg_arg:
                                                        if pkg_world:
-                                                               return colorize("PKG_MERGE_WORLD", pkg)
+                                                               return colorize("PKG_MERGE_ARG_WORLD", pkg)
                                                        elif pkg_system:
-                                                               return colorize("PKG_MERGE_SYSTEM", pkg)
+                                                               return colorize("PKG_MERGE_ARG_SYSTEM", pkg)
                                                        else:
                                                                return colorize("PKG_MERGE_ARG", pkg)
                                                else:
-                                                       return colorize("PKG_MERGE", pkg)
+                                                       if pkg_world:
+                                                               return colorize("PKG_MERGE_WORLD", pkg)
+                                                       elif pkg_system:
+                                                               return colorize("PKG_MERGE_SYSTEM", pkg)
+                                                       else:
+                                                               return colorize("PKG_MERGE", pkg)
                                        else:
                                                if pkg_arg:
                                                        if pkg_world:
-                                                               return colorize("PKG_NOMERGE_WORLD", pkg)
+                                                               return colorize("PKG_NOMERGE_ARG_WORLD", pkg)
                                                        elif pkg_system:
-                                                               return colorize("PKG_NOMERGE_SYSTEM", pkg)
+                                                               return colorize("PKG_NOMERGE_ARG_SYSTEM", pkg)
                                                        else:
                                                                return colorize("PKG_NOMERGE_ARG", pkg)
                                                else:
-                                                       return colorize("PKG_NOMERGE", pkg)
+                                                       if pkg_world:
+                                                               return colorize("PKG_NOMERGE_WORLD", pkg)
+                                                       elif pkg_system:
+                                                               return colorize("PKG_NOMERGE_SYSTEM", pkg)
+                                                       else:
+                                                               return colorize("PKG_NOMERGE", pkg)
 
                                if x[1]!="/":
                                        if myoldbest:
@@ -3123,6 +3189,7 @@ class depgraph(object):
                                msg.append("The best course of action depends on the reason that an offending\n")
                                msg.append("package.provided entry exists.\n\n")
                        sys.stderr.write("".join(msg))
+               return os.EX_OK
 
        def calc_changelog(self,ebuildpath,current,next):
                if ebuildpath == None or not os.path.exists(ebuildpath):
@@ -3176,61 +3243,40 @@ class depgraph(object):
                        if release.endswith('-r0'):
                                release = release[:-3]
 
-       def saveNomergeFavorites(self, mergelist, favorites):
+       def saveNomergeFavorites(self):
                """Find atoms in favorites that are not in the mergelist and add them
                to the world file if necessary."""
-               for x in ("--onlydeps", "--pretend", "--fetchonly", "--fetch-all-uri"):
+               for x in ("--fetchonly", "--fetch-all-uri",
+                       "--oneshot", "--onlydeps", "--pretend"):
                        if x in self.myopts:
                                return
-               favorites_set = AtomSet(favorites)
-               system_set = SystemSet(self.settings)
                world_set = WorldSet(self.settings)
                world_set.lock()
                world_set.load()
-               merge_atoms = set()
-               atom_pkgs = {}
-               for x in mergelist:
-                       pkg_type = x[0]
-                       if pkg_type not in self.pkg_tree_map:
-                               continue
+               args_set = self._sets["args"]
+               portdb = self.trees[self.target_root]["porttree"].dbapi
+               added_favorites = set()
+               for x in self._set_nodes:
                        pkg_type, root, pkg_key, pkg_status = x
-                       if root != self.target_root:
+                       if pkg_status != "nomerge":
                                continue
                        metadata = dict(izip(self._mydbapi_keys,
                                self.mydbapi[root].aux_get(pkg_key, self._mydbapi_keys)))
                        try:
-                               atom = favorites_set.findAtomForPackage(pkg_key, metadata)
+                               myfavkey = create_world_atom(pkg_key, metadata,
+                                       args_set, world_set, portdb)
+                               if myfavkey:
+                                       if myfavkey in added_favorites:
+                                               continue
+                                       added_favorites.add(myfavkey)
+                                       world_set.add(myfavkey)
+                                       print ">>> Recording",myfavkey,"in \"world\" favorites file..."
                        except portage.exception.InvalidDependString, e:
                                writemsg("\n\n!!! '%s' has invalid PROVIDE: %s\n" % \
                                        (pkg_key, str(e)), noiselevel=-1)
                                writemsg("!!! see '%s'\n\n" % os.path.join(
                                        root, portage.VDB_PATH, pkg_key, "PROVIDE"), noiselevel=-1)
                                del e
-                       if atom:
-                               merge_atoms.add(atom)
-               added_favorites = set()
-               root = self.target_root
-               for atom in set(favorites_set).difference(merge_atoms):
-                       pkgs = self.mydbapi[root].match(atom)
-                       for pkg_key in pkgs:
-                               metadata = dict(izip(self._mydbapi_keys,
-                                       self.mydbapi[root].aux_get(pkg_key, self._mydbapi_keys)))
-                               try:
-                                       if not (system_set.findAtomForPackage(pkg_key, metadata) or \
-                                               world_set.findAtomForPackage(pkg_key, metadata)):
-                                               myfavkey = portage.cpv_getkey(pkg_key)
-                                               if myfavkey in added_favorites:
-                                                       continue
-                                               added_favorites.add(myfavkey)
-                                               world_set.add(myfavkey)
-                                               modified = True
-                                               print ">>> Recording",myfavkey,"in \"world\" favorites file..."
-                               except portage.exception.InvalidDependString, e:
-                                       writemsg("\n\n!!! '%s' has invalid PROVIDE: %s\n" % \
-                                               (pkg_key, str(e)), noiselevel=-1)
-                                       writemsg("!!! see '%s'\n\n" % os.path.join(
-                                               root, portage.VDB_PATH, pkg_key, "PROVIDE"), noiselevel=-1)
-                                       del e
                if added_favorites:
                        world_set.save()
                world_set.unlock()
@@ -3311,6 +3357,7 @@ class MergeTask(object):
 
        def merge(self, mylist, favorites, mtimedb):
                from portage.elog import elog_process
+               from portage.elog.filtering import filter_mergephases
                failed_fetches = []
                fetchonly = "--fetchonly" in self.myopts or \
                        "--fetch-all-uri" in self.myopts
@@ -3372,9 +3419,8 @@ class MergeTask(object):
                                del x, mytype, myroot, mycpv, mystatus, quiet_config
                        del shown_verifying_msg, quiet_settings
 
-               #buildsyspkg: I need mysysdict also on resume (moved from the else block)
                system_set = SystemSet(self.settings)
-               favorites_set = AtomSet(favorites)
+               args_set = AtomSet(favorites)
                world_set = WorldSet(self.settings)
                if "--resume" not in self.myopts:
                        mymergelist = mylist
@@ -3471,7 +3517,7 @@ class MergeTask(object):
                        #buildsyspkg: Check if we need to _force_ binary package creation
                        issyspkg = ("buildsyspkg" in myfeat) \
                                        and x[0] != "blocks" \
-                                       and mysysdict.has_key(portage.cpv_getkey(x[2])) \
+                                       and system_set.findAtomForPackage(pkg_key, metadata) \
                                        and "--buildpkg" not in self.myopts
                        if x[0] in ["ebuild","blocks"]:
                                if x[0] == "blocks" and "--fetchonly" not in self.myopts:
@@ -3544,7 +3590,7 @@ class MergeTask(object):
                                                del pkgsettings["PORTAGE_BINPKG_TMPFILE"]
                                                if retval != os.EX_OK or \
                                                        "--buildpkgonly" in self.myopts:
-                                                       elog_process(pkg_key, pkgsettings)
+                                                       elog_process(pkg_key, pkgsettings, phasefilter=filter_mergephases)
                                                if retval != os.EX_OK:
                                                        return retval
                                                bintree = self.trees[myroot]["bintree"]
@@ -3661,13 +3707,12 @@ class MergeTask(object):
                                self.trees[x[1]]["vartree"].inject(x[2])
                                myfavkey = portage.cpv_getkey(x[2])
                                if not fetchonly and not pretend and \
-                                       favorites_set.findAtomForPackage(pkg_key, metadata):
+                                       args_set.findAtomForPackage(pkg_key, metadata):
                                        world_set.lock()
                                        world_set.load()
-                                       #don't record if already in system profile or already recorded
-                                       if not system_set.findAtomForPackage(pkg_key, metadata) and \
-                                               not world_set.findAtomForPackage(pkg_key, metadata):
-                                               #we don't have a favorites entry for this package yet; add one
+                                       myfavkey = create_world_atom(pkg_key, metadata,
+                                               args_set, world_set, portdb)
+                                       if myfavkey:
                                                world_set.add(myfavkey)
                                                print ">>> Recording",myfavkey,"in \"world\" favorites file..."
                                                emergelog(xterm_titles, " === ("+\
@@ -4818,9 +4863,8 @@ def action_sync(settings, trees, mtimedb, myopts, myaction):
                print
                print red(" * ")+bold("An update to portage is available.")+" It is _highly_ recommended"
                print red(" * ")+"that you update portage now, before any other packages are updated."
-               print red(" * ")+"Please run 'emerge portage' and then update "+bold("ALL")+" of your"
-               print red(" * ")+"configuration files."
-               print red(" * ")+"To update portage, run 'emerge portage'."
+               print
+               print red(" * ")+"To update portage, run 'emerge portage' now."
                print
        
        display_news_notification(trees)
@@ -5232,10 +5276,11 @@ def action_depclean(settings, trees, ldpath_mtimes,
        vardb = dep_check_trees[myroot]["vartree"].dbapi
        # Constrain dependency selection to the installed packages.
        dep_check_trees[myroot]["porttree"] = dep_check_trees[myroot]["vartree"]
-       syslist = getlist(settings, "system")
-       worldlist = getlist(settings, "world")
-       system_and_world = AtomSet(syslist)
-       system_and_world.update(worldlist)
+       system_set = SystemSet(settings)
+       syslist = list(system_set)
+       world_set = WorldSet(settings)
+       world_set.load()
+       worldlist = list(world_set)
        fakedb = portage.fakedbapi(settings=settings)
        myvarlist = vardb.cpv_all()
 
@@ -5273,29 +5318,11 @@ def action_depclean(settings, trees, ldpath_mtimes,
                        if not atom.startswith("!") and priority == hard:
                                unresolveable.setdefault(atom, []).append(parent)
                        continue
-               system_or_world = False
-               if parent in ('world', 'system'):
-                       system_or_world = True
-               else:
-                       for pkg in pkgs:
-                               metadata = dict(izip(metadata_keys,
-                                       vardb.aux_get(pkg, metadata_keys)))
-                               try:
-                                       if system_and_world.findAtomForPackage(pkg, metadata):
-                                               system_or_world = True
-                                               break
-                               except portage.exception.InvalidDependString, e:
-                                       writemsg("\n\n!!! '%s' has invalid PROVIDE: %s\n" % \
-                                               (pkg, str(e)), noiselevel=-1)
-                                       writemsg("!!! see '%s'\n\n" % os.path.join(
-                                               myroot, portage.VDB_PATH, pkg, "PROVIDE"),
-                                               noiselevel=-1)
-                                       del e
-               if not system_or_world:
+               if len(pkgs) > 1 and parent != "world":
                        # Prune all but the best matching slot, since that's all that a
-                       # deep world update would pull in.  Don't prune if the cpv is in
-                       # system or world though, since those sets trigger greedy update
-                       # of all slots.
+                       # deep world update would pull in.  Don't prune if this atom comes
+                       # directly from world though, since world atoms are greedy when
+                       # they don't specify a slot.
                        pkgs = [portage.best(pkgs)]
                for pkg in pkgs:
                        if fakedb.cpv_exists(pkg):
@@ -5443,7 +5470,7 @@ def action_build(settings, trees, mtimedb,
        else:
                if ("--resume" in myopts):
                        print darkgreen("emerge: It seems we have nothing to resume...")
-                       sys.exit(0)
+                       return os.EX_OK
 
                myparams = create_depgraph_params(myopts, myaction)
                if myaction in ["system","world"]:
@@ -5453,7 +5480,7 @@ def action_build(settings, trees, mtimedb,
                        mydepgraph = depgraph(settings, trees, myopts, myparams, spinner)
                        if not mydepgraph.xcreate(myaction):
                                print "!!! Depgraph creation failed."
-                               sys.exit(1)
+                               return 1
                        if "--quiet" not in myopts and "--nodeps" not in myopts:
                                print "\b\b... done!"
                else:
@@ -5465,9 +5492,9 @@ def action_build(settings, trees, mtimedb,
                                retval, favorites = mydepgraph.select_files(myfiles)
                        except portage.exception.PackageNotFound, e:
                                portage.writemsg("\n!!! %s\n" % str(e), noiselevel=-1)
-                               sys.exit(1)
+                               return 1
                        if not retval:
-                               sys.exit(1)
+                               return 1
                        if "--quiet" not in myopts and "--nodeps" not in myopts:
                                print "\b\b... done!"
 
@@ -5478,7 +5505,7 @@ def action_build(settings, trees, mtimedb,
                        for x in mydepgraph.missingbins:
                                sys.stderr.write("   "+str(x)+"\n")
                        sys.stderr.write("\nThese are required by '--usepkgonly' -- Terminating.\n\n")
-                       sys.exit(1)
+                       return 1
 
        if "--pretend" not in myopts and \
                ("--ask" in myopts or "--tree" in myopts or \
@@ -5491,12 +5518,18 @@ def action_build(settings, trees, mtimedb,
                                mymergelist = mymergelist[1:]
                        if len(mymergelist) == 0:
                                print colorize("INFORM", "emerge: It seems we have nothing to resume...")
-                               sys.exit(0)
-                       mydepgraph.display(mymergelist)
+                               return os.EX_OK
+                       favorites = mtimedb["resume"]["favorites"]
+                       retval = mydepgraph.display(mymergelist, favorites=favorites)
+                       if retval != os.EX_OK:
+                               return retval
                        prompt="Would you like to resume merging these packages?"
                else:
-                       mydepgraph.display(
-                               mydepgraph.altlist(reversed=("--tree" in myopts)))
+                       retval = mydepgraph.display(
+                               mydepgraph.altlist(reversed=("--tree" in myopts)),
+                               favorites=favorites)
+                       if retval != os.EX_OK:
+                               return retval
                        mergecount=0
                        for x in mydepgraph.altlist():
                                if x[0] != "blocks" and x[3] != "nomerge":
@@ -5507,7 +5540,7 @@ def action_build(settings, trees, mtimedb,
                                        print   "!!!        at the same time on the same system."
                                        if "--quiet" not in myopts:
                                                show_blocker_docs_link()
-                                       sys.exit(1)
+                                       return 1
                        if mergecount==0:
                                if "--noreplace" in myopts and favorites:
                                        print
@@ -5520,7 +5553,7 @@ def action_build(settings, trees, mtimedb,
                                        print
                                        print "Nothing to merge; quitting."
                                        print
-                                       sys.exit(0)
+                                       return os.EX_OK
                        elif "--fetchonly" in myopts or "--fetch-all-uri" in myopts:
                                prompt="Would you like to fetch the source files for these packages?"
                        else:
@@ -5530,7 +5563,7 @@ def action_build(settings, trees, mtimedb,
                        print
                        print "Quitting."
                        print
-                       sys.exit(0)
+                       return os.EX_OK
                # Don't ask again (e.g. when auto-cleaning packages after merge)
                myopts.pop("--ask", None)
 
@@ -5542,22 +5575,28 @@ def action_build(settings, trees, mtimedb,
                                mymergelist = mymergelist[1:]
                        if len(mymergelist) == 0:
                                print colorize("INFORM", "emerge: It seems we have nothing to resume...")
-                               sys.exit(0)
-                       mydepgraph.display(mymergelist)
+                               return os.EX_OK
+                       favorites = mtimedb["resume"]["favorites"]
+                       retval = mydepgraph.display(mymergelist, favorites=favorites)
+                       if retval != os.EX_OK:
+                               return retval
                else:
-                       mydepgraph.display(
-                               mydepgraph.altlist(reversed=("--tree" in myopts)))
+                       retval = mydepgraph.display(
+                               mydepgraph.altlist(reversed=("--tree" in myopts)),
+                               favorites=favorites)
+                       if retval != os.EX_OK:
+                               return retval
                        if "--buildpkgonly" in myopts and \
                                not mydepgraph.digraph.hasallzeros(ignore_priority=DepPriority.MEDIUM):
                                        print "\n!!! --buildpkgonly requires all dependencies to be merged."
                                        print "!!! You have to merge the dependencies before you can build this package.\n"
-                                       sys.exit(1)
+                                       return 1
        else:
                if ("--buildpkgonly" in myopts):
                        if not mydepgraph.digraph.hasallzeros(ignore_priority=DepPriority.MEDIUM):
                                print "\n!!! --buildpkgonly requires all dependencies to be merged."
                                print "!!! Cannot merge requested packages. Merge deps and try again.\n"
-                               sys.exit(1)
+                               return 1
 
                if ("--resume" in myopts):
                        favorites=mtimedb["resume"]["favorites"]
@@ -5571,7 +5610,7 @@ def action_build(settings, trees, mtimedb,
                        retval = mergetask.merge(
                                mtimedb["resume"]["mergelist"], favorites, mtimedb)
                        if retval != os.EX_OK:
-                               sys.exit(retval)
+                               return retval
                else:
                        if "resume" in mtimedb and \
                        "mergelist" in mtimedb["resume"] and \
@@ -5605,12 +5644,12 @@ def action_build(settings, trees, mtimedb,
                        else:
                                pkglist = mydepgraph.altlist()
                        if favorites:
-                               mydepgraph.saveNomergeFavorites(pkglist, favorites)
+                               mydepgraph.saveNomergeFavorites()
                        del mydepgraph
                        mergetask = MergeTask(settings, trees, myopts)
                        retval = mergetask.merge(pkglist, favorites, mtimedb)
                        if retval != os.EX_OK:
-                               sys.exit(retval)
+                               return retval
 
                if mtimedb.has_key("resume"):
                        del mtimedb["resume"]
@@ -6142,12 +6181,13 @@ def emerge_main():
                validate_ebuild_environment(trees)
                if "--pretend" not in myopts:
                        display_news_notification(trees)
-               action_build(settings, trees, mtimedb,
+               retval = action_build(settings, trees, mtimedb,
                        myopts, myaction, myfiles, spinner)
                if "--pretend" not in myopts:
-                       post_emerge(trees, mtimedb, os.EX_OK)
+                       post_emerge(trees, mtimedb, retval)
                else:
                        display_news_notification(trees)
+               return retval
 
 if __name__ == "__main__":
        retval = emerge_main()
index 79f3d6124ba86f687e077eaf4e28d86c21fbff46..20730b1c0c639891443237df110d216b9c29fd90 100644 (file)
@@ -28,8 +28,6 @@ try:
        from time import sleep
        from random import shuffle
        import UserDict
-       if getattr(__builtins__, "set", None) is None:
-               from sets import Set as set
        from itertools import chain, izip
 except ImportError, e:
        sys.stderr.write("\n\n")
index db13f57b3ac45a442868902ccb02857458a31be7..dfa7050c4e77484ea79d719f9238a45d4b3ad162 100644 (file)
@@ -3,8 +3,6 @@
 # $Header: $
 
 import time
-if not hasattr(__builtins__, "set"):
-       from sets import Set as set
 from portage.cache import template
 from portage.cache.cache_errors import CacheCorruption
 from portage.cache.flat_hash import database as db_rw
index 5c8f270564f483993d00f479bd30d782a129e082..d51270eaeaadbf220455ed91e6edba914659546f 100644 (file)
@@ -3,8 +3,6 @@
 # License: GPL2
 # $Id: util.py 1911 2005-08-25 03:44:21Z ferringb $
 
-if not hasattr(__builtins__, "set"):
-       from sets import Set as set
 from itertools import chain
 from portage.cache import cache_errors
 
index 12c23dd5639779e3f599684bfbb132642d0c4dfb..eb4f1eb9b9210bc7b0ccdb3f30c8ff0d72bd4376 100644 (file)
@@ -3,8 +3,6 @@
 # $Header: $
 
 import copy
-if not hasattr(__builtins__, "set"):
-       from sets import Set as set
 from portage.cache import template
 
 class database(template.database):
index 90c68c55ed9e813bbfb8c5beb884c140d0f41415..5dada13f2381b83d6a3506070b1139ebc6d8b16e 100644 (file)
@@ -3,9 +3,6 @@
 # Distributed under the terms of the GNU General Public License v2
 # $Id: $
 
-if not hasattr(__builtins__, "set"):
-       from sets import Set as set
-
 import os, sys, pwd, grp
 from portage.util import writemsg
 from portage.const import rootuid, portageuser, portagegroup
index 9fa0b38ca1f886737e1bc941fdc1bf7653af969e..1cc0dacfcd5a53286678e4857bf3838060b562aa 100644 (file)
@@ -9,7 +9,6 @@ from portage.data import portage_gid, portage_uid, secpass
 from portage.dbapi import dbapi
 from portage.dep import dep_getslot, use_reduce, paren_reduce, isvalidatom, \
        isjustname, dep_getkey, match_from_list
-from portage.elog import elog_process
 from portage.exception import InvalidPackageName, InvalidAtom, \
        FileNotFound, PermissionDenied, UnsupportedAPIException
 from portage.locks import lockdir, unlockdir
@@ -24,7 +23,9 @@ from portage import listdir, dep_expand, flatten, key_expand, \
        doebuild_environment, doebuild, env_update, \
        abssymlink, movefile, _movefile, bsd_chflags
 
+from portage.elog import elog_process
 from portage.elog.messages import ewarn
+from portage.elog.filtering import filter_mergephases, filter_unmergephases
 
 import os, sys, stat, errno, commands, copy, time
 from itertools import izip
@@ -1104,7 +1105,7 @@ class dblink(object):
                                try:
                                        if myebuildpath:
                                                # process logs created during pre/postrm
-                                               elog_process(self.mycpv, self.settings)
+                                               elog_process(self.mycpv, self.settings, phasefilter=filter_unmergephases)
                                                if retval == os.EX_OK:
                                                        doebuild(myebuildpath, "cleanrm", self.myroot,
                                                                self.settings, tree="vartree",
@@ -2106,7 +2107,7 @@ class dblink(object):
                        retval = self.treewalk(mergeroot, myroot, inforoot, myebuild,
                                cleanup=cleanup, mydbapi=mydbapi, prev_mtimes=prev_mtimes)
                        # Process ebuild logfiles
-                       elog_process(self.mycpv, self.settings)
+                       elog_process(self.mycpv, self.settings, phasefilter=filter_mergephases)
                        if retval == os.EX_OK and "noclean" not in self.settings.features:
                                if myebuild is None:
                                        myebuild = os.path.join(inforoot, self.pkg + ".ebuild")
index a1e349bd933bd00b06d69623aac5c714ae7d9911..3e566735deb8d5306e4ecb2c3acd110aeb0bf5cd 100644 (file)
@@ -3,9 +3,6 @@
 # Distributed under the terms of the GNU General Public License v2
 # $Id: getbinpkg.py 3483 2006-06-10 21:40:40Z genone $
 
-if not hasattr(__builtins__, "set"):
-       from sets import Set as set
-
 from portage.output import red, yellow, green
 import htmllib,HTMLParser,formatter,sys,os,portage.xpak,time,tempfile,base64,urllib2
 from portage.const import CACHE_PATH
index 61af21d94f898b2b2bc1f21233592d9d91edece4..3116922b7ef68336fed134845a09868e205cf9fb 100644 (file)
@@ -2,9 +2,7 @@
 # Distributed under the terms of the GNU General Public License v2
 # $Header: $
 
-import errno, os, sets
-if not hasattr(__builtins__, "set"):
-       from sets import Set as set
+import errno, os
 
 import portage.versions, portage.const
 from portage.checksum import *
@@ -113,7 +111,7 @@ class Manifest(object):
                self.hashes.append("size")
                if manifest1_compat:
                        self.hashes.extend(portage.const.MANIFEST1_HASH_FUNCTIONS)
-               self.hashes = sets.Set(self.hashes)
+               self.hashes = set(self.hashes)
                for t in portage.const.MANIFEST2_IDENTIFIERS:
                        self.fhashdict[t] = {}
                self.compat = manifest1_compat
index aec440ed9c8cc3cd70695ccd2af82560529e04bd..470fcb9b2e8f67c03c285a510cf8c110c7965b5e 100644 (file)
@@ -73,6 +73,7 @@ codes["standout"]  = esc_seq + "03m"
 codes["underline"] = esc_seq + "04m"
 codes["blink"]     = esc_seq + "05m"
 codes["overline"]  = esc_seq + "06m"  # Who made this up? Seriously.
+codes["reverse"]   = esc_seq + "07m"
 
 ansi_color_codes = []
 for x in xrange(30, 38):
@@ -119,6 +120,15 @@ codes["darkyellow"] = codes["0xAAAA00"]
 codes["fuscia"]     = codes["fuchsia"]
 codes["white"]      = codes["bold"]
 
+codes["bg_black"]   = esc_seq + "40m"
+codes["bg_red"]     = esc_seq + "41m"
+codes["bg_green"]   = esc_seq + "42m"
+codes["bg_brown"]   = esc_seq + "43m"
+codes["bg_blue"]    = esc_seq + "44m"
+codes["bg_magenta"] = esc_seq + "45m"
+codes["bg_cyan"]    = esc_seq + "46m"
+codes["bg_white"]   = esc_seq + "47m"
+
 # Colors from /sbin/functions.sh
 codes["GOOD"]       = codes["green"]
 codes["WARN"]       = codes["yellow"]
@@ -127,20 +137,33 @@ codes["HILITE"]     = codes["teal"]
 codes["BRACKET"]    = codes["blue"]
 
 # Portage functions
-codes["INFORM"] = codes["darkgreen"]
-codes["UNMERGE_WARN"] = codes["red"]
-codes["SECURITY_WARN"] = codes["red"]
-codes["MERGE_LIST_PROGRESS"] = codes["yellow"]
-codes["PKG_MERGE"]           = codes["darkgreen"]
-codes["PKG_MERGE_ARG"]       = codes["darkgreen"]
-codes["PKG_MERGE_SYSTEM"]    = codes["green"]
-codes["PKG_MERGE_WORLD"]     = codes["green"]
-codes["PKG_NOMERGE"]         = codes["darkblue"]
-codes["PKG_NOMERGE_ARG"]     = codes["darkblue"]
-codes["PKG_NOMERGE_SYSTEM"]  = codes["blue"]
-codes["PKG_NOMERGE_WORLD"]   = codes["blue"]
-
-def parse_color_map():
+codes["INFORM"]                  = codes["darkgreen"]
+codes["UNMERGE_WARN"]            = codes["red"]
+codes["SECURITY_WARN"]           = codes["red"]
+codes["MERGE_LIST_PROGRESS"]     = codes["yellow"]
+codes["PKG_MERGE"]               = codes["darkgreen"]
+codes["PKG_MERGE_ARG"]           = codes["darkgreen"]
+codes["PKG_MERGE_SYSTEM"]        = codes["green"]
+codes["PKG_MERGE_WORLD"]         = codes["green"]
+codes["PKG_MERGE_ARG_SYSTEM"]    = codes["green"]
+codes["PKG_MERGE_ARG_WORLD"]     = codes["green"]
+codes["PKG_NOMERGE"]             = codes["darkblue"]
+codes["PKG_NOMERGE_ARG"]         = codes["darkblue"]
+codes["PKG_NOMERGE_SYSTEM"]      = codes["blue"]
+codes["PKG_NOMERGE_WORLD"]       = codes["blue"]
+codes["PKG_NOMERGE_ARG_SYSTEM"]  = codes["blue"]
+codes["PKG_NOMERGE_ARG_WORLD"]   = codes["blue"]
+
+def parse_color_map(onerror=None):
+       """
+       Parse /etc/portage/color.map and return a dict of error codes.
+
+       @param onerror: an optional callback to handle any ParseError that would
+               otherwise be raised
+       @type onerror: callable
+       @rtype: dict
+       @return: a dictionary mapping color classes to color codes
+       """
        myfile = COLOR_MAP_FILE
        ansi_code_pattern = re.compile("^[0-9;]*m$")
        def strip_quotes(token, quotes):
@@ -156,16 +179,41 @@ def parse_color_map():
                        if k is s.eof:
                                break
                        if o != "=":
-                               raise ParseError("%s%s'%s'" % (s.error_leader(myfile, s.lineno), "expected '=' operator: ", o))
+                               e = ParseError("%s%s'%s'" % (
+                                       s.error_leader(myfile, s.lineno),
+                                       "expected '=' operator: ", o))
+                               if onerror:
+                                       onerror(e)
+                               else:
+                                       raise e
+                               continue
                        k = strip_quotes(k, s.quotes)
                        v = strip_quotes(v, s.quotes)
+                       if not k in codes:
+                               e = ParseError("%s%s'%s'" % (
+                                       s.error_leader(myfile, s.lineno),
+                                       "Unknown variable: ", k))
+                               if onerror:
+                                       onerror(e)
+                               else:
+                                       raise e
+                               continue
                        if ansi_code_pattern.match(v):
                                codes[k] = esc_seq + v
                        else:
-                               if v in codes:
-                                       codes[k] = codes[v]
-                               else:
-                                       raise ParseError("%s%s'%s'" % (s.error_leader(myfile, s.lineno), "Undefined: ", v))
+                               code_list = []
+                               for x in v.split(" "):
+                                       if x in codes:
+                                               code_list.append(codes[x])
+                                       else:
+                                               e = ParseError("%s%s'%s'" % (
+                                                       s.error_leader(myfile, s.lineno),
+                                                       "Undefined: ", x))
+                                               if onerror:
+                                                       onerror(e)
+                                               else:
+                                                       raise e
+                               codes[k] = "".join(code_list)
        except (IOError, OSError), e:
                if e.errno == errno.ENOENT:
                        raise FileNotFound(myfile)
@@ -174,7 +222,7 @@ def parse_color_map():
                raise
 
 try:
-       parse_color_map()
+       parse_color_map(onerror=lambda e: writemsg("%s\n" % str(e), noiselevel=-1))
 except FileNotFound, e:
        pass
 except PortageException, e:
index ebaafd70d9b0ae1e92df61630a9287e76bec475c..53b1c86f4cbe36b1316827fd8ca1681e1180da36 100644 (file)
@@ -14,9 +14,6 @@ try:
 except ImportError:
        import pickle as cPickle
 
-if not hasattr(__builtins__, "set"):
-       from sets import Set as set
-
 noiselimit = 0
 
 def writemsg(mystr,noiselevel=0,fd=None):