Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
8 changes: 6 additions & 2 deletions docs/configure.rst
Original file line number Diff line number Diff line change
Expand Up @@ -94,8 +94,12 @@ The valid attributes of a system are the following:

* ``descr``: A detailed description of the system (default is the system name).
* ``hostnames``: This is a list of hostname patterns that will be used by ReFrame when it tries to `auto-detect <#system-auto-detection>`__ the current system (default ``[]``).
* ``modules_system``: The modules system that should be used for loading environment modules on this system.
The only available modules system backend is currently ``tmod``, which corresponds to the `TCL implementation <http://modules.sourceforge.net/>`__ of the environment modules (default :class:`None`).
* ``modules_system``: The modules system that should be used for loading environment modules on this system (default :class:`None`).
Three types of modules systems are currently supported:

- ``tmod``: The classic Tcl implementation of the `environment modules <https://sourceforge.net/projects/modules/files/Modules/modules-3.2.10/>`__.
- ``tmod4``: The version 4 of the Tcl implementation of the `environment modules <http://modules.sourceforge.net/>`__.
- ``lmod``: The Lua implementation of the `environment modules <https://lmod.readthedocs.io/en/latest/>`__.
* ``prefix``: Default regression prefix for this system (default ``.``).
* ``stagedir``: Default stage directory for this system (default :class:`None`).
* ``outputdir``: Default output directory for this system (default :class:`None`).
Expand Down
45 changes: 44 additions & 1 deletion reframe/core/modules.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@

import reframe.core.fields as fields
import reframe.utility.os_ext as os_ext
from reframe.core.exceptions import ConfigError, EnvironError
from reframe.core.exceptions import (ConfigError, EnvironError,
SpawnedProcessError)


class Module:
Expand Down Expand Up @@ -451,6 +452,46 @@ def emit_unload_instr(self, module):
return 'module unload %s' % module


class TMod4Impl(TModImpl):
"""Module system for TMod 4."""

def __init__(self):
self._command = 'modulecmd python'
try:
completed = os_ext.run_command(self._command + ' -V', check=True)
except OSError as e:
raise ConfigError(
'could not find a sane Tmod4 installation') from e
except SpawnedProcessError as e:
raise ConfigError(
'could not get the Python bindings for Tmod4') from e

version_match = re.match('^Modules Release (\S+)\s+', completed.stderr)
if not version_match:
raise ConfigError('could not retrieve the TMod4 version')

self._version = version_match.group(1)

def name(self):
return 'tmod4'

def _exec_module_command(self, *args, msg=None):
command = ' '.join([self._command, *args])
completed = os_ext.run_command(command, check=True)
namespace = {}
exec(completed.stdout, {}, namespace)
if not namespace['_mlstatus']:
# _mlstatus is set by the TMod4 Python bindings
if msg is None:
msg = 'modules system command failed: '
if isinstance(completed.args, str):
msg += completed.args
else:
msg += ' '.join(completed.args)

raise EnvironError(msg)


class LModImpl(TModImpl):
"""Module system for Lmod (Tcl/Lua)."""

Expand Down Expand Up @@ -570,6 +611,8 @@ def init_modules_system(modules_kind=None):
_modules_system = ModulesSystem(NoModImpl())
elif modules_kind == 'tmod':
_modules_system = ModulesSystem(TModImpl())
elif modules_kind == 'tmod4':
_modules_system = ModulesSystem(TMod4Impl())
elif modules_kind == 'lmod':
_modules_system = ModulesSystem(LModImpl())
else:
Expand Down
16 changes: 16 additions & 0 deletions unittests/test_modules.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,22 @@ def expected_unload_instr(self, module):
return 'module unload %s' % module


class TestTMod4ModulesSystem(_TestModulesSystem):
def setUp(self):
try:
modules.init_modules_system('tmod4')
except ConfigError:
self.skipTest('tmod4 not supported')
else:
super().setUp()

def expected_load_instr(self, module):
return 'module load %s' % module

def expected_unload_instr(self, module):
return 'module unload %s' % module


class TestLModModulesSystem(_TestModulesSystem):
def setUp(self):
try:
Expand Down