mirror of
https://github.com/Pmodules/Pmodules.git
synced 2026-06-26 09:33:08 +02:00
2889 lines
81 KiB
Plaintext
2889 lines
81 KiB
Plaintext
#!@BASH@ --noprofile
|
||
#
|
||
|
||
unset CDPATH # unset CDPATH, otherwise 'cd' prints the directoy!
|
||
unset IFS # use default IFS
|
||
|
||
shopt -s nullglob
|
||
|
||
# used in some output messages only
|
||
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"
|
||
|
||
source "${libdir}/libstd.bash"
|
||
source "${libdir}/libpmodules.bash"
|
||
|
||
path="/bin:/usr/bin"
|
||
[[ $(uname -s) == 'Darwin' ]] && path+=":${libexecdir}"
|
||
std::def_cmds "${path}" \
|
||
'awk' 'base64' 'find' 'getopt' 'logger' 'mktemp' \
|
||
'rm' 'sort' 'find'
|
||
|
||
if [[ ${PMODULES_PURETCL} == yes ]]; then
|
||
declare -r modulecmd="${libexecdir}/modulecmd.tcl"
|
||
else
|
||
declare -rx TCLLIBPATH="${PMODULES_HOME}/lib/Pmodules"
|
||
declare -r modulecmd="${libexecdir}/modulecmd.bin"
|
||
fi
|
||
|
||
declare -r ol_normal='n'
|
||
declare -r ol_hiding='h'
|
||
declare -r ol_replacing='r'
|
||
|
||
declare verbosity_lvl=${PMODULES_VERBOSITY:-'verbose'}
|
||
|
||
declare Shell=''
|
||
|
||
declare -r pmodules_config_file="${PMODULES_ROOT}/${PMODULES_CONFIG_DIR}/Pmodules.conf"
|
||
|
||
# the following settings are used if the Pmodules.conf doesn't exist
|
||
|
||
# set groups which should be available after initialization
|
||
declare -- DefaultGroups='Tools Programming'
|
||
|
||
# define available release stages
|
||
declare -- ReleaseStages=':unstable:stable:deprecated:'
|
||
|
||
# set releases which should be available after initialization
|
||
declare -- DefaultReleaseStages='stable'
|
||
|
||
|
||
export_env() {
|
||
case "${Shell}" in
|
||
sh | bash | zsh )
|
||
local -r fmt="export %s=\"%s\"; "
|
||
;;
|
||
csh | tcsh )
|
||
local -r fmt="setenv %s \"%s\"; "
|
||
;;
|
||
* )
|
||
std::die 1 "Unsupported shell -- ${Shell}"
|
||
;;
|
||
esac
|
||
|
||
while (( $# > 0 )); do
|
||
printf "${fmt}" "$1" "${!1}"
|
||
shift
|
||
done
|
||
# :FIXME: UsedGroups can be modified in libmodule.tcl using
|
||
# append-path/remove-path! But we keep the state in PMODULES_ENV
|
||
# so we don't have to export it.
|
||
#
|
||
case "${Shell}" in
|
||
sh | bash | zsh )
|
||
echo "unset UsedGroups; "
|
||
;;
|
||
csh | tcsh )
|
||
echo "unsetenv UsedGroups; "
|
||
;;
|
||
esac
|
||
}
|
||
|
||
#
|
||
# Save/cache some variables.
|
||
# This function is called on exit via a trap handler.
|
||
#
|
||
# Args;
|
||
# none
|
||
#
|
||
declare g_env_must_be_saved='no'
|
||
|
||
save_env() {
|
||
[[ $1 == 'no' ]] && return 0
|
||
local vars=( Version )
|
||
vars+=( UsedReleaseStages UsedFlags UsedGroups )
|
||
vars+=( DefaultGroups DefaultReleaseStages )
|
||
vars+=( ReleaseStages )
|
||
vars+=( GroupDepths )
|
||
vars+=( OverlayList )
|
||
vars+=( OverlayDict Dir2OverlayMap)
|
||
|
||
local s=$(typeset -p ${vars[@]})
|
||
declare -g PMODULES_ENV=$( "${base64}" --wrap=0 <<< "$s" )
|
||
export_env 'PMODULES_ENV'
|
||
}
|
||
|
||
_exit() {
|
||
save_env "${g_env_must_be_saved}"
|
||
if [[ -n "${tmpfile}" ]] && [[ -e "${tmpfile}" ]]; then
|
||
${rm} -f "${tmpfile}" || :
|
||
fi
|
||
}
|
||
|
||
trap '_exit' EXIT
|
||
|
||
get_overlay_of_moduledir() {
|
||
local "$1"
|
||
local -r moduledir=$2
|
||
|
||
if [[ ! -v Dir2OverlayMap[${moduledir}] ]]; then
|
||
for overlay in "${OverlayList[@]}" 'other'; do
|
||
[[ ${moduledir} == ${overlay}/* ]] && break
|
||
done
|
||
Dir2OverlayMap[${moduledir}]="${overlay}"
|
||
fi
|
||
std::upvar $1 "${Dir2OverlayMap[${moduledir}]}"
|
||
}
|
||
|
||
#
|
||
# get release stage of module
|
||
# Note:
|
||
# - the release stage of a module outside ${OverlayDict[@]} is always 'stable'
|
||
# - the release stage of a module inside ${OverlayDict[@]} without a
|
||
# coresponding file is always 'unstable'
|
||
#
|
||
# Args:
|
||
# $1 upvar for returned release stage
|
||
# $2 modulefile directory (element of MODULEPATH)
|
||
# $3 module name/version
|
||
#
|
||
get_release_stage() {
|
||
local "$1"
|
||
local -r moduledir=$2
|
||
local -r name=$3
|
||
local -r modulefile="$2/$3"
|
||
|
||
local overlay
|
||
get_overlay_of_moduledir overlay "${moduledir}"
|
||
|
||
if [[ "${overlay}" == 'other' ]]; then
|
||
std::upvar $1 'stable'
|
||
return
|
||
fi
|
||
#
|
||
# In an overlay the name of the module-file is something like
|
||
# dir/modulefiles/name/version
|
||
# the corresponding file is
|
||
# dir/modulefiles/name/.release-version
|
||
#
|
||
local -r rel_stage_file="${modulefile%/*}/.release-${modulefile##*/}"
|
||
if [[ -r ${rel_stage_file} ]]; then
|
||
# read file, remove empty lines, spaces etc
|
||
std::upvar $1 $( < "${rel_stage_file}" )
|
||
else
|
||
std::upvar $1 'unstable'
|
||
fi
|
||
}
|
||
|
||
is_release_stage() {
|
||
[[ ${ReleaseStages} =~ :$1: ]]
|
||
}
|
||
|
||
#
|
||
# Check whether a given path is in an used overlay.
|
||
# 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 path to check
|
||
#
|
||
find_overlay () {
|
||
local "$1"
|
||
local "$2"
|
||
local -r path=$3
|
||
local overlay=${Dir2OverlayMap[${path}]}
|
||
get_overlay_of_moduledir overlay "${path}"
|
||
std::upvar $1 "${overlay}"
|
||
|
||
[[ "${overlay}" == 'other' ]] && return 1
|
||
|
||
local group="${path#${overlay}/}"
|
||
group=${group%%/*}
|
||
std::upvar $2 "${group}"
|
||
return 0
|
||
}
|
||
|
||
module_is_loaded() {
|
||
[[ :${LOADEDMODULES}: =~ :$1: ]]
|
||
}
|
||
|
||
#
|
||
# check shebang
|
||
# $1: file name to test
|
||
is_modulefile() {
|
||
local -r fname="$1"
|
||
local shebang
|
||
[[ -r ${fname} ]] || return 1
|
||
read -n 11 shebang < "${fname}"
|
||
[[ "${shebang:0:8}" == '#%Module' ]] || [[ "${shebang:0:9}" == '#%Pmodule' ]]
|
||
}
|
||
|
||
subcommand_generic0() {
|
||
local -r subcommand="$1"
|
||
shift
|
||
local -a args=()
|
||
while (( $# > 0 )); do
|
||
case $1 in
|
||
-\? | -H | --help )
|
||
print_help "${subcommand}"
|
||
;;
|
||
-- )
|
||
shift 1
|
||
args+=( "$@" )
|
||
break
|
||
;;
|
||
* )
|
||
args+=( "$1" )
|
||
;;
|
||
esac
|
||
shift 1
|
||
done
|
||
if (( ${#args[@]} > 0 )); then
|
||
std::die 3 "%s %s: %s" \
|
||
"${CMD}" "${subcommand}" \
|
||
"no arguments allowed"
|
||
fi
|
||
"${modulecmd}" "${Shell}" "${subcommand}"
|
||
}
|
||
|
||
subcommand_generic1() {
|
||
local -r subcommand="$1"
|
||
shift
|
||
local -a args=()
|
||
while (( $# > 0 )); do
|
||
case $1 in
|
||
-\? | -H | --help )
|
||
print_help "${subcommand}"
|
||
;;
|
||
-- )
|
||
shift 1
|
||
args+=( "$@" )
|
||
break
|
||
;;
|
||
* )
|
||
args+=( "$1" )
|
||
;;
|
||
esac
|
||
shift
|
||
done
|
||
if (( ${#args[@]} == 0 )); then
|
||
std::die 3 "%s %s: %s" \
|
||
"${CMD}" "${subcommand}" \
|
||
"missing argument"
|
||
elif (( ${#args[@]} > 1 )); then
|
||
std::die 3 "%s %s: %s" \
|
||
"${CMD}" "${subcommand}" \
|
||
"only one argument allowed"
|
||
fi
|
||
"${modulecmd}" "${Shell}" "${subcommand}" "${args[@]}"
|
||
}
|
||
|
||
subcommand_generic1plus() {
|
||
local -r subcommand="$1"
|
||
shift
|
||
local args=()
|
||
while (( $# > 0 )); do
|
||
case $1 in
|
||
-\? | -H | --help )
|
||
print_help "${subcommand}"
|
||
;;
|
||
-- )
|
||
shift 1
|
||
args+=( "$@" )
|
||
break
|
||
;;
|
||
* )
|
||
args+=( "$1" )
|
||
;;
|
||
esac
|
||
shift
|
||
done
|
||
if (( ${#args[@]} == 0 )); then
|
||
std::die 3 "%s %s: %s" \
|
||
"${CMD}" "${subcommand}" \
|
||
"missing argument"
|
||
fi
|
||
"${modulecmd}" "${Shell}" "${subcommand}" "${args[@]}"
|
||
}
|
||
|
||
##############################################################################
|
||
#
|
||
# load [-fsvw] <module>
|
||
#
|
||
# $1: module to load
|
||
#
|
||
Subcommands[add]='load'
|
||
Subcommands[load]='load'
|
||
Options[load]='-l help -o \?Hfsvw -l force -l silent -l verbose -l warn'
|
||
Help[load]='
|
||
USAGE:
|
||
module add modulefile...
|
||
module load modulefile...
|
||
Load modulefile(s) into the shell environment. Loading a
|
||
'group-head' will extend the MODULEPATH. E.g.: loading a
|
||
compiler makes additional modules like openmpi and libraries
|
||
compiled with this compiler available.
|
||
'
|
||
|
||
subcommand_load() {
|
||
local -r subcommand='load'
|
||
local rel_stage='undef'
|
||
local current_modulefile=''
|
||
local prefix=''
|
||
local m=''
|
||
|
||
#......................................................................
|
||
# Test whether a given module is available.
|
||
# The passed module-name can be
|
||
#
|
||
# - an absolute file- or link-name.
|
||
# The module can be either in- or outside our hierarchy.
|
||
#
|
||
# - a relative file- or link-name.
|
||
# The module can be either in- or outside out hierarchy.
|
||
#
|
||
# - specified with name and version (like gcc/5.2.0).
|
||
# The module can be either in- or outside our hierarchy.
|
||
#
|
||
# - specified with name only (without version, like gcc).
|
||
# The module can be either in- or outside our hierarchy.
|
||
#
|
||
# - directory in- or outsite our hierarchy (not supported by
|
||
# modulecmd.tcl!)
|
||
#
|
||
# arguments:
|
||
# $1: module name or file
|
||
#
|
||
# possible return values:
|
||
# 0: module is loadable
|
||
# 1: either not a modulefile or unsused release stage
|
||
#
|
||
# The following variables in the enclosing function are set:
|
||
# current_modulefile
|
||
# prefix
|
||
# rel_stage
|
||
#
|
||
is_available() {
|
||
local m=$1
|
||
local -a array
|
||
#
|
||
# the next command assigns the absolute modulefile path
|
||
# to ${arry[0]} and - if the module is in our root - the
|
||
# prefix of the module to ${array[1]}.
|
||
#
|
||
# The trick with the first line matching "_PREFIX" is not
|
||
# 100% reliable: One of the Pmodules extensions must be
|
||
# called before something like
|
||
# setenv FOO_PREFIX bar
|
||
# can be used.
|
||
#
|
||
mapfile -t array < <("${modulecmd}" 'bash' show "$m" 2>&1 | \
|
||
${awk} 'NR == 2 {print substr($0, 1, length($0)-1)}; /_PREFIX |_HOME / {print $3; exit}')
|
||
current_modulefile="${array[0]}"
|
||
prefix="${array[1]}"
|
||
test -n "${current_modulefile}" || return 1
|
||
get_release_stage rel_stage "${current_modulefile}" "${UsedReleaseStages}"
|
||
}
|
||
|
||
#......................................................................
|
||
# output load 'hints'
|
||
#
|
||
# Note:
|
||
# The variable 'm' from the parent function will be used
|
||
# but not changed.
|
||
#
|
||
# Args:
|
||
# none
|
||
get_load_hints() {
|
||
local "$1"
|
||
local output=''
|
||
local rel_stage=''
|
||
while read -a line; do
|
||
[[ -z ${line} ]] && continue
|
||
rel_stage=${line[1]}
|
||
if [[ ! ":${UsedReleaseStages}:" =~ "${rel_stage}" ]]; then
|
||
output+="module use ${rel_stage}; "
|
||
fi
|
||
local group=${line[2]}
|
||
if [[ ! ":${UsedGroups}:" =~ ":${group}:" ]] && \
|
||
(( ${GroupDepths[${group}]} == 0 )); then
|
||
output+="module use ${group}; "
|
||
fi
|
||
local -i n=$(( ${GroupDepths[${group}]}/2 ))
|
||
output+="module load ${line[@]:3:$n} ${line[0]}\n"
|
||
done < <(set +x; subcommand_search "${m}" -a --no-header 2>&1)
|
||
std::upvar $1 "${output}"
|
||
}
|
||
|
||
#......................................................................
|
||
module_is_loaded() {
|
||
[[ :${LOADEDMODULES}: =~ :$1: ]]
|
||
}
|
||
|
||
#......................................................................
|
||
load_dependencies() {
|
||
local -r fname="$1"
|
||
while read dep; do
|
||
[[ -z ${dep} ]] && continue
|
||
[[ ${dep:0:1} == \# ]] && continue
|
||
module_is_loaded "${dep}" && continue
|
||
subcommand_load "${dep}"
|
||
done < "${fname}"
|
||
}
|
||
|
||
#......................................................................
|
||
# Check whether argument is a group.
|
||
#
|
||
# In the following function we test whether the group exist in
|
||
# an overlay. It doesn't matter which overlay. If we find an
|
||
# overlay providing modules for this group, we compute the
|
||
# hierarchical depth of the group and save this value for later
|
||
# use.
|
||
#
|
||
# Args:
|
||
# $1: group
|
||
#
|
||
# Notes:
|
||
# This function is used with extended module names.
|
||
#
|
||
# Multiple overlays may provide modules for the same group. But the
|
||
# hierarchical depth of a group must always be the same.
|
||
#
|
||
is_group () {
|
||
local "$1"
|
||
find_an_overlay_providing_group () {
|
||
local "$1"
|
||
local -r group="$2/${PMODULES_MODULEFILES_DIR}"
|
||
local overlay
|
||
for overlay in "${OverlayList[@]}"; do
|
||
if [[ -d "${overlay}/${group}" ]]; then
|
||
std::upvar $1 "${overlay}"
|
||
return 0
|
||
fi
|
||
done
|
||
return 1
|
||
}
|
||
|
||
local -r group="$1"
|
||
# arg isn't emtpy and group already in cache
|
||
[[ -n ${group} ]] && [[ -n ${GroupDepths[${group}]} ]] && return 0
|
||
local overlay=''
|
||
find_an_overlay_providing_group overlay "${group}" || return 1
|
||
local moduledir="${overlay}/${group}/${PMODULES_MODULEFILES_DIR}"
|
||
compute_group_depth "${moduledir}" || return 1
|
||
g_env_must_be_saved='yes'
|
||
}
|
||
|
||
#......................................................................
|
||
local args=()
|
||
local opts=()
|
||
local overlay
|
||
while (($# > 0)); do
|
||
case $1 in
|
||
-\? | -H | --help )
|
||
print_help "${subcommand}"
|
||
;;
|
||
-f | --force )
|
||
opts+=(' -f')
|
||
;;
|
||
-s | --silent )
|
||
verbosity_lvl='silent'
|
||
;;
|
||
-v | --verbose )
|
||
verbosity_lvl='verbose'
|
||
;;
|
||
-w | --warn )
|
||
verbosity_lvl='warn'
|
||
;;
|
||
-- )
|
||
shift 1
|
||
args+=( "$@" )
|
||
break
|
||
;;
|
||
* )
|
||
args+=( $1 )
|
||
;;
|
||
esac
|
||
shift
|
||
done
|
||
if (( ${#args[@]} == 0 )); then
|
||
std::die 2 "%s %s: %s" \
|
||
"${CMD}" "${subcommand}" \
|
||
"No module specified"
|
||
fi
|
||
|
||
IFS=':'
|
||
local -a modulepath=(${MODULEPATH})
|
||
unset IFS
|
||
|
||
local m=''
|
||
for m in "${args[@]}"; do
|
||
if [[ "$m" =~ ":" ]]; then
|
||
|
||
# extendet module name is either
|
||
# - group:name or
|
||
# - group:name:rel_stage or
|
||
# - rel_stage:name or
|
||
# - rel_stage:group:name or
|
||
# - name:rel_stage
|
||
|
||
IFS=':'
|
||
local -a toks=($m)
|
||
unset IFS
|
||
local group=''
|
||
local rel_stage=''
|
||
if is_group "${toks[0]}"; then
|
||
group=${toks[0]}
|
||
m=${toks[1]}
|
||
rel_stage=${toks[2]}
|
||
elif is_release_stage "${toks[0]}"; then
|
||
rel_stage=${toks[0]}
|
||
if is_group "${toks[1]}"; then
|
||
group=${toks[1]}
|
||
m=${toks[2]}
|
||
else
|
||
m=${toks[1]}
|
||
group=${toks[2]}
|
||
fi
|
||
else
|
||
m=${toks[0]}
|
||
if is_group "${toks[1]}"; then
|
||
group=${toks[1]}
|
||
rel_stage=${toks[2]}
|
||
else
|
||
rel_stage=${toks[1]}
|
||
group=${toks[2]}
|
||
fi
|
||
fi
|
||
if [[ -n ${group} ]]; then
|
||
is_group "${group}" || \
|
||
std::die 3 "%s %s: %s -- %s" \
|
||
"${CMD}" "${subcommand}" \
|
||
"illegal group name" \
|
||
"${group}"
|
||
local -i depth=${GroupDepths[${group}]}
|
||
(( depth != 0 )) && \
|
||
std::die 3 "%s %s: %s -- %s" \
|
||
"${CMD}" "${subcommand}" \
|
||
"illegal group name" \
|
||
"${group}"
|
||
MODULEPATH=""
|
||
modulepath=()
|
||
group+="${PMODULES_MODULEFILES_DIR}"
|
||
for overlay in "${OverlayList[@]}"; do
|
||
MODULEPATH="${overlay}/${group}/:${MODULEPATH}"
|
||
modulepath=( "${overlay}/${group}/" "${modulepath[@]}" )
|
||
done
|
||
fi
|
||
if [[ -n ${rel_stage} ]]; then
|
||
is_release_stage "${rel_stage}" || \
|
||
std::die 3 "%s %s: %s -- %s" \
|
||
"${CMD}" "${subcommand}" \
|
||
"illegal release stage" \
|
||
"${rel_stage}"
|
||
std::append_path UsedReleaseStages "${rel_stage}"
|
||
g_env_must_be_saved='yes'
|
||
fi
|
||
fi # handle extended module names
|
||
find_module current_modulefile rel_stage "${m}" "${modulepath[@]}"
|
||
if [[ -z ${current_modulefile} ]]; then
|
||
local text=''
|
||
get_load_hints text
|
||
if [[ -z "${text}" ]]; then
|
||
std::die 3 "%s %s: module does not exist -- %s" \
|
||
"${CMD}" 'load' "${m}"
|
||
else
|
||
std::info "%s %s: module unavailable -- %s" \
|
||
"${CMD}" 'load' "${m}"
|
||
if [[ ${verbosity_lvl} == 'verbose' ]]; then
|
||
std::info ''
|
||
std::info "Try with one of the following command(s):"
|
||
std::info "${text}"
|
||
fi
|
||
std::die 3 ""
|
||
fi
|
||
fi
|
||
if [[ ${m} == Pmodules/* ]] && [[ -n ${LOADEDMODULES} ]]; then
|
||
std::error "%s %s: %s" \
|
||
"${CMD}" "${subcommand}" \
|
||
"cannot load a Pmodules module because other modules are already load!"
|
||
std::die 3 "%s %s: %s -- %s\n" \
|
||
"${CMD}" "${subcommand}" \
|
||
"failed" \
|
||
"${m}"
|
||
fi
|
||
if [[ ":${LOADEDMODULES}:" =~ ":${m}:" ]]; then
|
||
# already loaded
|
||
continue
|
||
fi
|
||
|
||
local prefix=$("${modulecmd}" 'bash' 'show' "${current_modulefile}" 2>&1 | \
|
||
awk '/_PREFIX |_HOME / {print $3; exit}')
|
||
if [[ -n ${prefix} ]]; then
|
||
test -r "${prefix}/.info" && cat "$_" 1>&2
|
||
test -r "${prefix}/.dependencies" && load_dependencies "$_"
|
||
fi
|
||
|
||
local output=$("${modulecmd}" 'bash' ${opts} 'load' \
|
||
"${current_modulefile}" 2> "${tmpfile}")
|
||
|
||
# we do not want to print the error message we got from
|
||
# modulecmd, they are a bit ugly
|
||
# :FIXME: Not sure whether this is now correct!
|
||
# The idea is to supress the error messages from the Tcl
|
||
# modulecmd, but not the output to stderr coded in a
|
||
# modulefile.
|
||
|
||
local error=$( < "${tmpfile}")
|
||
if [[ "${error}" =~ ":ERROR:" ]]; then
|
||
local s=${error%%$'\n'*}
|
||
local error_txt='failed'
|
||
if [[ "$s" =~ ' conflicts ' ]]; then
|
||
error_txt="conflicts with already loaded module(s): ${s#*module(s) }"
|
||
fi
|
||
std::die 3 "%s %s: %s -- %s" \
|
||
"${CMD}" "${subcommand}" \
|
||
"${error_txt}" \
|
||
"${m}"
|
||
fi
|
||
if [[ "${Shell}" == "sh" ]]; then
|
||
# for sh-like shells just echo
|
||
echo "${output}"
|
||
else
|
||
# re-run with right shell
|
||
"${modulecmd}" "${Shell}" ${opts} 'load' \
|
||
"${current_modulefile}"
|
||
fi
|
||
eval "${output}"
|
||
if [[ -n "${error}" ]]; then
|
||
echo "${error}" 1>&2
|
||
fi
|
||
|
||
local msg=$(printf "%s %s: %s -- %s" \
|
||
"${CMD}" 'load' \
|
||
"${rel_stage} module has been loaded" \
|
||
"${m}")
|
||
if [[ ${verbosity_lvl} != silent ]] && \
|
||
[[ ${rel_stage} != stable ]]; then
|
||
std::info "%s" "${msg}"
|
||
fi
|
||
${logger} -t Pmodules "${msg}"
|
||
done
|
||
# fix LOADEDMODULES
|
||
LOADEDMODULES="${_LMFILES_}"
|
||
local dir
|
||
while read dir; do
|
||
[[ "${dir: -1}" == "/" ]] || dir+="/"
|
||
LOADEDMODULES="${LOADEDMODULES//${dir}}"
|
||
get_overlay_of_moduledir overlay "${dir}"
|
||
done <<< "${MODULEPATH//:/$'\n'}"
|
||
g_env_must_be_saved='yes'
|
||
export_env 'LOADEDMODULES'
|
||
}
|
||
|
||
##############################################################################
|
||
#
|
||
# unload
|
||
#
|
||
Subcommands[rm]='unload'
|
||
Subcommands[unload]='unload'
|
||
Options[unload]='-o \?H -l help'
|
||
Help[unload]="
|
||
USAGE:
|
||
module rm modulefile...
|
||
module unload modulefile...
|
||
Remove modulefile(s) from the shell environment. Removing
|
||
a 'group-head' will also unload all modules belonging to
|
||
this group.
|
||
"
|
||
|
||
subcommand_unload() {
|
||
local -r subcommand='unload'
|
||
# :FIXME: add dependency tests: don't unload if module is required
|
||
# be another module.
|
||
# For the time being the modules requiring this module will
|
||
# be unloaded too.
|
||
local args=()
|
||
while (( $# > 0 )); do
|
||
case $1 in
|
||
-\? | -H | --help )
|
||
print_help "${subcommand}"
|
||
;;
|
||
-- )
|
||
shift 1
|
||
args+=( "$@" )
|
||
break
|
||
;;
|
||
* )
|
||
args+=( "$1" )
|
||
;;
|
||
esac
|
||
shift
|
||
done
|
||
if (( ${#args[@]} == 0 )); then
|
||
std::die 3 "%s %s: %s" \
|
||
"${CMD}" "${subcommand}" \
|
||
"missing argument"
|
||
fi
|
||
|
||
# The module() function uses PMODULES_HOME to call modulecmd.
|
||
# If a Pmodules module is unloaded this evnvironment variable
|
||
# will be unset. In consequence the module() function would
|
||
# fail. Instead of comparing the name of the module to unload
|
||
# with 'Pmodules', we save the value and set it at the end of
|
||
# the loop again, if it has been unset.
|
||
local saved_home="${PMODULES_HOME}"
|
||
|
||
local arg
|
||
for arg in "${args[@]}"; do
|
||
local output=$("${modulecmd}" "${Shell}" 'unload' "${arg}")
|
||
eval "${output}"
|
||
case ${Shell} in
|
||
sh | bash | zsh )
|
||
echo "${output}"
|
||
;;
|
||
* )
|
||
"${modulecmd}" "${Shell}" 'unload' "${arg}"
|
||
;;
|
||
esac
|
||
done
|
||
if [[ -z ${PMODULES_HOME} ]]; then
|
||
PMODULES_HOME=${saved_home}
|
||
export_env 'PMODULES_HOME'
|
||
fi
|
||
g_env_must_be_saved='yes'
|
||
} # subcommand_unload
|
||
|
||
##############################################################################
|
||
#
|
||
# swap <module> [<module>]
|
||
#
|
||
Subcommands[switch]='swap'
|
||
Subcommands[swap]='swap'
|
||
Options[swap]='-o \?H -l help'
|
||
Help[swap]="
|
||
USAGE:
|
||
module switch [modulefile1] modulefile2
|
||
module swap [modulefile1] modulefile2
|
||
Switch loaded modulefile1 with modulefile2. If modulefile1
|
||
is not specified, then it is assumed to be the currently
|
||
loaded module with the same base name as modulefile2.
|
||
"
|
||
|
||
subcommand_swap() {
|
||
local -r subcommand='swap'
|
||
local args=()
|
||
while (( $# > 0 )); do
|
||
case $1 in
|
||
-\? | -H | --help )
|
||
print_help "${subcommand}"
|
||
;;
|
||
-- )
|
||
shift 1
|
||
args+=( "$@" )
|
||
break
|
||
;;
|
||
* )
|
||
args+=( "$1" )
|
||
;;
|
||
esac
|
||
shift
|
||
done
|
||
if (( ${#args[@]} == 0 )); then
|
||
std::die 3 "%s %s: %s" \
|
||
"${CMD}" "${subcommand}" \
|
||
"missing argument"
|
||
elif (( ${#args[@]} > 2 )); then
|
||
std::die 3 "%s %s: %s" \
|
||
"${CMD}" "${subcommand}" \
|
||
"too many arguments"
|
||
fi
|
||
if (( ${#args[@]} == 1 )); then
|
||
local -r module_to_load=${args[0]}
|
||
local -r module_to_unload=${module_to_load%/*}
|
||
else
|
||
local -r module_to_unload=${args[0]}
|
||
local -r module_to_load=${args[1]}
|
||
fi
|
||
subcommand_unload "${module_to_unload}"
|
||
subcommand_load "${module_to_load}"
|
||
}
|
||
|
||
##############################################################################
|
||
#
|
||
# show <module>
|
||
#
|
||
Subcommands[display]='show'
|
||
Subcommands[show]='show'
|
||
Options[show]='-o \?H -l help'
|
||
Help[show]='
|
||
USAGE:
|
||
module display modulefile...
|
||
module show modulefile...
|
||
Display information about one or more modulefiles. The
|
||
display sub-command will list the full path of the
|
||
modulefile(s) and all (or most) of the environment changes
|
||
the modulefile(s) will make if loaded. It will not display
|
||
any environment changes found within conditional statements.
|
||
'
|
||
|
||
subcommand_show() {
|
||
local -r subcommand='show'
|
||
local args=()
|
||
while (( $# > 0 )); do
|
||
case $1 in
|
||
-\? | -H | --help )
|
||
print_help "${subcommand}"
|
||
;;
|
||
-- )
|
||
shift 1
|
||
args+=( "$@" )
|
||
break
|
||
;;
|
||
* )
|
||
args+=( "$1" )
|
||
;;
|
||
esac
|
||
shift
|
||
done
|
||
if (( ${#args[@]} == 0 )); then
|
||
std::die 3 "%s %s: %s" \
|
||
"${CMD}" "${subcommand}" \
|
||
"missing argument"
|
||
fi
|
||
|
||
local arg
|
||
for arg in "${args[@]}"; do
|
||
"${modulecmd}" "${Shell}" "${subcommand}" "${arg}"
|
||
done
|
||
}
|
||
|
||
###############################################################################
|
||
# Find all modules in a given modulepath matching a specific string.
|
||
# The search can be restricted to certain release stages.
|
||
#
|
||
# return list like
|
||
# modulename_1 rel_stage_1 modulefile_1 ...
|
||
#
|
||
get_available_modules() {
|
||
local var="$1"
|
||
local -r module="$2"
|
||
local -r used_rel_stages="${3:-${UsedReleaseStages}}"
|
||
shift 3 # in the for loop below we use $@ to loop over the directories
|
||
local -a mods=()
|
||
local rel_stage
|
||
|
||
local -A dict
|
||
local -A modulenames
|
||
local dir
|
||
for dir in "$@"; do
|
||
test -d "${dir}" || continue
|
||
{
|
||
cd "${dir}"
|
||
# there might be no mapping for ${dir}!
|
||
# - after loading the parent of a hierarchical group
|
||
# - if we do a search
|
||
# - if we create a new hierarchical group
|
||
local overlay
|
||
local group
|
||
find_overlay overlay group "${dir}"
|
||
|
||
# if no modules are installed in ${dir}, '*' expands to
|
||
# the empty string! Using '*' in the find command below
|
||
# would cause problems with some non-GNU find
|
||
# implementations.
|
||
local entries=$(echo *)
|
||
[[ -n ${entries} ]] || continue
|
||
while read mod; do
|
||
local add='no'
|
||
if [[ -n "${overlay}" ]]; then
|
||
# module is in an overlay
|
||
#
|
||
# add to list of available modules, if
|
||
# - first time found by name only
|
||
# - in same overlay as first found
|
||
# - new version and not hidden by overlay
|
||
local name="${mod%/*}"
|
||
if [[ -z "${modulenames[${name}]}" ]]; then
|
||
if [[ "${OverlayDict[$overlay]}" == "${ol_hiding}" ]]; then
|
||
modulenames[${name}]="${overlay}"
|
||
else
|
||
modulenames[${name}]='0'
|
||
fi
|
||
add='yes'
|
||
elif [[ "${modulenames[${name}]}" == "${overlay}" ]]; then
|
||
add='yes'
|
||
elif [[ "${modulenames[${name}]}" == '0' ]] \
|
||
&& [[ -z ${dict[${mod}]} ]]; then
|
||
add='yes'
|
||
fi
|
||
else
|
||
# module is NOT in an overlay
|
||
add='yes'
|
||
fi
|
||
[[ "${add}" == 'yes' ]] || continue
|
||
get_release_stage \
|
||
rel_stage \
|
||
"${dir}" \
|
||
"${mod}"
|
||
[[ :${used_rel_stages}: =~ :${rel_stage}: ]] || continue
|
||
|
||
mods+=( "${mod}" ${rel_stage} "${dir}/${mod}" )
|
||
dict[${mod}]=1
|
||
done < <(${find} -L ${entries} \
|
||
\( -type f -o -type l \) \
|
||
-not -name ".*" \
|
||
-ipath "${module}*" \
|
||
| ${sort} --version-sort)
|
||
}
|
||
done
|
||
std::upvar ${var} "${mods[@]}"
|
||
} # get_available_modules()
|
||
|
||
#
|
||
# find module(file) to load. Input arguments are
|
||
# $1 upvar: return module file
|
||
# $2 upvar: return module release stage
|
||
# $3 module to load
|
||
# $4 a modulepath (usually MODULEPATH)
|
||
#
|
||
# The module name can be
|
||
# name
|
||
# name/version
|
||
# name/version_flag
|
||
#
|
||
# Return
|
||
# return code 0 and modulefile in first argument
|
||
# return code 1 and modulefile in first argument
|
||
# if module
|
||
# return code 2
|
||
# if no modulefile could be found
|
||
#
|
||
find_module() {
|
||
local "$1"
|
||
local "$2"
|
||
local -r module="$3"
|
||
local -a dirs=("${@:4}")
|
||
|
||
for dir in "${dirs[@]}"; do
|
||
test -d "${dir}" || continue
|
||
local -i col=$((${#dir} + 2 ))
|
||
local -a modules
|
||
if [[ ${module} == */* ]]; then
|
||
# a version number has been specified. But we still might
|
||
# have the same module/version with different use flags.
|
||
# The different release stages we ignore in this case.
|
||
modules=$(${find} -L "${dir}" -type f -not -name ".*" \
|
||
-ipath "${dir}/${module}*" \
|
||
| cut -b${col}-)
|
||
for mod in "${modules[@]}"; do
|
||
#
|
||
# loop over all used flags. If a module with
|
||
# a used flag is available load this module.
|
||
local rel_stage
|
||
for flag in "${UseFlags[@]/#/_}" ""; do
|
||
[[ ${mod} == ${module}${flag} ]] || continue
|
||
std::upvar $1 "${dir}/${mod}"
|
||
get_release_stage \
|
||
rel_stage \
|
||
"${dir}" \
|
||
"${mod}"
|
||
std::upvar $2 "${rel_stage}"
|
||
return 0
|
||
done
|
||
done
|
||
else
|
||
# no version has been specified. This makes it more
|
||
# difficult. We have to load the newest version taking
|
||
# the used release stages and flags into account.
|
||
(( col += ${#module} + 1 ))
|
||
modules=( $(${find} -L "${dir}" -type f -not -name ".*" \
|
||
-ipath "${dir}/${module}/*" \
|
||
| cut -b${col}- \
|
||
| sort -rV ) )
|
||
modules=( "${modules[@]/#/${module}/}" )
|
||
for mod in "${modules[@]}"; do
|
||
#
|
||
# loop over all used flags. If a module with
|
||
# a used flag is available load this module.
|
||
local rel_stage=''
|
||
for flag in "${UseFlags[@]/#/_}" ""; do
|
||
[[ ${mod} == ${module}/*${flag} ]] || continue
|
||
std::upvar $1 "${dir}/${mod}"
|
||
get_release_stage \
|
||
rel_stage \
|
||
"${dir}" \
|
||
"${mod}"
|
||
std::upvar $2 "${rel_stage}"
|
||
[[ :${release}: =~ :${UsedReleaseStages}: ]] && \
|
||
return 0
|
||
done
|
||
done
|
||
fi
|
||
done
|
||
return 1
|
||
} # find_module()
|
||
|
||
##############################################################################
|
||
#
|
||
# avail [-hlt] [<module-pattern>...]
|
||
#
|
||
Subcommands[avail]='avail'
|
||
Options[avail]='-l help -o \?Hahlmtg: -l all -l all-release-stages -l group: '
|
||
Options[avail]+='-l human -l long -l machine -l terse'
|
||
Help[avail]="
|
||
USAGE:
|
||
module avail [switches] string
|
||
List all available modulefiles in the current MODULEPATH. If
|
||
an argument is given, then each directory in the MODULEPATH
|
||
is searched for modulefiles whose pathname match the argument.
|
||
|
||
This command does *not* display all installed modules on the
|
||
system. Only *loadable* modules are listed. The list of
|
||
available modules may change either by loading other modules,
|
||
e.g. a compiler, or with the sub-command 'use'.
|
||
|
||
SWITCHES:
|
||
-a|--all||--all-release-stages
|
||
List all available modules independend of the release stage.
|
||
|
||
-t|--terse
|
||
Output in short format.
|
||
|
||
-l|--long
|
||
Output in long format.
|
||
|
||
-g|--group=<GROUP>
|
||
Output modules available in <GROUP>
|
||
|
||
-h|--human
|
||
Output in human readable format.
|
||
|
||
-m|--machine
|
||
Output in machine readable format
|
||
"
|
||
|
||
subcommand_avail() {
|
||
local -r subcommand='avail'
|
||
# use this variable in the output functions
|
||
local -a mods=()
|
||
local dir=''
|
||
|
||
# get number of columns of terminal
|
||
cols=$(tput cols)
|
||
|
||
#......................................................................
|
||
output_header() {
|
||
local caption="$1"
|
||
let i=($cols-${#caption})/2-2
|
||
printf -- "%0.s-" $(seq 1 $i) 1>&2
|
||
printf -- " %s " "${caption}" 1>&2
|
||
printf -- "%0.s-" $(seq 1 $i) 1>&2
|
||
printf -- "\n" 1>&2
|
||
}
|
||
|
||
#......................................................................
|
||
terse_output() {
|
||
output_header "$1"
|
||
local -i i=0
|
||
for (( i=0; i<${#mods[@]}; i+=3 )); do
|
||
local mod=${mods[i]}
|
||
local rel_stage=${mods[i+1]}
|
||
case ${rel_stage} in
|
||
stable )
|
||
out=''
|
||
;;
|
||
* )
|
||
out="${rel_stage}"
|
||
;;
|
||
esac
|
||
printf "%-20s\t%s\n" "${mod}" "${out}" 1>&2
|
||
done
|
||
std::info ""
|
||
}
|
||
|
||
#......................................................................
|
||
machine_output() {
|
||
for (( i=0; i<${#mods[@]}; i+=3 )); do
|
||
printf "%-20s\t%s\n" "${mods[i]}" "${mods[i+1]}" 1>&2
|
||
done
|
||
}
|
||
|
||
#......................................................................
|
||
# :FIXME: for the time being, this is the same as terse_output!
|
||
long_output() {
|
||
output_header "$1"
|
||
for (( i=0; i<${#mods[@]}; i+=3 )); do
|
||
local mod=${mods[i]}
|
||
local rel_stage=${mods[i+1]}
|
||
case ${rel_stage} in
|
||
stable )
|
||
out=''
|
||
;;
|
||
* )
|
||
out=${rel_stage}
|
||
;;
|
||
esac
|
||
printf "%-20s\t%s\n" "${mod}" "${out}" 1>&2
|
||
done
|
||
std::info ""
|
||
}
|
||
|
||
#......................................................................
|
||
human_readable_output() {
|
||
output_header "$1"
|
||
|
||
local -a available_modules=()
|
||
local mod=''
|
||
local -i max_length=1
|
||
for ((i=0; i<${#mods[@]}; i+=3)); do
|
||
if [[ ${verbosity_lvl} == 'verbose' ]]; then
|
||
local rel_stage=${mods[i+1]}
|
||
case ${rel_stage} in
|
||
stable )
|
||
mod="${mods[i]}"
|
||
;;
|
||
* )
|
||
mod="${mods[i]}(${rel_stage:0:1})"
|
||
;;
|
||
esac
|
||
else
|
||
mod=${mods[i]}
|
||
fi
|
||
local -i n=${#mod}
|
||
(( n > max_length )) && (( max_length=n ))
|
||
available_modules+=("${mod}")
|
||
done
|
||
IFS=$'\n' available_modules=($(sort --version-sort <<<"${available_modules[*]}"))
|
||
unset IFS
|
||
local -i span=$(( max_length / 16 + 1 )) # compute column size
|
||
local -i colsize=$(( span * 16 )) # as multiple of 16
|
||
local -i column=$cols # force a line-break
|
||
for mod in "${available_modules[@]}"; do
|
||
local -i len=${#mod}
|
||
if (( column+len >= cols )); then
|
||
printf -- "\n" 1>&2
|
||
column=0
|
||
fi
|
||
if (( column+colsize < cols )); then
|
||
fmt="%-${colsize}s"
|
||
else
|
||
fmt="%-s"
|
||
fi
|
||
printf "${fmt}" "${mod}" 1>&2
|
||
column+=colsize
|
||
done
|
||
printf -- "\n\n" 1>&2
|
||
}
|
||
|
||
#......................................................................
|
||
local pattern=()
|
||
local output_function='human_readable_output'
|
||
local opt_use_rel_stages="${UsedReleaseStages}"
|
||
local -A opt_groups=()
|
||
local val=''
|
||
while (($# > 0)); do
|
||
case $1 in
|
||
-\? | -H | --help )
|
||
print_help "${subcommand}"
|
||
;;
|
||
-a | --all | --all-release-stages )
|
||
opt_use_rel_stages="${ReleaseStages}"
|
||
;;
|
||
-h | --human )
|
||
output_function='human_readable_output'
|
||
;;
|
||
-l | --long )
|
||
output_function='long_output'
|
||
;;
|
||
-t | --terse )
|
||
output_function='terse_output'
|
||
;;
|
||
-m | --machine )
|
||
output_function='machine_output'
|
||
;;
|
||
-g | --group | --group=* )
|
||
if [[ $1 == --group=* ]]; then
|
||
val="${1#--*=}"
|
||
else
|
||
val="$2"
|
||
shift
|
||
fi
|
||
opt_groups[${val}]=1
|
||
;;
|
||
-- )
|
||
shift 1
|
||
pattern+=( "$@" )
|
||
break
|
||
;;
|
||
* )
|
||
pattern+=( "$1" )
|
||
;;
|
||
esac
|
||
shift
|
||
done
|
||
if (( ${#pattern[@]} == 0 )); then
|
||
pattern+=( '' )
|
||
fi
|
||
IFS=':'
|
||
local -a modulepath=(${MODULEPATH})
|
||
unset IFS
|
||
local dir
|
||
local group=''
|
||
local overlay=''
|
||
for dir in "${modulepath[@]}"; do
|
||
group='other'
|
||
find_overlay overlay group "${dir}"
|
||
if [[ ! -v modulepath_${group} ]]; then
|
||
typeset -a modulepath_${group}
|
||
fi
|
||
typeset -n path=modulepath_${group}
|
||
path+=("${dir}")
|
||
done
|
||
local p
|
||
for string in "${pattern[@]}"; do
|
||
for group in ${UsedGroups//:/ } other; do
|
||
if (( ${#opt_groups[@]} > 0 )) && [[ ! -v opt_groups[${group}] ]]; then
|
||
continue
|
||
fi
|
||
[[ -v modulepath_${group} ]] || continue
|
||
typeset -n path=modulepath_${group}
|
||
get_available_modules \
|
||
mods \
|
||
"${string}*" \
|
||
"${opt_use_rel_stages}" \
|
||
"${path[@]}"
|
||
|
||
[[ ${#mods[@]} == 0 ]] && continue
|
||
${output_function} "${group}"
|
||
done
|
||
done
|
||
} # subcommand_avail()
|
||
|
||
##############################################################################
|
||
#
|
||
# use [-a|--append|-p|--prepend] [directory|group|release_stage...]
|
||
#
|
||
Subcommands[use]='use'
|
||
Options[use]='-l help -o \?Hap -l append -l prepend'
|
||
Help[use]="
|
||
USAGE:
|
||
module use [-a|--append|-p|--prepend] [directory|group|release_stage|...]
|
||
Without arguments this sub-command displays information about
|
||
the module search path, used groups and release stages. You can
|
||
use this sub-command to get a list of available groups and
|
||
releases stages.
|
||
|
||
With a directory as argument, this directory will either be
|
||
prepended or appended to the module search path. The default
|
||
is to prepend the directory.
|
||
|
||
With a group as argument, the modules in this group will
|
||
be made available.
|
||
|
||
With a release as argument, this modules with this release
|
||
will be made available.
|
||
|
||
SWITCHES:
|
||
-a | --append -p | --prepend )
|
||
Append/prepend agrument to module search path or list of to be
|
||
searched releases.
|
||
"
|
||
|
||
# helper function for subcommand_use() und subcommand_unuse()
|
||
get_overlay_info(){
|
||
# Args:
|
||
# $1 [in] overlay name or directory plus optional type
|
||
# $2 [upvar] overlay type
|
||
# $3 [upvar] overlay root directory
|
||
# $4 [upvar] overlay prefix for software installation
|
||
#
|
||
local name_or_dir="${1%:*}"
|
||
[[ -d ${name_or_dir} ]] && name_or_dir=$(cd "${name_or_dir}" && pwd -L)
|
||
|
||
local config_files=()
|
||
if [[ -v PMODULES_OVERLAYS_CONF ]]; then
|
||
config_files+=("${PMODULES_OVERLAYS_CONF}")
|
||
fi
|
||
config_files+=("${HOME}/.Pmodules/overlays.conf")
|
||
config_files+=("${PMODULES_ROOT}/config/overlays.conf")
|
||
|
||
for config_file in "${config_files[@]}"; do
|
||
[[ -r "${config_file}" ]] || continue
|
||
local toks=()
|
||
while read -a toks; do
|
||
[[ -n "${toks[0]}" ]] || continue
|
||
[[ ${toks[0]} == \#* ]] && continue
|
||
local _name="${toks[0]%:*}"
|
||
if [[ "${toks[0]%:*}" == "${name_or_dir}" ]] \
|
||
|| [[ "${toks[1]}" == "${name_or_dir}" ]]; then
|
||
# take type from
|
||
# 1. $1
|
||
# 2. configuration file
|
||
# 3. use default type
|
||
local _type="${ol_normal}"
|
||
if [[ "$1" == *:* ]]; then
|
||
_type="${1##*:}"
|
||
elif [[ "${toks[0]}" == *:* ]]; then
|
||
_type="${toks[0]##*:}"
|
||
fi
|
||
[[ -n "$2" ]] && std::upvar "$2" "${_type}"
|
||
[[ -n "$3" ]] && std::upvar "$3" "${toks[1]}"
|
||
[[ -n "$4" ]] && std::upvar "$4" "${toks[2]}"
|
||
return 0
|
||
fi
|
||
done < "${config_file}"
|
||
done
|
||
return 1
|
||
}
|
||
|
||
subcommand_use() {
|
||
local -r subcommand='use'
|
||
IFS=':'
|
||
local -a modulepath=(${MODULEPATH})
|
||
unset IFS
|
||
local add2path_func='std::append_path'
|
||
|
||
#......................................................................
|
||
group_is_used() {
|
||
[[ :${UsedGroups}: =~ :$1: ]]
|
||
}
|
||
|
||
#......................................................................
|
||
print_info() {
|
||
local f
|
||
local r
|
||
std::info "Used groups:"
|
||
for f in ${UsedGroups//:/ }; do
|
||
std::info "\t${f}"
|
||
done
|
||
std::info ''
|
||
std::info "Unused groups:"
|
||
local _group
|
||
for _group in "${!GroupDepths[@]}"; do
|
||
local -i depth=${GroupDepths[${_group}]}
|
||
if ! group_is_used "${_group}" && (( depth == 0 )); then
|
||
std::info "\t${_group}"
|
||
fi
|
||
done
|
||
|
||
std::info "\nUsed releases stages:"
|
||
for r in ${UsedReleaseStages//:/ }; do
|
||
std::info "\t${r}"
|
||
done
|
||
std::info "\nUnused release stages:"
|
||
for r in ${ReleaseStages//:/ }; do
|
||
[[ ! ":${UsedReleaseStages}:" =~ :$r: ]] && std::info "\t${r}"
|
||
done
|
||
|
||
std::info "\nUsed flags:"
|
||
for flag in "${UsedFlags[@]}"; do
|
||
std::info "\t${flag}"
|
||
done
|
||
|
||
local overlay
|
||
std::info ''
|
||
std::info "Used overlays:"
|
||
for overlay in "${OverlayList[@]}"; do
|
||
local hiding=''
|
||
[[ "${OverlayDict[${overlay}]}" == "${ol_hiding}" ]] && \
|
||
hiding=' (hiding)'
|
||
std::info "\t${overlay}${hiding}"
|
||
done
|
||
|
||
std::info ''
|
||
std::info "Additonal directories in MODULEPATH:"
|
||
let n=0
|
||
local group
|
||
for (( i=0; i<${#modulepath[@]}; i++)); do
|
||
if ! find_overlay overlay group "${modulepath[i]}"; then
|
||
std::info "\t${modulepath[i]}"
|
||
let n+=1
|
||
fi
|
||
done
|
||
if (( n == 0 )); then
|
||
std::info "\tnone"
|
||
fi
|
||
std::info ""
|
||
}
|
||
|
||
#......................................................................
|
||
use () {
|
||
use_overlay() {
|
||
local ol_name_or_dir="$1"
|
||
|
||
if [[ -n "${LOADEDMODULES}" ]] && \
|
||
[[ "${LOADEDMODULES}" != Pmodules/+([.0-9rc]) ]]; then
|
||
std::die 3 "%s %s: %s %s" \
|
||
"${CMD}" "${subcommand}" \
|
||
"overlay cannot be added since some" \
|
||
"modules are already loaded!"
|
||
fi
|
||
|
||
local ol_dir=''
|
||
local ol_type=''
|
||
|
||
get_overlay_info \
|
||
"${ol_name_or_dir}" \
|
||
ol_type \
|
||
ol_dir \
|
||
|| std::die 3 "%s %s: %s -- %s" \
|
||
"${CMD}" "${subcommand}" \
|
||
"is not an overlay directory" \
|
||
"${ol_name_or_dir%:*}"
|
||
|
||
if [[ -n "${OverlayDict[${ol_dir}]}" ]]; then
|
||
std::die 3 "%s %s: %s -- %s" \
|
||
"${CMD}" "${subcommand}" \
|
||
"overlay already in use" \
|
||
"${ol_name_or_dir%:*}"
|
||
return 0
|
||
fi
|
||
|
||
case ${ol_type} in
|
||
${ol_normal} | ${ol_replacing} | ${ol_hiding} )
|
||
:
|
||
;;
|
||
* )
|
||
std::die 3 "%s %s: %s -- %s" \
|
||
"${CMD}" "${subcommand}" \
|
||
"invalid type '${ol_type}!" \
|
||
"${ol_name_or_dir}"
|
||
;;
|
||
esac
|
||
|
||
if [[ "${ol_type}" == "${ol_replacing}" ]]; then
|
||
# if this overlay replaces groups, we have
|
||
# to remove the modules made available by
|
||
# other overlays in these groups
|
||
for group in ${UsedGroups//:/ }; do
|
||
# is this group in the to be added overlay?
|
||
local dir="${ol_dir}/"
|
||
dir+="${group}/${PMODULES_MODULEFILES_DIR}"
|
||
[[ -d "${dir}" ]] || continue # no
|
||
|
||
dir="/${group}/${PMODULES_MODULEFILES_DIR}"
|
||
local -a dirs=( "${OverlayList[@]/%/${dir}}" )
|
||
std::remove_path MODULEPATH "${dirs[@]}"
|
||
done
|
||
fi
|
||
|
||
for group in ${UsedGroups//:/ }; do
|
||
local dir="${ol_dir}/"
|
||
dir+="${group}/${PMODULES_MODULEFILES_DIR}"
|
||
if [[ -d "${dir}" ]]; then
|
||
std::prepend_path MODULEPATH "${dir}"
|
||
Dir2OverlayMap[${dir}]="${ol_dir}"
|
||
fi
|
||
done
|
||
|
||
OverlayDict[${ol_dir}]="${ol_type}"
|
||
OverlayList=( "${ol_dir}" "${OverlayList[@]}" )
|
||
# FIXME: do we have to export it????
|
||
export_env OverlayList
|
||
g_env_must_be_saved='yes'
|
||
scan_groups "${OverlayList[@]}"
|
||
}
|
||
|
||
#..............................................................
|
||
use_group() {
|
||
std::append_path UsedGroups "$1"
|
||
local overlay group
|
||
for overlay in "${OverlayList[@]}"; do
|
||
for group in ${UsedGroups//:/ }; do
|
||
local dir="${overlay}/"
|
||
dir+="${group}/${PMODULES_MODULEFILES_DIR}"
|
||
if [[ -d "${dir}" ]]; then
|
||
std::prepend_path MODULEPATH "${dir}"
|
||
Dir2OverlayMap[${dir}]=${overlay}
|
||
fi
|
||
done
|
||
done
|
||
}
|
||
|
||
#..............................................................
|
||
local arg=$1
|
||
|
||
if is_release_stage "${arg}"; then
|
||
# argument is release stage
|
||
std::append_path UsedReleaseStages "${arg}"
|
||
return
|
||
fi
|
||
if [[ "${arg}" =~ "flag=" ]]; then
|
||
# argument is flag
|
||
UsedFlags+=( "${arg/flag=}" )
|
||
return
|
||
fi
|
||
if [[ "${arg}" =~ "overlay=" ]]; then
|
||
local overlay="${arg/overlay=}"
|
||
use_overlay "${overlay}"
|
||
return
|
||
fi
|
||
|
||
# check whether the user wants to add an unused group in
|
||
# an used overlay.
|
||
|
||
if [[ -z ${GroupDepths[${arg}]} ]]; then
|
||
# this scan is required if a new group has been
|
||
# create inside an used overlay
|
||
scan_groups "${overlays}"
|
||
g_env_must_be_saved='yes'
|
||
fi
|
||
|
||
if [[ -n ${GroupDepths[${arg}]} ]] &&
|
||
(( ${GroupDepths[${arg}]} == 0 )); then
|
||
# argument is group with depth 0
|
||
use_group "${arg}"
|
||
return
|
||
fi
|
||
if [[ -n ${GroupDepths[${arg}]} ]] &&
|
||
(( ${GroupDepths[${arg}]} > 0 )); then
|
||
# argument is a hierarchical group in our root
|
||
std::die 3 "%s %s: %s -- %s" \
|
||
"${CMD}" "${subcommand}" \
|
||
"illegal group" \
|
||
"${arg}"
|
||
fi
|
||
if get_overlay_info "${arg}"; then
|
||
use_overlay "${arg}"
|
||
return 0
|
||
fi
|
||
|
||
# arg must be a directory!
|
||
if [[ ! -d ${arg} ]]; then
|
||
std::die 3 "%s %s: %s -- %s" \
|
||
"${CMD}" "${subcommand}" \
|
||
"illegal argument: is neither a valid keyword, group nor directory" \
|
||
"${arg}"
|
||
fi
|
||
${add2path_func} MODULEPATH "${arg}"
|
||
}
|
||
|
||
#......................................................................
|
||
local -a args=()
|
||
while (( $# > 0)); do
|
||
case "$1" in
|
||
-\? | -H | --help )
|
||
print_help "${subcommand}"
|
||
;;
|
||
-a | --append )
|
||
add2path_func='std::append_path'
|
||
;;
|
||
-p | --prepend )
|
||
add2path_func='std::prepend_path'
|
||
;;
|
||
-- )
|
||
shift 1
|
||
args+=( "$@" )
|
||
break
|
||
;;
|
||
* )
|
||
args+=( "$1" )
|
||
;;
|
||
esac
|
||
shift
|
||
done
|
||
|
||
if (( ${#args[@]} == 0 )); then
|
||
print_info
|
||
return
|
||
fi
|
||
for arg in "${args[@]}"; do
|
||
use "${arg}"
|
||
done
|
||
g_env_must_be_saved='yes'
|
||
export_env 'MODULEPATH'
|
||
}
|
||
|
||
##############################################################################
|
||
#
|
||
# unuse directory|group|release_stage|...
|
||
#
|
||
Subcommands[unuse]='unuse'
|
||
Options[unuse]='-o \?H -l help'
|
||
Help[unuse]='
|
||
unuse directory|group|release...
|
||
Remove the given modulefiles directory, group, release stage,
|
||
flag from the search path.
|
||
'
|
||
|
||
subcommand_unuse() {
|
||
local -r subcommand='unuse'
|
||
IFS=':'
|
||
local -a modulepath=(${MODULEPATH})
|
||
unset IFS
|
||
|
||
#......................................................................
|
||
unuse() {
|
||
#..............................................................
|
||
unuse_overlay() {
|
||
local ol_name_or_dir="$1"
|
||
|
||
if [[ -n "${LOADEDMODULES}" ]] && \
|
||
[[ "${LOADEDMODULES}" != Pmodules/+([.0-9rc]) ]]; then
|
||
std::die 3 "%s %s: %s %s" \
|
||
"${CMD}" "${subcommand}" \
|
||
"overlay cannot be removed since" \
|
||
"some modules are still loaded!"
|
||
fi
|
||
|
||
local ol_dir=''
|
||
local ol_type=''
|
||
|
||
get_overlay_info \
|
||
"${ol_name_or_dir}" \
|
||
ol_type \
|
||
ol_dir \
|
||
|| std::die 3 "%s %s: %s -- %s" \
|
||
"${CMD}" "${subcommand}" \
|
||
"is not an overlay directory" \
|
||
"${ol_name_or_dir%:*}"
|
||
|
||
[[ "${ol_dir}" == "${PMODULES_ROOT}" ]] && \
|
||
std::die 3 "%s %s: %s -- %s" \
|
||
"${CMD}" "${subcommand}" \
|
||
"cannot remove root overlay" \
|
||
"${ol_name_or_dir%:*}"
|
||
[[ -z ${OverlayDict[${ol_dir}]} ]] && \
|
||
std::die 3 "%s %s: %s -- %s" \
|
||
"${CMD}" "${subcommand}" \
|
||
"not an used overlay" \
|
||
"${ol_name_or_dir%:*}"
|
||
|
||
if [[ "${OverlayDict[${ol_dir}]}" == "${ol_replacing}" ]]; then
|
||
# if this overlay hides groups, we have to re-add
|
||
# the modules made available by other overlays
|
||
for group in ${UsedGroups//:/ }; do
|
||
# first test whether this group is in the to be added overlay
|
||
local dir="${ol_dir}/"
|
||
dir+="${group}/${PMODULES_MODULEFILES_DIR}"
|
||
[[ -d "${dir}" ]] || continue # no
|
||
|
||
for dir in "${OverlayList[@]}"; do
|
||
dir+="/${group}/${PMODULES_MODULEFILES_DIR}"
|
||
std::remove_path MODULEPATH "${dir}"
|
||
done
|
||
done
|
||
fi
|
||
|
||
unset "OverlayDict[${ol_dir}]"
|
||
local i
|
||
for i in "${!OverlayList[@]}"; do
|
||
[[ ${OverlayList[i]} == ${ol_dir} ]] && unset 'OverlayList[i]'
|
||
done
|
||
g_env_must_be_saved='yes'
|
||
export_env OverlayList
|
||
local dir
|
||
for dir in "${modulepath[@]}"; do
|
||
if [[ "${dir}" =~ "${ol_dir}" ]]; then
|
||
std::remove_path MODULEPATH "${dir}"
|
||
fi
|
||
done
|
||
}
|
||
|
||
#..............................................................
|
||
unuse_group() {
|
||
local var="PMODULES_LOADED_${arg^^}"
|
||
if [[ -n "${!var}" ]]; then
|
||
std::die 3 "%s %s: %s -- %s" \
|
||
"${CMD}" "${subcommand}" \
|
||
"cannot remove group due to loaded modules" \
|
||
"${arg}"
|
||
fi
|
||
std::remove_path UsedGroups "${arg}"
|
||
local overlay
|
||
for overlay in "${OverlayList[@]}"; do
|
||
local dir="${overlay}/${arg}/${PMODULES_MODULEFILES_DIR}"
|
||
std::remove_path MODULEPATH "${dir}"
|
||
done
|
||
}
|
||
|
||
#..............................................................
|
||
local arg=$1
|
||
|
||
if is_release_stage "${arg}"; then
|
||
# argument is release stage
|
||
std::remove_path UsedReleaseStages "${arg}"
|
||
return
|
||
fi
|
||
if [[ "${arg}" =~ "flag=" ]]; then
|
||
# argument is flag
|
||
local flag="${arg/flag=}"
|
||
local i
|
||
for i in ${!UsedFlags[@]}; do
|
||
[[ ${UsedFlags[i]} == ${flag} ]] && unset UsedFlags[i]
|
||
done
|
||
return
|
||
fi
|
||
if [[ ${arg} =~ ^overlay= ]]; then
|
||
local overlay="${arg/overlay=}"
|
||
unuse_overlay "${overlay}"
|
||
return
|
||
fi
|
||
if [[ -n ${GroupDepths[${arg}]} ]] &&
|
||
(( ${GroupDepths[${arg}]} == 0 )); then
|
||
# argument is group in our root with depth 0
|
||
unuse_group "${arg}"
|
||
return
|
||
fi
|
||
if [[ -n ${GroupDepths[${arg}]} ]] &&
|
||
(( ${GroupDepths[${arg}]} > 0 )); then
|
||
# argument is a hierarchical group in our root
|
||
std::die 3 "%s %s: %s -- %s" \
|
||
"${CMD}" "${subcommand}" \
|
||
"illegal group" \
|
||
"${arg}"
|
||
fi
|
||
if get_overlay_info "${arg}"; then
|
||
unuse_overlay "${arg}"
|
||
return 0
|
||
fi
|
||
|
||
# arg must be a directory!
|
||
if [[ ! -d ${arg} ]]; then
|
||
std::die 3 "%s %s: %s -- %s" \
|
||
"${CMD}" "${subcommand}" \
|
||
"illegal argument" \
|
||
"${arg}"
|
||
fi
|
||
std::remove_path MODULEPATH "${dir}"
|
||
|
||
}
|
||
|
||
#......................................................................
|
||
local -a args=()
|
||
while (( $# > 0)); do
|
||
case "$1" in
|
||
-\? | -H | --help )
|
||
print_help "${subcommand}"
|
||
;;
|
||
-- )
|
||
shift 1
|
||
args+=( "$@" )
|
||
break
|
||
;;
|
||
* )
|
||
args+=( "$1" )
|
||
;;
|
||
esac
|
||
shift
|
||
done
|
||
if (( ${#args[@]} == 0 )); then
|
||
std::die 3 "%s %s: %s" \
|
||
"${CMD}" "${subcommand}" \
|
||
'missing argument'
|
||
fi
|
||
for arg in "${args[@]}"; do
|
||
unuse "${args[@]}"
|
||
done
|
||
g_env_must_be_saved='yes'
|
||
export_env 'MODULEPATH'
|
||
}
|
||
|
||
##############################################################################
|
||
#
|
||
# update
|
||
#
|
||
# :FIXME:
|
||
# either compile Modules with --enable-beginenv or remove the
|
||
# sub-command
|
||
#
|
||
Subcommands[update]='update'
|
||
Options[update]='-o \?H -l help'
|
||
Help[update]='
|
||
USAGE:
|
||
module update
|
||
Attempt to reload all loaded modulefiles.
|
||
'
|
||
|
||
subcommand_update() {
|
||
subcommand_generic0 'update' "$@"
|
||
}
|
||
|
||
##############################################################################
|
||
#
|
||
# refresh
|
||
#
|
||
Subcommands[refresh]='refresh'
|
||
Options[refresh]='-o \?H -l help'
|
||
Help[refresh]='
|
||
USAGE:
|
||
module refresh
|
||
Force a refresh of all non-persistent components of currently
|
||
loaded modules. This should be used on derived shells where
|
||
aliases need to be reinitialized but the environment variables
|
||
have already been set by the currently loaded modules.
|
||
'
|
||
|
||
subcommand_refresh() {
|
||
subcommand_generic0 'refresh' "$@"
|
||
}
|
||
|
||
#
|
||
# help function, used during initialization and for purging all modules
|
||
#
|
||
reset_modulepath() {
|
||
MODULEPATH=''
|
||
local group
|
||
local overlay
|
||
for overlay in "${!OverlayDict[@]}"; do
|
||
for group in ${UsedGroups//:/ }; do
|
||
local dir="${overlay}/${group}/${PMODULES_MODULEFILES_DIR}"
|
||
if [[ -d "${dir}" ]]; then
|
||
std::prepend_path MODULEPATH "${dir}"
|
||
Dir2OverlayMap[${dir}]="${overlay}"
|
||
fi
|
||
done
|
||
done
|
||
}
|
||
|
||
reset_used_groups() {
|
||
UsedGroups=''
|
||
local group
|
||
for group in ${DefaultGroups}; do
|
||
std::append_path UsedGroups "${group}"
|
||
done
|
||
g_env_must_be_saved='yes'
|
||
}
|
||
|
||
reset_used_releases() {
|
||
declare -g UsedReleaseStages=''
|
||
for r in ${DefaultReleaseStages//:/ }; do
|
||
std::append_path UsedReleaseStages "${r}"
|
||
done
|
||
g_env_must_be_saved='yes'
|
||
}
|
||
|
||
init_path() {
|
||
std::replace_path PATH "${PMODULES_HOME%/*}/.*"
|
||
std::prepend_path PATH "${PMODULES_HOME}/bin"
|
||
}
|
||
|
||
init_manpath() {
|
||
std::replace_path MANPATH "${PMODULES_HOME%/*}/.*"
|
||
|
||
if [[ -r /etc/man.config ]]; then
|
||
declare _manconf='/etc/man.config'
|
||
elif [[ -r /etc/man.conf ]]; then
|
||
declare _manconf='/etc/man.conf'
|
||
fi
|
||
if [[ -n ${_manconf} ]]; then
|
||
while read name value rest; do
|
||
std::append_path MANPATH "${value}"
|
||
done < <(grep "^MANPATH\s" "${_manconf}")
|
||
unset _manconf
|
||
else
|
||
std::append_path MANPATH "${PMODULES_HOME}/share/man"
|
||
std::append_path MANPATH "/usr/share/man"
|
||
fi
|
||
}
|
||
|
||
pmodules_init() {
|
||
if [[ -r "${pmodules_config_file}" ]]; then
|
||
source "${pmodules_config_file}" || \
|
||
std::die 3 "Oops: cannot parse config file -- %s\n" \
|
||
"${pmodules_config_file}"
|
||
fi
|
||
declare -gx LOADEDMODULES=''
|
||
declare -gx _LMFILES_=''
|
||
declare -gx UsedGroups=''
|
||
declare -gx MODULEPATH=''
|
||
declare -Ag GroupDepths='()'
|
||
declare -ag UsedFlags=()
|
||
declare -g Version="${PMODULES_VERSION}"
|
||
declare -Ag OverlayDict=([${PMODULES_ROOT}]="0")
|
||
declare -ag OverlayList=( "${PMODULES_ROOT}" )
|
||
|
||
reset_used_groups
|
||
init_overlay_vars
|
||
reset_modulepath
|
||
reset_used_releases
|
||
init_manpath
|
||
export_env \
|
||
LOADEDMODULES \
|
||
_LMFILES_ \
|
||
MODULEPATH \
|
||
PATH \
|
||
MANPATH
|
||
}
|
||
|
||
##############################################################################
|
||
#
|
||
# purge
|
||
#
|
||
Subcommands[purge]='purge'
|
||
Options[purge]='-o \?H -l help'
|
||
Help[purge]='
|
||
USAGE:
|
||
module purge
|
||
Unload all loaded modulefiles.
|
||
'
|
||
|
||
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
|
||
case "$1" in
|
||
-\? | -H | --help )
|
||
print_help "${subcommand}"
|
||
;;
|
||
-- )
|
||
shift 1
|
||
args+=( "$@" )
|
||
break
|
||
;;
|
||
* )
|
||
args+=( "$1" )
|
||
;;
|
||
esac
|
||
shift
|
||
done
|
||
if (( ${#args[@]} > 0 )); then
|
||
std::die 3 "%s %s: %s" \
|
||
"${CMD}" "${subcommand}" \
|
||
"no arguments allowd"
|
||
fi
|
||
|
||
# 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 output=$("${modulecmd}" 'bash' 'purge' 2> "${tmpfile}")
|
||
|
||
local error=$( < "${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
|
||
|
||
export_env MODULEPATH PMODULES_HOME
|
||
}
|
||
|
||
##############################################################################
|
||
#
|
||
# list [-hlt]
|
||
#
|
||
Subcommands[list]='list'
|
||
Options[list]='-l help -o \?Hhlt -l human -l long -l terse'
|
||
Help[list]='
|
||
USAGE:
|
||
module list
|
||
List loaded modules.
|
||
'
|
||
|
||
subcommand_list() {
|
||
local -r subcommand='list'
|
||
local opts=()
|
||
local args=()
|
||
while (( $# > 0 )); do
|
||
case $1 in
|
||
-\? | -H | --help )
|
||
print_help "${subcommand}"
|
||
;;
|
||
-h | --human )
|
||
opts+=( '-h' )
|
||
;;
|
||
-l | --long )
|
||
opts+=( '-l' )
|
||
;;
|
||
-t | --terse )
|
||
opts+=( '-t' )
|
||
;;
|
||
-- )
|
||
shift 1
|
||
args+=( "$@" )
|
||
break
|
||
;;
|
||
* )
|
||
args+=( "$1" )
|
||
;;
|
||
esac
|
||
shift
|
||
done
|
||
if (( ${#args[@]} > 0 )); then
|
||
std::die 3 "%s %s: %s" \
|
||
"${CMD}" "${subcommand}" \
|
||
"no arguments allowd"
|
||
fi
|
||
"${modulecmd}" "${Shell}" list "${opts[@]}"
|
||
}
|
||
|
||
|
||
##############################################################################
|
||
#
|
||
# clear
|
||
#
|
||
Subcommands[clear]='clear'
|
||
Options[clear]='-o \?H -l help'
|
||
Help[clear]='
|
||
USAGE:
|
||
module clear
|
||
Force the Modules package to believe that no modules are
|
||
currently loaded.
|
||
'
|
||
|
||
subcommand_clear() {
|
||
local -r subcommand='clear'
|
||
local -a args=()
|
||
while (( $# > 0 )); do
|
||
case $1 in
|
||
-\? | -H | --help )
|
||
print_help "${subcommand}"
|
||
;;
|
||
-- )
|
||
shift 1
|
||
args+=( "$@" )
|
||
break
|
||
;;
|
||
* )
|
||
args+=( "$1" )
|
||
;;
|
||
esac
|
||
shift
|
||
done
|
||
if (( ${#args[@]} > 0 )); then
|
||
std::die 3 "%s %s: %s" \
|
||
"${CMD}" "${subcommand}" \
|
||
"no arguments allowed"
|
||
fi
|
||
pmodules_init
|
||
export_env LOADEDMODULES MODULEPATH _LMFILES_
|
||
}
|
||
|
||
##############################################################################
|
||
#
|
||
# search [switches] [STRING...]
|
||
#
|
||
Subcommands[search]='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 '
|
||
Options[search]+='-l all-deps -l wrap '
|
||
Options[search]+='-l glob'
|
||
Help[search]='
|
||
USAGE:
|
||
module search [switches] STRING...
|
||
Search installed modules. If an argument is given, search
|
||
for modules whose name match the argument.
|
||
|
||
SWITCHES:
|
||
-a|--all-release-stages
|
||
Search within all releases.
|
||
|
||
--all-deps
|
||
Show all dependecies
|
||
|
||
--glob
|
||
Interpret STRING as shell pattern.
|
||
|
||
--no-header
|
||
Suppress output of a header.
|
||
|
||
--release-stage=RELEASE_STAGE
|
||
Search for modules within this release stage. You can specify
|
||
this switch multiple times. Without this switch, the release
|
||
stages in use will be searched.
|
||
|
||
--verbose
|
||
vebose output
|
||
|
||
--with=STRING
|
||
Search for modules compiled with modules matching string. The
|
||
command
|
||
|
||
module search --with=gcc/4.8.3
|
||
|
||
lists all modules in the hierarchy compiled with gcc 4.8.3.
|
||
|
||
--wrap
|
||
wrap output
|
||
'
|
||
|
||
subcommand_search() {
|
||
local -r subcommand='search'
|
||
local modules=()
|
||
local with_modules='//'
|
||
local -ir cols=$(tput cols) # get number of columns of terminal
|
||
local -i max_len_modulename=0
|
||
local src_prefix=()
|
||
local opt_print_header='yes'
|
||
local opt_print_modulefiles='no'
|
||
local opt_print_csv='no'
|
||
local opt_print_verbose='no'
|
||
local opt_use_releases=':'
|
||
local opt_all_deps='no'
|
||
local opt_wrap='no'
|
||
local opt_glob='no'
|
||
|
||
#.....................................................................
|
||
#
|
||
# output result of search
|
||
# Args:
|
||
# $1: tmp file
|
||
#
|
||
# variables used from enclosing function:
|
||
# opt_print_header
|
||
# opt_print_modulefiles
|
||
# with_modules
|
||
#
|
||
print_result() {
|
||
local func_print_header=''
|
||
local func_print_line=''
|
||
local fmt=''
|
||
|
||
print_default() {
|
||
fmt="%-${max_len_modulename}s %-10s %-12s %-s"
|
||
if [[ ${opt_print_header} == 'yes' ]]; then
|
||
func_print_header='print_header_default'
|
||
else
|
||
func_print_header='print_header_none'
|
||
fi
|
||
func_print_line='print_line_default'
|
||
}
|
||
|
||
print_header_default() {
|
||
std::info ''
|
||
std::info "${fmt}" "Module" "Rel.stage" "Group" "Requires"
|
||
std::info '-%.0s' $(seq 1 ${cols})
|
||
}
|
||
|
||
print_line_default() {
|
||
write_line() {
|
||
local str="$1"
|
||
if (( ${#str} >= cols )); then
|
||
str="${str:0:$((cols-1))}>"
|
||
fi
|
||
std::info "${str}"
|
||
}
|
||
if [[ "${opt_wrap}" == 'no' ]]; then
|
||
local deps="${@:5}"
|
||
local str=$(printf "${fmt}" "$1" "$2" "$3" "${deps[@]}")
|
||
write_line "${str}"
|
||
else
|
||
local deps=( "${@:5}" )
|
||
local str=$(printf "${fmt}" "$1" "$2" "$3" "${deps[0]}")
|
||
for (( i = 1; i < ${#deps[@]}; i++ )); do
|
||
if (( ${#str} + ${#deps[i]} + 1 <= cols )); then
|
||
str+=" ${deps[i]}"
|
||
else
|
||
write_line "${str}"
|
||
str=$(printf "${fmt}" "" "" "" "> ${deps[i]}")
|
||
fi
|
||
done
|
||
write_line "${str}"
|
||
fi
|
||
}
|
||
|
||
print_verbose() {
|
||
fmt="%-${max_len_modulename}s %-10s %-12s %-s"
|
||
func_print_header='print_header_verbose'
|
||
func_print_line='print_line_verbose'
|
||
}
|
||
|
||
print_header_verbose() {
|
||
std::info ''
|
||
std::info "${fmt}" "Module" "Rel.stage" "Group" "Dependencies/Modulefile"
|
||
std::info '-%.0s' $(seq 1 ${cols})
|
||
}
|
||
|
||
print_line_verbose() {
|
||
local deps="${@:5}"
|
||
std::info "${fmt}" "$1" "$2" "$3" "dependencies: ${deps}"
|
||
std::info "${fmt}" "" "" "" "modulefile: $4"
|
||
}
|
||
|
||
# print full modulefile names only
|
||
print_modulefiles() {
|
||
fmt=''
|
||
func_print_header='print_header_none'
|
||
func_print_line='print_line_modulefile'
|
||
}
|
||
|
||
print_header_none() {
|
||
:
|
||
}
|
||
|
||
print_line_modulefile() {
|
||
std::info "$4"
|
||
}
|
||
|
||
print_line_csv() {
|
||
:
|
||
}
|
||
|
||
print_csv() {
|
||
fmt=''
|
||
func_print_header='print_header_none'
|
||
func_print_line='print_line_csv'
|
||
}
|
||
|
||
if [[ "${opt_print_modulefiles}" == 'yes' ]]; then
|
||
print_modulefiles
|
||
elif [[ "${opt_print_csv}" == 'yes' ]]; then
|
||
print_csv
|
||
elif [[ "${opt_print_verbose}" == 'yes' ]]; then
|
||
print_verbose
|
||
else
|
||
print_default
|
||
fi
|
||
|
||
${func_print_header}
|
||
while read -a toks; do
|
||
${func_print_line} "${toks[@]}"
|
||
done < <("${sort}" --version-sort -k 1,1 -k 4,4 -k 5,5 "${tmpfile}" | \
|
||
${awk} "${with_modules}")
|
||
}
|
||
|
||
get_module_prefix() {
|
||
local "$1"
|
||
local modulefile="$2"
|
||
local -r _prefix=$("${modulecmd}" bash show "${modulefile}" 2>&1 | \
|
||
${awk} '/_PREFIX |_HOME / {print $3; exit}')
|
||
std::upvar $1 "${_prefix}"
|
||
}
|
||
|
||
#.....................................................................
|
||
#
|
||
# search modules
|
||
# Args:
|
||
# $1: module name pattern
|
||
#
|
||
# Variables used from enclosing function
|
||
# :FIXME:
|
||
#
|
||
search () {
|
||
if [[ ${opt_glob} == 'yes' ]]; then
|
||
local -r module="$1"
|
||
else
|
||
local -r module="${1}*"
|
||
fi
|
||
|
||
# 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} )
|
||
|
||
# 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+=3 )); do
|
||
local name=${mods[i]}
|
||
local rel_stage=${mods[i+1]}
|
||
local modulefile=${mods[i+2]}
|
||
|
||
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
|
||
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} \
|
||
${deps[@]} >> "${tmpfile}"
|
||
done
|
||
done
|
||
print_result
|
||
}
|
||
|
||
while (( $# > 0 )); do
|
||
case $1 in
|
||
-\? | -H | --help )
|
||
print_help "${subcommand}"
|
||
;;
|
||
--all-deps )
|
||
opt_all_deps='yes'
|
||
;;
|
||
--no-header )
|
||
opt_print_header='no'
|
||
;;
|
||
--print-modulefiles )
|
||
opt_print_modulefiles='yes'
|
||
opt_print_header='no'
|
||
;;
|
||
--print-csv )
|
||
opt_print_csv='yes'
|
||
opt_print_header='no'
|
||
;;
|
||
--release-stage | --release-stage=* )
|
||
if [[ "$1" == "--release" ]]; then
|
||
local arg=$2
|
||
shift
|
||
else
|
||
local arg=${1/--release=}
|
||
fi
|
||
is_release_stage "${arg}" || \
|
||
std::die 1 "%s %s: %s -- %s" \
|
||
"${CMD}" 'search' \
|
||
"illegal release stage" \
|
||
"${arg}"
|
||
opt_use_rel_stages+="${arg}:"
|
||
;;
|
||
--with | --with=* )
|
||
if [[ "$1" == --with ]]; then
|
||
local arg=$2
|
||
shift
|
||
else
|
||
local arg=${1/--with=}
|
||
fi
|
||
if [[ -z ${arg} ]] || [[ "${arg}" =~ "-*" ]]; then
|
||
std::die 1 "%s %s: %s -- %s" \
|
||
"${CMD}" 'search' \
|
||
"illegal value for --with option" \
|
||
"${arg}"
|
||
fi
|
||
arg=${arg//:/ }
|
||
arg=${arg//,/ }
|
||
for module in ${arg}; do
|
||
with_modules+=" && / ${module//\//\\/}/"
|
||
done
|
||
;;
|
||
-a | --all-releases-stages )
|
||
opt_use_rel_stages+="${ReleaseStages}"
|
||
;;
|
||
--src | --src=*)
|
||
if [[ "$1" == --src ]]; then
|
||
local src_prefix="$2"
|
||
shift
|
||
else
|
||
local src_prefix="${1/--src=}"
|
||
fi
|
||
if [[ ! -e "${src_prefix}" ]]; then
|
||
std::die 1 "%s %s: %s -- %s" \
|
||
"${CMD}" 'search' \
|
||
"illegal value for --src option" \
|
||
"${src_prefix} does not exist"
|
||
fi
|
||
if [[ ! -d "${src_prefix}" ]]; then
|
||
std::die 1 "%s %s: %s -- %s" \
|
||
"${CMD}" 'search' \
|
||
"illegal value for --src option" \
|
||
"${src_prefix} is not a directory"
|
||
fi
|
||
src_prefix=$(std::get_abspath "${src_prefix}")
|
||
;;
|
||
-v | --verbose )
|
||
opt_print_verbose='yes'
|
||
;;
|
||
--wrap )
|
||
opt_wrap='yes'
|
||
;;
|
||
--glob )
|
||
opt_glob='yes'
|
||
;;
|
||
-- )
|
||
shift 1
|
||
modules+=( "$@" )
|
||
break
|
||
;;
|
||
* )
|
||
modules+=( "$1" )
|
||
;;
|
||
esac
|
||
shift
|
||
done
|
||
if [[ -z "${src_prefix}" ]]; then
|
||
local -a src_prefix=( "${OverlayList[@]}" )
|
||
fi
|
||
|
||
if [[ "${opt_use_rel_stages}" == ":" ]]; then
|
||
opt_use_rel_stages=":${UsedReleaseStages}:"
|
||
fi
|
||
|
||
if [[ ${#modules[@]} == 0 ]]; then
|
||
modules+=( '' )
|
||
fi
|
||
|
||
# :FIXME: do we need this?
|
||
if (( ${#GroupDepths[@]} == 0 )) || \
|
||
[[ ${src_prefix} != ${PMODULES_ROOT} ]]; then
|
||
scan_groups "${src_prefix}"
|
||
g_env_must_be_saved='yes'
|
||
fi
|
||
|
||
local module
|
||
for module in "${modules[@]}"; do
|
||
search "${module}"
|
||
done
|
||
}
|
||
|
||
##############################################################################
|
||
#
|
||
# help [module|sub-command]
|
||
#
|
||
Subcommands[help]='help'
|
||
Options[help]='-o hHV\? -l version -l help'
|
||
Help[help]='
|
||
USAGE:
|
||
module [ switches ] [ subcommand ] [subcommand-args ]
|
||
|
||
SWITCHES:
|
||
-h|-H|-?|--help this usage info
|
||
-V|--version modules version & configuration options
|
||
--debug enable debug output
|
||
|
||
SUBCOMMANDS:
|
||
+ add|load [switches] modulefile [modulefile ...]
|
||
+ rm|unload modulefile [modulefile ...]
|
||
+ switch|swap [modulefile1] modulefile2
|
||
+ display|show modulefile [modulefile ...]
|
||
+ avail [switches] [modulefile [modulefile ...]]
|
||
+ search [switches] [args]
|
||
+ use [switches] [dir|group|release ...]
|
||
+ unuse dir|group|release [dir|group|release ...]
|
||
+ refresh
|
||
+ purge
|
||
+ list [switches]
|
||
+ clear
|
||
+ help [modulefile|subcommand]
|
||
+ whatis [modulefile [modulefile ...]]
|
||
+ apropos|keyword string
|
||
+ initadd modulefile [modulefile ...]
|
||
+ initprepend modulefile [modulefile ...]
|
||
+ initrm modulefile [modulefile ...]
|
||
+ initswitch modulefile1 modulefile2
|
||
+ initlist
|
||
+ initclear
|
||
'
|
||
|
||
subcommand_help() {
|
||
local -r subcommand='help'
|
||
local -a args=()
|
||
while (( $# > 0 )); do
|
||
case $1 in
|
||
-\? | -h | -H | --help )
|
||
print_help "${subcommand}"
|
||
;;
|
||
-V | --version )
|
||
print_help 'version'
|
||
;;
|
||
-- )
|
||
shift 1
|
||
args+=( "$@" )
|
||
break
|
||
;;
|
||
* )
|
||
args+=( "$1" )
|
||
;;
|
||
esac
|
||
shift
|
||
done
|
||
if (( ${#args[@]} == 0 )); then
|
||
print_help 'help'
|
||
fi
|
||
local arg
|
||
for arg in "${args[@]}"; do
|
||
if [[ -n "${Help[${arg}]}" ]] ; then
|
||
print_help "${arg}"
|
||
else
|
||
# :FIXME: print help of newest *available* module
|
||
# (respecting UsedReleaseStages)
|
||
"${modulecmd}" "${Shell}" "${subcommand}" "${arg}"
|
||
fi
|
||
done
|
||
}
|
||
|
||
##############################################################################
|
||
#
|
||
# whatis
|
||
#
|
||
Subcommands[whatis]='whatis'
|
||
Options[whatis]='-o \?H -l help'
|
||
Help[whatis]='
|
||
USAGE:
|
||
module whatis [modulefile...]
|
||
Display the information set up by the module-whatis commands
|
||
inside the specified modulefile(s). If no modulefile is
|
||
specified, all 'whatis' lines will be shown.
|
||
'
|
||
|
||
subcommand_whatis() {
|
||
if (( $# == 0 )); then
|
||
subcommand_generic0 'whatis'
|
||
else
|
||
subcommand_generic1plus 'whatis' "$@"
|
||
fi
|
||
}
|
||
|
||
##############################################################################
|
||
#
|
||
# apropos
|
||
#
|
||
Subcommands[apropos]='apropos'
|
||
Subcommands[keyword]='apropos'
|
||
Options[apropos]='-o \?H -l help'
|
||
Help[apropos]='
|
||
USAGE:
|
||
module apropos string
|
||
module keyword string Seeks through the 'whatis' informations of
|
||
all modulefiles for the specified string. All module-whatis
|
||
informations matching the string will be displayed.
|
||
'
|
||
|
||
subcommand_apropos() {
|
||
subcommand_generic1 'apropos' "$@"
|
||
}
|
||
|
||
##############################################################################
|
||
#
|
||
# initadd module...
|
||
#
|
||
Subcommands[initadd]='initadd'
|
||
Options[initadd]='-o \?H -l help'
|
||
Help[initadd]="
|
||
USAGE:
|
||
module initadd modulefile...
|
||
Add modulefile(s) to the shell's initialization file in the
|
||
user's home directory. The startup files checked (in order)
|
||
are:
|
||
|
||
csh - .modules, .cshrc(.ext), .csh_variables, and
|
||
.login(.ext)
|
||
tcsh - .modules, .tcshrc, .cshrc(.ext), .csh_variables,
|
||
and .login(.ext)
|
||
(k)sh - .modules, .profile(.ext), and .kshenv(.ext)
|
||
bash - .modules, .bash_profile, .bash_login,
|
||
.profile(.ext) and .bashrc(.ext)
|
||
zsh - .modules, .zcshrc(.ext), .zshenv(.ext), and
|
||
.zlogin(.ext)
|
||
|
||
If a 'module load' line is found in any of these files, the
|
||
modulefile(s) is(are) appended to any existing list of
|
||
modulefiles. The 'module load' line must be located in at
|
||
least one of the files listed above for any of the 'init'
|
||
sub-commands to work properly. If the 'module load' line
|
||
line is found in multiple shell initialization files, all
|
||
of the lines are changed.
|
||
"
|
||
|
||
subcommand_initadd() {
|
||
subcommand_generic1plus 'initadd' "$@"
|
||
}
|
||
|
||
##############################################################################
|
||
#
|
||
# initprepend module...
|
||
#
|
||
Subcommands[initprepend]='initprepend'
|
||
Options[initprepend]='-o \?H -l help'
|
||
Help[initprepend]="
|
||
USAGE:
|
||
module initprepend modulefile...
|
||
Does the same as initadd but prepends the given modules to
|
||
the beginning of the list.
|
||
"
|
||
|
||
subcommand_initprepend() {
|
||
subcommand_generic1plus 'initprepend' "$@"
|
||
}
|
||
|
||
##############################################################################
|
||
#
|
||
# initrm module...
|
||
#
|
||
Subcommands[initrm]='initrm'
|
||
Options[initrm]='-o \?H -l help'
|
||
Help[initrm]="
|
||
USAGE:
|
||
module initrm modulefile...
|
||
Remove modulefile(s) from the shell's initialization files.
|
||
"
|
||
|
||
subcommand_initrm() {
|
||
subcommand_generic1plus 'initrm' "$@"
|
||
}
|
||
|
||
##############################################################################
|
||
#
|
||
# initswitch module1 module2
|
||
#
|
||
Subcommands[initswitch]='initswitch'
|
||
Options[initswitch]='-o \?H -l help'
|
||
Help[initswitch]="
|
||
USAGE:
|
||
module initswitch modulefile1 modulefile2
|
||
Switch modulefile1 with modulefile2 in the shell's
|
||
initialization files.
|
||
"
|
||
|
||
subcommand_initswitch() {
|
||
subcommand='initswitch'
|
||
local args=()
|
||
while (( $# > 0 )); do
|
||
case $1 in
|
||
-\? | --help )
|
||
print_help "${subcommand}"
|
||
;;
|
||
-- )
|
||
shift 1
|
||
args+=( "$@" )
|
||
break
|
||
;;
|
||
* )
|
||
args+=( "$1" )
|
||
;;
|
||
esac
|
||
shift
|
||
done
|
||
if (( ${#args[@]} != 2 )); then
|
||
std::die 3 "%s %s: %s" \
|
||
"${CMD}" "${subcommand}" \
|
||
"two arguments required not less not more"
|
||
fi
|
||
"${modulecmd}" "${Shell}" "${subcommand}" "${args[@]}"
|
||
}
|
||
|
||
##############################################################################
|
||
#
|
||
# initlist
|
||
#
|
||
Subcommands[initlist]='initlist'
|
||
Options[initlist]='-o \?H -l help'
|
||
Help[initlist]="
|
||
USAGE:
|
||
module initlist
|
||
List all of the modulefiles loaded from the shell's
|
||
initialization file.
|
||
"
|
||
|
||
subcommand_initlist() {
|
||
subcommand_generic0 'initlist' "$@"
|
||
}
|
||
|
||
##############################################################################
|
||
#
|
||
# initclear
|
||
#
|
||
Subcommands[initclear]='initclear'
|
||
Options[initclear]='-o \?H -l help'
|
||
Help[initclear]="
|
||
USAGE:
|
||
module initclear
|
||
Clear all of the modulefiles from the shell's
|
||
initialization files.
|
||
"
|
||
|
||
subcommand_initclear() {
|
||
subcommand_generic0 'initclear' "$@"
|
||
}
|
||
|
||
##############################################################################
|
||
#
|
||
# main
|
||
#
|
||
case "$1" in
|
||
sh | bash | zsh )
|
||
declare Shell="sh"
|
||
;;
|
||
csh | tcsh )
|
||
declare Shell='csh'
|
||
;;
|
||
* )
|
||
std::die 1 "${CMD}: unsupported shell -- $1"
|
||
;;
|
||
esac
|
||
shift
|
||
|
||
declare -a opts=()
|
||
while (( $# > 0 )); do
|
||
case $1 in
|
||
-\? | -H | --help | -help )
|
||
print_help 'help'
|
||
;;
|
||
-V | --version )
|
||
print_help 'version'
|
||
;;
|
||
--debug )
|
||
set -x
|
||
;;
|
||
'' )
|
||
;;
|
||
-* )
|
||
opts+=( "$1" )
|
||
;;
|
||
* )
|
||
subcommand="$1"
|
||
shift
|
||
break
|
||
;;
|
||
esac
|
||
shift
|
||
done
|
||
|
||
if [[ -z "${subcommand}" ]]; then
|
||
std::die 1 "${CMD}: no sub-command specified."
|
||
fi
|
||
|
||
if [[ -z "${Subcommands[${subcommand}]}" ]]; then
|
||
std::die 1 "${CMD}: unknown sub-command -- ${subcommand}"
|
||
fi
|
||
|
||
init_overlay_vars() {
|
||
declare -ag OverlayList=( "${PMODULES_ROOT}" )
|
||
declare -Ag OverlayDict=([${PMODULES_ROOT}]="0")
|
||
declare -Ag Dir2OverlayMap=()
|
||
local overlay
|
||
for overlay in "${!OverlayDict[@]}"; do
|
||
local group
|
||
for group in ${UsedGroups//:/ }; do
|
||
local dir="${overlay}/${group}/${PMODULES_MODULEFILES_DIR}"
|
||
if [[ -d "${dir}" ]]; then
|
||
Dir2OverlayMap[${dir}]=${overlay}
|
||
fi
|
||
done
|
||
done
|
||
}
|
||
|
||
case ${subcommand} in
|
||
add )
|
||
subcommand='load'
|
||
;;
|
||
display )
|
||
subcommand='show'
|
||
;;
|
||
keyword )
|
||
subcommand='apropos'
|
||
;;
|
||
rm )
|
||
subcommand='unload'
|
||
;;
|
||
switch )
|
||
subcommand='swap'
|
||
;;
|
||
esac
|
||
|
||
if [[ -n ${PMODULES_ENV} ]]; then
|
||
eval "$("${base64}" -d <<< "${PMODULES_ENV}" 2>/dev/null)"
|
||
if [[ -z ${Version} ]] || [[ ${Version} != ${PMODULES_VERSION} ]]; then
|
||
# the Pmodules version changed!
|
||
declare -g Version="${PMODULES_VERSION}"
|
||
init_overlay_vars
|
||
# renamed in version 1.0.0rc10 and type changed from
|
||
# associative array to normal array
|
||
if [[ -v UseFlags ]]; then
|
||
declare -a UsedFlags=( "${!UseFlags[@]}" )
|
||
unset UseFlags
|
||
fi
|
||
if [[ ! -v UsedFlags ]]; then
|
||
declare -a UsedFlags=()
|
||
fi
|
||
if [[ -v UsedReleases ]]; then
|
||
declare -- UsedReleaseStages="${UsedReleases}"
|
||
unset UsedReleases
|
||
fi
|
||
if [[ -v PMODULES_DEFAULT_GROUPS ]]; then
|
||
declare -- DefaultGroups="${PMODULES_DEFAULT_GROUPS}"
|
||
unset PMODULES_DEFAULT_GROUPS
|
||
fi
|
||
if [[ -v PMODULES_DEFINED_RELEASES ]]; then
|
||
declare -- ReleaseStages="${PMODULES_DEFINED_RELEASES}"
|
||
unset PMODULES_DEFINED_RELEASES
|
||
fi
|
||
if [[ -v PMODULES_DEFAULT_RELEASES ]]; then
|
||
declare -- DefaultReleaseStages="${PMODULES_DEFAULT_RELEASES}"
|
||
unset PMODULES_DEFAULT_RELEASES
|
||
fi
|
||
g_env_must_be_saved='yes'
|
||
fi
|
||
else
|
||
pmodules_init
|
||
g_env_must_be_saved='yes'
|
||
fi
|
||
|
||
if (( ${#GroupDepths[@]} == 0 )); then
|
||
scan_groups "${!OverlayDict[@]}"
|
||
g_env_must_be_saved='yes'
|
||
fi
|
||
|
||
case ${subcommand} in
|
||
load|purge|search|swap )
|
||
declare -r tmpfile=$( ${mktemp} /tmp/Pmodules.XXXXXX ) \
|
||
|| std::die 1 "Oops: unable to create tmp file!"
|
||
;;
|
||
* )
|
||
declare -r tmpfile=''
|
||
;;
|
||
esac
|
||
|
||
|
||
tmp=$("${getopt}" --name="${CMD}" ${Options[${subcommand}]} -- "${opts[@]}" "$@" ) \
|
||
|| print_help "${subcommand}"
|
||
eval args=( "$tmp" )
|
||
unset tmp
|
||
subcommand_${Subcommands[$subcommand]} "${args[@]}"
|
||
|
||
# Local Variables:
|
||
# mode: sh
|
||
# sh-basic-offset: 8
|
||
# tab-width: 8
|
||
# End:
|