diff --git a/bin/yashchiki b/bin/yashchiki index 90cd7a5ba6425920443a3c52ab199045d97bab33..b56d83f21c66846d1e06ef85f8a08829790fc3d7 100755 --- a/bin/yashchiki +++ b/bin/yashchiki @@ -167,6 +167,7 @@ env = os.environ.copy() env.update({ "DOCKER_BASE_IMAGE": config["docker_base_image"], "BUILD_BASE_SANDBOX": str(int(config["build_base_sandbox"])), + "SPACK_ENVIRONMENT": str(int(config["spack_environment"])), # This needs to be here because otherwise the default python # (2.7.18) will pollute the spec and lead to a conflict # can be removed as soon as the explicit preferred version diff --git a/lib/yashchiki/commons.sh b/lib/yashchiki/commons.sh index a770878dca8d089a4459939e886e1e885a8a02a1..aa2c6c46a6864156e79b88dc822a31ce79626fc7 100755 --- a/lib/yashchiki/commons.sh +++ b/lib/yashchiki/commons.sh @@ -237,6 +237,15 @@ get_specfile_name() { awk '{ print "spec_" $1 ".yaml" }')" } +# Get the name of given environment, should only be called if one does not +# depend on the specfile existing or having correct content, see +# get_specfiles(). +get_specfile_name_for_environment() { + echo -n "${SPEC_FOLDER}/$(echo "environment_$1" | sha256sum | + awk '{ print "spec_" $1 ".yaml" }')" +} + + # Compute the concrete specfile for the given packages. # # Spec files are only computed once and afterwards their names are emitted via @@ -291,13 +300,38 @@ get_specfiles() { done } +# cf. get_specfiles but for spack environments +get_specfiles_for_environments() { + local specfiles=() + + for environment in "${@}"; do + # compute spec and put into temporary file derived from package name + specfiles+=("$(get_specfile_name_for_environment "${environment}")") + done + + ( + local idx=0 + for package in "${@}"; do + if [ ! -f "${specfiles[${idx}]}" ]; then + echo "${MY_SPACK_CMD} -e \"${environment}\" spec -y > ${specfiles[${idx}]}" + fi + idx=$((idx + 1)) + done + ) | parallel -r -j${YASHCHIKI_JOBS} 1>/dev/null + + for f in "${specfiles[@]}"; do + echo "${f}" + done +} + # Usage: install_from_buildcache PACKAGE... # # Install the given set of packages from yashchiki's buildcache. install_from_buildcache() { local install_failed=0 ( - _install_from_buildcache "${@}" + specfiles=$(_get_specfiles_for_packages_to_install "${@}") + install_from_buildcache_from_specfiles "${specfiles}" ) || install_failed=1 if (( install_failed == 1 )); then @@ -306,7 +340,20 @@ install_from_buildcache() { fi } -_install_from_buildcache() { +install_environment_from_buildcache() { + local install_failed=0 + ( + specfiles=$(_get_specfiles_for_environments_to_install "${@}") + install_from_buildcache_from_specfiles "${specfiles}" + ) || install_failed=1 + + if (( install_failed == 1 )); then + echo "Error during builcache install!" >&2 + exit 1 + fi +} + +_get_specfiles_for_packages_to_install() { # only extract the hashes present in buildcache on first invocation size_file_hashes=0 if [ -e "${FILE_HASHES_BUILDCACHE}" ]; then @@ -319,10 +366,35 @@ _install_from_buildcache() { local specfiles=() local packages_to_install=("${@}") readarray -t specfiles < <(get_specfiles "${packages_to_install[@]}") + echo "${specfiles[@]}" +} + +_get_specfiles_for_environments_to_install() { + # only extract the hashes present in buildcache on first invocation + size_file_hashes=0 + if [ -e "${FILE_HASHES_BUILDCACHE}" ]; then + size_file_hashes="$(wc -l <"${FILE_HASHES_BUILDCACHE}")" + fi + if (( "${size_file_hashes}" == 0 )); then + compute_hashes_buildcache + fi + + local specfiles=() + local environments_to_install=("${@}") + readarray -t specfiles < <(get_specfiles_for_environments "${environments_to_install[@]}") + echo "${specfiles[@]}" +} + +# Usage: install_from_buildcache_from_specfiles SPECFILES… +# +# Install the packages specified in the specfiles from yashchiki's buildcache. +install_from_buildcache_from_specfiles() { + local specfiles=("${@}") # check again that specfiles are not empty - otherwise a concretization failed echo "DEBUG: Checking specfiles for ${packages_to_install[*]}" >&2 for spec in "${specfiles[@]}"; do + # FIXME: check if file exists? if (( $(wc -l <"${spec}") == 0 )); then echo "One of the following specs failed to concretize: " \ "${packages_to_install[@]}" >&2 diff --git a/lib/yashchiki/fetch.sh b/lib/yashchiki/fetch.sh index 9c6c7fe1f1bb4ab475d17c66a2f44e34ad5191f9..1fb4f094a64be00fe9fc9bd9be18801f4f1ca668 100755 --- a/lib/yashchiki/fetch.sh +++ b/lib/yashchiki/fetch.sh @@ -124,6 +124,23 @@ done # wait for all spawned jobs to complete wait +if [ -n "${SPACK_ENVIRONMENT:-}" ]; then + echo "Using spack environment" + ${MY_SPACK_CMD} env remove -y default || true # FIXME: drop + ${MY_SPACK_CMD} env create default + # FIXME: via style config! + rsync -a ${SPACK_ENVIRONMENT_REPO}/. ${YASHCHIKI_SPACK_PATH}/var/spack/environments/default + echo "Created spack environment, now concretizing... " + # FIXME: track concretizer errors here: + ( + # FIXME: can we hash something to get a reproducible non-static specfile name? + specfile="env_specfile"; + # FIXME: style config! + ${MY_SPACK_CMD} -e default --test=root --fresh concretize && + ${MY_SPACK_CMD} -e default spec -y > "${specfile}" + ) && echo "done." || (echo "FAILED."; exit 1) +fi + # verify that all concretizations were successful if (( $(cat "${tmpfiles_concretize_err[@]}" | wc -l) > 0 )); then { @@ -169,6 +186,15 @@ for package in "${packages_to_fetch[@]}"; do fi fetch_specfiles+=( "${specfile}" ) done + +if [ -n "${SPACK_ENVIRONMENT:-}" ]; then + # spack fetch doesn't like proper multi-doc separators (---) + csplit -z --prefix=env_specfile_split --suffix-format=%02d.yaml ./env_specfile.yaml /---/ '{*}' + for split_specfile in ./env_specfile_split*.yaml; do + fetch_specfiles+=( ${split_specfile} ) + done +fi + if ! ${MY_SPACK_CMD} fetch -D "${fetch_specfiles[@]/^/-f }"; then # propagate error exit 1 diff --git a/lib/yashchiki/install_spack_packages.sh b/lib/yashchiki/install_spack_packages.sh index f3350d0c4f3212547e4a2c43dd94194ac8113029..c655785b1545ffbc550463fd866977e62bebff20 100755 --- a/lib/yashchiki/install_spack_packages.sh +++ b/lib/yashchiki/install_spack_packages.sh @@ -13,6 +13,8 @@ cd "$HOME" install_from_buildcache "${spack_packages[@]+"${spack_packages[@]}"}" +# FIXME: install_from_buildcache for environments! + echo "INSTALLING PACKAGES" # heurisitic: let's use -j 8 typically… (and parallelize spack builds) SPACK_INSTALL_PARALLELISM=1 # ECM (2024-09-16): disabled $(( (${YASHCHIKI_JOBS} - 8) / 8 + 1)) @@ -34,6 +36,16 @@ for package in "${spack_packages[@]+"${spack_packages[@]}"}"; do wait done +# Install stuff for environments +if [ -n "${SPACK_ENVIRONMENT:-}" ]; then + echo "Installing: environment \"default\" (parallelism factor ${SPACK_INSTALL_PARALLELISM})" >&2 + # FIXME: specfile not needed if concretized in fetch step + for i in `seq 1 ${SPACK_INSTALL_PARALLELISM}`; do + (nohup ${MY_SPACK_CMD} "${SPACK_ARGS_INSTALL[@]+"${SPACK_ARGS_INSTALL[@]}"}" -e default install -j $(( (${YASHCHIKI_JOBS} - ${SPACK_INSTALL_PARALLELISM}) / ${SPACK_INSTALL_PARALLELISM} + 1 )) --fresh --no-cache --show-log-on-error | sed -e "s:^:[ENV-default-${i}] :g") & + done + wait +fi + # create the filesystem views (exposed via singularity --app option) echo "CREATING VIEWS OF META PACKAGES" >&2 cd ${MY_SPACK_FOLDER}