From 80728b8a6a557b3157e5b6d0c9690766f2f3f489 Mon Sep 17 00:00:00 2001 From: Achim Gsell Date: Thu, 29 Apr 2021 18:10:55 +0200 Subject: [PATCH 1/7] modulecmd: tag log messages with 'Pmodules' --- Pmodules/modulecmd.bash.in | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Pmodules/modulecmd.bash.in b/Pmodules/modulecmd.bash.in index 8501996..ee4e922 100755 --- a/Pmodules/modulecmd.bash.in +++ b/Pmodules/modulecmd.bash.in @@ -22,6 +22,10 @@ declare -r sort awk=$(PATH=/bin:/usr/bin /usr/bin/which awk) declare -r awk rm=$(PATH=/bin:/usr/bin /usr/bin/which rm) +declare -r rm +logger=$(PATH=/bin:/usr/bin /usr/bin/which logger) +declare -r logger + if [[ $(uname -s) == 'Darwin' ]]; then declare -r getopt="${libexecdir}/getopt" declare -r find="${libexecdir}/find" @@ -556,7 +560,7 @@ subcommand_load() { [[ ${release} != stable ]]; then std::info "%s" "${msg}" fi - logger "${msg}" + ${logger} -t Pmodules "${msg}" done # fix LOADEDMODULES LOADEDMODULES="${_LMFILES_}" From a970be1cf3b2a91b8ab829fd38983a55c037c8a9 Mon Sep 17 00:00:00 2001 From: Achim Gsell Date: Thu, 29 Apr 2021 18:47:01 +0200 Subject: [PATCH 2/7] modulecmd: don't remove a loaded Pmodules module with module purge Removing a Pmodule module with module purge has some unwanted side-effects. It is not required to have modulecmd in a directory of PATH. If you user explicitly loads a Pmodules module the bin directory of the Pmodule module is added to the PATH. A Pmodules module might be loaded for two reasons. First to change the Pmodules version, second to make the build system available. If we remove a Pmodules module with module purge the build systems is getting unavailable again. This is confusing for the user. --- Pmodules/modulecmd.bash.in | 68 +++++++++++++++++++++++++++++++++----- 1 file changed, 60 insertions(+), 8 deletions(-) diff --git a/Pmodules/modulecmd.bash.in b/Pmodules/modulecmd.bash.in index ee4e922..744d64c 100755 --- a/Pmodules/modulecmd.bash.in +++ b/Pmodules/modulecmd.bash.in @@ -1320,7 +1320,7 @@ reset_modulepath() { MODULEPATH='' local group local root="${PMODULES_ROOT}" - for group in ${PMODULES_DEFAULT_GROUPS}; do + for group in ${UsedGroups//:/ }; do local dir="${root}/${group}/${PMODULES_MODULEFILES_DIR}" [[ -d "${dir}" ]] && std::prepend_path MODULEPATH "${dir}" done @@ -1395,6 +1395,13 @@ USAGE: ' subcommand_purge() { + # + # unload all loaded modules + # + # Note: + # If a Pmodule module is loaded, it will *not* be + # unloaded! + # local -r subcommand='purge' local -a args=() while (( $# > 0)); do @@ -1411,21 +1418,66 @@ subcommand_purge() { shift done if (( ${#args[@]} > 0 )); then - std::die 3 "%s %s: %s\n" \ + std::die 3 "%s %s: %s" \ "${CMD}" "${subcommand}" \ "no arguments allowd" fi - # we cannot unset PMODULES_HOME, otherwise the module function - # would fail. - local saved_home="${PMODULES_HOME}" - "${modulecmd}" "${Shell}" "${subcommand}" + + # is a Pmodule module loaded? + # if yes, save name in variable 'pmodule' + local pmodule='' + IFS=':' + local -a lmfiles=($_LMFILES_) + unset IFS + for f in "${lmfiles[@]}"; do + if [[ $f == */${PMODULES_MODULEFILES_DIR}/Pmodules/* ]]; then + pmodule="${f##*/${PMODULES_MODULEFILES_DIR}/}" + break; + fi + done + + # run module purge + # since we might have to reload a Pmodules module, we cannot + # just run 'modulecmd ${Shell} purge' + local tmpfile=$( "${mktemp}" /tmp/Pmodules.XXXXXX ) \ + || std::die 1 "Oops: unable to create tmp file!\n" + + local output=$("${modulecmd}" 'bash' 'purge' 2> "${tmpfile}") + + local error=$( < "${tmpfile}") + ${rm} "${tmpfile}" + if [[ "${error}" =~ ":ERROR:" ]]; then + local s=${error%%$'\n'*} + local error_txt='failed' + std::die 3 "%s %s: %s" \ + "${CMD}" "${subcommand}" \ + "${error_txt}" + fi + if [[ "${Shell}" == "sh" ]]; then + # for sh-like shells just echo + echo "${output}" + else + # re-run with right shell + "${modulecmd}" "${Shell}" 'purge' + fi + eval "${output}" + if [[ -n "${error}" ]]; then + echo "${error}" 1>&2 + fi + + if [[ -n "${pmodule}" ]]; then + # reload a previously loaded Pmodule module + # stderr is redirected to /dev/null, otherwise + # we may get output like + # 'unstable module has been loaded' + subcommand_load "${pmodule}" 2> /dev/null + fi reset_modulepath - reset_used_groups - PMODULES_HOME="${saved_home}" export_env MODULEPATH PMODULES_HOME } + ############################################################################## # # list [-hlt] From c55404a798237f5599784d64ef16d90b95f3e791 Mon Sep 17 00:00:00 2001 From: Achim Gsell Date: Thu, 29 Apr 2021 19:29:42 +0200 Subject: [PATCH 3/7] modulecmd: better tmp file handling A global tmp file is created if the sub-command is 'load', 'purge' or 'search' and removed in the exit function. --- Pmodules/modulecmd.bash.in | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/Pmodules/modulecmd.bash.in b/Pmodules/modulecmd.bash.in index 744d64c..124c95d 100755 --- a/Pmodules/modulecmd.bash.in +++ b/Pmodules/modulecmd.bash.in @@ -102,7 +102,7 @@ export_env() { declare g_env_must_be_saved='no' save_env() { - [[ ${g_env_must_be_saved} == 'no' ]] && return 0 + [[ $1 == 'no' ]] && return 0 local vars=( GroupDepths UsedReleases UseFlags UsedGroups ) vars+=( PMODULES_DEFAULT_GROUPS PMODULES_DEFINED_RELEASES ) vars+=( PMODULES_DEFAULT_RELEASES ) @@ -112,7 +112,12 @@ save_env() { export_env 'PMODULES_ENV' } -trap 'save_env ' EXIT +_exit() { + save_env "${g_env_must_be_saved}" + ${rm} -f "${tmpfile}" +} + +trap '_exit' EXIT # # get release of module @@ -515,8 +520,6 @@ subcommand_load() { test -r "${prefix}/.info" && cat "$_" 1>&2 test -r "${prefix}/.dependencies" && load_dependencies "$_" fi - local tmpfile=$( "${mktemp}" /tmp/Pmodules.XXXXXX ) \ - || std::die 1 "Oops: unable to create tmp file!\n" local output=$("${modulecmd}" 'bash' ${opts} 'load' \ "${current_modulefile}" 2> "${tmpfile}") @@ -1439,9 +1442,6 @@ subcommand_purge() { # run module purge # since we might have to reload a Pmodules module, we cannot # just run 'modulecmd ${Shell} purge' - local tmpfile=$( "${mktemp}" /tmp/Pmodules.XXXXXX ) \ - || std::die 1 "Oops: unable to create tmp file!\n" - local output=$("${modulecmd}" 'bash' 'purge' 2> "${tmpfile}") local error=$( < "${tmpfile}") @@ -1774,8 +1774,6 @@ subcommand_search() { search () { local -r module=$1 # write results to a temporary file for later processing - local -r tmpfile=$( "${mktemp}" /tmp/Pmodules.XXXXXX ) \ - || std::die 1 "Oops: unable to create tmp file!" local group # loop over all groups for group in "${!GroupDepths[@]}"; do @@ -2251,6 +2249,13 @@ if (( ${#GroupDepths[@]} == 0 )); then scan_groups "${PMODULES_ROOT}" fi +case ${subcommand} in + load|purge|search ) + declare -r tmpfile=$( ${mktemp} /tmp/Pmodules.XXXXXX ) \ + || std::die 1 "Oops: unable to create tmp file!" + ;; +esac + declare options options=$( "${getopt}" ${Options[${subcommand}]} -- -- "${opts[@]}" "$@" ) \ || print_help "${subcommand}" From 2747861b523b7ca8e9464469f303951a1bb3d876 Mon Sep 17 00:00:00 2001 From: Achim Gsell Date: Fri, 30 Apr 2021 15:23:44 +0200 Subject: [PATCH 4/7] modmanage: shebang fixed --- Pmodules/modmanage.bash.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Pmodules/modmanage.bash.in b/Pmodules/modmanage.bash.in index 9a59809..acf750d 100755 --- a/Pmodules/modmanage.bash.in +++ b/Pmodules/modmanage.bash.in @@ -1,4 +1,4 @@ -#!@PMODULES_HOME@/sbin/bash +#!@BASH@ --noprofile # we have to unset CDPATH, otherwise 'cd' prints the directoy! unset CDPATH From 291039084b55d981e3a7122a70c58723989fa23c Mon Sep 17 00:00:00 2001 From: Achim Gsell Date: Fri, 30 Apr 2021 15:24:13 +0200 Subject: [PATCH 5/7] modmanage: hardcode CMD --- Pmodules/modmanage.bash.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Pmodules/modmanage.bash.in b/Pmodules/modmanage.bash.in index acf750d..1f74361 100755 --- a/Pmodules/modmanage.bash.in +++ b/Pmodules/modmanage.bash.in @@ -4,7 +4,7 @@ unset CDPATH # used for some output only -declare -r CMD=$(basename "$0") +declare -r CMD='modmanage' declare -r mydir=$(cd $(dirname "$0") && pwd) declare -r prefix=$(dirname "${mydir}") From 8c4d911fa5bda535c3a6aaf461ff4566de3303db Mon Sep 17 00:00:00 2001 From: Achim Gsell Date: Fri, 30 Apr 2021 15:27:46 +0200 Subject: [PATCH 6/7] modmanage: don't use PATH to find commands --- Pmodules/modmanage.bash.in | 66 ++++++++++++++++++++++++-------------- 1 file changed, 42 insertions(+), 24 deletions(-) diff --git a/Pmodules/modmanage.bash.in b/Pmodules/modmanage.bash.in index 1f74361..62727e3 100755 --- a/Pmodules/modmanage.bash.in +++ b/Pmodules/modmanage.bash.in @@ -6,17 +6,37 @@ unset CDPATH # used for some output only declare -r CMD='modmanage' -declare -r mydir=$(cd $(dirname "$0") && pwd) -declare -r prefix=$(dirname "${mydir}") +dirname=$(PATH=/bin:/usr/bin which dirname) +declare -r dirname +uname=$(PATH=/bin:/usr/bin which uname) +declare -r uname +mkdir=$(PATH=/bin:/usr/bin which mkdir) +declare -r mkdir +rsync=$(PATH=/bin:/usr/bin which rsync) +declare -r rsync +rm=$(PATH=/bin:/usr/bin /usr/bin/which rm) +declare -r rm + +if [[ $(${uname} -s) == 'Darwin' ]]; then + declare -r getopt="${libexecdir}/getopt" + declare -r find="${libexecdir}/find" +else + getopt=$(PATH=/bin:/usr/bin /usr/bin/which getopt) + declare -r getopt + find=$(PATH=/bin:/usr/bin /usr/bin/which find) + declare -r find +fi + + +declare -r mydir=$(cd $(${dirname} "$0") && pwd) +declare -r prefix=$(${dirname} "${mydir}") declare -r bindir="${prefix}/bin" -declare -r sbindir="${prefix}/sbin" declare -r libdir="${prefix}/lib" declare -r libexecdir="${prefix}/libexec" -source "${libdir}/libstd.bash" -source "${libdir}/libpmodules.bash" -PATH="${sbindir}:${bindir}:${PATH}" +source "${libdir}/libstd.bash" + _exit () { std::die 1 "Interrupted..." @@ -205,7 +225,7 @@ get_module_prefix() { # $1: relative module file path # get_releasefile_name() { - echo "$(dirname "$1")/.release-$(basename "$1")" + echo "$(${dirname} "$1")/.release-$(basename "$1")" } ############################################################################## @@ -234,8 +254,8 @@ sync_module() { # install/update module if [[ ! -d "${target_prefix}/${rel_module_prefix}" ]] || [[ "${force}" == 'yes' ]]; then - $DRY mkdir -p "${target_prefix}/${rel_module_prefix}" || return $? - $DRY rsync --links --perms --recursive --delete \ + $DRY ${mkdir} -p "${target_prefix}/${rel_module_prefix}" || return $? + $DRY ${rsync} --links --perms --recursive --delete \ "${src_prefix}/${rel_module_prefix}/" \ "${target_prefix}/${rel_module_prefix}/" || exit $? fi @@ -246,8 +266,8 @@ sync_module() { # create target directory for module- and release-file if [[ -e "${src_modulefile}" ]] || [[ -e "${src_releasefile}" ]]; then - local dir=$( dirname "${target_modulefile}" ) - $DRY mkdir -p "${dir}" || return $? + local dir=$( ${dirname} "${target_modulefile}" ) + $DRY ${mkdir} -p "${dir}" || return $? fi # copy modulefile template @@ -260,20 +280,20 @@ sync_module() { local -r src_template="${src_prefix}/${template}" local -r target_template="${target_prefix}/${template}" if [[ -e "${src_template}" ]]; then - $DRY mkdir -p "${target_template}" - $DRY rsync --links --perms --recursive \ + $DRY ${mkdir} -p "${target_template}" + $DRY ${rsync} --links --perms --recursive \ "${src_template}" "${target_template}" || exit $? fi # copy modulefile if [[ -e "${src_modulefile}" ]]; then - $DRY rsync --links --perms --recursive \ + $DRY ${rsync} --links --perms --recursive \ "${src_modulefile}" "${target_modulefile}" || exit $? fi # copy release-file if [[ -e "${src_releasefile}" ]]; then - $DRY rsync --links --perms --recursive \ + $DRY ${rsync} --links --perms --recursive \ "${src_releasefile}" "${target_releasefile}" || exit $? fi @@ -290,9 +310,8 @@ sync_module() { sync_config() { src="$1/${PMODULES_CONFIG_DIR}/" dst="$2/${PMODULES_CONFIG_DIR}/" - $DRY rsync --recursive --links --perms --delete \ + $DRY ${rsync} --recursive --links --perms --delete \ "${src}" "${dst}" 2>/dev/null || return $? - sed -i.bak "s/PMODULES_VERSION=\(.*\)/PMODULES_VERSION=${PMODULES_VERSION}/" "${dst}/environment.bash" echo } @@ -416,7 +435,7 @@ environment at '${PMODULES_ROOT}' fi force='yes' echo "Creating target directory '${target_prefix}'..." - $DRY mkdir -p "${target_prefix}" || \ + $DRY ${mkdir} -p "${target_prefix}" || \ std::die 1 "Error: make directory failed!" echo @@ -430,13 +449,12 @@ environment at '${PMODULES_ROOT}' "${src_prefix}" \ "${target_prefix}" || \ std::die 1 "Error: sync Pmodules failed!" - mkdir -p "${target_prefix}/Tools/${PMODULES_MODULEFILES_DIR}" - echo dst="${target_prefix}/${PMODULES_CONFIG_DIR}/environment.bash" echo "Adding installation source '${src_prefix}' to '${dst}'..." sed -i.bak '/PMODULES_INSTALL_SOURCE/d' "${dst}" echo "declare -x PMODULES_INSTALL_SOURCE=\"${src_prefix}\"" >> "${dst}" + ${mkdir} -p "${target_prefix}/Tools/${PMODULES_MODULEFILES_DIR}" echo if [[ -n "${user}" ]]; then @@ -505,7 +523,7 @@ get_group_depths () { cd "${root}" local group for group in "${Groups[@]}"; do - local fname=$(find "${group}/${modulefiles_dir}" \ + local fname=$(${find} "${group}/${modulefiles_dir}" \ -depth \( -type f -o -type l \) -print -quit) [[ -n ${fname} ]] || continue local -a tmp @@ -591,7 +609,7 @@ subcommand_install() { [[ -z ${dep} ]] && continue # search for module with current modulepath and remember - local modulename=$(find "${modulepath[@]}" -path "*/${dep}" \ + local modulename=$(${find} "${modulepath[@]}" -path "*/${dep}" \ 2>/dev/null | head -n 1 ) [[ -n ${modulename} ]] || \ std::die 3 "Oops: required module '${dep}' not found!" @@ -606,7 +624,7 @@ subcommand_install() { modulepath+=( "${path}" ) fi done < "${tmpfile}" - rm "${tmpfile}" + ${rm} "${tmpfile}" } #...................................................................... @@ -729,7 +747,7 @@ subcommand_install() { map_to_family[$_key]=${_family} fi done < <({ cd "${src_prefix}" && \ - find */"${PMODULES_MODULEFILES_DIR}" \ + ${find} */"${PMODULES_MODULEFILES_DIR}" \ \( -type l -o -type f \) \! -name ".*"; } 2>/dev/null ) # From 47bccd5fa8f8062eaea33ea7d7b80b0720e1eee6 Mon Sep 17 00:00:00 2001 From: Achim Gsell Date: Fri, 30 Apr 2021 15:30:17 +0200 Subject: [PATCH 7/7] modmange: functions from libpmodules.bash added --- Pmodules/modmanage.bash.in | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/Pmodules/modmanage.bash.in b/Pmodules/modmanage.bash.in index 62727e3..6e11be2 100755 --- a/Pmodules/modmanage.bash.in +++ b/Pmodules/modmanage.bash.in @@ -345,11 +345,26 @@ delete_module() { # Initialize a new module environment in this directory- # subcommand_init() { + check_env() { + [[ -n "${PMODULES_ROOT}" ]] && + [[ -d "${PMODULES_ROOT}" ]] && + [[ -n "${PMODULES_HOME}" ]] && + [[ -n "${PMODULES_VERSION}" ]] || \ + std::die 1 " +Error: the module environment you are going to use as so urce has not been +initialized properly!" + + [[ -d "${src_prefix}/${PMODULES_CONFIG_DIR}" ]] && + [[ -d "${src_prefix}/Tools/Pmodules/${PMODULES_VERSION}" ]] || \ + std::die 1 " +Error: the module environment '${src_prefix}' has not been initialized properly!" + } + local src='' local target_prefixes=() local user='' local opts='' - opts=$(pmodules::get_options -o h -l src: -l user: -l help -l version: -- "$@") + opts=$(${getopt} -o h -l src: -l user: -l help -l version: -- "$@") if [[ $? != 0 ]]; then subcommand_help_init exit 1 @@ -407,7 +422,7 @@ subcommand_init() { std::die 1 "Error: --user option is only allowed if running as root!" fi - pmodules::check_env || \ + check_env || \ std::die 1 "Giving up..." echo " @@ -449,11 +464,6 @@ environment at '${PMODULES_ROOT}' "${src_prefix}" \ "${target_prefix}" || \ std::die 1 "Error: sync Pmodules failed!" - - dst="${target_prefix}/${PMODULES_CONFIG_DIR}/environment.bash" - echo "Adding installation source '${src_prefix}' to '${dst}'..." - sed -i.bak '/PMODULES_INSTALL_SOURCE/d' "${dst}" - echo "declare -x PMODULES_INSTALL_SOURCE=\"${src_prefix}\"" >> "${dst}" ${mkdir} -p "${target_prefix}/Tools/${PMODULES_MODULEFILES_DIR}" echo @@ -667,7 +677,7 @@ subcommand_install() { std::info "" } - opts=$(pmodules::get_options -o hf -l dry-run -l force -l with: -l release: -l help -l src: -- "$@") + opts=$(${getopt} -o hf -l dry-run -l force -l with: -l release: -l help -l src: -- "$@") if [[ $? != 0 ]]; then subcommand_help_install exit 1