Skip to content

Commit 377e66d

Browse files
committed
include path to cmd.sh script in output generated by run_shell_cmd when a command fails + use colors: red for ERROR line, yellow for path to output files + cmd.sh script
1 parent 9eb0e4a commit 377e66d

File tree

1 file changed

+29
-17
lines changed

1 file changed

+29
-17
lines changed

easybuild/tools/run.py

Lines changed: 29 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@
6868
from easybuild.tools.build_log import dry_run_msg, print_msg, time_str_since
6969
from easybuild.tools.config import build_option
7070
from easybuild.tools.hooks import RUN_SHELL_CMD, load_hooks, run_hook
71+
from easybuild.tools.output import COLOR_RED, COLOR_YELLOW, colorize
7172
from easybuild.tools.utilities import trace_msg
7273

7374

@@ -86,7 +87,7 @@
8687
)
8788

8889
RunShellCmdResult = namedtuple('RunShellCmdResult', ('cmd', 'exit_code', 'output', 'stderr', 'work_dir',
89-
'out_file', 'err_file', 'thread_id', 'task_id'))
90+
'out_file', 'err_file', 'cmd_sh', 'thread_id', 'task_id'))
9091

9192

9293
class RunShellCmdError(BaseException):
@@ -101,6 +102,7 @@ def __init__(self, cmd_result, caller_info, *args, **kwargs):
101102
self.out_file = cmd_result.out_file
102103
self.stderr = cmd_result.stderr
103104
self.err_file = cmd_result.err_file
105+
self.cmd_sh = cmd_result.cmd_sh
104106

105107
self.caller_info = caller_info
106108

@@ -112,31 +114,37 @@ def print(self):
112114
Report failed shell command for this RunShellCmdError instance
113115
"""
114116

115-
def pad_4_spaces(msg):
116-
return ' ' * 4 + msg
117+
def pad_4_spaces(msg, color=None):
118+
padded_msg = ' ' * 4 + msg
119+
if color:
120+
return colorize(padded_msg, color)
121+
else:
122+
return padded_msg
123+
124+
caller_file_name, caller_line_nr, caller_function_name = self.caller_info
125+
called_from_info = f"'{caller_function_name}' function in {caller_file_name} (line {caller_line_nr})"
117126

118127
error_info = [
119128
'',
120-
"ERROR: Shell command failed!",
129+
colorize("ERROR: Shell command failed!", COLOR_RED),
121130
pad_4_spaces(f"full command -> {self.cmd}"),
122131
pad_4_spaces(f"exit code -> {self.exit_code}"),
132+
pad_4_spaces(f"called from -> {called_from_info}"),
123133
pad_4_spaces(f"working directory -> {self.work_dir}"),
124134
]
125135

126136
if self.out_file is not None:
127137
# if there's no separate file for error/warnings, then out_file includes both stdout + stderr
128138
out_info_msg = "output (stdout + stderr)" if self.err_file is None else "output (stdout) "
129-
error_info.append(pad_4_spaces(f"{out_info_msg} -> {self.out_file}"))
139+
error_info.append(pad_4_spaces(f"{out_info_msg} -> {self.out_file}", color=COLOR_YELLOW))
130140

131141
if self.err_file is not None:
132-
error_info.append(pad_4_spaces(f"error/warnings (stderr) -> {self.err_file}"))
142+
error_info.append(pad_4_spaces(f"error/warnings (stderr) -> {self.err_file}", color=COLOR_YELLOW))
133143

134-
caller_file_name, caller_line_nr, caller_function_name = self.caller_info
135-
called_from_info = f"'{caller_function_name}' function in {caller_file_name} (line {caller_line_nr})"
136-
error_info.extend([
137-
pad_4_spaces(f"called from -> {called_from_info}"),
138-
'',
139-
])
144+
if self.cmd_sh is not None:
145+
error_info.append(pad_4_spaces(f"interactive shell script -> {self.cmd_sh}", color=COLOR_YELLOW))
146+
147+
error_info.append('')
140148

141149
sys.stderr.write('\n'.join(error_info) + '\n')
142150

@@ -254,6 +262,8 @@ def create_cmd_scripts(cmd_str, work_dir, env, tmpdir, out_file, err_file):
254262
]))
255263
os.chmod(cmd_fp, 0o775)
256264

265+
return cmd_fp
266+
257267

258268
def _answer_question(stdout, proc, qa_patterns, qa_wait_patterns):
259269
"""
@@ -430,9 +440,9 @@ def to_cmd_str(cmd):
430440
else:
431441
cmd_err_fp = None
432442

433-
create_cmd_scripts(cmd_str, work_dir, env, tmpdir, cmd_out_fp, cmd_err_fp)
443+
cmd_sh = create_cmd_scripts(cmd_str, work_dir, env, tmpdir, cmd_out_fp, cmd_err_fp)
434444
else:
435-
tmpdir, cmd_out_fp, cmd_err_fp = None, None, None
445+
tmpdir, cmd_out_fp, cmd_err_fp, cmd_sh = None, None, None, None
436446

437447
interactive_msg = 'interactive ' if interactive else ''
438448

@@ -445,7 +455,8 @@ def to_cmd_str(cmd):
445455
dry_run_msg(msg, silent=silent)
446456

447457
return RunShellCmdResult(cmd=cmd_str, exit_code=0, output='', stderr=None, work_dir=work_dir,
448-
out_file=cmd_out_fp, err_file=cmd_err_fp, thread_id=thread_id, task_id=task_id)
458+
out_file=cmd_out_fp, err_file=cmd_err_fp, cmd_sh=cmd_sh,
459+
thread_id=thread_id, task_id=task_id)
449460

450461
start_time = datetime.now()
451462
if not hidden:
@@ -571,8 +582,9 @@ def to_cmd_str(cmd):
571582
except IOError as err:
572583
raise EasyBuildError(f"Failed to dump command output to temporary file: {err}")
573584

574-
res = RunShellCmdResult(cmd=cmd_str, exit_code=proc.returncode, output=output, stderr=stderr, work_dir=work_dir,
575-
out_file=cmd_out_fp, err_file=cmd_err_fp, thread_id=thread_id, task_id=task_id)
585+
res = RunShellCmdResult(cmd=cmd_str, exit_code=proc.returncode, output=output, stderr=stderr,
586+
work_dir=work_dir, out_file=cmd_out_fp, err_file=cmd_err_fp, cmd_sh=cmd_sh,
587+
thread_id=thread_id, task_id=task_id)
576588

577589
# always log command output
578590
cmd_name = cmd_str.split(' ')[0]

0 commit comments

Comments
 (0)