#!@PMODULES_HOME@/bin/bash shopt -s expand_aliases declare -r bindir=$(cd $(dirname "$0") && pwd) declare -r libdir=$(cd "${bindir}/../lib" && pwd) source "${libdir}/libpmodules.bash" print_version() { echo " Pmodules ${version} using Tcl Environment Modules @MODULES_VERSION@ Copyright GNU GPL v2 " 1>&2 } usage() { local -r prog=$(basename $0) print_version echo " Usage: ${prog} [ switches ] [ subcommand ] [subcommand-args ] Switches: --dry-run do nothing --force force overwrite Available SubCommands and Args: init [--src=] [--user=] Initialize a new minimal Pmodule environment. install [--with=...] Install matching modules " } declare force='no' declare dry_run='no' declare DRY='' declare subcommand='' declare sargs=() subcommand_help_init() { echo " init [--src=] [--user=] Initialize a new minimal Pmodule environment in directory . The parameter must only be present if ${prog} is executed as root. " 1>&2 } subcommand_help_install() { echo " install ... [--with=...] [--release=...] [--src=] Install matching modules " 1>&2 } subcommand_help() { if [[ $# == 0 ]]; then usage elif typeset -F subcommand_help_$1 > /dev/null 2>&1 ; then # help for sub-command subcommand_help_$1 else usage fi } # # Derive the relative module installation path # from the relative modulefile path # # $1: relative module file path # get_module_prefix() { local -a comp=( ${1//\// } ) # split rel.path into components local path="${comp[0]}" # result path local -i i for ((i=1; i<${#comp[@]}; i+=2)); do path+="/${comp[$((-i-1))]}/${comp[$((-i))]}" done echo "${path}" } # # Derive the relative module release file path # from the relative module file path # # $1: relative module file path # get_releasefile_name() { echo "$(dirname "$1")/.release-$(basename "$1")" } # # Sync a module from one Pmodules environment to another: # - sync module installation # - sync modulefile # - sync release file # # $1: relative modulefile path # $2: source prefix of Pmodule environment # $3: target prefix of Pmodule environment # sync_module() { local -r rel_modulefile=$1 local -r src_prefix=$2 local -r target_prefix=$3 local -r rel_module_prefix=$( get_module_prefix "${rel_modulefile}" ) local -r rel_releasefile=$( get_releasefile_name "${rel_modulefile}" ) if [[ ! -d "${target_prefix}/${rel_module_prefix}" ]] || [[ "${force}" == 'yes' ]]; then $DRY mkdir -p "${target_prefix}/${rel_module_prefix}" || return $? $DRY rsync --links --perms --recursive --delete \ "${src_prefix}/${rel_module_prefix}/" \ "${target_prefix}/${rel_module_prefix}/" || return $? fi local -r src_modulefile="${src_prefix}/${PSI_MODULES_ROOT}/${rel_modulefile}" local -r src_releasefile="${src_prefix}/${PSI_MODULES_ROOT}/${rel_releasefile}" local -r target_modulefile="${target_prefix}/${PSI_MODULES_ROOT}/${rel_modulefile}" local -r target_releasefile="${target_prefix}/${PSI_MODULES_ROOT}/${rel_releasefile}" if [[ -e "${src_modulefile}" ]] || [[ -e "${src_releasefile}" ]]; then local dir=$( dirname "${target_modulefile}" ) $DRY mkdir -p "${dir}" || return $? fi if [[ -e "${src_modulefile}" ]]; then $DRY rsync --links --perms --recursive \ "${src_modulefile}" "${target_modulefile}" || return $? fi if [[ -e "${src_releasefile}" ]]; then $DRY rsync --links --perms --recursive \ "${src_releasefile}" "${target_releasefile}" || return $? fi } subcommand_init() { local src='' local target_prefixes=() local user='' local opts='' opts=$(get_options -o h -l src: -l user: -l help -- "$@") if [[ $? != 0 ]]; then subcommand_help_init exit 1 fi eval set -- "${opts}" while (($# > 0)); do case $1 in --src ) src=$2 shift ;; --user ) user=$2 shift ;; -- ) : ;; -* | -h | --help ) echo "$1: illegal option" 1>&2 subcommand_help_init exit 1 ;; * ) target_prefixes+=( "$1" ) ;; esac shift done (( ${#target_prefixes[@]} != 0 )) || die 1 "Error: no target directory specified!" if [[ -n "${src}" ]]; then [[ -d "${src}" ]] || die 1 "Error: ${src}: source directory does not exist!" [[ -r "${src}/config/profile.bash" ]] || \ die 1 "Error: ${src}: shell profile does not exist or is not readable!" source "${src}/config/profile.bash" fi local -i euid=$(id -u) if (( euid == 0 )); then [[ -n "${user}" ]] || \ die 1 "Error: --user parameter is required!" id -u "${user}" > /dev/null 2>&1 || \ die 1 "Error: Unable to retrieve user id of user '${user}'" else [[ -z "${user}" ]] || \ die 1 "Error: --user option is only allowed if running as root!" fi check_pmodules_env || die 1 "Giving up ..." echo " Attempting to create a minimal module environment from the environment at '${PSI_PREFIX}' " init_pmodules_environment() { local -r src_prefix="${PSI_PREFIX}" local -r target_prefix=$1 local src='' local dst='' echo "Initializing target directory '${target_prefix}' ..." echo if [[ -d "${target_prefix}" ]] && [[ ${force} == no ]]; then echo "Warning: ${target_prefix} already exists." get_YN_answer "Do you really want to re-run the initialization? (y/N) " || \ die 1 "Abort ..." fi echo "Creating target directory '${target_prefix}'..." $DRY mkdir -p "${target_prefix}" || die 1 "Error: make directory failed!" echo src="${src_prefix}/${PSI_CONFIG_DIR}/" dst="${target_prefix}/${PSI_CONFIG_DIR}/" echo "Synching configuration from '${src}' to '${dst}'..." $DRY rsync --recursive --links --perms --delete \ "${src}" "${dst}" || die 1 "Error: synch operation failed!" echo src="${src_prefix}/${PSI_TEMPLATES_DIR}/" dst="${target_prefix}/${PSI_TEMPLATES_DIR}/" echo "Synching template files from '${src}' to '${dst}'..." $DRY rsync --recursive --links --perms --delete \ "${src}" "${dst}" || die 1 "Error: synch operation failed!" echo dst="${target_prefix}/${PSI_MODULES_ROOT}/" echo "Creating root directory '${dst}' for module hierarchy ..." $DRY mkdir -p "${dst}" echo echo "Syncing Pmodules ..." sync_module "Tools/Pmodules/${PMODULES_VERSION}" \ "${src_prefix}" \ "${target_prefix}" || die 1 "Error: sync Pmodules failed!" echo dst="${target_prefix}/${PSI_CONFIG_DIR}/environment.bash" echo "Adding installation source '${src_prefix}' to '${dst}'..." sed -i .bak '/PMODULES_INSTALL_SOURCE/d' "${dst}" echo "declare -x PMODULES_INSTALL_SOURCE=\"${src_prefix}\"" >> "${dst}" echo if [[ -n "${user}" ]]; then echo "Changing user of new module environment to '${user}'..." $DRY chown -R "${user}" "${target_prefix}" || die 1 "Error: changing owner failed!" echo fi echo "New minimal module environment created at '${target_prefix}'." echo "To use this environment, execute" echo " sudo ln -fs ${target_prefix} /opt/psi" echo " source /opt/psi/${PSI_CONFIG_DIR}/profile.bash" } umask 022 for target_prefix in "${target_prefixes[@]}"; do init_pmodules_environment "${target_prefix}" done } subcommand_install() { local opts='' local -a with=() local -a releases=() local -a module_pattern=() local -r src_prefix="${PMODULES_INSTALL_SOURCE}" local -r target_prefix="${PSI_PREFIX}" opts=$(get_options -o hf -l dry-run -l force -l with: -l release: -l help -l src: -- "$@") if [[ $? != 0 ]]; then subcommand_help_install exit 1 fi eval set -- "${opts}" while (($# > 0)); do case $1 in --dry-run ) DRY='echo' ;; --force | -f ) force='yes' ;; --release ) releases+=( "$2" ) shift ;; --src ) src_prefix="$2" shift ;; --with ) with+=( "$2" ) shift ;; -- ) : ;; -h | --help ) subcommand_help_install exit 1 ;; -* ) echo "$1: illegal option" 1>&2 subcommand_help_init exit 1 ;; * ) module_pattern+=( "$1" ) ;; esac shift done local -A modules_to_install local -i n=0 while read rel_modulefile; do modules_to_install["${rel_modulefile}"]+='.' let n+=1 done < <(${PMODULES_HOME}/bin/modulecmd bash search \ "${module_pattern[@]}" \ "${with[@]/#/--with}" \ "${releases[@]/#/--release=}" \ --no-header --print-modulefiles \ --src="${src_prefix}" 2>&1) (( n == 0 )) && die 0 "Nothing to install..." echo -e "The following modules will be installed/updated:\n" 1>&2 for key in "${!modules_to_install[@]}"; do echo " ${key}" 1>&2 done echo 1>&2 get_YN_answer "Do you want to continue? [n] " || die 1 "Aborting..." echo 1>&2 for rel_modulefile in "${!modules_to_install[@]}"; do if [[ -d "${target_prefix}/${rel_modulefile}" ]]; then echo " Updating; ${rel_modulefile}..." 1>&2 else echo " Installing: ${rel_modulefile}..." fi sync_module "${rel_modulefile}" \ "${src_prefix}" \ "${target_prefix}" done echo -e "\nDone!\n" 1>&2 } while (($# > 0)); do case $1 in -h | -H | -\? | --help | -help ) usage exit 1 ;; -V | --version ) print_version exit 1 ;; -f | --force ) force='yes' ;; --dry-run ) dry_run='yes' DRY='echo' ;; -* ) echo "$1: unknown switch.\n" 1>&2 exit 1 ;; init|install|help ) subcommand="subcommand_$1" shift sargs=( $* ) shift $# ;; * ) echo "$1: unknown sub-command" 1>&2 exit 1 esac shift done $subcommand "${sargs[@]}" # Local Variables: # mode: sh # sh-basic-offset: 8 # tab-width: 8 # End: