diff --git a/.github/workflows/modules/append_module.lua b/.github/workflows/modules/append_module.lua new file mode 100644 index 00000000..e45cb640 --- /dev/null +++ b/.github/workflows/modules/append_module.lua @@ -0,0 +1,3 @@ +setenv("INSIDE_GITHUB_ACTIONS", "true") +-- Interfere with PATH so Lmod keeps a record +prepend_path("PATH", "/snap/bin") diff --git a/.github/workflows/modules/prepend_module.lua b/.github/workflows/modules/prepend_module.lua new file mode 100644 index 00000000..e45cb640 --- /dev/null +++ b/.github/workflows/modules/prepend_module.lua @@ -0,0 +1,3 @@ +setenv("INSIDE_GITHUB_ACTIONS", "true") +-- Interfere with PATH so Lmod keeps a record +prepend_path("PATH", "/snap/bin") diff --git a/.github/workflows/scripts/test_init_scripts.sh b/.github/workflows/scripts/test_init_scripts.sh index f543835c..509f71f4 100755 --- a/.github/workflows/scripts/test_init_scripts.sh +++ b/.github/workflows/scripts/test_init_scripts.sh @@ -11,11 +11,17 @@ if [ -z ${EXPECTED_EASYBUILD_VERSION} ]; then exit 1 fi +if [ -z ${EESSI_SOFTWARE_SUBDIR_OVERRIDE} ]; then + echo "\$EESSI_SOFTWARE_SUBDIR_OVERRIDE has to be set (e.g., x86_64/intel/haswell) so we can do well defined string comparison for the architecture." + exit 1 +fi + # initialize assert framework if [ ! -d assert.sh ]; then echo "assert.sh not cloned." echo "" echo "run \`git clone https://github.com/lehmannro/assert.sh.git\`" + echo "(see workflow file that calls this script for how to only clone specific commit if you are worried about security)" exit 1 fi . assert.sh/assert.sh @@ -28,9 +34,13 @@ for shell in ${SHELLS[@]}; do echo RUNNING TESTS FOR SHELL: $shell echo = | awk 'NF += (OFS = $_) + 100' if [[ ! " ${TEST_SHELLS[*]} " =~ [[:space:]]${shell}[[:space:]] ]]; then - ### EXCEPTION FOR CSH ### echo -e "\033[33mWe don't now how to test the shell '$shell', PRs are Welcome.\033[0m" else + if [ "$shell" = "csh" ]; then + # make sure our .cshrc is empty before we begin as we will clobber it + [ -f ~/.cshrc ] && mv ~/.cshrc ~/.cshrc_orig + fi + # TEST 1: Source Script and check Module Output expected="Module for EESSI/$EESSI_VERSION loaded successfully" assert "$shell -c 'source init/lmod/$shell' 2>&1 " "${expected}" @@ -45,11 +55,12 @@ for shell in ${SHELLS[@]}; do else MODULE_SECTIONS=($($shell -c "source init/lmod/$shell 2>/dev/null; module ov 2>&1 | grep -e '---'")) fi - PATTERN="/cvmfs/software\.eessi\.io/versions/$EESSI_VERSION/software/linux/x86_64/(intel/haswell|amd/zen3)/modules/all" + PATTERN="/cvmfs/software\.eessi\.io/versions/$EESSI_VERSION/software/linux/$EESSI_SOFTWARE_SUBDIR_OVERRIDE/modules/all" assert_raises 'echo "${MODULE_SECTIONS[1]}" | grep -E "$PATTERN"' + echo "${MODULE_SECTIONS[1]}" "$PATTERN" # TEST 3: Check if module overviews second section is the EESSI init module - assert "echo ${MODULE_SECTIONS[4]}" "/cvmfs/software.eessi.io/versions/$EESSI_VERSION/init/modules" + assert "echo ${MODULE_SECTIONS[4]}" "/cvmfs/software.eessi.io/init/modules" # TEST 4: Load EasyBuild module and check version # eb --version outputs: "This is EasyBuild 5.1.1 (framework: 5.1.1, easyblocks: 5.1.1) on host ..." @@ -69,12 +80,45 @@ for shell in ${SHELLS[@]}; do EASYBUILD_PATH=$($shell -c "source init/lmod/$shell 2>/dev/null; module load EasyBuild/${EXPECTED_EASYBUILD_VERSION}; which eb") fi # escape the dots in ${EASYBUILD_VERSION} - PATTERN="/cvmfs/software\.eessi\.io/versions/$EESSI_VERSION/software/linux/x86_64/(intel/haswell|amd/zen3)/software/EasyBuild/${EXPECTED_EASYBUILD_VERSION//./\\.}/bin/eb" + PATTERN="/cvmfs/software\.eessi\.io/versions/$EESSI_VERSION/software/linux/$EESSI_SOFTWARE_SUBDIR_OVERRIDE/software/EasyBuild/${EXPECTED_EASYBUILD_VERSION//./\\.}/bin/eb" echo "$EASYBUILD_PATH" | grep -E "$PATTERN" assert_raises 'echo "$EASYBUILD_PATH" | grep -E "$PATTERN"' + echo "$EASYBUILD_PATH" "$PATTERN" + + # TEST 6 and 7: Check the various options (EESSI_DEFAULT_MODULES_APPEND, EESSI_DEFAULT_MODULES_APPEND, EESSI_EXTRA_MODULEPATH) all work + if [ "$shell" = "csh" ]; then + echo "setenv EESSI_DEFAULT_MODULES_APPEND append_module" > ~/.cshrc + echo "setenv EESSI_DEFAULT_MODULES_PREPEND prepend_module" >> ~/.cshrc + echo "setenv EESSI_EXTRA_MODULEPATH .github/workflows/modules" >> ~/.cshrc + echo "source init/lmod/$shell" >> ~/.cshrc + TEST_LMOD_SYSTEM_DEFAULT_MODULES=$($shell -c 'echo $LMOD_SYSTEM_DEFAULT_MODULES') + TEST_MODULEPATH=$($shell -c 'echo $MODULEPATH') + elif [ "$shell" = "fish" ]; then + TEST_LMOD_SYSTEM_DEFAULT_MODULES=$($shell -c 'set -x EESSI_DEFAULT_MODULES_APPEND append_module ; set -x EESSI_DEFAULT_MODULES_PREPEND prepend_module ; set -x EESSI_EXTRA_MODULEPATH .github/workflows/modules ; source init/lmod/'"$shell"' 2>/dev/null; echo $LMOD_SYSTEM_DEFAULT_MODULES') + TEST_MODULEPATH=$($shell -c 'set -x EESSI_DEFAULT_MODULES_APPEND append_module ; set -x EESSI_DEFAULT_MODULES_PREPEND prepend_module ; set -x EESSI_EXTRA_MODULEPATH .github/workflows/modules ; source init/lmod/'"$shell"' 2>/dev/null; echo $MODULEPATH') + else + TEST_LMOD_SYSTEM_DEFAULT_MODULES=$($shell -c 'export EESSI_DEFAULT_MODULES_APPEND=append_module ; export EESSI_DEFAULT_MODULES_PREPEND=prepend_module ; export EESSI_EXTRA_MODULEPATH=.github/workflows/modules ; source init/lmod/'"$shell"' ; echo $LMOD_SYSTEM_DEFAULT_MODULES') + TEST_MODULEPATH=$($shell -c 'export EESSI_DEFAULT_MODULES_APPEND=append_module ; export EESSI_DEFAULT_MODULES_PREPEND=prepend_module ; export EESSI_EXTRA_MODULEPATH=.github/workflows/modules ; source init/lmod/'"$shell"' 2>/dev/null; echo $MODULEPATH') + fi + LMOD_SYSTEM_DEFAULT_MODULES_PATTERN='^prepend_module:.*:append_module$' + echo "$TEST_LMOD_SYSTEM_DEFAULT_MODULES" AND "$LMOD_SYSTEM_DEFAULT_MODULES_PATTERN" + assert_raises 'echo "$TEST_LMOD_SYSTEM_DEFAULT_MODULES" | grep -E "$LMOD_SYSTEM_DEFAULT_MODULES_PATTERN"' + if [ "$shell" = "fish" ]; then + MODULEPATH_PATTERN='\.github/workflows/modules$' + else + MODULEPATH_PATTERN=':\.github/workflows/modules$' + fi + echo "$TEST_MODULEPATH" AND "$MODULEPATH_PATTERN" + assert_raises 'echo "$TEST_MODULEPATH" | grep -E "$MODULEPATH_PATTERN"' # End Test Suite assert_end "source_eessi_$shell" + + if [ "$shell" = "csh" ]; then + # Restore our .cshrc + [ -f ~/.cshrc_orig ] && mv ~/.cshrc_orig ~/.cshrc + fi + fi done diff --git a/.github/workflows/tests_init_module.yml b/.github/workflows/tests_init_module.yml index b4d31435..902c31e3 100644 --- a/.github/workflows/tests_init_module.yml +++ b/.github/workflows/tests_init_module.yml @@ -46,8 +46,13 @@ jobs: sed -i "s/__EESSI_VERSION_DEFAULT__/${{matrix.EESSI_VERSION}}/g" init/lmod/${shell} done - - name: Clone assert.sh script - run: git clone https://github.com/lehmannro/assert.sh.git + - name: Clone assert.sh at pinned commit + run: | + ASSERT_COMMIT_SHA=fe359e341670f1e8e86a3804ca00e5a3ebc30fa4 + git clone --no-checkout https://github.com/lehmannro/assert.sh.git + cd assert.sh + git fetch --depth 1 origin $ASSERT_COMMIT_SHA + git checkout $ASSERT_COMMIT_SHA - name: Install missing shells run: | @@ -55,9 +60,20 @@ jobs: sudo apt install zsh ksh fish tcsh echo "# INIT ZSH" > ~/.zshrc - - name: Run tests for available shells + - name: Run tests for available shells without system Lmod run: | + export EESSI_SOFTWARE_SUBDIR_OVERRIDE=${{matrix.EESSI_SOFTWARE_SUBDIR_OVERRIDE}} + export EESSI_VERSION=${{matrix.EESSI_VERSION}} + export EXPECTED_EASYBUILD_VERSION=${{matrix.EXPECTED_EASYBUILD_VERSION}} + .github/workflows/scripts/test_init_scripts.sh "bash" "zsh" "ksh" "fish" "csh" + - name: Run tests for available shells with system Lmod + run: | + # We also want to perform the same test when there is an Lmod version available on the system + sudo apt install lmod + source /usr/share/lmod/lmod/init/bash + export MODULEPATH=/usr/share/lmod/lmod/modulefiles + module avail + export EESSI_SOFTWARE_SUBDIR_OVERRIDE=${{matrix.EESSI_SOFTWARE_SUBDIR_OVERRIDE}} export EESSI_VERSION=${{matrix.EESSI_VERSION}} export EXPECTED_EASYBUILD_VERSION=${{matrix.EXPECTED_EASYBUILD_VERSION}} .github/workflows/scripts/test_init_scripts.sh "bash" "zsh" "ksh" "fish" "csh" - diff --git a/init/lmod/bash b/init/lmod/bash index daba8351..2110400d 100644 --- a/init/lmod/bash +++ b/init/lmod/bash @@ -1,19 +1,91 @@ +#!/usr/bin/env bash + +# SPDX-License-Identifier: GPL-2.0-only +# Copyright (C) 2020-2026 EESSI contributors +# +# EESSI - European Environment for Scientific Software Installations +# +# This file is a template for initialising EESSI via Lmod for the environment indicated by the shebang. +# +# Assumptions: +# - EESSI accessible under $EESSI_CVMFS_REPO or /cvmfs/software.eessi.io +# - expected to be true as this file is also meant to be shipped under that location +# - Lmod must the shipped in the repository in the correct location +# +# Options: +# - The script listens to environment variables so that it can be silently configured by a site +# - EESSI_CVMFS_REPO: perform the initialisation from a respository other than /cvmfs/software.eessi.io +# - EESSI_VERSION: loads a specific EESSI version ignoring the default in the file +# - EESSI_DEFAULT_MODULES_PREPEND: environment variable allows you to prepend modules to the defaults (loaded last) +# - EESSI_DEFAULT_MODULES_APPEND: environment variable allows you to append modules to the defaults (loaded first) +# - EESSI_EXTRA_MODULEPATH: environment variable allows a site to append to MODULEPATH (lower priority than EESSI MODULEPATH) +# +# Other options that can be set to influence the end result: +# - The EESSI module also listens to environment variables so that it can be silently configured by a site +# - EESSI_MODULE_FAMILY_NAME: use the value of the environment variable to set an Lmod family for the EESSI module +# - EESSI_MODULE_STICKY: make the EESSI module sticky +# - EESSI_MODULE_UPDATE_PS1: have the EESSI module update PS1 to give a prompt that is prepended with "{EESSI/...} " +# +# Effects: +# - Should always succeed +# - Initialises Lmod from specific version of EESSI +# - Clobbers any existing Lmod configuration +# - Some special environment variables that are internal to Lmod (__LMOD_REF_COUNT_MODULEPATH and +# _ModuleTable001_) are used to force a hard reset of an existing Lmod installation. This +# approach may be brittle. +# - Then loads module EESSI/... to initialise EESSI +# - use `module show EESSI/...` to see the environment variables set by the EESSI module +# +# Reverting the effects: +# - EESSI initialisation via `module unload EESSI/...` +# - Lmod initialisation cannot be undone + # Choose an EESSI CVMFS repository EESSI_CVMFS_REPO="${EESSI_CVMFS_REPO:-/cvmfs/software.eessi.io}" -# Choose an EESSI version -EESSI_VERSION_DEFAULT="__EESSI_VERSION_DEFAULT__" + +# Choose an EESSI version (the default is only used if the EESSI_VERSION environment variable is not provided) +# (Note: in the repository which is home to this file a template value __EESSI_VERSION_DEFAULT__ is present in +# the line below which is replaced within our deployment pipeline.) +EESSI_VERSION_DEFAULT="${__EESSI_VERSION_USED_FOR_INIT:-__EESSI_VERSION_DEFAULT__}" EESSI_VERSION="${EESSI_VERSION:-${EESSI_VERSION_DEFAULT}}" -# Path to top-level module tree -export MODULEPATH="${EESSI_CVMFS_REPO}/versions/${EESSI_VERSION}/init/modules" -. "${EESSI_CVMFS_REPO}/versions/${EESSI_VERSION}/compat/linux/$(uname -m)/usr/share/Lmod/init/bash" +# On the first run we want to record the EESSI version used for init as an environment variable so that if a different +# version of this script is called (e.g, for a a different EESSI version) it retains a memory which EESSI +# version was actually used in the initialisation. This is useful as __Init_EESSI_Default_Modules used below will +# be defined on the first call and Lmod initialisation will not happen twice. +# This sets the value only on first execution, if the variable already exists in the environment +# the original value is retained. +export __EESSI_VERSION_USED_FOR_INIT="${__EESSI_VERSION_USED_FOR_INIT:-${EESSI_VERSION}}" + +# LMOD_SYSTEM_DEFAULT_MODULES are used by Lmod to load a default set of modules in the scenario +# - where we initialise Lmod (the if part of the clause below) +# - where we reset Lmod (the else part of the clause below) +# This means that if we call this script twice we will get the same end result: an Lmod installation +# with a set of default modules loaded. +# +# We also allow the ability to predefine elsewhere the default list of modules to load (colon separated): +# - EESSI_DEFAULT_MODULES_PREPEND environment variable allows you to prepend modules (loaded last) +# - EESSI_DEFAULT_MODULES_APPEND environment variable allows you to append modules (loaded first) +LMOD_SYSTEM_DEFAULT_MODULES="${EESSI_DEFAULT_MODULES_PREPEND:+$EESSI_DEFAULT_MODULES_PREPEND:}EESSI/$EESSI_VERSION${EESSI_DEFAULT_MODULES_APPEND:+:$EESSI_DEFAULT_MODULES_APPEND}" +export LMOD_SYSTEM_DEFAULT_MODULES + +if [ -z "$__Init_EESSI_Default_Modules" ]; then + export __Init_EESSI_Default_Modules=1; + + # Lmod version in 2023.06 has a problem with newer Lmod caches, so let's stick to more recent Lmod + # (has no effect except on Lmod itself, and compatible caches are still created/supported by EESSI) + LMOD_EESSI_VERSION=${EESSI_VERSION/2023.06/2025.06} -if [ -z "$__Init_Default_Modules" ]; then - export __Init_Default_Modules=1; + # Lmod may have been initialised so we need to clear some internal variables to allow for a full reset + # - make it forget about the system set MODULEPATH + unset __LMOD_REF_COUNT_MODULEPATH + # - and clear out any memory Lmod might have + unset _ModuleTable001_ - ## ability to predefine elsewhere the default list - LMOD_SYSTEM_DEFAULT_MODULES=${LMOD_SYSTEM_DEFAULT_MODULES:-"EESSI/$EESSI_VERSION"} - export LMOD_SYSTEM_DEFAULT_MODULES - module --initial_load --no_redirect restore + # Path to top-level module tree + # - EESSI_EXTRA_MODULEPATH environment variable allows a site to append to MODULEPATH (lower priority than EESSI MODULEPATH) + export MODULEPATH="${EESSI_CVMFS_REPO}/init/modules${EESSI_EXTRA_MODULEPATH:+:$EESSI_EXTRA_MODULEPATH}" + . "${EESSI_CVMFS_REPO}/versions/${LMOD_EESSI_VERSION}/compat/linux/$(uname -m)/usr/share/Lmod/init/bash" + module --initial_load --no_redirect restore else - module refresh + module reset fi diff --git a/init/lmod/csh b/init/lmod/csh index 2adb314c..a10836d1 100644 --- a/init/lmod/csh +++ b/init/lmod/csh @@ -1,24 +1,70 @@ +#!/usr/bin/env csh + +# SPDX-License-Identifier: GPL-2.0-only +# Copyright (C) 2020-2026 EESSI contributors +# +# EESSI - European Environment for Scientific Software Installations +# +# This file is a template for initialising EESSI via Lmod for the environment indicated by the shebang. +# +# Please refer to the reference bash implementation for full documentation, only minimal comments are included here + # Choose an EESSI CVMFS repository -if (! $?EESSI_CVMFS_REPO) then +if ( ! $?EESSI_CVMFS_REPO) then set EESSI_CVMFS_REPO = "/cvmfs/software.eessi.io" endif -# Choose an EESSI version -setenv EESSI_VERSION_DEFAULT "__EESSI_VERSION_DEFAULT__" -if (! $?EESSI_VERSION) then - set EESSI_VERSION = "${EESSI_VERSION_DEFAULT}" + +# Choose an EESSI version (default is used if EESSI_VERSION is not provided) +if ( ! $?__EESSI_VERSION_USED_FOR_INIT ) then + set EESSI_VERSION_DEFAULT = "__EESSI_VERSION_DEFAULT__" +else + set EESSI_VERSION_DEFAULT = "$__EESSI_VERSION_USED_FOR_INIT" +endif +if ( ! $?EESSI_VERSION ) then + set EESSI_VERSION = "$EESSI_VERSION_DEFAULT" +endif +# On first run, record the EESSI version used for init as an environment variable. +# We use setenv to ensure it is available to child processes (equivalent to export). +if ( ! $?__EESSI_VERSION_USED_FOR_INIT ) then + setenv __EESSI_VERSION_USED_FOR_INIT "$EESSI_VERSION" endif -# Path to top-level module tree -setenv MODULEPATH "${EESSI_CVMFS_REPO}/versions/${EESSI_VERSION}/init/modules" -source "${EESSI_CVMFS_REPO}/versions/${EESSI_VERSION}/compat/linux/`uname -m`/usr/share/Lmod/init/csh" -if (! $?__Init_Default_Modules ) then - setenv __Init_Default_Modules 1 +# ability to predefine elsewhere the default list (with options to append or prepend) +set LMOD_SYSTEM_DEFAULT_MODULES = "EESSI/${EESSI_VERSION}" +if ( $?EESSI_DEFAULT_MODULES_PREPEND ) then + set LMOD_SYSTEM_DEFAULT_MODULES = "${EESSI_DEFAULT_MODULES_PREPEND}:${LMOD_SYSTEM_DEFAULT_MODULES}" +endif +if ( $?EESSI_DEFAULT_MODULES_APPEND ) then + set LMOD_SYSTEM_DEFAULT_MODULES = "${LMOD_SYSTEM_DEFAULT_MODULES}:${EESSI_DEFAULT_MODULES_APPEND}" +endif +setenv LMOD_SYSTEM_DEFAULT_MODULES "${LMOD_SYSTEM_DEFAULT_MODULES}" + +if ( ! $?__Init_EESSI_Default_Modules ) then + setenv __Init_EESSI_Default_Modules 1 - # ability to predefine elsewhere the default list - if (! $?LMOD_SYSTEM_DEFAULT_MODULES) then - setenv LMOD_SYSTEM_DEFAULT_MODULES "EESSI/${EESSI_VERSION}" + # Lmod version in 2023.06 has a problem with newer Lmod caches, so let's stick to more recent Lmod + # (has no effect except on Lmod itself, and compatible caches are still created/supported by EESSI) + set LMOD_EESSI_VERSION = "${EESSI_VERSION}" + if ( "${LMOD_EESSI_VERSION}" == "2023.06" ) then + set LMOD_EESSI_VERSION = "2025.06" endif + + # If there is a local Lmod, make it forget about the system set MODULEPATH + unsetenv __LMOD_REF_COUNT_MODULEPATH + # and clear out any memory Lmod might have + unsetenv _ModuleTable001_ + # Path to top-level module tree + set modulepath = "${EESSI_CVMFS_REPO}/init/modules" + if ( $?EESSI_EXTRA_MODULEPATH ) then + # Now that we know it exists, check IF it is not empty + if ( "$EESSI_EXTRA_MODULEPATH" != "" ) then + set modulepath = "${modulepath}:${EESSI_EXTRA_MODULEPATH}" + endif + endif + setenv MODULEPATH "$modulepath" + source "${EESSI_CVMFS_REPO}/versions/${LMOD_EESSI_VERSION}/compat/linux/`uname -m`/usr/share/Lmod/init/csh" + module --initial_load --no_redirect restore else - module refresh + module reset endif diff --git a/init/lmod/fish b/init/lmod/fish index 9e595441..881e6262 100644 --- a/init/lmod/fish +++ b/init/lmod/fish @@ -1,18 +1,62 @@ +#!/usr/bin/env fish + +# SPDX-License-Identifier: GPL-2.0-only +# Copyright (C) 2020-2026 EESSI contributors +# +# EESSI - European Environment for Scientific Software Installations +# +# This file is a template for initialising EESSI via Lmod for the environment indicated by the shebang. +# +# Please refer to the reference bash implementation for full documentation, only minimal comments are included here + # Choose an EESSI CVMFS repository set EESSI_CVMFS_REPO (set -q EESSI_CVMFS_REPO; and echo "$EESSI_CVMFS_REPO"; or echo "/cvmfs/software.eessi.io") + # Choose an EESSI version -set EESSI_VERSION_DEFAULT "__EESSI_VERSION_DEFAULT__" -set EESSI_VERSION (set -q EESSI_VERSION; and echo "$EESSI_VERSION"; or echo "$EESSI_VERSION_DEFAULT") -# Path to top-level module tree -set -x MODULEPATH "$EESSI_CVMFS_REPO"/versions/"$EESSI_VERSION"/init/modules -. "$EESSI_CVMFS_REPO"/versions/"$EESSI_VERSION"/compat/linux/(uname -m)/usr/share/Lmod/init/fish - -if test -z "$__Init_Default_Modules" - export __Init_Default_Modules=1; - - ## ability to predefine elsewhere the default list - set -x LMOD_SYSTEM_DEFAULT_MODULES (set -q LMOD_SYSTEM_DEFAULT_MODULE; and echo "$LMOD_SYSTEM_DEFAULT_MODULE"; or echo "EESSI/$EESSI_VERSION") - module --initial_load --no_redirect restore +if not set -q __EESSI_VERSION_USED_FOR_INIT + set EESSI_VERSION_DEFAULT "__EESSI_VERSION_DEFAULT__" +else + set EESSI_VERSION_DEFAULT "$__EESSI_VERSION_USED_FOR_INIT" +end +if not set -q EESSI_VERSION + set EESSI_VERSION "$EESSI_VERSION_DEFAULT" +end + +# Record version used for init; -x exports it to the environment +if not set -q __EESSI_VERSION_USED_FOR_INIT + set -x __EESSI_VERSION_USED_FOR_INIT "$EESSI_VERSION" +end + +# ability to predefine elsewhere the default list (with options to append or prepend) +set LMOD_SYSTEM_DEFAULT_MODULES "EESSI/$EESSI_VERSION" +if set -q EESSI_DEFAULT_MODULES_PREPEND + set LMOD_SYSTEM_DEFAULT_MODULES "$EESSI_DEFAULT_MODULES_PREPEND:$LMOD_SYSTEM_DEFAULT_MODULES" +end +if set -q EESSI_DEFAULT_MODULES_APPEND + set LMOD_SYSTEM_DEFAULT_MODULES "$LMOD_SYSTEM_DEFAULT_MODULES:$EESSI_DEFAULT_MODULES_APPEND" +end +set -x LMOD_SYSTEM_DEFAULT_MODULES $LMOD_SYSTEM_DEFAULT_MODULES + +if test -z "$__Init_EESSI_Default_Modules" + set -x __Init_EESSI_Default_Modules 1 + + # Lmod version in 2023.06 has a problem with newer Lmod caches, so let's stick to more recent Lmod + # (has no effect except on Lmod itself, and compatible caches are still created/supported by EESSI) + set LMOD_EESSI_VERSION (string replace 2023.06 2025.06 -- $EESSI_VERSION) + + # If there is a local Lmod, make it forget about the system set MODULEPATH + set -e __LMOD_REF_COUNT_MODULEPATH + # and clear out any memory Lmod might have + set -e _ModuleTable001_ + # Path to top-level module tree + set modulepath "$EESSI_CVMFS_REPO/init/modules" + if set -q EESSI_EXTRA_MODULEPATH; and test -n "$EESSI_EXTRA_MODULEPATH" + set modulepath "$modulepath:$EESSI_EXTRA_MODULEPATH" + end + set -x MODULEPATH $modulepath + . "$EESSI_CVMFS_REPO"/versions/"$LMOD_EESSI_VERSION"/compat/linux/(uname -m)/usr/share/Lmod/init/fish + + module --initial_load --no_redirect restore else - module refresh + module reset end diff --git a/init/lmod/ksh b/init/lmod/ksh index ebf4c0ca..37c3caff 100644 --- a/init/lmod/ksh +++ b/init/lmod/ksh @@ -1,19 +1,48 @@ +#!/usr/bin/env ksh + +# SPDX-License-Identifier: GPL-2.0-only +# Copyright (C) 2020-2026 EESSI contributors +# +# EESSI - European Environment for Scientific Software Installations +# +# This file is a template for initialising EESSI via Lmod for the environment indicated by the shebang. +# +# Please refer to the reference bash implementation for full documentation, only minimal comments are included here + # Choose an EESSI CVMFS repository EESSI_CVMFS_REPO="${EESSI_CVMFS_REPO:-/cvmfs/software.eessi.io}" -# Choose an EESSI version -EESSI_VERSION_DEFAULT="__EESSI_VERSION_DEFAULT__" + +# Choose an EESSI version (the default is only used if the EESSI_VERSION environment variable is not provided) +EESSI_VERSION_DEFAULT="${__EESSI_VERSION_USED_FOR_INIT:-__EESSI_VERSION_DEFAULT__}" EESSI_VERSION="${EESSI_VERSION:-${EESSI_VERSION_DEFAULT}}" -# Path to top-level module tree -export MODULEPATH="${EESSI_CVMFS_REPO}/versions/${EESSI_VERSION}/init/modules" -. "${EESSI_CVMFS_REPO}/versions/${EESSI_VERSION}/compat/linux/$(uname -m)/usr/share/Lmod/init/ksh" +# On the first run we want to record the EESSI version used for init as an environment variable so that if a different +# version of this script is called (e.g, for a a different EESSI version) it retains a memory which EESSI +# version was actually used in the initialisation. This is useful as __Init_EESSI_Default_Modules used below will +# be defined on the first call and Lmod initialisation will not happen twice. +# This sets the value only on first execution, if the variable already exists in the environment +# the original value is retained. +export __EESSI_VERSION_USED_FOR_INIT="${__EESSI_VERSION_USED_FOR_INIT:-${EESSI_VERSION}}" + +# ability to predefine elsewhere the default list (with options to append or prepend) +LMOD_SYSTEM_DEFAULT_MODULES="${EESSI_DEFAULT_MODULES_PREPEND:+$EESSI_DEFAULT_MODULES_PREPEND:}EESSI/$EESSI_VERSION${EESSI_DEFAULT_MODULES_APPEND:+:$EESSI_DEFAULT_MODULES_APPEND}" +export LMOD_SYSTEM_DEFAULT_MODULES + +if [ -z "$__Init_EESSI_Default_Modules" ]; then + export __Init_EESSI_Default_Modules=1; + + # Lmod version in 2023.06 has a problem with newer Lmod caches, so let's stick to more recent Lmod + # (has no effect except on Lmod itself, and compatible caches are still created/supported by EESSI) + LMOD_EESSI_VERSION=${EESSI_VERSION/2023.06/2025.06} -if [ -z "$__Init_Default_Modules" ]; then - export __Init_Default_Modules=1; + # If there is a local Lmod, make it forget about the system set MODULEPATH + unset __LMOD_REF_COUNT_MODULEPATH + # and clear out any memory Lmod might have + unset _ModuleTable001_ + # Path to top-level module tree + export MODULEPATH="${EESSI_CVMFS_REPO}/init/modules${EESSI_EXTRA_MODULEPATH:+:$EESSI_EXTRA_MODULEPATH}" + . "${EESSI_CVMFS_REPO}/versions/${LMOD_EESSI_VERSION}/compat/linux/$(uname -m)/usr/share/Lmod/init/ksh" - ## ability to predefine elsewhere the default list - LMOD_SYSTEM_DEFAULT_MODULES=${LMOD_SYSTEM_DEFAULT_MODULES:-"EESSI/$EESSI_VERSION"} - export LMOD_SYSTEM_DEFAULT_MODULES - module --initial_load --no_redirect restore + module --initial_load --no_redirect restore else - module refresh + module reset fi diff --git a/init/lmod/zsh b/init/lmod/zsh index dfdff0c7..f7c0fc25 100644 --- a/init/lmod/zsh +++ b/init/lmod/zsh @@ -1,19 +1,48 @@ +#!/usr/bin/env zsh + +# SPDX-License-Identifier: GPL-2.0-only +# Copyright (C) 2020-2026 EESSI contributors +# +# EESSI - European Environment for Scientific Software Installations +# +# This file is a template for initialising EESSI via Lmod for the environment indicated by the shebang. +# +# Please refer to the reference bash implementation for full documentation, only minimal comments are included here + # Choose an EESSI CVMFS repository EESSI_CVMFS_REPO="${EESSI_CVMFS_REPO:-/cvmfs/software.eessi.io}" -# Choose an EESSI version -EESSI_VERSION_DEFAULT="__EESSI_VERSION_DEFAULT__" + +# Choose an EESSI version (the default is only used if the EESSI_VERSION environment variable is not provided) +EESSI_VERSION_DEFAULT="${__EESSI_VERSION_USED_FOR_INIT:-__EESSI_VERSION_DEFAULT__}" EESSI_VERSION="${EESSI_VERSION:-${EESSI_VERSION_DEFAULT}}" -# Path to top-level module tree -export MODULEPATH="${EESSI_CVMFS_REPO}/versions/${EESSI_VERSION}/init/modules" -. "${EESSI_CVMFS_REPO}/versions/${EESSI_VERSION}/compat/linux/$(uname -m)/usr/share/Lmod/init/zsh" +# On the first run we want to record the EESSI version used for init as an environment variable so that if a different +# version of this script is called (e.g, for a a different EESSI version) it retains a memory which EESSI +# version was actually used in the initialisation. This is useful as __Init_EESSI_Default_Modules used below will +# be defined on the first call and Lmod initialisation will not happen twice. +# This sets the value only on first execution, if the variable already exists in the environment +# the original value is retained. +export __EESSI_VERSION_USED_FOR_INIT="${__EESSI_VERSION_USED_FOR_INIT:-${EESSI_VERSION}}" + +# ability to predefine elsewhere the default list (with options to append or prepend) +LMOD_SYSTEM_DEFAULT_MODULES="${EESSI_DEFAULT_MODULES_PREPEND:+$EESSI_DEFAULT_MODULES_PREPEND:}EESSI/$EESSI_VERSION${EESSI_DEFAULT_MODULES_APPEND:+:$EESSI_DEFAULT_MODULES_APPEND}" +export LMOD_SYSTEM_DEFAULT_MODULES + +if [ -z "$__Init_EESSI_Default_Modules" ]; then + export __Init_EESSI_Default_Modules=1; + + # Lmod version in 2023.06 has a problem with newer Lmod caches, so let's stick to more recent Lmod + # (has no effect except on Lmod itself, and compatible caches are still created/supported by EESSI) + LMOD_EESSI_VERSION=${EESSI_VERSION/2023.06/2025.06} -if [ -z "$__Init_Default_Modules" ]; then - export __Init_Default_Modules=1; + # If there is a local Lmod, make it forget about the system set MODULEPATH + unset __LMOD_REF_COUNT_MODULEPATH + # and clear out any memory Lmod might have + unset _ModuleTable001_ + # Path to top-level module tree + export MODULEPATH="${EESSI_CVMFS_REPO}/init/modules${EESSI_EXTRA_MODULEPATH:+:$EESSI_EXTRA_MODULEPATH}" + . "${EESSI_CVMFS_REPO}/versions/${LMOD_EESSI_VERSION}/compat/linux/$(uname -m)/usr/share/Lmod/init/zsh" - ## ability to predefine elsewhere the default list - LMOD_SYSTEM_DEFAULT_MODULES=${LMOD_SYSTEM_DEFAULT_MODULES:-"EESSI/$EESSI_VERSION"} - export LMOD_SYSTEM_DEFAULT_MODULES - module --initial_load --no_redirect restore + module --initial_load --no_redirect restore else - module refresh + module reset fi