merged upstream

This commit is contained in:
2022-08-17 10:21:51 +02:00
5 changed files with 634 additions and 416 deletions
+51 -7
View File
@@ -1,20 +1,60 @@
# Changelog of Pmodules
## Version 1.1.10
## Version 1.1.10 (not yet tagged)
* **modulecmd**
* *User visible changes*
* ...
* New options for `module search`.
* With the option `--group` the search can be restricted to a
group.
* With the option `--newest` only the newest versions are
displayed.
* `find` as alias for the sub-command `search` added.
* Bugfix: the sub-commands `whatis` and `keyword|apropos` were
broken by design.
* Bugfix: after loading a `Pmodules` module, it was not shown with
`module list`.
* Bugfix in scanning the depth of groups.
* Bugfix: after `module purge` the environment variable
`PMODULES_HOME` was not defined an more.
* Bugfix: source the shell init file only if a `Pmodules` module
is loaded.
* Bugfix: unsetting aliases in modulefiles was not handled
properly in `module purge`
* *Internal changes and fixes*
* ...
* initialisation error for bash and zsh fixed
* **build-system**
* *User visible changes*
* ...
* *Internal changes and fixes*
* ...
* `modbuild` is now defined as function like `module`. Therefor no
`Pmodules` module must be loaded to build a module with `modbuild`
* The system can now be defined in the module (YAML) configuration
file.
* Build dependencies can (and should) now be specified with
`build_requires` in the YAML configuration file.
* Bugfix: cleanup of modulefiles in overlays fixed. A module can be in
more than one overlay. These overlays must be specified in the
module configuration file.
* Bugfix: querying dependencies from YAML configuration file
fixed. Under some conditions the string 'null' was in the list
of dependencies.
* Bugfix: create group directory if it doesn't exist.
* Bugfix: create the module `$PREFIX` before processing the
install targets not before all targets. If `$PREFIX` is created
before processing any target and the build fails, `modbuild`
assumes that the module have been already built successfully.
* *Internal changes and fixes*
* code review/re-factoring
* `modbuild` is now using the Bash installed in `Pmodules` itself.
* test code with `set -o nounset`, several issues with this
setting fixed (not necessarily bugs).
* **other changes**
* ...
* The build script to bootstrap Pmodules itself doesn't use modbuild
any more to compile required software packages. With this change
we can remove some special cases from modbuild.
* The bootstrap script requires Bash 5.0 or newer now.
* Bugfix: in the `Pmodules` modulefile force the sourcing of the
shell init script while in mode `load` only.
## Version 1.1.9
* **modulecmd**
@@ -47,6 +87,10 @@
- to override the overlay in a YAML variants file.
* The new keyword `with` has been introduced in YAML variants file
to specified hierarchical dependencies.
* The function `pbuild::supported_os` has been
removed. `pbuild::supported_systems` provides the same
functionality for legacy configuration files. In YAML module
configuration files `systems` have to be used.
* **Internal changes and fixes**
* bugfix in setting `PATH`
+270 -213
View File
@@ -116,149 +116,26 @@ pbuild.verbose() {
readonly -f pbuild.verbose
###############################################################################
#******************************************************************************
#
# function in the "namespace" (with prefix) 'pbuild::' can be used in
# build-scripts
#
#..............................................................................
###############################################################################
#
# compare two version numbers
# general functions
#
# original implementation found on stackoverflow:
# https://stackoverflow.com/questions/4023830/how-to-compare-two-strings-in-dot-separated-version-format-in-bash
#
pbuild::version_compare () {
is_uint() {
[[ $1 =~ ^[0-9]+$ ]]
}
[[ $1 == $2 ]] && return 0
local IFS=.
local i ver1=($1) ver2=($2)
# fill empty fields in ver1 with zeros
for ((i=${#ver1[@]}; i<${#ver2[@]}; i++)); do
ver1[i]=0
done
for ((i=0; i<${#ver1[@]}; i++)); do
[[ -z ${ver2[i]} ]] && ver2[i]=0
if is_uint ${ver1[i]} && is_uint ${ver2[i]}; then
((10#${ver1[i]} > 10#${ver2[i]})) && return 1
((10#${ver1[i]} < 10#${ver2[i]})) && return 2
else
[[ ${ver1[i]} > ${ver2[i]} ]] && return 1
[[ ${ver1[i]} < ${ver2[i]} ]] && return 2
fi
done
return 0
}
readonly -f pbuild::version_compare
#..............................................................................
# version less than
#
# return 0 if version passed in $1 is older then $2
#
pbuild::version_lt() {
pbuild::version_compare "$1" "$2"
(( $? == 2 ))
}
readonly -f pbuild::version_lt
#..............................................................................
# version less than or equal
#
# return 0 if version passed in $1 is older or equal then $2
#
pbuild::version_le() {
pbuild::version_compare "$1" "$2"
local -i exit_code=$?
(( exit_code == 0 || exit_code == 2 ))
}
readonly -f pbuild::version_le
#..............................................................................
# version greater than
#
# return 0 if version passed in $1 is newer then $2
#
pbuild::version_gt() {
pbuild::version_compare "$1" "$2"
(( $? == 1 ))
local -i exit_code=$?
(( exit_code == 0 || exit_code == 1 ))
}
readonly -f pbuild::version_gt
#..............................................................................
# version greater than
#
# return 0 if version passed in $1 and $2 are equal
#
pbuild::version_eq() {
pbuild::version_compare "$1" "$2"
}
readonly -f pbuild::version_eq
##############################################################################
#
# Set flag to build module in source tree.
#
# Arguments:
# none
#
pbuild::compile_in_sourcetree() {
BUILD_DIR="${SRC_DIR}"
}
readonly -f pbuild::compile_in_sourcetree
##############################################################################
#
# Check whether the script is running on a supported OS.
#
# Arguments:
# $@: supported opertating systems (something like RHEL6, macOS10.14, ...).
# Default is all.
#
pbuild::supported_systems() {
SUPPORTED_SYSTEMS+=( "$@" )
}
readonly -f pbuild::supported_systems
##############################################################################
#
# Check whether the script is running on a supported OS.
#
# Arguments:
# $@: supported opertating systems (like Linux, Darwin).
# Default is all.
#
pbuild::supported_os() {
SUPPORTED_OS+=( "$@" )
}
readonly -f pbuild::supported_os
##############################################################################
#
# Check whether the loaded compiler is supported.
#
# Arguments:
# $@: supported compiler (like GCC, Intel, PGI).
# Default is all.
#
pbuild::supported_compilers() {
SUPPORTED_COMPILERS+=( "$@" )
}
readonly -f pbuild::supported_compilers
##############################################################################
#
# Install module in given group.
#
# Note:
# This function is deprecated with YAML module configuration files.
#
# Arguments:
# $1: group
# $1: group
#
pbuild::add_to_group() {
if (( $# == 0 )); then
@@ -266,23 +143,26 @@ pbuild::add_to_group() {
"%s " "${module_name}/${module_version}:" \
"${FUNCNAME}: missing group argument."
fi
GROUP="$1"
if (( $# > 1 )); then
std::die 42 \
"%s " "${module_name}/${module_version}:" \
"${FUNCNAME}: only one argument is allowed."
fi
if [[ ${yaml_config} == 'yes' ]]; then
std::info \
"Using ${FUNCNAME} is deprecated with YAML module configuration files."
fi
pbuild.add_to_group "$@"
}
readonly -f pbuild::add_to_group
##############################################################################
#
# Set documentation file to be installed.
#
# Arguments:
# $@: documentation files relative to source
#
pbuild::install_docfiles() {
MODULE_DOCFILES+=("$@")
declare -gx GROUP=''
pbuild.add_to_group(){
GROUP="$1"
}
readonly -f pbuild::install_docfiles
readonly -f pbuild.add_to_group
##############################################################################
#..............................................................................
#
# Test whether a module with the given name is available. If yes, return
# release
@@ -315,8 +195,155 @@ pbuild::module_is_avail() {
}
readonly -f pbuild::module_is_avail
#..............................................................................
#
# compare two version numbers
#
# pbuild::version_compare
# - returns 0 if the version numbers are equal
# - returns 1 if first version number is higher
# - returns 2 if second version number is higher
#
# pbuild::version_lt
# - returns 0 if second version number is higher
# pbuild::version_le
# - returns 0 if second version number is higher or equal
# pbuild::version_gt
# - returns 0 if first version number is higher
# pbuild::version_ge
# - returns 0 if first version number is higher or equal
# pbuild::version_eq
# - returns 0 if version numbers are equal
#
# otherwise a value != 0 is returned
#
# Arguments:
# $1 first version number
# $2 second version number
#
# Note:
# Original implementation found on stackoverflow:
# https://stackoverflow.com/questions/4023830/how-to-compare-two-strings-in-dot-separated-version-format-in-bash
#
pbuild::version_compare () {
is_uint() {
[[ $1 =~ ^[0-9]+$ ]]
}
[[ $1 == $2 ]] && return 0
local IFS=.
local i ver1=($1) ver2=($2)
# fill empty fields in ver1 with zeros
for ((i=${#ver1[@]}; i<${#ver2[@]}; i++)); do
ver1[i]=0
done
for ((i=0; i<${#ver1[@]}; i++)); do
[[ -z ${ver2[i]} ]] && ver2[i]=0
if is_uint ${ver1[i]} && is_uint ${ver2[i]}; then
((10#${ver1[i]} > 10#${ver2[i]})) && return 1
((10#${ver1[i]} < 10#${ver2[i]})) && return 2
else
[[ ${ver1[i]} > ${ver2[i]} ]] && return 1
[[ ${ver1[i]} < ${ver2[i]} ]] && return 2
fi
done
return 0
}
readonly -f pbuild::version_compare
pbuild::version_lt() {
pbuild::version_compare "$1" "$2"
(( $? == 2 ))
}
readonly -f pbuild::version_lt
pbuild::version_le() {
pbuild::version_compare "$1" "$2"
local -i exit_code=$?
(( exit_code == 0 || exit_code == 2 ))
}
readonly -f pbuild::version_le
pbuild::version_gt() {
pbuild::version_compare "$1" "$2"
(( $? == 1 ))
local -i exit_code=$?
(( exit_code == 1 ))
}
readonly -f pbuild::version_gt
pbuild::version_ge() {
pbuild::version_compare "$1" "$2"
(( $? == 1 ))
local -i exit_code=$?
(( exit_code == 0 || exit_code == 1 ))
}
readonly -f pbuild::version_gt
pbuild::version_eq() {
pbuild::version_compare "$1" "$2"
}
readonly -f pbuild::version_eq
#..............................................................................
#
# Check whether the loaded compiler is supported.
#
# Arguments:
# $@: supported compiler (like GCC, Intel, PGI).
# Default is all.
#
pbuild::supported_compilers() {
if [[ ${yaml_config} == 'yes' ]]; then
std::info \
"Using ${FUNCNAME} is deprecated with YAML module configuration files."
fi
pbuild.supported_compilers "$@"
}
readonly -f pbuild::supported_compilers
declare SUPPORTED_COMPILERS=()
pbuild.supported_compilers(){
SUPPORTED_COMPILERS+=( "$@" )
}
readonly -f pbuild.supported_compilers
#..............................................................................
#
# Check whether the script is running on a supported OS.
#
# Arguments:
# $@: supported opertating systems (something like RHEL6, macOS10.14, ...).
# Default is all.
#
pbuild::supported_systems() {
if [[ ${yaml_config} == 'yes' ]]; then
std::info \
"Using ${FUNCNAME} is deprecated with YAML module configuration files."
fi
pbuild.supported_systems "$@"
}
readonly -f pbuild::supported_systems
declare SUPPORTED_SYSTEMS=()
pbuild.supported_systems() {
SUPPORTED_SYSTEMS+=( "$@" )
}
#..............................................................................
#
pbuild::use_flag() {
[[ "${USE_FLAGS}" =~ ":${1}:" ]]
}
readonly -f pbuild::use_flag
##############################################################################
#
# functions to prepare the sources
#..............................................................................
#
# Set the download URL and name of downloaded file.
#
# Arguments:
@@ -333,7 +360,7 @@ pbuild::set_download_url() {
}
readonly -f pbuild::set_download_url
##############################################################################
#..............................................................................
#
# Set hash sum for file.
#
@@ -348,7 +375,7 @@ pbuild::set_sha256sum() {
}
readonly -f pbuild::set_sha256sum
##############################################################################
#..............................................................................
#
# Unpack file $1 in directory $2
#
@@ -361,23 +388,7 @@ pbuild::set_unpack_dir() {
}
readonly -f pbuild::set_unpack_dir
##############################################################################
#
# Use this C-compiler
#
# Arguments:
# $1 C-compiler to use.
#
pbuild::use_cc() {
[[ -x "$1" ]] || std::die 3 \
"%s " "${module_name}/${module_version}:" \
"Error in setting CC:" \
"'$1' is not an executable!"
CC="$1"
}
readonly -f pbuild::use_cc
###############################################################################
#..............................................................................
#
pbuild::add_patch() {
[[ -z "$1" ]] && \
@@ -393,7 +404,7 @@ pbuild::add_patch() {
}
readonly -f pbuild::add_patch
###############################################################################
#..............................................................................
#
pbuild::set_default_patch_strip() {
[[ -n "$1" ]] || \
@@ -405,35 +416,7 @@ pbuild::set_default_patch_strip() {
}
readonly -f pbuild::set_default_patch_strip
###############################################################################
#
pbuild::use_flag() {
[[ "${USE_FLAGS}" =~ ":${1}:" ]]
}
readonly -f pbuild::use_flag
###############################################################################
#
pbuild::add_configure_args() {
CONFIGURE_ARGS+=( "$@" )
}
readonly -f pbuild::add_configure_args
###############################################################################
#
pbuild::use_autotools() {
configure_with='autotools'
}
readonly -f pbuild::use_autotools
###############################################################################
#
pbuild::use_cmake() {
configure_with='cmake'
}
readonly -f pbuild::use_cmake
###############################################################################
#..............................................................................
#
# extract sources. For the time being only tar-files are supported.
#
@@ -595,6 +578,59 @@ pbuild::prep() {
###############################################################################
#
# functions to configure the sources
#..............................................................................
#
pbuild::add_configure_args() {
CONFIGURE_ARGS+=( "$@" )
}
readonly -f pbuild::add_configure_args
#..............................................................................
#
pbuild::use_autotools() {
configure_with='autotools'
}
readonly -f pbuild::use_autotools
#..............................................................................
#
pbuild::use_cmake() {
configure_with='cmake'
}
readonly -f pbuild::use_cmake
#..............................................................................
#
# Use this C-compiler
#
# Arguments:
# $1 C-compiler to use.
#
pbuild::use_cc() {
[[ -x "$1" ]] || std::die 3 \
"%s " "${module_name}/${module_version}:" \
"Error in setting CC:" \
"'$1' is not an executable!"
CC="$1"
}
readonly -f pbuild::use_cc
#..............................................................................
#
# Set flag to build module in source tree.
#
# Arguments:
# none
#
pbuild::compile_in_sourcetree() {
BUILD_DIR="${SRC_DIR}"
}
readonly -f pbuild::compile_in_sourcetree
#..............................................................................
#
# Configure the software to be compiled.
#
# Arguments:
@@ -648,7 +684,11 @@ pbuild::configure() {
}
###############################################################################
##############################################################################
#
# functions to compile the sources
#..............................................................................
#
# Default compile function.
#
@@ -663,7 +703,23 @@ pbuild::compile() {
"compilation failed!"
}
###############################################################################
##############################################################################
#
# functions to install everything
#..............................................................................
#
# Set documentation file to be installed.
#
# Arguments:
# $@: documentation files relative to source
#
pbuild::install_docfiles() {
MODULE_DOCFILES+=("$@")
}
readonly -f pbuild::install_docfiles
#..............................................................................
#
# Default install function.
#
@@ -677,7 +733,7 @@ pbuild::install() {
"compilation failed!"
}
###############################################################################
#..............................................................................
#
pbuild::install_shared_libs() {
local -r binary="$1"
@@ -720,9 +776,26 @@ pbuild::install_shared_libs() {
###############################################################################
#
# This is the main entry function called by modbuild!
# The following two functions are the entry points called by modbuild!
#
pbuild.build_module() {
declare yaml_config='yes'
pbuild.build_module_legacy(){
yaml_config='no'
_build_module "$@"
}
readonly -f pbuild.build_module_legacy
pbuild.build_module_yaml(){
_build_module "$@"
}
readonly -f pbuild.build_module_yaml
#..............................................................................
#
# The real worker function.
#
_build_module() {
declare -gx module_name="$1"
declare -gx module_version="$2"
declare -gx module_release="$3"
@@ -987,7 +1060,6 @@ pbuild.build_module() {
P="${module_name}"
V="${module_version}"
parse_version "${module_version}"
declare -gx GROUP=''
declare -g PREFIX=''
SOURCE_URLS=()
@@ -995,9 +1067,6 @@ pbuild.build_module() {
SOURCE_NAMES=()
declare -Ag SOURCE_UNPACK_DIRS=()
CONFIGURE_ARGS=()
SUPPORTED_SYSTEMS=()
SUPPORTED_OS=()
SUPPORTED_COMPILERS=()
PATCH_FILES=()
PATCH_STRIPS=()
PATCH_STRIP_DEFAULT='1'
@@ -1016,17 +1085,6 @@ pbuild.build_module() {
"Not available for ${system}."
}
#......................................................................
check_supported_os() {
(( ${#SUPPORTED_OS[@]} == 0 )) && return 0
for os in "${SUPPORTED_OS[@]}"; do
[[ ${os,,} == ${OS,,} ]] && return 0
done
std::die 1 \
"%s " "${module_name}/${module_version}:" \
"Not available for ${OS}."
}
#......................................................................
check_supported_compilers() {
(( ${#SUPPORTED_COMPILERS[@]} == 0 )) && return 0
@@ -1547,7 +1605,6 @@ pbuild.build_module() {
# check whether this module is supported
check_supported_systems
check_supported_os
check_supported_compilers
# setup module name and prefix
set_full_module_name_and_prefix
@@ -1583,7 +1640,7 @@ pbuild.build_module() {
cleanup_modulefiles
std::info "* * * * *\n"
}
readonly -f pbuild.build_module
readonly -f _build_module
# Local Variables:
# mode: sh
+20 -29
View File
@@ -436,7 +436,7 @@ build_modules_legacy() {
version="${tokens[0]#*/}"
release="${tokens[1]}"
with_modules=( "${tokens[@]:2}" )
pbuild.build_module \
pbuild.build_module_legacy \
"${name}" "${version}" \
"${release}" "${with_modules[@]}"
done
@@ -519,25 +519,25 @@ build_modules_yaml(){
local fname="$2"
local version="$3"
local idx="$4"
_result=$(${yq} -Ne e ".\"${version}\"[${idx}].systems" \
"${fname}" 2>/dev/null)
_result=( $(${yq} -Ne e ".\"${version}\"[${idx}].systems" \
"${fname}" 2>/dev/null) )
(( $? == 0 )) && return
_result=$(${yq} -Ne e ".systems" "${fname}" 2>/dev/null)
_result=( $(${yq} -Ne e ".systems" "${fname}" 2>/dev/null) )
(( $? == 0 )) && return
_result='any'
_result=()
}
yaml_get_operating_systems(){
yaml_get_compilers(){
local -n _result="$1"
local fname="$2"
local version="$3"
local idx="$4"
_result=$(${yq} -Ne e ".\"${version}\"[${idx}].operating_systems" \
"${fname}" 2>/dev/null)
_result=( $(${yq} -Ne e ".\"${version}\"[${idx}].compilers" \
"${fname}" 2>/dev/null) )
(( $? == 0 )) && return
_result=$(${yq} -Ne e ".operating_systems" "${fname}" 2>/dev/null)
_result=( $(${yq} -Ne e ".compilers" "${fname}" 2>/dev/null) )
(( $? == 0 )) && return
_result='any'
_result=()
}
yaml_get_dependencies(){
@@ -595,6 +595,7 @@ build_modules_yaml(){
local -a deps=()
local -a build_requires=()
local relstage
local group
local ol_name
for (( i=0; i<n_variants; i++)); do
if [[ -z ${opt_overlay} ]]; then
@@ -613,6 +614,8 @@ build_modules_yaml(){
yaml_get_relstage relstage "${fname}" "${v}" $i
yaml_get_dependencies deps "${fname}" "${v}" $i
yaml_get_build_requirements build_requires "${fname}" "${v}" $i
yaml_get_group group "${fname}" "${v}" $i
pbuild.add_to_group "${group}"
# :FIXME:
# for the time being we prefix the build requirements
# with 'b:' and append them to the other dependencies.
@@ -623,31 +626,20 @@ build_modules_yaml(){
declare ol_inst_root="${OverlayInfo[${ol_name}:inst_root]}"
declare ol_mod_root="${OverlayInfo[${ol_name}:mod_root]}"
local systems
local -a systems=()
local -a compilers=()
yaml_get_systems systems "${fname}" "${v}" $i
# build module if
# - systems is any
# - opt_system is listed in systems
local build_it='no'
if [[ "${systems}" == 'any' ]]; then
build_it='yes'
fi
if [[ ,${systems}, == *,${opt_system},* ]]; then
build_it='yes'
fi
if [[ ${build_it} == 'no' ]]; then
# we don't build, but we remember the overlay for
# cleaning up the modulefiles later.
continue
fi
yaml_get_compilers compilers "${fname}" "${v}" $i
pbuild.supported_systems "${systems[@]}"
pbuild.supported_compilers "${compilers[@]}"
if (( ${#deps[@]} > 0 )); then
while read -a with_modules; do
pbuild.build_module \
pbuild.build_module_yaml \
"${name}" "${v##*/}" \
"${relstage}" "${with_modules[@]}"
done < <(bash_expand "" ${deps[@]}|${awk} "${pattern}")
else
pbuild.build_module \
pbuild.build_module_yaml \
"${name}" "${v##*/}" \
"${relstage}"
fi
@@ -655,7 +647,6 @@ build_modules_yaml(){
done
}
build_modules() {
if [[ -n $(ls "${BUILDBLOCK_DIR}/files/${BNAME_VARIANTS}"*.yaml 2>/dev/null) ]]; then
build_modules_yaml "$@"
+290 -164
View File
@@ -15,12 +15,12 @@ unset IFS # use default IFS
shopt -s nullglob
# used in some output messages only
declare -r CMD='module'
declare -r CMD='module'
declare -r mydir=$(cd $(dirname "$0") && pwd)
declare prefix=$(dirname "${mydir}")
declare -r libdir="${prefix}/lib"
declare -r libexecdir="${prefix}/libexec"
declare -r mydir=$(cd $(dirname "$0") && pwd)
declare -- prefix=$(dirname "${mydir}")
declare -r libdir="${prefix}/lib"
declare -r libexecdir="${prefix}/libexec"
source "${libdir}/libstd.bash"
source "${libdir}/libpmodules.bash"
@@ -32,20 +32,16 @@ std::def_cmds "${path}" \
'awk' 'base64' 'find' 'getopt' 'logger' 'mktemp' \
'rm' 'sort' 'yq'
if [[ ${PMODULES_PURETCL} == yes ]]; then
declare -r modulecmd="${libexecdir}/modulecmd.tcl"
if [[ -n ${TCLLIBPATH} ]]; then
declare -x TCLLIBPATH="${PMODULES_HOME}/lib/Pmodules:${TCLLIBPATH}"
else
if [[ -n ${TCLLIBPATH} ]]; then
declare -x TCLLIBPATH="${PMODULES_HOME}/lib/Pmodules:${TCLLIBPATH}"
else
declare -x TCLLIBPATH="${PMODULES_HOME}/lib/Pmodules"
fi
declare -r modulecmd="${libexecdir}/modulecmd.bin"
declare -x TCLLIBPATH="${PMODULES_HOME}/lib/Pmodules"
fi
declare -r modulecmd="${libexecdir}/modulecmd.bin"
declare verbosity_lvl=${PMODULES_VERBOSITY:-'verbose'}
declare -- verbosity_lvl=${PMODULES_VERBOSITY:-'verbose'}
declare Shell=''
declare -- Shell=''
# the following settings are used if the config file doesn't exist
@@ -95,30 +91,31 @@ export_env() {
}
#
# Save/cache some variables.
# This function is called on exit via a trap handler.
# Save/cache state in the environment variable PMODULES_ENV. The content is
# base64 encoded. This function is called on exit via a trap handler.
#
# Args;
# Arguments:
# none
#
declare g_env_must_be_saved='no'
encode_base64(){
case "${os_name}" in
Linux )
"${base64}" --wrap=0 <<< "$1"
;;
Darwin )
# does not wrap if running in a script
"${base64}" <<< "$1"
;;
* )
std::die 255 "Oops: Unsupported OS"
;;
esac
}
save_env() {
encode_base64(){
case "${os_name}" in
Linux )
"${base64}" --wrap=0 <<< "$1"
;;
Darwin )
# does not wrap if running in a script
"${base64}" <<< "$1"
;;
* )
std::die 255 "Oops: Unsupported OS"
;;
esac
}
[[ $1 == 'no' ]] && return 0
local vars=( Version )
vars+=( UsedReleaseStages UsedFlags UsedGroups )
@@ -133,6 +130,9 @@ save_env() {
declare -gx PMODULES_ENV=$( encode_base64 "$s" )
}
#
# function called on exit
#
_exit() {
save_env "${g_env_must_be_saved}"
export_env 'PMODULES_ENV'
@@ -140,7 +140,6 @@ _exit() {
${rm} -f "${tmpfile}" || :
fi
}
trap '_exit' EXIT
#
@@ -179,6 +178,9 @@ get_release_stage() {
fi
}
#
# check whether the argument in $1 is a valid release stage.
#
is_release_stage() {
[[ :${ReleaseStages}: =~ :$1: ]]
}
@@ -188,9 +190,10 @@ is_release_stage() {
# If yes, return 0 and the overlay with upvar of first argument
# otherwise return 1
#
# $1 upvar to return overlay
# $2 upvar to return group
# $3 moduledir to check
# Arguments
# $1 upvar to return overlay
# $2 upvar to return group
# $3 moduledir to check
#
find_overlay () {
local "$1"
@@ -209,29 +212,52 @@ find_overlay () {
return 0
}
#
# Check whether the module passed in argument $1 is loaded.
#
module_is_loaded() {
[[ :${LOADEDMODULES}: =~ :$1: ]]
}
#
# check shebang
# $1: file name to test
# Check shebang.
#
# Arguments:
# $1 file name to test
#
is_modulefile() {
local -r fname="$1"
local shebang
local -- shebang
[[ -r ${fname} ]] || return 1
read -n 11 shebang < "${fname}"
[[ "${shebang:0:8}" == '#%Module' ]] || [[ "${shebang:0:9}" == '#%Pmodule' ]]
}
#
# Get the value of <module>_PREFIX.
#
# Arguments:
# $1 upvar to return result
# $2 modulefile
#
get_module_prefix() {
local "$1"
local modulefile="$2"
local -r _prefix=$("${modulecmd}" bash show "${modulefile}" 2>&1 | \
local -n _prefix="$1"
local -- _prefix=$("${modulecmd}" bash show "$2" 2>&1 | \
${awk} '/_PREFIX |_HOME / {print $3; exit}')
std::upvar $1 "${_prefix}"
}
#
# Generic wrappers of 'modulecmd':
#
# subcommand_generic0:
# no argument allowed
# subcommand_generic1:
# Exact one argument must be passed
# subcommand_generic1plus:
# One or more arguments must be passed
#
# The options to output help are always accepted.
#
subcommand_generic0() {
local -r subcommand="$1"
shift
@@ -754,7 +780,7 @@ subcommand_unload() {
local arg
for arg in "${args[@]}"; do
local output=$("${modulecmd}" "${Shell}" 'unload' "${arg}")
eval "$(echo "${output}"|sed -e 's/;unalias [^;]*//g')"
eval "$(echo "${output}"|${sed} -e 's/;unalias [^;]*//g')"
case ${Shell} in
sh | bash | zsh )
echo "${output}"
@@ -1496,20 +1522,21 @@ subcommand_use() {
if is_release_stage "${arg}"; then
# argument is release stage
std::append_path UsedReleaseStages "${arg}"
return
return $?
fi
if [[ "${arg}" =~ "flag=" ]]; then
# argument is flag
UsedFlags+=( "${arg/flag=}" )
return
return $?
fi
if [[ -v OverlayInfo[${arg}:type] ]]; then
use_overlay "${arg}"
return 0
return $?
fi
if [[ -d ${arg} ]]; then
local dir=$(cd "${arg}" && pwd -L)
${add2path_func} MODULEPATH "${dir}"
return $?
fi
if [[ ! -v GroupDepths[${arg}] ]]; then
# this scan is required if a new group has been
@@ -1519,7 +1546,7 @@ subcommand_use() {
fi
if [[ -n ${GroupDepths[${arg}]} ]]; then
use_group "${arg}"
return
return $?
fi
std::die 3 "%s %s: %s -- %s" \
@@ -1771,7 +1798,10 @@ subcommand_refresh() {
}
#
# help function, used during initialization and for purging all modules
# Helper functions, used during initialization and for purging all modules.
#
# Arguments:
# none
#
init_modulepath() {
declare -gx MODULEPATH=''
@@ -1922,8 +1952,8 @@ subcommand_purge() {
"${error_txt}"
fi
if [[ "${Shell}" == "sh" ]]; then
# for sh-like shells just echo
echo "${output}"
# for sh-like shells just echo
eval "$(echo "${output}"|${sed} -e 's/;unalias [^;]*//g')"
else
# re-run with right shell
"${modulecmd}" "${Shell}" 'purge'
@@ -2041,14 +2071,17 @@ subcommand_clear() {
# search [switches] [STRING...]
#
Subcommands[search]='search'
Subcommands[find]='search'
Options[search]='-o a\?H -l help -l no-header -l print-modulefiles '
Options[search]+='-l release-stage: -l with: -l all-release-stages -l src: -l print-csv '
Options[search]+='-l verbose '
Options[search]+='-l all-deps -l wrap '
Options[search]+='-l glob'
Options[search]+='-l glob '
Options[search]+='-l newest '
Options[search]+='-l group:'
Help[search]='
USAGE:
module search [switches] STRING...
module find|search [switches] STRING...
Search installed modules. If an argument is given, search
for modules whose name match the argument.
@@ -2088,6 +2121,7 @@ SWITCHES:
subcommand_search() {
local -r subcommand='search'
local modules=()
local groups=()
local with_modules='//'
local -ir cols=$(tput cols) # get number of columns of terminal
local -i max_len_modulename=0
@@ -2100,6 +2134,7 @@ subcommand_search() {
local opt_all_deps='no'
local opt_wrap='no'
local opt_glob='no'
local opt_newest='no'
#.....................................................................
#
@@ -2167,9 +2202,7 @@ subcommand_search() {
}
print_header_verbose() {
std::info ''
#std::info "${fmt}" "Module" "Rel.stage" "Group" "Overlay" "Dependencies/Modulefile"
#std::info '-%.0s' $(seq 1 ${cols})
:
}
print_line_verbose() {
@@ -2195,7 +2228,9 @@ subcommand_search() {
}
print_line_modulefile() {
std::info "$4"
if (( $# >= 4 )) && [[ -n $4 ]]; then
std::info "$1 $4"
fi
}
print_line_csv() {
@@ -2218,11 +2253,15 @@ subcommand_search() {
print_default
fi
local _script=''
if [[ ${opt_newest} == 'yes' ]]; then
_script='{} END{print}'
fi
${func_print_header}
while read -a toks; do
${func_print_line} "${toks[@]}"
done < <("${sort}" --version-sort -k 1,1 -k 6,6 -k 7,7 "${tmpfile}" | \
${awk} "${with_modules}")
${awk} "${with_modules} ${_script}")
}
#.....................................................................
@@ -2235,72 +2274,65 @@ subcommand_search() {
# :FIXME:
#
search () {
if [[ ${opt_glob} == 'yes' ]]; then
local -r module="$1"
else
local -r module="${1}*"
fi
local module="$1"
local group="$2"
# write results to a temporary file for later processing
local group
# loop over all groups
for group in "${!GroupDepths[@]}"; do
# loop over all directories which can be added to
# MODULEPATH inside current group
local depth=${GroupDepths[${group}]}
local s=''
if (( depth > 0 )); then
s=$(printf '/*%.0s' $(seq 1 ${depth}))
fi
local modulepath=( ${src_prefix[@]/%//${group}/modulefiles$s} )
# loop over all directories which can be added to
# MODULEPATH inside current group
local depth=${GroupDepths[${group}]}
local s=''
if (( depth > 0 )); then
s=$(printf '/*%.0s' $(seq 1 ${depth}))
fi
local modulepath=( ${src_prefix[@]/%//${group}/modulefiles$s} )
# get and print all available modules in $mpath
# with respect to the requested release stage
# tmpfile: module/version rel_stage group dependencies...
local mods
get_available_modules \
mods \
"${module}" \
"${opt_use_rel_stages}" \
"${modulepath[@]}"
local i=0
for (( i=0; i<${#mods[@]}; i+=4 )); do
local name=${mods[i]}
local rel_stage=${mods[i+1]}
local modulefile=${mods[i+2]}
local ol=${mods[i+3]}
# get and print all available modules in $mpath
# with respect to the requested release stage
# tmpfile: module/version rel_stage group dependencies...
local mods
get_available_modules \
mods \
"${module}" \
"${opt_use_rel_stages}" \
"${modulepath[@]}" \
for (( i=0; i<${#mods[@]}; i+=4 )); do
local name=${mods[i]}
local rel_stage=${mods[i+1]}
local modulefile=${mods[i+2]}
local ol=${mods[i+3]}
if (( ${#name} > max_len_modulename)); then
max_len_modulename=${#name}
fi
if [[ "${opt_print_verbose}" == 'yes' ]] || [[ "${opt_all_deps}" == 'yes' ]]; then
local prefix=''
get_module_prefix prefix "${modulefile}"
local dependencies_file="${prefix}/.dependencies"
if [[ -n ${prefix} ]] && [[ -r "${dependencies_file}" ]]; then
deps=($(< "${dependencies_file}"))
else
deps=()
fi
if (( ${#name} > max_len_modulename)); then
max_len_modulename=${#name}
fi
if [[ "${opt_print_verbose}" == 'yes' ]] || \
[[ "${opt_all_deps}" == 'yes' ]]; then
local prefix=''
get_module_prefix prefix "${modulefile}"
local dependencies_file="${prefix}/.dependencies"
if [[ -n ${prefix} ]] && [[ -r "${dependencies_file}" ]]; then
deps=($(< "${dependencies_file}"))
else
# get dependencies encoded in directory name
local deps=()
local -i j
IFS='/' # note: IFS is used to concat in the for loop!
local toks=( ${modulefile} )
for ((j = -depth-2; j < -2; j += 2)); do
deps+=( "${toks[*]: $j:2}" );
done
unset IFS
deps=()
fi
echo ${name} ${rel_stage} ${group} ${modulefile} \
${ol} \
${deps[@]} >> "${tmpfile}"
done
else
# get dependencies encoded in directory name
local deps=()
local -i j
IFS='/' # note: IFS is used to concat in the for loop!
local toks=( ${modulefile} )
for ((j = -depth-2; j < -2; j += 2)); do
deps+=( "${toks[*]: $j:2}" );
done
unset IFS
fi
echo ${name} ${rel_stage} ${group} ${modulefile} \
${ol} \
${deps[@]} >> "${tmpfile}"
done
print_result
}
while (( $# > 0 )); do
@@ -2388,6 +2420,18 @@ subcommand_search() {
--glob )
opt_glob='yes'
;;
--newest )
opt_newest='yes'
;;
--group | --group=* )
if [[ $1 == *=* ]]; then
groups+=( ${1/--*=} )
else
groups+=( $2 )
shift
fi
;;
-- )
shift 1
modules+=( "$@" )
@@ -2422,8 +2466,19 @@ subcommand_search() {
fi
local module
if (( ${#groups[@]} == 0 )); then
groups=( "${!GroupDepths[@]}" )
fi
for module in "${modules[@]}"; do
search "${module}"
if [[ ${opt_glob} != 'yes' ]]; then
module+="*"
fi
local group
for group in "${groups[@]}"; do
search "${module}" "${group}"
done
print_result
echo -n > ${tmpfile}
done
}
@@ -2508,7 +2563,7 @@ subcommand_help() {
# whatis
#
Subcommands[whatis]='whatis'
Options[whatis]='-o \?H -l help'
Options[whatis]='-o \?Ha -l help -l all'
Help[whatis]='
USAGE:
module whatis [modulefile...]
@@ -2518,11 +2573,46 @@ USAGE:
'
subcommand_whatis() {
if (( $# == 0 )); then
subcommand_generic0 'whatis'
else
subcommand_generic1plus 'whatis' "$@"
fi
local options=()
local args=()
while (( $# > 0 )); do
case $1 in
-\? | --help )
print_help "${subcommand}"
;;
-a | --all )
options+=( '-a' )
;;
-- )
shift 1
args+=( "$@" )
break
;;
* )
args+=( "$1" )
;;
esac
shift
done
local group=''
for group in "${!GroupDepths[@]}"; do
local mod_name=''
local file_name=''
while read mod_name file_name; do
[[ -n ${file_name} ]] || continue
local whatis=$("${modulecmd}" bash \
whatis \
"${file_name}" \
2>&1 1>/dev/null)
printf "%-25s: %s\n" "${mod_name}" "${whatis/*:}" 1>&2
done < <(set +x; subcommand_search \
--group "${group}" \
--print-modulefiles \
--newest \
"${options[@]}" \
"${args[@]}" 2>&1)
done
}
##############################################################################
@@ -2531,7 +2621,7 @@ subcommand_whatis() {
#
Subcommands[apropos]='apropos'
Subcommands[keyword]='apropos'
Options[apropos]='-o \?H -l help'
Options[apropos]='-o \?Ha -l help -l all'
Help[apropos]='
USAGE:
module apropos string
@@ -2541,7 +2631,55 @@ USAGE:
'
subcommand_apropos() {
subcommand_generic1 'apropos' "$@"
local options=()
local args=()
while (( $# > 0 )); do
case $1 in
-\? | --help )
print_help "${subcommand}"
;;
-a | --all )
options+=( '-a' )
;;
-- )
shift 1
args+=( "$@" )
break
;;
* )
args+=( "$1" )
;;
esac
shift
done
if (( ${#args[@]} == 0 )); then
std::die 3 "%s %s: %s" \
"${CMD}" "${subcommand}" \
"no search string specified"
elif (( ${#args[@]} > 1 )); then
std::die 3 "%s %s: %s" \
"${CMD}" "${subcommand}" \
"more then one search string specified"
fi
local arg="${args[0]}"
local group=''
for group in "${!GroupDepths[@]}"; do
local mod_name=''
local file_name=''
while read mod_name file_name; do
[[ -n ${file_name} ]] || continue
local whatis=$("${modulecmd}" bash \
whatis \
"${file_name}" \
2>&1 1>/dev/null)
if [[ ${whatis,,} =~ ${arg,,} ]]; then
printf "%-25s: %s\n" "${mod_name}" "${whatis/*:}" 1>&2
fi
done < <(set +x; subcommand_search \
--group "${group}" \
--print-modulefiles \
"${options[@]}" 2>&1)
done
}
##############################################################################
@@ -2691,6 +2829,11 @@ subcommand_initclear() {
#
# main
#
# parse arguments
#
# first argument must be a shell!
case "$1" in
sh | bash | zsh )
declare Shell="sh"
@@ -2704,6 +2847,7 @@ case "$1" in
esac
shift
# parse agruments till and including the sub-command
declare -a opts=()
while (( $# > 0 )); do
case $1 in
@@ -2738,38 +2882,25 @@ if [[ -z "${Subcommands[${subcommand}]}" ]]; then
std::die 1 "${CMD}: unknown sub-command -- ${subcommand}"
fi
case ${subcommand} in
add )
subcommand='load'
;;
display )
subcommand='show'
;;
keyword )
subcommand='apropos'
;;
rm )
subcommand='unload'
;;
switch )
subcommand='swap'
;;
esac
# restore variables from last call
unset Version
if [[ -n ${PMODULES_ENV} ]]; then
eval "$("${base64}" -d <<< "${PMODULES_ENV}" 2>/dev/null)"
fi
# Version should now be defined again, if not:
# - PMODULES_ENV was not set
# - Version was not defined the last time the status was saved.
# This is true for older Pmodules versions.
# We (re-)initialise the Pmodules system, if
# - PMODULES_ENV was not set/is empty
# - A new Pmodules version has been loaded
if [[ -z ${Version} ]] || [[ ${Version} != ${PMODULES_VERSION} ]]; then
# this can only happen if the last command was
# module load Pmodules/${PMODULES_VERSION}
#
# the values these two variables must be saved before initialising
declare _tmp_loaded_modules_="${LOADEDMODULES}"
declare _tmp_lmfiles_="${_LMFILES_}"
pmodules_init
# restore and export
LOADEDMODULES="${_tmp_loaded_modules_}"
_LMFILES_="${_tmp_lmfiles_}"
export_env \
@@ -2777,13 +2908,10 @@ if [[ -z ${Version} ]] || [[ ${Version} != ${PMODULES_VERSION} ]]; then
_LMFILES_
fi
if (( ${#GroupDepths[@]} == 0 )); then
scan_groups "${UsedOverlays[@]}"
g_env_must_be_saved='yes'
fi
# We need a tmp-file in the following sub-commands. It will be removed
# in the exit function if exists.
case ${subcommand} in
load|purge|search|swap )
load|purge|search|swap|whatis|apropos )
declare -r tmpfile=$( ${mktemp} /tmp/Pmodules.XXXXXX ) \
|| std::die 1 "Oops: unable to create tmp file!"
;;
@@ -2792,12 +2920,10 @@ case ${subcommand} in
;;
esac
tmp=$("${getopt}" --name="${CMD}" ${Options[${subcommand}]} -- "${opts[@]}" "$@" ) \
|| print_help "${subcommand}"
eval args=( "$tmp" )
unset tmp
subcommand_${Subcommands[$subcommand]} "${args[@]}"
# parse arguments of the sub-command and call it
set -- $("${getopt}" --unquoted --name="${CMD}" ${Options[${subcommand}]} -- "${opts[@]}" "$@" ) \
|| print_help "${subcommand}"
subcommand_${Subcommands[$subcommand]} $@
# Local Variables:
# mode: sh
+3 -3
View File
@@ -7,9 +7,9 @@
##### no changes below this line ######
export PMODULES_VERSION
declare __pm_root__=${(%):-%N}
declare -x PMODULES_HOME="${__pm_root__:h:h}/Tools/Pmodules/${PMODULES_VERSION}"
unset __pm_root__
declare __this_file__=${(%):-%N}
declare -x PMODULES_HOME="${__this_file____:h:h}/Tools/Pmodules/${PMODULES_VERSION}"
unset __this_file__
test -r "${PMODULES_HOME}/init/zsh" && source "$_"