From 1aebcfd0698509a37dd4f02f60a742ce7a63e0ee Mon Sep 17 00:00:00 2001 From: Achim Gsell Date: Wed, 27 Jul 2022 11:03:57 +0200 Subject: [PATCH 01/20] profile.zsh: rename __pm_root__ to __this_file__ --- Pmodules/profile.zsh.in | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Pmodules/profile.zsh.in b/Pmodules/profile.zsh.in index b0a7f4a..6accc21 100644 --- a/Pmodules/profile.zsh.in +++ b/Pmodules/profile.zsh.in @@ -5,10 +5,11 @@ : ${PMODULES_VERSION:=@PMODULES_VERSION@} ##### no changes below this line ###### +export PMODULES_VERSION -declare __pm_root__=${(%):-%N} -declare -x PMODULES_HOME="${__pm_root__:h:h}/Tools/Pmodules/${PMODULES_VERSION}" -unset __pm_root__ +declare __this_file__=${(%):-%N} +declare -x PMODULES_HOME="${__this_file____:h:h}/Tools/Pmodules/${PMODULES_VERSION}" +unset __this_file__ test -r "${PMODULES_HOME}/init/zsh" && source "$_" From d9cf0684cd2314839fdc71522907e0f9cb4cb98f Mon Sep 17 00:00:00 2001 From: Achim Gsell Date: Wed, 27 Jul 2022 13:42:21 +0200 Subject: [PATCH 02/20] modulecmd: unalias issue in sub-cmd purge fixed --- Pmodules/modulecmd.bash.in | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Pmodules/modulecmd.bash.in b/Pmodules/modulecmd.bash.in index b4a2035..cad2c56 100644 --- a/Pmodules/modulecmd.bash.in +++ b/Pmodules/modulecmd.bash.in @@ -754,7 +754,7 @@ subcommand_unload() { local arg for arg in "${args[@]}"; do local output=$("${modulecmd}" "${Shell}" 'unload' "${arg}") - eval "$(echo "${output}"|sed -e 's/;unalias [^;]*//g')" + eval "$(echo "${output}"|${sed} -e 's/;unalias [^;]*//g')" case ${Shell} in sh | bash | zsh ) echo "${output}" @@ -1922,8 +1922,8 @@ subcommand_purge() { "${error_txt}" fi if [[ "${Shell}" == "sh" ]]; then - # for sh-like shells just echo - echo "${output}" + # for sh-like shells just echo + eval "$(echo "${output}"|${sed} -e 's/;unalias [^;]*//g')" else # re-run with right shell "${modulecmd}" "${Shell}" 'purge' From 3a0ab7168424d48fc2966907f3406e4770e279ab Mon Sep 17 00:00:00 2001 From: Achim Gsell Date: Thu, 28 Jul 2022 16:12:20 +0200 Subject: [PATCH 03/20] modulecmd: bugfix in sub-cmd 'use' Missing return added if argument is a directory to add to MODULEPATH --- Pmodules/modulecmd.bash.in | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/Pmodules/modulecmd.bash.in b/Pmodules/modulecmd.bash.in index cad2c56..da6f6fd 100644 --- a/Pmodules/modulecmd.bash.in +++ b/Pmodules/modulecmd.bash.in @@ -1496,20 +1496,21 @@ subcommand_use() { if is_release_stage "${arg}"; then # argument is release stage std::append_path UsedReleaseStages "${arg}" - return + return $? fi if [[ "${arg}" =~ "flag=" ]]; then # argument is flag UsedFlags+=( "${arg/flag=}" ) - return + return $? fi if [[ -v OverlayInfo[${arg}:type] ]]; then use_overlay "${arg}" - return 0 + return $? fi if [[ -d ${arg} ]]; then local dir=$(cd "${arg}" && pwd -L) ${add2path_func} MODULEPATH "${dir}" + return $? fi if [[ ! -v GroupDepths[${arg}] ]]; then # this scan is required if a new group has been @@ -1519,7 +1520,7 @@ subcommand_use() { fi if [[ -n ${GroupDepths[${arg}]} ]]; then use_group "${arg}" - return + return $? fi std::die 3 "%s %s: %s -- %s" \ From b764a92f2cbc5794fe95a8408cc9ccab9c461a6c Mon Sep 17 00:00:00 2001 From: Achim Gsell Date: Thu, 28 Jul 2022 16:15:05 +0200 Subject: [PATCH 04/20] modulecmd: restrict search to group and output only newest Two option have been added to the search sub-cmd: --newest: output only the newest version matching the search string --group : search only in --- Pmodules/modulecmd.bash.in | 162 +++++++++++++++++++++---------------- 1 file changed, 93 insertions(+), 69 deletions(-) diff --git a/Pmodules/modulecmd.bash.in b/Pmodules/modulecmd.bash.in index da6f6fd..e028579 100644 --- a/Pmodules/modulecmd.bash.in +++ b/Pmodules/modulecmd.bash.in @@ -2046,10 +2046,12 @@ Options[search]='-o a\?H -l help -l no-header -l print-modulefiles ' Options[search]+='-l release-stage: -l with: -l all-release-stages -l src: -l print-csv ' Options[search]+='-l verbose ' Options[search]+='-l all-deps -l wrap ' -Options[search]+='-l glob' +Options[search]+='-l glob ' +Options[search]+='-l newest ' +Options[search]+='-l group:' Help[search]=' USAGE: - module search [switches] STRING... + module find|search [switches] STRING... Search installed modules. If an argument is given, search for modules whose name match the argument. @@ -2089,6 +2091,7 @@ SWITCHES: subcommand_search() { local -r subcommand='search' local modules=() + local groups=() local with_modules='//' local -ir cols=$(tput cols) # get number of columns of terminal local -i max_len_modulename=0 @@ -2101,6 +2104,7 @@ subcommand_search() { local opt_all_deps='no' local opt_wrap='no' local opt_glob='no' + local opt_newest='no' #..................................................................... # @@ -2168,9 +2172,7 @@ subcommand_search() { } print_header_verbose() { - std::info '' - #std::info "${fmt}" "Module" "Rel.stage" "Group" "Overlay" "Dependencies/Modulefile" - #std::info '-%.0s' $(seq 1 ${cols}) + : } print_line_verbose() { @@ -2196,7 +2198,9 @@ subcommand_search() { } print_line_modulefile() { - std::info "$4" + if (( $# >= 4 )) && [[ -n $4 ]]; then + std::info "$1 $4" + fi } print_line_csv() { @@ -2219,11 +2223,15 @@ subcommand_search() { print_default fi + local _script='' + if [[ ${opt_newest} == 'yes' ]]; then + _script='{} END{print}' + fi ${func_print_header} while read -a toks; do ${func_print_line} "${toks[@]}" done < <("${sort}" --version-sort -k 1,1 -k 6,6 -k 7,7 "${tmpfile}" | \ - ${awk} "${with_modules}") + ${awk} "${with_modules} ${_script}") } #..................................................................... @@ -2236,72 +2244,65 @@ subcommand_search() { # :FIXME: # search () { - if [[ ${opt_glob} == 'yes' ]]; then - local -r module="$1" - else - local -r module="${1}*" - fi - + local module="$1" + local group="$2" # write results to a temporary file for later processing - local group - # loop over all groups - for group in "${!GroupDepths[@]}"; do - # loop over all directories which can be added to - # MODULEPATH inside current group - local depth=${GroupDepths[${group}]} - local s='' - if (( depth > 0 )); then - s=$(printf '/*%.0s' $(seq 1 ${depth})) - fi - local modulepath=( ${src_prefix[@]/%//${group}/modulefiles$s} ) + + # loop over all directories which can be added to + # MODULEPATH inside current group + local depth=${GroupDepths[${group}]} + local s='' + if (( depth > 0 )); then + s=$(printf '/*%.0s' $(seq 1 ${depth})) + fi + local modulepath=( ${src_prefix[@]/%//${group}/modulefiles$s} ) + + # get and print all available modules in $mpath + # with respect to the requested release stage + # tmpfile: module/version rel_stage group dependencies... + local mods + get_available_modules \ + mods \ + "${module}" \ + "${opt_use_rel_stages}" \ + "${modulepath[@]}" + local i=0 + for (( i=0; i<${#mods[@]}; i+=4 )); do + local name=${mods[i]} + local rel_stage=${mods[i+1]} + local modulefile=${mods[i+2]} + local ol=${mods[i+3]} - # get and print all available modules in $mpath - # with respect to the requested release stage - # tmpfile: module/version rel_stage group dependencies... - local mods - get_available_modules \ - mods \ - "${module}" \ - "${opt_use_rel_stages}" \ - "${modulepath[@]}" \ - - for (( i=0; i<${#mods[@]}; i+=4 )); do - local name=${mods[i]} - local rel_stage=${mods[i+1]} - local modulefile=${mods[i+2]} - local ol=${mods[i+3]} - - if (( ${#name} > max_len_modulename)); then - max_len_modulename=${#name} - fi - - if [[ "${opt_print_verbose}" == 'yes' ]] || [[ "${opt_all_deps}" == 'yes' ]]; then - local prefix='' - get_module_prefix prefix "${modulefile}" - local dependencies_file="${prefix}/.dependencies" - if [[ -n ${prefix} ]] && [[ -r "${dependencies_file}" ]]; then - deps=($(< "${dependencies_file}")) - else - deps=() - fi + if (( ${#name} > max_len_modulename)); then + max_len_modulename=${#name} + fi + + if [[ "${opt_print_verbose}" == 'yes' ]] || \ + [[ "${opt_all_deps}" == 'yes' ]]; then + local prefix='' + get_module_prefix prefix "${modulefile}" + local dependencies_file="${prefix}/.dependencies" + if [[ -n ${prefix} ]] && [[ -r "${dependencies_file}" ]]; then + deps=($(< "${dependencies_file}")) else - # get dependencies encoded in directory name - local deps=() - local -i j - IFS='/' # note: IFS is used to concat in the for loop! - local toks=( ${modulefile} ) - for ((j = -depth-2; j < -2; j += 2)); do - deps+=( "${toks[*]: $j:2}" ); - done - unset IFS + deps=() fi - - echo ${name} ${rel_stage} ${group} ${modulefile} \ - ${ol} \ - ${deps[@]} >> "${tmpfile}" - done + else + # get dependencies encoded in directory name + local deps=() + local -i j + IFS='/' # note: IFS is used to concat in the for loop! + local toks=( ${modulefile} ) + for ((j = -depth-2; j < -2; j += 2)); do + deps+=( "${toks[*]: $j:2}" ); + done + unset IFS + fi + + echo ${name} ${rel_stage} ${group} ${modulefile} \ + ${ol} \ + ${deps[@]} >> "${tmpfile}" done - print_result } while (( $# > 0 )); do @@ -2389,6 +2390,18 @@ subcommand_search() { --glob ) opt_glob='yes' ;; + --newest ) + opt_newest='yes' + ;; + --group | --group=* ) + if [[ $1 == *=* ]]; then + groups+=( ${1/--*=} ) + else + groups+=( $2 ) + shift + fi + ;; + -- ) shift 1 modules+=( "$@" ) @@ -2423,8 +2436,19 @@ subcommand_search() { fi local module + if (( ${#groups[@]} == 0 )); then + groups=( "${!GroupDepths[@]}" ) + fi for module in "${modules[@]}"; do - search "${module}" + if [[ ${opt_glob} != 'yes' ]]; then + module+="*" + fi + local group + for group in "${groups[@]}"; do + search "${module}" "${group}" + done + print_result + echo -n > ${tmpfile} done } From 9f3496010b9031fc7745fe68a450d089545ec8ce Mon Sep 17 00:00:00 2001 From: Achim Gsell Date: Thu, 28 Jul 2022 16:19:35 +0200 Subject: [PATCH 05/20] modulecmd: sub-cmds whatis and keyword/apropos fixed --- Pmodules/modulecmd.bash.in | 101 +++++++++++++++++++++++++++++++++---- 1 file changed, 92 insertions(+), 9 deletions(-) diff --git a/Pmodules/modulecmd.bash.in b/Pmodules/modulecmd.bash.in index e028579..32c52d7 100644 --- a/Pmodules/modulecmd.bash.in +++ b/Pmodules/modulecmd.bash.in @@ -2533,7 +2533,7 @@ subcommand_help() { # whatis # Subcommands[whatis]='whatis' -Options[whatis]='-o \?H -l help' +Options[whatis]='-o \?Ha -l help -l all' Help[whatis]=' USAGE: module whatis [modulefile...] @@ -2543,11 +2543,46 @@ USAGE: ' subcommand_whatis() { - if (( $# == 0 )); then - subcommand_generic0 'whatis' - else - subcommand_generic1plus 'whatis' "$@" - fi + local options=() + local args=() + while (( $# > 0 )); do + case $1 in + -\? | --help ) + print_help "${subcommand}" + ;; + -a | --all ) + options+=( '-a' ) + ;; + -- ) + shift 1 + args+=( "$@" ) + break + ;; + * ) + args+=( "$1" ) + ;; + esac + shift + done + + local group='' + for group in "${!GroupDepths[@]}"; do + local mod_name='' + local file_name='' + while read mod_name file_name; do + [[ -n ${file_name} ]] || continue + local whatis=$("${modulecmd}" bash \ + whatis \ + "${file_name}" \ + 2>&1 1>/dev/null) + printf "%-25s: %s\n" "${mod_name}" "${whatis/*:}" 1>&2 + done < <(set +x; subcommand_search \ + --group "${group}" \ + --print-modulefiles \ + --newest \ + "${options[@]}" \ + "${args[@]}" 2>&1) + done } ############################################################################## @@ -2556,7 +2591,7 @@ subcommand_whatis() { # Subcommands[apropos]='apropos' Subcommands[keyword]='apropos' -Options[apropos]='-o \?H -l help' +Options[apropos]='-o \?Ha -l help -l all' Help[apropos]=' USAGE: module apropos string @@ -2566,7 +2601,55 @@ USAGE: ' subcommand_apropos() { - subcommand_generic1 'apropos' "$@" + local options=() + local args=() + while (( $# > 0 )); do + case $1 in + -\? | --help ) + print_help "${subcommand}" + ;; + -a | --all ) + options+=( '-a' ) + ;; + -- ) + shift 1 + args+=( "$@" ) + break + ;; + * ) + args+=( "$1" ) + ;; + esac + shift + done + if (( ${#args[@]} == 0 )); then + std::die 3 "%s %s: %s" \ + "${CMD}" "${subcommand}" \ + "no search string specified" + elif (( ${#args[@]} > 1 )); then + std::die 3 "%s %s: %s" \ + "${CMD}" "${subcommand}" \ + "more then one search string specified" + fi + local arg="${args[0]}" + local group='' + for group in "${!GroupDepths[@]}"; do + local mod_name='' + local file_name='' + while read mod_name file_name; do + [[ -n ${file_name} ]] || continue + local whatis=$("${modulecmd}" bash \ + whatis \ + "${file_name}" \ + 2>&1 1>/dev/null) + if [[ ${whatis,,} =~ ${arg,,} ]]; then + printf "%-25s: %s\n" "${mod_name}" "${whatis/*:}" 1>&2 + fi + done < <(set +x; subcommand_search \ + --group "${group}" \ + --print-modulefiles \ + "${options[@]}" 2>&1) + done } ############################################################################## @@ -2808,7 +2891,7 @@ if (( ${#GroupDepths[@]} == 0 )); then fi case ${subcommand} in - load|purge|search|swap ) + load|purge|search|swap|whatis|apropos ) declare -r tmpfile=$( ${mktemp} /tmp/Pmodules.XXXXXX ) \ || std::die 1 "Oops: unable to create tmp file!" ;; From e4e21ebd5524660177d0cb86950abf76eb38f3bb Mon Sep 17 00:00:00 2001 From: Achim Gsell Date: Thu, 28 Jul 2022 16:20:09 +0200 Subject: [PATCH 06/20] modulecmd: add 'find' as alias of sub-cmd 'search' In the Tcl Environment Module version 4 and newer the sub-cmds 'appropos' and 'keyword' have been replaced by the sub-cmd 'search'. Thsi conflicts with Pmodules 'search' sub-cmd. In the future we might have to rename the 'search' sub-cmd to 'find'. --- Pmodules/modulecmd.bash.in | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Pmodules/modulecmd.bash.in b/Pmodules/modulecmd.bash.in index 32c52d7..0c25562 100644 --- a/Pmodules/modulecmd.bash.in +++ b/Pmodules/modulecmd.bash.in @@ -2859,6 +2859,9 @@ case ${subcommand} in rm ) subcommand='unload' ;; + find ) + subcommand='search' + ;; switch ) subcommand='swap' ;; From 1048ebfe40415a05eb6ffd7b36c6bf190625ad40 Mon Sep 17 00:00:00 2001 From: Achim Gsell Date: Fri, 29 Jul 2022 08:43:55 +0200 Subject: [PATCH 07/20] Changelog edited --- CHANGELOG.md | 54 +++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 47 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9bc8906..8cb283d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,20 +1,60 @@ # Changelog of Pmodules -## Version 1.1.10 +## Version 1.1.10 (not yet tagged) * **modulecmd** * *User visible changes* - * ... + * New options for `module search`. + * With the option `--group` the search can be restricted to a + group. + * With the option `--newest` only the newest versions are + displayed. + * `find` as alias for the sub-command `search` added. + * Bugfix: the sub-commands `whatis` and `keyword|apropos` were + broken by design. + * Bugfix: after loading a `Pmodules` module, it was not shown with + `module list`. + * Bugfix in scanning the depth of groups. + * Bugfix: after `module purge` the environment variable + `PMODULES_HOME` was not defined an more. + * Bugfix: source the shell init file only if a `Pmodules` module + is loaded. + * Bugfix: unsetting aliases in modulefiles was not handled + properly in `module purge` * *Internal changes and fixes* - * ... + * initialisation error for bash and zsh fixed * **build-system** * *User visible changes* - * ... - * *Internal changes and fixes* - * ... + * `modbuild` is now defined as function like `module`. Therefor no + `Pmodules` module must be loaded to build a module with `modbuild` + * The system can now be defined in the module (YAML) configuration + file. + * Build dependencies can (and should) now be specified with + `build_requires` in the YAML configuration file. + * Bugfix: cleanup of modulefiles in overlays fixed. A module can be in + more than one overlay. These overlays must be specified in the + module configuration file. + * Bugfix: querying dependencies from YAML configuration file + fixed. Under some conditions the string 'null' was in the list + of dependencies. + * Bugfix: create group directory if it doesn't exist. + * Bugfix: create the module `$PREFIX` before processing the + install targets not before all targets. If `$PREFIX` is created + before processing any target and the build fails, `modbuild` + assumes that the module have been already built successfully. + * *Internal changes and fixes* + * code review/re-factoring + * `modbuild` is now using the Bash installed in `Pmodules` itself. + * test code with `set -o nounset`, several issues with this + setting fixed (not necessarily bugs). * **other changes** - * ... + * The build script to bootstrap Pmodules itself doesn't use modbuild + any more to compile required software packages. With this change + we can remove some special cases from modbuild. + * The bootstrap script requires Bash 5.0 or newer now. + * Bugfix: in the `Pmodules` modulefile force the sourcing of the + shell init script while in mode `load` only. ## Version 1.1.9 * **modulecmd** From 06c41be687dd9650f73351be2ad78a173833fe97 Mon Sep 17 00:00:00 2001 From: Achim Gsell Date: Fri, 29 Jul 2022 14:47:33 +0200 Subject: [PATCH 08/20] modbuild/libpbuild: print warnings if deprecated functions are used --- Pmodules/libpbuild.bash | 23 ++++++++++++++++++++--- Pmodules/modbuild.in | 5 ++--- 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/Pmodules/libpbuild.bash b/Pmodules/libpbuild.bash index ddb954f..b313d6f 100644 --- a/Pmodules/libpbuild.bash +++ b/Pmodules/libpbuild.bash @@ -720,9 +720,26 @@ pbuild::install_shared_libs() { ############################################################################### # -# This is the main entry function called by modbuild! +# The following two functions are the entry points called by modbuild! # -pbuild.build_module() { + +declare yaml_config='yes' +pbuild.build_module_legacy(){ + yaml_config='no' + _build_module "$@" +} +readonly -f pbuild.build_module_legacy + +pbuild.build_module_yaml(){ + _build_module "$@" +} +readonly -f pbuild.build_module_yaml + +#.............................................................................. +# +# The real worker function. +# +_build_module() { declare -gx module_name="$1" declare -gx module_version="$2" declare -gx module_release="$3" @@ -1583,7 +1600,7 @@ pbuild.build_module() { cleanup_modulefiles std::info "* * * * *\n" } -readonly -f pbuild.build_module +readonly -f _build_module # Local Variables: # mode: sh diff --git a/Pmodules/modbuild.in b/Pmodules/modbuild.in index a87ab5f..5514f0c 100755 --- a/Pmodules/modbuild.in +++ b/Pmodules/modbuild.in @@ -436,7 +436,7 @@ build_modules_legacy() { version="${tokens[0]#*/}" release="${tokens[1]}" with_modules=( "${tokens[@]:2}" ) - pbuild.build_module \ + pbuild.build_module_legacy \ "${name}" "${version}" \ "${release}" "${with_modules[@]}" done @@ -647,7 +647,7 @@ build_modules_yaml(){ "${relstage}" "${with_modules[@]}" done < <(bash_expand "" ${deps[@]}|${awk} "${pattern}") else - pbuild.build_module \ + pbuild.build_module_yaml \ "${name}" "${v##*/}" \ "${relstage}" fi @@ -655,7 +655,6 @@ build_modules_yaml(){ done } - build_modules() { if [[ -n $(ls "${BUILDBLOCK_DIR}/files/${BNAME_VARIANTS}"*.yaml 2>/dev/null) ]]; then build_modules_yaml "$@" From c8b61bbf5f84d49ed623fedc78c7b0afbeb0bc78 Mon Sep 17 00:00:00 2001 From: Achim Gsell Date: Fri, 29 Jul 2022 14:50:25 +0200 Subject: [PATCH 09/20] libpbuild: pbuild::supported_os removed --- Pmodules/libpbuild.bash | 26 -------------------------- 1 file changed, 26 deletions(-) diff --git a/Pmodules/libpbuild.bash b/Pmodules/libpbuild.bash index b313d6f..305bc97 100644 --- a/Pmodules/libpbuild.bash +++ b/Pmodules/libpbuild.bash @@ -227,19 +227,6 @@ pbuild::supported_systems() { } readonly -f pbuild::supported_systems -############################################################################## -# -# Check whether the script is running on a supported OS. -# -# Arguments: -# $@: supported opertating systems (like Linux, Darwin). -# Default is all. -# -pbuild::supported_os() { - SUPPORTED_OS+=( "$@" ) -} -readonly -f pbuild::supported_os - ############################################################################## # # Check whether the loaded compiler is supported. @@ -1013,7 +1000,6 @@ _build_module() { declare -Ag SOURCE_UNPACK_DIRS=() CONFIGURE_ARGS=() SUPPORTED_SYSTEMS=() - SUPPORTED_OS=() SUPPORTED_COMPILERS=() PATCH_FILES=() PATCH_STRIPS=() @@ -1033,17 +1019,6 @@ _build_module() { "Not available for ${system}." } - #...................................................................... - check_supported_os() { - (( ${#SUPPORTED_OS[@]} == 0 )) && return 0 - for os in "${SUPPORTED_OS[@]}"; do - [[ ${os,,} == ${OS,,} ]] && return 0 - done - std::die 1 \ - "%s " "${module_name}/${module_version}:" \ - "Not available for ${OS}." - } - #...................................................................... check_supported_compilers() { (( ${#SUPPORTED_COMPILERS[@]} == 0 )) && return 0 @@ -1564,7 +1539,6 @@ _build_module() { # check whether this module is supported check_supported_systems - check_supported_os check_supported_compilers # setup module name and prefix set_full_module_name_and_prefix From bc381367879cf7aec7312944e25f6834369ef3c6 Mon Sep 17 00:00:00 2001 From: Achim Gsell Date: Fri, 29 Jul 2022 14:53:01 +0200 Subject: [PATCH 10/20] modbuild: quering group, supported systems and compilers added to YAML another big change is the re-ordering of the public pbuild:: functions --- Pmodules/libpbuild.bash | 428 +++++++++++++++++++++++----------------- Pmodules/modbuild.in | 42 ++-- 2 files changed, 264 insertions(+), 206 deletions(-) diff --git a/Pmodules/libpbuild.bash b/Pmodules/libpbuild.bash index 305bc97..1a4893b 100644 --- a/Pmodules/libpbuild.bash +++ b/Pmodules/libpbuild.bash @@ -116,136 +116,26 @@ pbuild.verbose() { readonly -f pbuild.verbose -############################################################################### +#****************************************************************************** # # function in the "namespace" (with prefix) 'pbuild::' can be used in # build-scripts # -#.............................................................................. +############################################################################### # -# compare two version numbers +# general functions # -# original implementation found on stackoverflow: -# https://stackoverflow.com/questions/4023830/how-to-compare-two-strings-in-dot-separated-version-format-in-bash -# -pbuild::version_compare () { - is_uint() { - [[ $1 =~ ^[0-9]+$ ]] - } - - [[ $1 == $2 ]] && return 0 - local IFS=. - local i ver1=($1) ver2=($2) - - # fill empty fields in ver1 with zeros - for ((i=${#ver1[@]}; i<${#ver2[@]}; i++)); do - ver1[i]=0 - done - for ((i=0; i<${#ver1[@]}; i++)); do - [[ -z ${ver2[i]} ]] && ver2[i]=0 - if is_uint ${ver1[i]} && is_uint ${ver2[i]}; then - ((10#${ver1[i]} > 10#${ver2[i]})) && return 1 - ((10#${ver1[i]} < 10#${ver2[i]})) && return 2 - else - [[ ${ver1[i]} > ${ver2[i]} ]] && return 1 - [[ ${ver1[i]} < ${ver2[i]} ]] && return 2 - fi - done - return 0 -} -readonly -f pbuild::version_compare #.............................................................................. -# version less than -# -# return 0 if version passed in $1 is older then $2 -# -pbuild::version_lt() { - pbuild::version_compare "$1" "$2" - (( $? == 2 )) -} -readonly -f pbuild::version_lt - -#.............................................................................. -# version less than or equal -# -# return 0 if version passed in $1 is older or equal then $2 -# -pbuild::version_le() { - pbuild::version_compare "$1" "$2" - local -i exit_code=$? - (( exit_code == 0 || exit_code == 2 )) -} -readonly -f pbuild::version_le - -#.............................................................................. -# version greater than -# -# return 0 if version passed in $1 is newer then $2 -# -pbuild::version_gt() { - pbuild::version_compare "$1" "$2" - (( $? == 1 )) - local -i exit_code=$? - (( exit_code == 0 || exit_code == 1 )) -} -readonly -f pbuild::version_gt - -#.............................................................................. -# version greater than -# -# return 0 if version passed in $1 and $2 are equal -# -pbuild::version_eq() { - pbuild::version_compare "$1" "$2" -} -readonly -f pbuild::version_eq - -############################################################################## -# -# Set flag to build module in source tree. -# -# Arguments: -# none -# -pbuild::compile_in_sourcetree() { - BUILD_DIR="${SRC_DIR}" -} -readonly -f pbuild::compile_in_sourcetree - -############################################################################## -# -# Check whether the script is running on a supported OS. -# -# Arguments: -# $@: supported opertating systems (something like RHEL6, macOS10.14, ...). -# Default is all. -# -pbuild::supported_systems() { - SUPPORTED_SYSTEMS+=( "$@" ) -} -readonly -f pbuild::supported_systems - -############################################################################## -# -# Check whether the loaded compiler is supported. -# -# Arguments: -# $@: supported compiler (like GCC, Intel, PGI). -# Default is all. -# -pbuild::supported_compilers() { - SUPPORTED_COMPILERS+=( "$@" ) -} -readonly -f pbuild::supported_compilers - -############################################################################## # # Install module in given group. # +# Note: +# This function is deprecated with YAML module configuration files. +# # Arguments: -# $1: group +# $1: group # pbuild::add_to_group() { if (( $# == 0 )); then @@ -253,23 +143,25 @@ pbuild::add_to_group() { "%s " "${module_name}/${module_version}:" \ "${FUNCNAME}: missing group argument." fi - GROUP="$1" + if (( $# > 1 )); then + std::die 42 \ + "%s " "${module_name}/${module_version}:" \ + "${FUNCNAME}: only one argument is allowed." + fi + if [[ ${yaml_config} == 'yes' ]]; then + std::info \ + "Using ${FUNCNAME} is deprecated with YAML module configuration files." + fi + pbuild.add_to_group "$@" } readonly -f pbuild::add_to_group -############################################################################## -# -# Set documentation file to be installed. -# -# Arguments: -# $@: documentation files relative to source -# -pbuild::install_docfiles() { - MODULE_DOCFILES+=("$@") +pbuild.add_to_group(){ + GROUP="$1" } -readonly -f pbuild::install_docfiles +readonly -f pbuild.add_to_group -############################################################################## +#.............................................................................. # # Test whether a module with the given name is available. If yes, return # release @@ -302,8 +194,153 @@ pbuild::module_is_avail() { } readonly -f pbuild::module_is_avail +#.............................................................................. +# +# compare two version numbers +# +# pbuild::version_compare +# - returns 0 if the version numbers are equal +# - returns 1 if first version number is higher +# - returns 2 if second version number is higher +# +# pbuild::version_lt +# - returns 0 if second version number is higher +# pbuild::version_le +# - returns 0 if second version number is higher or equal +# pbuild::version_gt +# - returns 0 if first version number is higher +# pbuild::version_ge +# - returns 0 if first version number is higher or equal +# pbuild::version_eq +# - returns 0 if version numbers are equal +# +# otherwise a value != 0 is returned +# +# Arguments: +# $1 first version number +# $2 second version number +# +# Note: +# Original implementation found on stackoverflow: +# https://stackoverflow.com/questions/4023830/how-to-compare-two-strings-in-dot-separated-version-format-in-bash +# +pbuild::version_compare () { + is_uint() { + [[ $1 =~ ^[0-9]+$ ]] + } + + [[ $1 == $2 ]] && return 0 + local IFS=. + local i ver1=($1) ver2=($2) + + # fill empty fields in ver1 with zeros + for ((i=${#ver1[@]}; i<${#ver2[@]}; i++)); do + ver1[i]=0 + done + for ((i=0; i<${#ver1[@]}; i++)); do + [[ -z ${ver2[i]} ]] && ver2[i]=0 + if is_uint ${ver1[i]} && is_uint ${ver2[i]}; then + ((10#${ver1[i]} > 10#${ver2[i]})) && return 1 + ((10#${ver1[i]} < 10#${ver2[i]})) && return 2 + else + [[ ${ver1[i]} > ${ver2[i]} ]] && return 1 + [[ ${ver1[i]} < ${ver2[i]} ]] && return 2 + fi + done + return 0 +} +readonly -f pbuild::version_compare + +pbuild::version_lt() { + pbuild::version_compare "$1" "$2" + (( $? == 2 )) +} +readonly -f pbuild::version_lt + +pbuild::version_le() { + pbuild::version_compare "$1" "$2" + local -i exit_code=$? + (( exit_code == 0 || exit_code == 2 )) +} +readonly -f pbuild::version_le + +pbuild::version_gt() { + pbuild::version_compare "$1" "$2" + (( $? == 1 )) + local -i exit_code=$? + (( exit_code == 1 )) +} +readonly -f pbuild::version_gt + +pbuild::version_ge() { + pbuild::version_compare "$1" "$2" + (( $? == 1 )) + local -i exit_code=$? + (( exit_code == 0 || exit_code == 1 )) +} +readonly -f pbuild::version_gt + +pbuild::version_eq() { + pbuild::version_compare "$1" "$2" +} +readonly -f pbuild::version_eq + +#.............................................................................. +# +# Check whether the loaded compiler is supported. +# +# Arguments: +# $@: supported compiler (like GCC, Intel, PGI). +# Default is all. +# +pbuild::supported_compilers() { + if [[ ${yaml_config} == 'yes' ]]; then + std::info \ + "Using ${FUNCNAME} is deprecated with YAML module configuration files." + fi + pbuild.supported_compilers "$@" +} +readonly -f pbuild::supported_compilers + +pbuild.supported_compilers(){ + SUPPORTED_COMPILERS+=( "$@" ) +} +readonly -f pbuild.supported_compilers + +#.............................................................................. +# +# Check whether the script is running on a supported OS. +# +# Arguments: +# $@: supported opertating systems (something like RHEL6, macOS10.14, ...). +# Default is all. +# +pbuild::supported_systems() { + if [[ ${yaml_config} == 'yes' ]]; then + std::info \ + "Using ${FUNCNAME} is deprecated with YAML module configuration files." + fi + pbuild.supported_systems "$@" +} +readonly -f pbuild::supported_systems + +pbuild.supported_systems() { + SUPPORTED_SYSTEMS+=( "$@" ) +} + +#.............................................................................. +# +pbuild::use_flag() { + [[ "${USE_FLAGS}" =~ ":${1}:" ]] +} +readonly -f pbuild::use_flag + ############################################################################## # +# functions to prepare the sources + +#.............................................................................. +# # Set the download URL and name of downloaded file. # # Arguments: @@ -320,7 +357,7 @@ pbuild::set_download_url() { } readonly -f pbuild::set_download_url -############################################################################## +#.............................................................................. # # Set hash sum for file. # @@ -335,7 +372,7 @@ pbuild::set_sha256sum() { } readonly -f pbuild::set_sha256sum -############################################################################## +#.............................................................................. # # Unpack file $1 in directory $2 # @@ -348,23 +385,7 @@ pbuild::set_unpack_dir() { } readonly -f pbuild::set_unpack_dir -############################################################################## -# -# Use this C-compiler -# -# Arguments: -# $1 C-compiler to use. -# -pbuild::use_cc() { - [[ -x "$1" ]] || std::die 3 \ - "%s " "${module_name}/${module_version}:" \ - "Error in setting CC:" \ - "'$1' is not an executable!" - CC="$1" -} -readonly -f pbuild::use_cc - -############################################################################### +#.............................................................................. # pbuild::add_patch() { [[ -z "$1" ]] && \ @@ -380,7 +401,7 @@ pbuild::add_patch() { } readonly -f pbuild::add_patch -############################################################################### +#.............................................................................. # pbuild::set_default_patch_strip() { [[ -n "$1" ]] || \ @@ -392,35 +413,7 @@ pbuild::set_default_patch_strip() { } readonly -f pbuild::set_default_patch_strip -############################################################################### -# -pbuild::use_flag() { - [[ "${USE_FLAGS}" =~ ":${1}:" ]] -} -readonly -f pbuild::use_flag - -############################################################################### -# -pbuild::add_configure_args() { - CONFIGURE_ARGS+=( "$@" ) -} -readonly -f pbuild::add_configure_args - -############################################################################### -# -pbuild::use_autotools() { - configure_with='autotools' -} -readonly -f pbuild::use_autotools - -############################################################################### -# -pbuild::use_cmake() { - configure_with='cmake' -} -readonly -f pbuild::use_cmake - -############################################################################### +#.............................................................................. # # extract sources. For the time being only tar-files are supported. # @@ -582,6 +575,59 @@ pbuild::prep() { ############################################################################### # +# functions to configure the sources + +#.............................................................................. +# +pbuild::add_configure_args() { + CONFIGURE_ARGS+=( "$@" ) +} +readonly -f pbuild::add_configure_args + +#.............................................................................. +# +pbuild::use_autotools() { + configure_with='autotools' +} +readonly -f pbuild::use_autotools + +#.............................................................................. +# +pbuild::use_cmake() { + configure_with='cmake' +} +readonly -f pbuild::use_cmake + +#.............................................................................. +# +# Use this C-compiler +# +# Arguments: +# $1 C-compiler to use. +# +pbuild::use_cc() { + [[ -x "$1" ]] || std::die 3 \ + "%s " "${module_name}/${module_version}:" \ + "Error in setting CC:" \ + "'$1' is not an executable!" + CC="$1" +} +readonly -f pbuild::use_cc + +#.............................................................................. +# +# Set flag to build module in source tree. +# +# Arguments: +# none +# +pbuild::compile_in_sourcetree() { + BUILD_DIR="${SRC_DIR}" +} +readonly -f pbuild::compile_in_sourcetree + +#.............................................................................. +# # Configure the software to be compiled. # # Arguments: @@ -635,7 +681,11 @@ pbuild::configure() { } -############################################################################### +############################################################################## +# +# functions to compile the sources + +#.............................................................................. # # Default compile function. # @@ -650,7 +700,23 @@ pbuild::compile() { "compilation failed!" } -############################################################################### +############################################################################## +# +# functions to install everything + +#.............................................................................. +# +# Set documentation file to be installed. +# +# Arguments: +# $@: documentation files relative to source +# +pbuild::install_docfiles() { + MODULE_DOCFILES+=("$@") +} +readonly -f pbuild::install_docfiles + +#.............................................................................. # # Default install function. # @@ -664,7 +730,7 @@ pbuild::install() { "compilation failed!" } -############################################################################### +#.............................................................................. # pbuild::install_shared_libs() { local -r binary="$1" diff --git a/Pmodules/modbuild.in b/Pmodules/modbuild.in index 5514f0c..48c1954 100755 --- a/Pmodules/modbuild.in +++ b/Pmodules/modbuild.in @@ -519,25 +519,25 @@ build_modules_yaml(){ local fname="$2" local version="$3" local idx="$4" - _result=$(${yq} -Ne e ".\"${version}\"[${idx}].systems" \ - "${fname}" 2>/dev/null) + _result=( $(${yq} -Ne e ".\"${version}\"[${idx}].systems" \ + "${fname}" 2>/dev/null) ) (( $? == 0 )) && return - _result=$(${yq} -Ne e ".systems" "${fname}" 2>/dev/null) + _result=( $(${yq} -Ne e ".systems" "${fname}" 2>/dev/null) ) (( $? == 0 )) && return - _result='any' + _result=() } - yaml_get_operating_systems(){ + yaml_get_compilers(){ local -n _result="$1" local fname="$2" local version="$3" local idx="$4" - _result=$(${yq} -Ne e ".\"${version}\"[${idx}].operating_systems" \ - "${fname}" 2>/dev/null) + _result=( $(${yq} -Ne e ".\"${version}\"[${idx}].compilers" \ + "${fname}" 2>/dev/null) ) (( $? == 0 )) && return - _result=$(${yq} -Ne e ".operating_systems" "${fname}" 2>/dev/null) + _result=( $(${yq} -Ne e ".compilers" "${fname}" 2>/dev/null) ) (( $? == 0 )) && return - _result='any' + _result=() } yaml_get_dependencies(){ @@ -595,6 +595,7 @@ build_modules_yaml(){ local -a deps=() local -a build_requires=() local relstage + local group local ol_name for (( i=0; i 0 )); then while read -a with_modules; do pbuild.build_module \ From 25aebf751825718f5755d382eb42a87cd42166d8 Mon Sep 17 00:00:00 2001 From: Achim Gsell Date: Fri, 29 Jul 2022 14:54:55 +0200 Subject: [PATCH 11/20] Changelog updated --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9bc8906..98fc15e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -47,6 +47,10 @@ - to override the overlay in a YAML variants file. * The new keyword `with` has been introduced in YAML variants file to specified hierarchical dependencies. + * The function `pbuild::supported_os` has been + removed. `pbuild::supported_systems` provides the same + functionality for legacy configuration files. In YAML module + configuration files `systems` have to be used. * **Internal changes and fixes** * bugfix in setting `PATH` From 2026450fbe48060bc35bb70919fbaa2cf4a244c9 Mon Sep 17 00:00:00 2001 From: Achim Gsell Date: Fri, 29 Jul 2022 14:55:31 +0200 Subject: [PATCH 12/20] overlay doc updated --- doc/Overlays.adoc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/Overlays.adoc b/doc/Overlays.adoc index b486cc6..52f7673 100644 --- a/doc/Overlays.adoc +++ b/doc/Overlays.adoc @@ -83,7 +83,9 @@ hdf5_serial/1.12.2: .... relstage: overlay: +group: systems: +compilers: /: - with: From bfcb42a3965d6ba3f74e3210438f19e212d6de1f Mon Sep 17 00:00:00 2001 From: Achim Gsell Date: Fri, 29 Jul 2022 15:56:08 +0200 Subject: [PATCH 13/20] modbuild: bugfixes --- Pmodules/libpbuild.bash | 6 +++--- Pmodules/modbuild.in | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Pmodules/libpbuild.bash b/Pmodules/libpbuild.bash index 1a4893b..4d766ca 100644 --- a/Pmodules/libpbuild.bash +++ b/Pmodules/libpbuild.bash @@ -156,6 +156,7 @@ pbuild::add_to_group() { } readonly -f pbuild::add_to_group +declare -gx GROUP='' pbuild.add_to_group(){ GROUP="$1" } @@ -302,6 +303,7 @@ pbuild::supported_compilers() { } readonly -f pbuild::supported_compilers +declare SUPPORTED_COMPILERS=() pbuild.supported_compilers(){ SUPPORTED_COMPILERS+=( "$@" ) } @@ -324,6 +326,7 @@ pbuild::supported_systems() { } readonly -f pbuild::supported_systems +declare SUPPORTED_SYSTEMS=() pbuild.supported_systems() { SUPPORTED_SYSTEMS+=( "$@" ) } @@ -1057,7 +1060,6 @@ _build_module() { P="${module_name}" V="${module_version}" parse_version "${module_version}" - declare -gx GROUP='' declare -g PREFIX='' SOURCE_URLS=() @@ -1065,8 +1067,6 @@ _build_module() { SOURCE_NAMES=() declare -Ag SOURCE_UNPACK_DIRS=() CONFIGURE_ARGS=() - SUPPORTED_SYSTEMS=() - SUPPORTED_COMPILERS=() PATCH_FILES=() PATCH_STRIPS=() PATCH_STRIP_DEFAULT='1' diff --git a/Pmodules/modbuild.in b/Pmodules/modbuild.in index 48c1954..e7303ee 100755 --- a/Pmodules/modbuild.in +++ b/Pmodules/modbuild.in @@ -634,7 +634,7 @@ build_modules_yaml(){ pbuild.supported_compilers "${compilers[@]}" if (( ${#deps[@]} > 0 )); then while read -a with_modules; do - pbuild.build_module \ + pbuild.build_module_yaml \ "${name}" "${v##*/}" \ "${relstage}" "${with_modules[@]}" done < <(bash_expand "" ${deps[@]}|${awk} "${pattern}") From 42929f835ffb975a96dcf8b643fc42ea89912b5c Mon Sep 17 00:00:00 2001 From: Achim Gsell Date: Wed, 3 Aug 2022 15:57:20 +0200 Subject: [PATCH 14/20] modulecmd: support for modulecmd written in Tcl removed --- Pmodules/modulecmd.bash.in | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/Pmodules/modulecmd.bash.in b/Pmodules/modulecmd.bash.in index 0c25562..58d35fc 100644 --- a/Pmodules/modulecmd.bash.in +++ b/Pmodules/modulecmd.bash.in @@ -32,16 +32,12 @@ std::def_cmds "${path}" \ 'awk' 'base64' 'find' 'getopt' 'logger' 'mktemp' \ 'rm' 'sort' 'yq' -if [[ ${PMODULES_PURETCL} == yes ]]; then - declare -r modulecmd="${libexecdir}/modulecmd.tcl" +if [[ -n ${TCLLIBPATH} ]]; then + declare -x TCLLIBPATH="${PMODULES_HOME}/lib/Pmodules:${TCLLIBPATH}" else - if [[ -n ${TCLLIBPATH} ]]; then - declare -x TCLLIBPATH="${PMODULES_HOME}/lib/Pmodules:${TCLLIBPATH}" - else - declare -x TCLLIBPATH="${PMODULES_HOME}/lib/Pmodules" - fi - declare -r modulecmd="${libexecdir}/modulecmd.bin" + declare -x TCLLIBPATH="${PMODULES_HOME}/lib/Pmodules" fi +declare -r modulecmd="${libexecdir}/modulecmd.bin" declare verbosity_lvl=${PMODULES_VERBOSITY:-'verbose'} From f83b68ba0d4e509331f8ac4deb550878ef5ac128 Mon Sep 17 00:00:00 2001 From: Achim Gsell Date: Wed, 3 Aug 2022 16:29:50 +0200 Subject: [PATCH 15/20] modulecmd: cosmetic changes (spacing) and comments added/edited --- Pmodules/modulecmd.bash.in | 123 ++++++++++++++++++++++++++----------- 1 file changed, 86 insertions(+), 37 deletions(-) diff --git a/Pmodules/modulecmd.bash.in b/Pmodules/modulecmd.bash.in index 58d35fc..0cc1711 100644 --- a/Pmodules/modulecmd.bash.in +++ b/Pmodules/modulecmd.bash.in @@ -15,12 +15,12 @@ unset IFS # use default IFS shopt -s nullglob # used in some output messages only -declare -r CMD='module' +declare -r CMD='module' -declare -r mydir=$(cd $(dirname "$0") && pwd) -declare prefix=$(dirname "${mydir}") -declare -r libdir="${prefix}/lib" -declare -r libexecdir="${prefix}/libexec" +declare -r mydir=$(cd $(dirname "$0") && pwd) +declare -- prefix=$(dirname "${mydir}") +declare -r libdir="${prefix}/lib" +declare -r libexecdir="${prefix}/libexec" source "${libdir}/libstd.bash" source "${libdir}/libpmodules.bash" @@ -39,9 +39,9 @@ else fi declare -r modulecmd="${libexecdir}/modulecmd.bin" -declare verbosity_lvl=${PMODULES_VERBOSITY:-'verbose'} +declare -- verbosity_lvl=${PMODULES_VERBOSITY:-'verbose'} -declare Shell='' +declare -- Shell='' # the following settings are used if the config file doesn't exist @@ -91,30 +91,31 @@ export_env() { } # -# Save/cache some variables. -# This function is called on exit via a trap handler. +# Save/cache state in the environment variable PMODULES_ENV. The content is +# base64 encoded. This function is called on exit via a trap handler. # -# Args; +# Arguments: # none # + declare g_env_must_be_saved='no' -encode_base64(){ - case "${os_name}" in - Linux ) - "${base64}" --wrap=0 <<< "$1" - ;; - Darwin ) - # does not wrap if running in a script - "${base64}" <<< "$1" - ;; - * ) - std::die 255 "Oops: Unsupported OS" - ;; - esac -} - save_env() { + encode_base64(){ + case "${os_name}" in + Linux ) + "${base64}" --wrap=0 <<< "$1" + ;; + Darwin ) + # does not wrap if running in a script + "${base64}" <<< "$1" + ;; + * ) + std::die 255 "Oops: Unsupported OS" + ;; + esac + } + [[ $1 == 'no' ]] && return 0 local vars=( Version ) vars+=( UsedReleaseStages UsedFlags UsedGroups ) @@ -129,6 +130,9 @@ save_env() { declare -gx PMODULES_ENV=$( encode_base64 "$s" ) } +# +# function called on exit +# _exit() { save_env "${g_env_must_be_saved}" export_env 'PMODULES_ENV' @@ -136,7 +140,6 @@ _exit() { ${rm} -f "${tmpfile}" || : fi } - trap '_exit' EXIT # @@ -175,6 +178,9 @@ get_release_stage() { fi } +# +# check whether the argument in $1 is a valid release stage. +# is_release_stage() { [[ :${ReleaseStages}: =~ :$1: ]] } @@ -184,9 +190,10 @@ is_release_stage() { # If yes, return 0 and the overlay with upvar of first argument # otherwise return 1 # -# $1 upvar to return overlay -# $2 upvar to return group -# $3 moduledir to check +# Arguments +# $1 upvar to return overlay +# $2 upvar to return group +# $3 moduledir to check # find_overlay () { local "$1" @@ -205,29 +212,52 @@ find_overlay () { return 0 } +# +# Check whether the module passed in argument $1 is loaded. +# module_is_loaded() { [[ :${LOADEDMODULES}: =~ :$1: ]] } # -# check shebang -# $1: file name to test +# Check shebang. +# +# Arguments: +# $1 file name to test +# is_modulefile() { local -r fname="$1" - local shebang + local -- shebang [[ -r ${fname} ]] || return 1 read -n 11 shebang < "${fname}" [[ "${shebang:0:8}" == '#%Module' ]] || [[ "${shebang:0:9}" == '#%Pmodule' ]] } +# +# Get the value of _PREFIX. +# +# Arguments: +# $1 upvar to return result +# $2 modulefile +# get_module_prefix() { - local "$1" - local modulefile="$2" - local -r _prefix=$("${modulecmd}" bash show "${modulefile}" 2>&1 | \ + local -n _prefix="$1" + local -- _prefix=$("${modulecmd}" bash show "$2" 2>&1 | \ ${awk} '/_PREFIX |_HOME / {print $3; exit}') - std::upvar $1 "${_prefix}" } +# +# Generic wrappers of 'modulecmd': +# +# subcommand_generic0: +# no argument allowed +# subcommand_generic1: +# Exact one argument must be passed +# subcommand_generic1plus: +# One or more arguments must be passed +# +# The options to output help are always accepted. +# subcommand_generic0() { local -r subcommand="$1" shift @@ -1768,7 +1798,10 @@ subcommand_refresh() { } # -# help function, used during initialization and for purging all modules +# Helper functions, used during initialization and for purging all modules. +# +# Arguments: +# none # init_modulepath() { declare -gx MODULEPATH='' @@ -2795,6 +2828,11 @@ subcommand_initclear() { # # main # + +# parse arguments +# + +# first argument must be a shell! case "$1" in sh | bash | zsh ) declare Shell="sh" @@ -2808,6 +2846,7 @@ case "$1" in esac shift +# parse agruments till and including the sub-command declare -a opts=() while (( $# > 0 )); do case $1 in @@ -2866,6 +2905,14 @@ esac if [[ -n ${PMODULES_ENV} ]]; then eval "$("${base64}" -d <<< "${PMODULES_ENV}" 2>/dev/null)" fi +# Version should now be defined again, if not: +# - PMODULES_ENV was not set +# - Version was not defined the last time the variables were saved. +# This is true for older Pmodules versions. + +# We (re-)initialise the Pmodules system, if +# - PMODULES_ENV was not set/empty +# - A Pmodules new version has been loaded if [[ -z ${Version} ]] || [[ ${Version} != ${PMODULES_VERSION} ]]; then # this can only happen if the last command was # module load Pmodules/${PMODULES_VERSION} @@ -2889,6 +2936,8 @@ if (( ${#GroupDepths[@]} == 0 )); then g_env_must_be_saved='yes' fi +# We need a tmp-file in the following sub-commands. It will be removed +# in the exit function if exists. case ${subcommand} in load|purge|search|swap|whatis|apropos ) declare -r tmpfile=$( ${mktemp} /tmp/Pmodules.XXXXXX ) \ From b308bf252acde33caaf508b72bb09d95b83bf26e Mon Sep 17 00:00:00 2001 From: Achim Gsell Date: Wed, 3 Aug 2022 16:32:20 +0200 Subject: [PATCH 16/20] modulecmd: mapping of sub-cmds and their aliases to functions reviwed --- Pmodules/modulecmd.bash.in | 22 +--------------------- 1 file changed, 1 insertion(+), 21 deletions(-) diff --git a/Pmodules/modulecmd.bash.in b/Pmodules/modulecmd.bash.in index 0cc1711..186dfd3 100644 --- a/Pmodules/modulecmd.bash.in +++ b/Pmodules/modulecmd.bash.in @@ -2071,6 +2071,7 @@ subcommand_clear() { # search [switches] [STRING...] # Subcommands[search]='search' +Subcommands[find]='search' Options[search]='-o a\?H -l help -l no-header -l print-modulefiles ' Options[search]+='-l release-stage: -l with: -l all-release-stages -l src: -l print-csv ' Options[search]+='-l verbose ' @@ -2881,27 +2882,6 @@ if [[ -z "${Subcommands[${subcommand}]}" ]]; then std::die 1 "${CMD}: unknown sub-command -- ${subcommand}" fi -case ${subcommand} in - add ) - subcommand='load' - ;; - display ) - subcommand='show' - ;; - keyword ) - subcommand='apropos' - ;; - rm ) - subcommand='unload' - ;; - find ) - subcommand='search' - ;; - switch ) - subcommand='swap' - ;; -esac - if [[ -n ${PMODULES_ENV} ]]; then eval "$("${base64}" -d <<< "${PMODULES_ENV}" 2>/dev/null)" fi From 8d7bba963192d1168781c5efba483742a077086a Mon Sep 17 00:00:00 2001 From: Achim Gsell Date: Wed, 3 Aug 2022 16:34:21 +0200 Subject: [PATCH 17/20] modulecmd: all group depths should be correct after initialisation. --- Pmodules/modulecmd.bash.in | 3 --- 1 file changed, 3 deletions(-) diff --git a/Pmodules/modulecmd.bash.in b/Pmodules/modulecmd.bash.in index 186dfd3..25f1036 100644 --- a/Pmodules/modulecmd.bash.in +++ b/Pmodules/modulecmd.bash.in @@ -2911,9 +2911,6 @@ if [[ -z ${Version} ]] || [[ ${Version} != ${PMODULES_VERSION} ]]; then _LMFILES_ fi -if (( ${#GroupDepths[@]} == 0 )); then - scan_groups "${UsedOverlays[@]}" - g_env_must_be_saved='yes' fi # We need a tmp-file in the following sub-commands. It will be removed From 50ef08ca2f7f886fd30b67dcd292bfc8cddbcb13 Mon Sep 17 00:00:00 2001 From: Achim Gsell Date: Wed, 3 Aug 2022 16:37:58 +0200 Subject: [PATCH 18/20] modulecmd: parsing the args of sub-cmds simplified --- Pmodules/modulecmd.bash.in | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/Pmodules/modulecmd.bash.in b/Pmodules/modulecmd.bash.in index 25f1036..cecce8a 100644 --- a/Pmodules/modulecmd.bash.in +++ b/Pmodules/modulecmd.bash.in @@ -2925,12 +2925,10 @@ case ${subcommand} in ;; esac - -tmp=$("${getopt}" --name="${CMD}" ${Options[${subcommand}]} -- "${opts[@]}" "$@" ) \ - || print_help "${subcommand}" -eval args=( "$tmp" ) -unset tmp -subcommand_${Subcommands[$subcommand]} "${args[@]}" +# parse arguments of the sub-command and call it +set -- $("${getopt}" --unquoted --name="${CMD}" ${Options[${subcommand}]} -- "${opts[@]}" "$@" ) \ + || print_help "${subcommand}" +subcommand_${Subcommands[$subcommand]} $@ # Local Variables: # mode: sh From ffbf6158e61c8bd08e72a7ce822c834864eb12fa Mon Sep 17 00:00:00 2001 From: Achim Gsell Date: Wed, 3 Aug 2022 16:41:15 +0200 Subject: [PATCH 19/20] modulecmd: unset 'Version' before restoring variables from cache If 'Version' is set in the calling shell, initialisation might be skipped. --- Pmodules/modulecmd.bash.in | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Pmodules/modulecmd.bash.in b/Pmodules/modulecmd.bash.in index cecce8a..92ecf4d 100644 --- a/Pmodules/modulecmd.bash.in +++ b/Pmodules/modulecmd.bash.in @@ -2882,6 +2882,8 @@ if [[ -z "${Subcommands[${subcommand}]}" ]]; then std::die 1 "${CMD}: unknown sub-command -- ${subcommand}" fi +# restore variables from last call +unset Version if [[ -n ${PMODULES_ENV} ]]; then eval "$("${base64}" -d <<< "${PMODULES_ENV}" 2>/dev/null)" fi From f44972947fafc83286b279d07f3843ac1c07494e Mon Sep 17 00:00:00 2001 From: Achim Gsell Date: Wed, 3 Aug 2022 16:54:44 +0200 Subject: [PATCH 20/20] modulecmd: comments edited --- Pmodules/modulecmd.bash.in | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/Pmodules/modulecmd.bash.in b/Pmodules/modulecmd.bash.in index 92ecf4d..2f747ee 100644 --- a/Pmodules/modulecmd.bash.in +++ b/Pmodules/modulecmd.bash.in @@ -2889,23 +2889,18 @@ if [[ -n ${PMODULES_ENV} ]]; then fi # Version should now be defined again, if not: # - PMODULES_ENV was not set -# - Version was not defined the last time the variables were saved. +# - Version was not defined the last time the status was saved. # This is true for older Pmodules versions. # We (re-)initialise the Pmodules system, if -# - PMODULES_ENV was not set/empty -# - A Pmodules new version has been loaded +# - PMODULES_ENV was not set/is empty +# - A new Pmodules version has been loaded if [[ -z ${Version} ]] || [[ ${Version} != ${PMODULES_VERSION} ]]; then - # this can only happen if the last command was - # module load Pmodules/${PMODULES_VERSION} - # - # the values these two variables must be saved before initialising declare _tmp_loaded_modules_="${LOADEDMODULES}" declare _tmp_lmfiles_="${_LMFILES_}" pmodules_init - # restore and export LOADEDMODULES="${_tmp_loaded_modules_}" _LMFILES_="${_tmp_lmfiles_}" export_env \ @@ -2913,8 +2908,6 @@ if [[ -z ${Version} ]] || [[ ${Version} != ${PMODULES_VERSION} ]]; then _LMFILES_ fi -fi - # We need a tmp-file in the following sub-commands. It will be removed # in the exit function if exists. case ${subcommand} in