2026-03-24 16:14:11 +08:00
|
|
|
#!/bin/bash
|
|
|
|
|
set -euo pipefail
|
|
|
|
|
|
|
|
|
|
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
|
|
|
BACKEND_DIR="$SCRIPT_DIR/backend"
|
|
|
|
|
FRONTEND_DIR="$SCRIPT_DIR/frontend"
|
|
|
|
|
ROOT_ENV="$SCRIPT_DIR/.env"
|
|
|
|
|
BACKEND_ENV="$BACKEND_DIR/.env"
|
|
|
|
|
BACKEND_ENV_EXAMPLE="$BACKEND_DIR/.env.example"
|
|
|
|
|
FRONTEND_ENV_LOCAL="$FRONTEND_DIR/.env.local"
|
|
|
|
|
HOST_OS="$(uname -s)"
|
|
|
|
|
USE_WINDOWS_TOOLS=false
|
|
|
|
|
|
|
|
|
|
if command -v cmd.exe >/dev/null 2>&1 || command -v powershell.exe >/dev/null 2>&1; then
|
|
|
|
|
USE_WINDOWS_TOOLS=true
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
if [[ "$USE_WINDOWS_TOOLS" == true ]]; then
|
|
|
|
|
BACKEND_PYTHON="$BACKEND_DIR/.venv/Scripts/python.exe"
|
|
|
|
|
FRONTEND_NPM="npm.cmd"
|
|
|
|
|
else
|
|
|
|
|
BACKEND_PYTHON="$BACKEND_DIR/.venv/bin/python"
|
|
|
|
|
FRONTEND_NPM="npm"
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
print_header() {
|
|
|
|
|
echo "=========================================="
|
|
|
|
|
echo " Jarvis - Setup"
|
|
|
|
|
echo "=========================================="
|
|
|
|
|
echo
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
require_command() {
|
|
|
|
|
local command_name="$1"
|
|
|
|
|
local hint="$2"
|
|
|
|
|
if ! command -v "$command_name" >/dev/null 2>&1; then
|
|
|
|
|
echo "[ERROR] $command_name was not found."
|
|
|
|
|
echo "[ERROR] $hint"
|
|
|
|
|
exit 1
|
|
|
|
|
fi
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ensure_backend_env() {
|
|
|
|
|
if [[ -f "$BACKEND_ENV" ]]; then
|
|
|
|
|
echo "[OK] Backend env file exists: $BACKEND_ENV"
|
|
|
|
|
return 0
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
if [[ -f "$ROOT_ENV" ]]; then
|
|
|
|
|
cp "$ROOT_ENV" "$BACKEND_ENV"
|
|
|
|
|
echo "[INFO] Created backend/.env from root .env"
|
|
|
|
|
return 0
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
if [[ -f "$BACKEND_ENV_EXAMPLE" ]]; then
|
|
|
|
|
cp "$BACKEND_ENV_EXAMPLE" "$BACKEND_ENV"
|
|
|
|
|
echo "[INFO] Created backend/.env from backend/.env.example"
|
|
|
|
|
echo "[INFO] Edit $BACKEND_ENV before running start.sh if needed."
|
|
|
|
|
return 0
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
echo "[ERROR] Could not create backend/.env"
|
|
|
|
|
exit 1
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sync_frontend_env() {
|
|
|
|
|
local backend_host
|
|
|
|
|
local backend_port
|
|
|
|
|
|
|
|
|
|
backend_host="$(grep '^HOST=' "$BACKEND_ENV" | cut -d'=' -f2- | tr -d '\r' || true)"
|
|
|
|
|
backend_port="$(grep '^PORT=' "$BACKEND_ENV" | cut -d'=' -f2- | tr -d '\r' || true)"
|
|
|
|
|
|
|
|
|
|
[[ -z "$backend_host" ]] && backend_host="127.0.0.1"
|
|
|
|
|
[[ -z "$backend_port" ]] && backend_port="3337"
|
|
|
|
|
|
|
|
|
|
printf 'VITE_API_URL=http://%s:%s\n' "$backend_host" "$backend_port" > "$FRONTEND_ENV_LOCAL"
|
|
|
|
|
echo "[OK] Synced frontend/.env.local -> http://$backend_host:$backend_port"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
print_header
|
|
|
|
|
|
|
|
|
|
require_command npm "Install Node.js and npm first."
|
|
|
|
|
|
|
|
|
|
if [[ "$USE_WINDOWS_TOOLS" == true ]]; then
|
|
|
|
|
if command -v py.exe >/dev/null 2>&1; then
|
2026-03-25 21:42:26 +08:00
|
|
|
if py.exe -3.13 --version >/dev/null 2>&1; then
|
|
|
|
|
PYTHON_BOOTSTRAP=("py.exe" "-3.13")
|
|
|
|
|
elif py.exe -3.12 --version >/dev/null 2>&1; then
|
|
|
|
|
PYTHON_BOOTSTRAP=("py.exe" "-3.12")
|
|
|
|
|
elif py.exe -3 --version >/dev/null 2>&1; then
|
|
|
|
|
PYTHON_BOOTSTRAP=("py.exe" "-3")
|
|
|
|
|
else
|
|
|
|
|
echo "[ERROR] Python 3 was not found via py.exe."
|
|
|
|
|
echo "[ERROR] Install Python 3.12+ for Windows first."
|
|
|
|
|
exit 1
|
|
|
|
|
fi
|
2026-03-24 16:14:11 +08:00
|
|
|
elif command -v python.exe >/dev/null 2>&1; then
|
|
|
|
|
PYTHON_BOOTSTRAP=("python.exe")
|
|
|
|
|
elif command -v python >/dev/null 2>&1; then
|
|
|
|
|
PYTHON_BOOTSTRAP=("python")
|
|
|
|
|
else
|
|
|
|
|
echo "[ERROR] Python was not found."
|
|
|
|
|
echo "[ERROR] Install Python 3.12+ for Windows first."
|
|
|
|
|
exit 1
|
|
|
|
|
fi
|
|
|
|
|
else
|
|
|
|
|
if command -v python3 >/dev/null 2>&1; then
|
|
|
|
|
PYTHON_BOOTSTRAP=("python3")
|
|
|
|
|
elif command -v python >/dev/null 2>&1; then
|
|
|
|
|
PYTHON_BOOTSTRAP=("python")
|
|
|
|
|
else
|
|
|
|
|
echo "[ERROR] python3/python was not found."
|
|
|
|
|
echo "[ERROR] Install Python 3.12+ first."
|
|
|
|
|
exit 1
|
|
|
|
|
fi
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
install_backend_dependencies() {
|
|
|
|
|
if command -v uv >/dev/null 2>&1; then
|
|
|
|
|
echo "[INFO] Using uv to install backend dependencies..."
|
|
|
|
|
(
|
|
|
|
|
cd "$BACKEND_DIR"
|
|
|
|
|
uv sync
|
|
|
|
|
)
|
|
|
|
|
return 0
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
echo "[INFO] uv was not found. Falling back to venv + pip..."
|
|
|
|
|
(
|
|
|
|
|
cd "$BACKEND_DIR"
|
|
|
|
|
if ! "${PYTHON_BOOTSTRAP[@]}" -m venv .venv; then
|
|
|
|
|
echo "[WARN] python -m venv failed. Trying virtualenv fallback..."
|
|
|
|
|
"${PYTHON_BOOTSTRAP[@]}" -m pip install --user virtualenv
|
|
|
|
|
"${PYTHON_BOOTSTRAP[@]}" -m virtualenv .venv
|
|
|
|
|
fi
|
|
|
|
|
if [[ "$USE_WINDOWS_TOOLS" == true ]]; then
|
|
|
|
|
.venv/Scripts/python.exe -m pip install --upgrade pip
|
|
|
|
|
.venv/Scripts/python.exe -m pip install -e .
|
|
|
|
|
else
|
|
|
|
|
.venv/bin/python -m pip install --upgrade pip
|
|
|
|
|
.venv/bin/python -m pip install -e .
|
|
|
|
|
fi
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
install_frontend_dependencies() {
|
|
|
|
|
if [[ "$USE_WINDOWS_TOOLS" == true ]]; then
|
|
|
|
|
(
|
|
|
|
|
cd "$FRONTEND_DIR"
|
|
|
|
|
if [[ -f "package-lock.json" ]]; then
|
|
|
|
|
cmd.exe /c npm ci
|
|
|
|
|
else
|
|
|
|
|
cmd.exe /c npm install
|
|
|
|
|
fi
|
|
|
|
|
)
|
|
|
|
|
else
|
|
|
|
|
(
|
|
|
|
|
cd "$FRONTEND_DIR"
|
|
|
|
|
if [[ -f "package-lock.json" ]]; then
|
|
|
|
|
npm ci
|
|
|
|
|
else
|
|
|
|
|
npm install
|
|
|
|
|
fi
|
|
|
|
|
)
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
if [[ -f "$FRONTEND_DIR/node_modules/.bin/vite" || -f "$FRONTEND_DIR/node_modules/.bin/vite.cmd" ]]; then
|
|
|
|
|
return 0
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
echo "[ERROR] Frontend dependencies were installed, but vite was not found."
|
|
|
|
|
echo "[ERROR] Check frontend/node_modules and npm output."
|
|
|
|
|
exit 1
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
echo "[1/4] Prepare backend environment file..."
|
|
|
|
|
ensure_backend_env
|
|
|
|
|
|
|
|
|
|
echo
|
|
|
|
|
echo "[2/4] Install backend dependencies..."
|
|
|
|
|
install_backend_dependencies
|
|
|
|
|
|
|
|
|
|
if [[ "$USE_WINDOWS_TOOLS" == true ]]; then
|
|
|
|
|
if [[ ! -f "$BACKEND_PYTHON" ]]; then
|
|
|
|
|
echo "[ERROR] Backend virtual environment Python was not found after setup: $BACKEND_PYTHON"
|
|
|
|
|
exit 1
|
|
|
|
|
fi
|
|
|
|
|
else
|
|
|
|
|
if [[ ! -x "$BACKEND_PYTHON" ]]; then
|
|
|
|
|
echo "[ERROR] Backend virtual environment Python was not found after setup: $BACKEND_PYTHON"
|
|
|
|
|
exit 1
|
|
|
|
|
fi
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
echo "[OK] Backend dependencies installed."
|
|
|
|
|
|
|
|
|
|
echo
|
|
|
|
|
echo "[3/4] Install frontend dependencies..."
|
|
|
|
|
install_frontend_dependencies
|
|
|
|
|
echo "[OK] Frontend dependencies installed."
|
|
|
|
|
|
|
|
|
|
echo
|
|
|
|
|
echo "[4/4] Sync frontend API configuration..."
|
|
|
|
|
sync_frontend_env
|
|
|
|
|
|
|
|
|
|
echo
|
|
|
|
|
echo "=========================================="
|
|
|
|
|
echo " Setup complete"
|
|
|
|
|
echo
|
|
|
|
|
echo " Backend env: $BACKEND_ENV"
|
|
|
|
|
echo " Frontend env: $FRONTEND_ENV_LOCAL"
|
|
|
|
|
echo
|
|
|
|
|
echo " Next: bash start.sh"
|
|
|
|
|
echo "=========================================="
|