Skip to content

Commit 00eb94f

Browse files
authored
Merge pull request #5045 from Flamefire/silent-module-cmd
Add `--debug-module-cmds` option
2 parents 7e13b6b + 8d9a1de commit 00eb94f

7 files changed

Lines changed: 56 additions & 20 deletions

File tree

easybuild/framework/easyblock.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1927,7 +1927,7 @@ def clean_up_fake_module(self, fake_mod_data):
19271927
# self.short_mod_name might not be set (e.g. during unit tests)
19281928
if fake_mod_path and self.short_mod_name is not None:
19291929
try:
1930-
self.modules_tool.unload([self.short_mod_name], log_changes=False)
1930+
self.modules_tool.unload([self.short_mod_name], hide_output=True)
19311931
self.modules_tool.remove_module_path(os.path.join(fake_mod_path, self.mod_subdir))
19321932
remove_dir(os.path.dirname(fake_mod_path))
19331933
except OSError as err:

easybuild/tools/config.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -312,6 +312,7 @@ def mk_full_default_path(name, prefix=DEFAULT_PREFIX):
312312
'cuda_sanity_check_strict',
313313
'debug',
314314
'debug_lmod',
315+
'debug_module_cmds',
315316
'dump_autopep8',
316317
'dump_env_script',
317318
'enforce_checksums',

easybuild/tools/modules.py

