From: Zac Medico Date: Thu, 5 Jul 2007 00:56:33 +0000 (-0000) Subject: For bug #183861, allow a color class in color.map to specify a space separated list... X-Git-Tag: v2.1.3~97 X-Git-Url: http://git.tremily.us/?a=commitdiff_plain;h=0024e08c303c9398091199da86422de7d85c6577;p=portage.git For bug #183861, allow a color class in color.map to specify a space separated list of attributes so that any combination of foreground, background, and other attributes is possible. Also make color class handling for package sets more consistent. Thanks to Arfrever Frehtes Taifersar Arahesis . svn path=/main/branches/2.1.2/; revision=7151 --- diff --git a/bin/emerge b/bin/emerge index d2421be26..a50ac1e07 100755 --- a/bin/emerge +++ b/bin/emerge @@ -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 diff --git a/man/color.map.5 b/man/color.map.5 index f76276100..10fa1a09a 100644 --- a/man/color.map.5 +++ b/man/color.map.5 @@ -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 diff --git a/pym/output.py b/pym/output.py index 2336e0fc2..2079bf6d9 100644 --- a/pym/output.py +++ b/pym/output.py @@ -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: