a4b3edd68a
If a user invoked "spack env activate example-henv", Spack would mistakenly interpret the "-h" from "example-henv" as the "-h" option. This commit allows users to create and activate environments with "-h" in the name. This issue existed for bash shell support as well as csh support, and this commit addresses both, along with some other unrelated csh support issues.
360 lines
13 KiB
Bash
Executable file
360 lines
13 KiB
Bash
Executable file
# Copyright 2013-2020 Lawrence Livermore National Security, LLC and other
|
|
# Spack Project Developers. See the top-level COPYRIGHT file for details.
|
|
#
|
|
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
|
|
|
|
|
|
########################################################################
|
|
#
|
|
# This file is part of Spack and sets up the spack environment for bash,
|
|
# zsh, and dash (sh). This includes environment modules and lmod support,
|
|
# and it also puts spack in your path. The script also checks that at least
|
|
# module support exists, and provides suggestions if it doesn't. Source
|
|
# it like this:
|
|
#
|
|
# . /path/to/spack/share/spack/setup-env.sh
|
|
#
|
|
########################################################################
|
|
# This is a wrapper around the spack command that forwards calls to
|
|
# 'spack load' and 'spack unload' to shell functions. This in turn
|
|
# allows them to be used to invoke environment modules functions.
|
|
#
|
|
# 'spack load' is smarter than just 'load' because it converts its
|
|
# arguments into a unique Spack spec that is then passed to module
|
|
# commands. This allows the user to use packages without knowing all
|
|
# their installation details.
|
|
#
|
|
# e.g., rather than requiring a full spec for libelf, the user can type:
|
|
#
|
|
# spack load libelf
|
|
#
|
|
# This will first find the available libelf module file and use a
|
|
# matching one. If there are two versions of libelf, the user would
|
|
# need to be more specific, e.g.:
|
|
#
|
|
# spack load libelf@0.8.13
|
|
#
|
|
# This is very similar to how regular spack commands work and it
|
|
# avoids the need to come up with a user-friendly naming scheme for
|
|
# spack module files.
|
|
########################################################################
|
|
|
|
spack() {
|
|
# Store LD_LIBRARY_PATH variables from spack shell function
|
|
# This is necessary because MacOS System Integrity Protection clears
|
|
# (DY?)LD_LIBRARY_PATH variables on process start.
|
|
if [ -n "${LD_LIBRARY_PATH-}" ]; then
|
|
export SPACK_LD_LIBRARY_PATH=$LD_LIBRARY_PATH
|
|
fi
|
|
if [ -n "${DYLD_LIBRARY_PATH-}" ]; then
|
|
export SPACK_DYLD_LIBRARY_PATH=$DYLD_LIBRARY_PATH
|
|
fi
|
|
|
|
# Zsh does not do word splitting by default, this enables it for this
|
|
# function only
|
|
if [ -n "${ZSH_VERSION:-}" ]; then
|
|
emulate -L sh
|
|
fi
|
|
|
|
# accumulate flags meant for the main spack command
|
|
# the loop condition is unreadable, but it means:
|
|
# while $1 is set (while there are arguments)
|
|
# and $1 starts with '-' (and the arguments are flags)
|
|
_sp_flags=""
|
|
while [ ! -z ${1+x} ] && [ "${1#-}" != "${1}" ]; do
|
|
_sp_flags="$_sp_flags $1"
|
|
shift
|
|
done
|
|
|
|
# h and V flags don't require further output parsing.
|
|
if [ -n "$_sp_flags" ] && \
|
|
[ "${_sp_flags#*h}" != "${_sp_flags}" ] || \
|
|
[ "${_sp_flags#*V}" != "${_sp_flags}" ];
|
|
then
|
|
command spack $_sp_flags "$@"
|
|
return
|
|
fi
|
|
|
|
# set the subcommand if there is one (if $1 is set)
|
|
_sp_subcommand=""
|
|
if [ ! -z ${1+x} ]; then
|
|
_sp_subcommand="$1"
|
|
shift
|
|
fi
|
|
|
|
# Filter out use and unuse. For any other commands, just run the
|
|
# command.
|
|
case $_sp_subcommand in
|
|
"cd")
|
|
_sp_arg=""
|
|
if [ -n "$1" ]; then
|
|
_sp_arg="$1"
|
|
shift
|
|
fi
|
|
if [ "$_sp_arg" = "-h" ] || [ "$_sp_arg" = "--help" ]; then
|
|
command spack cd -h
|
|
else
|
|
LOC="$(spack location $_sp_arg "$@")"
|
|
if [ -d "$LOC" ] ; then
|
|
cd "$LOC"
|
|
else
|
|
return 1
|
|
fi
|
|
fi
|
|
return
|
|
;;
|
|
"env")
|
|
_sp_arg=""
|
|
if [ -n "$1" ]; then
|
|
_sp_arg="$1"
|
|
shift
|
|
fi
|
|
|
|
if [ "$_sp_arg" = "-h" ] || [ "$_sp_arg" = "--help" ]; then
|
|
command spack env -h
|
|
else
|
|
case $_sp_arg in
|
|
activate)
|
|
# Get --sh, --csh, or -h/--help arguments.
|
|
# Space needed here becauses regexes start with a space
|
|
# and `-h` may be the only argument.
|
|
_a=" $@"
|
|
# Space needed here to differentiate between `-h`
|
|
# argument and environments with "-h" in the name.
|
|
# Also see: https://www.gnu.org/software/bash/manual/html_node/Shell-Parameter-Expansion.html#Shell-Parameter-Expansion
|
|
if [ -z ${1+x} ] || \
|
|
[ "${_a#* --sh}" != "$_a" ] || \
|
|
[ "${_a#* --csh}" != "$_a" ] || \
|
|
[ "${_a#* -h}" != "$_a" ] || \
|
|
[ "${_a#* --help}" != "$_a" ];
|
|
then
|
|
# No args or args contain --sh, --csh, or -h/--help: just execute.
|
|
command spack env activate "$@"
|
|
else
|
|
# Actual call to activate: source the output.
|
|
eval $(command spack $_sp_flags env activate --sh "$@")
|
|
fi
|
|
;;
|
|
deactivate)
|
|
# Get --sh, --csh, or -h/--help arguments.
|
|
# Space needed here becauses regexes start with a space
|
|
# and `-h` may be the only argument.
|
|
_a=" $@"
|
|
# Space needed here to differentiate between `--sh`
|
|
# argument and environments with "--sh" in the name.
|
|
# Also see: https://www.gnu.org/software/bash/manual/html_node/Shell-Parameter-Expansion.html#Shell-Parameter-Expansion
|
|
if [ "${_a#* --sh}" != "$_a" ] || \
|
|
[ "${_a#* --csh}" != "$_a" ];
|
|
then
|
|
# Args contain --sh or --csh: just execute.
|
|
command spack env deactivate "$@"
|
|
elif [ -n "$*" ]; then
|
|
# Any other arguments are an error or -h/--help: just run help.
|
|
command spack env deactivate -h
|
|
else
|
|
# No args: source the output of the command.
|
|
eval $(command spack $_sp_flags env deactivate --sh)
|
|
fi
|
|
;;
|
|
*)
|
|
command spack env $_sp_arg "$@"
|
|
;;
|
|
esac
|
|
fi
|
|
return
|
|
;;
|
|
"load"|"unload")
|
|
# Get --sh, --csh, -h, or --help arguments.
|
|
# Space needed here becauses regexes start with a space
|
|
# and `-h` may be the only argument.
|
|
_a=" $@"
|
|
# Space needed here to differentiate between `-h`
|
|
# argument and specs with "-h" in the name.
|
|
# Also see: https://www.gnu.org/software/bash/manual/html_node/Shell-Parameter-Expansion.html#Shell-Parameter-Expansion
|
|
if [ "${_a#* --sh}" != "$_a" ] || \
|
|
[ "${_a#* --csh}" != "$_a" ] || \
|
|
[ "${_a#* -h}" != "$_a" ] || \
|
|
[ "${_a#* --help}" != "$_a" ];
|
|
then
|
|
# Args contain --sh, --csh, or -h/--help: just execute.
|
|
command spack $_sp_flags $_sp_subcommand "$@"
|
|
else
|
|
eval $(command spack $_sp_flags $_sp_subcommand --sh "$@" || \
|
|
echo "return 1") # return 1 if spack command fails
|
|
fi
|
|
;;
|
|
*)
|
|
command spack $_sp_flags $_sp_subcommand "$@"
|
|
;;
|
|
esac
|
|
}
|
|
|
|
|
|
########################################################################
|
|
# Prepends directories to path, if they exist.
|
|
# pathadd /path/to/dir # add to PATH
|
|
# or pathadd OTHERPATH /path/to/dir # add to OTHERPATH
|
|
########################################################################
|
|
_spack_pathadd() {
|
|
# If no variable name is supplied, just append to PATH
|
|
# otherwise append to that variable.
|
|
_pa_varname=PATH
|
|
_pa_new_path="$1"
|
|
if [ -n "$2" ]; then
|
|
_pa_varname="$1"
|
|
_pa_new_path="$2"
|
|
fi
|
|
|
|
# Do the actual prepending here.
|
|
eval "_pa_oldvalue=\${${_pa_varname}:-}"
|
|
|
|
_pa_canonical=":$_pa_oldvalue:"
|
|
if [ -d "$_pa_new_path" ] && \
|
|
[ "${_pa_canonical#*:${_pa_new_path}:}" = "${_pa_canonical}" ];
|
|
then
|
|
if [ -n "$_pa_oldvalue" ]; then
|
|
eval "export $_pa_varname=\"$_pa_new_path:$_pa_oldvalue\""
|
|
else
|
|
export $_pa_varname="$_pa_new_path"
|
|
fi
|
|
fi
|
|
}
|
|
|
|
|
|
# Determine which shell is being used
|
|
_spack_determine_shell() {
|
|
if [ -f "/proc/$$/exe" ]; then
|
|
# If procfs is present this seems a more reliable
|
|
# way to detect the current shell
|
|
_sp_exe=$(readlink /proc/$$/exe)
|
|
# Shell may contain number, like zsh5 instead of zsh
|
|
basename ${_sp_exe} | tr -d '0123456789'
|
|
elif [ -n "${BASH:-}" ]; then
|
|
echo bash
|
|
elif [ -n "${ZSH_NAME:-}" ]; then
|
|
echo zsh
|
|
else
|
|
PS_FORMAT= ps -p $$ | tail -n 1 | awk '{print $4}' | sed 's/^-//' | xargs basename
|
|
fi
|
|
}
|
|
_sp_shell=$(_spack_determine_shell)
|
|
|
|
|
|
# Export spack function so it is available in subshells (only works with bash)
|
|
if [ "$_sp_shell" = bash ]; then
|
|
export -f spack
|
|
fi
|
|
|
|
#
|
|
# Figure out where this file is.
|
|
#
|
|
if [ "$_sp_shell" = bash ]; then
|
|
_sp_source_file="${BASH_SOURCE[0]:-}"
|
|
elif [ "$_sp_shell" = zsh ]; then
|
|
_sp_source_file="${(%):-%N}"
|
|
else
|
|
# Try to read the /proc filesystem (works on linux without lsof)
|
|
# In dash, the sourced file is the last one opened (and it's kept open)
|
|
_sp_source_file_fd="$(\ls /proc/$$/fd 2>/dev/null | sort -n | tail -1)"
|
|
if ! _sp_source_file="$(readlink /proc/$$/fd/$_sp_source_file_fd)"; then
|
|
# Last resort: try lsof. This works in dash on macos -- same reason.
|
|
# macos has lsof installed by default; some linux containers don't.
|
|
_sp_lsof_output="$(lsof -p $$ -Fn0 | tail -1)"
|
|
_sp_source_file="${_sp_lsof_output#*n}"
|
|
fi
|
|
|
|
# If we can't find this script's path after all that, bail out with
|
|
# plain old $0, which WILL NOT work if this is sourced indirectly.
|
|
if [ ! -f "$_sp_source_file" ]; then
|
|
_sp_source_file="$0"
|
|
fi
|
|
fi
|
|
|
|
#
|
|
# Find root directory and add bin to path.
|
|
#
|
|
# We send cd output to /dev/null to avoid because a lot of users set up
|
|
# their shell so that cd prints things out to the tty.
|
|
_sp_share_dir="$(cd "$(dirname $_sp_source_file)" > /dev/null && pwd)"
|
|
_sp_prefix="$(cd "$(dirname $(dirname $_sp_share_dir))" > /dev/null && pwd)"
|
|
if [ -x "$_sp_prefix/bin/spack" ]; then
|
|
export SPACK_ROOT="${_sp_prefix}"
|
|
else
|
|
# If the shell couldn't find the sourced script, fall back to
|
|
# whatever the user set SPACK_ROOT to.
|
|
if [ -n "$SPACK_ROOT" ]; then
|
|
_sp_prefix="$SPACK_ROOT"
|
|
_sp_share_dir="$_sp_prefix/share/spack"
|
|
fi
|
|
|
|
# If SPACK_ROOT didn't work, fail. We should need this rarely, as
|
|
# the tricks above for finding the sourced file are pretty robust.
|
|
if [ ! -x "$_sp_prefix/bin/spack" ]; then
|
|
echo "==> Error: SPACK_ROOT must point to spack's prefix when using $_sp_shell"
|
|
echo "Run this with the correct prefix before sourcing setup-env.sh:"
|
|
echo " export SPACK_ROOT=</path/to/spack>"
|
|
return 1
|
|
fi
|
|
fi
|
|
_spack_pathadd PATH "${_sp_prefix%/}/bin"
|
|
|
|
#
|
|
# Check whether a function of the given name is defined
|
|
#
|
|
_spack_fn_exists() {
|
|
LANG= type $1 2>&1 | grep -q 'function'
|
|
}
|
|
|
|
need_module="no"
|
|
if ! _spack_fn_exists use && ! _spack_fn_exists module; then
|
|
need_module="yes"
|
|
fi;
|
|
|
|
#
|
|
# make available environment-modules
|
|
#
|
|
if [ "${need_module}" = "yes" ]; then
|
|
eval `spack --print-shell-vars sh,modules`
|
|
|
|
# _sp_module_prefix is set by spack --print-sh-vars
|
|
if [ "${_sp_module_prefix}" != "not_installed" ]; then
|
|
# activate it!
|
|
# environment-modules@4: has a bin directory inside its prefix
|
|
_sp_module_bin="${_sp_module_prefix}/bin"
|
|
if [ ! -d "${_sp_module_bin}" ]; then
|
|
# environment-modules@3 has a nested bin directory
|
|
_sp_module_bin="${_sp_module_prefix}/Modules/bin"
|
|
fi
|
|
|
|
# _sp_module_bin and _sp_shell are evaluated here; the quoted
|
|
# eval statement and $* are deferred.
|
|
_sp_cmd="module() { eval \`${_sp_module_bin}/modulecmd ${_sp_shell} \$*\`; }"
|
|
eval "$_sp_cmd"
|
|
_spack_pathadd PATH "${_sp_module_bin}"
|
|
fi;
|
|
else
|
|
eval `spack --print-shell-vars sh`
|
|
fi;
|
|
|
|
|
|
#
|
|
# set module system roots
|
|
#
|
|
_sp_multi_pathadd() {
|
|
local IFS=':'
|
|
if [ "$_sp_shell" = zsh ]; then
|
|
emulate -L sh
|
|
fi
|
|
for pth in $2; do
|
|
for systype in ${_sp_compatible_sys_types}; do
|
|
_spack_pathadd "$1" "${pth}/${systype}"
|
|
done
|
|
done
|
|
}
|
|
_sp_multi_pathadd MODULEPATH "$_sp_tcl_roots"
|
|
|
|
# Add programmable tab completion for Bash
|
|
#
|
|
if [ "$_sp_shell" = bash ]; then
|
|
source $_sp_share_dir/spack-completion.bash
|
|
fi
|