108 lines
2.8 KiB
Bash
Executable File
108 lines
2.8 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
PROJECT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
PYTHON_BIN="${PYTHON_BIN:-python3.12}"
|
|
VENV_DIR="${PROJECT_DIR}/.venv"
|
|
WHEELHOUSE_DIR="${PROJECT_DIR}/wheelhouse"
|
|
LOCK_FILE="${PROJECT_DIR}/requirements.lock.txt"
|
|
WEIGHTS_FILE="${PROJECT_DIR}/weights/yolo11n.pt"
|
|
RUN_SCRIPT="${PROJECT_DIR}/scripts/run.sh"
|
|
INSTALL_SERVICE_SCRIPT="${PROJECT_DIR}/scripts/install_service.sh"
|
|
PROJECT_USER="${SUDO_USER:-$(id -un)}"
|
|
|
|
run_privileged() {
|
|
if [[ "$(id -u)" -eq 0 ]]; then
|
|
"$@"
|
|
return
|
|
fi
|
|
sudo "$@"
|
|
}
|
|
|
|
run_project_user() {
|
|
if [[ "$(id -u)" -eq 0 && -n "${SUDO_USER:-}" ]]; then
|
|
sudo -u "${PROJECT_USER}" -H "$@"
|
|
return
|
|
fi
|
|
"$@"
|
|
}
|
|
|
|
ensure_system_package() {
|
|
local command_name="$1"
|
|
local package_name="$2"
|
|
if command -v "${command_name}" >/dev/null 2>&1; then
|
|
return
|
|
fi
|
|
|
|
echo "Installing missing package: ${package_name}"
|
|
run_privileged apt-get -o Acquire::ForceIPv4=true update
|
|
run_privileged apt-get -o Acquire::ForceIPv4=true install -y "${package_name}"
|
|
}
|
|
|
|
require_file() {
|
|
local target="$1"
|
|
if [[ ! -e "${target}" ]]; then
|
|
echo "Missing required file: ${target}" >&2
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
if ! command -v "${PYTHON_BIN}" >/dev/null 2>&1; then
|
|
echo "Python interpreter not found: ${PYTHON_BIN}" >&2
|
|
echo "Set PYTHON_BIN=/path/to/python3.12 if needed." >&2
|
|
exit 1
|
|
fi
|
|
|
|
ensure_system_package ffmpeg ffmpeg
|
|
|
|
if [[ ! -d "/usr/lib/python3.12/venv" && ! -d "/usr/lib/python3.12/ensurepip" ]]; then
|
|
echo "Installing missing package: python3.12-venv"
|
|
run_privileged apt-get -o Acquire::ForceIPv4=true update
|
|
run_privileged apt-get -o Acquire::ForceIPv4=true install -y python3.12-venv
|
|
fi
|
|
|
|
if ! command -v nvidia-smi >/dev/null 2>&1; then
|
|
echo "nvidia-smi is required but not installed." >&2
|
|
exit 1
|
|
fi
|
|
|
|
require_file "${LOCK_FILE}"
|
|
require_file "${WEIGHTS_FILE}"
|
|
require_file "${RUN_SCRIPT}"
|
|
require_file "${INSTALL_SERVICE_SCRIPT}"
|
|
|
|
if [[ ! -d "${WHEELHOUSE_DIR}" ]]; then
|
|
echo "Missing wheelhouse directory: ${WHEELHOUSE_DIR}" >&2
|
|
exit 1
|
|
fi
|
|
|
|
run_project_user "${PYTHON_BIN}" -m venv "${VENV_DIR}"
|
|
run_project_user "${VENV_DIR}/bin/python" -m ensurepip --upgrade
|
|
while IFS= read -r requirement; do
|
|
if [[ -z "${requirement}" ]]; then
|
|
continue
|
|
fi
|
|
run_project_user "${VENV_DIR}/bin/python" -m pip install \
|
|
--no-index \
|
|
--no-deps \
|
|
--find-links "${WHEELHOUSE_DIR}" \
|
|
"${requirement}"
|
|
done < "${LOCK_FILE}"
|
|
|
|
mkdir -p \
|
|
"${PROJECT_DIR}/config" \
|
|
"${PROJECT_DIR}/data/runtime" \
|
|
"${PROJECT_DIR}/data/staff_gallery" \
|
|
"${PROJECT_DIR}/logs"
|
|
|
|
run_project_user bash "${RUN_SCRIPT}" --prepare-only
|
|
bash "${INSTALL_SERVICE_SCRIPT}"
|
|
run_privileged systemctl enable --now store-dwell-alert.service
|
|
|
|
cat <<EOF
|
|
Offline install complete.
|
|
Service started and enabled on boot: store-dwell-alert.service
|
|
Runtime log: ${PROJECT_DIR}/logs/runtime.log
|
|
Event sink: ${PROJECT_DIR}/logs/events.jsonl
|
|
EOF
|