From: Fabian Groffen Date: Fri, 19 Jun 2009 19:25:10 +0000 (-0000) Subject: Merged from trunk -r13640:13652 X-Git-Url: http://git.tremily.us/gitweb.cgi?a=commitdiff_plain;h=a07e953e9a73f9f53a116ae0f01a5a87125a3f4b;p=portage.git Merged from trunk -r13640:13652 | 13641 | Misc fixes and updates. Thanks to Sebastian Mingramm (few) | | zmedico | for this patch from bug #274279. | | 13642 | Escape hyphens from previous commit. | | zmedico | | | 13643 | Bug #274279 - Add color.map support for mapping a color to a | | zmedico | different color (rather than just mapping a class/style to a | | | different color). Thanks to Sebastian Mingramm (few) | | | for this patch. | | 13644 | Use map_code_to_color_code() where appropriate inside | | zmedico | ConsoleStyleFile.write(). | | 13645 | Add epydoc docstrings fro codes and color_codes variables. | | zmedico | | | 13646 | Rename map_code_to_color_code() to style_to_ansi_code(). | | zmedico | | | 13647 | Rename codes to _styles. | | zmedico | | | 13648 | Rename color_codes back to codes. | | zmedico | | | 13649 | Add NOCOLOR to the environment whitelist. This fixes | | zmedico | inappropriate colors produced by elog functions. Thanks to | | | Luis F. Araujo for reporting. | | 13650 | When --pretend overrides --ask, don't show any output. | | zmedico | | | 13651 | Allow missing ChangeLog when using git. We don't use | | zmedico | ChangeLogs in distributed SCMs. It will be generated on | | | server side from scm log, before package moves to the rsync | | | server. This is needed because we try to avoid merge | | | collisions. Thanks to Tomas Chvatal | | | for this patch. | | 13652 | Add a EMERGE_LOG_DIR variable to control the location of | | zmedico | emerge.log and emerge-fetch.log. This was requested by Eitan | | | Mosenkis for use in his 'online image | | | builder' soc project. | svn path=/main/branches/prefix/; revision=13653 --- diff --git a/bin/repoman b/bin/repoman index 243645bec..bcde969de 100755 --- a/bin/repoman +++ b/bin/repoman @@ -1113,8 +1113,11 @@ for x in scanlist: relative_path + ': %s' % error_match.group(1)) del mydigests - - if "ChangeLog" not in checkdirlist: + # Note: We don't use ChangeLogs in distributed SCMs. + # It will be generated on server side from scm log, + # before package moves to the rsync server. + # This is needed because we try to avoid merge collisions. + if vcs not in ( "git", ) and "ChangeLog" not in checkdirlist: stats["changelog.missing"]+=1 fails["changelog.missing"].append(x+"/ChangeLog") diff --git a/man/color.map.5 b/man/color.map.5 index 7b11ba23a..9ce76ad26 100644 --- a/man/color.map.5 +++ b/man/color.map.5 @@ -9,9 +9,14 @@ 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 or ansi code pattern]\fR .SH "VARIABLES" .TP +\fBNORMAL\fR = \fI"normal"\fR +Defines color used for some words occuring in other contexts than those below. +.TP \fBBAD\fR = \fI"red"\fR Defines color used for some words occuring in bad context. .TP @@ -89,10 +94,12 @@ Defines color used for warnings. .TP .B green .TP -\fBbrown\fR = \fBdarkyellow\fR +.B brown .TP .B yellow .TP +.B darkyellow +.TP .B darkblue .TP .B blue @@ -103,7 +110,7 @@ Defines color used for warnings. .TP .B teal .TP -.B turquoise +\fBturquoise\fR = \fBdarkteal\fR .TP .B lightgray .TP @@ -133,6 +140,10 @@ Defines color used for warnings. .B Other attributes .RS .TP +.B normal +.TP +.B no\-attr +.TP .B reset .TP .B bold @@ -141,11 +152,25 @@ Defines color used for warnings. .TP .B standout .TP +.B no\-standout +.TP .B underline .TP +.B no\-underline +.TP .B blink .TP +.B no\-blink +.TP +.B overline +.TP +.B no\-overline +.TP .B reverse +.TP +.B no\-reverse +.TP +.B invisible .RE .SH "REPORTING BUGS" Please report bugs via http://bugs.gentoo.org/ diff --git a/man/make.conf.5 b/man/make.conf.5 index ef5913a85..2b5a7645f 100644 --- a/man/make.conf.5 +++ b/man/make.conf.5 @@ -130,6 +130,11 @@ Options to append to the end of the \fBemerge\fR(1) command line on every invoca These options will not be appended to the command line if \-\-ignore\-default\-opts is specified. .TP +.B EMERGE_LOG_DIR +Controls the location of emerge.log and emerge-fetch.log. +.br +Defaults to /var/log. +.TP .B EPAUSE_IGNORE Defines whether or not to ignore short pauses that occur when displaying important informational messages. This variable is unset by default. diff --git a/pym/_emerge/__init__.py b/pym/_emerge/__init__.py index c2fe495c1..2f15be0c7 100644 --- a/pym/_emerge/__init__.py +++ b/pym/_emerge/__init__.py @@ -253,13 +253,15 @@ shortmapping={ "v":"--verbose", "V":"--version" } +_emerge_log_dir = EPREFIX+'/var/log' + def emergelog(xterm_titles, mystr, short_msg=None): if xterm_titles and short_msg: if "HOSTNAME" in os.environ: short_msg = os.environ["HOSTNAME"]+": "+short_msg xtermTitle(short_msg) try: - file_path = EPREFIX+"/var/log/emerge.log" + file_path = os.path.join(_emerge_log_dir, 'emerge.log') mylogfile = open(file_path, "a") portage.util.apply_secpass_permissions(file_path, uid=portage.portage_uid, gid=portage.portage_gid, @@ -10173,7 +10175,11 @@ class Scheduler(PollScheduler): _bad_resume_opts = set(["--ask", "--changelog", "--resume", "--skipfirst"]) +<<<<<<< .working _fetch_log = EPREFIX + "/var/log/emerge-fetch.log" +======= + _fetch_log = os.path.join(_emerge_log_dir, 'emerge-fetch.log') +>>>>>>> .merge-right.r13652 class _iface_class(SlotObject): __slots__ = ("dblinkEbuildPhase", "dblinkDisplayMerge", @@ -16175,9 +16181,8 @@ def emerge_main(): myopts["--usepkg"] = True # Allow -p to remove --ask - if ("--pretend" in myopts) and ("--ask" in myopts): - print ">>> --pretend disables --ask... removing --ask from options." - del myopts["--ask"] + if "--pretend" in myopts: + myopts.pop("--ask", None) # forbid --ask when not in a terminal # note: this breaks `emerge --ask | tee logfile`, but that doesn't work anyway. @@ -16267,6 +16272,20 @@ def emerge_main(): def emergelog(*pargs, **kargs): pass + else: + if 'EMERGE_LOG_DIR' in settings: + try: + # At least the parent needs to exist for the lock file. + portage.util.ensure_dirs(settings['EMERGE_LOG_DIR']) + except portage.exception.PortageException, e: + writemsg_level("!!! Error creating directory for " + \ + "EMERGE_LOG_DIR='%s':\n!!! %s\n" % \ + (settings['EMERGE_LOG_DIR'], e), + noiselevel=-1, level=logging.ERROR) + else: + global _emerge_log_dir + _emerge_log_dir = settings['EMERGE_LOG_DIR'] + if not "--pretend" in myopts: emergelog(xterm_titles, "Started emerge on: "+\ time.strftime("%b %d, %Y %H:%M:%S", time.localtime())) diff --git a/pym/portage/__init__.py b/pym/portage/__init__.py index fbad5fe24..b5c2abf05 100644 --- a/pym/portage/__init__.py +++ b/pym/portage/__init__.py @@ -1066,7 +1066,7 @@ class config(object): "DISTDIR", "DOC_SYMLINKS_DIR", "EBUILD", "EBUILD_EXIT_STATUS_FILE", "EBUILD_FORCE_TEST", "EBUILD_PHASE", "ECLASSDIR", "ECLASS_DEPTH", "EMERGE_FROM", - "FEATURES", "FILESDIR", "HOME", "PATH", + "FEATURES", "FILESDIR", "HOME", "NOCOLOR", "PATH", "PKGDIR", "PKGUSE", "PKG_LOGDIR", "PKG_TMPDIR", "PORTAGE_ACTUAL_DISTDIR", "PORTAGE_ARCHLIST", @@ -1142,6 +1142,7 @@ class config(object): "ACCEPT_KEYWORDS", "AUTOCLEAN", "CLEAN_DELAY", "COLLISION_IGNORE", "CONFIG_PROTECT", "CONFIG_PROTECT_MASK", "EGENCACHE_DEFAULT_OPTS", "EMERGE_DEFAULT_OPTS", + "EMERGE_LOG_DIR", "EMERGE_WARNING_DELAY", "FETCHCOMMAND", "FETCHCOMMAND_FTP", "FETCHCOMMAND_HTTP", "FETCHCOMMAND_SFTP", "GENTOO_MIRRORS", "NOCONFMEM", "O", @@ -5456,7 +5457,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.style_to_ansi_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 0711c4b5d..771a28ea7 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,80 +25,62 @@ from portage.exception import CommandNotFound, FileNotFound, \ havecolor=1 dotitles=1 -esc_seq = "\x1b[" +_styles = {} +"""Maps style class to tuple of attribute names.""" -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") -def color(fg, bg="default", attr=["normal"]): - mystr = esc_seq[:] + "%02d" % g_attr[fg] - for x in [bg]+attr: - mystr += ";%02d" % g_attr[x] - return mystr+"m" +codes = {} +"""Maps attribute name to ansi code.""" +esc_seq = "\x1b[" +codes["normal"] = esc_seq + "0m" +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" +codes["reverse"] = esc_seq + "07m" +codes["invisible"] = esc_seq + "08m" + +codes["no-attr"] = esc_seq + "22m" +codes["no-standout"] = esc_seq + "23m" +codes["no-underline"] = esc_seq + "24m" +codes["no-blink"] = esc_seq + "25m" +codes["no-overline"] = esc_seq + "26m" +codes["no-reverse"] = esc_seq + "27m" + +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_default"] = esc_seq + "49m" +codes["bg_darkyellow"] = codes["bg_brown"] -codes={} -codes["reset"] = esc_seq + "39;49;00m" +def color(fg, bg="default", attr=["normal"]): + mystr = codes[fg] + for x in [bg]+attr: + mystr += codes[x] + return mystr -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 = [] +ansi_codes = [] for x in xrange(30, 38): - ansi_color_codes.append("%im" % x) - ansi_color_codes.append("%i;01m" % x) + ansi_codes.append("%im" % x) + ansi_codes.append("%i;01m" % x) rgb_ansi_colors = ['0x000000', '0x555555', '0xAA0000', '0xFF5555', '0x00AA00', '0x55FF55', '0xAA5500', '0xFFFF55', '0x0000AA', '0x5555FF', '0xAA00AA', '0xFF55FF', '0x00AAAA', '0x55FFFF', '0xAAAAAA', '0xFFFFFF'] for x in xrange(len(rgb_ansi_colors)): - codes[rgb_ansi_colors[x]] = esc_seq + ansi_color_codes[x] + codes[rgb_ansi_colors[x]] = esc_seq + ansi_codes[x] del x @@ -130,43 +113,34 @@ codes["darkteal"] = codes["turquoise"] codes["0xAAAA00"] = codes["brown"] codes["darkyellow"] = 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"] +_styles["NORMAL"] = ( "normal", ) +_styles["GOOD"] = ( "green", ) +_styles["WARN"] = ( "yellow", ) +_styles["BAD"] = ( "red", ) +_styles["HILITE"] = ( "teal", ) +_styles["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): +_styles["INFORM"] = ( "darkgreen", ) +_styles["UNMERGE_WARN"] = ( "red", ) +_styles["SECURITY_WARN"] = ( "red", ) +_styles["MERGE_LIST_PROGRESS"] = ( "yellow", ) +_styles["PKG_BLOCKER"] = ( "red", ) +_styles["PKG_BLOCKER_SATISFIED"] = ( "darkblue", ) +_styles["PKG_MERGE"] = ( "darkgreen", ) +_styles["PKG_MERGE_SYSTEM"] = ( "darkgreen", ) +_styles["PKG_MERGE_WORLD"] = ( "green", ) +_styles["PKG_UNINSTALL"] = ( "red", ) +_styles["PKG_NOMERGE"] = ( "darkblue", ) +_styles["PKG_NOMERGE_SYSTEM"] = ( "darkblue", ) +_styles["PKG_NOMERGE_WORLD"] = ( "blue", ) +_styles["PROMPT_CHOICE_DEFAULT"] = ( "green", ) +_styles["PROMPT_CHOICE_OTHER"] = ( "red", ) + +def _parse_color_map(onerror=None): """ Parse /etc/portage/color.map and return a dict of error codes. @@ -177,32 +151,40 @@ def parse_color_map(onerror=None): @return: a dictionary mapping color classes to color codes """ myfile = EPREFIX + 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 _styles and not k in codes: + e = ParseError("'%s', line %s: %s'%s'" % ( + myfile, lineno, "Unknown variable: ", k)) if onerror: onerror(e) @@ -210,21 +192,30 @@ def parse_color_map(onerror=None): raise e continue if ansi_code_pattern.match(v): - codes[k] = esc_seq + v + if k in _styles: + _styles[k] = ( esc_seq + v, ) + elif k in codes: + codes[k] = esc_seq + v else: code_list = [] - for x in v.split(" "): + for x in v.split(): if x in codes: - code_list.append(codes[x]) + if k in _styles: + code_list.append(x) + elif k in codes: + code_list.append(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 _styles: + _styles[k] = tuple(code_list) + elif k in codes: + codes[k] = "".join(code_list) except (IOError, OSError), e: if e.errno == errno.ENOENT: raise FileNotFound(myfile) @@ -232,17 +223,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) @@ -310,10 +290,29 @@ def nocolor(): def resetColor(): return codes["reset"] +def style_to_ansi_code(style): + """ + @param style: A style name + @type style: String + @rtype: String + @return: A string containing one or more ansi escape codes that are + used to render the given style. + """ + ret = "" + for attr_name in _styles[style]: + # allow stuff that has found it's way through ansi_code_pattern + ret += codes.get(attr_name, attr_name) + return ret + def colorize(color_key, text): global havecolor if havecolor: - return codes[color_key] + text + codes["reset"] + if color_key in codes: + return codes[color_key] + text + codes["reset"] + elif color_key in _styles: + return style_to_ansi_code(color_key) + text + codes["reset"] + else: + return text else: return text @@ -350,7 +349,7 @@ class ConsoleStyleFile(object): global havecolor if havecolor and self._styles: for style in self._styles: - self._file.write(codes[style]) + self._file.write(style_to_ansi_code(style)) self._file.write(s) self._file.write(codes["reset"]) else: @@ -715,3 +714,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