659 lines
18 KiB
Bash
Executable File
659 lines
18 KiB
Bash
Executable File
#!/bin/sh
|
|
set -eu
|
|
|
|
SCRIPT_DIR="$(CDPATH= cd "$(dirname "$0")" && pwd)"
|
|
cd "$SCRIPT_DIR"
|
|
|
|
PYTHON_BIN_WAS_SET=0
|
|
if [ -n "${PYTHON_BIN:-}" ]; then
|
|
PYTHON_BIN_WAS_SET=1
|
|
fi
|
|
PYTHON_BIN="${PYTHON_BIN:-python3.13}"
|
|
VENV_DIR="backend/.venv"
|
|
TORCH_FLAVOR_FILE="$VENV_DIR/.heimgeist-torch-flavor"
|
|
TORCH_STATE_FILE="$VENV_DIR/.heimgeist-torch-state"
|
|
PYTHON_DEPS_STATE_FILE="$VENV_DIR/.heimgeist-python-deps-state"
|
|
NODE_DEPS_STATE_FILE="node_modules/.heimgeist-node-deps-state"
|
|
HEIMGEIST_NODE_MAJOR="${HEIMGEIST_NODE_MAJOR:-22}"
|
|
HEIMGEIST_NODE_DIR="${HEIMGEIST_NODE_DIR:-${XDG_CACHE_HOME:-$HOME/.cache}/heimgeist/node-v$HEIMGEIST_NODE_MAJOR}"
|
|
HEIMGEIST_TOOL_BIN_DIR="${HEIMGEIST_TOOL_BIN_DIR:-$HOME/.local/bin}"
|
|
HEIMGEIST_SKIP_SYSTEM_DEPS="${HEIMGEIST_SKIP_SYSTEM_DEPS:-0}"
|
|
HEIMGEIST_BOOTSTRAP_ONLY="${HEIMGEIST_BOOTSTRAP_ONLY:-0}"
|
|
HEIMGEIST_TORCH_FLAVOR="${HEIMGEIST_TORCH_FLAVOR:-auto}"
|
|
HEIMGEIST_TORCH_INDEX_URL="${HEIMGEIST_TORCH_INDEX_URL:-}"
|
|
HEIMGEIST_FORCE_BOOTSTRAP="${HEIMGEIST_FORCE_BOOTSTRAP:-0}"
|
|
CARGO_HOME="${CARGO_HOME:-$HOME/.cargo}"
|
|
RUSTUP_HOME="${RUSTUP_HOME:-$HOME/.rustup}"
|
|
PATH="$HEIMGEIST_TOOL_BIN_DIR:$CARGO_HOME/bin:$PATH"
|
|
export CARGO_HOME RUSTUP_HOME PATH
|
|
|
|
as_root() {
|
|
if [ "$(id -u)" -eq 0 ]; then
|
|
"$@"
|
|
return
|
|
fi
|
|
if ! command -v sudo >/dev/null 2>&1; then
|
|
echo "Installing native build dependencies requires root access, but sudo is unavailable." >&2
|
|
exit 1
|
|
fi
|
|
if ! sudo -v; then
|
|
if is_steamos; then
|
|
echo "SteamOS needs a local user password for sudo. Run 'passwd', then rerun ./run.sh." >&2
|
|
fi
|
|
exit 1
|
|
fi
|
|
sudo "$@"
|
|
}
|
|
|
|
is_steamos() {
|
|
[ -r /etc/os-release ] \
|
|
&& grep -Eiq '(^ID=steamos$|^NAME=.*SteamOS|^PRETTY_NAME=.*SteamOS)' /etc/os-release
|
|
}
|
|
|
|
linux_native_deps_usable() {
|
|
command -v cc >/dev/null 2>&1 \
|
|
&& command -v file >/dev/null 2>&1 \
|
|
&& command -v pkg-config >/dev/null 2>&1 \
|
|
&& pkg-config --exists webkit2gtk-4.1 gtk+-3.0 openssl librsvg-2.0
|
|
}
|
|
|
|
STEAMOS_RESTORE_READONLY=0
|
|
|
|
restore_steamos_readonly() {
|
|
if [ "$STEAMOS_RESTORE_READONLY" -eq 1 ]; then
|
|
echo "Re-enabling the SteamOS read-only filesystem"
|
|
as_root steamos-readonly enable
|
|
STEAMOS_RESTORE_READONLY=0
|
|
fi
|
|
}
|
|
|
|
prepare_steamos_package_install() {
|
|
if ! is_steamos || ! command -v steamos-readonly >/dev/null 2>&1; then
|
|
return
|
|
fi
|
|
|
|
readonly_status="$(as_root steamos-readonly status 2>/dev/null || true)"
|
|
if printf '%s\n' "$readonly_status" | grep -Eqi '(^|[[:space:]])enable(d)?($|[[:space:]])'; then
|
|
echo "Temporarily disabling the SteamOS read-only filesystem"
|
|
as_root steamos-readonly disable
|
|
STEAMOS_RESTORE_READONLY=1
|
|
fi
|
|
}
|
|
|
|
install_arch_native_deps() {
|
|
set -- \
|
|
webkit2gtk-4.1 \
|
|
base-devel \
|
|
curl \
|
|
wget \
|
|
file \
|
|
openssl \
|
|
appmenu-gtk-module \
|
|
libappindicator-gtk3 \
|
|
librsvg \
|
|
xdotool
|
|
|
|
missing_packages=""
|
|
for package_name in "$@"; do
|
|
if ! pacman -Q "$package_name" >/dev/null 2>&1; then
|
|
missing_packages="$missing_packages $package_name"
|
|
fi
|
|
done
|
|
if [ -z "$missing_packages" ]; then
|
|
return
|
|
fi
|
|
|
|
echo "Installing missing Tauri/Arch packages:$missing_packages"
|
|
echo "SteamOS/Arch may ask for your sudo password."
|
|
prepare_steamos_package_install
|
|
trap 'restore_steamos_readonly' EXIT
|
|
trap 'restore_steamos_readonly; exit 130' HUP INT TERM
|
|
|
|
install_status=0
|
|
if is_steamos; then
|
|
# SteamOS system updates own the base image, so only install missing packages.
|
|
as_root pacman -S --needed --noconfirm $missing_packages || install_status=$?
|
|
else
|
|
# Arch requires a full upgrade when synchronizing/installing packages.
|
|
as_root pacman -Syu --needed --noconfirm $missing_packages || install_status=$?
|
|
fi
|
|
|
|
restore_steamos_readonly
|
|
trap - EXIT HUP INT TERM
|
|
return "$install_status"
|
|
}
|
|
|
|
install_debian_native_deps() {
|
|
set -- \
|
|
libwebkit2gtk-4.1-dev \
|
|
build-essential \
|
|
curl \
|
|
wget \
|
|
file \
|
|
libxdo-dev \
|
|
libssl-dev \
|
|
libayatana-appindicator3-dev \
|
|
librsvg2-dev \
|
|
pkg-config
|
|
|
|
missing_packages=""
|
|
for package_name in "$@"; do
|
|
if ! dpkg-query -W -f='${Status}' "$package_name" 2>/dev/null | grep -q 'ok installed'; then
|
|
missing_packages="$missing_packages $package_name"
|
|
fi
|
|
done
|
|
if [ -z "$missing_packages" ]; then
|
|
return
|
|
fi
|
|
|
|
echo "Installing missing Tauri/Debian packages:$missing_packages"
|
|
as_root apt-get update
|
|
as_root env DEBIAN_FRONTEND=noninteractive apt-get install -y $missing_packages
|
|
}
|
|
|
|
ensure_native_build_dependencies() {
|
|
if [ "$HEIMGEIST_SKIP_SYSTEM_DEPS" = "1" ]; then
|
|
return
|
|
fi
|
|
|
|
case "$(uname -s)" in
|
|
Darwin)
|
|
if ! xcode-select -p >/dev/null 2>&1; then
|
|
echo "Installing the Xcode Command Line Tools required by Tauri."
|
|
xcode-select --install || true
|
|
echo "Complete the Xcode Command Line Tools installation, then run ./run.sh again." >&2
|
|
exit 1
|
|
fi
|
|
;;
|
|
Linux)
|
|
if linux_native_deps_usable; then
|
|
return
|
|
fi
|
|
if command -v pacman >/dev/null 2>&1; then
|
|
install_arch_native_deps
|
|
elif command -v apt-get >/dev/null 2>&1 && command -v dpkg-query >/dev/null 2>&1; then
|
|
install_debian_native_deps
|
|
else
|
|
echo "Native dependency installation currently supports Arch/SteamOS and Debian/Ubuntu." >&2
|
|
echo "Install your distribution's Tauri 2 system prerequisites, then run ./run.sh again." >&2
|
|
exit 1
|
|
fi
|
|
if ! linux_native_deps_usable; then
|
|
echo "The native Tauri dependencies are still incomplete after package installation." >&2
|
|
exit 1
|
|
fi
|
|
;;
|
|
esac
|
|
}
|
|
|
|
node_runtime_usable() {
|
|
command -v node >/dev/null 2>&1 \
|
|
&& command -v npm >/dev/null 2>&1 \
|
|
&& node -e 'const major = Number(process.versions.node.split(".")[0]); process.exit(major >= 18 ? 0 : 1)' >/dev/null 2>&1
|
|
}
|
|
|
|
download_file() {
|
|
download_url="$1"
|
|
download_target="$2"
|
|
|
|
if command -v curl >/dev/null 2>&1; then
|
|
curl --fail --location --silent --show-error "$download_url" --output "$download_target"
|
|
return
|
|
fi
|
|
if command -v wget >/dev/null 2>&1; then
|
|
wget --quiet --output-document="$download_target" "$download_url"
|
|
return
|
|
fi
|
|
|
|
echo "A required tool is missing and neither curl nor wget is available to download it." >&2
|
|
echo "Install curl or wget, then run ./run.sh again." >&2
|
|
exit 1
|
|
}
|
|
|
|
file_sha256() {
|
|
checksum_file="$1"
|
|
|
|
if command -v sha256sum >/dev/null 2>&1; then
|
|
sha256sum "$checksum_file" | awk '{print $1}'
|
|
return
|
|
fi
|
|
if command -v shasum >/dev/null 2>&1; then
|
|
shasum -a 256 "$checksum_file" | awk '{print $1}'
|
|
return
|
|
fi
|
|
|
|
echo "Cannot verify the Node.js download because sha256sum/shasum is unavailable." >&2
|
|
exit 1
|
|
}
|
|
|
|
install_uv() {
|
|
uv_tmp_dir="$(mktemp -d "${TMPDIR:-/tmp}/heimgeist-uv.XXXXXX")"
|
|
trap 'rm -rf "$uv_tmp_dir"' EXIT HUP INT TERM
|
|
|
|
echo "Python 3.13 is missing; installing the uv runtime manager locally"
|
|
download_file "https://astral.sh/uv/install.sh" "$uv_tmp_dir/install.sh"
|
|
mkdir -p "$HEIMGEIST_TOOL_BIN_DIR"
|
|
UV_UNMANAGED_INSTALL="$HEIMGEIST_TOOL_BIN_DIR" UV_NO_MODIFY_PATH=1 sh "$uv_tmp_dir/install.sh"
|
|
|
|
rm -rf "$uv_tmp_dir"
|
|
trap - EXIT HUP INT TERM
|
|
}
|
|
|
|
ensure_uv() {
|
|
if command -v uv >/dev/null 2>&1; then
|
|
return
|
|
fi
|
|
|
|
install_uv
|
|
if ! command -v uv >/dev/null 2>&1; then
|
|
echo "The local uv installation did not provide an executable." >&2
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
python_runtime_usable() {
|
|
command -v "$PYTHON_BIN" >/dev/null 2>&1 \
|
|
&& "$PYTHON_BIN" -c 'import sys; raise SystemExit(0 if sys.version_info[:2] == (3, 13) else 1)' >/dev/null 2>&1
|
|
}
|
|
|
|
ensure_python_runtime() {
|
|
if python_runtime_usable; then
|
|
return
|
|
fi
|
|
if [ "$PYTHON_BIN_WAS_SET" -eq 1 ]; then
|
|
echo "PYTHON_BIN '$PYTHON_BIN' is unavailable or is not Python 3.13." >&2
|
|
exit 1
|
|
fi
|
|
|
|
ensure_uv
|
|
echo "Installing Python 3.13 locally"
|
|
uv python install 3.13
|
|
PYTHON_BIN="$(uv python find 3.13)"
|
|
|
|
if ! python_runtime_usable; then
|
|
echo "The local Python 3.13 installation is incomplete." >&2
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
rust_runtime_usable() {
|
|
command -v cargo >/dev/null 2>&1 \
|
|
&& command -v rustc >/dev/null 2>&1 \
|
|
&& rustc --version | awk '
|
|
{
|
|
split($2, version, ".")
|
|
exit !((version[1] > 1) || (version[1] == 1 && version[2] >= 77))
|
|
}
|
|
'
|
|
}
|
|
|
|
install_rustup() {
|
|
rustup_tmp_dir="$(mktemp -d "${TMPDIR:-/tmp}/heimgeist-rustup.XXXXXX")"
|
|
trap 'rm -rf "$rustup_tmp_dir"' EXIT HUP INT TERM
|
|
|
|
echo "Rust/Cargo 1.77+ was not found; installing the stable Rust toolchain locally"
|
|
download_file "https://sh.rustup.rs" "$rustup_tmp_dir/rustup-init.sh"
|
|
sh "$rustup_tmp_dir/rustup-init.sh" -y --profile minimal --default-toolchain stable --no-modify-path
|
|
|
|
rm -rf "$rustup_tmp_dir"
|
|
trap - EXIT HUP INT TERM
|
|
}
|
|
|
|
ensure_rust_runtime() {
|
|
if rust_runtime_usable; then
|
|
return
|
|
fi
|
|
|
|
if command -v rustup >/dev/null 2>&1; then
|
|
echo "Installing/updating the stable Rust toolchain"
|
|
rustup toolchain install stable --profile minimal
|
|
rustup default stable
|
|
else
|
|
install_rustup
|
|
fi
|
|
|
|
if ! rust_runtime_usable; then
|
|
echo "The Rust installation is incomplete; cargo and rustc 1.77+ are required." >&2
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
install_project_node() {
|
|
case "$(uname -s)" in
|
|
Linux) node_platform="linux" ;;
|
|
Darwin) node_platform="darwin" ;;
|
|
*)
|
|
echo "Automatic Node.js installation is only supported on Linux and macOS." >&2
|
|
echo "Install Node.js 18+ and npm, then run ./run.sh again." >&2
|
|
exit 1
|
|
;;
|
|
esac
|
|
|
|
case "$(uname -m)" in
|
|
x86_64|amd64) node_arch="x64" ;;
|
|
arm64|aarch64) node_arch="arm64" ;;
|
|
*)
|
|
echo "Automatic Node.js installation does not support architecture $(uname -m)." >&2
|
|
echo "Install Node.js 18+ and npm, then run ./run.sh again." >&2
|
|
exit 1
|
|
;;
|
|
esac
|
|
|
|
node_release_url="https://nodejs.org/dist/latest-v$HEIMGEIST_NODE_MAJOR.x"
|
|
node_tmp_dir="$(mktemp -d "${TMPDIR:-/tmp}/heimgeist-node.XXXXXX")"
|
|
trap 'rm -rf "$node_tmp_dir"' EXIT HUP INT TERM
|
|
|
|
echo "Node.js 18+ with npm was not found; installing Node.js v$HEIMGEIST_NODE_MAJOR locally"
|
|
download_file "$node_release_url/SHASUMS256.txt" "$node_tmp_dir/SHASUMS256.txt"
|
|
|
|
node_archive="$(awk -v suffix="-$node_platform-$node_arch.tar.xz" '
|
|
length($2) >= length(suffix) && substr($2, length($2) - length(suffix) + 1) == suffix {
|
|
print $2
|
|
exit
|
|
}
|
|
' "$node_tmp_dir/SHASUMS256.txt")"
|
|
if [ -z "$node_archive" ]; then
|
|
echo "No Node.js v$HEIMGEIST_NODE_MAJOR archive is available for $node_platform-$node_arch." >&2
|
|
exit 1
|
|
fi
|
|
|
|
expected_sha256="$(awk -v archive="$node_archive" '$2 == archive {print $1; exit}' "$node_tmp_dir/SHASUMS256.txt")"
|
|
download_file "$node_release_url/$node_archive" "$node_tmp_dir/$node_archive"
|
|
actual_sha256="$(file_sha256 "$node_tmp_dir/$node_archive")"
|
|
if [ "$actual_sha256" != "$expected_sha256" ]; then
|
|
echo "Node.js download checksum verification failed." >&2
|
|
exit 1
|
|
fi
|
|
|
|
tar -xJf "$node_tmp_dir/$node_archive" -C "$node_tmp_dir"
|
|
mkdir -p "$(dirname "$HEIMGEIST_NODE_DIR")"
|
|
rm -rf "$HEIMGEIST_NODE_DIR"
|
|
mv "$node_tmp_dir/${node_archive%.tar.xz}" "$HEIMGEIST_NODE_DIR"
|
|
rm -rf "$node_tmp_dir"
|
|
trap - EXIT HUP INT TERM
|
|
}
|
|
|
|
ensure_node_runtime() {
|
|
if node_runtime_usable; then
|
|
return
|
|
fi
|
|
|
|
if [ -x "$HEIMGEIST_NODE_DIR/bin/node" ] && [ -x "$HEIMGEIST_NODE_DIR/bin/npm" ]; then
|
|
original_path="$PATH"
|
|
PATH="$HEIMGEIST_NODE_DIR/bin:$PATH"
|
|
export PATH
|
|
if node_runtime_usable; then
|
|
return
|
|
fi
|
|
PATH="$original_path"
|
|
export PATH
|
|
fi
|
|
|
|
install_project_node
|
|
PATH="$HEIMGEIST_NODE_DIR/bin:$PATH"
|
|
export PATH
|
|
|
|
if ! node_runtime_usable; then
|
|
echo "The local Node.js installation is incomplete or older than version 18." >&2
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
manifest_state() {
|
|
for manifest_path in "$@"; do
|
|
if [ -f "$manifest_path" ]; then
|
|
checksum="$(cksum "$manifest_path" | awk '{print $1 ":" $2}')"
|
|
printf '%s %s\n' "$manifest_path" "$checksum"
|
|
else
|
|
printf '%s missing\n' "$manifest_path"
|
|
fi
|
|
done
|
|
}
|
|
|
|
state_matches() {
|
|
state_file="$1"
|
|
shift
|
|
[ -r "$state_file" ] || return 1
|
|
current_state="$(manifest_state "$@")"
|
|
saved_state="$(cat "$state_file")"
|
|
[ "$saved_state" = "$current_state" ]
|
|
}
|
|
|
|
write_state() {
|
|
state_file="$1"
|
|
shift
|
|
manifest_state "$@" > "$state_file"
|
|
}
|
|
|
|
current_torch_state() {
|
|
printf 'flavor=%s\nindex=%s\n' "$TORCH_FLAVOR" "$HEIMGEIST_TORCH_INDEX_URL"
|
|
}
|
|
|
|
torch_state_matches() {
|
|
[ -r "$TORCH_STATE_FILE" ] || return 1
|
|
saved_state="$(cat "$TORCH_STATE_FILE")"
|
|
[ "$saved_state" = "$(current_torch_state)" ]
|
|
}
|
|
|
|
write_torch_state() {
|
|
current_torch_state > "$TORCH_STATE_FILE"
|
|
}
|
|
|
|
python_deps_usable() {
|
|
"$VENV_DIR/bin/python" - <<'PY' >/dev/null 2>&1
|
|
import fastapi
|
|
import httpx
|
|
import pydantic
|
|
import sqlalchemy
|
|
import uvicorn
|
|
import whisper
|
|
PY
|
|
}
|
|
|
|
node_deps_usable() {
|
|
node - <<'NODE' >/dev/null 2>&1
|
|
require('react')
|
|
require('vite')
|
|
require('wait-on')
|
|
NODE
|
|
if [ "$?" -ne 0 ]; then
|
|
return 1
|
|
fi
|
|
|
|
[ -x node_modules/.bin/tauri ] || [ -x node_modules/.bin/tauri.cmd ]
|
|
}
|
|
|
|
is_linux_x86_64() {
|
|
[ "$(uname -s)" = "Linux" ] && [ "$(uname -m)" = "x86_64" ]
|
|
}
|
|
|
|
has_nvidia_gpu() {
|
|
if command -v nvidia-smi >/dev/null 2>&1; then
|
|
return 0
|
|
fi
|
|
|
|
for vendor_file in /sys/class/drm/card*/device/vendor; do
|
|
[ -r "$vendor_file" ] || continue
|
|
if grep -qi "0x10de" "$vendor_file"; then
|
|
return 0
|
|
fi
|
|
done
|
|
|
|
return 1
|
|
}
|
|
|
|
is_steam_deck() {
|
|
if [ -r /etc/os-release ] && grep -Eiq '(^ID=steamos$|^NAME=.*SteamOS|^PRETTY_NAME=.*SteamOS)' /etc/os-release; then
|
|
return 0
|
|
fi
|
|
|
|
for dmi_file in \
|
|
/sys/devices/virtual/dmi/id/product_name \
|
|
/sys/devices/virtual/dmi/id/product_version \
|
|
/sys/devices/virtual/dmi/id/board_name
|
|
do
|
|
[ -r "$dmi_file" ] || continue
|
|
if grep -Eiq 'steam deck|jupiter|galileo' "$dmi_file"; then
|
|
return 0
|
|
fi
|
|
done
|
|
|
|
return 1
|
|
}
|
|
|
|
resolve_torch_flavor() {
|
|
case "$HEIMGEIST_TORCH_FLAVOR" in
|
|
auto)
|
|
if is_linux_x86_64; then
|
|
if is_steam_deck; then
|
|
printf '%s\n' "cpu"
|
|
return
|
|
fi
|
|
if has_nvidia_gpu; then
|
|
printf '%s\n' "default"
|
|
return
|
|
fi
|
|
printf '%s\n' "cpu"
|
|
return
|
|
fi
|
|
printf '%s\n' "default"
|
|
;;
|
|
default|cpu|cuda|rocm|rocm6.4)
|
|
printf '%s\n' "$HEIMGEIST_TORCH_FLAVOR"
|
|
;;
|
|
*)
|
|
echo "Unsupported HEIMGEIST_TORCH_FLAVOR '$HEIMGEIST_TORCH_FLAVOR'. Use auto, default, cpu, cuda, rocm, or rocm6.4." >&2
|
|
exit 1
|
|
;;
|
|
esac
|
|
}
|
|
|
|
install_selected_torch() {
|
|
torch_flavor="$1"
|
|
|
|
if [ -n "$HEIMGEIST_TORCH_INDEX_URL" ]; then
|
|
echo "Installing PyTorch from custom index: $HEIMGEIST_TORCH_INDEX_URL"
|
|
"$VENV_DIR/bin/python" -m pip install --upgrade --index-url "$HEIMGEIST_TORCH_INDEX_URL" torch
|
|
return
|
|
fi
|
|
|
|
case "$torch_flavor" in
|
|
default|cuda)
|
|
return
|
|
;;
|
|
cpu)
|
|
echo "Installing CPU-only PyTorch for Whisper"
|
|
"$VENV_DIR/bin/python" -m pip install --upgrade --index-url https://download.pytorch.org/whl/cpu torch
|
|
;;
|
|
rocm|rocm6.4)
|
|
echo "Installing ROCm PyTorch for Whisper"
|
|
"$VENV_DIR/bin/python" -m pip install --upgrade --index-url https://download.pytorch.org/whl/rocm6.4 torch
|
|
;;
|
|
esac
|
|
}
|
|
|
|
ensure_native_build_dependencies
|
|
ensure_node_runtime
|
|
ensure_python_runtime
|
|
ensure_rust_runtime
|
|
|
|
TORCH_FLAVOR="$(resolve_torch_flavor)"
|
|
RECREATE_VENV=0
|
|
|
|
if [ ! -x "$VENV_DIR/bin/python" ] || ! "$VENV_DIR/bin/python" -c 'import sys; raise SystemExit(0 if sys.version_info[:2] == (3, 13) else 1)'; then
|
|
RECREATE_VENV=1
|
|
fi
|
|
|
|
if [ "$RECREATE_VENV" -eq 0 ]; then
|
|
PREVIOUS_TORCH_FLAVOR=""
|
|
if [ -r "$TORCH_FLAVOR_FILE" ]; then
|
|
PREVIOUS_TORCH_FLAVOR="$(cat "$TORCH_FLAVOR_FILE")"
|
|
fi
|
|
if [ -n "$PREVIOUS_TORCH_FLAVOR" ] && [ "$PREVIOUS_TORCH_FLAVOR" != "$TORCH_FLAVOR" ]; then
|
|
RECREATE_VENV=1
|
|
elif [ -z "$PREVIOUS_TORCH_FLAVOR" ] && [ "$TORCH_FLAVOR" != "default" ]; then
|
|
RECREATE_VENV=1
|
|
fi
|
|
fi
|
|
|
|
if [ "$RECREATE_VENV" -eq 1 ]; then
|
|
rm -rf "$VENV_DIR"
|
|
"$PYTHON_BIN" -m venv "$VENV_DIR"
|
|
fi
|
|
|
|
printf '%s\n' "$TORCH_FLAVOR" > "$TORCH_FLAVOR_FILE"
|
|
echo "Using PyTorch flavor: $TORCH_FLAVOR"
|
|
|
|
NEEDS_LEGACY_PYTHON_STATE=0
|
|
if [ ! -r "$PYTHON_DEPS_STATE_FILE" ]; then
|
|
NEEDS_LEGACY_PYTHON_STATE=1
|
|
fi
|
|
if [ -z "$HEIMGEIST_TORCH_INDEX_URL" ] && [ ! -r "$TORCH_STATE_FILE" ]; then
|
|
NEEDS_LEGACY_PYTHON_STATE=1
|
|
fi
|
|
|
|
if [ "$RECREATE_VENV" -eq 0 ] && [ "$NEEDS_LEGACY_PYTHON_STATE" -eq 1 ] && python_deps_usable; then
|
|
if [ ! -r "$PYTHON_DEPS_STATE_FILE" ]; then
|
|
write_state "$PYTHON_DEPS_STATE_FILE" backend/requirements.txt
|
|
fi
|
|
if [ -z "$HEIMGEIST_TORCH_INDEX_URL" ] && [ ! -r "$TORCH_STATE_FILE" ]; then
|
|
write_torch_state
|
|
fi
|
|
fi
|
|
|
|
if [ -d node_modules ] && [ ! -r "$NODE_DEPS_STATE_FILE" ] && node_deps_usable; then
|
|
write_state "$NODE_DEPS_STATE_FILE" package.json package-lock.json
|
|
fi
|
|
|
|
NEED_PYTHON_DEPS_INSTALL="$RECREATE_VENV"
|
|
NEED_TORCH_INSTALL="$RECREATE_VENV"
|
|
NEED_NODE_DEPS_INSTALL=0
|
|
|
|
if [ "$HEIMGEIST_FORCE_BOOTSTRAP" = "1" ]; then
|
|
NEED_PYTHON_DEPS_INSTALL=1
|
|
NEED_TORCH_INSTALL=1
|
|
NEED_NODE_DEPS_INSTALL=1
|
|
fi
|
|
|
|
if [ "$NEED_PYTHON_DEPS_INSTALL" -eq 0 ] && ! state_matches "$PYTHON_DEPS_STATE_FILE" backend/requirements.txt; then
|
|
NEED_PYTHON_DEPS_INSTALL=1
|
|
fi
|
|
|
|
if [ "$NEED_TORCH_INSTALL" -eq 0 ] && ! torch_state_matches; then
|
|
NEED_TORCH_INSTALL=1
|
|
fi
|
|
|
|
if [ "$NEED_PYTHON_DEPS_INSTALL" -eq 1 ]; then
|
|
echo "Installing Python dependencies"
|
|
"$VENV_DIR/bin/python" -m pip install --upgrade pip
|
|
if [ "$NEED_TORCH_INSTALL" -eq 1 ]; then
|
|
install_selected_torch "$TORCH_FLAVOR"
|
|
write_torch_state
|
|
fi
|
|
"$VENV_DIR/bin/python" -m pip install -r backend/requirements.txt
|
|
write_state "$PYTHON_DEPS_STATE_FILE" backend/requirements.txt
|
|
elif [ "$NEED_TORCH_INSTALL" -eq 1 ]; then
|
|
install_selected_torch "$TORCH_FLAVOR"
|
|
write_torch_state
|
|
fi
|
|
|
|
if [ ! -d node_modules ]; then
|
|
NEED_NODE_DEPS_INSTALL=1
|
|
elif ! state_matches "$NODE_DEPS_STATE_FILE" package.json package-lock.json; then
|
|
NEED_NODE_DEPS_INSTALL=1
|
|
fi
|
|
|
|
if [ "$NEED_NODE_DEPS_INSTALL" -eq 1 ]; then
|
|
echo "Installing Node dependencies"
|
|
npm install --no-fund --no-audit
|
|
mkdir -p node_modules
|
|
write_state "$NODE_DEPS_STATE_FILE" package.json package-lock.json
|
|
fi
|
|
|
|
if [ "$HEIMGEIST_BOOTSTRAP_ONLY" = "1" ]; then
|
|
echo "Heimgeist development dependencies are ready."
|
|
exit 0
|
|
fi
|
|
|
|
npm run dev
|