Browse Source

feat: 实现H5应用更新客户端脚本及static文件夹可选更新功能

主要功能:
- 创建完整的更新客户端脚本,支持从版本服务器下载并更新H5应用
- 实现static文件夹可选更新功能,使用-X和--reject-regex参数真正跳过下载
- 添加交互模式询问和命令行参数(-i/--include-static)控制
- 支持版本选择、备份、完整性验证等完整更新流程
- 创建详细的使用教程文档,包含使用场景和FAQ

技术实现:
- 使用wget的-X参数排除目录(专门用于递归下载)
- 使用--reject-regex正则表达式提供额外保障
- 双参数组合确保完全跳过static目录,真正节省网络流量
- 在更新摘要和日志中显示static文件夹状态

工作流调整:
- 临时注释GitHub Actions中的服务器部署步骤

改动文件:
- .github/workflows/build-linux-arm-appimage.yml(注释部署步骤)
- update-client.sh(新增,完整更新客户端脚本+static可选功能)
- update-client使用教程.md(新增,详细使用文档)
dengdx 3 days ago
parent
commit
2c8e0ed83a
3 changed files with 1348 additions and 7 deletions
  1. 7 7
      .github/workflows/build-linux-arm-appimage.yml
  2. 627 0
      update-client.sh
  3. 714 0
      update-client使用教程.md

+ 7 - 7
.github/workflows/build-linux-arm-appimage.yml

@@ -58,13 +58,13 @@ jobs:
           rsync -av --delete dist/h5/ /home/ccos/dros/linux-arm64-unpacked/h5/
           echo "✅ 文件已成功复制到 /home/ccos/dros/linux-arm64-unpacked/h5"
 
-      - name: 部署到服务器
-        env:
-          DEPLOY_KEY: ${{ secrets.DEPLOY_KEY }}
-          DEPLOY_HOST: ${{ secrets.DEPLOY_HOST }}
-          DEPLOY_USER: ${{ secrets.DEPLOY_USER }}
-          DEPLOY_PATH: ${{ secrets.DEPLOY_PATH }}
-        run: node .build/deploy-to-server.js
+      # - name: 部署到服务器
+      #   env:
+      #     DEPLOY_KEY: ${{ secrets.DEPLOY_KEY }}
+      #     DEPLOY_HOST: ${{ secrets.DEPLOY_HOST }}
+      #     DEPLOY_USER: ${{ secrets.DEPLOY_USER }}
+      #     DEPLOY_PATH: ${{ secrets.DEPLOY_PATH }}
+      #   run: node .build/deploy-to-server.js
 
   # build-pkg:
   #   needs: deploy-h5-production

+ 627 - 0
update-client.sh

