Skip to content
Merged
37 changes: 34 additions & 3 deletions easybuild/tools/modules.py
Original file line number Diff line number Diff line change
Expand Up @@ -547,6 +547,7 @@ def mod_exists_via_show(mod_name):

:param mod_name: module name
"""
self.log.info("Checking whether %s exists based on output of 'module show'", mod_name)
stderr = self.show(mod_name)
res = False
# Parse the output:
Expand All @@ -555,13 +556,38 @@ def mod_exists_via_show(mod_name):
# - Check first non-whitespace line for something that looks like an absolute path terminated by a colon
mod_exists_regex = r'\s*/.+:\s*'
for line in stderr.split('\n'):

self.log.debug("Checking line '%s' to determine whether %s exists...", line, mod_name)
Comment thread
boegel marked this conversation as resolved.

# skip whitespace lines
if OUTPUT_MATCHES['whitespace'].search(line):
self.log.debug("Treating line '%s' as whitespace, so skipping it", line)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

isn't this overly verbose, even for debugging?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It helped a lot with figuring out the problem reported in #3376, so no.

continue

# if any errors occured, conclude that module doesn't exist
if OUTPUT_MATCHES['error'].search(line):
self.log.debug("Line '%s' looks like an error, so concluding that %s doesn't exist",
line, mod_name)
break
if re.match(mod_exists_regex, line):
res = True

# skip warning lines, which may be produced by modules tool but should not be used
# to determine whether a module file exists
if line.startswith('WARNING: '):
Comment thread
boegel marked this conversation as resolved.
self.log.debug("Skipping warning line '%s'", line)
continue

# skip lines that start with 'module-' (like 'module-version'),
# see https://github.com/easybuilders/easybuild-framework/issues/3376
if line.startswith('module-'):
self.log.debug("Skipping line '%s' since it starts with 'module-'", line)
continue

# if line matches pattern that indicates an existing module file, the module file exists
res = bool(re.match(mod_exists_regex, line))
self.log.debug("Result for existence check of %s based on 'module show' output line '%s': %s",
mod_name, line, res)
break

return res

if skip_avail:
Expand All @@ -577,10 +603,15 @@ def mod_exists_via_show(mod_name):

mods_exist = []
for (mod_name, visible) in mod_names:
self.log.info("Checking whether %s exists...", mod_name)
if visible:
mod_exists = mod_name in avail_mod_names
# module name may be partial, so also check via 'module show' as fallback
if not mod_exists and maybe_partial:
if mod_exists:
self.log.info("Module %s exists (found in list of available modules)", mod_name)
elif not mod_exists and maybe_partial:
Comment thread
boegel marked this conversation as resolved.
Outdated
self.log.info("Module %s not found in list of available modules, checking via 'module show'...",
Comment thread
boegel marked this conversation as resolved.
mod_name)
mod_exists = mod_exists_via_show(mod_name)
else:
# hidden modules are not visible in 'avail', need to use 'show' instead
Expand Down
28 changes: 28 additions & 0 deletions test/framework/modules.py
Original file line number Diff line number Diff line change
Expand Up @@ -310,6 +310,34 @@ def test_exist(self):
if self.modtool.__class__ != EnvironmentModulesC:
self.assertEqual(self.modtool.exist(['Java/Alias', 'Java/NonExist']), [True, False])

# set 'module avail' cache entries to empty lists,
# to enforce fallback to 'module show'
import easybuild.tools.modules
for key in easybuild.tools.modules.MODULE_AVAIL_CACHE:
easybuild.tools.modules.MODULE_AVAIL_CACHE[key] = []

# clear 'module show' cache, to keep control below
easybuild.tools.modules.MODULE_SHOW_CACHE.clear()
self.assertEqual(self.modtool.exist(['Java/1.8', 'Java/1.8.0_181']), [True, True])

# mimic more verbose stderr output produced by old Tmod version,
# including a warning produced when multiple .modulerc files are being picked up
# see https://github.com/easybuilders/easybuild-framework/issues/3376
ml_show_java18_stderr = '\n'.join([
"module-version Java/1.8.0_181 1.8",
"WARNING: Duplicate version symbol '1.8' found",
"module-version Java/1.8.0_181 1.8",
"-------------------------------------------------------------------",
"/modulefiles/lang/Java/1.8.0_181:",
"-------------------------------------------------------------------",
])

# overwrite 'module show' cache entries with output that includes extra lines
for key in easybuild.tools.modules.MODULE_SHOW_CACHE:
easybuild.tools.modules.MODULE_SHOW_CACHE[key] = ml_show_java18_stderr

self.assertEqual(self.modtool.exist(['Java/1.8', 'Java/1.8.0_181']), [True, True])

reset_module_caches()

# what if we're in an HMNS setting...
Expand Down