-
François LAURENT authoredFrançois LAURENT authored
install.sh 15.07 KiB
#!/usr/bin/env bash
for flag in "$@"; do
if [ "$flag" = "-h" -o "$flag" = "--help" ]; then
echo "Command-line installer for LarvaTagger"
echo
echo "Usage:"
echo " $0"
echo " WITH_BACKEND=1 $0"
echo " WITH_BACKEND=1 $0 --legacy"
echo " $0 --with-default-backend"
echo " $0 --with-backend --legacy"
echo " $0 --uninstall"
echo " $0 --help"
echo
echo "The legacy installation path for the MaggotUBA-based tagger relies"
echo "on Python3.8 and Torch1."
echo "The current default relies on Python3.11 and Torch2."
echo "Other environment variables can be set, similarly to WITH_BACKEND,"
echo "to control the script's behavior:"
echo " variable default value"
echo " BIN_DIR ~/.local/bin"
echo " LARVATAGGER_PATH ~/.local/share/larvatagger"
echo " JULIA_CHANNEL lts"
echo " JULIA_VERSION 1.10"
echo " PYTHON_VERSION 3.11 (3.8 if --legacy)"
echo " MAGGOTUBA_CORE_BRANCH main"
echo " MAGGOTUBA_ADAPTER_BRANCH torch2 (main if --legacy)"
echo " TAGGINGBACKENDS_BRANCH main"
echo " PLANARLARVAE_BRANCH main"
echo " LARVATAGGER_BRANCH main"
exit 0
fi
done
[ -d "`pwd`" ] || cd
if [ -z "$BIN_DIR" ]; then
BIN_DIR=~/.local/bin
else
echo "Using environment variable: BIN_DIR= $BIN_DIR"
echo "Only ~/.local/bin is fully supported at the moment"
fi
if [ -z "$LARVATAGGER_PATH" ]; then
LARVATAGGER_PATH=~/.local/share/larvatagger
else
echo "Using environment variable: LARVATAGGER_PATH= $LARVATAGGER_PATH"
fi
if [ "$1" = "--uninstall" ]; then
for pkg in MaggotUBA TaggingBackends; do
if [ -d "$LARVATAGGER_PATH/$pkg" ]; then
env=$(cd "$LARVATAGGER_PATH/$pkg" && poetry env info -p 2>/dev/null)
[ -d "$env" ] && rm -rf "$env"
fi
done
rm -rf "$BIN_DIR/larvatagger"
rm -rf "$LARVATAGGER_PATH"
# testing only; deletes Poetry, PyEnv and JuliaUp, and does not check beforehands
# whether these dependencies were installed by the present script or not
if [ "$2" = "--full" ]; then
PYTHON="python3"
if [[ "`python3 -V`" =~ "Python 3.6" ]] && command -v python3.8 &>/dev/null; then
# issue on Maestro
PYTHON="python3.8"
fi
command -v poetry &>/dev/null && curl -sSL https://install.python-poetry.org | $PYTHON - --uninstall
command -v pyenv &>/dev/null && rm -rf $(pyenv root)
command -v juliaup &>/dev/null && juliaup self uninstall
rm -rf ~/.juliaup
# TODO: clean up .bash_profile for pyenv-related stuff, .bashrc/.zshrc for PATH manipulations, and restart the shell
rm -rf ~/.julia
fi
else
# former default:
PYTHON_VERSION=3.8
# the internal_<VAR> variables need to be set non-empty only if
# the corresponding <VAR> variable is non-empty; they are used to
# determine whether or not to report externally sourced variables
internal_WITH_BACKEND=
internal_MAGGOTUBA_ADAPTER_BRANCH=
internal_MAGGOTUBA_ADAPTER_FREE_DEPENDENCIES=
internal_LEGACY=
internal_WITH_DEFAULT_BACKEND=
# primary use cases:
# WITH_BACKEND=1 scripts/install.sh
# WITH_BACKEND=1 scripts/install.sh --legacy
# scripts/install.sh --with-default-backend
# scripts/install.sh --with-backend
# scripts/install.sh --with-backend --experimental
# scripts/install.sh --with-backend --legacy
for arg in "$@"; do
if [ "$arg" = "--with-default-backend" ]; then
WITH_BACKEND=1
internal_WITH_BACKEND=1
internal_WITH_DEFAULT_BACKEND=1
if [ "$internal_LEGACY" = "1" ]; then
echo "Ignoring --legacy; pass --with-backend --legacy instead"
internal_LEGACY=0
fi
break
elif [ "$arg" = "--with-backend" ]; then
WITH_BACKEND=1
internal_WITH_BACKEND=1
elif [ "$arg" = "--experimental" ]; then
echo "The --experimental flag is deprecated and is now default"
internal_LEGACY=0
elif [ "$arg" = "--legacy" ]; then
internal_LEGACY=1
MAGGOTUBA_CORE_BRANCH=
# former default (empty) falls back to main
MAGGOTUBA_ADAPTER_BRANCH=
elif [ "$arg" = "--free-python-dependencies" ]; then
internal_MAGGOTUBA_ADAPTER_FREE_DEPENDENCIES=1
elif [ "$arg" = "--lock-python-dependencies" ]; then
internal_MAGGOTUBA_ADAPTER_FREE_DEPENDENCIES=0
fi
done
if [ "$WITH_BACKEND" = "1" -a "$internal_LEGACY" = "0" ]; then
# new defaults (formerly "--experimental")
MAGGOTUBA_CORE_BRANCH=
MAGGOTUBA_ADAPTER_BRANCH=torch2
internal_MAGGOTUBA_ADAPTER_BRANCH=1
PYTHON_VERSION=3.11
elif [ "$internal_LEGACY" != "1" ]; then
if [ "$internal_WITH_DEFAULT_BACKEND" = "1" ]; then
echo "The Python3.11/Torch2 backend is now default"
echo "Pass flags --with-backend --legacy to select the former Python3.8/Torch1 backend"
fi
MAGGOTUBA_CORE_BRANCH=
MAGGOTUBA_ADAPTER_BRANCH=torch2
internal_MAGGOTUBA_ADAPTER_BRANCH=1
PYTHON_VERSION=3.11
fi
PYTHON="python$PYTHON_VERSION"
check_brew() {
if [ "`uname`" = "Darwin" ]; then
# macOS
if ! command -v brew &>/dev/null; then
if ! [ -f /opt/homebrew/bin/brew ]; then
echo "Installing Homebrew; admin rights will be requested"
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
fi
# not sure why zsh does not support ~/ below, while it seems to behave properly elsewhere...
cat <<"EOF" >>$HOME/.zprofile
eval "$(/opt/homebrew/bin/brew shellenv)"
EOF
eval "$(/opt/homebrew/bin/brew shellenv)"
fi
fi
}
if ! command -v realpath &>/dev/null; then
# macOS
check_brew
if command -v brew &>/dev/null; then
brew install coreutils
fi
fi
if ! command -v curl &>/dev/null; then
if [ "`uname`" = "Darwin" ]; then
check_brew
# macOS users are not given the choice as they usually do not care about freedom
brew install curl
fi
fi
if ! command -v curl &>/dev/null; then
echo "Command curl required; aborting"
else
if [ -z "$JULIA_VERSION" ]; then
JULIA_VERSION=1.10
JULIA_CHANNEL=1.10
else
echo "Using environment variable: JULIA_VERSION= $JULIA_VERSION"
if [ -z "$JULIA_CHANNEL" ]; then
JULIA_CHANNEL=$JULIA_VERSION
else
echo "Using environment variable: JULIA_CHANNEL= $JULIA_CHANNEL"
fi
fi
JULIA="julia"
install_juliaup() {
if [ -z "$JULIA_INSTALL_ARGS" ]; then
JULIA_INSTALL_ARGS=-y
else
echo "Using environment variable: JULIA_INSTALL_ARGS= $JULIA_INSTALL_ARGS"
fi
curl -fsSL https://install.julialang.org | sh -s -- $JULIA_INSTALL_ARGS --default-channel $JULIA_VERSION
export PATH=~/.juliaup/bin:$PATH
}
if ! command -v $JULIA &>/dev/null; then
install_juliaup
elif ! [[ "`$JULIA -v`" =~ "julia version $JULIA_VERSION" ]]; then
if ! command -v juliaup &>/dev/null; then
install_juliaup
fi
fi
if command -v juliaup &>/dev/null; then
juliaup add $JULIA_CHANNEL
juliaup default $JULIA_CHANNEL
fi
add_local_bin_to_path() {
if [ "`realpath $BIN_DIR`" = "`realpath ~/.local/bin`" ]; then
# ~/.local/bin not in $PATH?
if [ "$SHELL" = "/bin/zsh" ]; then
rcfile=~/.zshrc
elif [ "$SHELL" = "/bin/bash" ]; then
if [ -f ~/.bashrc ]; then
rcfile=~/.bashrc
elif [ -f ~/.bash_profile ]; then
rcfile=~/.bash_profile
fi
fi
echo "Extending the PATH environment variable in $rcfile"
cat <<"EOF" >>$rcfile
export PATH=$PATH:~/.local/bin
EOF
else
echo "the larvatagger command is available in directory:"
echo " $BIN_DIR"
echo "consider adding the directory to the PATH variable in your rc or profile file"
fi
export PATH=$PATH:$BIN_DIR
}
install_pyenv_on_ubuntu2004() {
echo
echo "INFO: installing pyenv and its dependencies"
echo
if ! [ -d ~/.pyenv ]; then
sudo apt-get update
sudo apt-get install --no-install-recommends curl build-essential libssl-dev zlib1g-dev libbz2-dev libreadline-dev libsqlite3-dev llvm libncurses5-dev xz-utils libxml2-dev libxmlsec1-dev libffi-dev liblzma-dev #tk-dev
curl https://pyenv.run | bash
fi
export PATH=~/.pyenv/bin:$PATH
eval "$(~/.pyenv/bin/pyenv init -)"
cat <<"EOF" >>~/.bash_profile
command -v pyenv &>/dev/null || export PATH=~/.pyenv/bin:$PATH
eval "$(~/.pyenv/bin/pyenv init -)"
EOF
pyenv install $PYTHON_VERSION
}
install_pyenv() {
echo
echo "INFO: installing pyenv"
echo
if ! [ -d ~/.pyenv ]; then
curl https://pyenv.run | bash
fi
if ! command -v pyenv &>/dev/null; then
export PATH=~/.pyenv/bin:$PATH
eval "$(~/.pyenv/bin/pyenv init -)"
cat <<"EOF" >>~/.bash_profile
command -v pyenv &>/dev/null || export PATH=~/.pyenv/bin:$PATH
eval "$(~/.pyenv/bin/pyenv init -)"
EOF
fi
pyenv install $PYTHON_VERSION
pyenv shell $PYTHON_VERSION
}
if [ -n "$WITH_BACKEND" ]; then
if ! command -v python$PYTHON_VERSION &>/dev/null; then
if command -v pyenv &>/dev/null; then
[ `pyenv versions | grep $PYTHON_VERSION` ] || pyenv install $PYTHON_VERSION
elif [[ "`uname -r`" =~ "-microsoft-standard-WSL2" ]]; then
install_pyenv_on_ubuntu2004
elif [[ "`hostname`" =~ ".cluster.embl.de" ]]; then
install_pyenv
elif [ "`hostname`" = "maestro-submit" ]; then
# we could use `module load Python/<version>` but modules are removed without notice
install_pyenv
else
check_brew
if command -v brew &>/dev/null; then
brew install python@$PYTHON_VERSION
if ! command -v python$PYTHON_VERSION &>/dev/null; then
echo "Try instead $0 --with-backend --experimental"
echo "Aborting..."
exit 1
fi
else
echo "WARNING: command $PYTHON not found"
fi
fi
fi
if ! command -v poetry &>/dev/null; then
if command -v pipx &>/dev/null; then
pipx install poetry
else
# explicit Python version for Maestro
curl -fsSL https://install.python-poetry.org | $PYTHON -
command -v poetry &>/dev/null || add_local_bin_to_path
fi
fi
fi
mkdir -p "$LARVATAGGER_PATH" && pushd $_
##
if [ -d PlanarLarvae ]; then
echo "PlanarLarvae.jl installation found; skipping"
else
if [ -z "$PLANARLARVAE_BRANCH" ]; then
PLANARLARVAE_BRANCH=main
else
echo "Using environment variable: PLANARLARVAE_BRANCH= $PLANARLARVAE_BRANCH"
curl -fsSL https://gitlab.pasteur.fr/nyx/planarlarvae.jl/-/archive/${PLANARLARVAE_BRANCH}/planarlarvae.jl-${PLANARLARVAE_BRANCH}.tar.gz | tar zxv
mv planarlarvae.jl-${PLANARLARVAE_BRANCH} PlanarLarvae
fi
fi
if [ -d LarvaTagger.jl ]; then
echo "LarvaTagger.jl installation found; skipping"
else
if [ -z "$LARVATAGGER_BRANCH" ]; then
LARVATAGGER_BRANCH=main
else
echo "Using environment variable: LARVATAGGER_BRANCH= $LARVATAGGER_BRANCH"
fi
curl -fsSL https://gitlab.pasteur.fr/nyx/larvatagger.jl/-/archive/${LARVATAGGER_BRANCH}/larvatagger.jl-${LARVATAGGER_BRANCH}.tar.gz | tar zxv
mv larvatagger.jl-${LARVATAGGER_BRANCH} LarvaTagger.jl
fi
(cd LarvaTagger.jl && $JULIA --project=. -e 'using Pkg; Pkg.instantiate()')
[ -d PlanarLarvae ] && (cd LarvaTagger.jl && $JULIA --project=. -e 'using Pkg; Pkg.develop(path="../PlanarLarvae")')
if [ -z "$WITH_BACKEND" ]; then
mkdir -p "$BIN_DIR"
cat <<EOF >"$BIN_DIR"/larvatagger
#!/usr/bin/env bash
if command -v juliaup &>/dev/null; then
PREVIOUS_CHANNEL=\`juliaup status | grep '*' | cut -d'*' -f2 | cut -d\\ -f3\`
juliaup default $JULIA_VERSION &>/dev/null
fi
OPEN_BROWSER=1 "$LARVATAGGER_PATH/LarvaTagger.jl/scripts/larvatagger" \$@
if command -v juliaup &>/dev/null; then
juliaup default \$PREVIOUS_CHANNEL &>/dev/null
fi
EOF
else
[ -z "$internal_WITH_BACKEND" ] && echo "Using environment variable: WITH_BACKEND= $WITH_BACKEND"
activate() {
# pyenv activation is necessary on WSL
command -v pyenv &>/dev/null && [ -n "`pyenv versions | grep ' $PYTHON_VERSION'`" ] && pyenv local $PYTHON_VERSION
poetry env use $PYTHON_VERSION 2>/dev/null
}
if [ -d TaggingBackends ]; then
echo "TaggingBackends installation found; skipping"
else
if [ -z "$TAGGINGBACKENDS_BRANCH" ]; then
TAGGINGBACKENDS_BRANCH=main
else
echo "Using environment variable: TAGGINGBACKENDS_BRANCH= $TAGGINGBACKENDS_BRANCH"
fi
curl -fsSL https://gitlab.pasteur.fr/nyx/TaggingBackends/-/archive/${TAGGINGBACKENDS_BRANCH}/TaggingBackends-${TAGGINGBACKENDS_BRANCH}.tar.gz | tar zxv
mv TaggingBackends-${TAGGINGBACKENDS_BRANCH} TaggingBackends
fi
(cd TaggingBackends && activate && PYTHON="`poetry env info`/bin/python" $JULIA --project=. -e 'using Pkg; Pkg.instantiate()')
[ -d PlanarLarvae ] && (cd TaggingBackends && $JULIA --project=. -e 'using Pkg; Pkg.develop(path="../PlanarLarvae")')
(cd TaggingBackends && activate && JULIA_PROJECT=$(pwd) poetry install)
if [ -d MaggotUBA-core ]; then
echo "MaggotUBA-core installation found; skipping"
else
if [ -z "$MAGGOTUBA_CORE_BRANCH" ]; then
MAGGOTUBA_CORE_BRANCH=main
else
echo "Using environment variable: MAGGOTUBA_CORE_BRANCH= $MAGGOTUBA_CORE_BRANCH"
curl -fsSL https://gitlab.pasteur.fr/nyx/maggotuba-core/-/archive/${MAGGOTUBA_CORE_BRANCH}/maggotuba-core-${MAGGOTUBA_CORE_BRANCH}.tar.gz | tar zxv
mv maggotuba-core-${MAGGOTUBA_CORE_BRANCH} MaggotUBA-core
fi
fi
if [ -d MaggotUBA ]; then
echo "MaggotUBA installation found; skipping"
else
if [ -z "$MAGGOTUBA_ADAPTER_BRANCH" ]; then
MAGGOTUBA_ADAPTER_BRANCH=main
elif [ -z "$internal_MAGGOTUBA_ADAPTER_BRANCH" ]; then
echo "Using environment variable: MAGGOTUBA_ADAPTER_BRANCH= $MAGGOTUBA_ADAPTER_BRANCH"
fi
curl -fsSL https://gitlab.pasteur.fr/nyx/MaggotUBA-adapter/-/archive/${MAGGOTUBA_ADAPTER_BRANCH}/MaggotUBA-adapter-${MAGGOTUBA_ADAPTER_BRANCH}.tar.gz | tar zxv
mv MaggotUBA-adapter-${MAGGOTUBA_ADAPTER_BRANCH} MaggotUBA #-adapter
#ln -s $(realpath MaggotUBA-adapter) MaggotUBA
fi
# setting JULIA_PROJECT may not be necessary at this point
export JULIA_PROJECT=$(realpath TaggingBackends)
if [ -z "$internal_MAGGOTUBA_ADAPTER_FREE_DEPENDENCIES" ]; then
if [ "`uname`" = "Darwin" ]; then
# PyTorch requirements in the requirements.txt file are Cuda-based, suitable for Windows and Linux
# while alternative libraries are used on macOS
internal_MAGGOTUBA_ADAPTER_FREE_DEPENDENCIES=1
else
internal_MAGGOTUBA_ADAPTER_FREE_DEPENDENCIES=0
fi
fi
if [ "$internal_MAGGOTUBA_ADAPTER_FREE_DEPENDENCIES" = "0" ]; then
(cd MaggotUBA && activate && (cat requirements.txt | xargs -I % sh -c 'poetry add "%"' || true) && poetry install -v)
else
(cd MaggotUBA && activate && poetry install -v)
fi
[ -d TaggingBackends ] && (cd MaggotUBA && activate && poetry remove taggingbackends && poetry add ../TaggingBackends)
[ -d MaggotUBA-core ] && (cd MaggotUBA && activate && poetry remove maggotuba-core && poetry add ../MaggotUBA-core)
(cd MaggotUBA && scripts/make_models.jl default) # julia version does not matter here
mkdir -p "$BIN_DIR"
cat <<EOF >"$BIN_DIR"/larvatagger
#!/usr/bin/env bash
if command -v juliaup &>/dev/null; then
PREVIOUS_CHANNEL=\`juliaup status | grep '*' | cut -d'*' -f2 | cut -d\\ -f3\`
juliaup default $JULIA_VERSION &>/dev/null
fi
JULIA_PROJECT="$(realpath "$LARVATAGGER_PATH/TaggingBackends")" BACKENDS_PATH="$LARVATAGGER_PATH" OPEN_BROWSER=1 "$LARVATAGGER_PATH/LarvaTagger.jl/scripts/larvatagger" \$@
if command -v juliaup &>/dev/null; then
juliaup default \$PREVIOUS_CHANNEL &>/dev/null
fi
EOF
fi
chmod a+x "$BIN_DIR/larvatagger"
command -v larvatagger &>/dev/null || add_local_bin_to_path
##
popd
fi
fi