Skip to content

Commit 32031cb

Browse files
authored
Merge pull request #312 from trz42/nessi_rebuild_func_code_only
functionality for rebuilding software
2 parents deed9bb + 4afaaad commit 32031cb

4 files changed

+208
-23
lines changed

EESSI-install-software.sh

+17-12
Original file line numberDiff line numberDiff line change
@@ -204,29 +204,34 @@ ${EESSI_PREFIX}/scripts/gpu_support/nvidia/install_cuda_host_injections.sh -c 12
204204

205205
# use PR patch file to determine in which easystack files stuff was added
206206
changed_easystacks=$(cat ${pr_diff} | grep '^+++' | cut -f2 -d' ' | sed 's@^[a-z]/@@g' | grep '^easystacks/.*yml$' | egrep -v 'known-issues|missing')
207-
if [ -z ${changed_easystacks} ]; then
207+
if [ -z "${changed_easystacks}" ]; then
208208
echo "No missing installations, party time!" # Ensure the bot report success, as there was nothing to be build here
209209
else
210-
for easystack_file in ${changed_easystacks}; do
211-
210+
211+
# first process rebuilds, if any, then easystack files for new installations
212+
# "|| true" is used to make sure that the grep command always returns success
213+
rebuild_easystacks=$(echo "${changed_easystacks}" | (grep "/rebuilds/" || true))
214+
new_easystacks=$(echo "${changed_easystacks}" | (grep -v "/rebuilds/" || true))
215+
for easystack_file in ${rebuild_easystacks} ${new_easystacks}; do
216+
212217
echo -e "Processing easystack file ${easystack_file}...\n\n"
213-
218+
214219
# determine version of EasyBuild module to load based on EasyBuild version included in name of easystack file
215220
eb_version=$(echo ${easystack_file} | sed 's/.*eb-\([0-9.]*\).*/\1/g')
216-
221+
217222
# load EasyBuild module (will be installed if it's not available yet)
218223
source ${TOPDIR}/load_easybuild_module.sh ${eb_version}
219-
224+
220225
${EB} --show-config
221-
226+
222227
echo_green "All set, let's start installing some software with EasyBuild v${eb_version} in ${EASYBUILD_INSTALLPATH}..."
223-
228+
224229
if [ -f ${easystack_file} ]; then
225230
echo_green "Feeding easystack file ${easystack_file} to EasyBuild..."
226-
231+
227232
${EB} --easystack ${TOPDIR}/${easystack_file} --robot
228233
ec=$?
229-
234+
230235
# copy EasyBuild log file if EasyBuild exited with an error
231236
if [ ${ec} -ne 0 ]; then
232237
eb_last_log=$(unset EB_VERBOSE; eb --last-log)
@@ -236,12 +241,12 @@ else
236241
# copy to build logs dir (with context added)
237242
copy_build_log "${eb_last_log}" "${build_logs_dir}"
238243
fi
239-
244+
240245
$TOPDIR/check_missing_installations.sh ${TOPDIR}/${easystack_file} ${TOPDIR}/${pr_diff}
241246
else
242247
fatal_error "Easystack file ${easystack_file} not found!"
243248
fi
244-
249+
245250
done
246251
fi
247252

EESSI-remove-software.sh

+125
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
#!/bin/bash
2+
#
3+
# Script to remove part of the EESSI software stack (version set through init/eessi_defaults)
4+
5+
# see example parsing of command line arguments at
6+
# https://wiki.bash-hackers.org/scripting/posparams#using_a_while_loop
7+
# https://stackoverflow.com/questions/192249/how-do-i-parse-command-line-arguments-in-bash
8+
9+
display_help() {
10+
echo "usage: $0 [OPTIONS]"
11+
echo " -g | --generic - instructs script to build for generic architecture target"
12+
echo " -h | --help - display this usage information"
13+
}
14+
15+
POSITIONAL_ARGS=()
16+
17+
while [[ $# -gt 0 ]]; do
18+
case $1 in
19+
-g|--generic)
20+
DETECTION_PARAMETERS="--generic"
21+
shift
22+
;;
23+
-h|--help)
24+
display_help # Call your function
25+
# no shifting needed here, we're done.
26+
exit 0
27+
;;
28+
-*|--*)
29+
echo "Error: Unknown option: $1" >&2
30+
exit 1
31+
;;
32+
*) # No more options
33+
POSITIONAL_ARGS+=("$1") # save positional arg
34+
shift
35+
;;
36+
esac
37+
done
38+
39+
set -- "${POSITIONAL_ARGS[@]}"
40+
41+
TOPDIR=$(dirname $(realpath $0))
42+
43+
export TMPDIR=$(mktemp -d /tmp/eessi-remove.XXXXXXXX)
44+
45+
source $TOPDIR/scripts/utils.sh
46+
47+
echo ">> Determining software subdirectory to use for current build host..."
48+
if [ -z $EESSI_SOFTWARE_SUBDIR_OVERRIDE ]; then
49+
export EESSI_SOFTWARE_SUBDIR_OVERRIDE=$(python3 $TOPDIR/eessi_software_subdir.py $DETECTION_PARAMETERS)
50+
echo ">> Determined \$EESSI_SOFTWARE_SUBDIR_OVERRIDE via 'eessi_software_subdir.py $DETECTION_PARAMETERS' script"
51+
else
52+
echo ">> Picking up pre-defined \$EESSI_SOFTWARE_SUBDIR_OVERRIDE: ${EESSI_SOFTWARE_SUBDIR_OVERRIDE}"
53+
fi
54+
55+
echo ">> Setting up environment..."
56+
57+
source $TOPDIR/init/bash
58+
59+
if [ -d $EESSI_CVMFS_REPO ]; then
60+
echo_green "$EESSI_CVMFS_REPO available, OK!"
61+
else
62+
fatal_error "$EESSI_CVMFS_REPO is not available!"
63+
fi
64+
65+
if [[ -z ${EESSI_SOFTWARE_SUBDIR} ]]; then
66+
fatal_error "Failed to determine software subdirectory?!"
67+
elif [[ "${EESSI_SOFTWARE_SUBDIR}" != "${EESSI_SOFTWARE_SUBDIR_OVERRIDE}" ]]; then
68+
fatal_error "Values for EESSI_SOFTWARE_SUBDIR_OVERRIDE (${EESSI_SOFTWARE_SUBDIR_OVERRIDE}) and EESSI_SOFTWARE_SUBDIR (${EESSI_SOFTWARE_SUBDIR}) differ!"
69+
else
70+
echo_green ">> Using ${EESSI_SOFTWARE_SUBDIR} as software subdirectory!"
71+
fi
72+
73+
echo ">> Configuring EasyBuild..."
74+
EB="eb"
75+
source $TOPDIR/configure_easybuild
76+
77+
echo ">> Setting up \$MODULEPATH..."
78+
# make sure no modules are loaded
79+
module --force purge
80+
# ignore current $MODULEPATH entirely
81+
module unuse $MODULEPATH
82+
module use $EASYBUILD_INSTALLPATH/modules/all
83+
if [[ -z ${MODULEPATH} ]]; then
84+
fatal_error "Failed to set up \$MODULEPATH?!"
85+
else
86+
echo_green ">> MODULEPATH set up: ${MODULEPATH}"
87+
fi
88+
89+
# assume there's only one diff file that corresponds to the PR patch file
90+
pr_diff=$(ls [0-9]*.diff | head -1)
91+
92+
# if this script is run as root, use PR patch file to determine if software needs to be removed first
93+
if [ $EUID -eq 0 ]; then
94+
changed_easystacks_rebuilds=$(cat ${pr_diff} | grep '^+++' | cut -f2 -d' ' | sed 's@^[a-z]/@@g' | grep '^easystacks/.*yml$' | egrep -v 'known-issues|missing' | grep "/rebuilds/")
95+
if [ -z ${changed_easystacks_rebuilds} ]; then
96+
echo "No software needs to be removed."
97+
else
98+
for easystack_file in ${changed_easystacks_rebuilds}; do
99+
# determine version of EasyBuild module to load based on EasyBuild version included in name of easystack file
100+
eb_version=$(echo ${easystack_file} | sed 's/.*eb-\([0-9.]*\).*/\1/g')
101+
102+
# load EasyBuild module (will be installed if it's not available yet)
103+
source ${TOPDIR}/load_easybuild_module.sh ${eb_version}
104+
105+
if [ -f ${easystack_file} ]; then
106+
echo_green "Software rebuild(s) requested in ${easystack_file}, so determining which existing installation have to be removed..."
107+
# we need to remove existing installation directories first,
108+
# so let's figure out which modules have to be rebuilt by doing a dry-run and grepping "someapp/someversion" for the relevant lines (with [R])
109+
# * [R] $CFGS/s/someapp/someapp-someversion.eb (module: someapp/someversion)
110+
rebuild_apps=$(eb --allow-use-as-root-and-accept-consequences --dry-run-short --rebuild --easystack ${easystack_file} | grep "^ \* \[R\]" | grep -o "module: .*[^)]" | awk '{print $2}')
111+
for app in ${rebuild_apps}; do
112+
app_dir=${EASYBUILD_INSTALLPATH}/software/${app}
113+
app_module=${EASYBUILD_INSTALLPATH}/modules/all/${app}.lua
114+
echo_yellow "Removing ${app_dir} and ${app_module}..."
115+
rm -rf ${app_dir}
116+
rm -rf ${app_module}
117+
done
118+
else
119+
fatal_error "Easystack file ${easystack_file} not found!"
120+
fi
121+
done
122+
fi
123+
else
124+
fatal_error "This script can only be run by root!"
125+
fi

