#!/usr/bin/env bash # if [ "${BASH_VERSINFO[0]}" -lt 4 ]; then echo "BASH version >= 4 is required and must be available in PATH!" 1>&2 exit 1 fi declare -r OS=$(uname -s) declare BOOTSTRAP_DIR=$(dirname "$0") source "${BOOTSTRAP_DIR}/Pmodules/libstd.bash" || { echo "Oops!" 1>&2; exit 42; } declare -r BOOTSTRAP_DIR=$(std::get_abspath "${BOOTSTRAP_DIR}") declare -r SRC_DIR="${BOOTSTRAP_DIR}/Pmodules" # these variables need to be defined but must be initialized with an empty string declare -x PMODULES_HOME='' declare -x PMODULES_DISTFILESDIR='' declare -x PMODULES_TMPDIR='' declare -rx CONFIG_DIR='config' declare -rx CONFIG_FILE='modbuild.conf' # defaults declare -rx DEFAULT_PMODULES_ROOT='/opt/psi' declare -rx DEFAULT_DISTFILES_DIR="var/distfiles" declare -rx DEFAULT_VERSIONS_CONFIG="${CONFIG_DIR}/versions.conf" declare -rx DEFAULT_TMPDIR='var/tmp/${USER}' # directory where the required tools will be installed (like bash, tclsh, etc) declare -rx UTILBIN_DIR='libexec' #----------------------------------------------------------------------------- # get_version() { local -r name="$1" echo $(awk "/^$1[[:blank:]]/ {print \$2}" "${DEFAULT_VERSIONS_CONFIG}") } declare -rx PMODULES_VERSION=$(get_version 'Pmodules') #----------------------------------------------------------------------------- # usage() { local prog=$(basename $0) echo " Usage: ${prog} help|configure|compile|install This script must be used to - Bootstrap/configure a new Pmodules environment, - compile and install the required tools - install a new Pmodules version Run ${prog} help configure|compile|install or ${prog} configure|compile|install --help to get help for a specific sub-command. " std::die 1 "" } #----------------------------------------------------------------------------- # pmodules::help() { if (( $# > 1 )); then usage fi case $1 in configure|compile|install ) pmodules::help_$1 ;; * ) echo -en "$1 - invalid sub-command!\n" 1>&2 usage ;; esac } #----------------------------------------------------------------------------- # read_config_file() { local var="$1" local fname="${!var}" if [[ ! -r "${fname}" ]]; then std::die 1 "Configuration file '${fname}' does not exist or is not readable!" fi source "${fname}" || std::die 1 "Cannot read configuration file '${fname}'" if [[ -z "${PMODULES_ROOT}" ]]; then std::die 1 "Error in configuration file '${fname}': PMODULE_ROOT not defined!" fi if [[ -z "${PMODULES_VERSION}" ]]; then std::die 1 "Error in configuration file '${fname}': PMODULE_VERSION not defined!" fi if [[ -z "${PMODULES_DISTFILESDIR}" ]]; then std::die 1 "Error in configuration file '${fname}': PMODULES_DISTFILESDIR not defined!" fi if [[ -z "${PMODULES_TMPDIR}" ]]; then std::die 1 "Error in configuration file '${fname}': PMODULE_TMPDIR not defined!" fi # we have to make these variables global, otherwise they are not set # in the calling function declare -g PMODULES_ROOT="${PMODULES_ROOT}" declare -g PMODULES_HOME="${PMODULES_HOME}" declare -g PMODULES_DISTFILESDIR="${PMODULES_DISTFILESDIR}" declare -g PMODULES_TMPDIR="${PMODULES_TMPDIR}" std::upvar "${var}" "${fname}" } #----------------------------------------------------------------------------- # pmodules::help_configure() { echo " Usage: $(basename $0) configure [OPTION...] Configure and setup a new Pmodules environment. You need permissions to write to the installation root. Options: --prefix=DIR Root of the Pmodules environment installation. Everything will be installed in a directory hierarchy with 'DIR' as prefix. The default is '${DEFAULT_PMODULES_ROOT}'. --distfilesdir=DIR Directory where downloaded files are stored. The default is '${DEFAULT_PMODULES_DISTFILESDIR}' in the Pmodules root directory. --tmpdir=DIR Directory for temporary files. The default is '${DEFAULT_PMODULES_TMPDIR}' --help Print this help text. " 1>&2 std::die 1 "" } #----------------------------------------------------------------------------- # pmodules::configure() { local prefix="${PMODULES_ROOT:-${DEFAULT_PMODULES_ROOT}}" local distfilesdir='' local tmpdir='' local config_file='' local opt_force='no' while (( $# > 0 )); do case "$1" in --prefix ) prefix="$2" shift 1 ;; --prefix=* ) prefix="${1#*=}" ;; --distfilesdir ) distfilesdir="$2" shift 1 ;; --distfilesdir=* ) distfilesdir="${1#*=}" ;; -f | --force ) opt_force='yes' ;; --tmpdir ) tmpdir="$2" shift 1 ;; --tmpdir=* ) tmpdir="${1#*=}" ;; --help | -h | -\? ) pmodules::help_configure ;; -* ) std::die 1 "$1: illegal option" ;; * ) std::die 1 "$1: illegal argument to sub-command 'configure'." ;; esac shift 1 done if [[ ! -d ${prefix} ]]; then echo "The root directory '${prefix}' does not exist, trying to create it..." if ! mkdir -p "${prefix}"; then std::die 1 "Creating the root directory failed!\nAborting..." fi fi if [[ ! -w ${prefix} ]]; then std::die 1 "The root directory '${prefix}' is not writable!\nAborting..." fi mkdir -p "${prefix}/${CONFIG_DIR}" || \ std::die 1 "Aborting..." local config_file="${prefix}/${CONFIG_DIR}/${CONFIG_FILE}" if [[ "${opt_force}" == 'yes' ]]; then rm -f "${config_file}" fi if [[ -e "${config_file}" ]]; then std::die 1 "The Pmodules environment has already been configured! Use the option --force to override.\nAborting..." fi [[ -z "${distfilesdir}" ]] && distfilesdir="${prefix}/${DEFAULT_DISTFILES_DIR}" [[ -z "${tmpdir}" ]] && tmpdir="${prefix}/${DEFAULT_TMPDIR}" sed_cmd="s:@PMODULES_ROOT@:${prefix}:g;" sed_cmd+="s:@PMODULES_DISTFILESDIR@:${distfilesdir}:g;" sed_cmd+="s:@PMODULES_TMPDIR@:${tmpdir}:g;" sed_cmd+="s:@PMODULES_VERSION@:${PMODULES_VERSION}:g" sed "${sed_cmd}" "${BOOTSTRAP_DIR}/${CONFIG_DIR}/${CONFIG_FILE}.in" \ > "${config_file}" || \ std::die 1 "Cannot create configuration file in Pmodules root\nAborting..." read_config_file 'config_file' install -d -m 0755 "${PMODULES_HOME}/bin" install -d -m 0755 "${PMODULES_HOME}/init" install -d -m 0755 "${PMODULES_HOME}/lib" install -d -m 0755 "${PMODULES_HOME}/libexec" echo "Configuration:" echo " root of Pmodules environment: ${prefix}" echo " Pmodule prefix: ${PMODULES_HOME}" echo " tmp directory: ${tmpdir}" echo " store for downloaded files: ${distfilesdir}" echo "Done..." } #----------------------------------------------------------------------------- # pmodules::help_compile() { echo " Usage: $(basename $0) compile [OPTION...] Compile and install the required tools for a new Pmodules environment. ou need the permissions to write to the installation root. Options: --prefix=DIR Root of the Pmodules environment installation. The root of the installation must be either specified via this option or the environment variable PMODULES_ROOT. If this option is used and the PMODULES_ROOT is set, the directory specified with this option will be used. --debug Enable verbose/debug output. --disable-cleanup ) Do not cleanup the tmp directory after compilation and installation. --force | -f Force compilation. --help Print this help text. " 1>&2 std::die 1 "" } pmodules::compile() { build () { local -r name="$1" local -r version=$(get_version "${name}") shift "${BOOTSTRAP_DIR}/Pmodules/modbuild.in" \ "--config=${config_file}" \ "--enable-cleanup" \ "--force-rebuild" \ "--debug" \ "--verbose" \ "${BOOTSTRAP_DIR}/Tools/${name}/build" \ "${build_opts[@]}" "$@" "${version}" || \ std::die 3 "Compiling '${name}' failed!" } local prefix="${PMODULES_ROOT:-${DEFAULT_PMODULES_ROOT}}" local opt_force='no' local config_file='' while (( $# > 0 )); do case $1 in --prefix ) prefix="$2" shift 1 ;; --prefix=* ) prefix="${1#*=}" ;; --disable-cleanup ) build_opts+=( "$1" ) ;; --debug ) build_opts+=( "$1" ) ;; -f | --force ) opt_force='yes' ;; --help | -h | -\? ) pmodules::help_compile ;; -* ) std::die 1 "$1: illegal option" ;; * ) std::die 1 "$1: illegal argument for sub-command 'compile'." ;; esac shift 1 done local config_file="${prefix}/${CONFIG_DIR}/${CONFIG_FILE}" read_config_file config_file install -d -m 0755 "${PMODULES_HOME}/bin" install -d -m 0755 "${PMODULES_HOME}/init" install -d -m 0755 "${PMODULES_HOME}/lib" install -d -m 0755 "${PMODULES_HOME}/libexec" echo "Configuration:" echo " root of Pmodules environment: ${prefix}" echo " Pmodule prefix: ${PMODULES_HOME}" #if [[ ! -f "${PMODULES_HOME}/${UTILBIN_DIR}/base64" ]] || [[ ${opt_force} == 'yes' ]]; then # build coreutils #fi if [[ "${OS}" == 'Darwin' ]]; then if [[ ! -f "${PMODULES_HOME}/${UTILBIN_DIR}/getopt" ]] || [[ ${opt_force} == 'yes' ]]; then build getopt fi if [[ ! -f "${PMODULES_HOME}/${UTILBIN_DIR}/find" ]] || [[ ${opt_force} == 'yes' ]]; then build findutils fi fi if [[ ! -f "${PMODULES_HOME}/${UTILBIN_DIR}/bash" ]] || [[ ${opt_force} == 'yes' ]]; then build bash fi if [[ ! -e "${PMODULES_HOME}/${UTILBIN_DIR}/tclsh" ]] || [[ ${opt_force} == 'yes' ]]; then build Tcl fi if [[ ! -e "${PMODULES_HOME}/lib/tcllib1.20" ]] || [[ ${opt_force} == 'yes' ]]; then build tcllib fi if [[ ! -e "${PMODULES_HOME}/libexec/modulecmd.bin" ]] || [[ ${opt_force} == 'yes' ]]; then build modules fi rm -rf "${PMODULES_HOME}/include" rm -rf "${PMODULES_HOME}/lib/"*.a rm -rf "${PMODULES_HOME}/lib/"*.la rm -rf "${PMODULES_HOME}/lib/bash" rm -rf "${PMODULES_HOME}/lib/pkginfo" rm -rf "${PMODULES_HOME}/man" rm -rf "${PMODULES_HOME}/share" echo "Done..." } #----------------------------------------------------------------------------- # pmodules::help_install() { echo " Usage: $(basename $0) install [OPTION...] Install a new Pmodules version. Options: --prefix=DIR Root of the Pmodules environment installation. The root of the installation must be either specified via this option or the environment variable PMODULES_ROOT. If this option is used and the PMODULES_ROOT is set, the directory specified with this option will be used. --debug Enable verbose/debug output. --disable-cleanup ) Do not cleanup the tmp directory after compilation and installation. --force | -f Force compilation. --help Print this help text. " 1>&2 std::die 1 "" } pmodules::install() { local prefix="${PMODULES_ROOT:-${DEFAULT_PMODULES_ROOT}}" local config_file='' local opt_force='no' while (( $# > 0 )); do case $1 in --debug ) set -x ;; --prefix ) prefix="$2" shift 1 ;; --prefix=* ) prefix="${1#*=}" ;; -f | --force ) opt_force='yes' ;; --help | -h | -\? ) pmodules::help_install ;; -* ) std::die 1 "$1: illegal option" ;; * ) std::die 1 "$1: illegal argument to sub-command 'install'." ;; esac shift 1 done local config_file="${prefix}/${CONFIG_DIR}/${CONFIG_FILE}" read_config_file 'config_file' ### # # begin installation # echo "Configuration:" echo " root of Pmodules environment: ${PMODULES_ROOT}" echo " Pmodule prefix: ${PMODULES_HOME}" sed_cmd="s:@PMODULES_HOME@:${PMODULES_HOME}:g;" sed_cmd+="s:@PMODULES_VERSION@:${PMODULES_VERSION}:g;" sed_cmd+="s:@MODULES_VERSION@:${MODULES_VERSION}:g;" sed_cmd+="s:@PMODULES_DISTFILESDIR@:${PMODULES_DISTFILESDIR}:g;" sed_cmd+="s:@PMODULES_TMPDIR@:${PMODULES_TMPDIR}:g;" sed_cmd+="s:@TCLSHDIR@:${PMODULES_HOME}/${UTILBIN_DIR}:g;" sed_cmd+="s:@pager@::g;" sed_cmd+="s:@pageropts@::g;" sed_cmd+="s:@etcdir@:${PMODULES_ROOT}/${CONFIG_DIR}:g;" sed_cmd+="s:@VERSIONING@:#:g;" sed_cmd+="s:@prefix@:${PMODULES_HOME}:g;" sed_cmd+="s:@initdir@:${PMODULES_HOME}/init:g;" sed_cmd+="s:@MODULES_RELEASE@:${PMODULES_VERSION}:g;" sed_cmd+="s:@BASH@:${PMODULES_HOME}/${UTILBIN_DIR}/bash:g;" sed_cmd+="s:@MODULECMD@:${PMODULES_HOME}/${UTILBIN_DIR}/modulecmd.bash:g;" sed_cmd+="s:@MODMANAGE@:${PMODULES_HOME}/${UTILBIN_DIR}/modmanage.bash:g;" sed "${sed_cmd}" "${SRC_DIR}/profile.bash.in" > "${PMODULES_ROOT}/${CONFIG_DIR}/profile.bash-${PMODULES_VERSION}" sed "${sed_cmd}" "${SRC_DIR}/profile.csh.in" > "${PMODULES_ROOT}/${CONFIG_DIR}/profile.csh-${PMODULES_VERSION}" sed "${sed_cmd}" "${SRC_DIR}/profile.zsh.in" > "${PMODULES_ROOT}/${CONFIG_DIR}/profile.zsh-${PMODULES_VERSION}" chmod 0644 "${PMODULES_ROOT}/${CONFIG_DIR}"/*-${PMODULES_VERSION} test -e "${PMODULES_ROOT}/${CONFIG_DIR}/profile.bash" || \ install -m 0644 "$_-${PMODULES_VERSION}" "$_" test -e "${PMODULES_ROOT}/${CONFIG_DIR}/profile.csh" || \ install -m 0644 "$_-${PMODULES_VERSION}" "$_" test -e "${PMODULES_ROOT}/${CONFIG_DIR}/profile.zsh" || \ install -m 0644 "$_-${PMODULES_VERSION}" "$_" sed "${sed_cmd}" "${SRC_DIR}/modulecmd.in" > "${PMODULES_HOME}/bin/modulecmd" chmod 0755 "${PMODULES_HOME}/bin/modulecmd" sed "${sed_cmd}" "${SRC_DIR}/modulecmd.bash.in" > "${PMODULES_HOME}/libexec/modulecmd.bash" chmod 0755 "${PMODULES_HOME}/libexec/modulecmd.bash" sed "${sed_cmd}" "${SRC_DIR}/modulecmd.tcl.in" > "${PMODULES_HOME}/libexec/modulecmd.tcl" chmod 0755 "${PMODULES_HOME}/libexec/modulecmd.tcl" sed "${sed_cmd}" "${SRC_DIR}/modbuild.in" > "${PMODULES_HOME}/bin/modbuild" chmod 0755 "${PMODULES_HOME}/bin/modbuild" sed "${sed_cmd}" "${SRC_DIR}/modmanage.in" > "${PMODULES_HOME}/bin/modmanage" chmod 0755 "${PMODULES_HOME}/bin/modmanage" sed "${sed_cmd}" "${SRC_DIR}/modmanage.bash.in" > "${PMODULES_HOME}/libexec/modmanage.bash" chmod 0755 "${PMODULES_HOME}/libexec/modmanage.bash" test -e "${PMODULES_ROOT}/${CONFIG_DIR}/Pmodules.conf" || \ install -m 0644 "${SRC_DIR}/Pmodules.conf" "${PMODULES_ROOT}/${CONFIG_DIR}" install -m 0644 "${SRC_DIR}/bash" "${PMODULES_HOME}/init" install -m 0644 "${SRC_DIR}/bash_completion" "${PMODULES_HOME}/init" install -m 0644 "${SRC_DIR}/csh" "${PMODULES_HOME}/init" install -m 0644 "${SRC_DIR}/zsh" "${PMODULES_HOME}/init" install -m 0644 "${SRC_DIR}/libpmodules.bash" "${PMODULES_HOME}/lib" install -m 0644 "${SRC_DIR}/libpbuild.bash" "${PMODULES_HOME}/lib" install -m 0644 "${SRC_DIR}/libpbuild_dyn.bash" "${PMODULES_HOME}/lib" install -m 0644 "${SRC_DIR}/libstd.bash" "${PMODULES_HOME}/lib" install -m 0755 -d "${PMODULES_HOME}/lib/Pmodules" install -m 0644 "${SRC_DIR}/libmodules.tcl" "${PMODULES_HOME}/lib/Pmodules" { PATH="${PMODULES_HOME}/${UTILBIN_DIR}:${PATH}" cd "${PMODULES_HOME}/lib/Pmodules" "${BOOTSTRAP_DIR}/mkindex.tcl" } install -m 0755 -d "${PMODULES_ROOT}/Tools/modulefiles/Pmodules" install -m 0644 "${SRC_DIR}/modulefile" "${PMODULES_ROOT}/Tools/modulefiles/Pmodules/${PMODULES_VERSION}" mkdir -p "${PMODULES_ROOT}/Libraries/modulefiles" echo "Done..." } #============================================================================= # declare -a build_opts=() build_opts+=( '--bootstrap' ) declare subcmd='' declare -a subcmd_args=() while (( $# > 0 )); do case "$1" in --help | -h | -\? ) usage ;; --debug ) set -x ;; -* ) std::die 1 "$1: illegal option" ;; help | configure | compile | install ) subcmd="$1" shift 1 subcmd_args=( "$@" ) shift $# ;; * ) std::die 1 "Invalid sub-command '$1'.\n\nUse 'build --help' to get help..." ;; esac shift 1 done [[ -n "${subcmd}" ]] || std::die 1 "Missing sub-command.\n\nUse 'build --help' to get help..." pmodules::${subcmd} "${subcmd_args[@]}"