Skip to content

Commit beec303

Browse files
committed
adding PR handling, build and comparison of modules and envs
1 parent 58277ab commit beec303

File tree

1 file changed

+183
-59
lines changed

1 file changed

+183
-59
lines changed

modules/module_check.sh

Lines changed: 183 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -1,79 +1,203 @@
11
#!/bin/bash
2-
# Start interactive shell to access EESSI through build container
3-
# mkdir -p /tmp/$USER/EESSI
4-
# cd /tmp/$USER/EESSI
5-
# git clone https://github.com/EESSI/software-layer
6-
# cd software-layer
7-
# ./eessi_container.sh
8-
9-
# Initialize EESSI + load/configure EasyBuild
10-
# source /cvmfs/software.eessi.io/versions/2023.06/init/bash
11-
# module load EasyBuild/4.9.2
12-
# export WORKDIR=/tmp/$USER/EESSI
13-
# source configure_easybuild
14-
15-
# .eb directory as an argument
16-
if [ -z "$1" ]; then
17-
echo "Usage: $0 <directory>"
2+
3+
# This script checks the consistency of EB-generated modules and identifies broken or missing modules.
4+
# Usage: ./module_check.sh <path to easystack file> [<optional path to PR diff>]
5+
6+
# It uses an adapted approach from check_missing_installations.sh to handling PRs/unmerged PRs
7+
TOPDIR=$(dirname $(realpath $0))
8+
9+
if [ "$#" -eq 1 ]; then
10+
echo "No PR diff provided. Processing all modules in the easystack file."
11+
pr_exceptions=""
12+
elif [ "$#" -eq 2 ]; then
13+
echo "Using $2 to create exceptions for PR filtering of easystack"
14+
pr_diff="$2"
15+
pr_exceptions=$(grep '^+' "$pr_diff" | grep 'from-pr' | uniq | awk '{print $3}' | xargs -I {} echo " || /'{}'/")
16+
else
17+
echo "ERROR: Usage: $0 <path to easystack file> [<optional path to PR diff>]" >&2
1818
exit 1
1919
fi
2020

21-
base_dir="$1"
21+
easystack="$1"
22+
23+
LOCAL_TMPDIR=$(mktemp -d)
24+
mkdir -p "$LOCAL_TMPDIR"
25+
26+
# Clone the develop branch of EasyBuild and use that to search for easyconfigs
27+
git clone -b develop https://github.com/easybuilders/easybuild-easyconfigs.git $LOCAL_TMPDIR/easyconfigs
28+
export EASYBUILD_ROBOT_PATHS=$LOCAL_TMPDIR/easyconfigs/easybuild/easyconfigs
2229

23-
# Dir where the modules will be
24-
module_install_dir="/tmp/$USER/EESSI/module-only"
30+
# All PRs used in EESSI are supposed to be merged, so we can strip ou all cases of from-pr
31+
tmp_easystack="${LOCAL_TMPDIR}/$(basename "${easystack}")"
32+
grep -v 'from-pr' "${easystack}" > "${tmp_easystack}"
33+
34+
# If PR exceptions exist, modify the easystack file to include exceptions
35+
if [ -n "$pr_exceptions" ]; then
36+
# Use awk to exclude lines containing PR numbers specified in pr_exceptions
37+
awk_command="awk '!/from-pr/ EXCEPTIONS' ${easystack}"
38+
awk_command=${awk_command/\\/}
39+
eval "${awk_command/EXCEPTIONS/$pr_exceptions}" > "${tmp_easystack}"
40+
fi
2541

26-
locks_dir="/tmp/$USER/EESSI/locks"
42+
# Set up temporary directories for module installation and lock files
43+
TMPDIR=${TMPDIR:-/tmp}/$USER
44+
module_install_dir="$TMPDIR/EESSI/module-only"
45+
locks_dir="$TMPDIR/EESSI/locks"
46+
mkdir -p "$module_install_dir" "$locks_dir"
2747

28-
# Log file to record broken modules
48+
# Log file to record broken modules
2949
broken_modules_log="broken_modules.log"
30-
> $broken_modules_log
50+
> "$broken_modules_log"
3151