bot/build.sh

+55-11
Original file line numberDiff line numberDiff line change
@@ -168,12 +168,58 @@ COMMON_ARGS+=("--mode" "run")
168168
# make sure to use the same parent dir for storing tarballs of tmp
169169
PREVIOUS_TMP_DIR=${PWD}/previous_tmp
170170

171+
# prepare arguments to install_software_layer.sh (specific to build step)
172+
declare -a BUILD_STEP_ARGS=()
173+
declare -a INSTALL_SCRIPT_ARGS=()
174+
declare -a REMOVAL_SCRIPT_ARGS=()
175+
if [[ ${EESSI_SOFTWARE_SUBDIR_OVERRIDE} =~ .*/generic$ ]]; then
176+
INSTALL_SCRIPT_ARGS+=("--generic")
177+
REMOVAL_SCRIPT_ARGS+=("--generic")
178+
fi
179+
[[ ! -z ${BUILD_LOGS_DIR} ]] && INSTALL_SCRIPT_ARGS+=("--build-logs-dir" "${BUILD_LOGS_DIR}")
180+
[[ ! -z ${SHARED_FS_PATH} ]] && INSTALL_SCRIPT_ARGS+=("--shared-fs-path" "${SHARED_FS_PATH}")
181+
182+
# determine if the removal step has to be run
183+
# assume there's only one diff file that corresponds to the PR patch file
184+
pr_diff=$(ls [0-9]*.diff | head -1)
185+
# the true at the end of the next command is important: grep will expectedly return 1 if there is no easystack file being added under rebuilds,
186+
# but due to "set -e" the entire script would otherwise fail
187+
changed_easystacks_rebuilds=$(cat ${pr_diff} | grep '^+++' | cut -f2 -d' ' | sed 's@^[a-z]/@@g' | grep '^easystacks/.*yml$' | (grep "/rebuilds/" || true))
188+
if [[ -z "${changed_easystacks_rebuilds}" ]]; then
189+
echo "This PR does not add any easystack files in a rebuilds subdirectory, so let's skip the removal step."
190+
else
191+
# prepare directory to store tarball of tmp for removal and build steps
192+
TARBALL_TMP_REMOVAL_STEP_DIR=${PREVIOUS_TMP_DIR}/removal_step
193+
mkdir -p ${TARBALL_TMP_REMOVAL_STEP_DIR}
194+
195+
# prepare arguments to eessi_container.sh specific to remove step
196+
declare -a REMOVAL_STEP_ARGS=()
197+
REMOVAL_STEP_ARGS+=("--save" "${TARBALL_TMP_REMOVAL_STEP_DIR}")
198+
REMOVAL_STEP_ARGS+=("--storage" "${STORAGE}")
199+
# add fakeroot option in order to be able to remove software, see:
200+
# https://github.com/EESSI/software-layer/issues/312
201+
REMOVAL_STEP_ARGS+=("--fakeroot")
202+
203+
# create tmp file for output of removal step
204+
removal_outerr=$(mktemp remove.outerr.XXXX)
205+
206+
echo "Executing command to remove software:"
207+
echo "./eessi_container.sh ${COMMON_ARGS[@]} ${REMOVAL_STEP_ARGS[@]}"
208+
echo " -- ./EESSI-remove-software.sh \"${REMOVAL_SCRIPT_ARGS[@]}\" \"$@\" 2>&1 | tee -a ${removal_outerr}"
209+
./eessi_container.sh "${COMMON_ARGS[@]}" "${REMOVAL_STEP_ARGS[@]}" \
210+
-- ./EESSI-remove-software.sh "${REMOVAL_SCRIPT_ARGS[@]}" "$@" 2>&1 | tee -a ${removal_outerr}
211+
212+
# make sure that the build step resumes from the same temporary directory
213+
# this is important, as otherwise the removed software will still be there
214+
REMOVAL_TMPDIR=$(grep ' as tmp directory ' ${removal_outerr} | cut -d ' ' -f 2)
215+
BUILD_STEP_ARGS+=("--resume" "${REMOVAL_TMPDIR}")
216+
fi
217+
171218
# prepare directory to store tarball of tmp for build step
172219
TARBALL_TMP_BUILD_STEP_DIR=${PREVIOUS_TMP_DIR}/build_step
173220
mkdir -p ${TARBALL_TMP_BUILD_STEP_DIR}
174221

175222
# prepare arguments to eessi_container.sh specific to build step
176-
declare -a BUILD_STEP_ARGS=()
177223
BUILD_STEP_ARGS+=("--save" "${TARBALL_TMP_BUILD_STEP_DIR}")
178224
BUILD_STEP_ARGS+=("--storage" "${STORAGE}")
179225
# add options required to handle NVIDIA support
@@ -182,14 +228,6 @@ if [[ ! -z ${SHARED_FS_PATH} ]]; then
182228
BUILD_STEP_ARGS+=("--host-injections" "${SHARED_FS_PATH}/host-injections")
183229
fi
184230

185-
# prepare arguments to install_software_layer.sh (specific to build step)
186-
declare -a INSTALL_SCRIPT_ARGS=()
187-
if [[ ${EESSI_SOFTWARE_SUBDIR_OVERRIDE} =~ .*/generic$ ]]; then
188-
INSTALL_SCRIPT_ARGS+=("--generic")
189-
fi
190-
[[ ! -z ${BUILD_LOGS_DIR} ]] && INSTALL_SCRIPT_ARGS+=("--build-logs-dir" "${BUILD_LOGS_DIR}")
191-
[[ ! -z ${SHARED_FS_PATH} ]] && INSTALL_SCRIPT_ARGS+=("--shared-fs-path" "${SHARED_FS_PATH}")
192-
193231
# create tmp file for output of build step
194232
build_outerr=$(mktemp build.outerr.XXXX)
195233

@@ -211,8 +249,14 @@ declare -a TARBALL_STEP_ARGS=()
211249
TARBALL_STEP_ARGS+=("--save" "${TARBALL_TMP_TARBALL_STEP_DIR}")
212250

213251
# determine temporary directory to resume from
214-
BUILD_TMPDIR=$(grep ' as tmp directory ' ${build_outerr} | cut -d ' ' -f 2)
215-
TARBALL_STEP_ARGS+=("--resume" "${BUILD_TMPDIR}")
252+
if [[ -z ${REMOVAL_TMPDIR} ]]; then
253+
# no rebuild step was done, so the tarball step should resume from the build directory
254+
BUILD_TMPDIR=$(grep ' as tmp directory ' ${build_outerr} | cut -d ' ' -f 2)
255+
TARBALL_STEP_ARGS+=("--resume" "${BUILD_TMPDIR}")
256+
else
257+
# a removal step was done, so resume from its temporary directory (which was also used for the build step)
258+
TARBALL_STEP_ARGS+=("--resume" "${REMOVAL_TMPDIR}")
259+
fi
216260

217261
timestamp=$(date +%s)
218262
# to set EESSI_VERSION we need to source init/eessi_defaults now

eessi_container.sh

+11
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ display_help() {
7373
echo " -a | --access {ro,rw} - ro (read-only), rw (read & write) [default: ro]"
7474
echo " -c | --container IMG - image file or URL defining the container to use"
7575
echo " [default: docker://ghcr.io/eessi/build-node:debian11]"
76+
echo " -f | --fakeroot - run the container with --fakeroot [default: false]"
7677
echo " -g | --storage DIR - directory space on host machine (used for"
7778
echo " temporary data) [default: 1. TMPDIR, 2. /tmp]"
7879
echo " -h | --help - display this usage information [default: false]"
@@ -113,6 +114,7 @@ display_help() {
113114
ACCESS="ro"
114115
CONTAINER="docker://ghcr.io/eessi/build-node:debian11"
115116
#DRY_RUN=0
117+
FAKEROOT=0
116118
VERBOSE=0
117119
STORAGE=
118120
LIST_REPOS=0
@@ -140,6 +142,10 @@ while [[ $# -gt 0 ]]; do
140142
# DRY_RUN=1
141143
# shift 1
142144
# ;;
145+
-f|--fakeroot)
146+
FAKEROOT=1
147+
shift 1
148+
;;
143149
-g|--storage)
144150
STORAGE="$2"
145151
shift 2
@@ -466,6 +472,11 @@ if [[ ${SETUP_NVIDIA} -eq 1 ]]; then
466472
fi
467473
fi
468474

475+
# Configure the fakeroot setting for the container
476+
if [[ ${FAKEROOT} -eq 1 ]]; then
477+
ADDITIONAL_CONTAINER_OPTIONS+=("--fakeroot")
478+
fi
479+
469480
# set up repository config (always create directory repos_cfg and populate it with info when
470481
# arg -r|--repository is used)
471482
mkdir -p ${EESSI_TMPDIR}/repos_cfg

0 commit comments

Comments
 (0)