merge with trunk rev 2966:2979
authorKito <kito@gentoo.org>
Fri, 24 Mar 2006 03:44:34 +0000 (03:44 -0000)
committerKito <kito@gentoo.org>
Fri, 24 Mar 2006 03:44:34 +0000 (03:44 -0000)
svn path=/main/branches/prefix/; revision=2983

bin/ebuild
bin/ebuild.sh
bin/emerge
pym/portage.py
pym/portage_debug.py [new file with mode: 0644]

index b6b124e46eb2b0a471482e0120a7bc1caeab873f..f5be32ab4520c7c9aba806216944af2328e24284 100755 (executable)
@@ -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()
index 6ab87581b7aee3d9ce2c243d12419e9590c0d56d..680444df2d89d878a7aa48ee2023edb569ead0aa 100755 (executable)
@@ -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
index f8505b6d9a02e7dacb54bb6879f2a8873bdd9098..3ce49c4c9cf47dddb421c440a9db2277eea8cd66 100755 (executable)
@@ -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:
index 200b1c3cf1820d69ff0030e50c639d547b68604b..352f740bfbeccc667daa747bcdd90df552dc65fe 100644 (file)
@@ -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 (file)
index 0000000..318754d
--- /dev/null
@@ -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