@@ -0,0 +1,627 @@
+#!/usr/bin/env bash
+
+################################################################################
+# H5 应用更新客户端脚本
+# 
+# 功能:从版本服务器下载并更新 H5 应用
+# 版本:1.0.0
+# 作者:自动生成
+################################################################################
+
+set -euo pipefail  # 严格模式:遇到错误立即退出
+
+# ============================================================================
+# 颜色定义
+# ============================================================================
+readonly RED='\033[0;31m'
+readonly GREEN='\033[0;32m'
+readonly YELLOW='\033[1;33m'
+readonly BLUE='\033[0;34m'
+readonly NC='\033[0m' # No Color
+
+# ============================================================================
+# 全局变量
+# ============================================================================
+readonly SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+readonly LOCK_FILE="/tmp/update-client-${USER}.lock"
+readonly SERVER="dros.overs.games"
+readonly DEFAULT_USER="deploy"
+readonly DEFAULT_DIR="./h5"
+readonly LOG_DIR="./logs"
+
+# 用户输入变量
+USERNAME=""
+PASSWORD=""
+DOWNLOAD_DIR=""
+VERSION=""
+SILENT_MODE=false
+SKIP_CONFIRM=false
+INCLUDE_STATIC=false  # 是否包含 static 文件夹
+
+# 日志文件
+LOG_FILE=""
+
+# ============================================================================
+# 工具函数
+# ============================================================================
+
+# 打印信息
+log_info() {
+    echo -e "${GREEN}[INFO]${NC} $*" | tee -a "$LOG_FILE"
+}
+
+# 打印警告
+log_warn() {
+    echo -e "${YELLOW}[WARN]${NC} $*" | tee -a "$LOG_FILE"
+}
+
+# 打印错误
+log_error() {
+    echo -e "${RED}[ERROR]${NC} $*" | tee -a "$LOG_FILE" >&2
+}
+
+# 打印成功
+log_success() {
+    echo -e "${GREEN}[✓]${NC} $*" | tee -a "$LOG_FILE"
+}
+
+# 清理函数
+cleanup() {
+    if [ -f "$LOCK_FILE" ]; then
+        rm -f "$LOCK_FILE"
+    fi
+}
+
+# 设置清理陷阱
+trap cleanup EXIT INT TERM
+
+# ============================================================================
+# 帮助信息
+# ============================================================================
+show_help() {
+    cat << EOF
+H5 应用更新客户端
+
+用法: $0 [选项]
+
+选项:
+  -u, --user USERNAME       指定用户名(默认: $DEFAULT_USER)
+  -p, --password PASS       指定密码
+  -d, --dir DIRECTORY       指定下载目录(默认: $DEFAULT_DIR)
+  -v, --version VERSION     指定版本号(默认: latest)
+  -i, --include-static      包含 static 文件夹更新(默认: 不包含)
+  -y, --yes                 跳过确认提示
+  -s, --silent              静默模式(最小输出)
+  -h, --help                显示此帮助信息
+
+示例:
+  # 交互模式
+  $0
+
+  # 非交互模式(不包含 static)
+  $0 -u deploy -p mypassword -d ./h5 -v latest -y
+
+  # 包含 static 文件夹
+  $0 -u deploy -p mypassword -d ./h5 -v latest -y --include-static
+
+  # 静默模式
+  $0 -u deploy -p mypassword -v v1.1.5-20251129-062104 -y -s
+
+EOF
+}
+
+# ============================================================================
+# 检查依赖工具
+# ============================================================================
+check_dependencies() {
+    log_info "检查依赖工具..."
+    
+    local missing_tools=()
+    
+    for tool in curl wget tar; do
+        if ! command -v "$tool" &> /dev/null; then
+            missing_tools+=("$tool")
+        fi
+    done
+    
+    if [ ${#missing_tools[@]} -gt 0 ]; then
+        log_error "缺少必需工具: ${missing_tools[*]}"
+        log_error "请安装缺少的工具后重试"
+        exit 1
+    fi
+    
+    log_success "依赖工具检查通过"
+}
+
+# ============================================================================
+# 检查并发执行
+# ============================================================================
+check_lock() {
+    if [ -f "$LOCK_FILE" ]; then
+        log_error "更新脚本已在运行中(锁文件: $LOCK_FILE)"
+        log_error "如确认没有其他实例运行,请删除锁文件后重试"
+        exit 1
+    fi
+    
+    touch "$LOCK_FILE"
+    log_info "已创建锁文件"
+}
+
+# ============================================================================
+# 初始化日志
+# ============================================================================
+init_log() {
+    mkdir -p "$LOG_DIR"
+    LOG_FILE="$LOG_DIR/update_$(date +%Y%m%d_%H%M%S).log"
+    log_info "日志文件: $LOG_FILE"
+}
+
+# ============================================================================
+# 验证用户名格式
+# ============================================================================
+validate_username() {
+    local username=$1
+    
+    if [[ ! $username =~ ^[a-zA-Z0-9_]+$ ]]; then
+        log_error "用户名格式错误(仅允许字母、数字和下划线)"
+        return 1
+    fi
+    
+    return 0
+}
+
+# ============================================================================
+# 验证密码
+# ============================================================================
+validate_password() {
+    local password=$1
+    
+    if [ -z "$password" ]; then
+        log_error "密码不能为空"
+        return 1
+    fi
+    
+    if [ ${#password} -lt 6 ]; then
+        log_error "密码长度至少6位"
+        return 1
+    fi
+    
+    return 0
+}
+
+# ============================================================================
+# 获取用户输入
+# ============================================================================
+get_user_input() {
+    # 用户名
+    if [ -z "$USERNAME" ]; then
+        read -p "请输入用户名 [默认: $DEFAULT_USER]: " USERNAME
+        USERNAME=${USERNAME:-$DEFAULT_USER}
+    fi
+    
+    if ! validate_username "$USERNAME"; then
+        exit 1
+    fi
+    
+    log_info "用户名: $USERNAME"
+    
+    # 密码
+    if [ -z "$PASSWORD" ]; then
+        while true; do
+            read -s -p "请输入密码: " PASSWORD
+            echo
+            
+            if validate_password "$PASSWORD"; then
+                break
+            fi
+        done
+    fi
+    
+    log_info "密码已设置(已脱敏)"
+    
+    # 下载目录
+    if [ -z "$DOWNLOAD_DIR" ]; then
+        read -p "请输入下载目录 [默认: $DEFAULT_DIR]: " DOWNLOAD_DIR
+        DOWNLOAD_DIR=${DOWNLOAD_DIR:-$DEFAULT_DIR}
+    fi
+    
+    log_info "下载目录: $DOWNLOAD_DIR"
+    
+    # 询问是否更新 static 文件夹(仅在交互模式且未通过参数指定时询问)
+    if [ "$INCLUDE_STATIC" = "false" ]; then
+        read -p "是否需要更新 static 文件夹? [y/N]: " include_static
+        if [[ $include_static =~ ^[Yy]$ ]]; then
+            INCLUDE_STATIC=true
+            log_info "static 文件夹: 将包含在更新中"
+        else
+            INCLUDE_STATIC=false
+            log_info "static 文件夹: 将跳过更新"
+        fi
+    fi
+}
+
+# ============================================================================
+# 验证路径权限
+# ============================================================================
+validate_path() {
+    local dir=$1
+    
+    # 检查路径是否存在
+    if [ ! -d "$dir" ]; then
+        log_warn "目录不存在: $dir"
+        
+        if [ "$SKIP_CONFIRM" = false ]; then
+            read -p "是否创建该目录? [y/N]: " confirm
+            if [[ ! $confirm =~ ^[Yy]$ ]]; then
+                log_error "用户取消操作"
+                exit 1
+            fi
+        fi
+        
+        mkdir -p "$dir"
+        log_success "已创建目录: $dir"
+    fi
+    
+    # 检查写入权限
+    if [ ! -w "$dir" ]; then
+        log_error "无写入权限: $dir"
+        exit 1
+    fi
+    
+    log_success "路径验证通过"
+}
+
+# ============================================================================
+# 测试服务器连接
+# ============================================================================
+test_server_connection() {
+    log_info "测试服务器连接: https://$SERVER"
+    
+    if ! curl -k -s --max-time 10 --user "$USERNAME:$PASSWORD" \
+         "https://$SERVER/releases/" > /dev/null 2>&1; then
+        log_error "无法连接到服务器"
+        log_error "请检查网络连接、用户名和密码"
+        exit 1
+    fi
+    
+    log_success "服务器连接成功"
+}
+
+# ============================================================================
+# 获取版本列表
+# ============================================================================
+get_version_list() {
+    log_info "正在获取版本列表..."
+    
+    local versions
+    versions=$(curl -k -s --user "$USERNAME:$PASSWORD" \
+        "https://$SERVER/releases/" | \
+        grep -oP 'v\d+\.\d+\.\d+-\d{8}-\d{6}' | \
+        sort -Vr | \
+        head -10)
+    
+    if [ -z "$versions" ]; then
+        log_error "无法获取版本列表"
+        exit 1
+    fi
+    
+    echo "$versions"
+}
+
+# ============================================================================
+# 显示版本列表并选择
+# ============================================================================
+select_version() {
+    if [ -n "$VERSION" ]; then
+        log_info "使用指定版本: $VERSION"
+        return
+    fi
+    
+    log_info "获取可用版本..."
+    local versions
+    versions=$(get_version_list)
+    
+    echo
+    echo "可用版本列表(最新10个):"
+    echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
+    echo "  0. latest (最新版本)"
+    
+    local i=1
+    while IFS= read -r version; do
+        echo "  $i. $version"
+        ((i++))
+    done <<< "$versions"
+    echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
+    echo
+    
+    # 用户选择
+    while true; do
+        read -p "请选择版本 [0-$((i-1)),默认: 0]: " choice
+        choice=${choice:-0}
+        
+        if [[ $choice =~ ^[0-9]+$ ]]; then
+            if [ "$choice" -eq 0 ]; then
+                VERSION="latest"
+                break
+            elif [ "$choice" -lt "$i" ]; then
+                VERSION=$(echo "$versions" | sed -n "${choice}p")
+                break
+            fi
+        fi
+        
+        log_error "无效选择,请重新输入"
+    done
+    
+    log_info "已选择版本: $VERSION"
+}
+
+# ============================================================================
+# 验证版本是否存在
+# ============================================================================
+verify_version_exists() {
+    local version=$1
+    
+    log_info "验证版本: $version"
+    
+    if ! curl -k -s --fail --head --user "$USERNAME:$PASSWORD" \
+         "https://$SERVER/releases/$version/" > /dev/null 2>&1; then
+        log_error "版本不存在: $version"
+        exit 1
+    fi
+    
+    log_success "版本验证通过"
+}
+
+# ============================================================================
+# 备份当前版本
+# ============================================================================
+backup_current_version() {
+    local dir=$1
+    
+    if [ ! -d "$dir" ] || [ -z "$(ls -A "$dir" 2>/dev/null)" ]; then
+        log_info "无需备份(目录为空或不存在)"
+        return
+    fi
+    
+    local backup_name="${dir}_backup_$(date +%Y%m%d_%H%M%S)"
+    
+    log_info "备份当前版本到: $backup_name"
+    
+    if ! mv "$dir" "$backup_name"; then
+        log_error "备份失败"
+        exit 1
+    fi
+    
+    log_success "备份完成: $backup_name"
+}
+
+# ============================================================================
+# 下载并更新
+# ============================================================================
+download_and_update() {
+    local version=$1
+    local target_dir=$2
+    
+    log_info "开始下载版本: $version"
+    log_info "目标目录: $target_dir"
+    
+    mkdir -p "$target_dir"
+    
+    # 使用 wget 下载(显示进度)
+    local wget_opts=(
+        "--user=$USERNAME"
+        "--password=$PASSWORD"
+        "--no-check-certificate"
+        "--recursive"
+        "--no-parent"
+        "--no-host-directories"
+        "--cut-dirs=2"
+        "--level=inf"
+        "-N"
+        "-P"
+        "$target_dir"
+    )
+    
+    # 如果不包含 static,添加排除参数
+    if [ "$INCLUDE_STATIC" = "false" ]; then
+        wget_opts+=("-X" "static")
+        wget_opts+=("--reject-regex" ".*/static/.*")
+        log_info "static 文件夹: 跳过下载(使用排除参数)"
+    else
+        log_info "static 文件夹: 包含在更新中"
+    fi
+    
+    if [ "$SILENT_MODE" = true ]; then
+        wget_opts+=("-q")
+    fi
+    
+    if ! wget "${wget_opts[@]}" "https://$SERVER/releases/$version/"; then
+        log_error "下载失败"
+        exit 1
+    fi
+    
+    log_success "下载完成"
+}
+
+# ============================================================================
+# 验证文件完整性(如果存在校验文件)
+# ============================================================================
+verify_integrity() {
+    local dir=$1
+    
+    # 检查是否存在 MD5 校验文件
+    if [ -f "$dir/checksum.md5" ]; then
+        log_info "验证文件完整性(MD5)..."
+        
+        cd "$dir" || exit 1
+        if md5sum -c checksum.md5 > /dev/null 2>&1; then
+            log_success "文件完整性验证通过"
+        else
+            log_error "文件完整性验证失败"
+            exit 1
+        fi
+        cd - > /dev/null || exit 1
+    elif [ -f "$dir/checksum.sha256" ]; then
+        log_info "验证文件完整性(SHA256)..."
+        
+        cd "$dir" || exit 1
+        if sha256sum -c checksum.sha256 > /dev/null 2>&1; then
+            log_success "文件完整性验证通过"
+        else
+            log_error "文件完整性验证失败"
+            exit 1
+        fi
+        cd - > /dev/null || exit 1
+    else
+        log_warn "未找到校验文件,跳过完整性验证"
+    fi
+}
+
+# ============================================================================
+# 显示更新摘要
+# ============================================================================
+show_update_summary() {
+    local static_status
+    if [ "$INCLUDE_STATIC" = "true" ]; then
+        static_status="包含"
+    else
+        static_status="跳过"
+    fi
+    
+    echo
+    echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
+    echo "  更新摘要"
+    echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
+    echo "  服务器: $SERVER"
+    echo "  用户名: $USERNAME"
+    echo "  目标目录: $DOWNLOAD_DIR"
+    echo "  版本: $VERSION"
+    echo "  static 文件夹: $static_status"
+    echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
+    echo
+}
+
+# ============================================================================
+# 确认更新
+# ============================================================================
+confirm_update() {
+    if [ "$SKIP_CONFIRM" = true ]; then
+        return
+    fi
+    
+    read -p "确认执行更新? [y/N]: " confirm
+    if [[ ! $confirm =~ ^[Yy]$ ]]; then
+        log_info "用户取消更新"
+        exit 0
+    fi
+}
+
+# ============================================================================
+# 解析命令行参数
+# ============================================================================
+parse_args() {
+    while [[ $# -gt 0 ]]; do
+        case $1 in
+            -u|--user)
+                USERNAME="$2"
+                shift 2
+                ;;
+            -p|--password)
+                PASSWORD="$2"
+                shift 2
+                ;;
+            -d|--dir)
+                DOWNLOAD_DIR="$2"
+                shift 2
+                ;;
+            -v|--version)
+                VERSION="$2"
+                shift 2
+                ;;
+            -i|--include-static)
+                INCLUDE_STATIC=true
+                shift
+                ;;
+            -y|--yes)
+                SKIP_CONFIRM=true
+                shift
+                ;;
+            -s|--silent)
+                SILENT_MODE=true
+                shift
+                ;;
+            -h|--help)
+                show_help
+                exit 0
+                ;;
+            *)
+                log_error "未知选项: $1"
+                show_help
+                exit 1
+                ;;
+        esac
+    done
+}
+
+# ============================================================================
+# 主函数
+# ============================================================================
+main() {
+    # 解析命令行参数
+    parse_args "$@"
+    
+    # 初始化日志
+    init_log
+    
+    # 检查依赖
+    check_dependencies
+    
+    # 检查并发
+    check_lock
+    
+    # 获取用户输入
+    get_user_input
+    
+    # 验证路径
+    validate_path "$DOWNLOAD_DIR"
+    
+    # 测试服务器连接
+    test_server_connection
+    
+    # 选择版本
+    select_version
+    
+    # 验证版本存在
+    verify_version_exists "$VERSION"
+    
+    # 显示摘要
+    show_update_summary
+    
+    # 确认更新
+    confirm_update
+    
+    log_info "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
+    log_info "开始更新流程"
+    log_info "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
+    
+    # 备份当前版本
+    backup_current_version "$DOWNLOAD_DIR"
+    
+    # 下载并更新
+    download_and_update "$VERSION" "$DOWNLOAD_DIR"
+    
+    # 验证完整性
+    verify_integrity "$DOWNLOAD_DIR"
+    
+    log_info "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
+    log_success "更新完成!"
+    log_info "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
+    log_info "目标目录: $DOWNLOAD_DIR"
+    log_info "版本: $VERSION"
+    log_info "日志文件: $LOG_FILE"
+    
+    exit 0
+}
+
+# 运行主函数
+main "$@"

