Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
9 changes: 5 additions & 4 deletions docs/recipes.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ version: 2
* `name`: a plain text name for the environment
* `store`: the location where the environment will be mounted.
* `spack`: which spack and package repositories to use for installation.
* `modules`: _optional_ enable/diasble module file generation (default `true`).
* `modules`: (_deprecated_) _optional_ enable/disable module file generation.
* `description`: _optional_ a string that describes the environment (default empty).
* `version`: _default = 1_ the version of the uenv recipe (see below)

Expand Down Expand Up @@ -440,11 +440,12 @@ The `append_path` field is the same as `prepend_path`, except it appends instead

## Modules

Modules are generated for the installed compilers and packages by spack. The default module generation rules set by the version of spack specified in `config.yaml` will be used if no `modules.yaml` file is provided.
The presence of a `modules.yaml` file in the recipe is a necessary and sufficient condition to enable module generation.

To set rules for module generation, provide a `modules.yaml` file as per the [spack documentation](https://spack.readthedocs.io/en/latest/module_file_support.html).
!!! warning
`config:modules` field has been deprecated. It can still be specified, but it has to be consistent with the presence of `modules.yaml` file.

To disable module generation, set the field `config:modules:False` in `config.yaml`.
Modules are generated for the installed compilers and packages by spack. Rules for module generation in `modules.yaml` file should be provided as per the [spack documentation](https://spack.readthedocs.io/en/latest/module_file_support.html).

## Custom Spack Packages

Expand Down
15 changes: 8 additions & 7 deletions stackinator/builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ def environment_meta(self, recipe):
meta["views"] = recipe.environment_view_meta
meta["mount"] = str(recipe.mount)
modules = None
if conf["modules"]:
if recipe.with_modules:
modules = {"root": str(recipe.mount / "modules")}
meta["modules"] = modules
self._environment_meta = meta
Expand Down Expand Up @@ -227,7 +227,7 @@ def generate(self, recipe):
f.write(
makefile_template.render(
cache=recipe.mirror,
modules=recipe.config["modules"],
modules=recipe.with_modules,
post_install_hook=recipe.post_install_hook,
pre_install_hook=recipe.pre_install_hook,
spack_version=spack_version,
Expand Down Expand Up @@ -463,6 +463,7 @@ def generate(self, recipe):
with (generate_config_path / "Makefile").open("w") as f:
f.write(
make_config_template.render(
modules=recipe.with_modules,
build_path=self.path.as_posix(),
all_compilers=all_compilers,
release_compilers=all_compilers,
Expand All @@ -471,11 +472,11 @@ def generate(self, recipe):
)

# write modules/modules.yaml
modules_yaml = recipe.modules_yaml
generate_modules_path = self.path / "modules"
generate_modules_path.mkdir(exist_ok=True)
with (generate_modules_path / "modules.yaml").open("w") as f:
f.write(modules_yaml)
if recipe.with_modules:
generate_modules_path = self.path / "modules"
generate_modules_path.mkdir(exist_ok=True)
with (generate_modules_path / "modules.yaml").open("w") as f:
yaml.dump(recipe.modules, f)

# write the meta data
meta_path = store_path / "meta"
Expand Down
29 changes: 18 additions & 11 deletions stackinator/recipe.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,13 +63,23 @@ def __init__(self, args):
self.generate_compiler_specs(raw)

# optional modules.yaml file
self.modules = None
modules_path = self.path / "modules.yaml"
self._logger.debug(f"opening {modules_path}")
if not modules_path.is_file():
modules_path = pathlib.Path(args.build) / "spack/etc/spack/defaults/modules.yaml"
self._logger.debug(f"no modules.yaml provided - using the {modules_path}")
if modules_path.is_file():
with modules_path.open() as fid:
self.modules = yaml.load(fid, Loader=yaml.Loader)
# Note: it should match MODULEPATH set by envvars and used by uenv view "modules"
self.modules["modules"]["default"]["roots"]["tcl"] = (pathlib.Path(self.mount) / "modules").as_posix()

self.modules = modules_path
# DEPRECATED field `config:modules`
if "modules" in self.config:
self._logger.warning("boolean field config.yaml:modules has been deprecated")

if self.with_modules != self.config["modules"]:
self._logger.error(f"config.yaml:modules:{self.config['modules']}")
self._logger.error(f"modules.yaml:{self.with_modules}")
raise RuntimeError("conflicting modules configuration detected")

# optional packages.yaml file
packages_path = self.path / "packages.yaml"
Expand Down Expand Up @@ -261,6 +271,10 @@ def config(self, config_path):
schema.ConfigValidator.validate(raw)
self._config = raw

@property
def with_modules(self) -> bool:
return self.modules is not None

# In Stackinator 6 we replaced logic required to determine the
# pre 1.0 Spack version.
def find_spack_version(self, develop):
Expand Down Expand Up @@ -313,13 +327,6 @@ def environment_view_meta(self):

return view_meta

@property
def modules_yaml(self):
with self.modules.open() as fid:
raw = yaml.load(fid, Loader=yaml.Loader)
raw["modules"]["default"]["roots"]["tcl"] = (pathlib.Path(self.mount) / "modules").as_posix()
return yaml.dump(raw)

# creates the self.environments field that describes the full specifications
# for all of the environments sets, grouped in environments, from the raw
# environments.yaml input.
Expand Down
3 changes: 1 addition & 2 deletions stackinator/schema/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,7 @@
}
},
"modules" : {
"type": "boolean",
"default": true
"type": "boolean"
},
"description" : {
"oneOf": [
Expand Down
2 changes: 1 addition & 1 deletion stackinator/templates/Makefile.generate-config
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ ALL_COMPILER_PREFIXES ={% for compiler in all_compilers %} $$($(SPACK_HELPER) -e
COMPILER_PREFIXES ={% for compiler in release_compilers %} $$($(SPACK_HELPER) -e ../compilers/{{ compiler }} find --explicit --format='{prefix}' gcc llvm llvm-amdgpu nvhpc){% endfor %}


all: $(CONFIG_DIR)/upstreams.yaml $(CONFIG_DIR)/packages.yaml $(CONFIG_DIR)/repos.yaml $(MODULE_DIR)/upstreams.yaml $(MODULE_DIR)/compilers.yaml
all: $(CONFIG_DIR)/upstreams.yaml $(CONFIG_DIR)/packages.yaml $(CONFIG_DIR)/repos.yaml{% if modules %} $(MODULE_DIR)/upstreams.yaml $(MODULE_DIR)/compilers.yaml{% endif %}

# Generate the upstream configuration that will be provided by the mounted image
$(CONFIG_DIR)/upstreams.yaml:
Expand Down
3 changes: 0 additions & 3 deletions unittests/test_schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@ def test_config_yaml(yaml_path):
assert raw["store"] == "/user-environment"
assert raw["spack"]["commit"] is None
assert raw["spack"]["packages"]["commit"] is None
assert raw["modules"] == True # noqa: E712
assert raw["mirror"] == {"enable": True, "key": None}
assert raw["description"] is None

Expand All @@ -64,7 +63,6 @@ def test_config_yaml(yaml_path):
schema.ConfigValidator.validate(raw)
assert raw["spack"]["commit"] is None
assert raw["spack"]["packages"]["commit"] is not None
assert raw["modules"] == True # noqa: E712
assert raw["mirror"] == {"enable": True, "key": None}
assert raw["description"] is None

Expand All @@ -85,7 +83,6 @@ def test_config_yaml(yaml_path):
schema.ConfigValidator.validate(raw)
assert raw["spack"]["commit"] == "develop"
assert raw["spack"]["packages"]["commit"] is None
assert raw["modules"] == True # noqa: E712
assert raw["mirror"] == {"enable": True, "key": None}
assert raw["description"] is None

Expand Down