Skip to content

Commit 8a44d89

Browse files
modular uenv
remove bootstrap from schema remove compilers.yaml add squashfs-mount for base-uenvs cleanup cleanup change order typo typo typo skip compiler target convert to string fix path skip base uenvs in post-install loop.last tab look for squashfs in global tree always install squashfs add dependency do not generate {{env}}/compilers.yaml skip {{env}}/compilers.yaml in envvars.py skip -C /user-environment/config do not find compilers cleanup deps remove compilers.yaml install squashfs to bind mounted /tmp do not use filesystem locks remove dependency remove -d install squashfs in an env fix fix cleanup install -D the mount point doesn't need to exist base-uenv.json is optional wip fix squashfs-mount-wrapper allow to use a non-existent directory for STORE comment add padded_length for cache add missing file undo use padded_lenght in env do not use self.mount for mirror path use same sandbox in stack-debug.sh Revert "do not use self.mount for mirror path" This reverts commit f187450. ignore store/mountpath for build cache fix stack-debug.sh fix bwrap-store Revert "ignore store/mountpath for build cache" This reverts commit a13fc2b. remove padded_length remove stdout add generation of packages.yaml for externals fix chmod wip avoid spack --color fix structure set buildable false fix gen packages.yaml update do not use -all-root remove unused compiler target v2.0 repo format path must contain spack_repo repo -> spack_repo repo path must include namespace repo -> spack_repo update base-uenv.json schema compilers.yaml -> packages.yaml fix sandbox fix path, version doesn't belong here add missing version to packages.yaml set extra_attributes for compilers fix fix split debug Revert "debug" This reverts commit 4172a0a. fix find command cleanup update the schema remove compilers.yaml and the bits related to it from recipe.py remove more occurences of compilers.yaml avoid empty packages.all in environments.spack.yaml update for new base_uenv.json schema typo in schema base_uenv schema, default null for optional entries fix schema wip schema fix schema typo fix environments.spack.yaml typo fix environment.spack.yaml include exports from the gpu sub uenv fix schema change title remove compiler from env schema remove compiler from _internal_utils
1 parent eff1127 commit 8a44d89

22 files changed

+429
-247
lines changed

