From: Kito Date: Fri, 24 Mar 2006 03:44:34 +0000 (-0000) Subject: merge with trunk rev 2966:2979 X-Git-Url: http://git.tremily.us/gitweb.cgi?a=commitdiff_plain;h=9c7b881d73a3abcdc99c5d7749c112db2d25b1bb;p=portage.git merge with trunk rev 2966:2979 svn path=/main/branches/prefix/; revision=2983 --- diff --git a/bin/ebuild b/bin/ebuild index b6b124e46..f5be32ab4 100755 --- a/bin/ebuild +++ b/bin/ebuild @@ -25,6 +25,11 @@ sys.path = ["@PORTAGE_BASE@/pym"]+sys.path import portage, portage_util, portage_const +# do this _after_ 'import portage' to prevent unnecessary tracing +if debug and "python-trace" in portage.features: + import portage_debug + portage_debug.set_trace(True) + if portage.settings["NOCOLOR"] in ("yes","true") or not sys.stdout.isatty(): import output output.nocolor() diff --git a/bin/ebuild.sh b/bin/ebuild.sh index 6ab87581b..680444df2 100755 --- a/bin/ebuild.sh +++ b/bin/ebuild.sh @@ -42,7 +42,15 @@ OCC="$CC" OCXX="$CXX" source ${PREFIX}/etc/profile.env &>/dev/null if [ -f "${PORTAGE_BASHRC}" ]; then - source "${PORTAGE_BASHRC}" + # If $- contains x, then tracing has already enabled elsewhere for some + # reason. We preserve it's state so as not to interfere. + if [ "$PORTAGE_DEBUG" != "1" ] || [ "${-/x/}" != "$-" ]; then + source "${PORTAGE_BASHRC}" + else + set -x + source "${PORTAGE_BASHRC}" + set +x + fi fi [ ! -z "$OCC" ] && export CC="$OCC" [ ! -z "$OCXX" ] && export CXX="$OCXX" @@ -373,6 +381,7 @@ diefunc() { echo >&2 echo "!!! ERROR: $CATEGORY/$PF failed." >&2 dump_trace 2 1>&2 + echo " $(basename "${BASH_SOURCE[1]}"), line ${BASH_LINENO[0]}: Called die" 1>&2 echo >&2 echo "!!! ${*:-(no error message)}" >&2 echo "!!! If you need support, post the topmost build error, and the call stack if relevant." >&2 diff --git a/bin/emerge b/bin/emerge index f8505b6d9..3ce49c4c9 100755 --- a/bin/emerge +++ b/bin/emerge @@ -401,6 +401,9 @@ if ("--debug" in myopts): portage.settings.backup_changes("PORTAGE_DEBUG") portage.debug=1 portage.settings.lock() + if "python-trace" in portage.features: + import portage_debug + portage_debug.set_trace(True) if ("--resume" in myopts): if "--tree" in myopts: diff --git a/pym/portage.py b/pym/portage.py index 200b1c3cf..352f740bf 100644 --- a/pym/portage.py +++ b/pym/portage.py @@ -2360,7 +2360,10 @@ def spawnebuild(mydo,actionmap,mysettings,debug,alwaysdep=0,logfile=None): if phase_retval == os.EX_OK: if mydo == "install": mycommand = " ".join([MISC_SH_BINARY, "install_qa_check"]) - return spawn(mycommand, mysettings, debug=debug, logfile=logfile, **kwargs) + qa_retval = spawn(mycommand, mysettings, debug=debug, logfile=logfile, **kwargs) + if qa_retval: + writemsg("!!! install_qa_check failed; exiting.\n") + return qa_retval return phase_retval # chunked out deps for each phase, so that ebuild binary can use it @@ -2739,7 +2742,9 @@ def doebuild(myebuild,mydo,myroot,mysettings,debug=0,listonly=0,fetchonly=0,clea # Post phase logic and tasks that have been factored out of ebuild.sh. myargs = [MISC_SH_BINARY, "preinst_mask", "preinst_sfperms", "preinst_selinux_labels", "preinst_suid_scan"] - spawn(" ".join(myargs), mysettings, debug=debug, free=1, logfile=logfile) + phase_retval = spawn(" ".join(myargs), mysettings, debug=debug, free=1, logfile=logfile) + if phase_retval != os.EX_OK: + writemsg("!!! post preinst failed; exiting.\n") del mysettings["IMAGE"] return phase_retval elif mydo in ["prerm","postrm","postinst","config"]: diff --git a/pym/portage_debug.py b/pym/portage_debug.py new file mode 100644 index 000000000..318754d75 --- /dev/null +++ b/pym/portage_debug.py @@ -0,0 +1,116 @@ +# Copyright 1999-2006 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 +# $Header: $ + +import os, sys, threading + +import portage_const +from portage_util import writemsg + +def set_trace(on=True): + if on: + t = trace_handler() + threading.settrace(t.event_handler) + sys.settrace(t.event_handler) + else: + sys.settrace(None) + threading.settrace(None) + +class trace_handler(object): + + def __init__(self): + python_base = None + for x in sys.path: + if os.path.basename(x).startswith("python2."): + python_base = x + break + + self.ignore_prefixes = [] + if python_base is not None: + self.ignore_prefixes.append(python_base + os.sep) + + self.trim_filename = prefix_trimmer(os.path.join(portage_const.PORTAGE_BASE_PATH, "pym") + os.sep).trim + self.show_local_lines = False + self.max_repr_length = 200 + + def event_handler(self, *args): + frame, event, arg = args + if "line" == event: + if self.show_local_lines: + self.trace_line(*args) + else: + if not self.ignore_filename(frame.f_code.co_filename): + self.trace_event(*args) + return self.event_handler + + def trace_event(self, frame, event, arg): + writemsg("%s line=%d name=%s event=%s %slocals=%s\n" % \ + (self.trim_filename(frame.f_code.co_filename), + frame.f_lineno, + frame.f_code.co_name, + event, + self.arg_repr(frame, event, arg), + self.locals_repr(frame, event, arg))) + + def arg_repr(self, frame, event, arg): + my_repr = None + if "return" == event: + my_repr = repr(arg) + if len(my_repr) > self.max_repr_length: + my_repr = "'omitted'" + return "value=%s " % my_repr + elif "exception" == event: + my_repr = repr(arg[1]) + if len(my_repr) > self.max_repr_length: + my_repr = "'omitted'" + return "type=%s value=%s " % (arg[0], my_repr) + + return "" + + def trace_line(self, frame, event, arg): + writemsg("%s line=%d\n" % (self.trim_filename(frame.f_code.co_filename), frame.f_lineno)) + + def ignore_filename(self, filename): + if filename: + for x in self.ignore_prefixes: + if filename.startswith(x): + return True + return False + + def locals_repr(self, frame, event, arg): + """Create a representation of the locals dict that is suitable for + tracing output.""" + + my_locals = frame.f_locals.copy() + + # prevent unsafe __repr__ call on self when __init__ is called + # (method calls aren't safe until after __init__ has completed). + if frame.f_code.co_name == "__init__" and "self" in my_locals: + my_locals["self"] = "omitted" + + # We omit items that will lead to unreasonable bloat of the trace + # output (and resulting log file). + for k, v in my_locals.iteritems(): + my_repr = repr(v) + if len(my_repr) > self.max_repr_length: + my_locals[k] = "omitted" + return my_locals + +class prefix_trimmer(object): + def __init__(self, prefix): + self.prefix = prefix + self.cut_index = len(prefix) + self.previous = None + self.previous_trimmed = None + + def trim(self, s): + """Remove a prefix from the string and return the result. + The previous result is automatically cached.""" + if s == self.previous: + return self.previous_trimmed + else: + if s.startswith(self.prefix): + self.previous_trimmed = s[self.cut_index:] + else: + self.previous_trimmed = s + return self.previous_trimmed