From 7213f563d7334c8041e98d15f6af5e3bedd4dc17 Mon Sep 17 00:00:00 2001 From: bcumming Date: Tue, 10 Mar 2026 17:19:58 +0100 Subject: [PATCH 1/5] add support for default-view in config.yaml --- stackinator/builder.py | 1 + stackinator/recipe.py | 24 ++++++++++++++++-------- stackinator/schema/config.json | 25 +++++++------------------ 3 files changed, 24 insertions(+), 26 deletions(-) diff --git a/stackinator/builder.py b/stackinator/builder.py index 2c05e3c1..ae4997a1 100644 --- a/stackinator/builder.py +++ b/stackinator/builder.py @@ -156,6 +156,7 @@ def environment_meta(self, recipe): meta["name"] = conf["name"] meta["description"] = conf["description"] meta["views"] = recipe.environment_view_meta + meta["default-view"] = recipe.default_view meta["mount"] = str(recipe.mount) modules = None if recipe.with_modules: diff --git a/stackinator/recipe.py b/stackinator/recipe.py index ca8d2b3d..180293f7 100644 --- a/stackinator/recipe.py +++ b/stackinator/recipe.py @@ -87,14 +87,6 @@ def __init__(self, args): 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" - self._logger.debug(f"opening {packages_path}") - self.packages = None - if packages_path.is_file(): - with packages_path.open() as fid: - self.packages = yaml.load(fid, Loader=yaml.Loader) - self._logger.debug("creating packages") # load recipe/packages.yaml -> recipe_packages (if it exists) @@ -169,6 +161,15 @@ def __init__(self, args): schema.EnvironmentsValidator.validate(raw) self.generate_environment_specs(raw) + # check that the default view exists (if one has been set) + self._default_view = self.config["default-view"] + if self._default_view is not None: + if self._default_view not in [view["name"] for env in self.environments.values() for view in env["views"]]: + self._logger.warning( + "The default-view {self.default_view} is not the name of a view in the environments.yaml definition" + ) + raise RuntimeError("Ivalid default-view in the recipe.") + # optional mirror configurtion mirrors_path = self.path / "mirrors.yaml" if mirrors_path.is_file(): @@ -286,6 +287,13 @@ def with_modules(self) -> bool: def find_spack_version(self, develop): return "1.0" + # Returns: + # Path: if the recipe contains a spack package repository + # None: if there is the recipe contains no repo + @property + def default_view(self): + return self._default_view + @property def environment_view_meta(self): # generate the view meta data that is presented in the squashfs image meta data diff --git a/stackinator/schema/config.json b/stackinator/schema/config.json index d6fec3a0..d9de503e 100644 --- a/stackinator/schema/config.json +++ b/stackinator/schema/config.json @@ -46,24 +46,6 @@ } } }, - "mirror" : { - "type" : "object", - "additionalProperties": false, - "default": {"enable": true, "key": null}, - "properties" : { - "enable" : { - "type": "boolean", - "default": true - }, - "key" : { - "oneOf": [ - {"type" : "string"}, - {"type" : "null"} - ], - "default": null - } - } - }, "modules" : { "type": "boolean" }, @@ -74,6 +56,13 @@ ], "default": null }, + "default-view" : { + "oneOf": [ + {"type" : "string"}, + {"type" : "null"} + ], + "default": null + }, "version" : { "type": "number", "default": 1, From 38dc2943a9979284a887e1fd86c905a4dbb6eb0d Mon Sep 17 00:00:00 2001 From: bcumming Date: Wed, 11 Mar 2026 13:03:57 +0100 Subject: [PATCH 2/5] support setting modules and spack views as default view --- stackinator/recipe.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/stackinator/recipe.py b/stackinator/recipe.py index 180293f7..fe5d9e72 100644 --- a/stackinator/recipe.py +++ b/stackinator/recipe.py @@ -164,9 +164,15 @@ def __init__(self, args): # check that the default view exists (if one has been set) self._default_view = self.config["default-view"] if self._default_view is not None: - if self._default_view not in [view["name"] for env in self.environments.values() for view in env["views"]]: - self._logger.warning( - "The default-view {self.default_view} is not the name of a view in the environments.yaml definition" + available_views = [view["name"] for env in self.environments.values() for view in env["views"]] + # add the modules and spack views to the list of available views + if self.with_modules: + available_views.append("modules") + available_views.append("spack") + if self._default_view not in available_views: + self._logger.error( + f"The default-view {self._default_view} is not the name of a view in the environments.yaml " + "definition (one of {[name for name in available_views]}" ) raise RuntimeError("Ivalid default-view in the recipe.") From d445ebbbf419acdb697e29ac752efffd8709cf56 Mon Sep 17 00:00:00 2001 From: bcumming Date: Mon, 23 Mar 2026 08:58:49 +0100 Subject: [PATCH 3/5] add default view docs --- docs/recipes.md | 41 +++++++++++++++++++++++++++++++---------- 1 file changed, 31 insertions(+), 10 deletions(-) diff --git a/docs/recipes.md b/docs/recipes.md index cbe71290..7ff0b301 100644 --- a/docs/recipes.md +++ b/docs/recipes.md @@ -15,6 +15,7 @@ A recipe is comprised of the following yaml files in a directory: * `post-install`: _optional_ a script to run after Spack has been executed to build the stack. * `pre-install`: _optional_ a script to run before any packages have been built. +[](){#ref-recipes-config} ## Configuration ```yaml title="config.yaml" @@ -26,17 +27,18 @@ spack: packages: repo: https://github.com/spack/spack-packages.git commit: develop -modules: true description: "HPC development tools for building MPI applications with the GNU compiler toolchain" +default-view: develop 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`: (_deprecated_) _optional_ enable/disable module file generation. * `description`: _optional_ a string that describes the environment (default empty). +* `default-view`: _default = null_ the name of a uenv view to load if no view is explicitly requested by the user. See the documentation for [default views][ref-recipes-default-view]. If no default view is specified, none will be set. * `version`: _default = 1_ the version of the uenv recipe (see below) +* `modules`: (_deprecated_) _optional_ enable/disable module file generation. !!! note "uenv recipe versions" Stackinator 6 introduces breaking changes to the uenv recipe format, introduced to support Spack v1.0. @@ -350,7 +352,7 @@ For example, the `views` description: ```yaml cuda-env: views: - default: + full: no-python: exclude: - 'python' @@ -358,19 +360,26 @@ cuda-env: will configure two views: -* `default`: a view of all the software in the environment using the default settings of Spack. -* `no-python`: everything in the default view, except any versions of `python`. +* `full`: a view of all the software in the environment using the full settings of Spack. +* `no-python`: everything in the `full` view, except any versions of `python`. + +!!! warning "only name views default if they are loaded by default" + It is possible to name views `default`, and there are uenv images like `prgenv-gnu` that follow this practice for legacy reasons. + + However the name default can be confusing for users because it implies that the view is loaded by default. + However, [default views][ref-recipes-default-view] must be explicitly set in [`config.yaml`][ref-recipes-config]. Stackinator provides some additional options that are not provided by Spack, to fine tune the view, that can be set in the `uenv:` field: ```yaml cuda-env: views: - uenv: - add_compilers: true - prefix_paths: - LD_LIBRARY_PATH: [lib, lib64] - env_vars: + my-view: + uenv: + add_compilers: true + prefix_paths: + LD_LIBRARY_PATH: [lib, lib64] + env_vars: set: - WOMBAT: null - NOCOLOR: "1" @@ -392,6 +401,18 @@ cuda-env: !!! info See the [interfaces documentation](interfaces.md#environment-views) for more information about how the environment views are provided. +[](){#ref-recipes-default-view} +#### Setting default views + +!!! info "available in uenv 9.3 and later" + Default views are only loaded in recent versions of uenv. + Older uenv versions will ignore the default view - it is not an error to load a uenv that provides a default view using uenv 9.2 and older. + +It is possible to specify a view that will be loaded automatically if no view is specified, by setting the `default-view` field in [`config.yaml` file][ref-recipes-config]. + +* a default view is only used if it is explicitly specified in `config.yaml`. +* if a uenv is started with a view specified, the default view is ignored. + #### Setting environment variables with `env_vars` The `views::uenv:env_vars` field can be used to further fine-tune the environment variables that are set when the view is started. From 6751d829139a1007e4efac61b7ded7481ae00c55 Mon Sep 17 00:00:00 2001 From: Ben Cumming Date: Mon, 23 Mar 2026 09:00:36 +0100 Subject: [PATCH 4/5] Apply suggestion from @RMeli Co-authored-by: Rocco Meli --- stackinator/recipe.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/stackinator/recipe.py b/stackinator/recipe.py index fe5d9e72..9274e179 100644 --- a/stackinator/recipe.py +++ b/stackinator/recipe.py @@ -293,9 +293,6 @@ def with_modules(self) -> bool: def find_spack_version(self, develop): return "1.0" - # Returns: - # Path: if the recipe contains a spack package repository - # None: if there is the recipe contains no repo @property def default_view(self): return self._default_view From 9d96ef44e5d564a6bf1f399c6c9cd5348f1a8c39 Mon Sep 17 00:00:00 2001 From: bcumming Date: Mon, 23 Mar 2026 11:03:30 +0100 Subject: [PATCH 5/5] remove mirrors from tests --- unittests/recipes/base-nvgpu/config.yaml | 2 -- unittests/recipes/cache/config.yaml | 3 --- unittests/test_schema.py | 4 ---- unittests/yaml/config.defaults.yaml | 6 ------ unittests/yaml/config.full.yaml | 3 --- 5 files changed, 18 deletions(-) diff --git a/unittests/recipes/base-nvgpu/config.yaml b/unittests/recipes/base-nvgpu/config.yaml index 0102735a..ccdd1f7c 100644 --- a/unittests/recipes/base-nvgpu/config.yaml +++ b/unittests/recipes/base-nvgpu/config.yaml @@ -5,6 +5,4 @@ spack: commit: 6408b51 packages: repo: https://github.com/spack/spack-packages.git -mirror: - enable: false version: 2 diff --git a/unittests/recipes/cache/config.yaml b/unittests/recipes/cache/config.yaml index 8609b78a..a3c01cf7 100644 --- a/unittests/recipes/cache/config.yaml +++ b/unittests/recipes/cache/config.yaml @@ -5,7 +5,4 @@ spack: commit: 6408b51 packages: repo: https://github.com/spack/spack-packages.git -mirror: - key: /scratch/e1000/bcumming/secret/spack-key.gpg - enable: true version: 2 diff --git a/unittests/test_schema.py b/unittests/test_schema.py index bbd752df..b30f73da 100644 --- a/unittests/test_schema.py +++ b/unittests/test_schema.py @@ -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["mirror"] == {"enable": True, "key": None} assert raw["description"] is None # no spack:commit @@ -63,7 +62,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["mirror"] == {"enable": True, "key": None} assert raw["description"] is None # no spack:packages:commit @@ -83,7 +81,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["mirror"] == {"enable": True, "key": None} assert raw["description"] is None # full config @@ -94,7 +91,6 @@ def test_config_yaml(yaml_path): assert raw["spack"]["commit"] == "6408b51" assert raw["spack"]["packages"]["commit"] == "v2025.07.0" assert raw["modules"] == False # noqa: E712 - assert raw["mirror"] == {"enable": True, "key": "/home/bob/veryprivate.key"} assert raw["description"] == "a really useful environment" # unsupported old version diff --git a/unittests/yaml/config.defaults.yaml b/unittests/yaml/config.defaults.yaml index d021bd01..7197272a 100644 --- a/unittests/yaml/config.defaults.yaml +++ b/unittests/yaml/config.defaults.yaml @@ -9,11 +9,5 @@ spack: repo: https://github.com/spack/spack-packages.git # default: None == no `git checkout` command #commit: 6408b51 -#mirror: - # default None - #key: None - # default True - #enable: True -# default True #modules: True version: 2 diff --git a/unittests/yaml/config.full.yaml b/unittests/yaml/config.full.yaml index e13aa035..f7891614 100644 --- a/unittests/yaml/config.full.yaml +++ b/unittests/yaml/config.full.yaml @@ -6,9 +6,6 @@ spack: packages: repo: https://github.com/spack/spack-packages.git commit: v2025.07.0 -mirror: - key: /home/bob/veryprivate.key - enable: True modules: False description: "a really useful environment" version: 2