From 20654a9a072d8569e4484303f6b1f52c6d5ff284 Mon Sep 17 00:00:00 2001 From: Theofilos Manitaras Date: Wed, 17 Mar 2021 17:05:52 +0100 Subject: [PATCH 1/4] Support previewing of build error in failure report --- docs/config_reference.rst | 9 +++++++++ reframe/core/exceptions.py | 8 +++----- reframe/core/pipeline.py | 18 ++++++++++++++++-- reframe/schemas/config.json | 1 + 4 files changed, 29 insertions(+), 7 deletions(-) diff --git a/docs/config_reference.rst b/docs/config_reference.rst index 2651f80481..9a8b375af6 100644 --- a/docs/config_reference.rst +++ b/docs/config_reference.rst @@ -1204,6 +1204,15 @@ General Configuration See also :option:`--non-default-craype` for more details. +.. js:attribute:: .general[].preview_build_error + + :required: No + :default: ``0`` + + The number of lines to print in the failure report if there is an error during the build job of the test. + In the default case, only the names of the stderr and stdout files of the build job are going to be reported. + + .. js:attribute:: .general[].purge_environment :required: No diff --git a/reframe/core/exceptions.py b/reframe/core/exceptions.py index 16905345bd..140b9fc98e 100644 --- a/reframe/core/exceptions.py +++ b/reframe/core/exceptions.py @@ -156,12 +156,10 @@ class ContainerError(ReframeError): class BuildError(ReframeError): '''Raised when a build fails.''' - def __init__(self, stdout, stderr): + def __init__(self, stdout, stderr, msg=None): super().__init__() - self._message = ( - "standard error can be found in `%s', " - "standard output can be found in `%s'" % (stderr, stdout) - ) + self._message = msg or (f'standard error can be found in {stderr!r}, ' + f'standard output can be found in {stdout!r}') class SpawnedProcessError(ReframeError): diff --git a/reframe/core/pipeline.py b/reframe/core/pipeline.py index 6545f97aea..8943e412e6 100644 --- a/reframe/core/pipeline.py +++ b/reframe/core/pipeline.py @@ -1291,9 +1291,23 @@ def compile_wait(self): ''' self._build_job.wait() - # We raise a BuildError when we an exit code and it is non zero + # We raise a BuildError when we get an exit code and it is non zero if self._build_job.exitcode: - raise BuildError(self._build_job.stdout, self._build_job.stderr) + error_message = None + err_lines = rt.runtime().get_option( + 'general/0/preview_build_error' + ) + if err_lines and err_lines > 0: + with contextlib.suppress(OSError): + with open(os.path.join( + self._stagedir, self._build_job.stderr)) as f: + error_message = '\n'.join([ + f'\nPreview of {self._build_job.stderr!r}:\n', + *f.readlines()[:err_lines] + ]) + + raise BuildError(self._build_job.stdout, self._build_job.stderr, + error_message) self.build_system.post_build(self._build_job) diff --git a/reframe/schemas/config.json b/reframe/schemas/config.json index 1d5b143b1c..6aee0d2868 100644 --- a/reframe/schemas/config.json +++ b/reframe/schemas/config.json @@ -446,6 +446,7 @@ "items": {"type": "string"} }, "non_default_craype": {"type": "boolean"}, + "preview_build_error": {"type": "number"}, "purge_environment": {"type": "boolean"}, "report_file": {"type": "string"}, "save_log_files": {"type": "boolean"}, From b41b1b42a21a7473eeb25679b7ed1c89d8a25e62 Mon Sep 17 00:00:00 2001 From: Theofilos Manitaras Date: Wed, 17 Mar 2021 17:08:49 +0100 Subject: [PATCH 2/4] Indentation fix --- reframe/core/pipeline.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/reframe/core/pipeline.py b/reframe/core/pipeline.py index 8943e412e6..5bb03960e6 100644 --- a/reframe/core/pipeline.py +++ b/reframe/core/pipeline.py @@ -1301,10 +1301,10 @@ def compile_wait(self): with contextlib.suppress(OSError): with open(os.path.join( self._stagedir, self._build_job.stderr)) as f: - error_message = '\n'.join([ - f'\nPreview of {self._build_job.stderr!r}:\n', - *f.readlines()[:err_lines] - ]) + error_message = '\n'.join([ + f'\nPreview of {self._build_job.stderr!r}:\n', + *f.readlines()[:err_lines] + ]) raise BuildError(self._build_job.stdout, self._build_job.stderr, error_message) From 0e7fd67c0f0c17653b855e1c6714eb7d89376ad0 Mon Sep 17 00:00:00 2001 From: Theofilos Manitaras Date: Wed, 17 Mar 2021 17:11:46 +0100 Subject: [PATCH 3/4] Fix indentation (2) --- reframe/core/pipeline.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/reframe/core/pipeline.py b/reframe/core/pipeline.py index 5bb03960e6..2e854f3d3f 100644 --- a/reframe/core/pipeline.py +++ b/reframe/core/pipeline.py @@ -1299,12 +1299,12 @@ def compile_wait(self): ) if err_lines and err_lines > 0: with contextlib.suppress(OSError): - with open(os.path.join( - self._stagedir, self._build_job.stderr)) as f: - error_message = '\n'.join([ - f'\nPreview of {self._build_job.stderr!r}:\n', - *f.readlines()[:err_lines] - ]) + with open(os.path.join(self._stagedir, + self._build_job.stderr)) as f: + error_message = '\n'.join([ + f'\nPreview of {self._build_job.stderr!r}:\n', + *f.readlines()[:err_lines] + ]) raise BuildError(self._build_job.stdout, self._build_job.stderr, error_message) From 75f82ea7fbcce3c41d18bcaf29a051e22c6880d4 Mon Sep 17 00:00:00 2001 From: Vasileios Karakasis Date: Sat, 20 Mar 2021 23:00:36 +0100 Subject: [PATCH 4/4] Revert changes and implement from scratch The `BuildError` gets simply an additional `prefix` argument and makes sure to construct the right message by reading the stderr. The 10 first lines of stderr are printed and this is hard coded. No need to be configurable. --- docs/config_reference.rst | 9 --------- reframe/core/exceptions.py | 20 +++++++++++++++++--- reframe/core/pipeline.py | 19 +++---------------- reframe/schemas/config.json | 1 - 4 files changed, 20 insertions(+), 29 deletions(-) diff --git a/docs/config_reference.rst b/docs/config_reference.rst index 9a8b375af6..2651f80481 100644 --- a/docs/config_reference.rst +++ b/docs/config_reference.rst @@ -1204,15 +1204,6 @@ General Configuration See also :option:`--non-default-craype` for more details. -.. js:attribute:: .general[].preview_build_error - - :required: No - :default: ``0`` - - The number of lines to print in the failure report if there is an error during the build job of the test. - In the default case, only the names of the stderr and stdout files of the build job are going to be reported. - - .. js:attribute:: .general[].purge_environment :required: No diff --git a/reframe/core/exceptions.py b/reframe/core/exceptions.py index 140b9fc98e..f254d68328 100644 --- a/reframe/core/exceptions.py +++ b/reframe/core/exceptions.py @@ -7,6 +7,7 @@ # Base regression exceptions # +import contextlib import inspect import os import sys @@ -156,10 +157,23 @@ class ContainerError(ReframeError): class BuildError(ReframeError): '''Raised when a build fails.''' - def __init__(self, stdout, stderr, msg=None): + def __init__(self, stdout, stderr, prefix=None): super().__init__() - self._message = msg or (f'standard error can be found in {stderr!r}, ' - f'standard output can be found in {stdout!r}') + num_lines = 10 + prefix = prefix or '.' + lines = [ + f'stdout: {stdout!r}, stderr: {stderr!r}', + f'--- {stderr} (first {num_lines} lines) ---' + ] + with contextlib.suppress(OSError): + with open(os.path.join(prefix, stderr)) as fp: + for i, line in enumerate(fp): + if i < num_lines: + # Remove trailing '\n' + lines.append(line[:-1]) + + lines += [f'--- {stderr} --- '] + self._message = '\n'.join(lines) class SpawnedProcessError(ReframeError): diff --git a/reframe/core/pipeline.py b/reframe/core/pipeline.py index 2e854f3d3f..92389707d2 100644 --- a/reframe/core/pipeline.py +++ b/reframe/core/pipeline.py @@ -1291,23 +1291,10 @@ def compile_wait(self): ''' self._build_job.wait() - # We raise a BuildError when we get an exit code and it is non zero + # We raise a BuildError when we an exit code and it is non zero if self._build_job.exitcode: - error_message = None - err_lines = rt.runtime().get_option( - 'general/0/preview_build_error' - ) - if err_lines and err_lines > 0: - with contextlib.suppress(OSError): - with open(os.path.join(self._stagedir, - self._build_job.stderr)) as f: - error_message = '\n'.join([ - f'\nPreview of {self._build_job.stderr!r}:\n', - *f.readlines()[:err_lines] - ]) - - raise BuildError(self._build_job.stdout, self._build_job.stderr, - error_message) + raise BuildError(self._build_job.stdout, + self._build_job.stderr, self._stagedir) self.build_system.post_build(self._build_job) diff --git a/reframe/schemas/config.json b/reframe/schemas/config.json index 6aee0d2868..1d5b143b1c 100644 --- a/reframe/schemas/config.json +++ b/reframe/schemas/config.json @@ -446,7 +446,6 @@ "items": {"type": "string"} }, "non_default_craype": {"type": "boolean"}, - "preview_build_error": {"type": "number"}, "purge_environment": {"type": "boolean"}, "report_file": {"type": "string"}, "save_log_files": {"type": "boolean"},