Hidden modules: always append hash (#40868)
This commit is contained in:
parent
c9dfb9b0fd
commit
4755b28398
10 changed files with 147 additions and 144 deletions
|
@ -3,17 +3,22 @@
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
|
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
|
||||||
|
|
||||||
|
from typing import Optional, Set
|
||||||
|
|
||||||
from llnl.util import tty
|
from llnl.util import tty
|
||||||
|
|
||||||
import spack.config
|
import spack.config
|
||||||
import spack.modules
|
import spack.modules
|
||||||
|
import spack.spec
|
||||||
|
|
||||||
|
|
||||||
def _for_each_enabled(spec, method_name, explicit=None):
|
def _for_each_enabled(
|
||||||
|
spec: spack.spec.Spec, method_name: str, explicit: Optional[bool] = None
|
||||||
|
) -> None:
|
||||||
"""Calls a method for each enabled module"""
|
"""Calls a method for each enabled module"""
|
||||||
set_names = set(spack.config.get("modules", {}).keys())
|
set_names: Set[str] = set(spack.config.get("modules", {}).keys())
|
||||||
for name in set_names:
|
for name in set_names:
|
||||||
enabled = spack.config.get("modules:%s:enable" % name)
|
enabled = spack.config.get(f"modules:{name}:enable")
|
||||||
if not enabled:
|
if not enabled:
|
||||||
tty.debug("NO MODULE WRITTEN: list of enabled module files is empty")
|
tty.debug("NO MODULE WRITTEN: list of enabled module files is empty")
|
||||||
continue
|
continue
|
||||||
|
@ -28,7 +33,7 @@ def _for_each_enabled(spec, method_name, explicit=None):
|
||||||
tty.warn(msg.format(method_name, str(e)))
|
tty.warn(msg.format(method_name, str(e)))
|
||||||
|
|
||||||
|
|
||||||
def post_install(spec, explicit):
|
def post_install(spec, explicit: bool):
|
||||||
import spack.environment as ev # break import cycle
|
import spack.environment as ev # break import cycle
|
||||||
|
|
||||||
if ev.active_environment():
|
if ev.active_environment():
|
||||||
|
|
|
@ -7,10 +7,15 @@
|
||||||
include Tcl non-hierarchical modules, Lua hierarchical modules, and others.
|
include Tcl non-hierarchical modules, Lua hierarchical modules, and others.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from .common import disable_modules
|
from typing import Dict, Type
|
||||||
|
|
||||||
|
from .common import BaseModuleFileWriter, disable_modules
|
||||||
from .lmod import LmodModulefileWriter
|
from .lmod import LmodModulefileWriter
|
||||||
from .tcl import TclModulefileWriter
|
from .tcl import TclModulefileWriter
|
||||||
|
|
||||||
__all__ = ["TclModulefileWriter", "LmodModulefileWriter", "disable_modules"]
|
__all__ = ["TclModulefileWriter", "LmodModulefileWriter", "disable_modules"]
|
||||||
|
|
||||||
module_types = {"tcl": TclModulefileWriter, "lmod": LmodModulefileWriter}
|
module_types: Dict[str, Type[BaseModuleFileWriter]] = {
|
||||||
|
"tcl": TclModulefileWriter,
|
||||||
|
"lmod": LmodModulefileWriter,
|
||||||
|
}
|
||||||
|
|
|
@ -35,7 +35,7 @@
|
||||||
import os.path
|
import os.path
|
||||||
import re
|
import re
|
||||||
import string
|
import string
|
||||||
from typing import Optional
|
from typing import List, Optional
|
||||||
|
|
||||||
import llnl.util.filesystem
|
import llnl.util.filesystem
|
||||||
import llnl.util.tty as tty
|
import llnl.util.tty as tty
|
||||||
|
@ -50,6 +50,7 @@
|
||||||
import spack.projections as proj
|
import spack.projections as proj
|
||||||
import spack.repo
|
import spack.repo
|
||||||
import spack.schema.environment
|
import spack.schema.environment
|
||||||
|
import spack.spec
|
||||||
import spack.store
|
import spack.store
|
||||||
import spack.tengine as tengine
|
import spack.tengine as tengine
|
||||||
import spack.util.environment
|
import spack.util.environment
|
||||||
|
@ -395,16 +396,14 @@ class BaseConfiguration:
|
||||||
|
|
||||||
default_projections = {"all": "{name}/{version}-{compiler.name}-{compiler.version}"}
|
default_projections = {"all": "{name}/{version}-{compiler.name}-{compiler.version}"}
|
||||||
|
|
||||||
def __init__(self, spec, module_set_name, explicit=None):
|
def __init__(self, spec: spack.spec.Spec, module_set_name: str, explicit: bool) -> None:
|
||||||
# Module where type(self) is defined
|
# Module where type(self) is defined
|
||||||
self.module = inspect.getmodule(self)
|
m = inspect.getmodule(self)
|
||||||
|
assert m is not None # make mypy happy
|
||||||
|
self.module = m
|
||||||
# Spec for which we want to generate a module file
|
# Spec for which we want to generate a module file
|
||||||
self.spec = spec
|
self.spec = spec
|
||||||
self.name = module_set_name
|
self.name = module_set_name
|
||||||
# Software installation has been explicitly asked (get this information from
|
|
||||||
# db when querying an existing module, like during a refresh or rm operations)
|
|
||||||
if explicit is None:
|
|
||||||
explicit = spec._installed_explicitly()
|
|
||||||
self.explicit = explicit
|
self.explicit = explicit
|
||||||
# Dictionary of configuration options that should be applied
|
# Dictionary of configuration options that should be applied
|
||||||
# to the spec
|
# to the spec
|
||||||
|
@ -458,7 +457,11 @@ def suffixes(self):
|
||||||
if constraint in self.spec:
|
if constraint in self.spec:
|
||||||
suffixes.append(suffix)
|
suffixes.append(suffix)
|
||||||
suffixes = list(dedupe(suffixes))
|
suffixes = list(dedupe(suffixes))
|
||||||
if self.hash:
|
# For hidden modules we can always add a fixed length hash as suffix, since it guards
|
||||||
|
# against file name clashes, and the module is not exposed to the user anyways.
|
||||||
|
if self.hidden:
|
||||||
|
suffixes.append(self.spec.dag_hash(length=7))
|
||||||
|
elif self.hash:
|
||||||
suffixes.append(self.hash)
|
suffixes.append(self.hash)
|
||||||
return suffixes
|
return suffixes
|
||||||
|
|
||||||
|
@ -551,8 +554,7 @@ def exclude_env_vars(self):
|
||||||
def _create_list_for(self, what):
|
def _create_list_for(self, what):
|
||||||
include = []
|
include = []
|
||||||
for item in self.conf[what]:
|
for item in self.conf[what]:
|
||||||
conf = type(self)(item, self.name)
|
if not self.module.make_configuration(item, self.name).excluded:
|
||||||
if not conf.excluded:
|
|
||||||
include.append(item)
|
include.append(item)
|
||||||
return include
|
return include
|
||||||
|
|
||||||
|
@ -826,8 +828,7 @@ def autoload(self):
|
||||||
def _create_module_list_of(self, what):
|
def _create_module_list_of(self, what):
|
||||||
m = self.conf.module
|
m = self.conf.module
|
||||||
name = self.conf.name
|
name = self.conf.name
|
||||||
explicit = self.conf.explicit
|
return [m.make_layout(x, name).use_name for x in getattr(self.conf, what)]
|
||||||
return [m.make_layout(x, name, explicit).use_name for x in getattr(self.conf, what)]
|
|
||||||
|
|
||||||
@tengine.context_property
|
@tengine.context_property
|
||||||
def verbose(self):
|
def verbose(self):
|
||||||
|
@ -836,12 +837,19 @@ def verbose(self):
|
||||||
|
|
||||||
|
|
||||||
class BaseModuleFileWriter:
|
class BaseModuleFileWriter:
|
||||||
def __init__(self, spec, module_set_name, explicit=None):
|
default_template: str
|
||||||
|
hide_cmd_format: str
|
||||||
|
modulerc_header: List[str]
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self, spec: spack.spec.Spec, module_set_name: str, explicit: Optional[bool] = None
|
||||||
|
) -> None:
|
||||||
self.spec = spec
|
self.spec = spec
|
||||||
|
|
||||||
# This class is meant to be derived. Get the module of the
|
# This class is meant to be derived. Get the module of the
|
||||||
# actual writer.
|
# actual writer.
|
||||||
self.module = inspect.getmodule(self)
|
self.module = inspect.getmodule(self)
|
||||||
|
assert self.module is not None # make mypy happy
|
||||||
m = self.module
|
m = self.module
|
||||||
|
|
||||||
# Create the triplet of configuration/layout/context
|
# Create the triplet of configuration/layout/context
|
||||||
|
|
|
@ -6,8 +6,7 @@
|
||||||
import collections
|
import collections
|
||||||
import itertools
|
import itertools
|
||||||
import os.path
|
import os.path
|
||||||
import posixpath
|
from typing import Dict, List, Optional, Tuple
|
||||||
from typing import Any, Dict, List
|
|
||||||
|
|
||||||
import llnl.util.filesystem as fs
|
import llnl.util.filesystem as fs
|
||||||
import llnl.util.lang as lang
|
import llnl.util.lang as lang
|
||||||
|
@ -24,18 +23,19 @@
|
||||||
|
|
||||||
|
|
||||||
#: lmod specific part of the configuration
|
#: lmod specific part of the configuration
|
||||||
def configuration(module_set_name):
|
def configuration(module_set_name: str) -> dict:
|
||||||
config_path = "modules:%s:lmod" % module_set_name
|
return spack.config.get(f"modules:{module_set_name}:lmod", {})
|
||||||
config = spack.config.get(config_path, {})
|
|
||||||
return config
|
|
||||||
|
|
||||||
|
|
||||||
# Caches the configuration {spec_hash: configuration}
|
# Caches the configuration {spec_hash: configuration}
|
||||||
configuration_registry: Dict[str, Any] = {}
|
configuration_registry: Dict[Tuple[str, str, bool], BaseConfiguration] = {}
|
||||||
|
|
||||||
|
|
||||||
def make_configuration(spec, module_set_name, explicit):
|
def make_configuration(
|
||||||
|
spec: spack.spec.Spec, module_set_name: str, explicit: Optional[bool] = None
|
||||||
|
) -> BaseConfiguration:
|
||||||
"""Returns the lmod configuration for spec"""
|
"""Returns the lmod configuration for spec"""
|
||||||
|
explicit = bool(spec._installed_explicitly()) if explicit is None else explicit
|
||||||
key = (spec.dag_hash(), module_set_name, explicit)
|
key = (spec.dag_hash(), module_set_name, explicit)
|
||||||
try:
|
try:
|
||||||
return configuration_registry[key]
|
return configuration_registry[key]
|
||||||
|
@ -45,16 +45,18 @@ def make_configuration(spec, module_set_name, explicit):
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def make_layout(spec, module_set_name, explicit):
|
def make_layout(
|
||||||
|
spec: spack.spec.Spec, module_set_name: str, explicit: Optional[bool] = None
|
||||||
|
) -> BaseFileLayout:
|
||||||
"""Returns the layout information for spec"""
|
"""Returns the layout information for spec"""
|
||||||
conf = make_configuration(spec, module_set_name, explicit)
|
return LmodFileLayout(make_configuration(spec, module_set_name, explicit))
|
||||||
return LmodFileLayout(conf)
|
|
||||||
|
|
||||||
|
|
||||||
def make_context(spec, module_set_name, explicit):
|
def make_context(
|
||||||
|
spec: spack.spec.Spec, module_set_name: str, explicit: Optional[bool] = None
|
||||||
|
) -> BaseContext:
|
||||||
"""Returns the context information for spec"""
|
"""Returns the context information for spec"""
|
||||||
conf = make_configuration(spec, module_set_name, explicit)
|
return LmodContext(make_configuration(spec, module_set_name, explicit))
|
||||||
return LmodContext(conf)
|
|
||||||
|
|
||||||
|
|
||||||
def guess_core_compilers(name, store=False) -> List[spack.spec.CompilerSpec]:
|
def guess_core_compilers(name, store=False) -> List[spack.spec.CompilerSpec]:
|
||||||
|
@ -97,10 +99,7 @@ def guess_core_compilers(name, store=False) -> List[spack.spec.CompilerSpec]:
|
||||||
class LmodConfiguration(BaseConfiguration):
|
class LmodConfiguration(BaseConfiguration):
|
||||||
"""Configuration class for lmod module files."""
|
"""Configuration class for lmod module files."""
|
||||||
|
|
||||||
# Note: Posixpath is used here as well as below as opposed to
|
default_projections = {"all": "{name}/{version}"}
|
||||||
# os.path.join due to spack.spec.Spec.format
|
|
||||||
# requiring forward slash path seperators at this stage
|
|
||||||
default_projections = {"all": posixpath.join("{name}", "{version}")}
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def core_compilers(self) -> List[spack.spec.CompilerSpec]:
|
def core_compilers(self) -> List[spack.spec.CompilerSpec]:
|
||||||
|
@ -274,19 +273,16 @@ def filename(self):
|
||||||
hierarchy_name = os.path.join(*parts)
|
hierarchy_name = os.path.join(*parts)
|
||||||
|
|
||||||
# Compute the absolute path
|
# Compute the absolute path
|
||||||
fullname = os.path.join(
|
return os.path.join(
|
||||||
self.arch_dirname, # root for lmod files on this architecture
|
self.arch_dirname, # root for lmod files on this architecture
|
||||||
hierarchy_name, # relative path
|
hierarchy_name, # relative path
|
||||||
".".join([self.use_name, self.extension]), # file name
|
f"{self.use_name}.{self.extension}", # file name
|
||||||
)
|
)
|
||||||
return fullname
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def modulerc(self):
|
def modulerc(self):
|
||||||
"""Returns the modulerc file associated with current module file"""
|
"""Returns the modulerc file associated with current module file"""
|
||||||
return os.path.join(
|
return os.path.join(os.path.dirname(self.filename), f".modulerc.{self.extension}")
|
||||||
os.path.dirname(self.filename), ".".join([".modulerc", self.extension])
|
|
||||||
)
|
|
||||||
|
|
||||||
def token_to_path(self, name, value):
|
def token_to_path(self, name, value):
|
||||||
"""Transforms a hierarchy token into the corresponding path part.
|
"""Transforms a hierarchy token into the corresponding path part.
|
||||||
|
@ -319,9 +315,7 @@ def path_part_fmt(token):
|
||||||
# we need to append a hash to the version to distinguish
|
# we need to append a hash to the version to distinguish
|
||||||
# among flavors of the same library (e.g. openblas~openmp vs.
|
# among flavors of the same library (e.g. openblas~openmp vs.
|
||||||
# openblas+openmp)
|
# openblas+openmp)
|
||||||
path = path_part_fmt(token=value)
|
return f"{path_part_fmt(token=value)}-{value.dag_hash(length=7)}"
|
||||||
path = "-".join([path, value.dag_hash(length=7)])
|
|
||||||
return path
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def available_path_parts(self):
|
def available_path_parts(self):
|
||||||
|
@ -333,8 +327,7 @@ def available_path_parts(self):
|
||||||
# List of services that are part of the hierarchy
|
# List of services that are part of the hierarchy
|
||||||
hierarchy = self.conf.hierarchy_tokens
|
hierarchy = self.conf.hierarchy_tokens
|
||||||
# Tokenize each part that is both in the hierarchy and available
|
# Tokenize each part that is both in the hierarchy and available
|
||||||
parts = [self.token_to_path(x, available[x]) for x in hierarchy if x in available]
|
return [self.token_to_path(x, available[x]) for x in hierarchy if x in available]
|
||||||
return parts
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@lang.memoized
|
@lang.memoized
|
||||||
|
@ -452,7 +445,7 @@ def missing(self):
|
||||||
@lang.memoized
|
@lang.memoized
|
||||||
def unlocked_paths(self):
|
def unlocked_paths(self):
|
||||||
"""Returns the list of paths that are unlocked unconditionally."""
|
"""Returns the list of paths that are unlocked unconditionally."""
|
||||||
layout = make_layout(self.spec, self.conf.name, self.conf.explicit)
|
layout = make_layout(self.spec, self.conf.name)
|
||||||
return [os.path.join(*parts) for parts in layout.unlocked_paths[None]]
|
return [os.path.join(*parts) for parts in layout.unlocked_paths[None]]
|
||||||
|
|
||||||
@tengine.context_property
|
@tengine.context_property
|
||||||
|
@ -460,7 +453,7 @@ def conditionally_unlocked_paths(self):
|
||||||
"""Returns the list of paths that are unlocked conditionally.
|
"""Returns the list of paths that are unlocked conditionally.
|
||||||
Each item in the list is a tuple with the structure (condition, path).
|
Each item in the list is a tuple with the structure (condition, path).
|
||||||
"""
|
"""
|
||||||
layout = make_layout(self.spec, self.conf.name, self.conf.explicit)
|
layout = make_layout(self.spec, self.conf.name)
|
||||||
value = []
|
value = []
|
||||||
conditional_paths = layout.unlocked_paths
|
conditional_paths = layout.unlocked_paths
|
||||||
conditional_paths.pop(None)
|
conditional_paths.pop(None)
|
||||||
|
@ -482,9 +475,9 @@ def manipulate_path(token):
|
||||||
class LmodModulefileWriter(BaseModuleFileWriter):
|
class LmodModulefileWriter(BaseModuleFileWriter):
|
||||||
"""Writer class for lmod module files."""
|
"""Writer class for lmod module files."""
|
||||||
|
|
||||||
default_template = posixpath.join("modules", "modulefile.lua")
|
default_template = "modules/modulefile.lua"
|
||||||
|
|
||||||
modulerc_header: list = []
|
modulerc_header = []
|
||||||
|
|
||||||
hide_cmd_format = 'hide_version("%s")'
|
hide_cmd_format = 'hide_version("%s")'
|
||||||
|
|
||||||
|
|
|
@ -7,28 +7,29 @@
|
||||||
non-hierarchical modules.
|
non-hierarchical modules.
|
||||||
"""
|
"""
|
||||||
import os.path
|
import os.path
|
||||||
import posixpath
|
from typing import Dict, Optional, Tuple
|
||||||
from typing import Any, Dict
|
|
||||||
|
|
||||||
import spack.config
|
import spack.config
|
||||||
|
import spack.spec
|
||||||
import spack.tengine as tengine
|
import spack.tengine as tengine
|
||||||
|
|
||||||
from .common import BaseConfiguration, BaseContext, BaseFileLayout, BaseModuleFileWriter
|
from .common import BaseConfiguration, BaseContext, BaseFileLayout, BaseModuleFileWriter
|
||||||
|
|
||||||
|
|
||||||
#: Tcl specific part of the configuration
|
#: Tcl specific part of the configuration
|
||||||
def configuration(module_set_name):
|
def configuration(module_set_name: str) -> dict:
|
||||||
config_path = "modules:%s:tcl" % module_set_name
|
return spack.config.get(f"modules:{module_set_name}:tcl", {})
|
||||||
config = spack.config.get(config_path, {})
|
|
||||||
return config
|
|
||||||
|
|
||||||
|
|
||||||
# Caches the configuration {spec_hash: configuration}
|
# Caches the configuration {spec_hash: configuration}
|
||||||
configuration_registry: Dict[str, Any] = {}
|
configuration_registry: Dict[Tuple[str, str, bool], BaseConfiguration] = {}
|
||||||
|
|
||||||
|
|
||||||
def make_configuration(spec, module_set_name, explicit):
|
def make_configuration(
|
||||||
|
spec: spack.spec.Spec, module_set_name: str, explicit: Optional[bool] = None
|
||||||
|
) -> BaseConfiguration:
|
||||||
"""Returns the tcl configuration for spec"""
|
"""Returns the tcl configuration for spec"""
|
||||||
|
explicit = bool(spec._installed_explicitly()) if explicit is None else explicit
|
||||||
key = (spec.dag_hash(), module_set_name, explicit)
|
key = (spec.dag_hash(), module_set_name, explicit)
|
||||||
try:
|
try:
|
||||||
return configuration_registry[key]
|
return configuration_registry[key]
|
||||||
|
@ -38,16 +39,18 @@ def make_configuration(spec, module_set_name, explicit):
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def make_layout(spec, module_set_name, explicit):
|
def make_layout(
|
||||||
|
spec: spack.spec.Spec, module_set_name: str, explicit: Optional[bool] = None
|
||||||
|
) -> BaseFileLayout:
|
||||||
"""Returns the layout information for spec"""
|
"""Returns the layout information for spec"""
|
||||||
conf = make_configuration(spec, module_set_name, explicit)
|
return TclFileLayout(make_configuration(spec, module_set_name, explicit))
|
||||||
return TclFileLayout(conf)
|
|
||||||
|
|
||||||
|
|
||||||
def make_context(spec, module_set_name, explicit):
|
def make_context(
|
||||||
|
spec: spack.spec.Spec, module_set_name: str, explicit: Optional[bool] = None
|
||||||
|
) -> BaseContext:
|
||||||
"""Returns the context information for spec"""
|
"""Returns the context information for spec"""
|
||||||
conf = make_configuration(spec, module_set_name, explicit)
|
return TclContext(make_configuration(spec, module_set_name, explicit))
|
||||||
return TclContext(conf)
|
|
||||||
|
|
||||||
|
|
||||||
class TclConfiguration(BaseConfiguration):
|
class TclConfiguration(BaseConfiguration):
|
||||||
|
@ -75,10 +78,7 @@ def prerequisites(self):
|
||||||
class TclModulefileWriter(BaseModuleFileWriter):
|
class TclModulefileWriter(BaseModuleFileWriter):
|
||||||
"""Writer class for tcl module files."""
|
"""Writer class for tcl module files."""
|
||||||
|
|
||||||
# Note: Posixpath is used here as opposed to
|
default_template = "modules/modulefile.tcl"
|
||||||
# os.path.join due to spack.spec.Spec.format
|
|
||||||
# requiring forward slash path seperators at this stage
|
|
||||||
default_template = posixpath.join("modules", "modulefile.tcl")
|
|
||||||
|
|
||||||
modulerc_header = ["#%Module4.7"]
|
modulerc_header = ["#%Module4.7"]
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@ enable:
|
||||||
- lmod
|
- lmod
|
||||||
lmod:
|
lmod:
|
||||||
hide_implicits: true
|
hide_implicits: true
|
||||||
|
hash_length: 0
|
||||||
core_compilers:
|
core_compilers:
|
||||||
- 'clang@3.3'
|
- 'clang@3.3'
|
||||||
hierarchy:
|
hierarchy:
|
||||||
|
|
|
@ -4,5 +4,6 @@ enable:
|
||||||
- tcl
|
- tcl
|
||||||
tcl:
|
tcl:
|
||||||
exclude_implicits: true
|
exclude_implicits: true
|
||||||
|
hash_length: 0
|
||||||
all:
|
all:
|
||||||
autoload: direct
|
autoload: direct
|
||||||
|
|
|
@ -2,5 +2,6 @@ enable:
|
||||||
- tcl
|
- tcl
|
||||||
tcl:
|
tcl:
|
||||||
hide_implicits: true
|
hide_implicits: true
|
||||||
|
hash_length: 0
|
||||||
all:
|
all:
|
||||||
autoload: direct
|
autoload: direct
|
||||||
|
|
|
@ -435,7 +435,7 @@ def test_modules_no_arch(self, factory, module_configuration):
|
||||||
|
|
||||||
assert str(spec.os) not in path
|
assert str(spec.os) not in path
|
||||||
|
|
||||||
def test_hide_implicits(self, module_configuration):
|
def test_hide_implicits(self, module_configuration, temporary_store):
|
||||||
"""Tests the addition and removal of hide command in modulerc."""
|
"""Tests the addition and removal of hide command in modulerc."""
|
||||||
module_configuration("hide_implicits")
|
module_configuration("hide_implicits")
|
||||||
|
|
||||||
|
@ -446,29 +446,42 @@ def test_hide_implicits(self, module_configuration):
|
||||||
writer.write()
|
writer.write()
|
||||||
assert os.path.exists(writer.layout.modulerc)
|
assert os.path.exists(writer.layout.modulerc)
|
||||||
with open(writer.layout.modulerc) as f:
|
with open(writer.layout.modulerc) as f:
|
||||||
content = f.readlines()
|
content = [line.strip() for line in f.readlines()]
|
||||||
content = "".join(content).split("\n")
|
hide_implicit_mpileaks = f'hide_version("{writer.layout.use_name}")'
|
||||||
hide_cmd = 'hide_version("%s")' % writer.layout.use_name
|
assert len([x for x in content if hide_implicit_mpileaks == x]) == 1
|
||||||
assert len([x for x in content if hide_cmd == x]) == 1
|
|
||||||
|
|
||||||
# mpileaks becomes explicit, thus modulerc is removed
|
# The direct dependencies are all implicitly installed, and they should all be hidden,
|
||||||
writer = writer_cls(spec, "default", True)
|
# except for mpich, which is provider for mpi, which is in the hierarchy, and therefore
|
||||||
writer.write(overwrite=True)
|
# can't be hidden. All other hidden modules should have a 7 character hash (the config
|
||||||
assert not os.path.exists(writer.layout.modulerc)
|
# hash_length = 0 only applies to exposed modules).
|
||||||
|
with open(writer.layout.filename) as f:
|
||||||
|
depends_statements = [line.strip() for line in f.readlines() if "depends_on" in line]
|
||||||
|
for dep in spec.dependencies(deptype=("link", "run")):
|
||||||
|
if dep.satisfies("mpi"):
|
||||||
|
assert not any(dep.dag_hash(7) in line for line in depends_statements)
|
||||||
|
else:
|
||||||
|
assert any(dep.dag_hash(7) in line for line in depends_statements)
|
||||||
|
|
||||||
# mpileaks is defined as explicit, no modulerc file should exist
|
# when mpileaks becomes explicit, its file name changes (hash_length = 0), meaning an
|
||||||
|
# extra module file is created; the old one still exists and remains hidden.
|
||||||
writer = writer_cls(spec, "default", True)
|
writer = writer_cls(spec, "default", True)
|
||||||
writer.write()
|
writer.write()
|
||||||
assert not os.path.exists(writer.layout.modulerc)
|
assert os.path.exists(writer.layout.modulerc)
|
||||||
|
with open(writer.layout.modulerc) as f:
|
||||||
|
content = [line.strip() for line in f.readlines()]
|
||||||
|
assert hide_implicit_mpileaks in content # old, implicit mpileaks is still hidden
|
||||||
|
assert f'hide_version("{writer.layout.use_name}")' not in content
|
||||||
|
|
||||||
# explicit module is removed
|
# after removing both the implicit and explicit module, the modulerc file would be empty
|
||||||
writer.remove()
|
# and should be removed.
|
||||||
|
writer_cls(spec, "default", False).remove()
|
||||||
|
writer_cls(spec, "default", True).remove()
|
||||||
assert not os.path.exists(writer.layout.modulerc)
|
assert not os.path.exists(writer.layout.modulerc)
|
||||||
assert not os.path.exists(writer.layout.filename)
|
assert not os.path.exists(writer.layout.filename)
|
||||||
|
|
||||||
# implicit module is removed
|
# implicit module is removed
|
||||||
writer = writer_cls(spec, "default", False)
|
writer = writer_cls(spec, "default", False)
|
||||||
writer.write(overwrite=True)
|
writer.write()
|
||||||
assert os.path.exists(writer.layout.filename)
|
assert os.path.exists(writer.layout.filename)
|
||||||
assert os.path.exists(writer.layout.modulerc)
|
assert os.path.exists(writer.layout.modulerc)
|
||||||
writer.remove()
|
writer.remove()
|
||||||
|
@ -486,35 +499,19 @@ def test_hide_implicits(self, module_configuration):
|
||||||
writer_alt2.write(overwrite=True)
|
writer_alt2.write(overwrite=True)
|
||||||
assert os.path.exists(writer.layout.modulerc)
|
assert os.path.exists(writer.layout.modulerc)
|
||||||
with open(writer.layout.modulerc) as f:
|
with open(writer.layout.modulerc) as f:
|
||||||
content = f.readlines()
|
content = [line.strip() for line in f.readlines()]
|
||||||
content = "".join(content).split("\n")
|
hide_cmd = f'hide_version("{writer.layout.use_name}")'
|
||||||
hide_cmd = 'hide_version("%s")' % writer.layout.use_name
|
hide_cmd_alt1 = f'hide_version("{writer_alt1.layout.use_name}")'
|
||||||
hide_cmd_alt1 = 'hide_version("%s")' % writer_alt1.layout.use_name
|
hide_cmd_alt2 = f'hide_version("{writer_alt2.layout.use_name}")'
|
||||||
hide_cmd_alt2 = 'hide_version("%s")' % writer_alt2.layout.use_name
|
|
||||||
assert len([x for x in content if hide_cmd == x]) == 1
|
assert len([x for x in content if hide_cmd == x]) == 1
|
||||||
assert len([x for x in content if hide_cmd_alt1 == x]) == 1
|
assert len([x for x in content if hide_cmd_alt1 == x]) == 1
|
||||||
assert len([x for x in content if hide_cmd_alt2 == x]) == 1
|
assert len([x for x in content if hide_cmd_alt2 == x]) == 1
|
||||||
|
|
||||||
# one version is removed, a second becomes explicit
|
# one version is removed
|
||||||
writer_alt1.remove()
|
writer_alt1.remove()
|
||||||
writer_alt2 = writer_cls(spec_alt2, "default", True)
|
|
||||||
writer_alt2.write(overwrite=True)
|
|
||||||
assert os.path.exists(writer.layout.modulerc)
|
assert os.path.exists(writer.layout.modulerc)
|
||||||
with open(writer.layout.modulerc) as f:
|
with open(writer.layout.modulerc) as f:
|
||||||
content = f.readlines()
|
content = [line.strip() for line in f.readlines()]
|
||||||
content = "".join(content).split("\n")
|
|
||||||
assert len([x for x in content if hide_cmd == x]) == 1
|
assert len([x for x in content if hide_cmd == x]) == 1
|
||||||
assert len([x for x in content if hide_cmd_alt1 == x]) == 0
|
assert len([x for x in content if hide_cmd_alt1 == x]) == 0
|
||||||
assert len([x for x in content if hide_cmd_alt2 == x]) == 0
|
assert len([x for x in content if hide_cmd_alt2 == x]) == 1
|
||||||
|
|
||||||
# disable hide_implicits configuration option
|
|
||||||
module_configuration("autoload_direct")
|
|
||||||
writer = writer_cls(spec, "default")
|
|
||||||
writer.write(overwrite=True)
|
|
||||||
assert not os.path.exists(writer.layout.modulerc)
|
|
||||||
|
|
||||||
# reenable hide_implicits configuration option
|
|
||||||
module_configuration("hide_implicits")
|
|
||||||
writer = writer_cls(spec, "default")
|
|
||||||
writer.write(overwrite=True)
|
|
||||||
assert os.path.exists(writer.layout.modulerc)
|
|
||||||
|
|
|
@ -488,7 +488,7 @@ def test_modules_no_arch(self, factory, module_configuration):
|
||||||
|
|
||||||
assert str(spec.os) not in path
|
assert str(spec.os) not in path
|
||||||
|
|
||||||
def test_hide_implicits(self, module_configuration):
|
def test_hide_implicits(self, module_configuration, temporary_store):
|
||||||
"""Tests the addition and removal of hide command in modulerc."""
|
"""Tests the addition and removal of hide command in modulerc."""
|
||||||
module_configuration("hide_implicits")
|
module_configuration("hide_implicits")
|
||||||
|
|
||||||
|
@ -499,29 +499,37 @@ def test_hide_implicits(self, module_configuration):
|
||||||
writer.write()
|
writer.write()
|
||||||
assert os.path.exists(writer.layout.modulerc)
|
assert os.path.exists(writer.layout.modulerc)
|
||||||
with open(writer.layout.modulerc) as f:
|
with open(writer.layout.modulerc) as f:
|
||||||
content = f.readlines()
|
content = [line.strip() for line in f.readlines()]
|
||||||
content = "".join(content).split("\n")
|
hide_implicit_mpileaks = f"module-hide --soft --hidden-loaded {writer.layout.use_name}"
|
||||||
hide_cmd = "module-hide --soft --hidden-loaded %s" % writer.layout.use_name
|
assert len([x for x in content if hide_implicit_mpileaks == x]) == 1
|
||||||
assert len([x for x in content if hide_cmd == x]) == 1
|
|
||||||
|
|
||||||
# mpileaks becomes explicit, thus modulerc is removed
|
# The direct dependencies are all implicit, and they should have depends-on with fixed
|
||||||
writer = writer_cls(spec, "default", True)
|
# 7 character hash, even though the config is set to hash_length = 0.
|
||||||
writer.write(overwrite=True)
|
with open(writer.layout.filename) as f:
|
||||||
assert not os.path.exists(writer.layout.modulerc)
|
depends_statements = [line.strip() for line in f.readlines() if "depends-on" in line]
|
||||||
|
for dep in spec.dependencies(deptype=("link", "run")):
|
||||||
|
assert any(dep.dag_hash(7) in line for line in depends_statements)
|
||||||
|
|
||||||
# mpileaks is defined as explicit, no modulerc file should exist
|
# when mpileaks becomes explicit, its file name changes (hash_length = 0), meaning an
|
||||||
|
# extra module file is created; the old one still exists and remains hidden.
|
||||||
writer = writer_cls(spec, "default", True)
|
writer = writer_cls(spec, "default", True)
|
||||||
writer.write()
|
writer.write()
|
||||||
assert not os.path.exists(writer.layout.modulerc)
|
assert os.path.exists(writer.layout.modulerc)
|
||||||
|
with open(writer.layout.modulerc) as f:
|
||||||
|
content = [line.strip() for line in f.readlines()]
|
||||||
|
assert hide_implicit_mpileaks in content # old, implicit mpileaks is still hidden
|
||||||
|
assert f"module-hide --soft --hidden-loaded {writer.layout.use_name}" not in content
|
||||||
|
|
||||||
# explicit module is removed
|
# after removing both the implicit and explicit module, the modulerc file would be empty
|
||||||
writer.remove()
|
# and should be removed.
|
||||||
|
writer_cls(spec, "default", False).remove()
|
||||||
|
writer_cls(spec, "default", True).remove()
|
||||||
assert not os.path.exists(writer.layout.modulerc)
|
assert not os.path.exists(writer.layout.modulerc)
|
||||||
assert not os.path.exists(writer.layout.filename)
|
assert not os.path.exists(writer.layout.filename)
|
||||||
|
|
||||||
# implicit module is removed
|
# implicit module is removed
|
||||||
writer = writer_cls(spec, "default", False)
|
writer = writer_cls(spec, "default", False)
|
||||||
writer.write(overwrite=True)
|
writer.write()
|
||||||
assert os.path.exists(writer.layout.filename)
|
assert os.path.exists(writer.layout.filename)
|
||||||
assert os.path.exists(writer.layout.modulerc)
|
assert os.path.exists(writer.layout.modulerc)
|
||||||
writer.remove()
|
writer.remove()
|
||||||
|
@ -539,35 +547,19 @@ def test_hide_implicits(self, module_configuration):
|
||||||
writer_alt2.write(overwrite=True)
|
writer_alt2.write(overwrite=True)
|
||||||
assert os.path.exists(writer.layout.modulerc)
|
assert os.path.exists(writer.layout.modulerc)
|
||||||
with open(writer.layout.modulerc) as f:
|
with open(writer.layout.modulerc) as f:
|
||||||
content = f.readlines()
|
content = [line.strip() for line in f.readlines()]
|
||||||
content = "".join(content).split("\n")
|
hide_cmd = f"module-hide --soft --hidden-loaded {writer.layout.use_name}"
|
||||||
hide_cmd = "module-hide --soft --hidden-loaded %s" % writer.layout.use_name
|
hide_cmd_alt1 = f"module-hide --soft --hidden-loaded {writer_alt1.layout.use_name}"
|
||||||
hide_cmd_alt1 = "module-hide --soft --hidden-loaded %s" % writer_alt1.layout.use_name
|
hide_cmd_alt2 = f"module-hide --soft --hidden-loaded {writer_alt2.layout.use_name}"
|
||||||
hide_cmd_alt2 = "module-hide --soft --hidden-loaded %s" % writer_alt2.layout.use_name
|
|
||||||
assert len([x for x in content if hide_cmd == x]) == 1
|
assert len([x for x in content if hide_cmd == x]) == 1
|
||||||
assert len([x for x in content if hide_cmd_alt1 == x]) == 1
|
assert len([x for x in content if hide_cmd_alt1 == x]) == 1
|
||||||
assert len([x for x in content if hide_cmd_alt2 == x]) == 1
|
assert len([x for x in content if hide_cmd_alt2 == x]) == 1
|
||||||
|
|
||||||
# one version is removed, a second becomes explicit
|
# one version is removed
|
||||||
writer_alt1.remove()
|
writer_alt1.remove()
|
||||||
writer_alt2 = writer_cls(spec_alt2, "default", True)
|
|
||||||
writer_alt2.write(overwrite=True)
|
|
||||||
assert os.path.exists(writer.layout.modulerc)
|
assert os.path.exists(writer.layout.modulerc)
|
||||||
with open(writer.layout.modulerc) as f:
|
with open(writer.layout.modulerc) as f:
|
||||||
content = f.readlines()
|
content = [line.strip() for line in f.readlines()]
|
||||||
content = "".join(content).split("\n")
|
|
||||||
assert len([x for x in content if hide_cmd == x]) == 1
|
assert len([x for x in content if hide_cmd == x]) == 1
|
||||||
assert len([x for x in content if hide_cmd_alt1 == x]) == 0
|
assert len([x for x in content if hide_cmd_alt1 == x]) == 0
|
||||||
assert len([x for x in content if hide_cmd_alt2 == x]) == 0
|
assert len([x for x in content if hide_cmd_alt2 == x]) == 1
|
||||||
|
|
||||||
# disable hide_implicits configuration option
|
|
||||||
module_configuration("autoload_direct")
|
|
||||||
writer = writer_cls(spec, "default")
|
|
||||||
writer.write(overwrite=True)
|
|
||||||
assert not os.path.exists(writer.layout.modulerc)
|
|
||||||
|
|
||||||
# reenable hide_implicits configuration option
|
|
||||||
module_configuration("hide_implicits")
|
|
||||||
writer = writer_cls(spec, "default")
|
|
||||||
writer.write(overwrite=True)
|
|
||||||
assert os.path.exists(writer.layout.modulerc)
|
|
||||||
|
|
Loading…
Reference in a new issue