From cd408ba3d3d6e045ff4dfeaff43dacfd4cf6201c Mon Sep 17 00:00:00 2001 From: Vasileios Karakasis Date: Sun, 6 May 2018 20:59:09 +0200 Subject: [PATCH 1/2] Add TMod4 support --- docs/configure.rst | 8 ++++++-- reframe/core/modules.py | 42 +++++++++++++++++++++++++++++++++++++++ unittests/test_modules.py | 16 +++++++++++++++ 3 files changed, 64 insertions(+), 2 deletions(-) diff --git a/docs/configure.rst b/docs/configure.rst index 91514c9de5..a1b61a1ed0 100644 --- a/docs/configure.rst +++ b/docs/configure.rst @@ -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 `__ 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 `__. + - ``tmod4``: The version 4 of the Tcl implementation of the `environment modules `__. + - ``lmod``: The Lua implementation of the `environment modules `__. * ``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`). diff --git a/reframe/core/modules.py b/reframe/core/modules.py index ff55270938..388bf54ce4 100644 --- a/reframe/core/modules.py +++ b/reframe/core/modules.py @@ -451,6 +451,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: %s' % e) from e + except SpawnedProcessError as e: + raise ConfigError( + 'could not get the Python bindings for Tmod4: ' % e) 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).""" @@ -570,6 +610,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: diff --git a/unittests/test_modules.py b/unittests/test_modules.py index 7cd2608bee..e0587d19eb 100644 --- a/unittests/test_modules.py +++ b/unittests/test_modules.py @@ -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: From 344ad2ba80682cc92000970025e2ccac79df75b1 Mon Sep 17 00:00:00 2001 From: Vasileios Karakasis Date: Mon, 7 May 2018 11:10:50 +0200 Subject: [PATCH 2/2] Fix unit tests --- reframe/core/modules.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/reframe/core/modules.py b/reframe/core/modules.py index 388bf54ce4..db6ed098b4 100644 --- a/reframe/core/modules.py +++ b/reframe/core/modules.py @@ -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: @@ -460,10 +461,10 @@ def __init__(self): completed = os_ext.run_command(self._command + ' -V', check=True) except OSError as e: raise ConfigError( - 'could not find a sane Tmod4 installation: %s' % e) from e + 'could not find a sane Tmod4 installation') from e except SpawnedProcessError as e: raise ConfigError( - 'could not get the Python bindings for Tmod4: ' % e) from e + 'could not get the Python bindings for Tmod4') from e version_match = re.match('^Modules Release (\S+)\s+', completed.stderr) if not version_match: