summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSteven Knight <knight@baldmt.com>2004-09-18 12:41:15 (GMT)
committerSteven Knight <knight@baldmt.com>2004-09-18 12:41:15 (GMT)
commit56f6ebd377b893efa78130cc49db48675e48439e (patch)
treea6471aa2c86cfe1d44b297e29d7df306152b477d
parent797e94a2484a11a771fb537619bdc011bf94bf2d (diff)
downloadSCons-56f6ebd377b893efa78130cc49db48675e48439e.zip
SCons-56f6ebd377b893efa78130cc49db48675e48439e.tar.gz
SCons-56f6ebd377b893efa78130cc49db48675e48439e.tar.bz2
Print tracebacks for errors other than UserError and StopError. (Gary Oberbrunner)
-rw-r--r--doc/man/scons.15
-rw-r--r--src/CHANGES.txt3
-rw-r--r--src/engine/SCons/Script/__init__.py19
-rw-r--r--src/engine/SCons/Taskmaster.py9
-rw-r--r--src/engine/SCons/TaskmasterTests.py22
-rw-r--r--test/option--debug.py45
6 files changed, 94 insertions, 9 deletions
diff --git a/doc/man/scons.1 b/doc/man/scons.1
index d4f2103..c63a23a 100644
--- a/doc/man/scons.1
+++ b/doc/man/scons.1
@@ -562,6 +562,11 @@ Building myprog.o with action(s):
.EE
.TP
+--debug=stacktrace
+Prints an internal Python stack trace
+when encountering an otherwise unexplained error.
+
+.TP
--debug=time
Prints various time profiling information: the time spent
executing each build command, the total build time, the total time spent
diff --git a/src/CHANGES.txt b/src/CHANGES.txt
index b035acb..1965c61 100644
--- a/src/CHANGES.txt
+++ b/src/CHANGES.txt
@@ -73,6 +73,9 @@ RELEASE 0.97 - XXX
- Add a PRINT_CMD_LINE_FUNC construction variable to allow people
to filter (or log) command-line output.
+ - Print an internal Python stack trace in response to an otherwise
+ unexplained error when --debug=stacktrace is specified.
+
From Kevin Quick:
- Fix the Builder name returned from ListBuilders and other instances
diff --git a/src/engine/SCons/Script/__init__.py b/src/engine/SCons/Script/__init__.py
index dfee767..160fae3 100644
--- a/src/engine/SCons/Script/__init__.py
+++ b/src/engine/SCons/Script/__init__.py
@@ -141,8 +141,12 @@ class BuildTask(SCons.Taskmaster.Task):
# is to display the various types of Errors and Exceptions
# appropriately.
status = 2
- t, e = self.exc_info()[:2]
- tb = None
+ exc_info = self.exc_info()
+ try:
+ t, e, tb = exc_info
+ except ValueError:
+ t, e = exc_info
+ tb = None
if t is None:
# The Taskmaster didn't record an exception for this Task;
# see if the sys module has one.
@@ -166,7 +170,7 @@ class BuildTask(SCons.Taskmaster.Task):
s = s + ' Stop.'
sys.stderr.write("scons: *** %s\n" % s)
- if tb:
+ if tb and print_stacktrace:
sys.stderr.write("scons: internal stack trace:\n")
traceback.print_tb(tb, file=sys.stderr)
@@ -240,6 +244,7 @@ print_dtree = 0
print_explanations = 0
print_includes = 0
print_objects = 0
+print_stacktrace = 0
print_time = 0
print_tree = 0
memory_stats = None
@@ -400,7 +405,8 @@ def _set_globals(options):
global repositories, keep_going_on_error, ignore_errors
global print_count, print_dtree
global print_explanations, print_includes
- global print_objects, print_time, print_tree
+ global print_objects, print_stacktrace
+ global print_time, print_tree
global memory_outf, memory_stats
if options.repository:
@@ -423,6 +429,8 @@ def _set_globals(options):
print_objects = 1
elif options.debug == "presub":
SCons.Action.print_actions_presub = 1
+ elif options.debug == "stacktrace":
+ print_stacktrace = 1
elif options.debug == "time":
print_time = 1
elif options.debug == "tree":
@@ -520,7 +528,8 @@ class OptParser(OptionParser):
debug_options = ["count", "dtree", "explain",
"includes", "memory", "objects",
- "pdb", "presub", "time", "tree"]
+ "pdb", "presub", "stacktrace",
+ "time", "tree"]
def opt_debug(option, opt, value, parser, debug_options=debug_options):
if value in debug_options:
diff --git a/src/engine/SCons/Taskmaster.py b/src/engine/SCons/Taskmaster.py
index dab5026..84eb08d 100644
--- a/src/engine/SCons/Taskmaster.py
+++ b/src/engine/SCons/Taskmaster.py
@@ -461,5 +461,10 @@ class Taskmaster:
self.pending = []
def exception_raise(self, exception):
- exc_type, exc_value = exception[:2]
- raise exc_type, exc_value
+ exc = exception[:]
+ try:
+ exc_type, exc_value, exc_traceback = exc
+ except ValueError:
+ exc_type, exc_value = exc
+ exc_traceback = None
+ raise exc_type, exc_value, exc_traceback
diff --git a/src/engine/SCons/TaskmasterTests.py b/src/engine/SCons/TaskmasterTests.py
index 8865e09..a908192 100644
--- a/src/engine/SCons/TaskmasterTests.py
+++ b/src/engine/SCons/TaskmasterTests.py
@@ -921,7 +921,25 @@ class TaskmasterTestCase(unittest.TestCase):
else:
assert 0, "did not catch expected exception"
- t.exception_set(("exception 3", "XYZZY"))
+ try:
+ 1/0
+ except:
+ tb = sys.exc_info()[2]
+ t.exception_set(("exception 3", "arg", tb))
+ try:
+ t.exception_raise()
+ except:
+ exc_type, exc_value, exc_tb = sys.exc_info()
+ assert exc_type == 'exception 3', exc_type
+ assert exc_value == "arg", exc_value
+ import traceback
+ x = traceback.extract_tb(tb)[-1]
+ y = traceback.extract_tb(exc_tb)[-1]
+ assert x == y, "x = %s, y = %s" % (x, y)
+ else:
+ assert 0, "did not catch expected exception"
+
+ t.exception_set(("exception 4", "XYZZY"))
def fw_exc(exc):
raise 'exception_forwarded', exc
tm.exception_raise = fw_exc
@@ -930,7 +948,7 @@ class TaskmasterTestCase(unittest.TestCase):
except:
exc_type, exc_value = sys.exc_info()[:2]
assert exc_type == 'exception_forwarded', exc_type
- assert exc_value[0] == "exception 3", exc_value[0]
+ assert exc_value[0] == "exception 4", exc_value[0]
assert exc_value[1] == "XYZZY", exc_value[1]
else:
assert 0, "did not catch expected exception"
diff --git a/test/option--debug.py b/test/option--debug.py
index 64cc424..e3d9960 100644
--- a/test/option--debug.py
+++ b/test/option--debug.py
@@ -384,4 +384,49 @@ test.must_match('file16.out', "file16.in\n")
test.must_match('file17.out', "file17.in\n")
test.must_match('file18.out', "file18.in\n")
+############################
+# test --debug=stacktrace
+
+test.write('SConstruct', """\
+def kfile_scan(node, env, target):
+ raise "kfile_scan error"
+
+kscan = Scanner(name = 'kfile',
+ function = kfile_scan,
+ skeys = ['.k'])
+
+env = Environment()
+env.Append(SCANNERS = [kscan])
+
+env.Command('foo', 'foo.k', Copy('$TARGET', '$SOURCE'))
+""")
+
+test.write('foo.k', "foo.k\n")
+
+test.run(status = 2, stderr = "scons: *** kfile_scan error\n")
+
+test.run(arguments = "--debug=stacktrace",
+ status = 2,
+ stderr = None)
+
+stderr = test.stderr()
+
+lines = [
+ "scons: *** kfile_scan error",
+ "scons: internal stack trace:",
+ 'raise "kfile_scan error"',
+]
+
+missing = []
+for line in lines:
+ if string.find(stderr, line) == -1:
+ missing.append(line)
+
+if missing:
+ print "STDERR is missing the following lines:"
+ print "\t" + string.join(lines, "\n\t")
+ print "STDERR ====="
+ print stderr
+ test.fail_test(1)
+
test.pass_test()