From 9ba9e3e1e0979cb0569d7e6ed789eece05cb6328 Mon Sep 17 00:00:00 2001 From: Achim Gsell Date: Thu, 25 Apr 2019 15:24:01 +0200 Subject: [PATCH] basic functionality implemented --- Pmodules/bash | 10 +-- Pmodules/libmodules.tcl | 70 ++++++++++------ Pmodules/modulecmd.bash.in | 163 +++++++++++++++++-------------------- 3 files changed, 126 insertions(+), 117 deletions(-) diff --git a/Pmodules/bash b/Pmodules/bash index 976cd75..65478bb 100644 --- a/Pmodules/bash +++ b/Pmodules/bash @@ -134,11 +134,11 @@ for r in ${PMODULES_DEFAULT_RELEASES//:/ }; do std::append_path UsedReleases "${r}" done -eval $(save_env UsedReleases PMODULES_DEFAULT_RELEASES PMODULES_DEFAULT_GROUPS PMODULES_DEFINED_RELEASES) -unset UsedReleases -unset PMODULES_DEFAULT_RELEASES -unset PMODULES_DEFAULT_GROUPS -unset PMODULES_DEFINED_RELEASES +#eval $(save_env UsedReleases PMODULES_DEFAULT_RELEASES PMODULES_DEFAULT_GROUPS PMODULES_DEFINED_RELEASES) +#unset UsedReleases +#unset PMODULES_DEFAULT_RELEASES +#unset PMODULES_DEFAULT_GROUPS +#unset PMODULES_DEFINED_RELEASES std::replace_path PATH "${PMODULES_HOME%/*}/.*" std::replace_path MANPATH "${PMODULES_HOME%/*}/.*" diff --git a/Pmodules/libmodules.tcl b/Pmodules/libmodules.tcl index d929a7b..e15f31c 100644 --- a/Pmodules/libmodules.tcl +++ b/Pmodules/libmodules.tcl @@ -28,7 +28,7 @@ proc module-addgroup { group } { global version debug "called with arg $group" - set Implementation [file join {*}$::implementation] + set Variant [file join {*}$::variant] set GROUP [string toupper $group] regsub -- "-" ${GROUP} "_" GROUP @@ -40,8 +40,12 @@ proc module-addgroup { group } { if { [module-info mode load] } { debug "mode is load" - - prepend-path MODULEPATH $::PmodulesRoot/$group/$::PmodulesModulfilesDir/$Implementation + foreach overlay $::PmodulesOverlays { + set dir $overlay/$group/$::PmodulesModulfilesDir/$Variant + if { [file isdirectory $dir] } { + prepend-path MODULEPATH $dir + } + } prepend-path PMODULES_USED_GROUPS $group debug "mode=load: new MODULEPATH=$env(MODULEPATH)" debug "mode=load: new PMODULES_USED_GROUPS=$env(PMODULES_USED_GROUPS)" @@ -65,13 +69,17 @@ proc module-addgroup { group } { debug "no orphan modules to unload" } debug "mode=remove: $env(MODULEPATH)" - remove-path MODULEPATH $::PmodulesRoot/$group/$::PmodulesModulfilesDir/$Implementation + foreach overlay $::PmodulesOverlays { + remove-path MODULEPATH $overlay/$group/$::PmodulesModulfilesDir/$Variant + } debug "mode=remove: $env(PMODULES_USED_GROUPS)" remove-path PMODULES_USED_GROUPS $group } if { [module-info mode switch2] } { debug "mode=switch2" - append-path MODULEPATH $::PmodulesRoot/$group/$::PmodulesModulfilesDir/[module-info name] + foreach overlay $::PmodulesOverlays { + append-path MODULEPATH $overlay/$group/$::PmodulesModulfilesDir/[module-info name] + } append-path PMODULES_USED_GROUPS ${group} } } @@ -131,6 +139,7 @@ proc lreverse_n { list n } { set res } +debug "test" # # set standard environment variables # @@ -291,6 +300,22 @@ proc ModulesHelp { } { # or # ${PMODULES_ROOT}/group/${PMODULES_MODULEFILES_DIR}/X1/Y1//X2/Y2/name/version # +proc _find_overlay { modulefile_components } { + debug "_is_in_overlay" + foreach overlay $::PmodulesOverlays { + set overlay_components [file split $overlay] + set overlay_num_components [llength $overlay_components] + set modulefile_root [file join \ + {*}[lrange \ + $modulefile_components \ + 0 [expr $overlay_num_components - 1]]] + if { [string compare $overlay $modulefile_root] == 0 } { + return $overlay_components + } + } + return {} +} + proc _pmodules_init_global_vars { } { global group global GROUP @@ -303,38 +328,34 @@ proc _pmodules_init_global_vars { } { global V_PATCHLVL global V_RELEASE global V_PKG - - global implementation + global variant global PREFIX # prefix of package - debug "$::ModulesCurrentModulefile" - set ::PmodulesRoot $::env(PMODULES_ROOT) - set ::PmodulesModulfilesDir $::env(PMODULES_MODULEFILES_DIR) - set modulefile [file split $::ModulesCurrentModulefile] - set pmodules_root [file split $::PmodulesRoot] - set pmodules_root_num_dirs [llength $pmodules_root] + set ::PmodulesOverlays [split $::env(PMODULES_OVERLAYS) ':'] + set ::PmodulesModulfilesDir $::env(PMODULES_MODULEFILES_DIR) + set modulefile_components [file split $::ModulesCurrentModulefile] + + set overlay_components [_find_overlay ${modulefile_components}] + if { [ string compare $overlay_components "" ] == 0 } { + debug "not in an overlay" + return + } - set modulefile_root [file join {*}[lrange $modulefile 0 [expr $pmodules_root_num_dirs - 1]]] - if { $::PmodulesRoot != $modulefile_root } { - debug "stop sourcing: ${::PmodulesRoot} != $modulefile_root" - return - } debug "modulefile is inside our root" - set rel_modulefile [lrange $modulefile [llength $pmodules_root] end] + set rel_modulefile [lrange $modulefile_components [llength $overlay_components] end] set group [lindex $rel_modulefile 0] set GROUP "${group}" - set name [lindex $modulefile end-1] + set name [lindex $modulefile_components end-1] set P "${name}" - set version [lindex $modulefile end] + set version [lindex $modulefile_components end] set V "${version}" lassign [split $V -] V_PKG tmp set V_RELEASE [lindex [split $tmp _] 0] lassign [split $V_PKG .] V_MAJOR V_MINOR V_PATCHLVL - set implementation [lrange $rel_modulefile 2 end] - set prefix "$pmodules_root $group [lreverse_n $implementation 2]" + set variant [lrange $rel_modulefile 2 end] + set prefix "$overlay_components $group [lreverse_n $variant 2]" set PREFIX [file join {*}$prefix] - debug "PREFIX=$PREFIX" debug "group of module $name: $group" } @@ -367,3 +388,4 @@ _pmodules_setenv ${PREFIX} ${name} ${version} _pmodules_update_loaded_modules ${group} ${name} ${version} debug "return from lib" + diff --git a/Pmodules/modulecmd.bash.in b/Pmodules/modulecmd.bash.in index 8fcfb3b..f86c2e7 100755 --- a/Pmodules/modulecmd.bash.in +++ b/Pmodules/modulecmd.bash.in @@ -37,7 +37,6 @@ declare verbosity_lvl=${PMODULES_VERBOSITY:-'verbose'} shopt -s nullglob -declare -a Groups='()' declare -A GroupDepths='()' declare current_modulefile='' declare g_shell='' @@ -77,7 +76,7 @@ pbuild::save_env() { pbuild::export_env ${shell} PMODULES_ENV } -trap 'pbuild::save_env ${g_shell} Groups GroupDepths UsedReleases UseFlags PMODULES_DEFAULT_GROUPS PMODULES_DEFINED_RELEASES PMODULES_DEFAULT_RELEASES' EXIT +trap 'pbuild::save_env ${g_shell} Overlays PMODULES_OVERLAYS GroupDepths UsedReleases UseFlags PMODULES_DEFAULT_GROUPS PMODULES_DEFINED_RELEASES PMODULES_DEFAULT_RELEASES' EXIT print_version() { echo " @@ -440,8 +439,8 @@ USAGE: # # get release of module # Note: -# - the release of a module outside ${PMODULES_ROOT[@]} is always 'stable' -# - the release of a module inside ${PMODULES_ROOT[@]} without a +# - the release of a module outside ${Overlays[@]} is always 'stable' +# - the release of a module inside ${Overlays[@]} without a # coresponding release file is always 'unstable' # # Args: @@ -451,8 +450,8 @@ get_release() { local "$1" local -r modulefile="$2" - # is modulefile outside ${PMODULES_ROOT}? - for root in "${PMODULES_ROOT[@]}" 'ZZZZZZZ'; do + # is modulefile in a used overlay? + for root in "${!Overlays[@]}" 'ZZZZZZZ'; do [[ ${modulefile} =~ ${root} ]] && break done if [[ "${root}" == 'ZZZZZZZ' ]]; then @@ -460,7 +459,7 @@ get_release() { return 0 fi - # we are inside ${PMODULES_ROOT[@]} + # we are inside the used overlays local -r releasefile="${modulefile%/*}/.release-${modulefile##*/}" if [[ -r ${releasefile} ]]; then # read releasefile, remove empty lines, spaces etc @@ -485,7 +484,7 @@ is_used_release() { find_overlay () { local "$1" local -r group="$2" - for root in "${PMODULES_ROOT[@]}"; do + for root in "${!Overlays[@]}"; do if [[ -d "${root}/${group}/${PMODULES_MODULEFILES_DIR}" ]]; then std::upvar $1 "${root}" return 0 @@ -502,7 +501,6 @@ is_group () { # not yet cached or not a group local overlay='' find_overlay overlay "${group}" || return 1 - Groups+=( "${group}" ) get_group_depths "${root}" "${group}" return 0 } @@ -817,7 +815,7 @@ subcommand_load() { "${CMD}" 'load' "${group}" MODULEPATH="" modulepath=() - for root in "${PMODULES_ROOT[@]}"; do + for root in "${!Overlays[@]}"; do MODULEPATH+="${root}/${group}/${PMODULES_MODULEFILES_DIR}:" modulepath+=( ${MODULEPATH} ) done @@ -844,10 +842,10 @@ subcommand_load() { std::die 3 "" fi if [[ ":${LOADEDMODULES}:" =~ ":${m}:" ]]; then - std::die 3 "%s %s: module conflicts with already loaded module -- %s\n" \ + std::die 3 "%s %s: module already loaded -- %s\n" \ "${CMD}" 'load' "${m}" fi - for root in "${PMODULES_ROOT[@]}"; do + for root in "${!Overlays[@]}"; do if [[ ${current_modulefile} =~ ${root} ]]; then # modulefile is in our hierarchy # ${prefix} was set in is_available()! @@ -856,7 +854,7 @@ subcommand_load() { fi done local -r tmpfile=$( "${mktemp}" /tmp/Pmodules.XXXXXX ) \ - || std::die 1 "Oops: unable to create tmp file!\n" + || std::die 1 "Oops: unable to create tmp file!\n" local output=$("${modulecmd}" "${shell}" ${opts} load "${current_modulefile}" 2> "${tmpfile}") echo "${output}" eval "${output}" @@ -953,7 +951,7 @@ subcommand_avail() { output_header() { local caption=${dir} - for root in "${PMODULES_ROOT[@]}"; do + for root in "${!Overlays[@]}"; do if [[ ${current_modulefile} =~ ${root} ]]; then local caption=${dir/${root}\/} local caption=${caption/\/${PMODULES_MODULEFILES_DIR}/: } @@ -1086,7 +1084,7 @@ subcommand_avail() { shift done if [[ "${opt_all_groups}" = 'yes' ]]; then - rescan_groups "${PMODULES_ROOT[@]}" + rescan_groups "${!Overlays[@]}" fi if (( ${#pattern[@]} == 0 )); then pattern+=( '' ) @@ -1106,29 +1104,11 @@ subcommand_avail() { done } -# get available groups -# $1: root of modulefile hierarchy -# -get_groups () { - local -r roots="$@" - local root - for root in "${roots[@]}"; do - { - cd "${root}" - # for some unknown reason [A-Z]* doesn't work - # on (some?) SL6 systems - for f in [ABCDEFGHIJKLMNOPQRSTUVWXYZ]*; do - Groups+=( $f ) - done - }; - done -} - # compute depths or passed group # Note: cwd must be Pmodules root directory # $1: group # -get_group_depth2 () { +get_group_depth () { local -r group="$1" local -r dir="${group}/${PMODULES_MODULEFILES_DIR}" test -d "${dir}" || return 0 @@ -1136,38 +1116,27 @@ get_group_depth2 () { local -a tmp2=( ${tmp//\// } ) local depth=${#tmp2[@]} (( depth-=4 )) - # if a group doesn't contain a module yet, depth would be -4 - # instead of 0 + # if a group doesn't contain a module, the above computed depth is < 0. + # We set it to 0 (even this might be wrong). # :FIXME: better solution? - (( depth == -4 )) && (( depth = 0 )) + (( depth < 0 )) && (( depth = 0 )) GroupDepths[$group]=${depth} } -# compute depths or passed group -# $1: root -# $2: group -# -get_group_depth () { - local -r root="$1" - local -r group="$2" - { - cd "${root}" - get_group_depth2 "${group}" - } -} - # # Compute depth for all known groups # $1: root of modulefile hierarchy get_group_depths () { - local -r roots="$@" + local -r roots=( "$@" ) local root for root in "${roots[@]}"; do { cd "${root}" local group - for group in "${Groups[@]}"; do - get_group_depth2 "${group}" + # for some unknown reason [A-Z]* doesn't work + # on (some?) SL6 systems + for group in [ABCDEFGHIJKLMNOPQRSTUVWXYZ]*; do + get_group_depth "${group}" done }; done @@ -1190,8 +1159,7 @@ rescan_groups() { # some bash versions for group in [ABCDEFGHIJKLMNOPQRSTUVWXYZ]*; do if [[ -z "${GroupDepths[${group}]}" ]]; then - Groups+=( "${group}" ) - get_group_depth2 "${group}" + get_group_depth "${group}" fi done }; @@ -1200,7 +1168,7 @@ rescan_groups() { is_in_pmodules_root() { local -r dir="$1" local root - for root in "${PMODULES_ROOT[@]}"; do + for root in "${!Overlays[@]}"; do [[ ${dir} =~ ${root} ]] && return 0 done return 1 @@ -1210,9 +1178,8 @@ is_in_pmodules_root() { # use [-a|--append|-p|--prepend] [directory|group|release...] # subcommand_use() { - if (( ${#Groups[@]} == 0 )); then - get_groups "${PMODULES_ROOT[@]}" - get_group_depths "${PMODULES_ROOT[@]}" + if (( ${#GroupDepths[@]} == 0 )); then + get_group_depths "${!Overlays[@]}" fi local saved_IFS=${IFS}; IFS=':' @@ -1229,7 +1196,7 @@ subcommand_use() { done std::info "\nUnused groups:\n" local _group - for _group in "${Groups[@]}"; do + for _group in "${!GroupDepths[@]}"; do local -i depth=${GroupDepths[${_group}]} if ! is_used_group "${_group}" && (( depth == 0 )); then std::info "\t${_group}\n" @@ -1255,7 +1222,7 @@ subcommand_use() { std::info "\nAdditonal directories in MODULEPATH:\n" let n=0 for (( i=0; i<${#modulepath[@]}; i++)); do - if [[ ! is_in_pmodules_root "${modulepath[i]}" ]]; then + if ! is_in_pmodules_root "${modulepath[i]}"; then std::info "\t${modulepath[i]}\n" let n+=1 fi @@ -1267,10 +1234,6 @@ subcommand_use() { } use () { - declare -g PMODULES - _USED_GROUPS - declare -g MODULEPATH - local dirs_to_add=() while (( $# > 0)); do arg="$1" @@ -1290,15 +1253,39 @@ subcommand_use() { std::append_path UsedReleases "${arg}" elif [[ "${arg}" =~ "flag=" ]]; then std::append_path UseFlags "${arg/flag=}" - elif [[ ! ${arg} =~ */* ]] && is_group "${arg}" ]]; then - if (( ${GroupDepths[$arg]} != 0 )); then + elif [[ "${arg}" =~ "overlay=" ]]; then + local overlay="${arg/overlay=}" + [[ -d "${overlay}" ]] || \ + std:die 3 "%s %s: is not a directory -- %s\n" \ + "${CMD}" "${FUNCNAME[0]##*_}" "${overlay}" + if [[ ! ${Overlays[${overlay}]} ]]; then + Overlays[${overlay}]=1 + PMODULES_OVERLAYS="${PMODULES_OVERLAYS}:${overlay}" + get_group_depths "${!Overlays[@]}" + echo "MODULEPATH=$MODULEPATH" 1>&2 + for group in ${PMODULES_USED_GROUPS//:/ }; do + local dir="${overlay}/${group}/${PMODULES_MODULEFILES_DIR}" + if [[ -d "${dir}" ]]; then + std::prepend_path MODULEPATH "${dir}" + fi + done + fi + + elif [[ ! ${arg} =~ */* ]] && is_group "${arg}"; then + if (( ${GroupDepths[$arg]} != 0 )); then std::die 3 "%s %s: cannot add group to module path -- %s\n" \ "${CMD}" "${FUNCNAME[0]##*_}" "${arg}" fi std::append_path PMODULES_USED_GROUPS "${arg}" - local overlay='' - find_overlay overlay "${arg}" - ${add2path_func} MODULEPATH "${overlay}/${PMODULES_MODULEFILES_DIR}/${arg}" + for overlay in "${!Overlays[@]}"; do + for group in ${PMODULES_USED_GROUPS//:/ }; do + local dir="${overlay}/" + dir+="${group}/${PMODULES_MODULEFILES_DIR}" + if [[ -d "${dir}" ]]; then + std::prepend_path MODULEPATH "${dir}" + fi + done + done elif [[ ${arg} =~ ^${PMODULES_ROOT} ]]; then std::die 3 "%s %s: illegal directory -- %s\n" \ "${CMD}" "${FUNCNAME[0]##*_}" "${arg}" @@ -1418,13 +1405,12 @@ subcommand_refresh() { reset_modulepath() { MODULEPATH='' local group - for group in ${PMODULES_DEFAULT_GROUPS}; do - local root - for root in "${PMODULES_ROOT[@]}"; do + local root + for root in "${!Overlays[@]}"; do + for group in ${PMODULES_DEFAULT_GROUPS}; do local dir="${root}/${group}/${PMODULES_MODULEFILES_DIR}" - [[ -d "${dir}" ]] && std::append_path MODULEPATH "${dir}" + [[ -d "${dir}" ]] && std::prepend_path MODULEPATH "${dir}" done - std::append_path PMODULES_USED_GROUPS "${group}" done } @@ -1486,17 +1472,16 @@ pmodules_init() { declare -g LOADEDMODULES='' declare -g _LMFILES_='' - reset_modulepath - reset_used_groups - - declare -ag Groups='()' + declare -Ag Overlays=([${PMODULES_ROOT}]="1") + declare -xg PMODULES_OVERLAYS="${PMODULES_ROOT}" declare -Ag GroupDepths='()' declare -g UsedReleases='' declare -g UseFlags=() for r in ${PMODULES_DEFAULT_RELEASES//:/ }; do std::append_path UsedReleases "${r}" done - + reset_modulepath + reset_used_groups } ############################################################################## @@ -1580,6 +1565,7 @@ subcommand_search() { "${sort}" -k 1,1 -k 4,4 -k 5,5 "${tmpfile}" | awk "${with_modules}" 1>&2 fi } + #..................................................................... # # search modules @@ -1596,12 +1582,12 @@ subcommand_search() { || std::die 1 "Oops: unable to create tmp file!\n" local _group # loop over all groups - for _group in "${Groups[@]}"; do + for _group in "${!GroupDepths[@]}"; do # loop over all directories which can be added to # MODULEPATH inside current group local depth=${GroupDepths[${_group}]} local mpaths=( $(find \ - "${src_prefix[@]/%//${_group}/modulefiles" \ + "${src_prefix[@]/%//${_group}/modulefiles}" \ -type d \ -mindepth ${depth} -maxdepth ${depth} \ 2>/dev/null)) @@ -1696,7 +1682,7 @@ subcommand_search() { shift done if [[ -z "${src_prefix}" ]]; then - src_prefix="${PMODULES_ROOT[@]}" + src_prefix="${PMODULES_ROOT}" fi if [[ "${opt_use_releases}" == ":" ]]; then @@ -1707,8 +1693,7 @@ subcommand_search() { modules+=( '' ) fi - if (( ${#Groups[@]} == 0 )) || [[ ${src_prefix} != ${PMODULES_ROOT} ]]; then - get_groups "${src_prefix}" + if (( ${#GroupDepths[@]} == 0 )) || [[ ${src_prefix} != ${PMODULES_ROOT} ]]; then get_group_depths "${src_prefix}" fi @@ -1830,6 +1815,9 @@ case "$1" in ;; esac shift + +export PMODULES_OVERLAYS + if [[ -n ${PMODULES_ENV} ]]; then eval "$("${base64}" -d <<< "${PMODULES_ENV}" 2>/dev/null)" else @@ -1912,9 +1900,8 @@ if [[ -z "${subcommand}" ]]; then std::die 1 "${CMD}: no sub-command specified.\n" fi -if (( ${#Groups[@]} == 0 )); then - get_groups "${PMODULES_ROOT[@]}" - get_group_depths "${PMODULES_ROOT[@]}" +if (( ${#GroupDepths[@]} == 0 )); then + get_group_depths "${!Overlays[@]}" fi ${Subcommands[$subcommand]} "${opts[@]}"