From 0296400ffad8c97b31c67488f8f9aabf1293d3dc Mon Sep 17 00:00:00 2001 From: Hans-Christian Stadler Kleeb Date: Fri, 13 Mar 2015 09:39:53 +0100 Subject: [PATCH] Merged with newest version of Achim --- scripts/Bootstrap/Pmodules/dialog.bash | 9 +- scripts/Bootstrap/Pmodules/libpmodules.bash | 9 +- scripts/Bootstrap/Pmodules/modmanage.in | 179 +++++++++++++++++--- 3 files changed, 167 insertions(+), 30 deletions(-) diff --git a/scripts/Bootstrap/Pmodules/dialog.bash b/scripts/Bootstrap/Pmodules/dialog.bash index 92f6814..82447cc 100755 --- a/scripts/Bootstrap/Pmodules/dialog.bash +++ b/scripts/Bootstrap/Pmodules/dialog.bash @@ -1,8 +1,7 @@ #!/usr/bin/env bash # Hardcoded path to dialog software -LOCAL_DIALOGHOME=Tools/dialog/1.2.1 -DIALOG_CMD=$PSI_PREFIX/$LOCAL_DIALOGHOME/bin/dialog +DIALOG_CMD=$PMODULES_HOME/bin/dialog declare -a modlist # module info declare -A selected # module info indices selected @@ -338,9 +337,9 @@ function module_picker() { # if DIALOG_LIB is NOT set, call module picker [[ ${DIALOG_LIB:+"is_lib"} == "is_lib" ]] || { - if [[ -x ${PSI_PREFIX}/${PSI_CONFIG_DIR}/modulecmd.bash ]]; then - module_picker "$1" < <(${PSI_PREFIX}/${PSI_CONFIG_DIR}/modulecmd.bash bash search --no-header -a 2>&1) + if [[ -x ${PMODULES_HOME}/bin/modulecmd ]]; then + module_picker "$1" < <(${PMODULES_HOME}/bin/modulecmd bash search --no-header -a 2>&1) else - echo "ERROR: module environment configuration: ${PSI_PREFIX}/${PSI_CONFIG_DIR}/modulecmd.bash is not an executable!" + echo "ERROR: module environment configuration: ${PMODULES_HOME}/bin/modulecmd is not an executable!" fi } diff --git a/scripts/Bootstrap/Pmodules/libpmodules.bash b/scripts/Bootstrap/Pmodules/libpmodules.bash index 0590835..44c0b7e 100644 --- a/scripts/Bootstrap/Pmodules/libpmodules.bash +++ b/scripts/Bootstrap/Pmodules/libpmodules.bash @@ -28,7 +28,7 @@ die() { cout='1' else cout='2' - fi + fi if [[ -n $@ ]]; then local -r fmt=$1 shift @@ -47,7 +47,7 @@ get_YN_answer() { local ans read -p "${prompt}" ans case ${ans} in - y|Y ) + y|Y ) return 0;; * ) return 1;; @@ -65,15 +65,14 @@ check_pmodules_env() { [[ -n "${PSI_TEMPLATES_DIR}" ]] && [[ -n "${PMODULES_HOME}" ]] && [[ -n "${PMODULES_VERSION}" ]] || die 1 " -Error: the module environment you are going to use as source has not been -initialized properly!" +Error: not running within a valid module environment!" [[ -d "${PSI_PREFIX}" ]] && [[ -d "${PSI_PREFIX}/${PSI_CONFIG_DIR}" ]] && [[ -d "${PSI_PREFIX}/${PSI_MODULES_ROOT}" ]] && [[ -d "${PSI_PREFIX}/${PSI_TEMPLATES_DIR}" ]] && [[ -d "${PMODULES_HOME}" ]] || die 1 " -Error: the module environment '$PSI_PREFIX' has not been initialized properly!" +Error: the module environment '$PSI_PREFIX' is invalid!" } diff --git a/scripts/Bootstrap/Pmodules/modmanage.in b/scripts/Bootstrap/Pmodules/modmanage.in index 6301e31..a9053f8 100755 --- a/scripts/Bootstrap/Pmodules/modmanage.in +++ b/scripts/Bootstrap/Pmodules/modmanage.in @@ -30,9 +30,12 @@ Available SubCommands and Args: install [--with=...] Install matching modules + + sync [--delete] [--dst=] + Synchronize modules. " } - + declare force='no' declare dry_run='no' @@ -56,6 +59,17 @@ install [--with=...] " 1>&2 } +subcommand_help_sync() { + echo " +sync [--delete] [--dst=] + Synchronize environment modules and configuration files + from Pmodule environment to Pmodule environment + (default: currently active Pmodule environment). + If --delete is given, unmarked modules present in + will be deleted. +" 1>&2 +} + subcommand_help() { if [[ $# == 0 ]]; then usage @@ -135,6 +149,26 @@ sync_module() { fi } +# +# Sync the Pmodules configuration and templates +# +# $1: source prefix of Pmodule environment +# $2: target prefix of Pmodule environment +# +sync_config() { + src="$1/${PSI_CONFIG_DIR}/" + dst="$2/${PSI_CONFIG_DIR}/" + $DRY rsync --recursive --links --perms --delete \ + "${src}" "${dst}" || die 1 "Error: synch operation failed!" + echo + + src="$1/${PSI_TEMPLATES_DIR}/" + dst="$2/${PSI_TEMPLATES_DIR}/" + $DRY rsync --recursive --links --perms --delete \ + "${src}" "${dst}" || die 1 "Error: synch operation failed!" + echo +} + subcommand_init() { local src='' local target_prefixes=() @@ -147,7 +181,7 @@ subcommand_init() { fi eval set -- "${opts}" while (($# > 0)); do - case $1 in + case $1 in --src ) src=$2 shift @@ -188,9 +222,9 @@ subcommand_init() { [[ -z "${user}" ]] || \ die 1 "Error: --user option is only allowed if running as root!" fi - - check_pmodules_env || die 1 "Giving up ..." - + + check_pmodules_env || die 1 "Giving up..." + echo " Attempting to create a minimal module environment from the environment at '${PSI_PREFIX}' @@ -212,26 +246,16 @@ environment at '${PSI_PREFIX}' $DRY mkdir -p "${target_prefix}" || die 1 "Error: make directory failed!" echo - src="${PSI_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="${PSI_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 + echo "Syncing configuration ..." + sync_config "${PSI_PREFIX}" \ + "${target_prefix}" || die 1 "Error: configuration synchronization failed!" echo "Syncing Pmodules ..." sync_module "Tools/Pmodules/${PMODULES_VERSION}" \ "${PSI_PREFIX}" \ "${target_prefix}" || die 1 "Error: sync Pmodules failed!" 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!" @@ -290,6 +314,121 @@ subcommand_install() { ${PMODULES_HOME}/bin/modulecmd bash search "${module_pattern[@]}" "${with[@]/#/--with}" "${releases[@]/#/--release=}" --no-header } +subcommand_sync() { + local delete=false + local opts='' + local dst_prefix='' + local source_prefix='' + opts=$(get_options -o h -l dst: -l delete -l help -- "$@") + if [[ $? != 0 ]]; then + subcommand_help_sync + exit 1 + fi + eval set -- "${opts}" + while (($# > 0)); do + case $1 in + --dst ) + dst_prefix="$2" + shift + ;; + --delete ) + delete=true + ;; + -- ) + : + ;; + -* | -h | --help ) + echo "$1: illegal option" 1>&2 + subcommand_help_init + exit 1 + ;; + * ) + [[ -n "${source_prefix}" ]] && die 1 "Error: Only one source is allowed!" + source_prefix="$1" + ;; + esac + shift + done + unset -v opts + if [[ -z "${dst_prefix}" ]]; then + [[ -z "${PSI_PREFIX}" ]] && die 1 "Error: No current module environment and no destination specified!" + dst_prefix="${PSI_PREFIX}" + fi + ( + PSI_PREFIX="${dst_prefix}" check_pmodules_env || die 1 "Error: invalid destination modules environment!" + ) || die 1 "Giving up..." + ( + PSI_PREFIX="${src_prefix}" check_pmodules_env || die 1 "Error: invalid source modules environment!" + ) || die 1 "Giving up..." + [[ "$( cd "$src_prefix"; pwd -P )" == "$( cd "$dst_prefix"; pwd -P )" ]] && die 1 "Error: source and destination are equal!" + local modbin=${PMODULES_HOME#"${PSI_PREFIX}/"}/bin/modulecmd.tcl + local file_type_src=$( file -b "${src_prefix}/${modbin}" 2>&1 || echo err1 ) + local file_type_dst=$( file -b "${dst_prefix}/${modbin}" 2>&1 || echo err2 ) + [[ "${file_type_src}" == "${file_type_dst}" ]] || die 1 "Error: The file signatures in the source and destination installation do not match!" + unset -v file_type_src file_type_dst + + local profile_script="${src_prefix}/${PSI_CONFIG_DIR}/profile.bash" + [[ -r "${profile_script}" ]] || die 1 "Error: Unable to find profile script of installation $profile_script"; + local search_script="${src_prefix}/${modbin}/bin/modulecmd" + [[ -x "${search_script}" ]] || die 1 "Error: Unable to find search script of installation $search_script"; +# local dialog_script="${src_prefix}/${modbin}/bin/dialog.bash" + local dialog_script="./dialog.bash" + [[ -r "$dialog_script" ]] || die 1 "Error: Unable to find dialog script of installation $dialog_script"; + + source "$profile_script" # set variables for the source installation + DIALOG_LIB=1 # use dialog script as a library + source "$dialog_script" # dialog functions + + local -a selected_modules + + # Redefine module_out to append modules to the selected_modules variable + function module_out() { + local -a args=(${modlist[$1]}) + local path="" + IFS=/ + [[ -n "${args[3]}" ]] && path="/${args[*]:3}" + unset IFS + selected_modules+=( "${args[2]}${path}/${args[0]}" ) + } + + module_picker "${dst_prefix}" < <("$search_script" bash search --no-header -a 2>&1) # this calls module_out for each selected module, filling up the selected_modules array + + local -a destination_modules=( $(cd "${dst_prefix}/${PSI_MODULES_ROOT}"; find -L . -type f | while read f; do echo ${f#./}; done) ) + + # redefine set difference, the version in dialog.bash only handles integers + function set_difference() { # $1 \ $2 + local -a operand1=($1) + local -a operand2=($2) + local -A members + local elem + for elem in "${operand1[@]}"; do + members[$elem]=1 + done + for elem in "${operand2[@]}"; do + unset members[$elem] + done + echo ${!members[@]} + } + + if [[ "$delete" == "true" ]]; then + local -a modules_delete=( $(set_difference "${destination_modules[*]}" "${selected_modules[*]}") ) + for m in "${modules_delete[@]}"; do + delete_module "$m" "$dst_prefix" + done + unset modules_delete + fi + + local -a modules_copy=( $(set_difference "${selected_modules[*]}" "${destination_modules[*]}") ) + if [[ -n $modules_copy ]]; then + echo "Syncing configuration ..." + sync_config "$src_prefix" "$dst_prefix" || die 1 "Error: syncing the configuration failed" + fi + for m in "${modules_copy[@]}"; do + sync_module "$m" "$src_prefix" "$dst_prefix" || die 1 "Error: syncing of module $m failed!" + done + unset modules_copy +} + while (($# > 0)); do case $1 in -h | -H | -\? | --help | -help ) @@ -311,7 +450,7 @@ while (($# > 0)); do echo "$1: unknown switch.\n" 1>&2 exit 1 ;; - init|install|help ) + init|install|sync|help ) subcommand="subcommand_$1" shift sargs=( $* )