mirror of
https://github.com/Pmodules/Pmodules.git
synced 2026-07-02 20:00:50 +02:00
Removing a Pmodule module with module purge has some unwanted side-effects. It is not required to have modulecmd in a directory of PATH. If you user explicitly loads a Pmodules module the bin directory of the Pmodule module is added to the PATH. A Pmodules module might be loaded for two reasons. First to change the Pmodules version, second to make the build system available. If we remove a Pmodules module with module purge the build systems is getting unavailable again. This is confusing for the user.
2265 lines
59 KiB
Plaintext
Executable File
2265 lines
59 KiB
Plaintext
Executable File
#!@BASH@ --noprofile
|
|
#
|
|
|
|
#set -o nounset
|
|
# we have to unset CDPATH, otherwise 'cd' prints the directoy!
|
|
unset CDPATH
|
|
|
|
# used for some output 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"
|
|
|
|
base64=$(PATH=/bin:/usr/bin /usr/bin/which base64)
|
|
declare -r base64
|
|
mktemp=$(PATH=/bin:/usr/bin /usr/bin/which mktemp)
|
|
declare -r mktemp
|
|
sort=$(PATH=/bin:/usr/bin /usr/bin/which sort)
|
|
declare -r sort
|
|
awk=$(PATH=/bin:/usr/bin /usr/bin/which awk)
|
|
declare -r awk
|
|
rm=$(PATH=/bin:/usr/bin /usr/bin/which rm)
|
|
declare -r rm
|
|
logger=$(PATH=/bin:/usr/bin /usr/bin/which logger)
|
|
declare -r logger
|
|
|
|
if [[ $(uname -s) == 'Darwin' ]]; then
|
|
declare -r getopt="${libexecdir}/getopt"
|
|
declare -r find="${libexecdir}/find"
|
|
else
|
|
getopt=$(PATH=/bin:/usr/bin /usr/bin/which getopt)
|
|
declare -r getopt
|
|
find=$(PATH=/bin:/usr/bin /usr/bin/which find)
|
|
declare -r find
|
|
fi
|
|
|
|
source "${libdir}/libstd.bash"
|
|
|
|
: ${PMODULES_DEFINED_RELEASES:=':unstable:stable:deprecated:'}
|
|
|
|
declare -r version='@PMODULES_VERSION@'
|
|
|
|
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 verbosity_lvl=${PMODULES_VERBOSITY:-'verbose'}
|
|
|
|
# we use newline as internal field separator
|
|
IFS=$' \t\n'
|
|
declare -r __IFS=${IFS} # used to restore IFS
|
|
|
|
shopt -s nullglob
|
|
|
|
declare -A GroupDepths='()'
|
|
declare Shell=''
|
|
declare -A Subcommands
|
|
declare -A Options
|
|
declare -A Help
|
|
|
|
Help['version']="
|
|
Pmodules ${version} using Tcl Environment Modules @MODULES_VERSION@
|
|
Copyright GNU GPL v2
|
|
"
|
|
|
|
print_help() {
|
|
echo -e "${Help[$1]}" 1>&2
|
|
std::die 1
|
|
}
|
|
|
|
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}\n"
|
|
;;
|
|
esac
|
|
|
|
while (( $# > 0 )); do
|
|
printf "${fmt}" "$1" "${!1}"
|
|
shift
|
|
done
|
|
}
|
|
|
|
#
|
|
# 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() {
|
|
[[ ${g_env_must_be_saved} == 'no' ]] && return 0
|
|
local vars=( GroupDepths UsedReleases UseFlags UsedGroups )
|
|
vars+=( PMODULES_DEFAULT_GROUPS PMODULES_DEFINED_RELEASES )
|
|
vars+=( PMODULES_DEFAULT_RELEASES )
|
|
|
|
local s=$(typeset -p ${vars[@]})
|
|
declare -g PMODULES_ENV=$( "${base64}" --wrap=0 <<< "$s" )
|
|
export_env 'PMODULES_ENV'
|
|
}
|
|
|
|
trap 'save_env ' EXIT
|
|
|
|
#
|
|
# get release of module
|
|
# Note:
|
|
# - the release of a modulefile outside ${PMODULES_ROOT} is 'stable'
|
|
# - the release of a modulefile inside ${PMODULES_ROOT} without a
|
|
# coresponding release file is 'unstable'
|
|
#
|
|
# Args:
|
|
# $1: absolute modulefile name
|
|
#
|
|
get_release() {
|
|
local "$1"
|
|
local -r modulefile="$2"
|
|
|
|
# is modulefile outside ${PMODULES_ROOT}?
|
|
if [[ ! ${modulefile} =~ ${PMODULES_ROOT} ]]; then
|
|
std::upvar $1 'stable'
|
|
return 0
|
|
fi
|
|
|
|
# we are inside ${PMODULES_ROOT}
|
|
local -r releasefile="${modulefile%/*}/.release-${modulefile##*/}"
|
|
if [[ -r ${releasefile} ]]; then
|
|
# read releasefile, remove empty lines, spaces etc
|
|
local -r data=$( < "${releasefile}" )
|
|
std::upvar $1 "${data}"
|
|
else
|
|
std::upvar $1 'unstable'
|
|
fi
|
|
return 0
|
|
}
|
|
|
|
is_release() {
|
|
[[ ${PMODULES_DEFINED_RELEASES} =~ :$1: ]]
|
|
}
|
|
|
|
#
|
|
# Check whether argument is a group
|
|
#
|
|
# Args:
|
|
# $1: string
|
|
#
|
|
is_group () {
|
|
local -r group="$1"
|
|
# arg isn't emtpy and group already in cache
|
|
[[ -n ${group} ]] && [[ -n ${GroupDepths[${group}]} ]] && return 0
|
|
local moduledir="${PMODULES_ROOT}/${group}/${PMODULES_MODULEFILES_DIR}"
|
|
[[ -d "${moduledir}" ]] || return 1
|
|
compute_group_depth "${moduledir}"
|
|
}
|
|
|
|
#
|
|
# 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}"
|
|
;;
|
|
-- )
|
|
:
|
|
;;
|
|
* )
|
|
args+=( "$1" )
|
|
;;
|
|
esac
|
|
done
|
|
if (( ${#args[@]} > 0 )); then
|
|
std::die 3 "%s %s: %s\n" \
|
|
"${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}"
|
|
;;
|
|
-- )
|
|
:
|
|
;;
|
|
* )
|
|
args+=( "$1" )
|
|
;;
|
|
esac
|
|
shift
|
|
done
|
|
if (( ${#args[@]} == 0 )); then
|
|
std::die 3 "%s %s: %s\n" \
|
|
"${CMD}" "${subcommand}" \
|
|
"missing argument"
|
|
elif (( ${#args[@]} > 1 )); then
|
|
std::die 3 "%s %s: %s\n" \
|
|
"${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}"
|
|
;;
|
|
-- )
|
|
:
|
|
;;
|
|
* )
|
|
args+=( "$1" )
|
|
;;
|
|
esac
|
|
shift
|
|
done
|
|
if (( ${#args[@]} == 0 )); then
|
|
std::die 3 "%s %s: %s\n" \
|
|
"${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 Hfsvwi -l force -l silent -l verbose -l warn -l internal'
|
|
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 release='undef'
|
|
local current_modulefile=''
|
|
local prefix=''
|
|
local m=''
|
|
|
|
IFS=':'
|
|
local -a modulepath=(${MODULEPATH})
|
|
IFS=${__IFS}
|
|
|
|
#
|
|
# 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
|
|
#
|
|
# The following variables in the enclosing function are set:
|
|
# current_modulefile
|
|
# prefix
|
|
# release
|
|
#
|
|
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 release "${current_modulefile}" "${UsedReleases}"
|
|
}
|
|
|
|
#
|
|
# output load 'hints'
|
|
#
|
|
# Note:
|
|
# The variable 'm' from the parent function will be used
|
|
# but not changed.
|
|
#
|
|
# Args:
|
|
# none
|
|
output_load_hints() {
|
|
local output=''
|
|
local release=''
|
|
while read -a line; do
|
|
release=${line[1]}
|
|
if [[ ! ":${UsedReleases}:" =~ "${release}" ]]; then
|
|
output+="module use ${release}; "
|
|
fi
|
|
local group=${line[2]}
|
|
if [[ ! ":${UsedGroups}:" =~ ":${group}:" ]] && \
|
|
(( ${GroupDepths[${group}]} == 0 )); then
|
|
output+="module use ${group}; "
|
|
fi
|
|
output+="module load ${line[@]:3} ${line[0]}\n"
|
|
done < <(subcommand_search "${m}" -a --no-header 2>&1)
|
|
if [[ -n "${output}" ]]; then
|
|
std::info "\nTry with one of the following command(s):"
|
|
std::die 3 "${output}\n"
|
|
fi
|
|
}
|
|
|
|
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}"
|
|
}
|
|
|
|
local args=()
|
|
opts=()
|
|
while (($# > 0)); do
|
|
case $1 in
|
|
-H | --help )
|
|
print_help "${subcommand_load}"
|
|
;;
|
|
-f | --force )
|
|
opts+=(' -f')
|
|
;;
|
|
-s | --silent )
|
|
verbosity_lvl='silent'
|
|
;;
|
|
-v | --verbose )
|
|
verbosity_lvl='verbose'
|
|
;;
|
|
-w | --warn )
|
|
verbosity_lvl='warn'
|
|
;;
|
|
-- )
|
|
;;
|
|
* )
|
|
args+=( $1 )
|
|
;;
|
|
esac
|
|
shift
|
|
done
|
|
if (( ${#args[@]} == 0 )); then
|
|
std::die 2 "%s %s: %s\n" \
|
|
"${CMD}" "${subcommand}" \
|
|
"No module specified"
|
|
fi
|
|
for m in "${args[@]}"; do
|
|
if [[ "$m" =~ ":" ]]; then
|
|
|
|
# extendet module name is either
|
|
# - group:name or
|
|
# - group:name:release or
|
|
# - release:name or
|
|
# - release:group:name or
|
|
# - name:release
|
|
|
|
IFS=':'
|
|
local -a toks=($m)
|
|
IFS=${__IFS}
|
|
local group=''
|
|
local release=''
|
|
if is_group "${toks[0]}"; then
|
|
group=${toks[0]}
|
|
m=${toks[1]}
|
|
release=${toks[2]}
|
|
elif is_release "${toks[0]}"; then
|
|
release=${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]}
|
|
release=${toks[2]}
|
|
else
|
|
release=${toks[1]}
|
|
group=${toks[2]}
|
|
fi
|
|
fi
|
|
if [[ -n ${group} ]]; then
|
|
is_group "${group}" || \
|
|
std::die 3 "%s %s: %s -- %s\n" \
|
|
"${CMD}" "${subcommand}" \
|
|
"illegal group name" \
|
|
"${group}"
|
|
local -i depth=${GroupDepths[${group}]}
|
|
(( depth != 0 )) && \
|
|
std::die 3 "%s %s: %s -- %s\n" \
|
|
"${CMD}" "${subcommand}" \
|
|
"illegal group name" \
|
|
"${group}"
|
|
MODULEPATH="${PMODULES_ROOT}/${group}/"
|
|
MODULEPATH+="${PMODULES_MODULEFILES_DIR}"
|
|
modulepath=( ${MODULEPATH} )
|
|
fi
|
|
if [[ -n ${release} ]]; then
|
|
is_release "${release}" || \
|
|
std::die 3 "%s %s: %s -- %s\n" \
|
|
"${CMD}" "${subcommand}" \
|
|
"illegal release name"
|
|
"${release}"
|
|
std::append_path UsedReleases "${release}"
|
|
g_env_must_be_saved='yes'
|
|
fi
|
|
fi
|
|
local found=''
|
|
for flag in "${!UseFlags[@]}"; do
|
|
# :FIXME: this doesn't work if ${m} is a
|
|
# modulename without version
|
|
if is_available "${m}_${flag}"; then
|
|
m+="_${flag}"
|
|
found=':'
|
|
break
|
|
fi
|
|
done
|
|
if [[ ! "${found}" ]]; then
|
|
# no use-flags set
|
|
if is_available "${m}"; then
|
|
found=':'
|
|
fi
|
|
fi
|
|
if [[ ! "${found}" ]]; then
|
|
std::info "%s %s: module unavailable -- %s" \
|
|
"${CMD}" 'load' "${m}"
|
|
[[ ${verbosity_lvl} == 'verbose' ]] && output_load_hints
|
|
std::die 3 ""
|
|
fi
|
|
if [[ ${current_modulefile} =~ ${PMODULES_ROOT} ]] \
|
|
&& [[ ! ${m} =~ / ]]; then
|
|
m+="/${current_modulefile##*/}"
|
|
fi
|
|
if [[ ":${LOADEDMODULES}:" =~ ":${m}:" ]]; then
|
|
continue
|
|
fi
|
|
if [[ ${current_modulefile} =~ ${PMODULES_ROOT} ]]; then
|
|
# modulefile is in our hierarchy
|
|
# ${prefix} was set in is_available()!
|
|
test -r "${prefix}/.info" && cat "$_" 1>&2
|
|
test -r "${prefix}/.dependencies" && load_dependencies "$_"
|
|
fi
|
|
local tmpfile=$( "${mktemp}" /tmp/Pmodules.XXXXXX ) \
|
|
|| std::die 1 "Oops: unable to create tmp file!\n"
|
|
local output=$("${modulecmd}" 'bash' ${opts} 'load' \
|
|
"${current_modulefile}" 2> "${tmpfile}")
|
|
|
|
# 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 modules'
|
|
fi
|
|
std::die 3 "%s %s: %s -- %s\n" \
|
|
"${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' \
|
|
"${release} module has been loaded" \
|
|
"${m}")
|
|
if [[ ${verbosity_lvl} != silent ]] && \
|
|
[[ ${release} != 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}}"
|
|
done <<< "${MODULEPATH//:/$'\n'}"
|
|
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}"
|
|
;;
|
|
-- )
|
|
;;
|
|
* )
|
|
args+=( "$1" )
|
|
;;
|
|
esac
|
|
shift
|
|
done
|
|
if (( ${#args[@]} == 0 )); then
|
|
std::die 3 "%s %s: %s\n" \
|
|
"${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
|
|
}
|
|
|
|
##############################################################################
|
|
#
|
|
# 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 root name as modulefile2.
|
|
"
|
|
|
|
subcommand_swap() {
|
|
local -r subcommand='swap'
|
|
local args=()
|
|
while (( $# > 0 )); do
|
|
case $1 in
|
|
-H | --help )
|
|
print_help "${subcommand}"
|
|
;;
|
|
-- )
|
|
;;
|
|
* )
|
|
args+=( "$1" )
|
|
;;
|
|
esac
|
|
shift
|
|
done
|
|
if (( ${#args[@]} == 0 )); then
|
|
std::die 3 "%s %s: %s\n" \
|
|
"${CMD}" "${subcommand}" \
|
|
"missing argument"
|
|
elif (( ${#args[@]} > 2 )); then
|
|
std::die 3 "%s %s: %s\n" \
|
|
"${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}"
|
|
;;
|
|
-- )
|
|
;;
|
|
* )
|
|
args+=( "$1" )
|
|
;;
|
|
esac
|
|
shift
|
|
done
|
|
if (( ${#args[@]} == 0 )); then
|
|
std::die 3 "%s %s: %s\n" \
|
|
"${CMD}" "${subcommand}" \
|
|
"missing argument"
|
|
fi
|
|
|
|
local arg
|
|
for arg in "${args[@]}"; do
|
|
"${modulecmd}" "${Shell}" "${subcommand}" "${arg}"
|
|
done
|
|
}
|
|
|
|
#
|
|
# get all available modules in given directory.
|
|
# return list like
|
|
# modulename1 release1 modulename2 release2 ...
|
|
#
|
|
get_available_modules() {
|
|
local var="$1"
|
|
local -r module="$2"
|
|
local -r use_releases="${3:-${UsedReleases}}"
|
|
shift 3 # in the for loop below we use $@ to loop over the directories
|
|
|
|
local -a mods=()
|
|
local release
|
|
local dir=''
|
|
|
|
for dir in "$@"; do
|
|
test -d "${dir}" || continue
|
|
{
|
|
cd "${dir}"
|
|
while read mod; do
|
|
get_release release "${dir}/${mod}"
|
|
|
|
if [[ :${use_releases}: =~ :${release}: ]]; then
|
|
mods+=( "${mod}" ${release} "${dir}/${mod}")
|
|
fi
|
|
done < <(${find} -L * \( -type f -o -type l \) -not -name ".*" -ipath "${module}*")
|
|
}
|
|
done
|
|
std::upvar ${var} "${mods[@]}"
|
|
}
|
|
|
|
##############################################################################
|
|
#
|
|
# avail [-hlt] [<module-pattern>...]
|
|
#
|
|
Subcommands[avail]='avail'
|
|
Options[avail]='-l help -o Hahlmt -l all -l all-releases -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-releases
|
|
List all available modules independend of the release.
|
|
|
|
-t|--terse
|
|
Output in short format.
|
|
|
|
-l|--long
|
|
Output in long format.
|
|
|
|
-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=${dir/${PMODULES_ROOT}\/}
|
|
local caption=${caption/\/${PMODULES_MODULEFILES_DIR}/: }
|
|
local caption=${caption/: \//: }
|
|
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
|
|
for (( i=0; i<${#mods[@]}; i+=3 )); do
|
|
local mod=${mods[i]}
|
|
local release=${mods[i+1]}
|
|
case $release in
|
|
stable )
|
|
out=''
|
|
;;
|
|
* )
|
|
out="${release}"
|
|
;;
|
|
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
|
|
for (( i=0; i<${#mods[@]}; i+=3 )); do
|
|
local mod=${mods[i]}
|
|
local release=${mods[i+1]}
|
|
case $release in
|
|
stable )
|
|
out=''
|
|
;;
|
|
* )
|
|
out=${release}
|
|
;;
|
|
esac
|
|
printf "%-20s\t%s\n" "${mod}" "${out}" 1>&2
|
|
done
|
|
std::info ""
|
|
}
|
|
|
|
human_readable_output() {
|
|
output_header
|
|
|
|
local -i column=$cols
|
|
local -i colsize=16
|
|
for ((i=0; i<${#mods[@]}; i+=3 )); do
|
|
if [[ ${verbosity_lvl} == 'verbose' ]]; then
|
|
local release=${mods[i+1]}
|
|
case ${mods[i+1]} in
|
|
stable )
|
|
mod=${mods[i]}
|
|
;;
|
|
* )
|
|
mod="${mods[i]}(${release:0:1})"
|
|
;;
|
|
esac
|
|
else
|
|
mod=${mods[i]}
|
|
fi
|
|
local -i len=${#mod}
|
|
local -i span=$(( len / 16 + 1 ))
|
|
local -i colsize=$(( span * 16 ))
|
|
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_all_groups='no'
|
|
local opt_use_releases="${UsedReleases}"
|
|
while (($# > 0)); do
|
|
case $1 in
|
|
-H | --help )
|
|
print_help "${subcommand}"
|
|
;;
|
|
-a | --all )
|
|
opt_all_groups='yes'
|
|
opt_use_releases="${PMODULES_DEFINED_RELEASES}"
|
|
;;
|
|
--all-releases )
|
|
opt_use_releases="${PMODULES_DEFINED_RELEASES}"
|
|
;;
|
|
-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'
|
|
;;
|
|
-- | '' )
|
|
;;
|
|
* )
|
|
pattern+=( "$1" )
|
|
;;
|
|
esac
|
|
shift
|
|
done
|
|
if (( ${#pattern[@]} == 0 )); then
|
|
pattern+=( '' )
|
|
fi
|
|
IFS=':'
|
|
local -a modulepath=(${MODULEPATH})
|
|
IFS=${__IFS}
|
|
local string
|
|
for string in "${pattern[@]}"; do
|
|
for dir in "${modulepath[@]}"; do
|
|
get_available_modules \
|
|
mods \
|
|
"${string}" \
|
|
"${opt_use_releases}" \
|
|
"${dir}"
|
|
[[ ${#mods[@]} == 0 ]] && continue
|
|
${output_function}
|
|
done
|
|
done
|
|
}
|
|
|
|
#
|
|
# compute depth of modulefile directory.
|
|
#
|
|
# Args:
|
|
# $1: absolute path of a modulefile directory
|
|
#
|
|
compute_group_depth () {
|
|
local -r dir=$1
|
|
test -d "${dir}" || return 1
|
|
local group=${dir%/*}
|
|
local group=${group##*/}
|
|
[[ -n "${GroupDepths[${group}]}" ]] && return 0
|
|
local -i depth=$(${find} "${dir}" -depth \( -type f -o -type l \) \
|
|
-printf "%d" -quit 2>/dev/null)
|
|
(( depth-=2 ))
|
|
# if a group doesn't contain a modulefile, depth is negativ
|
|
# :FIXME: better solution?
|
|
(( depth < 0 )) && (( depth = 0 ))
|
|
GroupDepths[$group]=${depth}
|
|
g_env_must_be_saved='yes'
|
|
}
|
|
|
|
#
|
|
# (Re-)Scan available groups in given root and compute group depth's
|
|
#
|
|
# Args:
|
|
# $1: root of modulefile hierarchy
|
|
#
|
|
scan_groups () {
|
|
local -r root="$1"
|
|
local moduledir
|
|
for moduledir in ${root}/*/${PMODULES_MODULEFILES_DIR}; do
|
|
compute_group_depth "${moduledir}"
|
|
done
|
|
}
|
|
|
|
##############################################################################
|
|
#
|
|
# use [-a|--append|-p|--prepend] [directory|group|release...]
|
|
#
|
|
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...]
|
|
Without arguments this sub-command displays information about
|
|
the module search path, used families and releases. You can
|
|
use this sub-command to get a list of available families and
|
|
releases.
|
|
|
|
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.
|
|
"
|
|
|
|
subcommand_use() {
|
|
local -r subcommand='use'
|
|
IFS=':'
|
|
local -a modulepath=(${MODULEPATH})
|
|
IFS=${__IFS}
|
|
local add2path_func='std::append_path'
|
|
|
|
group_is_used() {
|
|
[[ :${UsedGroups}: =~ :$1: ]]
|
|
}
|
|
|
|
release_is_used() {
|
|
[[ ":${UsedReleases}:" =~ :$1: ]]
|
|
}
|
|
|
|
print_info() {
|
|
local f
|
|
local r
|
|
std::info "Used groups:"
|
|
for f in ${UsedGroups//:/ }; do
|
|
std::info "\t${f}"
|
|
done
|
|
std::info "\nUnused 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:"
|
|
for r in ${UsedReleases//:/ }; do
|
|
std::info "\t${r}"
|
|
done
|
|
std::info "\nUnused releases:"
|
|
for r in ${PMODULES_DEFINED_RELEASES//:/ }; do
|
|
if ! release_is_used $r; then
|
|
std::info "\t${r}"
|
|
fi
|
|
done
|
|
|
|
std::info "\nUsed flags:"
|
|
for flag in "${!UseFlags[@]}"; do
|
|
std::info "\t${flag}"
|
|
done
|
|
|
|
std::info "\nAdditonal directories in MODULEPATH:"
|
|
let n=0
|
|
for (( i=0; i<${#modulepath[@]}; i++)); do
|
|
if [[ ! ${modulepath[i]} =~ ${PMODULES_ROOT} ]]; then
|
|
std::info "\t${modulepath[i]}"
|
|
let n+=1
|
|
fi
|
|
done
|
|
if (( n == 0 )); then
|
|
std::info "\tnone"
|
|
fi
|
|
std::info ""
|
|
}
|
|
|
|
use () {
|
|
local arg=$1
|
|
|
|
if is_release "${arg}"; then
|
|
# argument is release
|
|
std::append_path UsedReleases "${arg}"
|
|
return
|
|
fi
|
|
if [[ "${arg}" =~ "flag=" ]]; then
|
|
# argument is flag
|
|
UseFlags["${arg/flag=}"]=1
|
|
return
|
|
fi
|
|
if [[ -z ${GroupDepths[${arg}]} ]] && [[ -d "${PMODULES_ROOT}/${arg}" ]]; then
|
|
scan_groups "${PMODULES_ROOT}"
|
|
fi
|
|
|
|
if [[ -n ${GroupDepths[${arg}]} ]] &&
|
|
(( ${GroupDepths[${arg}]} == 0 )); then
|
|
# argument is group in our root with depth 0
|
|
std::append_path UsedGroups "${arg}"
|
|
local dir="${PMODULES_ROOT}/${arg}/"
|
|
dir+="${PMODULES_MODULEFILES_DIR}"
|
|
${add2path_func} MODULEPATH "${dir}"
|
|
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\n" \
|
|
"${CMD}" "${subcommand}" \
|
|
"illegal group" \
|
|
"${arg}"
|
|
return
|
|
fi
|
|
# arg must be a directory!
|
|
if [[ ! -d ${arg} ]]; then
|
|
std::die 3 "%s %s: %s -- %s\n" \
|
|
"${CMD}" "${subcommand}" \
|
|
"illegal argument" \
|
|
"${arg}"
|
|
return
|
|
fi
|
|
|
|
dir="$(cd "${arg}" && pwd)"
|
|
if [[ ${dir} =~ ^${PMODULES_ROOT} ]]; then
|
|
# argument is somehing in our root
|
|
std::die 3 "%s %s: %s -- %s\n" \
|
|
"${CMD}" "${subcommand}" \
|
|
"illegal argument" \
|
|
"${arg}"
|
|
return
|
|
fi
|
|
# argument is a modulepath
|
|
${add2path_func} MODULEPATH "$(cd "${arg}" && pwd)"
|
|
}
|
|
|
|
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'
|
|
;;
|
|
-- )
|
|
;;
|
|
* )
|
|
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...
|
|
#
|
|
Subcommands[unuse]='unuse'
|
|
Options[unuse]='-o H -l help'
|
|
Help[unuse]='
|
|
unuse directory|group|release...
|
|
Remove the given directory, group or release from the search
|
|
path.
|
|
'
|
|
|
|
subcommand_unuse() {
|
|
local -r subcommand='unuse'
|
|
unuse() {
|
|
local arg=$1
|
|
|
|
if is_release "${arg}"; then
|
|
# argument is release
|
|
std::remove_path UsedReleases "${arg}"
|
|
return
|
|
fi
|
|
if [[ "${arg}" =~ "flag=" ]]; then
|
|
# argument is flag
|
|
unset UseFlags["${arg/flag=}"]
|
|
return
|
|
fi
|
|
if [[ -n ${GroupDepths[${arg}]} ]] &&
|
|
(( ${GroupDepths[${arg}]} == 0 )); then
|
|
# argument is group in our root with depth 0
|
|
local var="PMODULES_LOADED_${arg^^}"
|
|
if [[ -n "${!var}" ]]; then
|
|
std::die 3 "%s %s: %s -- %s\n" \
|
|
"${CMD}" "${subcommand}" \
|
|
"cannot remove group due to loaded modules" \
|
|
"${arg}"
|
|
fi
|
|
std::remove_path UsedGroups "${arg}"
|
|
local dir="${PMODULES_ROOT}/${arg}/"
|
|
dir+="${PMODULES_MODULEFILES_DIR}"
|
|
std::remove_path MODULEPATH "${dir}"
|
|
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\n" \
|
|
"${CMD}" "${subcommand}" \
|
|
"illegal group" \
|
|
"${arg}"
|
|
return
|
|
fi
|
|
# arg must be a directory!
|
|
if [[ ! -d ${arg} ]]; then
|
|
std::die 3 "%s %s: %s -- %s\n" \
|
|
"${CMD}" "${subcommand}" \
|
|
"illegal argument" \
|
|
"${arg}"
|
|
return
|
|
fi
|
|
|
|
dir="$(cd "${arg}" && pwd)"
|
|
if [[ ${dir} =~ ^${PMODULES_ROOT} ]]; then
|
|
# argument is somehing in our root
|
|
std::die 3 "%s %s: %s -- %s\n" \
|
|
"${CMD}" "${subcommand}" \
|
|
"illegal argument" \
|
|
"${arg}"
|
|
return
|
|
fi
|
|
# argument is a modulepath
|
|
std::remove_path MODULEPATH "${dir}"
|
|
|
|
}
|
|
|
|
local -a args=()
|
|
while (( $# > 0)); do
|
|
case "$1" in
|
|
-H | --help )
|
|
print_help "${subcommand}"
|
|
;;
|
|
-- )
|
|
;;
|
|
* )
|
|
args+=( "$1" )
|
|
;;
|
|
esac
|
|
shift
|
|
done
|
|
if (( ${#args[@]} == 0 )); then
|
|
std::die 3 "%s %s: %s\n" \
|
|
"${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' "$@"
|
|
}
|
|
|
|
reset_modulepath() {
|
|
MODULEPATH=''
|
|
local group
|
|
local root="${PMODULES_ROOT}"
|
|
for group in ${UsedGroups//:/ }; do
|
|
local dir="${root}/${group}/${PMODULES_MODULEFILES_DIR}"
|
|
[[ -d "${dir}" ]] && std::prepend_path MODULEPATH "${dir}"
|
|
done
|
|
}
|
|
|
|
reset_used_groups() {
|
|
UsedGroups=''
|
|
local group
|
|
for group in ${PMODULES_DEFAULT_GROUPS}; do
|
|
std::append_path UsedGroups "${group}"
|
|
done
|
|
g_env_must_be_saved='yes'
|
|
}
|
|
|
|
reset_used_releases() {
|
|
declare -g UsedReleases=''
|
|
for r in ${PMODULES_DEFAULT_RELEASES//:/ }; do
|
|
std::append_path UsedReleases "${r}"
|
|
done
|
|
g_env_must_be_saved='yes'
|
|
}
|
|
|
|
|
|
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() {
|
|
declare -gx LOADEDMODULES=''
|
|
declare -gx _LMFILES_=''
|
|
declare -gx UsedGroups=''
|
|
declare -gx MODULEPATH=''
|
|
|
|
declare -Ag GroupDepths='()'
|
|
declare -Ag UseFlags=()
|
|
reset_modulepath
|
|
reset_used_groups
|
|
reset_used_releases
|
|
init_manpath
|
|
export_env \
|
|
LOADEDMODULES \
|
|
_LMFILES_ \
|
|
MODULEPATH \
|
|
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}"
|
|
;;
|
|
-- )
|
|
;;
|
|
* )
|
|
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 tmpfile=$( "${mktemp}" /tmp/Pmodules.XXXXXX ) \
|
|
|| std::die 1 "Oops: unable to create tmp file!\n"
|
|
|
|
local output=$("${modulecmd}" 'bash' 'purge' 2> "${tmpfile}")
|
|
|
|
local error=$( < "${tmpfile}")
|
|
${rm} "${tmpfile}"
|
|
if [[ "${error}" =~ ":ERROR:" ]]; then
|
|
local s=${error%%$'\n'*}
|
|
local error_txt='failed'
|
|
std::die 3 "%s %s: %s" \
|
|
"${CMD}" "${subcommand}" \
|
|
"${error_txt}"
|
|
fi
|
|
if [[ "${Shell}" == "sh" ]]; then
|
|
# for sh-like shells just echo
|
|
echo "${output}"
|
|
else
|
|
# re-run with right shell
|
|
"${modulecmd}" "${Shell}" 'purge'
|
|
fi
|
|
eval "${output}"
|
|
if [[ -n "${error}" ]]; then
|
|
echo "${error}" 1>&2
|
|
fi
|
|
|
|
if [[ -n "${pmodule}" ]]; then
|
|
# reload a previously loaded Pmodule module
|
|
# stderr is redirected to /dev/null, otherwise
|
|
# we may get output like
|
|
# 'unstable module has been loaded'
|
|
subcommand_load "${pmodule}" 2> /dev/null
|
|
fi
|
|
reset_modulepath
|
|
|
|
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' )
|
|
;;
|
|
-- )
|
|
;;
|
|
* )
|
|
args+=( "$1" )
|
|
;;
|
|
esac
|
|
shift
|
|
done
|
|
if (( ${#args[@]} > 0 )); then
|
|
std::die 3 "%s %s: %s\n" \
|
|
"${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}"
|
|
;;
|
|
-- )
|
|
:
|
|
;;
|
|
* )
|
|
args+=( "$1" )
|
|
;;
|
|
esac
|
|
shift
|
|
done
|
|
if (( ${#args[@]} > 0 )); then
|
|
std::die 3 "%s %s: %s\n" \
|
|
"${CMD}" "${subcommand}" \
|
|
"no arguments allowed"
|
|
fi
|
|
pmodules_init
|
|
export_env LOADEDMODULES MODULEPATH _LMFILES_
|
|
}
|
|
|
|
##############################################################################
|
|
#
|
|
# search [switches] [STRING...]
|
|
#
|
|
Subcommands[search]='search'
|
|
Options[search]='-o aH -l help -l no-header -l print-modulefiles '
|
|
Options[search]+='-l release: -l with: -l all-releases -l src: -l print-csv '
|
|
Options[search]+='-l verbose '
|
|
Options[search]+='-l all-deps -l wrap'
|
|
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-releases
|
|
Search within all releases.
|
|
|
|
--all-deps
|
|
Show all dependecies
|
|
|
|
--no-header
|
|
Suppress output of a header.
|
|
|
|
--release=RELEASE
|
|
Search for modules within this release. You can specify this
|
|
switch multiple times. Without this switch, the used releases
|
|
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'
|
|
|
|
#.....................................................................
|
|
#
|
|
# 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" "Release" "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" "Release" "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_header_none'
|
|
}
|
|
|
|
print_header_none() {
|
|
:
|
|
}
|
|
|
|
print_line_modulefile() {
|
|
local line=( "$@" )
|
|
# group first
|
|
local out="${line[2]}/"
|
|
# add directory of modulefiles
|
|
out+="${PMODULES_MODULEFILES_DIR}/"
|
|
for d in "${line[@]:3}"; do
|
|
out+="$d/"
|
|
done
|
|
out+="${line[0]}"
|
|
std::info "${out}"
|
|
}
|
|
|
|
print_line_csv() {
|
|
:
|
|
}
|
|
|
|
print_csv() {
|
|
fmt=''
|
|
func_print_header='print_header_none'
|
|
func_print_line='print_line_csv'
|
|
}
|
|
|
|
local -r tmpfile=$1
|
|
|
|
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}" -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 () {
|
|
local -r module=$1
|
|
# write results to a temporary file for later processing
|
|
local -r tmpfile=$( "${mktemp}" /tmp/Pmodules.XXXXXX ) \
|
|
|| std::die 1 "Oops: unable to create tmp file!"
|
|
local group
|
|
# loop over all groups
|
|
for group in "${!GroupDepths[@]}"; do
|
|
# 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 releases
|
|
# tmpfile: module/version release group group-
|
|
# dependencies...
|
|
local mods
|
|
get_available_modules \
|
|
mods \
|
|
"${module}" \
|
|
"${opt_use_releases}" \
|
|
"${modulepath[@]}" \
|
|
|
|
for (( i=0; i<${#mods[@]}; i+=3 )); do
|
|
local name=${mods[i]}
|
|
local release=${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='/'
|
|
local toks=( ${modulefile} )
|
|
for ((j = -depth-2; j < -2; j += 2)); do
|
|
deps+=( "${toks[*]: $j:2}" );
|
|
done
|
|
IFS=${__IFS}
|
|
fi
|
|
|
|
echo ${name} ${release} ${group} ${modulefile} \
|
|
${deps[@]} >> "${tmpfile}"
|
|
done
|
|
done
|
|
print_result "${tmpfile}"
|
|
${rm} -f "${tmpfile}"
|
|
}
|
|
|
|
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 | --release=* )
|
|
if [[ "$1" == "--release" ]]; then
|
|
local arg=$2
|
|
shift
|
|
else
|
|
local arg=${1/--release=}
|
|
fi
|
|
is_release "${arg}" || \
|
|
std::die 1 "%s %s: %s -- %s" \
|
|
"${CMD}" 'search' \
|
|
"illegal release name" \
|
|
"${arg}"
|
|
opt_use_releases+="${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 )
|
|
opt_use_releases="${PMODULES_DEFINED_RELEASES}"
|
|
;;
|
|
--src )
|
|
# :FIXME: do we have to add some sanity checks here?
|
|
src_prefix=$2
|
|
shift
|
|
;;
|
|
-v | --verbose )
|
|
opt_print_verbose='yes'
|
|
;;
|
|
--wrap )
|
|
opt_wrap='yes'
|
|
;;
|
|
-- )
|
|
;;
|
|
* )
|
|
modules+=( "$1" )
|
|
;;
|
|
esac
|
|
shift
|
|
done
|
|
if [[ -z "${src_prefix}" ]]; then
|
|
src_prefix="${PMODULES_ROOT}"
|
|
fi
|
|
|
|
if [[ "${opt_use_releases}" == ":" ]]; then
|
|
opt_use_releases=":${UsedReleases}:"
|
|
fi
|
|
|
|
if [[ ${#modules[@]} == 0 ]]; then
|
|
modules+=( '' )
|
|
fi
|
|
|
|
# :FIXME: do we need this?
|
|
if (( ${#GroupDepths[@]} == 0 )) || \
|
|
[[ ${src_prefix} != ${PMODULES_ROOT} ]]; then
|
|
scan_groups "${src_prefix}"
|
|
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
|
|
|
|
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
|
|
-[hH] | --help )
|
|
print_help "${subcommand}"
|
|
;;
|
|
-V | --version )
|
|
print_help 'version'
|
|
;;
|
|
-- )
|
|
:
|
|
;;
|
|
* )
|
|
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 UsedReleases)
|
|
"${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
|
|
-h | --help )
|
|
print_help "${subcommand}"
|
|
;;
|
|
-- )
|
|
:
|
|
;;
|
|
* )
|
|
args+=( "$1" )
|
|
;;
|
|
esac
|
|
shift
|
|
done
|
|
if (( ${#args[@]} != 2 )); then
|
|
std::die 3 "%s %s: %s\n" \
|
|
"${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\n"
|
|
;;
|
|
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.\n"
|
|
fi
|
|
|
|
if [[ -z "${Subcommands[${subcommand}]}" ]]; then
|
|
std::die 1 "${CMD}: unknown sub-command -- ${subcommand}\n"
|
|
fi
|
|
|
|
if [[ -n ${PMODULES_ENV} ]]; then
|
|
eval "$("${base64}" -d <<< "${PMODULES_ENV}" 2>/dev/null)"
|
|
else
|
|
pmodules_init
|
|
fi
|
|
|
|
if (( ${#GroupDepths[@]} == 0 )); then
|
|
scan_groups "${PMODULES_ROOT}"
|
|
fi
|
|
|
|
declare options
|
|
options=$( "${getopt}" ${Options[${subcommand}]} -- -- "${opts[@]}" "$@" ) \
|
|
|| print_help "${subcommand}"
|
|
eval set -- ${options}
|
|
subcommand_${Subcommands[$subcommand]} "$@"
|
|
|
|
# Local Variables:
|
|
# mode: sh
|
|
# sh-basic-offset: 8
|
|
# tab-width: 8
|
|
# End:
|