Skip to content

Commit 8ed7912

Browse files
authored
Reduce the number of Spack environments (#258)
Remove a long-standing work around to an old Spack bug, that required us to generate a separate Spack environment for every view. This meant that if an `environments.yaml` recipe contained more than one view in an environment (e.g. `default` and `develop`), then the environment would be concretised twice. Spack 1.0 fixes this issue, so we can . This has no impact on users or recipes, it is a back end optimization. Fixes #209
1 parent 5581430 commit 8ed7912

File tree

3 files changed

+32
-56
lines changed

3 files changed

+32
-56
lines changed

stackinator/recipe.py

Lines changed: 23 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -269,8 +269,7 @@ def environment_view_meta(self):
269269
# generate the view meta data that is presented in the squashfs image meta data
270270
view_meta = {}
271271
for _, env in self.environments.items():
272-
view = env["view"]
273-
if view is not None:
272+
for view in env["views"]:
274273
view_meta[view["name"]] = {
275274
"root": view["config"]["root"],
276275
"activate": view["config"]["root"] + "/activate.sh",
@@ -368,58 +367,33 @@ def generate_environment_specs(self, raw):
368367
env_name_map = {}
369368
for name, config in environments.items():
370369
env_name_map[name] = []
371-
for view, vc in config["views"].items():
372-
if view in env_names:
373-
raise Exception(f"An environment view with the name '{view}' already exists.")
370+
views = []
371+
for view_name, vc in config["views"].items():
372+
if view_name in env_names:
373+
raise Exception(f"An environment view with the name '{name}' already exists.")
374+
env_names.add(view_name)
375+
view_config = copy.deepcopy(vc)
374376
# set some default values:
375-
# vc["link"] = "roots"
376-
# vc["uenv"]["add_compilers"] = True
377-
# vc["uenv"]["prefix_paths"] = {}
378-
if vc is None:
379-
vc = {}
380-
vc.setdefault("link", "roots")
381-
vc.setdefault("uenv", {})
382-
vc["uenv"].setdefault("add_compilers", True)
383-
vc["uenv"].setdefault("prefix_paths", {})
377+
# ["link"] = "roots"
378+
# ["uenv"]["add_compilers"] = True
379+
# ["uenv"]["prefix_paths"] = {}
380+
if view_config is None:
381+
view_config = {}
382+
view_config.setdefault("link", "roots")
383+
view_config.setdefault("uenv", {})
384+
view_config["uenv"].setdefault("add_compilers", True)
385+
view_config["uenv"].setdefault("prefix_paths", {})
384386
prefix_string = ",".join(
385-
[f"{name}={':'.join(paths)}" for name, paths in vc["uenv"]["prefix_paths"].items()]
387+
[f"{pname}={':'.join(paths)}" for pname, paths in view_config["uenv"]["prefix_paths"].items()]
386388
)
387-
vc["uenv"]["prefix_string"] = prefix_string
388-
# save a copy of the view configuration
389-
env_name_map[name].append((view, vc))
390-
391-
# Iterate over each environment:
392-
# - creating copies of the env so that there is one copy per view.
393-
# - configure each view
394-
for name, views in env_name_map.items():
395-
numviews = len(env_name_map[name])
396-
397-
# The configuration of the environment without views
398-
base = copy.deepcopy(environments[name])
399-
400-
environments[name]["view"] = None
401-
for i in range(numviews):
402-
# pick a name for the environment
403-
cname = name if i == 0 else name + f"-{i + 1}__"
404-
if i > 0:
405-
environments[cname] = copy.deepcopy(base)
406-
407-
view_name, view_config = views[i]
408-
# note: the root path is stored as a string, not as a pathlib.PosixPath
409-
# to avoid serialisation issues when generating the spack.yaml file for
410-
# each environment.
411-
if view_config is None:
412-
view_config = {"root": str(self.mount / "env" / view_name)}
413-
else:
414-
view_config["root"] = str(self.mount / "env" / view_name)
415-
416-
# The "uenv" field is not spack configuration, it is additional information
417-
# used by stackinator additionally set compiler paths and LD_LIBRARY_PATH
418-
# Remove it from the view_config that will be passed directly to spack, and pass
419-
# it separately for configuring the envvars.py helper during the uenv build.
389+
view_config["uenv"]["prefix_string"] = prefix_string
390+
view_config["root"] = str(self.mount / "env" / view_name)
391+
420392
extra = view_config.pop("uenv")
393+
env_name_map[name].append((view_name, view_config))
394+
views.append({"name": view_name, "config": view_config, "extra": extra})
421395

422-
environments[cname]["view"] = {"name": view_name, "config": view_config, "extra": extra}
396+
config["views"] = views
423397

424398
self.environments = environments
425399

stackinator/templates/Makefile.environments

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,10 @@ all:{% for env in environments %} {{ env }}/generated/build_cache{% endfor %}
3232
# Create environment view where requested
3333
{% for env, config in environments.items() %}
3434
{{ env }}/generated/view_config: {{ env }}/generated/env
35-
{% if config.view %}
36-
$(SPACK) env activate --with-view default --sh ./{{ env }} > $(STORE)/env/{{ config.view.name }}/activate.sh
37-
$(BUILD_ROOT)/envvars.py view {% if config.view.extra.add_compilers %}--compilers=./{{ env }}/packages.yaml {% endif %} --prefix_paths="{{ config.view.extra.prefix_string }}" $(STORE)/env/{{ config.view.name }} $(BUILD_ROOT)
38-
{% endif %}
35+
{% for view in config.views %}
36+
$(SPACK) env activate --with-view {{ view.name }} --sh ./{{ env }} > $(STORE)/env/{{ view.name }}/activate.sh
37+
$(BUILD_ROOT)/envvars.py view {% if view.extra.add_compilers %}--compilers=./{{ env }}/packages.yaml {% endif %} --prefix_paths="{{ view.extra.prefix_string }}" $(STORE)/env/{{ view.name }} $(BUILD_ROOT)
38+
{% endfor %}
3939
touch $@
4040

4141
{% endfor %}

stackinator/templates/environments.spack.yaml

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,12 @@ spack:
2929
require: '{{ config.mpi }}'
3030
{% endif %}
3131
{% endif %}
32-
{% if config.view %}
32+
{% if config.views %}
3333
view:
34-
default:
35-
{{ config.view.config|py2yaml(6) }}
34+
{% for view in config.views %}
35+
{{ view.name }}:
36+
{{ view.config|py2yaml(6) }}
37+
{% endfor %}
3638
{% else %}
3739
view: false
3840
{% endif %}

0 commit comments

Comments
 (0)