diff --git a/easybuild/tools/modules.py b/easybuild/tools/modules.py index 43a2e2ff87..3700a1a8ab 100644 --- a/easybuild/tools/modules.py +++ b/easybuild/tools/modules.py @@ -122,7 +122,8 @@ class ModulesTool(object): TERSE_OPTION = (0, '--terse') # module command to use COMMAND = None - # environment variable to determine the module command (instead of COMMAND) + # environment variable to determine path to module command; + # used as fallback in case command is not available in $PATH COMMAND_ENVIRONMENT = None # run module command explicitly using this shell COMMAND_SHELL = None @@ -156,10 +157,19 @@ def __init__(self, mod_paths=None, testing=False): # actual module command (i.e., not the 'module' wrapper function, but the binary) self.cmd = self.COMMAND - if self.COMMAND_ENVIRONMENT is not None and self.COMMAND_ENVIRONMENT in os.environ: - self.log.debug('Set command via environment variable %s' % self.COMMAND_ENVIRONMENT) - self.cmd = os.environ[self.COMMAND_ENVIRONMENT] + env_cmd_path = os.environ.get(self.COMMAND_ENVIRONMENT) + # only use command path in environment variable if command in not available in $PATH + if which(self.cmd) is None and env_cmd_path is not None: + self.log.debug('Set command via environment variable %s: %s', self.COMMAND_ENVIRONMENT, self.cmd) + self.cmd = env_cmd_path + + # check whether paths obtained via $PATH and $LMOD_CMD are different + elif which(self.cmd) != env_cmd_path: + self.log.debug("Different paths found for module command '%s' via which/$PATH and $%s: %s vs %s", + self.COMMAND, self.COMMAND_ENVIRONMENT, self.cmd, env_cmd_path) + + # make sure the module command was found if self.cmd is None: raise EasyBuildError("No command set.") else: diff --git a/test/framework/modulestool.py b/test/framework/modulestool.py index f6ca56b8a8..6130e33564 100644 --- a/test/framework/modulestool.py +++ b/test/framework/modulestool.py @@ -29,6 +29,7 @@ """ import os import re +import stat import tempfile from vsc.utils import fancylogger @@ -41,7 +42,7 @@ from easybuild.tools import config, modules from easybuild.tools.build_log import EasyBuildError from easybuild.tools.config import build_option -from easybuild.tools.filetools import which +from easybuild.tools.filetools import which, write_file from easybuild.tools.modules import modules_tool, Lmod from test.framework.utilities import init_config @@ -95,7 +96,8 @@ def test_environment_command(self): # should never get here self.assertTrue(False, 'BrokenMockModulesTool should fail') except EasyBuildError, err: - self.assertTrue('command is not available' in str(err)) + err_msg = "command is not available" + self.assertTrue(err_msg in str(err), "'%s' found in: %s" % (err_msg, err)) os.environ[BrokenMockModulesTool.COMMAND_ENVIRONMENT] = MockModulesTool.COMMAND os.environ['module'] = "() { /bin/echo $*\n}" @@ -160,6 +162,9 @@ def test_lmod_specific(self): } init_config(build_options=build_options) + lmod = Lmod(testing=True) + self.assertEqual(lmod.cmd, lmod_abspath) + # drop any location where 'lmod' or 'spider' can be found from $PATH paths = os.environ.get('PATH', '').split(os.pathsep) new_paths = [] @@ -173,8 +178,18 @@ def test_lmod_specific(self): # make sure $MODULEPATH contains path that provides some modules os.environ['MODULEPATH'] = os.path.abspath(os.path.join(os.path.dirname(__file__), 'modules')) - # initialize Lmod modules tool, pass full path to 'lmod' via $LMOD_CMD + # initialize Lmod modules tool, pass (fake) full path to 'lmod' via $LMOD_CMD + fake_path = os.path.join(self.test_installpath, 'lmod') + write_file(fake_path, '#!/bin/bash\necho "Modules based on Lua: Version %s " >&2' % Lmod.REQ_VERSION) + os.chmod(fake_path, stat.S_IRUSR|stat.S_IXUSR) + os.environ['LMOD_CMD'] = fake_path + init_config(build_options=build_options) + lmod = Lmod(testing=True) + self.assertEqual(lmod.cmd, fake_path) + + # use correct full path for 'lmod' via $LMOD_CMD os.environ['LMOD_CMD'] = lmod_abspath + init_config(build_options=build_options) lmod = Lmod(testing=True) # obtain list of availabe modules, should be non-empty