deploy.sh 5.4 KB
#!/usr/bin/env bash
#
# 部署脚本:构建项目 -> 上传七牛 -> 打包并上传到服务器
# 说明:在 macOS 环境下执行,依赖 npm、qshell、ssh/scp

set -euo pipefail

# 全局变量(按需修改)
repo_root="$(cd "$(dirname "$0")/.." && pwd)"
server_host="zhsy@oa.jcedu.org"
server_port="12101"
remote_dir="/home/www/f"
local_tar="dist.tar.gz"
local_package_dir="stdj"
qshell_dir="$HOME/.qshell"
qshell_conf="stdj_upload.conf"
build_out_dir="dist"

# 打印信息日志
# 说明:输出带前缀的日志,便于观察执行过程
log_info() {
    echo "[deploy] $1"
}

# 执行命令并显示日志
# 参数:cmd 命令字符串
# 说明:包装命令执行,便于统一错误处理与日志输出
run_cmd() {
    local cmd="$1"
    log_info "执行:$cmd"
    eval "$cmd"
}

# 检测构建输出目录
# 说明:按优先级读取 .env.production -> .env -> .env.development 中的 VITE_OUTDIR,缺省为 dist
detect_out_dir() {
    # POSIX 兼容实现:按顺序检查 .env.production -> .env -> .env.development
    # 若未设置,回退为 dist
    local outdir="dist"
    for env_file in "$repo_root/.env.production" "$repo_root/.env" "$repo_root/.env.development"; do
        if [ -f "$env_file" ]; then
            # 提取键值:去注释、去空格、去引号
            local value
            value=$(grep -E '^\s*VITE_OUTDIR\s*=' "$env_file" | head -n1 | cut -d '=' -f2- | sed 's/#.*$//' | tr -d '[:space:]' | sed -e 's/^"//;s/"$//' -e "s/^'//;s/'$//" || true)
            if [ -n "${value:-}" ]; then
                outdir="$value"
                break
            fi
        fi
    done
    echo "$outdir"
}

# 构建项目
# 说明:使用 npm 脚本进行构建,产物位于 dist/
build_project() {
    log_info "开始构建项目"
    cd "$repo_root"
    if command -v pnpm >/dev/null 2>&1; then
        run_cmd "pnpm run build"
    elif command -v npm >/dev/null 2>&1; then
        run_cmd "npm run build"
    elif command -v yarn >/dev/null 2>&1; then
        run_cmd "yarn build"
    else
        echo "错误:未检测到 pnpm/npm/yarn,请先安装其中之一"
        exit 1
    fi
    build_out_dir="$(detect_out_dir)"
    if [ ! -d "$repo_root/${build_out_dir:-}" ]; then
        echo "错误:未找到构建输出目录 '${build_out_dir:-}/',请检查 .env/.env.production 的 VITE_OUTDIR 或构建是否成功"
        exit 1
    fi
    log_info "构建完成:${build_out_dir:-}/"
}

# 准备打包目录
# 说明:将 dist 内容复制到 stdj 目录,用于后续打包
prepare_package_dir() {
    log_info "准备打包目录:$local_package_dir"
    cd "$repo_root"
    # 保留 stdj 目录,仅增量同步构建产物
    run_cmd "mkdir -p '$local_package_dir'"
    if [ "${build_out_dir:-}" = "$local_package_dir" ]; then
        # 输出目录与包目录一致,直接使用,无需复制
        log_info "输出目录与包目录一致:${build_out_dir:-},跳过复制"
        return 0
    fi
    if command -v rsync >/dev/null 2>&1; then
        # 使用 rsync 增量复制,保留 stdj 目录和其他文件(不删除已有文件)
        run_cmd "rsync -a '${build_out_dir:-}/' '$local_package_dir/'"
    else
        # 回退到 cp -R,同样保留 stdj 目录
        run_cmd "cp -R '${build_out_dir:-}'/. '$local_package_dir'/"
    fi
}

# 上传静态资源到七牛云
# 说明:进入 ~/.qshell 并执行 qupload,同步 upload.conf 中配置的资源
upload_qiniu() {
    log_info "检查 qshell 安装与配置"
    if ! command -v qshell >/dev/null 2>&1; then
        echo "错误:未检测到 qshell,请先安装 https://developer.qiniu.com/kodo/tools/1302/qshell"
        exit 1
    fi
    if [ ! -d "$qshell_dir" ]; then
        echo "错误:未找到目录 $qshell_dir"
        exit 1
    fi
    if [ ! -f "$qshell_dir/$qshell_conf" ]; then
        echo "错误:未找到七牛配置文件 $qshell_dir/$qshell_conf"
        exit 1
    fi
    log_info "开始上传七牛云资源(qupload)"
    cd "$qshell_dir"
    # 说明:部分文件已存在会导致 qshell 返回非零退出码,此处不终止流程
    log_info "执行:qshell qupload '$qshell_conf'"
    if ! qshell qupload "$qshell_conf"; then
        log_info "qshell qupload 退出码非零(可能因文件已存在),继续后续部署"
    fi
    log_info "七牛云资源上传完成"
}

# 打包本地目录并上传到服务器
# 说明:打包 stdj -> 通过 scp 上传到指定目录 -> 远端解压并删除压缩包
upload_server() {
    log_info "开始打包:${local_tar:-}"
    cd "$repo_root"
    run_cmd "tar -czvpf '${local_tar:-}' '${local_package_dir:-}'"

    log_info "上传到服务器:${server_host:-}:${remote_dir:-}(端口 ${server_port:-})"
    run_cmd "scp -P '${server_port:-}' '${local_tar:-}' '${server_host:-}':'${remote_dir:-}'"

    log_info "服务器解压:${remote_dir:-}/${local_tar:-}"
    # 说明:构造远端命令,避免变量名意外字符导致的未绑定错误
    local remote_cmd
    remote_cmd="cd \"${remote_dir:-}\" && tar -xzvf \"${local_tar:-}\" && rm -rf \"${local_tar:-}\""
    run_cmd "ssh -p '${server_port:-}' '${server_host:-}' \"$remote_cmd\""

    log_info "删除本地压缩包"
    run_cmd "rm -f '${local_tar:-}'"
}

# 主流程
# 说明:串行执行:构建 -> 七牛上传 -> 服务器打包上传
main() {
    build_project
    prepare_package_dir
    upload_qiniu
    upload_server
    log_info "部署完成"
}

main "$@"