Skip to content
Permalink
Branch: master
Find file Copy path
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
executable file 1235 lines (1028 sloc) 29.9 KB
#!/bin/bash
# Please preserve tabs as indenting whitespace at Mario's request
# to keep heredocs nice (--fe)
#
# Bootstrap lsst stack install by:
# * Installing Miniconda Python distribution, if necessary
# * Installing EUPS
# * Creating the loadLSST.xxx scripts
#
set -Eeo pipefail
#
# Note to developers: change these when the EUPS version we use changes
#
LSST_EUPS_VERSION=${LSST_EUPS_VERSION:-2.1.5}
LSST_EUPS_GITREV=${LSST_EUPS_GITREV:-}
LSST_EUPS_GITREPO=${LSST_EUPS_GITREPO:-https://github.com/RobertLuptonTheGood/eups.git}
LSST_EUPS_TARURL=${LSST_EUPS_TARURL:-https://github.com/RobertLuptonTheGood/eups/archive/${LSST_EUPS_VERSION}.tar.gz}
LSST_EUPS_PKGROOT_BASE_URL=${LSST_EUPS_PKGROOT_BASE_URL:-https://eups.lsst.codes/stack}
LSST_EUPS_USE_TARBALLS=${LSST_EUPS_USE_TARBALLS:-false}
LSST_EUPS_USE_EUPSPKG=${LSST_EUPS_USE_EUPSPKG:-true}
# force Python 3
LSST_PYTHON_VERSION=3
LSST_MINICONDA_VERSION=${LSST_MINICONDA_VERSION:-4.7.10}
# this git ref controls which set of conda packages are used to initialize the
# the default conda env defined in scipipe_conda_env git package (RFC-553).
LSST_SPLENV_REF=${LSST_SPLENV_REF:-${LSST_LSSTSW_REF:-4d7b902}}
LSST_MINICONDA_BASE_URL=${LSST_MINICONDA_BASE_URL:-https://repo.continuum.io/miniconda}
LSST_CONDA_CHANNELS=${LSST_CONDA_CHANNELS:-}
LSST_CONDA_ENV_NAME=${LSST_CONDA_ENV_NAME:-lsst-scipipe-${LSST_SPLENV_REF}}
# these optional env vars may be used by functions but should be considered
# unstable and for internal testing only.
#
# LSST_OS_FAMILY
# LSST_OS_RELEASE
# LSST_PLATFORM
# LSST_COMPILER
LSST_HOME="$PWD"
# the canonical source of this script
NEWINSTALL_URL="https://raw.githubusercontent.com/lsst/lsst/master/scripts/newinstall.sh"
#
# removing leading/trailing whitespace from a string
#
#http://stackoverflow.com/questions/369758/how-to-trim-whitespace-from-a-bash-variable#12973694
#
n8l::trim() {
local var="$*"
# remove leading whitespace characters
var="${var#"${var%%[![:space:]]*}"}"
# remove trailing whitespace characters
var="${var%"${var##*[![:space:]]}"}"
echo -n "$var"
}
n8l::print_error() {
>&2 echo -e "$@"
}
n8l::fail() {
local code=${2:-1}
[[ -n $1 ]] && n8l::print_error "$1"
# shellcheck disable=SC2086
exit $code
}
#
# create/update a *relative* symlink, in the basedir of the target. An existing
# file or directory will be *stomped on*.
#
n8l::ln_rel() {
local link_target=${1?link target is required}
local link_name=${2?link name is required}
target_dir=$(dirname "$link_target")
target_name=$(basename "$link_target")
( set -e
cd "$target_dir"
if [[ $(readlink "$target_name") != "$link_name" ]]; then
# at least "ln (GNU coreutils) 8.25" will not change an abs symlink to be
# rel, even with `-f`
rm -rf "$link_name"
ln -sf "$target_name" "$link_name"
fi
)
}
n8l::has_cmd() {
local command=${1?command is required}
command -v "$command" > /dev/null 2>&1
}
# check that all required cli programs are present
n8l::require_cmds() {
local cmds=("${@?at least one command is required}")
local errors=()
# accumulate a list of all missing commands before failing to reduce end-user
# install/retry cycles
for c in "${cmds[@]}"; do
if ! n8l::has_cmd "$c"; then
errors+=("prog: ${c} is required")
fi
done
if [[ ${#errors[@]} -ne 0 ]]; then
for e in "${errors[@]}"; do
n8l::print_error "$e"
done
n8l::fail
fi
}
n8l::fmt() {
fmt -w 78
}
n8l::usage() {
n8l::fail "$(cat <<-EOF
usage: newinstall.sh [-b] [-f] [-h] [-n] [-3|-2] [-t|-T] [-s|-S] [-p]
[-P <path-to-python>]
-b -- Run in batch mode. Do not ask any questions and install all extra
packages.
-c -- Attempt to continue a previously failed install.
-n -- No-op. Go through the motions but echo commands instead of running
them.
-P [PATH_TO_PYTHON] -- Use a specific python interpreter for EUPS.
-2 -- use Python 2 (no longer supported -- fatal error)
-3 -- Use Python 3 if the script is installing its own Python. (default)
-t -- Use pre-compiled EUPS "tarball" packages, if available.
-T -- DO NOT use pre-compiled EUPS "tarball" packages.
-s -- Use EUPS source "eupspkg" packages, if available.
-S -- DO NOT use EUPS source "eupspkg" packages.
-p -- Preserve EUPS_PKGROOT environment variable.
-h -- Display this help message.
EOF
)"
}
n8l::miniconda_slug() {
echo "miniconda${LSST_PYTHON_VERSION}-${LSST_MINICONDA_VERSION}"
}
n8l::python_env_slug() {
echo "$(n8l::miniconda_slug)-${LSST_SPLENV_REF}"
}
n8l::eups_slug() {
local eups_slug=$LSST_EUPS_VERSION
if [[ -n $LSST_EUPS_GITREV ]]; then
eups_slug=$LSST_EUPS_GITREV
fi
echo "$eups_slug"
}
n8l::eups_base_dir() {
echo "${LSST_HOME}/eups"
}
n8l::eups_dir() {
echo "$(n8l::eups_base_dir)/$(n8l::eups_slug)"
}
#
# version the eups product installation path using the *complete* python
# environment
#
# XXX this will probably need to be extended to include the compiler used for
# binary tarballs
#
n8l::eups_path() {
echo "${LSST_HOME}/stack/$(n8l::python_env_slug)"
}
n8l::parse_args() {
local OPTIND
local opt
while getopts cbhnP:32tTsSp opt; do
case $opt in
b)
BATCH_FLAG=true
;;
c)
CONT_FLAG=true
;;
n)
NOOP_FLAG=true
;;
P)
EUPS_PYTHON=$OPTARG
;;
2)
n8l::fail 'Python 2.x is no longer supported.'
;;
3)
# noop
;;
t)
LSST_EUPS_USE_TARBALLS=true
;;
T)
LSST_EUPS_USE_TARBALLS=false
;;
s)
LSST_EUPS_USE_EUPSPKG=true
;;
S)
LSST_EUPS_USE_EUPSPKG=false
;;
p)
PRESERVE_EUPS_PKGROOT_FLAG=true
;;
h|*)
n8l::usage
;;
esac
done
shift $((OPTIND - 1))
}
#
# determine the osfamily and release string
#
# where osfamily is one of:
# - redhat (includes centos & fedora)
# - osx (Darwin)
#
# where release is:
# - on osx, the release string is the complete version (Eg. 10.11.6)
# - on redhat, the release string is only the major version number (Eg. 7)
#
# osfamily string is returned in the variable name passed as $1
# release string is returned in the variable name passed as $2
#
n8l::sys::osfamily() {
local __osfamily_result=${1?osfamily result variable is required}
local __release_result=${2?release result variable is required}
local __debug=$3
local __osfamily
local __release
case $(uname -s) in
Linux*)
local release_file='/etc/redhat-release'
if [[ ! -e $release_file ]]; then
[[ $__debug == true ]] && n8l::print_error "unknown osfamily"
fi
__osfamily="redhat"
# capture only major version number because "posix character classes"
if [[ ! $(<"$release_file") =~ release[[:space:]]*([[:digit:]]+) ]]; then
[[ $__debug == true ]] && n8l::print_error "unable to find release string"
fi
__release="${BASH_REMATCH[1]}"
;;
Darwin*)
__osfamily="osx"
if ! release=$(sw_vers -productVersion); then
[[ $__debug == true ]] && n8l::print_error "unable to find release string"
fi
__release=$(n8l::trim "$release")
;;
*)
[[ $__debug == true ]] && n8l::print_error "unknown osfamily"
;;
esac
# bash 3.2 does not support `declare -g`
eval "$__osfamily_result=$__osfamily"
eval "$__release_result=$__release"
}
#
# return a single string representation of a platform.
# Eg. el7
#
# XXX cc lookup should be a seperate function if/when there is more than one #
# compiler option per platform.
#
n8l::sys::platform() {
local __osfamily=${1?osfamily is required}
local __release=${2?release is required}
local __platform_result=${3?platform result variable is required}
local __target_cc_result=${4?target_cc result variable is required}
local __debug=$5
local __platform
local __target_cc
case $__osfamily in
redhat)
case $__release in
6)
__platform=el6
__target_cc=devtoolset-8
;;
7)
__platform=el7
__target_cc=devtoolset-8
;;
*)
[[ $__debug == true ]] && n8l::print_error "unsupported release: $__release"
;;
esac
;;
osx)
case $__release in
# XXX bash 3.2 on osx does not support case fall-through
10.9.* | 10.1?.* | 10.1?)
__platform=10.9
__target_cc=clang-1000.10.44.4
;;
*)
[[ $__debug == true ]] && n8l::print_error "unsupported release: $__release"
;;
esac
;;
*)
[[ $__debug == true ]] && n8l::print_error "unsupported osfamily: $__osfamily"
;;
esac
# bash 3.2 does not support `declare -g`
eval "$__platform_result=$__platform"
eval "$__target_cc_result=$__target_cc"
}
# http://stackoverflow.com/questions/1527049/join-elements-of-an-array#17841619
n8l::join() {
local IFS=${1?separator is required}
shift
echo -n "$*"
}
n8l::default_eups_pkgroot() {
local use_eupspkg=${1:-true}
local use_tarballs=${2:-false}
local osfamily
local release
local platform
local target_cc
declare -a roots
local base_url=$LSST_EUPS_PKGROOT_BASE_URL
local pyslug
pyslug=$(n8l::python_env_slug)
# only probe system *IF* tarballs are desired
if [[ $use_tarballs == true ]]; then
n8l::sys::osfamily osfamily release
fi
osfamily=${LSST_OS_FAMILY:-$osfamily}
release=${LSST_OS_RELEASE:-$release}
if [[ -n $osfamily && -n $release ]]; then
n8l::sys::platform "$osfamily" "$release" platform target_cc
fi
platform=${LSST_PLATFORM:-$platform}
target_cc=${LSST_COMPILER:-$target_cc}
if [[ -n $base_url ]]; then
if [[ -n $platform && -n $target_cc ]]; then
# binary "tarball" pkgroot
roots+=( "${base_url}/${osfamily}/${platform}/${target_cc}/${pyslug}" )
fi
if [[ $use_eupspkg == true ]]; then
roots+=( "${base_url}/src" )
fi
fi
echo -n "$(n8l::join '|' "${roots[@]}")"
}
# XXX this sould be split into two functions that echo values. This would
# allow them to be called directly and remove the usage of the global
# variables.
n8l::config_curl() {
# Prefer system curl; user-installed ones sometimes behave oddly
if [[ -x /usr/bin/curl ]]; then
CURL=${CURL:-/usr/bin/curl}
else
CURL=${CURL:-curl}
fi
# disable curl progress meter unless running under a tty -- this is intended
# to reduce the amount of console output when running under CI
CURL_OPTS='-#'
if [[ ! -t 1 ]]; then
CURL_OPTS='-sS'
fi
}
n8l::miniconda::install() {
local py_ver=${1?python version is required}
local mini_ver=${2?miniconda version is required}
local prefix=${3?prefix is required}
local miniconda_base_url=${4:-https://repo.continuum.io/miniconda}
case $(uname -s) in
Linux*)
ana_platform="Linux-x86_64"
;;
Darwin*)
ana_platform="MacOSX-x86_64"
;;
*)
n8l::fail "Cannot install miniconda: unsupported platform $(uname -s)"
;;
esac
# the miniconda installer internally uses bzip2
n8l::require_cmds bzip2
miniconda_file_name="Miniconda${py_ver}-${mini_ver}-${ana_platform}.sh"
echo "::: Deploying ${miniconda_file_name}"
(
set -Eeo pipefail
# Create a temporary directory to download the installation script into
tmpdir=$(mktemp -d -t miniconda-XXXXXXXX)
tmpfile="$tmpdir/${miniconda_file_name}"
# attempt to be a good citizen and not leave tmp files laying around
# after either a normal exit or an error condition
# shellcheck disable=SC2064
trap "{ rm -rf $tmpdir; }" EXIT
$cmd "$CURL" "$CURL_OPTS" -L \
"${miniconda_base_url}/${miniconda_file_name}" \
--output "$tmpfile"
$cmd bash "$tmpfile" -b -p "$prefix"
)
}
# configure alt conda channel(s)
n8l::miniconda::config_channels() {
local channels=${1?channels is required}
n8l::require_cmds conda
# remove any previously configured non-default channels
# XXX allowed to fail
$cmd conda config --remove-key channels || true
for c in $channels; do
$cmd conda config --add channels "$c"
done
# remove the default channels
$cmd conda config --remove channels defaults
$cmd conda config --show
}
# Install packages on which the stack is known to depend
n8l::miniconda::lsst_env() {
local py_ver=${1?python version is required}
local ref=${2?lsstsw git ref is required}
n8l::require_cmds conda activate
case $(uname -s) in
Linux*)
conda_packages="conda${py_ver}_packages-linux-64.yml"
;;
Darwin*)
conda_packages="conda${py_ver}_packages-osx-64.yml"
;;
*)
n8l::fail "Cannot configure miniconda env: unsupported platform $(uname -s)"
;;
esac
local baseurl="https://raw.githubusercontent.com/lsst/scipipe_conda_env/${ref}/etc/"
local tmpfile
(
set -Eeo pipefail
tmpfile=$(mktemp -t "${conda_packages//X/_}.XXXXXXXX")
tmpfile="${tmpfile}.yml"
# attempt to be a good citizen and not leave tmp files laying around
# after either a normal exit or an error condition
# shellcheck disable=SC2064
trap "{ rm -rf $tmpfile; }" EXIT
$cmd "$CURL" "$CURL_OPTS" \
-L \
"${baseurl}/${conda_packages}" \
--output "$tmpfile"
args=()
args+=('env' 'update')
args+=('--name' "$LSST_CONDA_ENV_NAME")
# disable the conda install progress bar when not attached to a tty. Eg.,
# when running under CI
if [[ ! -t 1 ]]; then
args+=("--quiet")
fi
args+=("--file" "$tmpfile")
$cmd conda "${args[@]}"
)
# shellcheck disable=SC1091
source activate "$LSST_CONDA_ENV_NAME"
# report packages in the current conda env
conda env export
}
#
# Warn if there's a different version on the server
#
# Don't make this fatal, it should still work for developers who are hacking
# their copy.
#
# Don't attempt to run diff when the script has been piped into the shell
#
n8l::up2date_check() {
local amidiff
diff \
--brief "$0" \
<($CURL "$CURL_OPTS" -L "$NEWINSTALL_URL") > /dev/null \
&& amidiff=$? || amidiff=$?
case $amidiff in
0) ;;
1)
n8l::print_error "$({ cat <<-EOF
!!! This script differs from the official version on the distribution
server. If this is not intentional, get the current version from here:
${NEWINSTALL_URL}
EOF
} | n8l::fmt)"
;;
2|*)
n8l::print_error "$({ cat <<-EOF
!!! There is an error in comparing the official version with the local
copy of the script.
EOF
} | n8l::fmt)"
;;
esac
}
# Discuss the state of Git.
# XXX should probably fail if git version is insufficient under batch mode.
n8l::git_check() {
if n8l::has_cmd git; then
local gitvernum
gitvernum=$(git --version | cut -d\ -f 3)
local gitver
# shellcheck disable=SC2046 disable=SC2183
gitver=$(printf "%02d-%02d-%02d\\n" \
$(echo "$gitvernum" | cut -d. -f1-3 | tr . ' '))
fi
if [[ $gitver < 01-08-04 ]]; then
if [[ $BATCH_FLAG != true ]]; then
{ cat <<-EOF
Detected $(git --version).
The git version control system is frequently used with LSST software.
While the LSST stack should build and work even in the absence of git, we
don not regularly run and test it in such environments. We therefore
recommend you have at least git 1.8.4 installed with your normal
package manager.
EOF
} | n8l::fmt
while true; do
read -r -p "Would you like to try continuing without git? " yn
case $yn in
[Yy]* )
echo "Continuing without git"
break
;;
[Nn]* )
echo "Okay install git and rerun the script."
exit
break;
;;
* ) echo "Please answer yes or no.";;
esac
done
fi
else
echo "Detected $(git --version). OK."
fi
}
n8l::pyverok() {
local min_major=${1?min_major is required}
local min_minor=${2?min_minor is required}
local py_interp=${3:-python}
$py_interp -c "import sys
rmaj=${min_major}
rmin=${min_minor}
vmaj = sys.version_info[0]
vmin = sys.version_info[1]
if (vmaj >= rmaj) and (vmin >= rmin):
sys.exit(0)
else:
sys.exit(1)"
}
#
# Test/warn about Python versions, offer to get miniconda if not supported.
# LSST currently mandates specific versions of Python. We assume that the
# python in PATH is the python that will be used to build the stack if
# miniconda is not installed.
#
n8l::python_check() {
# Check the version by running a small Python program (taken from the Python
# EUPS package) XXX this will break if python is not in $PATH
local py_interp=python
local min_major=3
local min_minor=6
local has_python=false
local pyok=false
if n8l::has_cmd $py_interp; then
has_python=true
if n8l::pyverok $min_major $min_minor $py_interp; then
pyok=true
fi
fi
if [[ $pyok != true ]]; then
if [[ $has_python == true ]]; then
{ cat <<-EOF
LSST stack requires Python >= ${min_major}.${min_minor}; you seem to
have $($py_interp -V 2>&1) on your path ($(command -v $py_interp)).
EOF
} | n8l::fmt
else
{ cat <<-EOF
Unable to locate python.
Please set up a compatible python interpreter, prepend it to your PATH,
and rerun this script. Alternatively, we can set up the Miniconda Python
distribution for you.
EOF
} | n8l::fmt
fi
fi
{ cat <<-EOF
In addition to Python >= ${min_major}.${min_minor}, some LSST packages
depend on recent versions of numpy, matplotlib, and scipy. If you do not
have all of these, the installation may fail. Using the Miniconda Python
distribution will ensure all these are set up.
EOF
} | n8l::fmt
while true; do
read -r -p "$({ cat <<-EOF
Would you like us to install the Miniconda Python distribution (if
unsure, say yes)?
EOF
} | n8l::fmt)" yn
case $yn in
[Yy]* )
WITH_MINICONDA=true
break
;;
[Nn]* )
if [[ $pyok != true ]]; then
{ cat <<-EOF
Thanks. After you install the required version of Python and the
required modules, rerun this script to continue the installation.
EOF
} | n8l::fmt
n8l::fail
fi
break;
;;
* ) echo "Please answer yes or no.";;
esac
done
}
#
# boostrap a complete miniconda based env that includes configuring conda
# channels and installation of the conda packages.
#
# this appears to be a bug in shellcheck
# shellcheck disable=SC2120
n8l::miniconda::bootstrap() {
local py_ver=${1?python version is required}
local mini_ver=${2?miniconda version is required}
local prefix=${3?prefix is required}
local __miniconda_path_result=${4?__miniconda_path_result is required}
local miniconda_base_url=${5:-https://repo.continuum.io/miniconda}
local splenv_ref=$6
local conda_channels=$7
local miniconda_base_path="${prefix}/python"
local miniconda_path
miniconda_path="${miniconda_base_path}/$(n8l::miniconda_slug)"
local miniconda_path_old
miniconda_path_old="${prefix}/$(n8l::miniconda_slug)"
# remove old unnested miniconda -- the install has hard coded shebangs
if [[ -e $miniconda_path_old ]]; then
rm -rf "$miniconda_path_old"
fi
if [[ ! -e $miniconda_path ]]; then
n8l::miniconda::install \
"$py_ver" \
"$mini_ver" \
"$miniconda_path" \
"$miniconda_base_url"
fi
# update miniconda current symlink
n8l::ln_rel "$miniconda_path" current
export PATH="${miniconda_path}/bin:${PATH}"
if [[ -n $conda_channels ]]; then
n8l::miniconda::config_channels "$conda_channels"
fi
if [[ -n $splenv_ref ]]; then
n8l::miniconda::lsst_env "$py_ver" "$splenv_ref"
fi
# bash 3.2 does not support `declare -g`
eval "$__miniconda_path_result=$miniconda_path"
}
#
# $EUPS_PYTHON is the Python used to install/run EUPS. It can be any Python >=
# v2.6
#
# XXX this function should be broken up to enable better unit testing.
n8l::install_eups() {
if [[ ! -x $EUPS_PYTHON ]]; then
n8l::fail "$({ cat <<-EOF
Cannot find or execute '${EUPS_PYTHON}'. Please set the EUPS_PYTHON
environment variable or use the -P option to point to a functioning
Python >= 2.6 interpreter and rerun.
EOF
} | n8l::fmt)"
fi
local min_major=2
local min_minor=6
if ! n8l::pyverok "$min_major" "$min_minor" "$EUPS_PYTHON"; then
n8l::fail "$({ cat <<-EOF
EUPS requires Python ${min_major}.${min_minor} or newer; we are using
$("$EUPS_PYTHON" -V 2>&1) from ${EUPS_PYTHON}. Please set up a
compatible python interpreter using the EUPS_PYTHON environment variable
or the -P command line option.
EOF
} | n8l::fmt)"
fi
if [[ $EUPS_PYTHON != /usr/bin/python ]]; then
echo "Using python at ${EUPS_PYTHON} to install EUPS"
fi
# if there is an existing, unversioned install, renamed it to "legacy"
if [[ -e "$(n8l::eups_base_dir)/Release_Notes" ]]; then
local eups_legacy_dir
eups_legacy_dir="$(n8l::eups_base_dir)/legacy"
local eups_tmp_dir="${LSST_HOME}/eups-tmp"
echo "Moving old EUPS to ${eups_legacy_dir}"
mv "$(n8l::eups_base_dir)" "$eups_tmp_dir"
mkdir -p "$(n8l::eups_base_dir)"
mv "$eups_tmp_dir" "$eups_legacy_dir"
fi
echo -n "Installing EUPS ($(n8l::eups_slug))... "
# remove previous install
if [[ -e $(n8l::eups_dir) ]]; then
chmod -R +w "$(n8l::eups_dir)"
rm -rf "$(n8l::eups_dir)"
fi
local eups_build_dir="$LSST_HOME/_build"
# make is absent from many minimal linux images
n8l::require_cmds make "${CC:-cc}" which perl awk sed
if ! ( set -Eeo pipefail
mkdir "$eups_build_dir"
cd "$eups_build_dir"
if [[ -z $LSST_EUPS_GITREV ]]; then
# Download tarball from github
$cmd "$CURL" "$CURL_OPTS" -L "$LSST_EUPS_TARURL" | tar xzvf -
$cmd cd "eups-${LSST_EUPS_VERSION}"
else
# Clone from git repository
$cmd git clone "$EUPS_GITREPO" eups
$cmd cd eups
$cmd git checkout "$LSST_EUPS_GITREV"
fi
$cmd ./configure \
--prefix="$(n8l::eups_dir)" \
--with-eups="$(n8l::eups_path)" \
--with-python="$EUPS_PYTHON"
$cmd make install
) > eupsbuild.log 2>&1 ; then
n8l::fail "$(cat <<-EOF
FAILED.
"See log in eupsbuild.log"
EOF
)"
fi
# symlinks should be relative to support relocation of the newinstall root
# update $EUPS_DIR current symlink
n8l::ln_rel "$(n8l::eups_dir)" current
# update EUPS_PATH current symlink
n8l::ln_rel "$(n8l::eups_path)" current
echo " done."
}
n8l::problem_vars() {
local problems=(
EUPS_PATH
EUPS_PKGROOT
REPOSITORY_PATH
)
local found=()
for v in ${problems[*]}; do
if [[ -n ${!v+1} ]]; then
found+=("$v")
fi
done
echo -n "${found[@]}"
}
n8l::problem_vars_check() {
local problems=()
IFS=" " read -r -a problems <<< "$(n8l::problem_vars)"
if [[ ${#problems} -gt 0 ]]; then
n8l::print_error "$({ cat <<-EOF
WARNING: the following environment variables are defined that will affect
the operation of the LSST build tooling.
EOF
} | n8l::fmt)"
for v in ${problems[*]}; do
n8l::print_error "${v}=\"${!v}\""
done
n8l::print_error "$(cat <<-EOF
It is recommended that they are undefined before running this script.
unset ${problems[*]}
EOF
)"
return 1
fi
}
n8l::generate_loader_bash() {
local file_name=${1?file_name is required}
local eups_pkgroot=${2?eups_pkgroot is required}
local miniconda_path=$3
if [[ -n $miniconda_path ]]; then
local cmd_setup_miniconda
cmd_setup_miniconda="$(cat <<-EOF
export PATH="${miniconda_path}/bin:\${PATH}"
export LSST_CONDA_ENV_NAME=\${LSST_CONDA_ENV_NAME:-${LSST_CONDA_ENV_NAME}}
# shellcheck disable=SC1091
source activate "\$LSST_CONDA_ENV_NAME"
EOF
)"
fi
# shellcheck disable=SC2094
cat > "$file_name" <<-EOF
# This script is intended to be used with bash to load the minimal LSST
# environment
# Usage: source $(basename "$file_name")
${cmd_setup_miniconda}
LSST_HOME="\$( cd "\$( dirname "\${BASH_SOURCE[0]}" )" && pwd )"
# Bootstrap EUPS
EUPS_DIR="\${LSST_HOME}/eups/$(n8l::eups_slug)"
source "\${EUPS_DIR}/bin/setups.sh"
export -f setup
export -f unsetup
export EUPS_PKGROOT=\${EUPS_PKGROOT:-$eups_pkgroot}
EOF
}
n8l::generate_loader_csh() {
local file_name=${1?file_name is required}
local eups_pkgroot=${2?eups_pkgroot is required}
local miniconda_path=$3
if [[ -n $miniconda_path ]]; then
local cmd_setup_miniconda
cmd_setup_miniconda="$(cat <<-EOF
setenv PATH "${miniconda_path}/bin:\$PATH"
if ( ! \$?LSST_CONDA_ENV_NAME ) then
set LSST_CONDA_ENV_NAME="${LSST_CONDA_ENV_NAME}"
endif
source "${miniconda_path}/etc/profile.d/conda.csh"
conda activate "\$LSST_CONDA_ENV_NAME"
EOF
)"
fi
# shellcheck disable=SC2094
cat > "$file_name" <<-EOF
# This script is intended to be used with (t)csh to load the minimal LSST
# environment
# Usage: source $(basename "$file_name")
${cmd_setup_miniconda}
set LSST_HOME = \`dirname \$0\`
set LSST_HOME = \`cd \${LSST_HOME} && pwd\`
# Bootstrap EUPS
set EUPS_DIR = "\${LSST_HOME}/eups/$(n8l::eups_slug)"
source "\${EUPS_DIR}/bin/setups.csh"
if ( ! \${?EUPS_PKGROOT} ) then
setenv EUPS_PKGROOT "$eups_pkgroot"
endif
EOF
}
n8l::generate_loader_ksh() {
local file_name=${1?file_name is required}
local eups_pkgroot=${2?eups_pkgroot is required}
local miniconda_path=$3
if [[ -n $miniconda_path ]]; then
# XXX untested
local cmd_setup_miniconda
cmd_setup_miniconda="$(cat <<-EOF
export PATH="${miniconda_path}/bin:\${PATH}"
export LSST_CONDA_ENV_NAME=\${LSST_CONDA_ENV_NAME:-${LSST_CONDA_ENV_NAME}}
# shellcheck disable=SC1091
source activate "\$LSST_CONDA_ENV_NAME"
EOF
)"
fi
# shellcheck disable=SC2094
cat > "$file_name" <<-EOF
# This script is intended to be used with ksh to load the minimal LSST
# environment
# Usage: source $(basename "$file_name")
${cmd_setup_miniconda}
LSST_HOME="\$( cd "\$( dirname "\${.sh.file}" )" && pwd )"
# Bootstrap EUPS
EUPS_DIR="\${LSST_HOME}/eups/$(n8l::eups_slug)"
source "\${EUPS_DIR}/bin/setups.sh"
export EUPS_PKGROOT=\${EUPS_PKGROOT:-$eups_pkgroot}
EOF
}
n8l::generate_loader_zsh() {
local file_name=${1?file_name is required}
local eups_pkgroot=${2?eups_pkgroot is required}
local miniconda_path=$3
if [[ -n $miniconda_path ]]; then
# XXX untested
local cmd_setup_miniconda
cmd_setup_miniconda="$(cat <<-EOF
export PATH="${miniconda_path}/bin:\${PATH}"
export LSST_CONDA_ENV_NAME=\${LSST_CONDA_ENV_NAME:-${LSST_CONDA_ENV_NAME}}
source activate "\$LSST_CONDA_ENV_NAME"
EOF
)"
fi
# shellcheck disable=SC2094
cat > "$file_name" <<-EOF
# This script is intended to be used with zsh to load the minimal LSST
# environment
# Usage: source $(basename "$file_name")
${cmd_setup_miniconda}
LSST_HOME=\`dirname "\$0:A"\`
# Bootstrap EUPS
EUPS_DIR="\${LSST_HOME}/eups/$(n8l::eups_slug)"
source "\${EUPS_DIR}/bin/setups.zsh"
export EUPS_PKGROOT=\${EUPS_PKGROOT:-$eups_pkgroot}
EOF
}
n8l::create_load_scripts() {
local prefix=${1?prefix is required}
local eups_pkgroot=${2?eups_pkgroot is required}
local miniconda_path=$3
for sfx in bash ksh csh zsh; do
echo -n "Creating startup scripts (${sfx}) ... "
# shellcheck disable=SC2086
n8l::generate_loader_$sfx \
"${prefix}/loadLSST.${sfx}" \
"$eups_pkgroot" \
$miniconda_path
echo "done."
done
}
n8l::print_greeting() {
cat <<-EOF
Bootstrap complete. To continue installing (and to use) the LSST stack type
one of:
source "${LSST_HOME}/loadLSST.bash" # for bash
source "${LSST_HOME}/loadLSST.csh" # for csh
source "${LSST_HOME}/loadLSST.ksh" # for ksh
source "${LSST_HOME}/loadLSST.zsh" # for zsh
Individual LSST packages may now be installed with the usual \`eups distrib
install\` command. For example, to install the science pipeline elements
of the LSST stack, use:
eups distrib install lsst_apps
Next, read the documentation at:
https://pipelines.lsst.io
and feel free to ask any questions via the LSST Community forum:
https://community.lsst.org/c/support
Thanks!
-- The LSST Software Teams
http://dm.lsst.org/
EOF
}
#
# test to see if script is being sourced or executed. Note that this function
# will work correctly when the source is being piped to a shell. `Ie., cat
# newinstall.sh | bash -s`
#
# See: https://stackoverflow.com/a/12396228
#
n8l::am_i_sourced() {
if [ "${FUNCNAME[1]}" = source ]; then
return 0
else
return 1
fi
}
#
# script main
#
n8l::main() {
n8l::config_curl
CONT_FLAG=false
BATCH_FLAG=false
NOOP_FLAG=false
PRESERVE_EUPS_PKGROOT_FLAG=false
n8l::parse_args "$@"
{ cat <<-EOF
LSST Software Stack Builder
=======================================================================
EOF
} | n8l::fmt
# If no-op, prefix every install command with echo
if [[ $NOOP_FLAG == true ]]; then
cmd="echo"
echo "!!! -n flag specified, no install commands will be really executed"
else
cmd=""
fi
# Refuse to run from a non-empty directory
if [[ $CONT_FLAG == false ]]; then
if [[ ! -z $(ls) && ! $(ls) == newinstall.sh ]]; then
n8l::fail "$({ cat <<-EOF
Please run this script from an empty directory. The LSST stack will be
installed into it.
EOF
} | n8l::fmt)"
fi
fi
# Warn if there's a different version on the server
if [[ -n $0 && $0 != bash ]]; then
n8l::up2date_check
fi
if [[ $BATCH_FLAG != true ]]; then
n8l::problem_vars_check
fi
n8l::git_check
# always use miniconda when in batch mode
if [[ $BATCH_FLAG == true ]]; then
WITH_MINICONDA=true
else
n8l::python_check
fi
# Bootstrap miniconda (optional)
# Note that this will add miniconda to the path
if [[ $WITH_MINICONDA == true ]]; then
# this appears to be a bug in shellcheck
# shellcheck disable=SC2119
n8l::miniconda::bootstrap \
"$LSST_PYTHON_VERSION" \
"$LSST_MINICONDA_VERSION" \
"$LSST_HOME" \
'MINICONDA_PATH' \
"$LSST_MINICONDA_BASE_URL" \
"$LSST_SPLENV_REF" \
"$LSST_CONDA_CHANNELS"
fi
# By default we use the PATH Python to bootstrap EUPS. Set $EUPS_PYTHON to
# override this or use the -P command line option. $EUPS_PYTHON is used to
# install and run EUPS and will not necessarily be the python in the path
# being used to build the stack itself.
EUPS_PYTHON=${EUPS_PYTHON:-$(command -v python)}
if [[ $PRESERVE_EUPS_PKGROOT_FLAG == true ]]; then
EUPS_PKGROOT=${EUPS_PKGROOT:-$(
n8l::default_eups_pkgroot \
$LSST_EUPS_USE_EUPSPKG \
$LSST_EUPS_USE_TARBALLS
)}
else
EUPS_PKGROOT=$(
n8l::default_eups_pkgroot \
$LSST_EUPS_USE_EUPSPKG \
$LSST_EUPS_USE_TARBALLS
)
fi
n8l::print_error "Configured EUPS_PKGROOT: ${LSST_EUPS_PKGROOT}"
# Install EUPS
n8l::install_eups
# Create the environment loader scripts
# shellcheck disable=SC2153
# it can not know that MINICONDA_PATH is created by eval
# shellcheck disable=SC2086
n8l::create_load_scripts \
"$LSST_HOME" \
"$EUPS_PKGROOT" \
$MINICONDA_PATH
# Helpful message about what to do next
n8l::print_greeting
}
#
# support being sourced as a lib or executed
#
if ! n8l::am_i_sourced; then
n8l::main "$@"
fi
# vim: tabstop=2 shiftwidth=2 noexpandtab
You can’t perform that action at this time.