+ 714 - 0
update-client使用教程.md

@@ -0,0 +1,714 @@
+# H5 应用更新客户端使用教程
+
+## 📖 目录
+
+- [简介](#简介)
+- [系统要求](#系统要求)
+- [快速开始](#快速开始)
+- [详细使用说明](#详细使用说明)
+  - [交互模式](#交互模式)
+  - [非交互模式](#非交互模式)
+  - [命令行参数](#命令行参数)
+- [使用场景](#使用场景)
+- [常见问题](#常见问题)
+- [故障排除](#故障排除)
+- [最佳实践](#最佳实践)
+
+---
+
+## 简介
+
+`update-client.sh` 是一个用于从版本服务器下载和更新 H5 应用的自动化脚本。它提供了以下功能:
+
+✅ **安全认证** - 用户名密码验证,密码隐藏输入  
+✅ **版本管理** - 自动获取和选择可用版本  
+✅ **自动备份** - 更新前自动备份当前版本  
+✅ **完整性验证** - 支持 MD5/SHA256 校验  
+✅ **详细日志** - 记录完整操作日志  
+✅ **锁机制** - 防止重复执行  
+✅ **交互式和自动化模式** - 灵活适应不同场景
+
+---
+
+## 系统要求
+
+### 必需工具
+
+脚本依赖以下工具,请确保已安装:
+
+- `bash` - Bash shell 解释器
+- `curl` - 用于 HTTP 请求
+- `wget` - 用于文件下载
+- `tar` - 文件归档工具(可选)
+
+### 支持的操作系统
+
+- ✅ Linux (所有发行版)
+- ✅ macOS
+- ✅ Windows (通过 Git Bash、WSL 或 MSYS2)
+
+### 在 Windows 上运行
+
+**推荐方式:Git Bash**
+
+1. 安装 [Git for Windows](https://git-scm.com/download/win)
+2. 右键项目文件夹 → "Git Bash Here"
+3. 执行脚本
+
+**其他方式:**
+- WSL (Windows Subsystem for Linux)
+- MSYS2
+
+---
+
+## 快速开始
+
+### 1. 下载脚本
+
+```bash
+# 确保脚本在项目根目录
+ls -l update-client.sh
+```
+
+### 2. 基本执行(交互模式)
+
+```bash
+# 使用 bash 执行脚本
+bash update-client.sh
+```
+
+### 3. 按提示操作
+
+```
+请输入用户名 [默认: deploy]: deploy
+请输入密码: ********
+请输入下载目录 [默认: ./h5]: 
+```
+
+### 4. 选择版本
+
+```
+可用版本列表(最新10个):
+━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+  0. latest (最新版本)
+  1. v1.1.5-20251129-143005
+  2. v1.1.5-20251129-120530
+  3. v1.1.4-20251128-163015
+━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+
+请选择版本 [0-3,默认: 0]: 0
+```
+
+### 5. 确认并执行
+
+```
+━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+  更新摘要
+━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+  服务器: dros.overs.games
+  用户名: deploy
+  目标目录: ./h5
+  版本: latest
+━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+
+确认执行更新? [y/N]: y
+```
+
+---
+
+## 详细使用说明
+
+### 交互模式
+
+交互模式适合手动操作,提供友好的提示和选择界面。
+
+#### 启动交互模式
+
+```bash
+bash update-client.sh
+```
+
+#### 交互流程
+
+1. **输入用户名**
+   - 默认值:`deploy`
+   - 直接按 Enter 使用默认值
+   - 或输入其他用户名
+
+2. **输入密码**
+   - 密码输入时不显示(安全)
+   - 至少 6 位字符
+   - 不能为空
+
+3. **指定下载目录**
+   - 默认值:`./h5`
+   - 如果目录不存在,会询问是否创建
+
+4. **选择版本**
+   - 显示最新 10 个可用版本
+   - 输入序号选择
+   - 默认选择 `latest`(最新版本)
+
+5. **确认更新**
+   - 显示更新摘要
+   - 输入 `y` 确认,`n` 或其他取消
+
+6. **自动执行**
+   - 备份当前版本
+   - 下载新版本
+   - 验证文件完整性
+   - 完成更新
+
+---
+
+### 非交互模式
+
+非交互模式适合自动化脚本和 CI/CD 流程。
+
+#### 基本语法
+
+```bash
+bash update-client.sh [选项]
+```
+
+#### 完整示例
+
+```bash
+bash update-client.sh \
+  --user deploy \
+  --password your_password \
+  --dir ./h5 \
+  --version latest \
+  --yes
+```
+
+#### 静默模式(最小输出)
+
+```bash
+bash update-client.sh \
+  -u deploy \
+  -p your_password \
+  -d ./h5 \
+  -v v1.1.5-20251129-143005 \
+  -y \
+  -s
+```
+
+---
+
+### 命令行参数
+
+| 参数 | 简写 | 说明 | 默认值 | 必需 |
+|------|------|------|--------|------|
+| `--user` | `-u` | 用户名 | `deploy` | 否 |
+| `--password` | `-p` | 密码 | - | 否* |
+| `--dir` | `-d` | 下载目录 | `./h5` | 否 |
+| `--version` | `-v` | 版本号 | `latest` | 否 |
+| `--include-static` | `-i` | 包含 static 文件夹 | `false` | 否 |
+| `--yes` | `-y` | 跳过确认 | `false` | 否 |
+| `--silent` | `-s` | 静默模式 | `false` | 否 |
+| `--help` | `-h` | 显示帮助 | - | 否 |
+
+\* 如果不通过参数提供密码,会在交互时提示输入
+
+**关于 static 文件夹**:
+- `static` 文件夹通常包含大量静态资源(图片、视频等)
+- 默认情况下**不包含** static 文件夹,以节省时间和带宽
+- 首次部署或 static 资源有更新时,需添加 `-i` 参数
+
+#### 查看帮助
+
+```bash
+bash update-client.sh --help
+```
+
+---
+
+## 使用场景
+
+### 场景 1:开发环境日常更新
+
+```bash
+# 最简单的方式 - 交互模式
+bash update-client.sh
+```
+
+### 场景 2:生产环境自动部署
+
+```bash
+#!/bin/bash
+# deploy.sh - 生产部署脚本
+
+# 从环境变量读取密码
+DEPLOY_PASSWORD="${DEPLOY_PASSWORD}"
+
+bash update-client.sh \
+  -u deploy \
+  -p "$DEPLOY_PASSWORD" \
+  -d /var/www/html/h5 \
+  -v latest \
+  -y \
+  -s
+
+# 检查更新是否成功
+if [ $? -eq 0 ]; then
+    echo "部署成功!"
+    # 可以在这里重启服务等
+    # systemctl restart nginx
+else
+    echo "部署失败!"
+    exit 1
+fi
+```
+
+### 场景 3:定时更新任务
+
+```bash
+# 添加到 crontab
+# 每天凌晨 2 点自动更新
+
+0 2 * * * cd /path/to/project && bash update-client.sh -u deploy -p password -y -s >> /var/log/update.log 2>&1
+```
+
+### 场景 4:更新到特定版本
+
+```bash
+# 回滚到之前的版本
+bash update-client.sh \
+  -u deploy \
+  -p your_password \
+  -v v1.1.4-20251128-163015 \
+  -y
+```
+
+### 场景 5:CI/CD 集成
+
+**GitHub Actions 示例:**
+
+```yaml
+name: Deploy to Production
+
+on:
+  push:
+    branches: [main]
+
+jobs:
+  deploy:
+    runs-on: ubuntu-latest
+    steps:
+      - name: Checkout code
+        uses: actions/checkout@v3
+      
+      - name: Deploy to server
+        env:
+          DEPLOY_PASSWORD: ${{ secrets.DEPLOY_PASSWORD }}
+        run: |
+          bash update-client.sh \
+            -u deploy \
+            -p "$DEPLOY_PASSWORD" \
+            -d ./h5 \
+            -v latest \
+            -y \
+            -s
+```
+
+---
+
+## 常见问题
+
+### Q1: 如何查看脚本版本?
+
+A: 脚本顶部有版本信息,或查看帮助:
+
+```bash
+bash update-client.sh --help
+```
+
+### Q2: 密码可以保存在文件中吗?
+
+A: 不推荐!但如果需要,可以:
+
+```bash
+# 从文件读取密码
+PASSWORD=$(cat ~/.deploy_password)
+bash update-client.sh -u deploy -p "$PASSWORD" -y
+```
+
+**更安全的方式:**
+
+```bash
+# 使用环境变量
+export DEPLOY_PASSWORD="your_password"
+bash update-client.sh -u deploy -p "$DEPLOY_PASSWORD" -y
+```
+
+### Q3: 如何查看更新日志?
+
+A: 日志保存在 `./logs/` 目录:
+
+```bash
+# 查看最新日志
+ls -lt ./logs/update_*.log | head -1
+
+# 查看日志内容
+tail -f ./logs/update_20251129_143005.log
+```
+
+### Q4: 备份的旧版本在哪里?
+
+A: 备份保存在原目录旁边:
+
+```bash
+# 如果更新目录是 ./h5
+# 备份会命名为 ./h5_backup_20251129_143005
+
+ls -d ./h5_backup_*
+```
+
+### Q5: 如何恢复到备份版本?
+
+A:
+
+```bash
+# 删除当前版本
+rm -rf ./h5
+
+# 恢复备份(替换为实际的备份目录名)
+mv ./h5_backup_20251129_143005 ./h5
+```
+
+### Q6: 脚本运行中断了怎么办?
+
+A: 删除锁文件后重试:
+
+```bash
+# 删除锁文件
+rm -f /tmp/update-client-${USER}.lock
+
+# 重新运行
+bash update-client.sh
+```
+
+### Q7: 如何跳过备份步骤?
+
+A: 脚本会自动检测,如果目录为空或不存在则跳过备份。如果需要强制不备份,可以先清空目录:
+
+```bash
+# 谨慎操作!
+rm -rf ./h5/*
+```
+
+### Q8: 什么时候需要更新 static 文件夹?
+
+A: **需要更新 static 的情况**:
+- ✅ 首次部署应用
+- ✅ 静态资源有更新(图片、字体、视频等)
+- ✅ 版本升级涉及静态文件变更
+
+**可以跳过 static 的情况**:
+- ✅ 仅代码逻辑更新
+- ✅ 静态资源使用 CDN
+- ✅ static 文件夹从未变化
+
+**示例**:
+
+```bash
+# 首次部署 - 包含 static
+bash update-client.sh -u deploy -p password -y -i
+
+# 日常更新 - 跳过 static(默认)
+bash update-client.sh -u deploy -p password -y
+
+# 静态资源有更新 - 包含 static
+bash update-client.sh -u deploy -p password -y --include-static
+```
+
+### Q9: 如何确认 static 文件夹是否被更新?
+
+A: 查看更新摘要和日志:
+
+**更新摘要中会显示**:
+```
+━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+  更新摘要
+━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+  服务器: dros.overs.games
+  用户名: deploy
+  目标目录: ./h5
+  版本: latest
+  static 文件夹: 跳过    ← 这里显示状态
+━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+```
+
+**日志中会记录**:
+```bash
+# 查看日志
+cat ./logs/update_*.log | grep "static"
+
+# 会看到类似输出
+[INFO] static 文件夹: 跳过更新
+# 或
+[INFO] static 文件夹: 包含在更新中
+```
+
+---
+
+## 故障排除
+
+### 问题 1:无法连接到服务器
+
+**错误信息:**
+```
+[ERROR] 无法连接到服务器
+[ERROR] 请检查网络连接、用户名和密码
+```
+
+**解决方法:**
+
+1. 检查网络连接:
+   ```bash
+   ping dros.overs.games
+   ```
+
+2. 手动测试连接:
+   ```bash
+   curl -k -I --user "deploy:your_password" https://dros.overs.games/releases/
+   ```
+
+3. 检查用户名和密码是否正确
+
+4. 检查服务器地址是否正确
+
+---
+
+### 问题 2:缺少依赖工具
+
+**错误信息:**
+```
+[ERROR] 缺少必需工具: wget curl
+```
+
+**解决方法:**
+
+**Linux (Ubuntu/Debian):**
+```bash
+sudo apt-get update
+sudo apt-get install curl wget
+```
+
+**Linux (CentOS/RHEL):**
+```bash
+sudo yum install curl wget
+```
+
+**macOS:**
+```bash
+brew install wget
+# curl 通常已预装
+```
+
+**Windows (Git Bash):**
+- Git Bash 通常已包含这些工具
+- 如果缺失,重新安装 Git for Windows
+
+---
+
+### 问题 3:权限被拒绝
+
+**错误信息:**
+```
+bash: ./update-client.sh: Permission denied
+```
+
+**解决方法:**
+
+```bash
+# 不要用 ./update-client.sh
+# 改用 bash 命令
+bash update-client.sh
+```
+
+---
+
+### 问题 4:版本列表为空
+
+**错误信息:**
+```
+[ERROR] 无法获取版本列表
+```
+
+**解决方法:**
+
+1. 检查服务器上是否有可用版本
+2. 确认 releases 目录访问权限
+3. 手动检查:
+   ```bash
+   curl -k --user "deploy:password" https://dros.overs.games/releases/
+   ```
+
+---
+
+### 问题 5:下载失败
+
+**错误信息:**
+```
+[ERROR] 下载失败
+```
+
+**解决方法:**
+
+1. 检查磁盘空间:
+   ```bash
+   df -h
+   ```
+
+2. 检查目录写入权限:
+   ```bash
+   ls -ld ./h5
+   ```
+
+3. 手动测试下载:
+   ```bash
+   wget --user=deploy --password=your_password \
+        --no-check-certificate \
+        https://dros.overs.games/releases/latest/
+   ```
+
+---
+
+### 问题 6:文件完整性验证失败
+
+**错误信息:**
+```
+[ERROR] 文件完整性验证失败
+```
+
+**解决方法:**
+
+1. 重新下载
+2. 检查网络稳定性
+3. 如果持续失败,联系服务器管理员检查校验文件
+
+---
+
+## 最佳实践
+
+### 1. 安全性
+
+✅ **DO(推荐):**
+- 使用环境变量存储密码
+- 定期更换密码
+- 限制脚本文件权限:`chmod 700 update-client.sh`
+- 在生产环境使用非交互模式
+
+❌ **DON'T(不推荐):**
+- 在脚本中硬编码密码
+- 在命令历史中暴露密码
+- 将密码提交到版本控制系统
+
+### 2. 自动化
+
+```bash
+# 创建包装脚本
+cat > auto-update.sh << 'EOF'
+#!/bin/bash
+set -e
+
+# 从安全位置读取密码
+DEPLOY_PASSWORD=$(cat ~/.secrets/deploy_password)
+
+# 执行更新
+bash update-client.sh \
+  -u deploy \
+  -p "$DEPLOY_PASSWORD" \
+  -d /var/www/html/h5 \
+  -v latest \
+  -y \
+  -s
+
+# 更新成功后的操作
+if [ $? -eq 0 ]; then
+    # 重启服务
+    sudo systemctl reload nginx
+    
+    # 发送通知
+    echo "H5 应用已更新到最新版本" | mail -s "部署成功" admin@example.com
+fi
+EOF
+
+chmod 700 auto-update.sh
+```
+
+### 3. 监控和日志
+
+```bash
+# 保留最近 30 天的日志
+find ./logs -name "update_*.log" -mtime +30 -delete
+
+# 监控更新状态
+tail -f ./logs/update_*.log | grep -E "\[ERROR\]|\[✓\]"
+```
+
+### 4. 版本管理
+
+```bash
+# 记录当前版本
+echo "latest" > ./h5/.version
+
+# 更新后验证
+cat ./h5/.version
+```
+
+### 5. 回滚策略
+
+```bash
+# 更新前记录当前版本信息
+CURRENT_VERSION=$(cat ./h5/.version 2>/dev/null || echo "unknown")
+echo "更新前版本: $CURRENT_VERSION" >> ./logs/update_history.log
+
+# 执行更新
+bash update-client.sh -u deploy -p "$PASSWORD" -v latest -y
+
+# 如果更新失败,自动回滚
+if [ $? -ne 0 ]; then
+    echo "更新失败,正在回滚..."
+    if [ -d "./h5_backup_*" ]; then
+        rm -rf ./h5
+        mv $(ls -dt ./h5_backup_* | head -1) ./h5
+        echo "已回滚到: $CURRENT_VERSION"
+    fi
+fi
+```
+
+---
+
+## 技术支持
+
+如有问题或建议,请:
+
+1. 查看日志文件:`./logs/update_*.log`
+2. 检查常见问题部分
+3. 联系系统管理员
+
+---
+
+## 版本历史
+
+- **v1.0.0** (2025-11-29)
+  - 初始版本发布
+  - 支持交互和非交互模式
+  - 添加版本选择功能
+  - 实现自动备份机制
+  - 支持文件完整性验证
+  - 添加锁机制防止并发
+
+---
+
+## 许可证
+
+本脚本为内部使用工具,请勿外传。
+
+---
+
+**最后更新:** 2025-11-29  
+**维护者:** 开发团队