Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .github/workflows/modules/append_module.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
setenv("INSIDE_GITHUB_ACTIONS", "true")
-- Interfere with PATH so Lmod keeps a record
prepend_path("PATH", "/snap/bin")
3 changes: 3 additions & 0 deletions .github/workflows/modules/prepend_module.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
setenv("INSIDE_GITHUB_ACTIONS", "true")
-- Interfere with PATH so Lmod keeps a record
prepend_path("PATH", "/snap/bin")
52 changes: 48 additions & 4 deletions .github/workflows/scripts/test_init_scripts.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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}"
Expand All @@ -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 ..."
Expand All @@ -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

Expand Down
24 changes: 20 additions & 4 deletions .github/workflows/tests_init_module.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,18 +46,34 @@ 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: |
sudo apt update
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"

96 changes: 84 additions & 12 deletions init/lmod/bash
Original file line number Diff line number Diff line change
@@ -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
74 changes: 60 additions & 14 deletions init/lmod/csh
Original file line number Diff line number Diff line change
@@ -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
Loading