diff options
author | Zac Medico <zmedico@gentoo.org> | 2009-06-16 21:53:17 +0000 |
---|---|---|
committer | Zac Medico <zmedico@gentoo.org> | 2009-06-16 21:53:17 +0000 |
commit | 9f2484465799cf8dc74850938e3eceb7d54d5b72 (patch) | |
tree | b018835d457f9d080e574a9829b4a3af6870edca | |
parent | a88675dc78ea74f802984cb71ea4fab90a6b375d (diff) | |
download | portage-9f2484465799cf8dc74850938e3eceb7d54d5b72.tar.gz portage-9f2484465799cf8dc74850938e3eceb7d54d5b72.tar.bz2 portage-9f2484465799cf8dc74850938e3eceb7d54d5b72.zip |
Bug #274279 - Add color.map support for mapping a color to a different color
(rather than just mapping a class/style to a different color). Thanks to
Sebastian Mingramm (few) <s.mingramm@gmx.de> for this patch.
svn path=/main/trunk/; revision=13643
-rw-r--r-- | man/color.map.5 | 4 | ||||
-rw-r--r-- | pym/portage/__init__.py | 3 | ||||
-rw-r--r-- | pym/portage/output.py | 296 |
3 files changed, 152 insertions, 151 deletions
diff --git a/man/color.map.5 b/man/color.map.5 index 9082e7693..9ce76ad26 100644 --- a/man/color.map.5 +++ b/man/color.map.5 @@ -9,9 +9,9 @@ Portage will check this file first for color classes settings. If no setting of given color class is found in /etc/portage/color.map, Portage uses default value defined internally. .SH "SYNTAX" -\fBVARIABLE\fR = \fI[space delimited list of attributes]\fR +\fBVARIABLE\fR = \fI[space delimited list of attributes or ansi code pattern]\fR .TP -\fBATTRIBUTE\fR = \fI[space delimited list of attributes]\fR +\fBATTRIBUTE\fR = \fI[space delimited list of attributes or ansi code pattern]\fR .SH "VARIABLES" .TP \fBNORMAL\fR = \fI"normal"\fR diff --git a/pym/portage/__init__.py b/pym/portage/__init__.py index 6854eea99..c17072870 100644 --- a/pym/portage/__init__.py +++ b/pym/portage/__init__.py @@ -5431,7 +5431,8 @@ def doebuild_environment(myebuild, mydo, myroot, mysettings, debug, use_cache, m # Allow color.map to control colors associated with einfo, ewarn, etc... mycolors = [] for c in ("GOOD", "WARN", "BAD", "HILITE", "BRACKET"): - mycolors.append("%s=$'%s'" % (c, portage.output.codes[c])) + mycolors.append("%s=$'%s'" % \ + (c, portage.output.map_code_to_color_code(c))) mysettings["PORTAGE_COLORMAP"] = "\n".join(mycolors) def prepare_build_dirs(myroot, mysettings, cleanup): diff --git a/pym/portage/output.py b/pym/portage/output.py index 983cbec60..2096b24be 100644 --- a/pym/portage/output.py +++ b/pym/portage/output.py @@ -4,6 +4,7 @@ __docformat__ = "epytext" +import codecs import commands import errno import formatter @@ -24,68 +25,47 @@ from portage.exception import CommandNotFound, FileNotFound, \ havecolor=1 dotitles=1 +codes = {} +color_codes = {} + esc_seq = "\x1b[" -g_attr = {} -g_attr["normal"] = 0 - -g_attr["bold"] = 1 -g_attr["faint"] = 2 -g_attr["standout"] = 3 -g_attr["underline"] = 4 -g_attr["blink"] = 5 -g_attr["overline"] = 6 # Why is overline actually useful? -g_attr["reverse"] = 7 -g_attr["invisible"] = 8 - -g_attr["no-attr"] = 22 -g_attr["no-standout"] = 23 -g_attr["no-underline"] = 24 -g_attr["no-blink"] = 25 -g_attr["no-overline"] = 26 -g_attr["no-reverse"] = 27 -# 28 isn't defined? -# 29 isn't defined? -g_attr["black"] = 30 -g_attr["red"] = 31 -g_attr["green"] = 32 -g_attr["yellow"] = 33 -g_attr["blue"] = 34 -g_attr["magenta"] = 35 -g_attr["cyan"] = 36 -g_attr["white"] = 37 -# 38 isn't defined? -g_attr["default"] = 39 -g_attr["bg_black"] = 40 -g_attr["bg_red"] = 41 -g_attr["bg_green"] = 42 -g_attr["bg_yellow"] = 43 -g_attr["bg_blue"] = 44 -g_attr["bg_magenta"] = 45 -g_attr["bg_cyan"] = 46 -g_attr["bg_white"] = 47 -g_attr["bg_default"] = 49 - - -# make_seq("blue", "black", "normal") +color_codes["normal"] = esc_seq + "0m" +color_codes["reset"] = esc_seq + "39;49;00m" + +color_codes["bold"] = esc_seq + "01m" +color_codes["faint"] = esc_seq + "02m" +color_codes["standout"] = esc_seq + "03m" +color_codes["underline"] = esc_seq + "04m" +color_codes["blink"] = esc_seq + "05m" +color_codes["overline"] = esc_seq + "06m" +color_codes["reverse"] = esc_seq + "07m" +color_codes["invisible"] = esc_seq + "08m" + +color_codes["no-attr"] = esc_seq + "22m" +color_codes["no-standout"] = esc_seq + "23m" +color_codes["no-underline"] = esc_seq + "24m" +color_codes["no-blink"] = esc_seq + "25m" +color_codes["no-overline"] = esc_seq + "26m" +color_codes["no-reverse"] = esc_seq + "27m" + +color_codes["bg_black"] = esc_seq + "40m" +color_codes["bg_darkred"] = esc_seq + "41m" +color_codes["bg_darkgreen"] = esc_seq + "42m" +color_codes["bg_brown"] = esc_seq + "43m" +color_codes["bg_darkblue"] = esc_seq + "44m" +color_codes["bg_purple"] = esc_seq + "45m" +color_codes["bg_teal"] = esc_seq + "46m" +color_codes["bg_lightgray"] = esc_seq + "47m" +color_codes["bg_default"] = esc_seq + "49m" +color_codes["bg_darkyellow"] = color_codes["bg_brown"] + def color(fg, bg="default", attr=["normal"]): - mystr = esc_seq[:] + "%02d" % g_attr[fg] + mystr = color_codes[fg] for x in [bg]+attr: - mystr += ";%02d" % g_attr[x] - return mystr+"m" - - + mystr += color_codes[x] + return mystr -codes={} -codes["reset"] = esc_seq + "39;49;00m" - -codes["bold"] = esc_seq + "01m" -codes["faint"] = esc_seq + "02m" -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): @@ -97,76 +77,67 @@ rgb_ansi_colors = ['0x000000', '0x555555', '0xAA0000', '0xFF5555', '0x00AA00', '0xFF55FF', '0x00AAAA', '0x55FFFF', '0xAAAAAA', '0xFFFFFF'] for x in xrange(len(rgb_ansi_colors)): - codes[rgb_ansi_colors[x]] = esc_seq + ansi_color_codes[x] + color_codes[rgb_ansi_colors[x]] = esc_seq + ansi_color_codes[x] del x -codes["black"] = codes["0x000000"] -codes["darkgray"] = codes["0x555555"] +color_codes["black"] = color_codes["0x000000"] +color_codes["darkgray"] = color_codes["0x555555"] -codes["red"] = codes["0xFF5555"] -codes["darkred"] = codes["0xAA0000"] +color_codes["red"] = color_codes["0xFF5555"] +color_codes["darkred"] = color_codes["0xAA0000"] -codes["green"] = codes["0x55FF55"] -codes["darkgreen"] = codes["0x00AA00"] +color_codes["green"] = color_codes["0x55FF55"] +color_codes["darkgreen"] = color_codes["0x00AA00"] -codes["yellow"] = codes["0xFFFF55"] -codes["brown"] = codes["0xAA5500"] +color_codes["yellow"] = color_codes["0xFFFF55"] +color_codes["brown"] = color_codes["0xAA5500"] -codes["blue"] = codes["0x5555FF"] -codes["darkblue"] = codes["0x0000AA"] +color_codes["blue"] = color_codes["0x5555FF"] +color_codes["darkblue"] = color_codes["0x0000AA"] -codes["fuchsia"] = codes["0xFF55FF"] -codes["purple"] = codes["0xAA00AA"] +color_codes["fuchsia"] = color_codes["0xFF55FF"] +color_codes["purple"] = color_codes["0xAA00AA"] -codes["turquoise"] = codes["0x55FFFF"] -codes["teal"] = codes["0x00AAAA"] +color_codes["turquoise"] = color_codes["0x55FFFF"] +color_codes["teal"] = color_codes["0x00AAAA"] -codes["white"] = codes["0xFFFFFF"] -codes["lightgray"] = codes["0xAAAAAA"] +color_codes["white"] = color_codes["0xFFFFFF"] +color_codes["lightgray"] = color_codes["0xAAAAAA"] -codes["darkteal"] = codes["turquoise"] +color_codes["darkteal"] = color_codes["turquoise"] # Some terminals have darkyellow instead of brown. -codes["0xAAAA00"] = codes["brown"] -codes["darkyellow"] = codes["0xAAAA00"] +color_codes["0xAAAA00"] = color_codes["brown"] +color_codes["darkyellow"] = color_codes["0xAAAA00"] -codes["bg_black"] = esc_seq + "40m" -codes["bg_darkred"] = esc_seq + "41m" -codes["bg_darkgreen"] = esc_seq + "42m" -codes["bg_brown"] = esc_seq + "43m" -codes["bg_darkblue"] = esc_seq + "44m" -codes["bg_purple"] = esc_seq + "45m" -codes["bg_teal"] = esc_seq + "46m" -codes["bg_lightgray"] = esc_seq + "47m" -codes["bg_darkyellow"] = codes["bg_brown"] # Colors from /etc/init.d/functions.sh -codes["NORMAL"] = esc_seq + "0m" -codes["GOOD"] = codes["green"] -codes["WARN"] = codes["yellow"] -codes["BAD"] = codes["red"] -codes["HILITE"] = codes["teal"] -codes["BRACKET"] = codes["blue"] +codes["NORMAL"] = ( "normal", ) +codes["GOOD"] = ( "green", ) +codes["WARN"] = ( "yellow", ) +codes["BAD"] = ( "red", ) +codes["HILITE"] = ( "teal", ) +codes["BRACKET"] = ( "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_BLOCKER"] = codes["red"] -codes["PKG_BLOCKER_SATISFIED"] = codes["darkblue"] -codes["PKG_MERGE"] = codes["darkgreen"] -codes["PKG_MERGE_SYSTEM"] = codes["darkgreen"] -codes["PKG_MERGE_WORLD"] = codes["green"] -codes["PKG_UNINSTALL"] = codes["red"] -codes["PKG_NOMERGE"] = codes["darkblue"] -codes["PKG_NOMERGE_SYSTEM"] = codes["darkblue"] -codes["PKG_NOMERGE_WORLD"] = codes["blue"] -codes["PROMPT_CHOICE_DEFAULT"] = codes["green"] -codes["PROMPT_CHOICE_OTHER"] = codes["red"] - -def parse_color_map(onerror=None): +codes["INFORM"] = ( "darkgreen", ) +codes["UNMERGE_WARN"] = ( "red", ) +codes["SECURITY_WARN"] = ( "red", ) +codes["MERGE_LIST_PROGRESS"] = ( "yellow", ) +codes["PKG_BLOCKER"] = ( "red", ) +codes["PKG_BLOCKER_SATISFIED"] = ( "darkblue", ) +codes["PKG_MERGE"] = ( "darkgreen", ) +codes["PKG_MERGE_SYSTEM"] = ( "darkgreen", ) +codes["PKG_MERGE_WORLD"] = ( "green", ) +codes["PKG_UNINSTALL"] = ( "red", ) +codes["PKG_NOMERGE"] = ( "darkblue", ) +codes["PKG_NOMERGE_SYSTEM"] = ( "darkblue", ) +codes["PKG_NOMERGE_WORLD"] = ( "blue", ) +codes["PROMPT_CHOICE_DEFAULT"] = ( "green", ) +codes["PROMPT_CHOICE_OTHER"] = ( "red", ) + +def _parse_color_map(onerror=None): """ Parse /etc/portage/color.map and return a dict of error codes. @@ -177,32 +148,40 @@ def parse_color_map(onerror=None): @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): + ansi_code_pattern = re.compile("^[0-9;]*m$") + quotes = '\'"' + def strip_quotes(token): if token[0] in quotes and token[0] == token[-1]: token = token[1:-1] return token try: - s = shlex.shlex(open(myfile)) - s.wordchars = s.wordchars + ";" # for ansi codes - while True: - k, o, v = s.get_token(), s.get_token(), s.get_token() - if k is s.eof: - break - if o != "=": - e = ParseError("%s%s'%s'" % ( - s.error_leader(myfile, s.lineno), - "expected '=' operator: ", o)) + lineno=0 + for line in codecs.open( myfile, mode = 'r', errors = 'replace' ): + lineno += 1 + + commenter_pos = line.find("#") + line = line[:commenter_pos].strip() + + if len(line) == 0: + continue + + split_line = line.split("=") + if len(split_line) != 2: + e = ParseError("'%s', line %s: %s" % ( + myfile, lineno, + "expected exactly one occurence of '=' operator")) + raise e 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), + + k = strip_quotes(split_line[0].strip()) + v = strip_quotes(split_line[1].strip()) + if not k in codes and not k in color_codes: + e = ParseError("'%s', line %s: %s'%s'" % ( + myfile, lineno, "Unknown variable: ", k)) if onerror: onerror(e) @@ -210,21 +189,30 @@ def parse_color_map(onerror=None): raise e continue if ansi_code_pattern.match(v): - codes[k] = esc_seq + v + if k in codes: + codes[k] = ( esc_seq + v, ) + elif k in color_codes: + color_codes[k] = esc_seq + v else: code_list = [] - for x in v.split(" "): - if x in codes: - code_list.append(codes[x]) + for x in v.split(): + if x in color_codes: + if k in codes: + code_list.append(x) + elif k in color_codes: + code_list.append(color_codes[x]) else: - e = ParseError("%s%s'%s'" % ( - s.error_leader(myfile, s.lineno), + e = ParseError("'%s', line %s: %s'%s'" % ( + myfile, lineno, "Undefined: ", x)) if onerror: onerror(e) else: raise e - codes[k] = "".join(code_list) + if k in codes: + codes[k] = tuple(code_list) + elif k in color_codes: + color_codes[k] = "".join(code_list) except (IOError, OSError), e: if e.errno == errno.ENOENT: raise FileNotFound(myfile) @@ -232,17 +220,6 @@ def parse_color_map(onerror=None): raise PermissionDenied(myfile) raise -try: - parse_color_map(onerror=lambda e: writemsg("%s\n" % str(e), noiselevel=-1)) -except FileNotFound: - pass -except PermissionDenied, e: - writemsg("Permission denied: '%s'\n" % str(e), noiselevel=-1) - del e -except PortageException, e: - writemsg("%s\n" % str(e), noiselevel=-1) - del e - def nc_len(mystr): tmp = re.sub(esc_seq + "^m]+m", "", mystr); return len(tmp) @@ -308,12 +285,24 @@ def nocolor(): havecolor=0 def resetColor(): - return codes["reset"] + return color_codes["reset"] + +def map_code_to_color_code(code): + ret = "" + for color_code in codes[code]: + # allow stuff that has found it's way through ansi_code_pattern + ret += color_codes.get(color_code, color_code) + return ret def colorize(color_key, text): global havecolor if havecolor: - return codes[color_key] + text + codes["reset"] + if color_key in color_codes: + return color_codes[color_key] + text + color_codes["reset"] + elif color_key in codes: + return map_code_to_color_code(color_key) + text + color_codes["reset"] + else: + return text else: return text @@ -350,9 +339,9 @@ class ConsoleStyleFile(object): global havecolor if havecolor and self._styles: for style in self._styles: - self._file.write(codes[style]) + self._file.write(color_codes[style]) self._file.write(s) - self._file.write(codes["reset"]) + self._file.write(color_codes["reset"]) else: self._file.write(s) if self.write_listener: @@ -715,3 +704,14 @@ class TermProgressBar(ProgressBar): image = image + "[" + (bar_width * "=") + \ ">" + ((max_bar_width - bar_width) * " ") + "]" return image + +try: + _parse_color_map(onerror=lambda e: writemsg("%s\n" % str(e), noiselevel=-1)) +except FileNotFound: + pass +except PermissionDenied, e: + writemsg("Permission denied: '%s'\n" % str(e), noiselevel=-1) + del e +except PortageException, e: + writemsg("%s\n" % str(e), noiselevel=-1) + del e |