summaryrefslogtreecommitdiff
path: root/lib/spack/spack/build_environment.py
diff options
context:
space:
mode:
authorTodd Gamblin <tgamblin@llnl.gov>2017-08-07 15:09:44 -0700
committerTodd Gamblin <tgamblin@llnl.gov>2017-08-22 16:14:38 -0700
commit139d5bfa6bee97415094dd471947011303168049 (patch)
treeb7ddcf6107a41e101ea68e23117a5b8444af6f43 /lib/spack/spack/build_environment.py
parentd54110d208f5502bc5ceaf38781508378ddbbdbc (diff)
downloadspack-139d5bfa6bee97415094dd471947011303168049.tar.gz
spack-139d5bfa6bee97415094dd471947011303168049.tar.bz2
spack-139d5bfa6bee97415094dd471947011303168049.tar.xz
spack-139d5bfa6bee97415094dd471947011303168049.zip
Display build output on ProcessError, instead of Python context.
- If a failure comes from an external command and NOT the Python code, display errors highlighted with some context. - Add some rudimentary support for parsing errors out of the build log (not very sophisticated yet). - Build errors in Python code will still display with Python context.
Diffstat (limited to 'lib/spack/spack/build_environment.py')
-rw-r--r--lib/spack/spack/build_environment.py95
1 files changed, 66 insertions, 29 deletions
diff --git a/lib/spack/spack/build_environment.py b/lib/spack/spack/build_environment.py
index 6c4674bd26..ad27b3321d 100644
--- a/lib/spack/spack/build_environment.py
+++ b/lib/spack/spack/build_environment.py
@@ -1,5 +1,5 @@
##############################################################################
-# Copyright (c) 2013-2016, Lawrence Livermore National Security, LLC.
+# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
# Produced at the Lawrence Livermore National Laboratory.
#
# This file is part of Spack.
@@ -58,6 +58,7 @@ import shutil
import sys
import traceback
from six import iteritems
+from six import StringIO
import llnl.util.tty as tty
from llnl.util.tty.color import colorize
@@ -69,6 +70,9 @@ from spack.environment import EnvironmentModifications, validate
from spack.util.environment import *
from spack.util.executable import Executable
from spack.util.module_cmd import load_module, get_path_from_module
+from spack.util.log_parse import *
+
+
#
# This can be set by the user to globally disable parallel builds.
#
@@ -576,8 +580,12 @@ def fork(pkg, function, dirty=False):
build_log = pkg.log_path
# make a pickleable exception to send to parent.
- msg = "%s: %s" % (str(exc_type.__name__), str(exc))
- ce = ChildError(msg, tb_string, build_log, package_context)
+ msg = "%s: %s" % (exc_type.__name__, str(exc))
+
+ ce = ChildError(msg,
+ exc_type.__module__,
+ exc_type.__name__,
+ tb_string, build_log, package_context)
child_pipe.send(ce)
finally:
@@ -657,7 +665,7 @@ def get_package_context(traceback, context=3):
for i, line in enumerate(sourcelines):
is_error = start_ctx + i == l
mark = ">> " if is_error else " "
- marked = " %s%-5d%s" % (mark, start_ctx + i, line.rstrip())
+ marked = " %s%-6d%s" % (mark, start_ctx + i, line.rstrip())
if is_error:
marked = colorize('@R{%s}' % marked)
lines.append(marked)
@@ -683,40 +691,67 @@ class ChildError(spack.error.SpackError):
failure in lieu of trying to run sys.excepthook on the parent
process, so users will see the correct stack trace from a child.
- 3. They also contain package_context, which shows source code context
- in the Package implementation where the error happened. To get
- this, Spack searches the stack trace for the deepest frame where
- ``self`` is in scope and is an instance of PackageBase. This will
- generally find a useful spot in the ``package.py`` file.
+ 3. They also contain context, which shows context in the Package
+ implementation where the error happened. This helps people debug
+ Python code in their packages. To get it, Spack searches the
+ stack trace for the deepest frame where ``self`` is in scope and
+ is an instance of PackageBase. This will generally find a useful
+ spot in the ``package.py`` file.
+
+ The long_message of a ChildError displays one of two things:
+
+ 1. If the original error was a ProcessError, indicating a command
+ died during the build, we'll show context from the build log.
- The long_message of a ChildError displays all this stuff to the user,
- and SpackError handles displaying the special traceback if we're in
- debug mode with spack -d.
+ 2. If the original error was any other type of error, we'll show
+ context from the Python code.
+
+ SpackError handles displaying the special traceback if we're in debug
+ mode with spack -d.
"""
- def __init__(self, msg, traceback_string, build_log, package_context):
+ # List of errors considered "build errors", for which we'll show log
+ # context instead of Python context.
+ build_errors = [('spack.util.executable', 'ProcessError')]
+
+ def __init__(self, msg, module, classname, traceback_string, build_log,
+ context):
super(ChildError, self).__init__(msg)
+ self.module = module
+ self.name = classname
self.traceback = traceback_string
self.build_log = build_log
- self.package_context = package_context
+ self.context = context
@property
def long_message(self):
- msg = self._long_message if self._long_message else ''
-
- if self.package_context:
- if msg:
- msg += "\n\n"
- msg += '\n'.join(self.package_context)
-
- if msg:
- msg += "\n\n"
+ out = StringIO()
+ out.write(self._long_message if self._long_message else '')
+
+ if (self.module, self.name) in ChildError.build_errors:
+ # The error happened in some external executed process. Show
+ # the build log with errors highlighted.
+ if self.build_log:
+ events = parse_log_events(self.build_log)
+ out.write("\n%d errors in build log:\n" % len(events))
+ out.write(make_log_context(events))
+
+ else:
+ # The error happened in in the Python code, so try to show
+ # some context from the Package itself.
+ out.write('%s: %s\n\n' % (self.name, self.message))
+ if self.context:
+ out.write('\n'.join(self.context))
+ out.write('\n')
+
+ if out.getvalue():
+ out.write('\n')
if self.build_log:
- msg += "See build log for details:\n"
- msg += " %s" % self.build_log
+ out.write('See build log for details:\n')
+ out.write(' %s' % self.build_log)
- return msg
+ return out.getvalue()
def __reduce__(self):
"""__reduce__ is used to serialize (pickle) ChildErrors.
@@ -726,11 +761,13 @@ class ChildError(spack.error.SpackError):
"""
return _make_child_error, (
self.message,
+ self.module,
+ self.name,
self.traceback,
self.build_log,
- self.package_context)
+ self.context)
-def _make_child_error(msg, traceback, build_log, package_context):
+def _make_child_error(msg, module, name, traceback, build_log, context):
"""Used by __reduce__ in ChildError to reconstruct pickled errors."""
- return ChildError(msg, traceback, build_log, package_context)
+ return ChildError(msg, module, name, traceback, build_log, context)