From a3c9d37b18172fe1d93e82718f1fc1324cbc024b Mon Sep 17 00:00:00 2001 From: Victor Giers Date: Mon, 22 Jun 2026 20:24:14 +0200 Subject: [PATCH] Improve dependency management in run.sh by adding automatic download, verification, and path setting for required Node.js versions (v18+). --- README.md | 3 +- run.sh | 128 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 129 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index d5308a9..3e1337a 100644 --- a/README.md +++ b/README.md @@ -40,7 +40,6 @@ Packaged Tauri builds launch the bundled backend with app-managed data paths so Requirements: -- Node.js 18+ - Python 3.13 - Ollama running locally - Optional: SearXNG on `http://127.0.0.1:8888` @@ -51,7 +50,7 @@ Quick start: ./run.sh ``` -This creates or refreshes `backend/.venv`, installs Python dependencies, installs npm dependencies, and starts the dev stack. +This creates or refreshes `backend/.venv`, installs Python dependencies, installs npm dependencies, and starts the dev stack. If Node.js 18+ and npm are missing, `run.sh` downloads the current Node.js 22 LTS binary for Linux or macOS into the user cache and verifies its SHA-256 checksum. Set `HEIMGEIST_NODE_MAJOR` or `HEIMGEIST_NODE_DIR` to override that bootstrap. On Linux `x86_64`, `run.sh` now selects a PyTorch flavor before installing `openai-whisper`: diff --git a/run.sh b/run.sh index 3792766..05b3d82 100755 --- a/run.sh +++ b/run.sh @@ -1,16 +1,142 @@ #!/bin/sh set -eu +SCRIPT_DIR="$(CDPATH= cd "$(dirname "$0")" && pwd)" +cd "$SCRIPT_DIR" + 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_TORCH_FLAVOR="${HEIMGEIST_TORCH_FLAVOR:-auto}" HEIMGEIST_TORCH_INDEX_URL="${HEIMGEIST_TORCH_INDEX_URL:-}" HEIMGEIST_FORCE_BOOTSTRAP="${HEIMGEIST_FORCE_BOOTSTRAP:-0}" +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 "Node.js 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_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 @@ -164,6 +290,8 @@ install_selected_torch() { esac } +ensure_node_runtime + if ! command -v "$PYTHON_BIN" >/dev/null 2>&1; then echo "Python 3.13 is required. Set PYTHON_BIN to a Python 3.13 executable if needed." >&2 exit 1