Skip to content

Instantly share code, notes, and snippets.

@treydock
Created September 14, 2014 17:37
Show Gist options
  • Save treydock/84fa69d4c22f44a130a4 to your computer and use it in GitHub Desktop.
Save treydock/84fa69d4c22f44a130a4 to your computer and use it in GitHub Desktop.
LocalHierarchicalMNS
##
# Copyright 2013-2014 Ghent University
#
# This file is part of EasyBuild,
# originally created by the HPC team of Ghent University (http://ugent.be/hpc/en),
# with support of Ghent University (http://ugent.be/hpc),
# the Flemish Supercomputer Centre (VSC) (https://vscentrum.be/nl/en),
# the Hercules foundation (http://www.herculesstichting.be/in_English)
# and the Department of Economy, Science and Innovation (EWI) (http://www.ewi-vlaanderen.be/en).
#
# http://github.com/hpcugent/easybuild
#
# EasyBuild is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation v2.
#
# EasyBuild is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with EasyBuild. If not, see <http://www.gnu.org/licenses/>.
##
"""
Implementation of an example hierarchical module naming scheme.
@author: Kenneth Hoste (Ghent University)
@author: Markus Geimer (Forschungszentrum Juelich GmbH)
"""
import os
import re
from vsc.utils import fancylogger
from easybuild.tools.module_naming_scheme import ModuleNamingScheme
from easybuild.tools.module_naming_scheme.toolchain import det_toolchain_compilers, det_toolchain_mpi
CORE = 'Core'
COMPILER = 'Compiler'
MPI = 'MPI'
MODULECLASS_COMPILER = 'compiler'
MODULECLASS_MPI = 'mpi'
class LocalHierarchicalMNS(ModuleNamingScheme):
"""Class implementing an example hierarchical module naming scheme."""
REQUIRED_KEYS = ['name', 'version', 'versionsuffix', 'toolchain', 'moduleclass']
def requires_toolchain_details(self):
"""
Determine whether toolchain details are required by this module naming scheme,
e.g. whether one of det_toolchain_* functions are relied upon.
"""
return True
def det_full_module_name(self, ec):
"""
Determine full module name, relative to the top of the module path.
Examples: Core/GCC/4.8.3, Compiler/GCC/4.8.3/OpenMPI/1.6.5, MPI/GCC/4.8.3/OpenMPI/1.6.5/HPL/2.1
"""
return os.path.join(self.det_module_subdir(ec), self.det_short_module_name(ec))
def det_short_module_name(self, ec):
"""
Determine short module name, i.e. the name under which modules will be exposed to users.
Examples: GCC/4.8.3, OpenMPI/1.6.5, OpenBLAS/0.2.9, HPL/2.1, Python/2.7.5
"""
return os.path.join(ec['name'].lower(), ec['version'] + ec['versionsuffix'])
def det_toolchain_compilers_name_version(self, tc_comps):
"""
Determine toolchain compiler tag, for given list of compilers.
"""
if tc_comps is None:
# no compiler in toolchain, dummy toolchain
res = None
elif len(tc_comps) == 1:
res = (tc_comps[0]['name'].lower(), tc_comps[0]['version'])
else:
tc_comp_names = [comp['name'].lower() for comp in tc_comps]
if set(tc_comp_names) == set(['icc', 'ifort']):
tc_comp_name = 'intel'
if tc_comps[0]['version'] == tc_comps[1]['version']:
tc_comp_ver = tc_comps[0]['version']
else:
self.log.error("Bumped into different versions for toolchain compilers: %s" % tc_comps)
else:
self.log.error("Unknown set of toolchain compilers, module naming scheme needs to be enhanced first.")
res = (tc_comp_name.lower(), tc_comp_ver)
return res
def det_module_subdir(self, ec):
"""
Determine module subdirectory, relative to the top of the module path.
This determines the separation between module names exposed to users, and what's part of the $MODULEPATH.
Examples: Core, Compiler/GCC/4.8.3, MPI/GCC/4.8.3/OpenMPI/1.6.5
"""
tc_comps = det_toolchain_compilers(ec)
tc_comp_info = self.det_toolchain_compilers_name_version(tc_comps)
# determine prefix based on type of toolchain used
if tc_comp_info is None:
# no compiler in toolchain, dummy toolchain => Core module
subdir = CORE
else:
tc_comp_name, tc_comp_ver = tc_comp_info
tc_mpi = det_toolchain_mpi(ec)
if tc_mpi is None:
# compiler-only toolchain => Compiler/<compiler_name>/<compiler_version> namespace
subdir = os.path.join(COMPILER, tc_comp_name.lower(), tc_comp_ver)
else:
# compiler-MPI toolchain => MPI/<comp_name>/<comp_version>/<MPI_name>/<MPI_version> namespace
tc_mpi_fullver = tc_mpi['version'] + tc_mpi['versionsuffix']
subdir = os.path.join(MPI, tc_comp_name.lower(), tc_comp_ver, tc_mpi['name'].lower(), tc_mpi_fullver)
return subdir
def det_modpath_extensions(self, ec):
"""
Determine module path extensions, if any.
Examples: Compiler/GCC/4.8.3 (for GCC/4.8.3 module), MPI/GCC/4.8.3/OpenMPI/1.6.5 (for OpenMPI/1.6.5 module)
"""
modclass = ec['moduleclass']
paths = []
if modclass == MODULECLASS_COMPILER:
if ec['name'].lower() in ['icc', 'ifort']:
compdir = 'intel'
else:
compdir = ec['name'].lower()
paths.append(os.path.join(COMPILER, compdir, ec['version']))
elif modclass == MODULECLASS_MPI:
tc_comps = det_toolchain_compilers(ec)
tc_comp_info = self.det_toolchain_compilers_name_version(tc_comps)
if tc_comp_info is None:
tup = (ec['toolchain'], ec['name'].lower(), ec['version'])
error_msg = ("No compiler available in toolchain %s used to install MPI library %s v%s, "
"which is required by the active module naming scheme.") % tup
self.log.error(error_msg)
else:
tc_comp_name, tc_comp_ver = tc_comp_info
fullver = ec['version'] + ec['versionsuffix']
paths.append(os.path.join(MPI, tc_comp_name.lower(), tc_comp_ver, ec['name'].lower(), fullver))
return paths
def expand_toolchain_load(self):
"""
Determine whether load statements for a toolchain should be expanded to load statements for its dependencies.
This is useful when toolchains are not exposed to users.
"""
return True
def det_init_modulepaths(self, ec):
"""
Determine list of initial module paths (i.e. top of the hierarchy).
"""
return [CORE]
def is_short_modname_for(self, short_modname, name):
"""
Determine whether the specified (short) module name is a module for software with the specified name.
Default implementation checks via a strict regex pattern, and assumes short module names are of the form:
<name>/<version>[-<toolchain>]
"""
modname_regex = re.compile('^%s/\S+$' % re.escape(name.lower()))
res = bool(modname_regex.match(short_modname))
tup = (short_modname, name, modname_regex.pattern, res)
self.log.debug("Checking whether '%s' is a module name for software with name '%s' via regex %s: %s" % tup)
return res
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment