Files
galaxy/scripts/common_startup.sh
T
mvdbeek a05c2c22d4 Resolve conditional dependencies from tool_shed.yml for the Tool Shed
common_startup.sh resolved only galaxy.yml, so a Tool Shed deployment
installed nothing from conditional-requirements.txt. That is why the
sentry-sdk>=2.63.0 pin never reached toolshed.test, which kept an older
sentry-sdk and hit the FastAPI >= 0.137 wrapper-loop crash: sentry
re-wraps dependant.call on every request there, and inspect.unwrap
raises once the chain passes the recursion limit.

Move the machinery and the app-agnostic checks into
BaseConditionalDependencies so the Tool Shed evaluates the database
driver and sentry-sdk checks against its own config section, and let
run_tool_shed.sh select it with GALAXY_CONDITIONAL_DEPENDENCIES_APP.
Galaxy-only checks stay on ConditionalDependencies, where check() keeps
treating a missing check_<name> method as "not needed".
2026-07-30 12:45:42 +02:00

310 lines
13 KiB
Bash
Executable File

#!/bin/sh
set -e
# The caller may do this as well, but since common_startup.sh can be called independently, we need to do it here
. ./scripts/common_startup_functions.sh
DEV_WHEELS=0
FETCH_WHEELS=1
CREATE_VENV=1
COPY_SAMPLE_FILES=1
SET_VENV=1
SKIP_CLIENT_BUILD=${GALAXY_SKIP_CLIENT_BUILD:-0}
INSTALL_PREBUILT_CLIENT=${GALAXY_INSTALL_PREBUILT_CLIENT:-0}
: "${PNPM_INSTALL_OPTS:=--frozen-lockfile}"
: "${GALAXY_CONDA_PYTHON_VERSION:=3.10}"
for arg in "$@"; do
if [ "$arg" = "--skip-venv" ]; then
SET_VENV=0
skip_venv=1 # for common startup functions
fi
[ "$arg" = "--skip-eggs" ] && FETCH_WHEELS=0
[ "$arg" = "--skip-wheels" ] && FETCH_WHEELS=0
[ "$arg" = "--dev-wheels" ] && DEV_WHEELS=1
[ "$arg" = "--no-create-venv" ] && CREATE_VENV=0
[ "$arg" = "--stop-daemon" ] && FETCH_WHEELS=0
[ "$arg" = "--skip-samples" ] && COPY_SAMPLE_FILES=0
[ "$arg" = "--skip-client-build" ] && SKIP_CLIENT_BUILD=1
done
SAMPLES="
tool-data/shared/ucsc/builds.txt.sample
tool-data/shared/ucsc/manual_builds.txt.sample
"
RMFILES="
lib/pkg_resources.pyc
"
MIN_PYTHON_VERSION=3.10
MIN_PIP_VERSION=20.3
# return true if $1 is in $2 else false
in_dir() {
case $1 in
$2*)
return 0
;;
''|*)
return 1
;;
esac
}
# return true if $1 is in $VIRTUAL_ENV else false
in_venv() {
in_dir "$1" "$VIRTUAL_ENV"
}
# return true if $1 is in $CONDA_PREFIX else false
in_conda_env() {
in_dir "$1" "$CONDA_PREFIX"
}
if [ $COPY_SAMPLE_FILES -eq 1 ]; then
# Create any missing config/location files
for sample in $SAMPLES; do
file=${sample%.sample}
if [ ! -f "$file" ] && [ -f "$sample" ]; then
echo "Initializing $file from $(basename "$sample")"
cp "$sample" "$file"
fi
done
fi
# remove problematic cached files
for rmfile in $RMFILES; do
[ -f "$rmfile" ] && rm -f "$rmfile"
done
# Determine branch (if using git)
if command -v git >/dev/null && [ -d .git ]; then
GIT_BRANCH=$(git rev-parse --abbrev-ref HEAD)
case $GIT_BRANCH in
release_*|master)
# All branches should now build the client as necessary, turn this
# back into an if? Or is there more we need to do here?
;;
*)
DEV_WHEELS=1
# SKIP_CLIENT_BUILD will default to false, but can be overridden by the command line argument
;;
esac
else
GIT_BRANCH=0
fi
: "${GALAXY_VIRTUAL_ENV:=.venv}"
# GALAXY_CONDA_ENV is not set here because we don't want to execute the Galaxy version check if we don't need to
if [ $SET_VENV -eq 1 ] && [ $CREATE_VENV -eq 1 ]; then
if [ ! -d "$GALAXY_VIRTUAL_ENV" ]; then
# Locate `conda` and set $CONDA_EXE (if needed). setup_python calls this
# as well, but in this case we need it done beforehand.
set_conda_exe
if [ -n "$CONDA_EXE" ]; then
echo "Found Conda, will set up a virtualenv using a Python installed from Conda."
echo "To use a non-Conda Python for the virtualenv, pre-create the virtualenv at $GALAXY_VIRTUAL_ENV"
: "${GALAXY_CONDA_ENV:=_galaxy_}"
if [ "$CONDA_DEFAULT_ENV" != "$GALAXY_CONDA_ENV" ]; then
if ! check_conda_env "$GALAXY_CONDA_ENV"; then
echo "Creating Conda environment for Galaxy: $GALAXY_CONDA_ENV"
echo "To avoid this, use the --no-create-venv flag or set \$GALAXY_CONDA_ENV to an"
echo "existing environment before starting Galaxy."
$CONDA_EXE create --yes --override-channels --channel conda-forge --name "$GALAXY_CONDA_ENV" "python=${GALAXY_CONDA_PYTHON_VERSION}" "pip>=${MIN_PIP_VERSION}" uv
unset __CONDA_INFO
fi
conda_activate
fi
if command -v uv >/dev/null; then
# Ensure uv uses the active conda python to avoid picking a different uv-managed interpreter.
uv venv --python "${CONDA_PREFIX}/bin/python" "$GALAXY_VIRTUAL_ENV"
else
python3 -m venv "$GALAXY_VIRTUAL_ENV"
fi
else
# If $GALAXY_VIRTUAL_ENV does not exist, and there is no conda available, attempt to create it.
# Ensure Python is a supported version before creating $GALAXY_VIRTUAL_ENV
find_python_command
"$GALAXY_PYTHON" ./scripts/check_python.py || exit 1
echo "Creating Python virtual environment for Galaxy: $GALAXY_VIRTUAL_ENV"
echo "using Python: $GALAXY_PYTHON"
echo "To avoid this, use the --no-create-venv flag or set \$GALAXY_VIRTUAL_ENV to an"
echo "existing environment before starting Galaxy."
if command -v uv >/dev/null; then
uv venv --python "$GALAXY_PYTHON" "$GALAXY_VIRTUAL_ENV"
else
# First try to use the venv standard library module, although it is
# not always installed by default on Linux distributions.
if ! "$GALAXY_PYTHON" -m venv "$GALAXY_VIRTUAL_ENV"; then
echo "Creating the Python virtual environment using the venv standard library module failed."
echo "Trying with virtualenv now."
if command -v virtualenv >/dev/null; then
virtualenv -p "$GALAXY_PYTHON" "$GALAXY_VIRTUAL_ENV"
else
# Download virtualenv zipapp
vurl="https://bootstrap.pypa.io/virtualenv/${MIN_PYTHON_VERSION}/virtualenv.pyz"
vtmp=$(mktemp -d -t galaxy-virtualenv-XXXXXX)
vsrc="$vtmp/$(basename $vurl)"
echo "Fetching $vurl"
if command -v curl >/dev/null; then
curl -L -o "$vsrc" "$vurl"
elif command -v wget >/dev/null; then
wget -O "$vsrc" "$vurl"
else
"$GALAXY_PYTHON" -c "try:
from urllib import urlretrieve
except:
from urllib.request import urlretrieve
urlretrieve('$vurl', '$vsrc')"
fi
"$GALAXY_PYTHON" "$vsrc" "$GALAXY_VIRTUAL_ENV"
rm -rf "$vtmp"
fi
fi
fi
fi
fi
fi
if command -v uv >/dev/null; then
PIP_CMD="$(command -v uv) pip"
UNINSTALL_OPTIONS=''
else
PIP_CMD='python -m pip'
UNINSTALL_OPTIONS='--yes'
fi
# activate virtualenv or conda env, sets $GALAXY_VIRTUAL_ENV and $GALAXY_CONDA_ENV
setup_python
if [ $SET_VENV -eq 1 ] && [ -z "$VIRTUAL_ENV" ]; then
echo "ERROR: A virtualenv cannot be found. Please create a virtualenv in $GALAXY_VIRTUAL_ENV, or activate one."
exit 1
fi
: "${GALAXY_WHEELS_INDEX_URL:=https://wheels.galaxyproject.org/simple}"
: "${GALAXY_DEV_REQUIREMENTS:=./lib/galaxy/dependencies/dev-requirements.txt}"
# Which app's config decides the conditional dependencies to install. Set by the
# launcher (run_tool_shed.sh exports tool_shed) since this script is shared.
: "${GALAXY_CONDITIONAL_DEPENDENCIES_APP:=galaxy}"
requirement_args="-r requirements.txt"
if [ $DEV_WHEELS -eq 1 ]; then
requirement_args="$requirement_args -r ${GALAXY_DEV_REQUIREMENTS}"
fi
[ "$CI" = 'true' ] && export PIP_PROGRESS_BAR=off
if [ $FETCH_WHEELS -eq 1 ]; then
if [ "${PIP_CMD}" = 'python -m pip' ]; then
if ! python -m pip --version >/dev/null; then
python -m ensurepip
fi
${PIP_CMD} install "pip>=${MIN_PIP_VERSION}" wheel
fi
# shellcheck disable=SC2086
${PIP_CMD} install $requirement_args --extra-index-url "${GALAXY_WHEELS_INDEX_URL}"
if [ "$GALAXY_CONDITIONAL_DEPENDENCIES_APP" = "tool_shed" ]; then
set_tool_shed_config_file_var
conditional_dependencies_config_file="$TOOL_SHED_CONFIG_FILE"
else
set_galaxy_config_file_var
conditional_dependencies_config_file="$GALAXY_CONFIG_FILE"
fi
GALAXY_CONDITIONAL_DEPENDENCIES=$(PYTHONPATH=lib python -c "from __future__ import print_function; import galaxy.dependencies; print('\n'.join(galaxy.dependencies.optional('$conditional_dependencies_config_file', app='$GALAXY_CONDITIONAL_DEPENDENCIES_APP')))")
if [ -n "$GALAXY_CONDITIONAL_DEPENDENCIES" ]; then
if ${PIP_CMD} list --format=columns | grep "psycopg2[\(\ ]*2.7.3" > /dev/null; then
echo "An older version of psycopg2 (non-binary, version 2.7.3) has been detected. Galaxy now uses psycopg2-binary, which will be installed after removing psycopg2."
${PIP_CMD} uninstall ${UNINSTALL_OPTIONS} psycopg2 psycopg2-binary
fi
echo "$GALAXY_CONDITIONAL_DEPENDENCIES" | ${PIP_CMD} install -r /dev/stdin --extra-index-url "${GALAXY_WHEELS_INDEX_URL}" --constraint lib/galaxy/dependencies/conditional-constraints.txt
fi
fi
# Check client build state.
if [ "$SKIP_CLIENT_BUILD" -eq 0 ]; then
if [ "$INSTALL_PREBUILT_CLIENT" -ne 0 ]; then
echo "The Galaxy prebuilt client will be installed from PyPI."
elif [ -f static/client_build_hash.txt ]; then
# If git is not used and static/client_build_hash.txt is present, next
# client rebuilds must be done manually by the admin
if [ "$GIT_BRANCH" = "0" ]; then
echo "Skipping Galaxy client build because git is not in use and the client build state cannot be compared against local changes. If you have made local modifications, then manual client builds will be required. See ./client/README.md for more information."
SKIP_CLIENT_BUILD=1
else
# Check if anything has changed in client/ or visualization plugins since the last build
if git diff --quiet "$(cat static/client_build_hash.txt)" -- client/ config/plugins/visualizations/; then
echo "The Galaxy client build is up to date and will not be rebuilt at this time."
SKIP_CLIENT_BUILD=1
else
echo "The Galaxy client is out of date and will be built now."
fi
fi
else
echo "The Galaxy client has not yet been built and will be built now."
fi
else
echo "The Galaxy client build is being skipped due to the SKIP_CLIENT_BUILD environment variable."
fi
# Build or install client if necessary.
if [ "$SKIP_CLIENT_BUILD" -eq 0 ]; then
if [ "$INSTALL_PREBUILT_CLIENT" -ne 0 ]; then
# Prebuilt install: pull the matching galaxy-web-client wheel from PyPI.
# webapp.py picks it up via `import galaxy.web_client` and serves its
# bundled dist/ directly -- no pnpm or staging required.
GALAXY_WEB_CLIENT_VERSION=$(PYTHONPATH=lib python -c "from galaxy.version import VERSION; print(VERSION)")
case "$GALAXY_WEB_CLIENT_VERSION" in
*dev*)
echo "ERROR: Galaxy is at development version ${GALAXY_WEB_CLIENT_VERSION}, for which no galaxy-web-client wheel is published to PyPI."
echo "The prebuilt client install path (GALAXY_INSTALL_PREBUILT_CLIENT=1) is only supported against tagged releases. Unset GALAXY_INSTALL_PREBUILT_CLIENT to build the client from source instead."
exit 1
;;
esac
# shellcheck disable=SC2086
if ! ${PIP_CMD} install "galaxy-web-client==${GALAXY_WEB_CLIENT_VERSION}"; then
echo "ERROR: Galaxy prebuilt client install failed. See ./client/README.md for more information, including how to get help."
exit 1
fi
else
# Dev build: use pnpm to build client from source.
# Ensure pnpm is installed.
INSTALL_PNPM=0
if ! command -v pnpm >/dev/null; then
INSTALL_PNPM=1
fi
if [ $INSTALL_PNPM -eq 1 ]; then
if [ -n "$CONDA_DEFAULT_ENV" ] && [ -n "$CONDA_EXE" ]; then
echo "Installing pnpm into '$CONDA_DEFAULT_ENV' Conda environment with conda."
$CONDA_EXE install --yes --override-channels --channel conda-forge --name "$CONDA_DEFAULT_ENV" pnpm
elif [ -n "$VIRTUAL_ENV" ] && in_venv "$(command -v npm)"; then
echo "Installing pnpm into $VIRTUAL_ENV with corepack."
corepack enable pnpm
else
echo "Installing pnpm locally with npm."
npm install -g pnpm
fi
fi
# We need GALAXY_CONFIG_FILE here, ensure it's set.
set_galaxy_config_file_var
# Set plugin path
GALAXY_PLUGIN_PATH=$(python scripts/config_parse.py --setting=plugin_path --config-file="$GALAXY_CONFIG_FILE")
cd client
# shellcheck disable=SC2086
if pnpm install $PNPM_INSTALL_OPTS; then
if ! (export GALAXY_PLUGIN_PATH="$GALAXY_PLUGIN_PATH"; pnpm run build-production-maps;) then
echo "ERROR: Galaxy client build failed. See ./client/README.md for more information, including how to get help."
exit 1
fi
else
echo "ERROR: Galaxy client dependency installation failed. See ./client/README.md for more information, including how to get help."
exit 1
fi
cd -
fi
fi