For bug #183861, allow a color class in color.map to specify a space separated list...
authorZac Medico <zmedico@gentoo.org>
Thu, 5 Jul 2007 00:56:33 +0000 (00:56 -0000)
committerZac Medico <zmedico@gentoo.org>
Thu, 5 Jul 2007 00:56:33 +0000 (00:56 -0000)
svn path=/main/branches/2.1.2/; revision=7151

bin/emerge
man/color.map.5
pym/output.py

index d2421be26a676004f2ed8274cedb8f1dd9b56d7c..a50ac1e0782f4b9d74360edfa15221f6e8c15abe 100755 (executable)
@@ -629,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()))
@@ -673,6 +675,20 @@ 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
@@ -812,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"]
+                               "RESTRICT", "DEPEND", "RDEPEND", "PDEPEND"]
                        real_dbapi = real_vartree.dbapi
                        slot_counters = {}
                        for cpv in real_dbapi.cpv_all():
@@ -1053,9 +1069,10 @@ class depgraph:
                self._slot_node_map = {}
                self.mydbapi = {}
                self._mydbapi_keys = ["SLOT", "DEPEND", "RDEPEND", "PDEPEND",
-                       "USE", "IUSE", "PROVIDE"]
+                       "USE", "IUSE", "PROVIDE", "RESTRICT"]
                self.useFlags = {}
                self.trees = {}
+               self.roots = {}
                for myroot in trees:
                        self.trees[myroot] = {}
                        for tree in ("porttree", "bintree"):
@@ -1068,6 +1085,7 @@ class depgraph:
                        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])
@@ -1098,8 +1116,11 @@ class depgraph:
                self.outdatedpackages=[]
                self._args_atoms = AtomSet()
                self._args_nodes = set()
+               # contains all sets added to the graph by self.xcreate()
                self._sets = {}
-               self._sets_nodes = {}
+               # contains all atoms from all sets added to the graph, including
+               # atoms given as arguments
+               self._set_atoms = AtomSet()
                self.blocker_digraph = digraph()
                self.blocker_parents = {}
                self._unresolved_blocker_parents = {}
@@ -1239,7 +1260,7 @@ class depgraph:
 
                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"]),
@@ -1350,17 +1371,6 @@ class depgraph:
 
                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
 
                # Do this even when addme is False (--onlydeps) so that the
                # parent/child relationship is always known in case
@@ -1586,6 +1596,7 @@ class depgraph:
                        if myatom in self._args_atoms:
                                continue
                        self._args_atoms.add(myatom)
+                       self._set_atoms.add(myatom)
                        if not oneshot:
                                myfavorites.append(myatom)
                for myarg, myatom in arg_atoms:
@@ -1690,7 +1701,7 @@ class depgraph:
                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:
@@ -2376,24 +2387,15 @@ class depgraph:
                        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
@@ -2466,7 +2468,7 @@ class depgraph:
                mylist = newlist
 
                for myatom in mylist:
-                       self._args_atoms.add(myatom)
+                       self._set_atoms.add(myatom)
 
                missing_atoms = []
                for mydep in mylist:
@@ -2493,10 +2495,14 @@ class depgraph:
 
                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._args_atoms.update(favorites)
+               favorites_set = AtomSet()
+               favorites_set.update(favorites)
                changelogs=[]
                p=[]
                blockers = []
@@ -2717,6 +2723,19 @@ class depgraph:
                                        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."""
@@ -2937,42 +2956,55 @@ class depgraph:
                                        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"]
+
+                               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:
+                                       pkg_arg = self._args_atoms.findAtomForPackage(pkg_key, metadata)
+                                       pkg_system = system_set.findAtomForPackage(pkg_key, metadata)
+                                       pkg_world  = world_set.findAtomForPackage(pkg_key, metadata)
+                                       if not pkg_world:
+                                               # 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:
@@ -3096,6 +3128,7 @@ class depgraph:
                                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):
@@ -5283,11 +5316,17 @@ def action_build(settings, trees, mtimedb,
                        if len(mymergelist) == 0:
                                print colorize("INFORM", "emerge: It seems we have nothing to resume...")
                                sys.exit(0)
-                       mydepgraph.display(mymergelist)
+                       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":
@@ -5334,10 +5373,16 @@ def action_build(settings, trees, mtimedb,
                        if len(mymergelist) == 0:
                                print colorize("INFORM", "emerge: It seems we have nothing to resume...")
                                sys.exit(0)
-                       mydepgraph.display(mymergelist)
+                       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."
@@ -5936,10 +5981,11 @@ def emerge_main():
        # "update", "system", or just process files:
        else:
                validate_ebuild_environment(trees)
-               action_build(settings, trees, mtimedb,
+               retval = action_build(settings, trees, mtimedb,
                        myopts, myaction, myfiles, spinner)
                if "--pretend" not in myopts:
-                       post_emerge(settings, mtimedb, 0)
+                       post_emerge(settings, mtimedb, retval)
+               return retval
 
 if __name__ == "__main__":
        from portage_exception import PermissionDenied
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 2336e0fc2507e42e65c96a55b8a964e033d84aa6..2079bf6d991dcb86b6739baaf5ecdb166847271e 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: