5050from easybuild .base import fancylogger
5151from easybuild .tools .build_log import EasyBuildError , dry_run_msg , print_msg , time_str_since
5252from easybuild .tools .config import ERROR , IGNORE , WARN , build_option
53+ from easybuild .tools .hooks import RUN_SHELL_CMD , load_hooks , run_hook
5354from easybuild .tools .py2vs3 import string_type
5455from easybuild .tools .utilities import trace_msg
5556
@@ -131,7 +132,8 @@ def get_output_from_process(proc, read_size=None, asynchronous=False):
131132
132133@run_cmd_cache
133134def run_cmd (cmd , log_ok = True , log_all = False , simple = False , inp = None , regexp = True , log_output = False , path = None ,
134- force_in_dry_run = False , verbose = True , shell = None , trace = True , stream_output = None , asynchronous = False ):
135+ force_in_dry_run = False , verbose = True , shell = None , trace = True , stream_output = None , asynchronous = False ,
136+ with_hooks = True ):
135137 """
136138 Run specified command (in a subshell)
137139 :param cmd: command to run
@@ -148,6 +150,7 @@ def run_cmd(cmd, log_ok=True, log_all=False, simple=False, inp=None, regexp=True
148150 :param trace: print command being executed as part of trace output
149151 :param stream_output: enable streaming command output to stdout
150152 :param asynchronous: run command asynchronously (returns subprocess.Popen instance if set to True)
153+ :param with_hooks: trigger pre/post run_shell_cmd hooks (if defined)
151154 """
152155 cwd = os .getcwd ()
153156
@@ -233,6 +236,13 @@ def run_cmd(cmd, log_ok=True, log_all=False, simple=False, inp=None, regexp=True
233236 else :
234237 raise EasyBuildError ("Don't know how to prefix with /usr/bin/env for commands of type %s" , type (cmd ))
235238
239+ if with_hooks :
240+ hooks = load_hooks (build_option ('hooks' ))
241+ hook_res = run_hook (RUN_SHELL_CMD , hooks , pre_step_hook = True , args = [cmd ], kwargs = {'work_dir' : os .getcwd ()})
242+ if isinstance (hook_res , string_type ):
243+ cmd , old_cmd = hook_res , cmd
244+ _log .info ("Command to run was changed by pre-%s hook: '%s' (was: '%s')" , RUN_SHELL_CMD , cmd , old_cmd )
245+
236246 _log .info ('running cmd: %s ' % cmd )
237247 try :
238248 proc = subprocess .Popen (cmd , shell = shell , stdout = subprocess .PIPE , stderr = subprocess .STDOUT ,
@@ -248,7 +258,7 @@ def run_cmd(cmd, log_ok=True, log_all=False, simple=False, inp=None, regexp=True
248258 return (proc , cmd , cwd , start_time , cmd_log )
249259 else :
250260 return complete_cmd (proc , cmd , cwd , start_time , cmd_log , log_ok = log_ok , log_all = log_all , simple = simple ,
251- regexp = regexp , stream_output = stream_output , trace = trace )
261+ regexp = regexp , stream_output = stream_output , trace = trace , with_hook = with_hooks )
252262
253263
254264def check_async_cmd (proc , cmd , owd , start_time , cmd_log , fail_on_error = True , output_read_size = 1024 , output = '' ):
@@ -293,7 +303,7 @@ def check_async_cmd(proc, cmd, owd, start_time, cmd_log, fail_on_error=True, out
293303
294304
295305def complete_cmd (proc , cmd , owd , start_time , cmd_log , log_ok = True , log_all = False , simple = False ,
296- regexp = True , stream_output = None , trace = True , output = '' ):
306+ regexp = True , stream_output = None , trace = True , output = '' , with_hook = True ):
297307 """
298308 Complete running of command represented by passed subprocess.Popen instance.
299309
@@ -308,6 +318,7 @@ def complete_cmd(proc, cmd, owd, start_time, cmd_log, log_ok=True, log_all=False
308318 :param regexp: regex used to check the output for errors; if True it will use the default (see parse_log_for_error)
309319 :param stream_output: enable streaming command output to stdout
310320 :param trace: print command being executed as part of trace output
321+ :param with_hook: trigger post run_shell_cmd hooks (if defined)
311322 """
312323 # use small read size when streaming output, to make it stream more fluently
313324 # read size should not be too small though, to avoid too much overhead
@@ -343,6 +354,15 @@ def complete_cmd(proc, cmd, owd, start_time, cmd_log, log_ok=True, log_all=False
343354 sys .stdout .write (output )
344355 stdouterr += output
345356
357+ if with_hook :
358+ hooks = load_hooks (build_option ('hooks' ))
359+ run_hook_kwargs = {
360+ 'exit_code' : ec ,
361+ 'output' : stdouterr ,
362+ 'work_dir' : os .getcwd (),
363+ }
364+ run_hook (RUN_SHELL_CMD , hooks , post_step_hook = True , args = [cmd ], kwargs = run_hook_kwargs )
365+
346366 if trace :
347367 trace_msg ("command completed: exit %s, ran in %s" % (ec , time_str_since (start_time )))
348368
@@ -485,6 +505,17 @@ def check_answers_list(answers):
485505 # Part 2: Run the command and answer questions
486506 # - this needs asynchronous stdout
487507
508+ hooks = load_hooks (build_option ('hooks' ))
509+ run_hook_kwargs = {
510+ 'interactive' : True ,
511+ 'work_dir' : os .getcwd (),
512+ }
513+ hook_res = run_hook (RUN_SHELL_CMD , hooks , pre_step_hook = True , args = [cmd ], kwargs = run_hook_kwargs )
514+ if isinstance (hook_res , string_type ):
515+ cmd , old_cmd = hook_res , cmd
516+ _log .info ("Interactive command to run was changed by pre-%s hook: '%s' (was: '%s')" ,
517+ RUN_SHELL_CMD , cmd , old_cmd )
518+
488519 # # Log command output
489520 if cmd_log :
490521 cmd_log .write ("# output for interactive command: %s\n \n " % cmd )
@@ -599,6 +630,13 @@ def get_proc():
599630 except IOError as err :
600631 _log .debug ("runqanda cmd %s: remaining data read failed: %s" , cmd , err )
601632
633+ run_hook_kwargs .update ({
634+ 'interactive' : True ,
635+ 'exit_code' : ec ,
636+ 'output' : stdout_err ,
637+ })
638+ run_hook (RUN_SHELL_CMD , hooks , post_step_hook = True , args = [cmd ], kwargs = run_hook_kwargs )
639+
602640 if trace :
603641 trace_msg ("interactive command completed: exit %s, ran in %s" % (ec , time_str_since (start_time )))
604642
0 commit comments