diff options
author | Todd Gamblin <tgamblin@llnl.gov> | 2017-08-07 15:09:44 -0700 |
---|---|---|
committer | Todd Gamblin <tgamblin@llnl.gov> | 2017-08-22 16:14:38 -0700 |
commit | 139d5bfa6bee97415094dd471947011303168049 (patch) | |
tree | b7ddcf6107a41e101ea68e23117a5b8444af6f43 /lib/spack/spack/build_environment.py | |
parent | d54110d208f5502bc5ceaf38781508378ddbbdbc (diff) | |
download | spack-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.py | 95 |
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) |