#!@BASH@ --noprofile # unset CDPATH # unset CDPATH, otherwise 'cd' prints the directoy! unset IFS # use default IFS shopt -s nullglob # 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" 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' declare -rx TCL_LIBRARY="${PMODULES_HOME}/lib/tcl@TCL_VERSION@" declare -rx TCLLIBPATH="${PMODULES_HOME}/lib/Pmodules" declare -r modulecmd="${libexecdir}/modulecmd.bin" 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}\n" ;; 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 ) 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 release stage of module # Note: # - the release stage of a modulefile outside ${PMODULES_ROOT} is 'stable' # - the release stage of a modulefile inside ${PMODULES_ROOT} without a # coresponding file is 'unstable' # # Args: # $1: absolute modulefile name # get_release_stage() { 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 rel_stage_file="${modulefile%/*}/.release-${modulefile##*/}" if [[ -r ${rel_stage_file} ]]; then # read file, remove empty lines, spaces etc local -r data=$( < "${rel_stage_file}" ) std::upvar $1 "${data}" else std::upvar $1 'unstable' fi return 0 } is_release_stage() { [[ ${ReleaseStages} =~ :$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}" g_env_must_be_saved='yes' } # # 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\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}" ;; -- ) shift 1 args+=( "$@" ) break ;; * ) 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}" ;; -- ) shift 1 args+=( "$@" ) break ;; * ) 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] # # $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='' IFS=':' local -a modulepath=(${MODULEPATH}) unset 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 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 output_load_hints() { local output='' local rel_stage='' while read -a line; do 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 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}" ;; -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\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: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\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 ${rel_stage} ]]; then is_release_stage "${rel_stage}" || \ std::die 3 "%s %s: %s -- %s\n" \ "${CMD}" "${subcommand}" \ "illegal release stage" "${rel_stage}" std::append_path UsedReleaseStages "${rel_stage}" g_env_must_be_saved='yes' fi fi local found='' for flag in "${UsedFlags[@]/#/_}" ''; do # :FIXME: this doesn't work if ${m} is a # modulename without version if is_available "${m}"; then m+="${flag}" found=':' break fi done 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 # the module is in our hierarchy but no version # has been specified. We take the version from # current_modulefile and append it m+="/${current_modulefile##*/}" 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 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 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='' if [[ ${verbosity_lvl} != silent ]] && \ [[ ${rel_stage} != stable ]]; then msg=$(printf "%s %s: %s -- %s" \ "${CMD}" 'load' \ "${rel_stage} module has been loaded" \ "${m}") std::info "%s" "${msg}" fi msg=$(printf "%s: %s %s %s" \ 'load' \ "modulefile=${current_modulefile}" \ "rel-stage=${rel_stage}" \ "user=${USER}") ${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}" ;; -- ) shift 1 args+=( "$@" ) break ;; * ) 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 "$(echo "${output}"|sed -e 's/;unalias [^;]*//g')" 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' } ############################################################################## # # swap [] # 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}" ;; -- ) shift 1 args+=( "$@" ) break ;; * ) 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 # 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\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 # modulename_1 rel_stage_1 modulefile_1 modulename_2 rel_stage_2 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 dir='' for dir in "$@"; do test -d "${dir}" || continue { cd "${dir}" while read mod; do get_release_stage rel_stage "${dir}/${mod}" if [[ :${used_rel_stages}: =~ :${rel_stage}: ]]; then mods+=( "${mod}" ${rel_stage} "${dir}/${mod}") fi done < <(${find} -L * \ \( -type f -o -type l \) -not -name ".*" \ -ipath "${module}" \ | ${sort} --version-sort) } done std::upvar ${var} "${mods[@]}" } ############################################################################## # # avail [-hlt] [...] # 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= Output modules available in -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 string for string in "${pattern[@]}"; do for dir in "${modulepath[@]}"; do if [[ ${dir} =~ ${PMODULES_ROOT} ]]; then local group="${dir/${PMODULES_ROOT}\/}" group="${group%%/*}" else local group="${dir}" fi if (( ${#opt_groups[@]} > 0 )) && [[ ! -v opt_groups[${group}] ]]; then continue fi get_available_modules \ mods \ "${string}*" \ "${opt_use_rel_stages}" \ "${dir}" [[ ${#mods[@]} == 0 ]] && continue ${output_function} "${group}" done done } ############################################################################## # # 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. " 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 "\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 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 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_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 [[ -z ${GroupDepths[${arg}]} ]] && [[ -d "${PMODULES_ROOT}/${arg}" ]]; then scan_groups "${PMODULES_ROOT}" g_env_must_be_saved='yes' 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' ;; -- ) 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' unuse() { 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 [[ -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}" ;; -- ) shift 1 args+=( "$@" ) break ;; * ) 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 g_env_must_be_saved='yes' } 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_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}" reset_used_groups reset_modulepath 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}" ;; -- ) 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 "$(echo "${output}"|sed -e 's/;unalias [^;]*//g')" 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\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}" ;; -- ) shift 1 args+=( "$@" ) break ;; * ) 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 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 "$1 $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='/' 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 "${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-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 src_prefix="${PMODULES_ROOT}" 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 \?Ha -l help -l all' 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() { local options=() local args=() while (( $# > 0 )); do case $1 in -\? | --help ) print_help "${subcommand}" ;; -a | --all ) options+=( '-a' ) ;; -- ) shift 1 args+=( "$@" ) break ;; * ) args+=( "$1" ) ;; esac shift done local mod_name='' local file_name='' while read mod_name file_name; do [[ -n ${file_name} ]] || continue local whatis=$("${modulecmd}" bash \ whatis \ "${file_name}" \ 2>&1 1>/dev/null) printf "%-25s: %s\n" "${mod_name}" "${whatis/*:}" 1>&2 done < <(set +x; subcommand_search \ --print-modulefiles \ "${options[@]}" \ "${args[@]}" 2>&1) } ############################################################################## # # apropos # Subcommands[apropos]='apropos' Subcommands[keyword]='apropos' Options[apropos]='-o \?Ha -l help -l all' 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() { local options=() local args=() while (( $# > 0 )); do case $1 in -\? | --help ) print_help "${subcommand}" ;; -a | --all ) options+=( '-a' ) ;; -- ) shift 1 args+=( "$@" ) break ;; * ) args+=( "$1" ) ;; esac shift done if (( ${#args[@]} == 0 )); then std::die 3 "%s %s: %s" \ "${CMD}" "${subcommand}" \ "no search string specified" elif (( ${#args[@]} > 1 )); then std::die 3 "%s %s: %s" \ "${CMD}" "${subcommand}" \ "more then one search string specified" fi local arg="${args[0]}" local mod_name='' local file_name='' while read mod_name file_name; do [[ -n ${file_name} ]] || continue local whatis=$("${modulecmd}" bash \ whatis \ "${file_name}" \ 2>&1 1>/dev/null) whatis="${whatis/*:}" if [[ ${whatis,,} =~ ${arg,,} ]]; then printf "%-25s: %s\n" "${mod_name}" "${whatis/*:}" 1>&2 fi done < <(set +x; subcommand_search \ --print-modulefiles \ "${options[@]}" 2>&1) } ############################################################################## # # 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\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 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}" # 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 fi if (( ${#GroupDepths[@]} == 0 )); then scan_groups "${PMODULES_ROOT}" g_env_must_be_saved='yes' fi case ${subcommand} in load|purge|search|swap|whatis|apropos ) 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: