Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
d56f4fa
Adding the lowercase module name scheme
victorusu Jul 10, 2017
dc51f55
Merge pull request #3 from victorusu/lowercase-name-scheme
victorusu Jul 10, 2017
54d9722
Merge branch 'master' of https://github.com/easybuilders/easybuild-fr…
victorusu Jan 30, 2019
00d0077
Merge branch 'master' of https://github.com/easybuilders/easybuild-fr…
victorusu Jan 23, 2020
46473d5
Add probe of PREFIX and VERSION variable in external modules
victorusu Jan 23, 2020
9cdf2ed
Fix PR remarks and add support for Lua syntax
victorusu Jan 23, 2020
afe4e11
Improve the design
victorusu Jan 23, 2020
5d87a9a
improve cray support
victorusu Jan 30, 2020
6648542
Fix PR remarks
victorusu Feb 17, 2020
bab80b3
Add Cray specific mapping
victorusu Mar 2, 2020
b3152c7
Address PR remarks
victorusu Mar 2, 2020
e6f3eb7
Address style changes
victorusu Mar 2, 2020
6d3a63e
Quick fix to test external_metadata definition hypothesis
victorusu Mar 2, 2020
1a8cf18
Merge branch 'develop' into cug20
boegel Apr 8, 2020
b80c8d6
Merge pull request #4 from boegel/cug20
victorusu Apr 8, 2020
e36cde2
rename ModulesTool.get_variable_from_modulefile method to ModulesTool…
boegel Apr 8, 2020
1507e62
reimplement handle_external_module_metadata + clean up probe_external…
boegel Apr 8, 2020
0277662
enhance test_external_dependencies to check probing of external modul…
boegel Apr 8, 2020
12573ab
fix broken test_resolve_dependencies test by providing dummy implemen…
boegel Apr 8, 2020
a9facb3
strip off leading/trailing whitespace in get_setenv_value_from_module…
boegel Apr 8, 2020
227a9fd
use prefix value rather than name of environment variable that contai…
boegel Apr 8, 2020
1fbea39
Merge pull request #5 from boegel/cug20
victorusu Apr 9, 2020
3aed793
remove unused imports in test/framework/modules.py
boegel Apr 9, 2020
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
53 changes: 51 additions & 2 deletions easybuild/framework/easyconfig/easyconfig.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
:author: Alan O'Cais (Juelich Supercomputing Centre)
:author: Bart Oldeman (McGill University, Calcul Quebec, Compute Canada)
:author: Maxime Boissonneault (Universite Laval, Calcul Quebec, Compute Canada)
:author: Victor Holanda (CSCS, ETH Zurich)
"""

import copy
Expand All @@ -61,7 +62,7 @@
from easybuild.tools.config import LOCAL_VAR_NAMING_CHECK_ERROR, LOCAL_VAR_NAMING_CHECK_LOG, LOCAL_VAR_NAMING_CHECK_WARN
from easybuild.tools.config import Singleton, build_option, get_module_naming_scheme
from easybuild.tools.filetools import EASYBLOCK_CLASS_PREFIX, copy_file, decode_class_name, encode_class_name
from easybuild.tools.filetools import find_backup_name_candidate, find_easyconfigs, read_file, write_file
from easybuild.tools.filetools import convert_name, find_backup_name_candidate, find_easyconfigs, read_file, write_file
from easybuild.tools.hooks import PARSE, load_hooks, run_hook
from easybuild.tools.module_naming_scheme.mns import DEVEL_MODULE_SUFFIX
from easybuild.tools.module_naming_scheme.utilities import avail_module_naming_schemes, det_full_ec_version
Expand Down Expand Up @@ -1152,6 +1153,52 @@ def _validate(self, attr, values): # private method
if self[attr] and self[attr] not in values:
raise EasyBuildError("%s provided '%s' is not valid: %s", attr, self[attr], values)

def handle_external_module_metadata_by_probing_modules(self, dep_name):
"""
helper function for handle_external_module_metadata
handles metadata for external module dependencies when there is not entry in the
metadata file

It should look for the pair of variables definitions in the available modules
1. CRAY_XXXX_PREFIX and CRAY_XXXX_VERSION
2. CRAY_XXXX_DIR and CRAY_XXXX_VERSION
2. CRAY_XXXX_ROOT and CRAY_XXXX_VERSION
5. XXXX_PREFIX and XXXX_VERSION
4. XXXX_DIR and XXXX_VERSION
5. XXXX_ROOT and XXXX_VERSION
3. XXXX_HOME and XXXX_VERSION

