Skip to content

Commit 7beeb98

Browse files
authored
Merge pull request #4223 from fgonzalez-HPCNow/modunloadmsg
add suport for 'modunloadmsg' easyconfig parameter
2 parents 9b480c8 + de8f3fc commit 7beeb98

File tree

5 files changed

+71
-0
lines changed

5 files changed

+71
-0
lines changed

easybuild/framework/easyblock.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1412,6 +1412,13 @@ def make_module_extra(self, altroot=None, altversion=None):
14121412
modloadmsg += '\n'
14131413
lines.append(self.module_generator.msg_on_load(modloadmsg))
14141414

1415+
modunloadmsg = self.cfg['modunloadmsg']
1416+
if modunloadmsg:
1417+
# add trailing newline to prevent that shell prompt is 'glued' to module unload/purge message
1418+
if not modunloadmsg.endswith('\n'):
1419+
modunloadmsg += '\n'
1420+
lines.append(self.module_generator.msg_on_unload(modunloadmsg))
1421+
14151422
for (key, value) in self.cfg['modaliases'].items():
14161423
lines.append(self.module_generator.set_alias(key, value))
14171424

easybuild/framework/easyconfig/default.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,7 @@
195195
'modextrapaths': [{}, "Extra paths to be prepended in module file", MODULES],
196196
'modextravars': [{}, "Extra environment variables to be added to module file", MODULES],
197197
'modloadmsg': [{}, "Message that should be printed when generated module is loaded", MODULES],
198+
'modunloadmsg': [{}, "Message that should be printed when generated module is unloaded", MODULES],
198199
'modluafooter': ["", "Footer to include in generated module file (Lua syntax)", MODULES],
199200
'modaltsoftname': [None, "Module name to use (rather than using software name", MODULES],
200201
'modtclfooter': ["", "Footer to include in generated module file (Tcl syntax)", MODULES],

easybuild/tools/module_generator.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -502,6 +502,12 @@ def msg_on_load(self, msg):
502502
"""
503503
raise NotImplementedError
504504

505+
def msg_on_unload(self, msg):
506+
"""
507+
Add a message that should be printed when unloading the module.
508+
"""
509+
raise NotImplementedError
510+
505511
def set_alias(self, key, value):
506512
"""
507513
Generate set-alias statement in modulefile for the given key/value pair.
@@ -951,6 +957,15 @@ def msg_on_load(self, msg):
951957
print_cmd = "puts stderr %s" % quote_str(msg, tcl=True)
952958
return '\n'.join(['', self.conditional_statement("module-info mode load", print_cmd, indent=False)])
953959

960+
def msg_on_unload(self, msg):
961+
"""
962+
Add a message that should be printed when unloading the module.
963+
"""
964+
# escape any (non-escaped) characters with special meaning by prefixing them with a backslash
965+
msg = re.sub(r'((?<!\\)[%s])' % ''.join(self.CHARS_TO_ESCAPE), r'\\\1', msg)
966+
print_cmd = "puts stderr %s" % quote_str(msg, tcl=True)
967+
return '\n'.join(['', self.conditional_statement("module-info mode unload", print_cmd, indent=False)])
968+
954969
def update_paths(self, key, paths, prepend=True, allow_abs=False, expand_relpaths=True):
955970
"""
956971
Generate prepend-path or append-path statements for the given list of paths.
@@ -1384,6 +1399,14 @@ def msg_on_load(self, msg):
13841399
stmt = 'io.stderr:write(%s%s%s)' % (self.START_STR, self.check_str(msg), self.END_STR)
13851400
return '\n' + self.conditional_statement('mode() == "load"', stmt, indent=False)
13861401

1402+
def msg_on_unload(self, msg):
1403+
"""
1404+
Add a message that should be printed when loading the module.
1405+
"""
1406+
# take into account possible newlines in messages by using [==...==] (requires Lmod 5.8)
1407+
stmt = 'io.stderr:write(%s%s%s)' % (self.START_STR, self.check_str(msg), self.END_STR)
1408+
return '\n' + self.conditional_statement('mode() == "unload"', stmt, indent=False)
1409+
13871410
def modulerc(self, module_version=None, filepath=None, modulerc_txt=None):
13881411
"""
13891412
Generate contents of .modulerc(.lua) file, in Lua syntax (but only if Lmod is recent enough, i.e. >= 7.7.38)

