pack.sh 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253
  1. #!/usr/bin/env bash
  2. # pack.sh - RK3578 二进制部署打包脚本
  3. # 用法: bash deploy/pack.sh [输出目录]
  4. #
  5. # 前置条件:
  6. # 在项目根目录执行: pyinstaller HookVision-linux.spec --noconfirm
  7. #
  8. # 输出:
  9. # hookvision_rk3578/ - 可直接传输到 RK3578 的二进制部署目录(不含源码)
  10. set -euo pipefail
  11. SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
  12. PROJECT_ROOT="$(dirname "$SCRIPT_DIR")"
  13. PACKAGE_NAME="hookvision_rk3578"
  14. BUILD_DIR="/tmp/${PACKAGE_NAME}"
  15. echo "=== HookVision RK3578 二进制部署包构建 ==="
  16. echo "项目根目录: ${PROJECT_ROOT}"
  17. echo "构建目录: ${BUILD_DIR}"
  18. # 检查 PyInstaller 产出
  19. DIST_DIR="${PROJECT_ROOT}/dist/HookVision"
  20. if [ ! -f "${DIST_DIR}/HookVision" ]; then
  21. echo "错误: 未找到 PyInstaller 构建产物 ${DIST_DIR}/HookVision"
  22. echo "请先在项目根目录执行: pyinstaller HookVision-linux.spec --noconfirm"
  23. exit 1
  24. fi
  25. # 清理旧构建
  26. rm -rf "${BUILD_DIR}"
  27. mkdir -p "${BUILD_DIR}/hookvision"
  28. # ---------- 复制二进制 ----------
  29. echo "[1/5] 复制二进制可执行文件..."
  30. cp "${DIST_DIR}/HookVision" "${BUILD_DIR}/hookvision/"
  31. cp -r "${DIST_DIR}/_internal" "${BUILD_DIR}/hookvision/"
  32. # ---------- 复制配置文件 ----------
  33. echo "[2/5] 复制配置文件..."
  34. cp "${PROJECT_ROOT}/config.ini" "${BUILD_DIR}/hookvision/"
  35. cp "${PROJECT_ROOT}/config.prod.ini" "${BUILD_DIR}/hookvision/"
  36. cp "${PROJECT_ROOT}/config.dev.ini" "${BUILD_DIR}/hookvision/"
  37. # ---------- 复制离线依赖 ----------
  38. echo "[3/5] 复制离线 .deb 依赖..."
  39. if [ -d "${PROJECT_ROOT}/deploy/hookvision_rk3578/debs" ]; then
  40. cp -r "${PROJECT_ROOT}/deploy/hookvision_rk3578/debs" "${BUILD_DIR}/"
  41. fi
  42. # ---------- 生成 install.sh ----------
  43. echo "[4/5] 生成 install.sh..."
  44. cat > "${BUILD_DIR}/install.sh" << 'INSTALL_EOF'
  45. #!/usr/bin/env bash
  46. # install.sh - RK3578 二进制部署安装脚本
  47. # 用法: sudo bash install.sh
  48. #
  49. # 说明: 此包为 PyInstaller 编译的二进制版本,无需安装 Python 依赖
  50. # 系统依赖以离线 .deb 包提供,无需联网
  51. set -euo pipefail
  52. INSTALL_DIR="/opt/hookvision"
  53. SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
  54. echo "=== HookVision RK3578 二进制安装 ==="
  55. # 卸载旧版本
  56. echo "卸载旧版本..."
  57. if [ -d "${INSTALL_DIR}" ]; then
  58. systemctl stop hookvision 2>/dev/null || true
  59. systemctl disable hookvision 2>/dev/null || true
  60. rm -rf "${INSTALL_DIR}"
  61. echo "旧版本已卸载"
  62. else
  63. echo "未找到旧版本,跳过"
  64. fi
  65. # 安装离线系统依赖
  66. echo "[1/3] 安装离线系统依赖..."
  67. if [ -d "${SCRIPT_DIR}/debs" ] && ls "${SCRIPT_DIR}/debs/"*.deb >/dev/null 2>&1; then
  68. dpkg -i "${SCRIPT_DIR}/debs/"*.deb 2>/dev/null || true
  69. apt-get install -y -f 2>/dev/null || true
  70. echo "离线依赖安装完成"
  71. else
  72. echo "未找到离线依赖包,跳过"
  73. fi
  74. # 备份目标设备上的已有配置文件
  75. echo "[2/4] 检查已有配置文件..."
  76. BACKUP_DIR=""
  77. if [ -d "${INSTALL_DIR}" ]; then
  78. BACKUP_DIR="/tmp/hookvision_config_backup_$$"
  79. mkdir -p "${BACKUP_DIR}"
  80. for f in config.ini config.prod.ini config.dev.ini; do
  81. if [ -f "${INSTALL_DIR}/hookvision/$f" ]; then
  82. cp "${INSTALL_DIR}/hookvision/$f" "${BACKUP_DIR}/"
  83. echo " 备份: $f"
  84. fi
  85. done
  86. fi
  87. # 创建安装目录
  88. echo "[3/4] 创建安装目录 ${INSTALL_DIR}..."
  89. mkdir -p "${INSTALL_DIR}"
  90. # 复制文件
  91. echo "[4/4] 复制应用文件..."
  92. cp -r "${SCRIPT_DIR}/hookvision" "${INSTALL_DIR}/"
  93. cp -r "${SCRIPT_DIR}/start.sh" "${INSTALL_DIR}/"
  94. chmod +x "${INSTALL_DIR}/hookvision/HookVision"
  95. # 恢复目标设备上的配置文件
  96. if [ -n "${BACKUP_DIR}" ] && [ -d "${BACKUP_DIR}" ]; then
  97. echo "恢复已有配置文件..."
  98. for f in config.ini config.prod.ini config.dev.ini; do
  99. if [ -f "${BACKUP_DIR}/$f" ]; then
  100. cp "${BACKUP_DIR}/$f" "${INSTALL_DIR}/hookvision/"
  101. echo " 恢复: $f"
  102. fi
  103. done
  104. rm -rf "${BACKUP_DIR}"
  105. fi
  106. # 安装 systemd 服务
  107. echo "安装 systemd 服务..."
  108. cat > /etc/systemd/system/hookvision.service << 'SERVICE_EOF'
  109. [Unit]
  110. Description=HookVision - 钢包工位视频监测系统
  111. After=network-online.target graphical.target
  112. Wants=network-online.target
  113. Requires=display-manager.service
  114. [Service]
  115. Type=simple
  116. ExecStart=/opt/hookvision/start.sh
  117. WorkingDirectory=/opt/hookvision
  118. Restart=on-failure
  119. RestartSec=5
  120. Environment=DISPLAY=:0
  121. Environment=QT_QPA_PLATFORM=xcb
  122. [Install]
  123. WantedBy=graphical.target
  124. SERVICE_EOF
  125. systemctl daemon-reload
  126. systemctl enable hookvision
  127. echo "systemd 服务已安装并设置开机自启"
  128. # 设置屏幕永不熄屏
  129. echo "设置屏幕永不熄屏..."
  130. if [ -d /etc/xdg/autostart ]; then
  131. cat > /etc/xdg/autostart/screensaver-disable.desktop << 'DESKTOP_EOF'
  132. [Desktop Entry]
  133. Type=Application
  134. Name=Disable Screensaver
  135. Exec=bash -c 'xset s off && xset -dpms && xset s noblank'
  136. Hidden=false
  137. NoDisplay=true
  138. X-GNOME-Autostart-enabled=true
  139. DESKTOP_EOF
  140. fi
  141. if command -v xset &>/dev/null; then
  142. xset s off 2>/dev/null || true
  143. xset -dpms 2>/dev/null || true
  144. xset s noblank 2>/dev/null || true
  145. fi
  146. # 禁用 lightdm 屏幕保护(如使用 lightdm)
  147. if [ -f /etc/lightdm/lightdm.conf ]; then
  148. 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
  149. fi
  150. echo "屏幕永不熄屏已设置"
  151. # 创建软链接
  152. ln -sf "${INSTALL_DIR}/install.sh" /usr/local/bin/hv-install 2>/dev/null || true
  153. echo ""
  154. echo "=== 安装完成 ==="
  155. echo "启动服务: systemctl start hookvision"
  156. echo "查看状态: systemctl status hookvision"
  157. INSTALL_EOF
  158. chmod +x "${BUILD_DIR}/install.sh"
  159. # ---------- 生成 start.sh ----------
  160. echo "[5/5] 生成 start.sh..."
  161. cat > "${BUILD_DIR}/start.sh" << 'START_EOF'
  162. #!/usr/bin/env bash
  163. # start.sh - HookVision 二进制启动脚本
  164. # 用法: bash start.sh [--prod|--dev]
  165. set -uo pipefail
  166. SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
  167. # 默认使用生产配置
  168. MODE_FLAG="--prod"
  169. case "${1:-}" in
  170. --dev)
  171. MODE_FLAG="--dev"
  172. ;;
  173. --prod)
  174. MODE_FLAG="--prod"
  175. ;;
  176. *)
  177. if [ -f "${SCRIPT_DIR}/config.prod.ini" ]; then
  178. MODE_FLAG="--prod"
  179. elif [ -f "${SCRIPT_DIR}/config.dev.ini" ]; then
  180. MODE_FLAG="--dev"
  181. fi
  182. ;;
  183. esac
  184. cd "${SCRIPT_DIR}"
  185. # 捕获信号,优雅退出
  186. cleanup() {
  187. echo "收到退出信号,正在停止 HookVision..."
  188. kill "$PID" 2>/dev/null
  189. wait "$PID" 2>/dev/null
  190. echo "已退出"
  191. exit 0
  192. }
  193. trap cleanup SIGINT SIGTERM SIGHUP
  194. echo "启动 HookVision (${MODE_FLAG})..."
  195. ./hookvision/HookVision ${MODE_FLAG} &
  196. PID=$!
  197. wait "$PID"
  198. START_EOF
  199. chmod +x "${BUILD_DIR}/start.sh"
  200. # ---------- 拷贝到输出目录 ----------
  201. OUTPUT_DIR="${1:-$(dirname "${PROJECT_ROOT}")}"
  202. OUTPUT_PATH="${OUTPUT_DIR}/${PACKAGE_NAME}"
  203. rm -rf "${OUTPUT_PATH}"
  204. cp -r "${BUILD_DIR}" "${OUTPUT_PATH}"
  205. # 清理构建目录
  206. rm -rf "${BUILD_DIR}"
  207. echo ""
  208. echo "=== 构建完成 ==="
  209. echo "部署目录: ${OUTPUT_PATH}"
  210. echo "大小: $(du -sh "${OUTPUT_PATH}" | cut -f1)"
  211. echo ""
  212. echo "部署到 RK3578:"
  213. echo " scp -r ${OUTPUT_PATH} root@<RK3578_IP>:/tmp/"
  214. echo " ssh root@<RK3578_IP>"
  215. echo " cd /tmp/hookvision_rk3578 && sudo bash install.sh"
  216. echo " bash /opt/hookvision/start.sh"