Lines changed: 26 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1130,12 +1130,19 @@ def load(self, modules, mod_paths=None, purge=False, init_env=None, allow_reload
11301130
for mod in modules:
11311131
self.run_module('load', mod)
11321132

1133-
def unload(self, modules, log_changes=True):
1133+
def unload(self, modules, log_changes=None, *, hide_output=None):
11341134
"""
11351135
Unload all requested modules.
11361136
"""
1137+
if log_changes is not None:
1138+
if hide_output is not None:
1139+
raise EasyBuildError("Cannot specify both log_changes and hide_output")
1140+
self.log.deprecated("Parameter 'log_changes' is replaced by 'hide_output'", '6.0')
1141+
hide_output = not log_changes
1142+
elif hide_output is None:
1143+
hide_output = False # TODO: make this the default in 6.0
11371144
for mod in modules:
1138-
self.run_module('unload', mod, log_changes=log_changes)
1145+
self.run_module('unload', mod, hide_output=hide_output)
11391146

11401147
def purge(self):
11411148
"""
@@ -1259,13 +1266,23 @@ def run_module(self, *args, **kwargs):
12591266
self.log.debug("Changing %s from '%s' to '%s' in environment for module command",
12601267
key, old_value, new_value)
12611268

1262-
log_changes = kwargs.get('log_changes', True)
1269+
debug_module_cmds = build_option('debug_module_cmds')
1270+
log_changes = kwargs.get('log_changes')
1271+
hide_output = kwargs.get('hide_output')
1272+
1273+
if log_changes is not None:
1274+
if hide_output is not None:
1275+
raise EasyBuildError("Cannot specify both log_changes and hide_output")
1276+
self.log.deprecated("Parameter 'log_changes' is replaced by 'hide_output'", '6.0')
1277+
hide_output = not log_changes
1278+
1279+
log_output = debug_module_cmds and not hide_output
12631280
cmd_list = self.compose_cmd_list(args)
12641281
cmd = ' '.join(cmd_list)
12651282
# note: module commands are always run in dry mode, and are kept hidden in trace and dry run output
12661283
res = run_shell_cmd(cmd_list, env=environ, fail_on_error=False, use_bash=False, split_stderr=True,
1267-
hidden=True, in_dry_run=True, output_file=False,
1268-
log_output_on_success=log_changes)
1284+
hidden=True, in_dry_run=True, output_file=debug_module_cmds,
1285+
log_output_on_success=log_output)
12691286

12701287
# stdout will contain python code (to change environment etc)
12711288
# stderr will contain text (just like the normal module command)
@@ -1312,7 +1329,7 @@ def run_module(self, *args, **kwargs):
13121329

13131330
if new_ld_val != curr_ld_val:
13141331
self.log.debug("Correcting paths in $%s from %s to %s" % (key, curr_ld_val, new_ld_val))
1315-
self.set_path_env_var(key, new_ld_val)
1332+
self.set_path_env_var(key, new_ld_val, log_changes=log_output)
13161333

13171334
# Process stderr
13181335
result = []
@@ -1695,9 +1712,9 @@ class EnvironmentModulesTcl(EnvironmentModulesC):
16951712
DEPR_VERSION = '9999.9'
16961713
VERSION_REGEXP = r'^Modules\s+Release\s+Tcl\s+(?P<version>\d\S*)\s'
16971714

1698-
def set_path_env_var(self, key, paths):
1715+
def set_path_env_var(self, key, paths, log_changes=True):
16991716
"""Set environment variable with given name to the given list of paths."""
1700-
super().set_path_env_var(key, paths)
1717+
super().set_path_env_var(key, paths, log_changes)
17011718
# for Tcl Environment Modules, we need to make sure the _modshare env var is kept in sync
17021719
setvar('%s_modshare' % key, ':1:'.join(paths), verbose=False)
17031720

@@ -2263,7 +2280,7 @@ def avail_modules_tools():
22632280
return class_dict
22642281

22652282

2266-
def modules_tool(mod_paths=None, testing=False):
2283+
def modules_tool(mod_paths=None, testing=False) -> ModulesTool:
22672284
"""
22682285
Return interface to modules tool (EnvironmentModules, Lmod, ...)
22692286
"""

easybuild/tools/options.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -438,6 +438,7 @@ def override_options(self):
438438
"more compute capabilities than defined in --cuda-compute-capabilities.",
439439
None, 'store_true', False),
440440
'debug-lmod': ("Run Lmod modules tool commands in debug module", None, 'store_true', False),
441+
'debug-module-cmds': ("Show additional information of module commands", None, 'store_true', False),
441442
'default-opt-level': ("Specify default optimisation level", 'choice', 'store', DEFAULT_OPT_LEVEL,
442443
Compiler.COMPILER_OPT_OPTIONS),
443444
'deprecated': ("Run pretending to be (future) version, to test removal of deprecated code.",

test/framework/modules.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1070,13 +1070,13 @@ def test_modules_tool_stateless(self):
10701070

10711071
modtxt = read_file(os.path.join(self.test_prefix, 'Core', 'GCC', '6.4.0-2.28'))
10721072
modpath_extension = os.path.join(self.test_prefix, 'Compiler', 'GCC', '6.4.0-2.28')
1073-
modtxt = re.sub('module use .*', 'module use %s' % modpath_extension, modtxt, re.M)
1073+
modtxt = re.sub('module use .*', 'module use %s' % modpath_extension, modtxt, flags=re.M)
10741074
write_file(os.path.join(self.test_prefix, 'Core', 'GCC', '6.4.0-2.28'), modtxt)
10751075

10761076
modtxt = read_file(os.path.join(self.test_prefix, 'Compiler', 'GCC', '6.4.0-2.28', 'OpenMPI', '2.1.2'))
10771077
modpath_extension = os.path.join(self.test_prefix, 'MPI', 'GCC', '6.4.0-2.28', 'OpenMPI', '2.1.2')
10781078
mkdir(modpath_extension, parents=True)
1079-
modtxt = re.sub('module use .*', 'module use %s' % modpath_extension, modtxt, re.M)
1079+
modtxt = re.sub('module use .*', 'module use %s' % modpath_extension, modtxt, flags=re.M)
10801080
write_file(os.path.join(self.test_prefix, 'Compiler', 'GCC', '6.4.0-2.28', 'OpenMPI', '2.1.2'), modtxt)
10811081

10821082
# force reset of any singletons by reinitiating config

test/framework/options.py

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3228,7 +3228,7 @@ def test_http_header_fields_urlpat(self):
32283228
mentionhdr = 'Custom HTTP header field set: %s'
32293229
mentionfile = 'File included in parse_http_header_fields_urlpat: %s'
32303230

3231-
def run_and_assert(args, _msg, words_expected=None, words_unexpected=None):
3231+
def run_and_assert(args, words_expected=None, words_unexpected=None):
32323232
stdout, _stderr = self._run_mock_eb(args, do_build=True, raise_error=True, testing=False)
32333233
if words_expected is not None:
32343234
self.assert_multi_regex(words_expected, stdout)
@@ -3243,7 +3243,7 @@ def run_and_assert(args, _msg, words_expected=None, words_unexpected=None):
32433243
])
32443244
# expect to find everything passed on cmdline
32453245
expected = [mentionhdr % (testdohdr), testdoval, testdonthdr, testdontval]
3246-
run_and_assert(args, "case A", expected)
3246+
run_and_assert(args, expected)
32473247

32483248
# all subsequent tests share this argument list
32493249
args = common_args
@@ -3259,7 +3259,7 @@ def run_and_assert(args, _msg, words_expected=None, words_unexpected=None):
32593259
# expect to find only the header key (not its value) and only for the appropriate url
32603260
expected = [mentionhdr % testdohdr, mentionfile % testcmdfile]
32613261
not_expected = [testdoval, testdonthdr, testdontval]
3262-
run_and_assert(args, "case B", expected, not_expected)
3262+
run_and_assert(args, expected, not_expected)
32633263

32643264
# C: recursion one: header value is another file
32653265
txt = '\n'.join([
@@ -3274,7 +3274,7 @@ def run_and_assert(args, _msg, words_expected=None, words_unexpected=None):
32743274
expected = [mentionhdr % (testdohdr), mentionfile % (testcmdfile),
32753275
mentionfile % (testincfile), mentionfile % (testexcfile)]
32763276
not_expected = [testdoval, testdonthdr, testdontval]
3277-
run_and_assert(args, "case C", expected, not_expected)
3277+
run_and_assert(args, expected, not_expected)
32783278

32793279
# D: recursion two: header field+value is another file,
32803280
write_file(testcmdfile, '\n'.join([
@@ -3288,7 +3288,7 @@ def run_and_assert(args, _msg, words_expected=None, words_unexpected=None):
32883288
expected = [mentionhdr % (testdohdr), mentionfile % (testcmdfile),
32893289
mentionfile % (testinchdrfile), mentionfile % (testexchdrfile)]
32903290
not_expected = [testdoval, testdonthdr, testdontval]
3291-
run_and_assert(args, "case D", expected, not_expected)
3291+
run_and_assert(args, expected, not_expected)
32923292

32933293
# E: recursion three: url pattern + header field + value in another file
32943294
write_file(testcmdfile, '%s\n' % (testurlpatfile))
@@ -3301,7 +3301,7 @@ def run_and_assert(args, _msg, words_expected=None, words_unexpected=None):
33013301
# expect to find only the header key (but not the literal filename) and only for the appropriate url
33023302
expected = [mentionhdr % (testdohdr), mentionfile % (testcmdfile), mentionfile % (testurlpatfile)]
33033303
not_expected = [testdoval, testdonthdr, testdontval]
3304-
run_and_assert(args, "case E", expected, not_expected)
3304+
run_and_assert(args, expected, not_expected)
33053305

33063306
# cleanup downloads
33073307
shutil.rmtree(tmpdir)
@@ -5682,6 +5682,23 @@ def test_debug_lmod(self):
56825682
else:
56835683
print("Skipping test_debug_lmod, requires Lmod as modules tool")
56845684

5685+
def test_debug_module_cmds(self):
5686+
"""Test use of --debug-module-cmds."""
5687+
patterns = [
5688+
"Output of ",
5689+
r"os\.env.*EBROOTGCC.*=",
5690+
r"os\.env.*PATH.*=",
5691+
]
5692+
for enable in (True, False):
5693+
with self.subTest(debug_module_cmds=enable):
5694+
init_config(build_options={'debug_module_cmds': enable})
5695+
with self.log_to_testlogfile():
5696+
self.modtool.load(['GCC/4.6.3'])
5697+
logtxt = read_file(self.logfile)
5698+
self.assertRegex(logtxt, "Running .*\n.*load GCC/4.6.3")
5699+
self.assert_multi_regex(patterns, logtxt, assert_true=enable)
5700+
self.modtool.purge()
5701+
56855702
def test_use_color(self):
56865703
"""Test use_color function."""
56875704
self.assertTrue(use_color('always'))

test/framework/utilities.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@
5353
from easybuild.tools.configobj import ConfigObj
5454
from easybuild.tools.environment import modify_env
5555
from easybuild.tools.filetools import copy_dir, mkdir, read_file, which
56-
from easybuild.tools.modules import curr_module_paths, modules_tool, reset_module_caches
56+
from easybuild.tools.modules import curr_module_paths, modules_tool, ModulesTool, reset_module_caches
5757
from easybuild.tools.options import CONFIG_ENV_VAR_PREFIX, EasyBuildOptions, set_tmpdir
5858

5959

@@ -211,7 +211,7 @@ def setUp(self):
211211
self.env_path = os.environ.get('PATH')
212212
self.env_pythonpath = os.environ.get('PYTHONPATH')
213213

214-
self.modtool = modules_tool()
214+
self.modtool: ModulesTool = modules_tool()
215215
self.reset_modulepath([os.path.join(testdir, 'modules')])
216216
reset_module_caches()
217217

0 commit comments

Comments
 (0)