If neither of the pairs is found, then an empty dictionary is returned
"""
dependency = {}

short_ext_modname = dep_name.split('/')[0]
short_ext_modname_upper = convert_name(short_ext_modname, upper=True)

allowed_pairs = [
('CRAY_%s_PREFIX' % short_ext_modname_upper, 'CRAY_%s_VERSION' % short_ext_modname_upper),
('CRAY_%s_DIR' % short_ext_modname_upper, 'CRAY_%s_VERSION' % short_ext_modname_upper),
('CRAY_%s_ROOT' % short_ext_modname_upper, 'CRAY_%s_VERSION' % short_ext_modname_upper),
('%s_PREFIX' % short_ext_modname_upper, '%s_VERSION' % short_ext_modname_upper),
('%s_DIR' % short_ext_modname_upper, '%s_VERSION' % short_ext_modname_upper),
('%s_ROOT' % short_ext_modname_upper, '%s_VERSION' % short_ext_modname_upper),
('%s_HOME' % short_ext_modname_upper, '%s_VERSION' % short_ext_modname_upper),
]

for p, v in allowed_pairs:
prefix = self.modules_tool.get_variable_from_modulefile(dep_name, p)
version = self.modules_tool.get_variable_from_modulefile(dep_name, v)

if prefix and version:
Copy link
Member

Choose a reason for hiding this comment

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

if prefix is found but not version, and if the version is in dep_name, can't we simply use that one?

Copy link
Member

Choose a reason for hiding this comment

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

The point is to only trust the metadata obtained by probing the module if it provides both the installation prefix and software version.
If it only provides one of both, we could have a "lucky hit", and the obtained metadata may be less trustworthy...

Let's go forward as is with this strict requirement, which can easily be loosened up later (the other way around is more difficult).

The other scenario, where the prefix is already known from the metadata file, but (only) the version is available through the module, may actually be more likely (since the prefix can be specified as the name of the environment variable specifying the installation prefix, not an actual hardcoded prefix, which can be done generically in the metadata file).

dependency = {
'name': [short_ext_modname],
'version': [version],
'prefix': p
}
break

return dependency

def handle_external_module_metadata(self, dep_name):
"""
helper function for _parse_dependency
Expand All @@ -1163,7 +1210,9 @@ def handle_external_module_metadata(self, dep_name):
self.log.info("Updated dependency info with available metadata for external module %s: %s",
dep_name, dependency['external_module_metadata'])
else:
self.log.info("No metadata available for external module %s", dep_name)
self.log.info("No metadata available for external module %s. Attempting to read from available modules",
dep_name)
dependency['external_module_metadata'] = self.handle_external_module_metadata_by_probing_modules(dep_name)

return dependency

Expand Down
39 changes: 39 additions & 0 deletions easybuild/tools/modules.py
Original file line number Diff line number Diff line change
Expand Up @@ -649,6 +649,15 @@ def show(self, mod_name):

return ans

def get_variable_from_modulefile(self, mod_name, var_name):
"""
Get info from the module file for the specified module.

:param mod_name: module name
:param var_name: name of the variable value to be extracted
"""
pass

def get_value_from_modulefile(self, mod_name, regex):
"""
Get info from the module file for the specified module.
Expand Down Expand Up @@ -1126,6 +1135,21 @@ def update(self):
"""Update after new modules were added."""
pass

def get_variable_from_modulefile(self, mod_name, var_name):
"""
Get info from the module file for the specified module.

:param mod_name: module name
:param var_name: name of the variable value to be extracted
"""
try:
# Tcl syntax
regex = re.compile(r'^setenv\s*%s\s*(?P<value>\S*)' % var_name, re.M)
ans = self.get_value_from_modulefile(mod_name, regex)
except Exception:
return None

return ans

class EnvironmentModulesTcl(EnvironmentModulesC):
"""Interface to (Tcl) environment modules (modulecmd.tcl)."""
Expand Down Expand Up @@ -1390,6 +1414,21 @@ def exist(self, mod_names, skip_avail=False, maybe_partial=True):
return super(Lmod, self).exist(mod_names, mod_exists_regex_template=r'^\s*\S*/%s.*(\.lua)?:\s*$',
skip_avail=skip_avail, maybe_partial=maybe_partial)

def get_variable_from_modulefile(self, mod_name, var_name):
"""
Get info from the module file for the specified module.

:param mod_name: module name
:param var_name: name of the variable value to be extracted
"""
try:
# Lua syntax
regex = re.compile(r'^setenv\(\"%s\",\s*\"(?P<value>\S*)\"\)' % var_name, re.M)
ans = self.get_value_from_modulefile(mod_name, regex)
except Exception:
return None

return ans

def get_software_root_env_var_name(name):
"""Return name of environment variable for software root."""
Expand Down