docs/interfaces.md

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ For example, the Spack configuration is in the following files when a stack has
1212
```
1313
/user-environment
1414
├─ config
15-
│ ├─ compilers.yaml
1615
│ ├─ repos.yaml
1716
│ ├─ packages.yaml
1817
│ └─ upstreams.yaml
@@ -31,7 +30,6 @@ Notes on the configuration files:
3130
system:
3231
install_tree: /user-environment
3332
```
34-
* `compilers.yaml`: includes all compilers that were installed in the `gcc:` and `llvm:` sections of the `compilers.yaml` recipe file. Note that the `bootstrap` compiler is not included.
3533
* `packages.yaml`: refers to the external packages that were used to configure the recipe: both the defaults in the cluster configuration, and any additional packages that were set in the recipe.
3634
* `repos.yaml`: points to the custom Spack repository:
3735
```yaml

stackinator/builder.py

Lines changed: 16 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -266,19 +266,30 @@ def generate(self, recipe):
266266

267267
make_user_template = jinja_env.get_template("Make.user")
268268
with (self.path / "Make.user").open("w") as f:
269+
base_uenvs = [e["image"] for e in recipe.base_uenv["compilers"]]
270+
if "gpu" in recipe.base_uenv:
271+
base_uenvs += [recipe.base_uenv["gpu"]["image"]]
269272
f.write(
270273
make_user_template.render(
271274
spack_version=spack_version,
272275
build_path=self.path,
273276
store=recipe.mount,
274277
no_bwrap=recipe.no_bwrap,
278+
base_uenv=base_uenvs,
275279
verbose=False,
276280
)
277281
)
278282
f.write("\n")
279283

280284
etc_path = self.root / "etc"
281-
for f_etc in ["Make.inc", "bwrap-mutable-root.sh", "envvars.py"]:
285+
for f_etc in [
286+
"Make.inc",
287+
"bwrap-mutable-root.sh",
288+
"bwrap-store.sh",
289+
"envvars.py",
290+
"gen_packages_yaml.py",
291+
"squashfs-mount-wrapper.sh",
292+
]:
282293
shutil.copy2(etc_path / f_etc, self.path / f_etc)
283294

284295
# used to configure both pre and post install hooks, if they are provided.
@@ -414,7 +425,7 @@ def generate(self, recipe):
414425

415426
# Delete the store/repo path, if it already exists.
416427
# Do this so that incremental builds (though not officially supported) won't break if a repo is updated.
417-
repo_dst = store_path / "repo"
428+
repo_dst = store_path / "spack_repo/alps"
418429
self._logger.debug(f"creating the stack spack prepo in {repo_dst}")
419430
if repo_dst.exists():
420431
self._logger.debug(f"{repo_dst} exists ... deleting")
@@ -432,13 +443,14 @@ def generate(self, recipe):
432443
"""\
433444
repo:
434445
namespace: alps
446+
api: v2.0
435447
"""
436448
)
437449

438450
# create the repository step 2: create the repos.yaml file in build_path/config
439451
repos_yaml_template = jinja_env.get_template("repos.yaml")
440452
with (config_path / "repos.yaml").open("w") as f:
441-
repo_path = recipe.mount / "repo"
453+
repo_path = recipe.mount / "spack_repo/alps"
442454
f.write(repos_yaml_template.render(repo_path=repo_path.as_posix(), verbose=False))
443455
f.write("\n")
444456

@@ -457,19 +469,6 @@ def generate(self, recipe):
457469
elif dst.exists():
458470
self._logger.debug(f" NOT installing package {pkg_path}")
459471

460-
# Generate the makefile and spack.yaml files that describe the compilers
461-
compiler_files = recipe.compiler_files
462-
compiler_path = self.path / "compilers"
463-
compiler_path.mkdir(exist_ok=True)
464-
with (compiler_path / "Makefile").open(mode="w") as f:
465-
f.write(compiler_files["makefile"])
466-
467-
for name, yml in compiler_files["config"].items():
468-
compiler_config_path = compiler_path / name
469-
compiler_config_path.mkdir(exist_ok=True)
470-
with (compiler_config_path / "spack.yaml").open(mode="w") as f:
471-
f.write(yml)
472-
473472
# generate the makefile and spack.yaml files that describe the environments
474473
environment_files = recipe.environment_files
475474
environments_path = self.path / "environments"
@@ -480,6 +479,7 @@ def generate(self, recipe):
480479
for name, yml in environment_files["config"].items():
481480
env_config_path = environments_path / name
482481
env_config_path.mkdir(exist_ok=True)
482+
# packages.yaml is added in the makefile from the base uenv
483483
with (env_config_path / "spack.yaml").open(mode="w") as f:
484484
f.write(yml)
485485

@@ -490,14 +490,10 @@ def generate(self, recipe):
490490
generate_config_path.mkdir(exist_ok=True)
491491

492492
# write generate-config/Makefile
493-
all_compilers = [x for x in recipe.compilers.keys()]
494-
release_compilers = [x for x in all_compilers if x != "bootstrap"]
495493
with (generate_config_path / "Makefile").open("w") as f:
496494
f.write(
497495
make_config_template.render(
498496
build_path=self.path.as_posix(),
499-
all_compilers=all_compilers,
500-
release_compilers=release_compilers,
501497
verbose=False,
502498
)
503499
)

stackinator/etc/Make.inc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ store:
1616
mkdir -p $(STORE)
1717

1818
# Concretization
19-
%/spack.lock: %/spack.yaml %/compilers.yaml %/config.yaml %/packages.yaml
19+
%/spack.lock: %/spack.yaml %/config.yaml %/packages.yaml
2020
$(SPACK_ENV) concretize -f
2121

2222
# Generate Makefiles for the environment install
Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,21 @@
11
#!/bin/bash
2+
3+
set -euo pipefail
24
args=()
35
shopt -s dotglob
6+
7+
# from /user-environment/foo/bar/baz store /user-environment as _top_level
8+
_top_level=$(echo $STORE | cut -d "/" -f 2 | xargs printf "/%s")
9+
410
for d in /*; do
11+
# skip STORE
12+
if [ "$d" = "${_top_level}" ]; then
13+
continue
14+
fi
515
# skip invalid symlinks, as they will break bwrap
616
if [ ! -L "$d" ] || [ -e "$d" ]; then
717
args+=("--dev-bind" "$d" "$d")
818
fi
919
done
10-
PS1="\[\e[36;1m\]build-env >>> \[\e[0m\]" bwrap "${args[@]}" "$@"
1120

21+
PS1="\[\e[36;1m\]build-env >>> \[\e[0m\]" bwrap "${args[@]}" "$@"

stackinator/etc/bwrap-store.sh

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
#!/bin/bash
2+
3+
set -euo pipefail
4+
5+
mkdir -p $STORE
6+
7+
bwrap --dev-bind / / \
8+
--bind ${BUILD_ROOT}/store $STORE \
9+
-- "$@"
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
#!/usr/bin/python3
2+
3+
import argparse
4+
import json
5+
import subprocess
6+
import pathlib
7+
import yaml
8+
9+
10+
def compiler_extra_attributes(name, prefix):
11+
"""Find paths to compiler"""
12+
if name == "gcc":
13+
cc = "gcc"
14+
cxx = "g++"
15+
f90 = "gfortran"
16+
elif name == "llvm":
17+
cc = "clang"
18+
cxx = "clang++"
19+
f90 = None
20+
elif name == "nvhpc":
21+
cc = "nvc"
22+
cxx = "nvc++"
23+
f90 = "nvfortran"
24+
else:
25+
# this is not a compiler
26+
return {}
27+
28+
def find(comp):
29+
p = subprocess.run(
30+
["find", prefix, "-name", f"{comp}", "-path", "*/bin/*"],
31+
shell=False,
32+
check=True,
33+
stdout=subprocess.PIPE,
34+
stderr=subprocess.PIPE,
35+
)
36+
return p.stdout.strip().decode("utf-8")
37+
38+
extra_attributes = {"extra_attributes": {"compilers": {"c": find(cc), "cxx": find(cxx)}}}
39+
if f90 is not None:
40+
extra_attributes["extra_attributes"]["compilers"]["fortran"] = find(f90)
41+
42+
return extra_attributes
43+
44+
45+
def gen_packages_impl(lock_file, env_path):
46+
spack_lock = json.load(open(lock_file, "r"))
47+
48+
packages = {"packages": {}}
49+
50+
for dd in spack_lock["roots"]:
51+
hash = dd["hash"]
52+
# call subprocess to find install dir
53+
spack_find_prefix = subprocess.run(
54+
["spack", "--color=never", "-e", env_path, "find", "--format={prefix}", f"/{hash}"],
55+
shell=False,
56+
check=True,
57+
stdout=subprocess.PIPE,
58+
stderr=subprocess.PIPE,
59+
)
60+
61+
spack_find_spec = subprocess.run(
62+
["spack", "--color=never", "-e", env_path, "find", "--format={name}|{version}|{variants}", f"/{hash}"],
63+
shell=False,
64+
check=True,
65+
stdout=subprocess.PIPE,
66+
stderr=subprocess.PIPE,
67+
)
68+
69+
name, version, variants = spack_find_spec.stdout.strip().decode("utf-8").split("|")
70+
prefix = spack_find_prefix.stdout.strip().decode("utf-8")
71+
72+
packages["packages"][name] = {
73+
"buildable": False,
74+
"externals": [
75+
{
76+
"spec": f"{name}@{version} {variants}",
77+
"prefix": prefix,
78+
}
79+
],
80+
}
81+
# add `extra_attributes` for compilers
82+
if name in ["gcc", "nvhpc", "llvm"]:
83+
extra_attributes = compiler_extra_attributes(name, prefix)
84+
packages["packages"][name]["externals"][0].update(extra_attributes)
85+
86+
return packages
87+
88+
89+
if __name__ == "__main__":
90+
# parse CLI arguments
91+
parser = argparse.ArgumentParser()
92+
parser.add_argument("--lock-file", help="spack.lock", type=str)
93+
parser.add_argument("--env-path", help="path to spack env", type=str)
94+
parser.add_argument("--view", help="path to spack view", type=str)
95+
96+
args = parser.parse_args()
97+
98+
packages = gen_packages_impl(args.lock_file, args.env_path)
99+
100+
dst = pathlib.Path(args.view) / "packages.yaml"
101+
with open(dst, "w") as f:
102+
yaml.dump(packages, f)
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
#!/bin/bash
2+
# Function to display usage
3+
usage() {
4+
echo "Usage: $0 --build-root=<build-root> --sqfs-images '<sqfs1>:<mnt1> <sqfs2>:<mnt2> ..' -- <command>"
5+
exit 1
6+
}
7+
8+
# Initialize variables
9+
BUILD_ROOT=""
10+
SQFS_IMAGES=""
11+
12+
# Parse options using getopt
13+
TEMP=$(getopt -o '' --long build-root: --long sqfs-images: -n "$0" -- "$@")
14+
if [ $? -ne 0 ]; then
15+
echo "Error parsing arguments" >&2
16+
usage
17+
fi
18+
19+
# Reset the positional parameters to the short options
20+
eval set -- "$TEMP"
21+
22+
# Extract options
23+
while true; do
24+
case "$1" in
25+
--build-root)
26+
BUILD_ROOT="$2"
27+
shift 2
28+
;;
29+
--sqfs-images)
30+
SQFS_IMAGES="$2"
31+
shift 2
32+
;;
33+
--)
34+
shift
35+
break
36+
;;
37+
*)
38+
echo "Unknown option: $1"
39+
usage
40+
;;
41+
esac
42+
done
43+
44+
if [ -z "$BUILD_ROOT" ]; then
45+
echo "Error: --build-root is required" >&2
46+
usage
47+
fi
48+
49+
if [ -z "$SQFS_IMAGES" ]; then
50+
# no images to mount, skip squashfs-mount
51+
exec "$@"
52+
fi
53+
54+
read -ra array <<<"$SQFS_IMAGES"
55+
56+
if [ ${#array[@]} -eq 0 ]; then
57+
echo "no mountpoints specified, skip squashfs-mount"
58+
exec "$@"
59+
fi
60+
61+
build_root_mounts=""
62+
for elem in "${array[@]}"; do
63+
mount_point=${elem#*:}
64+
sqfs=${elem%%:*}
65+
tmp_mount_point="${BUILD_ROOT}/tmp/mounts/${mount_point}"
66+
mkdir -p ${tmp_mount_point}
67+
build_root_mounts="${build_root_mounts} ${sqfs}:${tmp_mount_point}"
68+
done
69+
70+
squashfs-mount $build_root_mounts -- "$@"

0 commit comments

Comments
 (0)