52+
# To keep track of already-checked modules and avoid re-checking
3253
declare -A checked_modules
3354

34-
# Locate all .eb files within the base dir
35-
easyconfig_files=$(find $base_dir -name "*.eb")
55+
# Identify missing easyconfigs based on the temporary easystack file
56+
echo "Identifying missing easyconfigs using the temporary easystack file..."
57+
missing_easyconfigs=$(eb --easystack "${tmp_easystack}" --missing --robot 2>&1)
3658

37-
# Iterate over all eb files found. Package name based on eb file name
38-
for easyconfig_file in $easyconfig_files; do
39-
package_name=$(basename $easyconfig_file .eb)
59+
if [ -z "$missing_easyconfigs" ]; then
60+
echo "No missing easyconfigs to install."
61+
rm -rf "$LOCAL_TMPDIR"
62+
exit 0
63+
fi
64+
65+
# Process each missing easyconfig file
66+
for easyconfig_file in $missing_easyconfigs; do
67+
package_name=$(basename "$easyconfig_file" .eb)
68+
69+
# Building of the easyconfig
70+
echo "Building $package_name using EasyBuild..."
71+
eb "$easyconfig_file" --robot
72+
if [ $? -ne 0 ]; then
73+
echo "EasyBuild build failed for $package_name. Skipping..."
74+
echo "$package_name: EasyBuild build failed" >> "$broken_modules_log"
75+
continue
76+
fi
4077

41-
# Run EB to generate the modules. Check if the eb command failed.
42-
echo "Generating modules for $package_name using EasyBuild..."
43-
eb $easyconfig_file --module-only --installpath-modules $module_install_dir --locks-dir $locks_dir --force --robot
78+
# Generate the module using --module-only
79+
echo "Generating module for $package_name using --module-only..."
80+
eb "$easyconfig_file" --module-only --installpath-modules "$module_install_dir" --locks-dir "$locks_dir" --force --robot
4481
if [ $? -ne 0 ]; then
45-
echo "EasyBuild command failed for $package_name. Skipping..."
46-
echo "$package_name: EasyBuild command failed" >> $broken_modules_log
82+
echo "EasyBuild --module-only command failed for $package_name. Skipping..."
83+
echo "$package_name: EasyBuild --module-only command failed" >> "$broken_modules_log"
84+
continue
85+
fi
86+
87+
# Find the module file generated from the build
88+
module_relpath=$(eb "$easyconfig_file" --show-module --robot 2>/dev/null)
89+
if [ -z "$module_relpath" ]; then
90+
echo "Failed to get module relative path for $package_name"
91+
echo "$package_name: Failed to get module relative path" >> "$broken_modules_log"
92+
continue
93+
fi
94+
95+
# Modules names and version
96+
module_software=$(echo "$module_relpath" | sed 's/\.lua$//')
97+
98+
# Check if the module has already been validated to avoid redundant checks
99+
if [ -n "${checked_modules[$module_software]}" ]; then
100+
echo "Module $module_software already checked. Skipping."
47101
continue
48102
fi
49103

50-
# Check the generated modules and iterate over the modules in the 'all' dir
51-
echo "Checking generated modules for $package_name..."
52-
for module_category in $(ls $module_install_dir/all); do
53-
for module_version in $(ls $module_install_dir/all/$module_category); do
54-
module_name="$module_category/$module_version"
55-
56-
# Checks if the module has already been tested
57-
if [ -n "${checked_modules[$module_name]}" ]; then
58-
echo "Module $module_name already checked. Skipping."
59-
continue
60-
fi
61-
62-
echo "Testing module: $module_name"
63-
64-
# Try loading the module
65-
if module --ignore_cache load $module_name 2>/dev/null; then
66-
echo "$module_name loaded successfully."
67-
module unload $module_name
68-
else
69-
echo "$module_name is broken."
70-
echo "$package_name: $module_name" >> $broken_modules_log
71-
fi
72-
73-
checked_modules[$module_name]=1
74-
done
75-
done
104+
# Paths to the module files generated from build and the --module-only
105+
module_file_build="${EASYBUILD_INSTALLPATH}/modules/all/${module_relpath}"
106+
module_file_module_only="${module_install_dir}/all/${module_relpath}"
107+
108+
# Check if both module files exist
109+
if [ ! -f "$module_file_build" ]; then
110+
echo "Module file from full build not found: $module_file_build"
111+
echo "$package_name: Module file from full build not found" >> "$broken_modules_log"
112+
continue
113+
fi
114+
115+
if [ ! -f "$module_file_module_only" ]; then
116+
echo "Module file from --module-only build not found: $module_file_module_only"
117+
echo "$package_name: Module file from --module-only build not found" >> "$broken_modules_log"
118+
continue
119+
fi
120+
121+
# Compare the module files
122+
if diff -q "$module_file_build" "$module_file_module_only" >/dev/null; then
123+
echo "Module files for $package_name match"
124+
else
125+
echo "Module files for $package_name differ"
126+
echo "$package_name: Module files differ" >> "$broken_modules_log"
127+
# Save differences
128+
diff_file="${module_software//\//_}_module_diff.txt"
129+
diff "$module_file_build" "$module_file_module_only" > "$diff_file"
130+
echo "Module file differences saved to $diff_file"
131+
fi
132+
133+
# Proceed to compare the environments
134+
echo "Testing module: $module_software"
135+
136+
# Function to get filtered environment variables, excluding lmod-related vars
137+
get_filtered_env() {
138+
env | grep -v -E '^(LMOD_|MODULEPATH|MODULESHOME|LOADEDMODULES|BASH_FUNC_module|_ModuleTable_|PWD=|SHLVL=|OLDPWD=|PS1=|PS2=|_LMFILES_)=.*$' | sort
139+
}
140+
141+
# Compare the environments of the modules
142+
module purge
143+
module unuse "$module_install_dir"
144+
module load EasyBuild
145+
146+
# Load the module from the full build
147+
if module --ignore_cache load "$module_software" 2>/dev/null; then
148+
original_env=$(get_filtered_env)
149+
module unload "$module_software"
150+
else
151+
echo "Failed to load module from full build: $module_software."
152+
original_env=""
153+
fi
154+
155+
# Load the module from the --module-only
156+
module purge
157+
module use "$module_install_dir"
158+
159+
if module --ignore_cache load "$module_software" 2>/dev/null; then
160+
new_env=$(get_filtered_env)
161+
module unload "$module_software"
162+
else
163+
echo "Failed to load module from --module-only build: $module_software."
164+
echo "$package_name: Failed to load module from --module-only build" >> "$broken_modules_log"
165+
module unuse "$module_install_dir"
166+
continue
167+
fi
168+
169+
# Compare the environments
170+
if [ -n "$original_env" ]; then
171+
if diff <(echo "$original_env") <(echo "$new_env") >/dev/null; then
172+
echo "$module_software loaded with identical environment."
173+
else
174+
echo "$module_software environment mismatch."
175+
echo "$package_name: $module_software (environment mismatch)" >> "$broken_modules_log"
176+
diff_file="${module_software//\//_}_env_diff.txt"
177+
diff <(echo "$original_env") <(echo "$new_env") > "$diff_file"
178+
echo "Environment differences saved to $diff_file"
179+
fi
180+
else
181+
echo "Original environment not available for comparison for $module_software."
182+
echo "$package_name: $module_software (failed to load module from full build)" >> "$broken_modules_log"
183+
fi
184+
185+
186+
module unuse "$module_install_dir"
187+
188+
# Mark module as checked
189+
checked_modules[$module_software]=1
190+
76191
done
77192

78-
echo "All module checks completed. Broken modules are listed in $broken_modules_log"
193+
# Report
194+
if [ -f "$broken_modules_log" ] && [ -s "$broken_modules_log" ]; then
195+
echo "Some modules did not match. See $broken_modules_log for details."
196+
exit 1
197+
else
198+
echo "All modules match between build and --module-only build."
199+
fi
200+
201+
# Clean up temporary directories
202+
rm -rf "$LOCAL_TMPDIR"
79203

0 commit comments

Comments
 (0)