summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorZac Medico <zmedico@gentoo.org>2006-03-23 08:22:58 +0000
committerZac Medico <zmedico@gentoo.org>2006-03-23 08:22:58 +0000
commit7e8b27c1d972f4eff89fd58c29d078c310b44e6b (patch)
treea0ddff2e17ba817680a21377b46c63d7999432be
parentf2468b530d094199b5e91d0856e99f6caf20c5e2 (diff)
downloadportage-7e8b27c1d972f4eff89fd58c29d078c310b44e6b.tar.gz
portage-7e8b27c1d972f4eff89fd58c29d078c310b44e6b.tar.bz2
portage-7e8b27c1d972f4eff89fd58c29d078c310b44e6b.zip
Add a portage_debug module and python-trace feature for --debug mode.
svn path=/main/trunk/; revision=2979
-rwxr-xr-xbin/ebuild5
-rwxr-xr-xbin/emerge3
-rw-r--r--pym/portage_debug.py116
3 files changed, 124 insertions, 0 deletions
diff --git a/bin/ebuild b/bin/ebuild
index fafdbbccc..a62585a5e 100755
--- a/bin/ebuild
+++ b/bin/ebuild
@@ -25,6 +25,11 @@ sys.path = ["/usr/lib/portage/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/emerge b/bin/emerge
index b17a2a6b2..55e9420d1 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_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