#!/usr/bin/env bash # pack.sh - RK3578 二进制部署打包脚本 # 用法: bash deploy/pack.sh [输出目录] # # 前置条件: # 在项目根目录执行: pyinstaller HookVision-linux.spec --noconfirm # # 输出: # hookvision_rk3578/ - 可直接传输到 RK3578 的二进制部署目录(不含源码) set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" PROJECT_ROOT="$(dirname "$SCRIPT_DIR")" PACKAGE_NAME="hookvision_rk3578" BUILD_DIR="/tmp/${PACKAGE_NAME}" echo "=== HookVision RK3578 二进制部署包构建 ===" echo "项目根目录: ${PROJECT_ROOT}" echo "构建目录: ${BUILD_DIR}" # 检查 PyInstaller 产出 DIST_DIR="${PROJECT_ROOT}/dist/HookVision" if [ ! -f "${DIST_DIR}/HookVision" ]; then echo "错误: 未找到 PyInstaller 构建产物 ${DIST_DIR}/HookVision" echo "请先在项目根目录执行: pyinstaller HookVision-linux.spec --noconfirm" exit 1 fi # 清理旧构建 rm -rf "${BUILD_DIR}" mkdir -p "${BUILD_DIR}/hookvision" # ---------- 复制二进制 ---------- echo "[1/5] 复制二进制可执行文件..." cp "${DIST_DIR}/HookVision" "${BUILD_DIR}/hookvision/" cp -r "${DIST_DIR}/_internal" "${BUILD_DIR}/hookvision/" # ---------- 复制配置文件 ---------- echo "[2/5] 复制配置文件..." cp "${PROJECT_ROOT}/config.ini" "${BUILD_DIR}/hookvision/" cp "${PROJECT_ROOT}/config.prod.ini" "${BUILD_DIR}/hookvision/" cp "${PROJECT_ROOT}/config.dev.ini" "${BUILD_DIR}/hookvision/" # ---------- 复制离线依赖 ---------- echo "[3/5] 复制离线 .deb 依赖..." if [ -d "${PROJECT_ROOT}/deploy/hookvision_rk3578/debs" ]; then cp -r "${PROJECT_ROOT}/deploy/hookvision_rk3578/debs" "${BUILD_DIR}/" fi # ---------- 生成 install.sh ---------- echo "[4/5] 生成 install.sh..." cat > "${BUILD_DIR}/install.sh" << 'INSTALL_EOF' #!/usr/bin/env bash # install.sh - RK3578 二进制部署安装脚本 # 用法: sudo bash install.sh # # 说明: 此包为 PyInstaller 编译的二进制版本,无需安装 Python 依赖 # 系统依赖以离线 .deb 包提供,无需联网 set -euo pipefail INSTALL_DIR="/opt/hookvision" SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" echo "=== HookVision RK3578 二进制安装 ===" # 卸载旧版本 echo "卸载旧版本..." if [ -d "${INSTALL_DIR}" ]; then systemctl stop hookvision 2>/dev/null || true systemctl disable hookvision 2>/dev/null || true rm -rf "${INSTALL_DIR}" echo "旧版本已卸载" else echo "未找到旧版本,跳过" fi # 安装离线系统依赖 echo "[1/3] 安装离线系统依赖..." if [ -d "${SCRIPT_DIR}/debs" ] && ls "${SCRIPT_DIR}/debs/"*.deb >/dev/null 2>&1; then dpkg -i "${SCRIPT_DIR}/debs/"*.deb 2>/dev/null || true apt-get install -y -f 2>/dev/null || true echo "离线依赖安装完成" else echo "未找到离线依赖包,跳过" fi # 备份目标设备上的已有配置文件 echo "[2/4] 检查已有配置文件..." BACKUP_DIR="" if [ -d "${INSTALL_DIR}" ]; then BACKUP_DIR="/tmp/hookvision_config_backup_$$" mkdir -p "${BACKUP_DIR}" for f in config.ini config.prod.ini config.dev.ini; do if [ -f "${INSTALL_DIR}/hookvision/$f" ]; then cp "${INSTALL_DIR}/hookvision/$f" "${BACKUP_DIR}/" echo " 备份: $f" fi done fi # 创建安装目录 echo "[3/4] 创建安装目录 ${INSTALL_DIR}..." mkdir -p "${INSTALL_DIR}" # 复制文件 echo "[4/4] 复制应用文件..." cp -r "${SCRIPT_DIR}/hookvision" "${INSTALL_DIR}/" cp -r "${SCRIPT_DIR}/start.sh" "${INSTALL_DIR}/" chmod +x "${INSTALL_DIR}/hookvision/HookVision" # 恢复目标设备上的配置文件 if [ -n "${BACKUP_DIR}" ] && [ -d "${BACKUP_DIR}" ]; then echo "恢复已有配置文件..." for f in config.ini config.prod.ini config.dev.ini; do if [ -f "${BACKUP_DIR}/$f" ]; then cp "${BACKUP_DIR}/$f" "${INSTALL_DIR}/hookvision/" echo " 恢复: $f" fi done rm -rf "${BACKUP_DIR}" fi # 安装 systemd 服务 echo "安装 systemd 服务..." cat > /etc/systemd/system/hookvision.service << 'SERVICE_EOF' [Unit] Description=HookVision - 钢包工位视频监测系统 After=network-online.target graphical.target Wants=network-online.target Requires=display-manager.service [Service] Type=simple ExecStart=/opt/hookvision/start.sh WorkingDirectory=/opt/hookvision Restart=on-failure RestartSec=5 Environment=DISPLAY=:0 Environment=QT_QPA_PLATFORM=xcb [Install] WantedBy=graphical.target SERVICE_EOF systemctl daemon-reload systemctl enable hookvision echo "systemd 服务已安装并设置开机自启" # 设置屏幕永不熄屏 echo "设置屏幕永不熄屏..." if [ -d /etc/xdg/autostart ]; then cat > /etc/xdg/autostart/screensaver-disable.desktop << 'DESKTOP_EOF' [Desktop Entry] Type=Application Name=Disable Screensaver Exec=bash -c 'xset s off && xset -dpms && xset s noblank' Hidden=false NoDisplay=true X-GNOME-Autostart-enabled=true DESKTOP_EOF fi if command -v xset &>/dev/null; then xset s off 2>/dev/null || true xset -dpms 2>/dev/null || true xset s noblank 2>/dev/null || true fi # 禁用 lightdm 屏幕保护(如使用 lightdm) if [ -f /etc/lightdm/lightdm.conf ]; then sed -i 's/^greeter-setup-script=.*/greeter-setup-script=xset s off \&\& xset -dpms \&\& xset s noblank/' /etc/lightdm/lightdm.conf 2>/dev/null || true fi echo "屏幕永不熄屏已设置" # 创建软链接 ln -sf "${INSTALL_DIR}/install.sh" /usr/local/bin/hv-install 2>/dev/null || true echo "" echo "=== 安装完成 ===" echo "启动服务: systemctl start hookvision" echo "查看状态: systemctl status hookvision" INSTALL_EOF chmod +x "${BUILD_DIR}/install.sh" # ---------- 生成 start.sh ---------- echo "[5/5] 生成 start.sh..." cat > "${BUILD_DIR}/start.sh" << 'START_EOF' #!/usr/bin/env bash # start.sh - HookVision 二进制启动脚本 # 用法: bash start.sh [--prod|--dev] set -uo pipefail SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" # 默认使用生产配置 MODE_FLAG="--prod" case "${1:-}" in --dev) MODE_FLAG="--dev" ;; --prod) MODE_FLAG="--prod" ;; *) if [ -f "${SCRIPT_DIR}/config.prod.ini" ]; then MODE_FLAG="--prod" elif [ -f "${SCRIPT_DIR}/config.dev.ini" ]; then MODE_FLAG="--dev" fi ;; esac cd "${SCRIPT_DIR}" # 捕获信号,优雅退出 cleanup() { echo "收到退出信号,正在停止 HookVision..." kill "$PID" 2>/dev/null wait "$PID" 2>/dev/null echo "已退出" exit 0 } trap cleanup SIGINT SIGTERM SIGHUP echo "启动 HookVision (${MODE_FLAG})..." ./hookvision/HookVision ${MODE_FLAG} & PID=$! wait "$PID" START_EOF chmod +x "${BUILD_DIR}/start.sh" # ---------- 拷贝到输出目录 ---------- OUTPUT_DIR="${1:-$(dirname "${PROJECT_ROOT}")}" OUTPUT_PATH="${OUTPUT_DIR}/${PACKAGE_NAME}" rm -rf "${OUTPUT_PATH}" cp -r "${BUILD_DIR}" "${OUTPUT_PATH}" # 清理构建目录 rm -rf "${BUILD_DIR}" echo "" echo "=== 构建完成 ===" echo "部署目录: ${OUTPUT_PATH}" echo "大小: $(du -sh "${OUTPUT_PATH}" | cut -f1)" echo "" echo "部署到 RK3578:" echo " scp -r ${OUTPUT_PATH} root@:/tmp/" echo " ssh root@" echo " cd /tmp/hookvision_rk3578 && sudo bash install.sh" echo " bash /opt/hookvision/start.sh"