Skip to content

Commit 8cda179

Browse files
authored
Merge pull request #24 from bedroge/reprod_hook
add hook that copies the `easybuild` subdirectory of every installation to a central `reprod` directory
2 parents 9411674 + 269cca8 commit 8cda179

File tree

3 files changed

+59
-3
lines changed

3 files changed

+59
-3
lines changed

bot/check-build.sh

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -502,7 +502,9 @@ if [[ $USE_CHECK_BUILD_ARTEFACTS_SCRIPT -eq 0 ]]; then
502502
# extract directories/entries from tarball content
503503
modules_entries=$(grep "${prefix}/modules" ${tmpfile})
504504
software_entries=$(grep "${prefix}/software" ${tmpfile})
505-
other_entries=$(cat ${tmpfile} | grep -v "${prefix}/modules" | grep -v "${prefix}/software")
505+
reprod_entries=$(grep "${prefix}/reprod" ${tmpfile})
506+
reprod_shortened=$(echo "${reprod_entries}" | sed -e "s@${prefix}/reprod/@@" | awk -F/ '{if (NR >= 4) {print $1 "/" $2 "/" $3}}' | sort -u)
507+
other_entries=$(cat ${tmpfile} | grep -v "${prefix}/modules" | grep -v "${prefix}/software" | grep -v "${prefix}/reprod")
506508
other_shortened=$(echo "${other_entries}" | sed -e "s@^.*${prefix}/@@" | sort -u)
507509
modules=$(echo "${modules_entries}" | grep "/all/.*/.*lua$" | sed -e 's@^.*/\([^/]*/[^/]*.lua\)$@\1@' | sort -u)
508510
software_pkgs=$(echo "${software_entries}" | sed -e "s@${prefix}/software/@@" | awk -F/ '{if (NR >= 2) {print $1 "/" $2}}' | sort -u)
@@ -531,6 +533,16 @@ if [[ $USE_CHECK_BUILD_ARTEFACTS_SCRIPT -eq 0 ]]; then
531533
comment_artifacts_list="${comment_artifacts_list}$(print_br_item '__ITEM__' 'no software packages in tarball')"
532534
fi
533535
comment_artifacts_list="${comment_artifacts_list}</pre>"
536+
comment_artifacts_list="${comment_artifacts_list}$(print_br_item 'reprod directories under ___ITEM___' ${prefix}/reprod)"
537+
comment_artifacts_list="${comment_artifacts_list}<pre>"
538+
if [[ ! -z ${reprod_shortened} ]]; then
539+
while IFS= read -r reprod ; do
540+
comment_artifacts_list="${comment_artifacts_list}$(print_br_item '<code>__ITEM__</code>' ${reprod})"
541+
done <<< "${reprod_shortened}"
542+
else
543+
comment_artifacts_list="${comment_artifacts_list}$(print_br_item '__ITEM__' 'no reprod directories in tarball')"
544+
fi
545+
comment_artifacts_list="${comment_artifacts_list}</pre>"
534546
comment_artifacts_list="${comment_artifacts_list}$(print_br_item 'other under ___ITEM___' ${prefix})"
535547
comment_artifacts_list="${comment_artifacts_list}<pre>"
536548
if [[ ! -z ${other_shortened} ]]; then

create_tarball.sh

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,8 +90,13 @@ for subdir in ${sw_subdirs}; do
9090
for package_version in $(cat ${module_files_list}); do
9191
echo "handling ${package_version}"
9292
find ${eessi_version}/software/${os}/${subdir}/software/${package_version} -maxdepth 0 -type d \! -name '.wh.*' >> ${files_list}
93+
# if there is a directory for this installation in the stack's reprod directory, include that too
94+
if [ -d ${eessi_version}/software/${os}/${subdir}/reprod ]; then
95+
find ${eessi_version}/software/${os}/${subdir}/reprod/${package_version} -maxdepth 0 -type d \! -name '.wh.*' >> ${files_list}
96+
fi
9397
done
9498
fi
99+
95100
done
96101

97102
# add a bit debug output

eb_hooks.py

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,17 @@
11
# Hooks to customize how EasyBuild installs software in EESSI
22
# see https://docs.easybuild.io/en/latest/Hooks.html
3+
import datetime
34
import glob
45
import os
56
import re
67

78
import easybuild.tools.environment as env
89
from easybuild.easyblocks.generic.configuremake import obtain_config_guess
910
from easybuild.framework.easyconfig.constants import EASYCONFIG_CONSTANTS
11+
from easybuild.tools import config
1012
from easybuild.tools.build_log import EasyBuildError, print_msg
11-
from easybuild.tools.config import build_option, update_build_option
12-
from easybuild.tools.filetools import apply_regex_substitutions, copy_file, remove_file, symlink, which
13+
from easybuild.tools.config import build_option, install_path, update_build_option
14+
from easybuild.tools.filetools import apply_regex_substitutions, copy_dir, copy_file, remove_file, symlink, which
1315
from easybuild.tools.run import run_cmd
1416
from easybuild.tools.systemtools import AARCH64, POWER, X86_64, get_cpu_architecture, get_cpu_features
1517
from easybuild.tools.toolchain.compiler import OPTARCH_GENERIC
@@ -46,6 +48,9 @@
4648
# Make sure a single environment variable name is used for this throughout the hooks
4749
EESSI_IGNORE_ZEN4_GCC1220_ENVVAR="EESSI_IGNORE_LMOD_ERROR_ZEN4_GCC1220"
4850

51+
STACK_REPROD_SUBDIR = 'reprod'
52+
53+
4954
def is_gcccore_1220_based(**kwargs):
5055
# ecname, ecversion, tcname, tcversion):
5156
"""
@@ -516,6 +521,20 @@ def post_module_hook_zen4_gcccore1220(self, *args, **kwargs):
516521
del self.initial_environ[EESSI_IGNORE_ZEN4_GCC1220_ENVVAR]
517522

518523

524+
def post_easyblock_hook_copy_easybuild_subdir(self, *args, **kwargs):
525+
"""
526+
Post easyblock hook that copies the easybuild subdirectory of every installed application
527+
to a central and timestamped location in the root of the software stack, e.g.:
528+
/path/to/stack/reprod/MyApp/1.2-foss-2025a/20250102T12:34:56Z
529+
"""
530+
531+
stack_reprod_dir = os.path.join(os.path.dirname(install_path()), STACK_REPROD_SUBDIR)
532+
now_utc_timestamp = datetime.datetime.now(datetime.UTC).strftime('%Y%m%d_%H%M%S%Z')
533+
app_easybuild_dir = os.path.join(self.installdir, config.log_path(ec=self.cfg))
534+
app_reprod_dir = os.path.join(stack_reprod_dir, self.install_subdir, now_utc_timestamp, 'easybuild')
535+
copy_dir(app_easybuild_dir, app_reprod_dir)
536+
537+
519538
# Modules for dependencies are loaded in the prepare step. Thus, that's where we need this variable to be set
520539
# so that the modules can be succesfully loaded without printing the error (so that we can create a module
521540
# _with_ the warning for the current software being installed)
@@ -1297,6 +1316,24 @@ def post_module_hook(self, *args, **kwargs):
12971316
post_module_hook_zen4_gcccore1220(self, *args, **kwargs)
12981317

12991318

1319+
# The post_easyblock_hook was introduced in EasyBuild 5.1.1.
1320+
# Older versions would fail if the function is defined anyway, as EasyBuild performs some checks on function names in hooks files.
1321+
if EASYBUILD_VERSION >= '5.1.1':
1322+
def post_easyblock_hook(self, *args, **kwargs):
1323+
"""Main post easyblock hook: trigger custom functions based on software name."""
1324+
if self.name in POST_EASYBLOCK_HOOKS:
1325+
POST_EASYBLOCK_HOOKS[self.name](self, *args, **kwargs)
1326+
1327+
# Always trigger this one for EESSI CVMFS/site installations and version 2025.06 or newer, regardless of self.name
1328+
if os.getenv('EESSI_CVMFS_INSTALL') or os.getenv('EESSI_SITE_INSTALL'):
1329+
if os.getenv('EESSI_VERSION') and LooseVersion(os.getenv('EESSI_VERSION')) >= '2025.06':
1330+
post_easyblock_hook_copy_easybuild_subdir(self, *args, **kwargs)
1331+
else:
1332+
self.log.debug("No CVMFS/site installation requested, not running post_easyblock_hook_copy_easybuild_subdir.")
1333+
else:
1334+
print_msg(f"Not enabling the post_easybuild_hook, as it requires EasyBuild 5.1.1 or newer.")
1335+
1336+
13001337
PARSE_HOOKS = {
13011338
'casacore': parse_hook_casacore_disable_vectorize,
13021339
'CGAL': parse_hook_cgal_toolchainopts_precise,
@@ -1365,6 +1402,8 @@ def post_module_hook(self, *args, **kwargs):
13651402

13661403
POST_MODULE_HOOKS = {}
13671404

1405+
POST_EASYBLOCK_HOOKS = {}
1406+
13681407
# Define parallelism limit operations
13691408
def divide_by_factor(parallel, factor):
13701409
"""Divide parallelism by given factor"""

0 commit comments

Comments
 (0)