Skip to content
Merged
Show file tree
Hide file tree
Changes from 18 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
dc9c218
Attempt command logging
Micket Mar 19, 2024
75a6070
Use only cmd_str for logging
Micket Mar 19, 2024
84ccc73
Check for env == None
Micket Mar 19, 2024
9cae748
Fix utf-8 encoded output for cmd log
Micket Mar 20, 2024
aa4b417
Use normal strings instead of f-strings
Micket Mar 20, 2024
e3e582c
Move save_cmd to output directory
Micket Mar 29, 2024
30d300c
Remove double qouting in save_cmd, add missing newline
Micket Apr 7, 2024
4fd99dc
Exclude bash functions, add shebang, add norc
Micket Apr 7, 2024
d6eda62
Fix missing parenthesis
Micket Apr 7, 2024
66806e1
Move chmod until after file exists
Micket Apr 7, 2024
ccd95e0
Add missing linebreak after shebang
Micket Apr 7, 2024
5420fa2
Split cmd.sh into env.sh and rework bash shell to pick up environment…
Micket Apr 7, 2024
9777222
Fix missing f-string
Micket Apr 7, 2024
3c20328
Add helpful comment to cmd.sh script
Micket Apr 7, 2024
e6ccf9e
Move PS1 and history to env file (simplifies and fixes escaping)
Micket Apr 11, 2024
5ae9be7
Changed trace output to mention directory
Micket Apr 14, 2024
37d994b
Merge branch '5.0.x' into cmdlog
Micket Apr 20, 2024
668d044
Fix tests for new run command output dir
Micket Apr 21, 2024
4ddad9b
minor tweaks to dumping of env.sh + run.sh helper scripts in run_shel…
boegel May 30, 2024
8f4b323
Merge pull request #3 from boegel/cmdlog
Micket May 30, 2024
3338c61
fix handling of specified command environment in create_cmd_scripts +…
boegel May 30, 2024
a2b9e06
fix unsetting of current environment in env.sh script produced by run…
boegel May 31, 2024
d906c88
Merge pull request #4 from boegel/cmdlog
Micket Jun 1, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 37 additions & 9 deletions easybuild/tools/run.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
import locale
import os
import re
import shlex
import shutil
import string
import subprocess
Expand Down Expand Up @@ -196,6 +197,34 @@ def fileprefix_from_cmd(cmd, allowed_chars=False):
return ''.join([c for c in cmd if c in allowed_chars])


def save_cmd(cmd_str, work_dir, env, tmpdir):
# Save environment variables in it's own environment file
full_env = os.environ.copy()
if env is not None:
full_env.update(env)
env_fp = os.path.join(tmpdir, 'env.sh')
with open(env_fp, 'w') as fid:
# excludes bash functions (environment variables ending with %)
fid.write('\n'.join(f'export {key}={shlex.quote(value)}' for key, value in full_env.items()
if not key.endswith('%')))
fid.write('\n\nPS1="eb-shell> "')
fid.write(f'\nhistory -s {shlex.quote(cmd_str)}')

# Make script that sets up bash shell with given environments set.
cmd_fp = os.path.join(tmpdir, 'cmd.sh')
with open(cmd_fp, 'w') as fid:
fid.write('#!/usr/bin/env bash\n')
fid.write('# Run this script to replicate the environment that EB used to run the shell command\n')
fid.write('\n'.join([
f'\ncd "{work_dir}"',
'EB_SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )',
f'echo Shell for the command: {shlex.quote(cmd_str)}',
'echo Use command history, exit to stop',
'bash --rcfile $EB_SCRIPT_DIR/env.sh',
]))
os.chmod(cmd_fp, 0o775)


def _answer_question(stdout, proc, qa_patterns, qa_wait_patterns):
"""
Private helper function to try and answer questions raised in interactive shell commands.
Expand Down Expand Up @@ -335,6 +364,8 @@ def to_cmd_str(cmd):
os.makedirs(toptmpdir, exist_ok=True)
cmd_name = fileprefix_from_cmd(os.path.basename(cmd_str.split(' ')[0]))
tmpdir = tempfile.mkdtemp(dir=toptmpdir, prefix=f'{cmd_name}-')
_log.info(f'run_shell_cmd: command environment of "{cmd_str}" will be saved to {tmpdir}')
save_cmd(cmd_str, work_dir, env, tmpdir)
cmd_out_fp = os.path.join(tmpdir, 'out.txt')
_log.info(f'run_shell_cmd: Output of "{cmd_str}" will be logged to {cmd_out_fp}')
if split_stderr:
Expand All @@ -343,7 +374,7 @@ def to_cmd_str(cmd):
else:
cmd_err_fp = None
else:
cmd_out_fp, cmd_err_fp = None, None
tmpdir, cmd_out_fp, cmd_err_fp = None, None, None

interactive = bool(qa_patterns)
interactive_msg = 'interactive ' if interactive else ''
Expand All @@ -361,7 +392,7 @@ def to_cmd_str(cmd):

start_time = datetime.now()
if not hidden:
_cmd_trace_msg(cmd_str, start_time, work_dir, stdin, cmd_out_fp, cmd_err_fp, thread_id, interactive=interactive)
_cmd_trace_msg(cmd_str, start_time, work_dir, stdin, tmpdir, thread_id, interactive=interactive)

if stream_output:
print_msg(f"(streaming) output for command '{cmd_str}':")
Expand Down Expand Up @@ -522,16 +553,15 @@ def to_cmd_str(cmd):
return res


def _cmd_trace_msg(cmd, start_time, work_dir, stdin, cmd_out_fp, cmd_err_fp, thread_id, interactive=False):
def _cmd_trace_msg(cmd, start_time, work_dir, stdin, tmpdir, thread_id, interactive=False):
"""
Helper function to construct and print trace message for command being run

:param cmd: command being run
:param start_time: datetime object indicating when command was started
:param work_dir: path of working directory in which command is run
:param stdin: stdin input value for command
:param cmd_out_fp: path to output file for command
:param cmd_err_fp: path to errors/warnings output file for command
:param tmpdir: path to temporary output directory for command
:param thread_id: thread ID (None when not running shell command asynchronously)
:param interactive: boolean indicating whether it is an interactive command, or not
"""
Expand All @@ -551,10 +581,8 @@ def _cmd_trace_msg(cmd, start_time, work_dir, stdin, cmd_out_fp, cmd_err_fp, thr
]
if stdin:
lines.append(f"\t[input: {stdin}]")
if cmd_out_fp:
lines.append(f"\t[output saved to {cmd_out_fp}]")
if cmd_err_fp:
lines.append(f"\t[errors/warnings saved to {cmd_err_fp}]")
if tmpdir:
lines.append(f"\t[output and state saved to {tmpdir}]")

trace_msg('\n'.join(lines))

Expand Down
6 changes: 3 additions & 3 deletions test/framework/run.py
Original file line number Diff line number Diff line change
Expand Up @@ -676,7 +676,7 @@ def test_run_shell_cmd_trace(self):
r"\techo hello",
r"\t\[started at: .*\]",
r"\t\[working dir: .*\]",
r"\t\[output saved to .*\]",
r"\t\[output and state saved to .*\]",
r" >> command completed: exit 0, ran in .*",
]

Expand Down Expand Up @@ -736,7 +736,7 @@ def test_run_shell_cmd_trace_stdin(self):
r"\techo hello",
r"\t\[started at: [0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9] [0-9][0-9]:[0-9][0-9]:[0-9][0-9]\]",
r"\t\[working dir: .*\]",
r"\t\[output saved to .*\]",
r"\t\[output and state saved to .*\]",
r" >> command completed: exit 0, ran in .*",
]

Expand Down Expand Up @@ -1092,7 +1092,7 @@ def test_run_shell_cmd_qa_trace(self):
pattern += r"\techo \'n: \'; read n; seq 1 \$n\n"
pattern += r"\t\[started at: .*\]\n"
pattern += r"\t\[working dir: .*\]\n"
pattern += r"\t\[output saved to .*\]\n"
pattern += r"\t\[output and state saved to .*\]\n"
pattern += r' >> command completed: exit 0, ran in .*'
self.assertTrue(re.search(pattern, stdout), "Pattern '%s' found in: %s" % (pattern, stdout))

Expand Down
2 changes: 1 addition & 1 deletion test/framework/toy_build.py
Original file line number Diff line number Diff line change
Expand Up @@ -2985,7 +2985,7 @@ def test_toy_build_trace(self):
r"\tgcc toy.c -o toy\n"
r"\t\[started at: .*\]",
r"\t\[working dir: .*\]",
r"\t\[output saved to .*\]",
r"\t\[output and state saved to .*\]",
r'',
]),
r" >> command completed: exit 0, ran in .*",
Expand Down