test/framework/easyconfig.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1100,6 +1100,13 @@ def test_templating_constants(self):
11001100
'Perl: %%(perlver)s, %%(perlmajver)s, %%(perlminver)s, %%(perlshortver)s',
11011101
'R: %%(rver)s, %%(rmajver)s, %%(rminver)s, %%(rshortver)s',
11021102
]),
1103+
'modunloadmsg = "%s"' % '; '.join([
1104+
'CUDA: %%(cudaver)s, %%(cudamajver)s, %%(cudaminver)s, %%(cudashortver)s',
1105+
'Java: %%(javaver)s, %%(javamajver)s, %%(javaminver)s, %%(javashortver)s',
1106+
'Python: %%(pyver)s, %%(pymajver)s, %%(pyminver)s, %%(pyshortver)s',
1107+
'Perl: %%(perlver)s, %%(perlmajver)s, %%(perlminver)s, %%(perlshortver)s',
1108+
'R: %%(rver)s, %%(rmajver)s, %%(rminver)s, %%(rshortver)s',
1109+
]),
11031110
'modextrapaths = {"PI_MOD_NAME": "%%(module_name)s"}',
11041111
'license_file = HOME + "/licenses/PI/license.txt"',
11051112
"github_account = 'easybuilders'",
@@ -1139,6 +1146,7 @@ def test_templating_constants(self):
11391146
"Perl: 5.22.0, 5, 22, 5.22; "
11401147
"R: 3.2.3, 3, 2, 3.2")
11411148
self.assertEqual(ec['modloadmsg'], expected)
1149+
self.assertEqual(ec['modunloadmsg'], expected)
11421150
self.assertEqual(ec['modextrapaths'], {'PI_MOD_NAME': 'PI/3.04-Python-2.7.10'})
11431151
self.assertEqual(ec['license_file'], os.path.join(os.environ['HOME'], 'licenses', 'PI', 'license.txt'))
11441152

@@ -1225,6 +1233,7 @@ def test_java_wrapper_templating(self):
12251233
'toolchain = {"name":"GCC", "version": "4.6.3"}',
12261234
'dependencies = [("Java", "11", "", SYSTEM)]',
12271235
'modloadmsg = "Java: %(javaver)s, %(javamajver)s, %(javashortver)s"',
1236+
'modunloadmsg = "Java: %(javaver)s, %(javamajver)s, %(javashortver)s"',
12281237
])
12291238
self.prep()
12301239
eb = EasyConfig(self.eb_file)
@@ -1236,6 +1245,7 @@ def test_java_wrapper_templating(self):
12361245
self.assertNotIn('javaminver', eb.template_values)
12371246

12381247
self.assertEqual(eb['modloadmsg'], "Java: 11, 11, 11")
1248+
self.assertEqual(eb['modunloadmsg'], "Java: 11, 11, 11")
12391249

12401250
def test_python_whl_templating(self):
12411251
"""test templating for Python wheels"""

test/framework/module_generator.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1097,6 +1097,36 @@ def test_load_msg(self):
10971097
])
10981098
self.assertEqual(lua_load_msg, self.modgen.msg_on_load('test $test \\$test\ntest $foo \\$bar'))
10991099

1100+
def test_unload_msg(self):
1101+
"""Test including an unload message in the module file."""
1102+
if self.MODULE_GENERATOR_CLASS == ModuleGeneratorTcl:
1103+
expected = "\nif { [ module-info mode unload ] } {\nputs stderr \"test\"\n}\n"
1104+
self.assertEqual(expected, self.modgen.msg_on_unload('test'))
1105+
1106+
tcl_unload_msg = '\n'.join([
1107+
'',
1108+
"if { [ module-info mode unload ] } {",
1109+
"puts stderr \"test \\$test \\$test",
1110+
"test \\$foo \\$bar\"",
1111+
"}",
1112+
'',
1113+
])
1114+
self.assertEqual(tcl_unload_msg, self.modgen.msg_on_unload('test $test \\$test\ntest $foo \\$bar'))
1115+
1116+
else:
1117+
expected = '\nif mode() == "unload" then\nio.stderr:write([==[test]==])\nend\n'
1118+
self.assertEqual(expected, self.modgen.msg_on_unload('test'))
1119+
1120+
lua_unload_msg = '\n'.join([
1121+
'',
1122+
'if mode() == "unload" then',
1123+
'io.stderr:write([==[test $test \\$test',
1124+
'test $foo \\$bar]==])',
1125+
'end',
1126+
'',
1127+
])
1128+
self.assertEqual(lua_unload_msg, self.modgen.msg_on_unload('test $test \\$test\ntest $foo \\$bar'))
1129+
11001130
def test_module_naming_scheme(self):
11011131
"""Test using default module naming scheme."""
11021132
all_stops = [x[0] for x in EasyBlock.get_steps()]

0 commit comments

Comments
 (0)