diff --git a/README.md b/README.md index 7753698..78ecb64 100644 --- a/README.md +++ b/README.md @@ -403,7 +403,8 @@ chmod +x https.sh ### 更新升级 update.sh 脚本用于自动更新 EasyAI 应用,包含以下功能: -- 自动检查和更新 `docker-compose.yml` 文件(从远程仓库获取最新版本) +- **拉取整个仓库**:执行 `git pull` 获取最新代码(docker-compose.yml、start.sh、.env.*.sample 等全部文件) +- 自动补齐缺失的环境配置文件(.env、.env.tools、.env.ASG、.env.AMS,从 .sample 生成且不覆盖已有文件) - 兼容 `docker compose` 和 `docker-compose` 两种命令格式 - 自动拉取最新镜像并重启服务 @@ -413,32 +414,32 @@ update.sh 脚本用于自动更新 EasyAI 应用,包含以下功能: chmod +x update.sh ``` -2. 执行更新(默认会检查并更新 docker-compose.yml) +2. 执行更新(默认会 `git pull` 拉取整个仓库) ```bash ./update.sh ``` -#### 参数选项 -- **跳过 docker-compose.yml 更新**:如果你已经手动修改了 `docker-compose.yml` 文件,可以使用 `-s` 或 `--skip-compose-update` 参数跳过更新 -```bash -# 跳过 docker-compose.yml 更新,仅更新容器镜像 -./update.sh -s -# 或 -./update.sh --skip-compose-update -``` +> **注意**:update.sh 需要在 Git 克隆的目录下运行。若通过 zip 下载而非 git clone,请先使用 `git clone` 获取项目。 -- **查看帮助信息**: -```bash -./update.sh -h -# 或 -./update.sh --help -``` +#### 使用方式 +- 执行 `./update.sh` 后会**命令行内选择**更新方式: + - `[1]` 更新并拉取仓库(git pull)+ 更新镜像并重启(**默认**,回车即选) + - `[2]` 仅更新镜像并重启(跳过 git pull,适用于有本地修改不想被覆盖的场景) + +- **查看帮助**:`./update.sh -h` 或 `./update.sh --help` #### 更新说明 -- 脚本会自动从远程仓库下载最新的 `docker-compose.yml` 文件 -- 如果本地文件与远程文件不同,会将原文件备份为 `docker-compose.yml.bak` -- 如果本地文件已是最新版本,则跳过更新 -- 更新完成后会自动执行 `docker-compose pull` 和 `docker-compose up -d` 来重启服务 +- 脚本会执行 `git pull` 拉取整个仓库最新代码 +- 拉取后会检查并补齐缺失的 .env、.env.tools、.env.ASG、.env.AMS(不会覆盖已有文件) +- 最后执行 `docker compose pull` 和 `docker compose up -d` 拉取镜像并重启服务 + +#### Windows 用户(update.ps1) +Windows 下使用 `update.ps1`,功能与 Linux 版一致: +```powershell +.\update.ps1 +``` +- 执行后会**命令行内选择**:`[1]` 更新并拉取仓库 + 更新镜像(默认);`[2]` 仅更新镜像 +- 需在 Git 克隆的 easyai 目录下运行 diff --git a/update.ps1 b/update.ps1 new file mode 100644 index 0000000..dd79b7f --- /dev/null +++ b/update.ps1 @@ -0,0 +1,201 @@ +#Requires -Version 5.1 +# EasyAI Windows 更新脚本 +# 拉取仓库最新代码,更新镜像并重启服务 +# 用法: .\update.ps1 + +# 设置控制台编码为 UTF-8 +[Console]::OutputEncoding = [System.Text.Encoding]::UTF8 +$OutputEncoding = [System.Text.Encoding]::UTF8 + +$ErrorActionPreference = "Stop" +$script:LogDir = $PSScriptRoot +if (-not $script:LogDir) { $script:LogDir = $env:TEMP } +$script:LogFile = Join-Path $script:LogDir "update.ps1.log" + +function Write-Log { + param([string]$Msg) + try { + $line = "[$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')] $Msg" + Add-Content -Path $script:LogFile -Value $line -Encoding UTF8 -ErrorAction SilentlyContinue + } catch { } +} + +trap { + $errMsg = $_.Exception.Message + try { + Add-Content -Path $script:LogFile -Value "[$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')] 错误: $errMsg" -Encoding UTF8 -ErrorAction SilentlyContinue + } catch { } + Write-Host "" + Write-Host "发生错误: $errMsg" -ForegroundColor Red + if ($env:CI -ne "true") { Read-Host "按 Enter 键退出" } + exit 1 +} + +function Wait-ForExit { + if ($env:CI -eq "true") { return } + Write-Host "" + Read-Host "按 Enter 键退出" +} + +function Write-Step { param($Msg) Write-Host $Msg } +function Write-Ok { param($Msg) Write-Host " ✓ $Msg" -ForegroundColor Green } +function Write-Err { param($Msg) Write-Host "❌ $Msg" -ForegroundColor Red; throw $Msg } +function Write-Warn { param($Msg) Write-Host "⚠️ $Msg" -ForegroundColor Yellow } + +# -h/--help +if ($args -contains "-h" -or $args -contains "--help") { + Write-Host "用法: .\update.ps1" + Write-Host "" + Write-Host "脚本将提示选择更新方式,默认拉取仓库并更新镜像。" + exit 0 +} + +# 进入项目目录 +$scriptDir = $PSScriptRoot +if (-not $scriptDir) { Write-Err "无法获取脚本所在目录" } +$composePath = Join-Path $scriptDir "docker-compose.yml" +if (-not (Test-Path $composePath)) { Write-Err "未找到 docker-compose.yml,请在 easyai 目录下运行 update.ps1" } +Set-Location $scriptDir +Write-Step "📁 项目目录: $scriptDir" + +# ==================== 命令行内选择 ==================== +Write-Host "" +Write-Host "请选择更新方式:" +Write-Host " [1] 更新并拉取仓库(git pull)+ 更新镜像并重启(默认)" +Write-Host " [2] 仅更新镜像并重启(跳过 git pull)" +$choice = Read-Host "请选择 [1/2,回车默认 1]" +if ([string]::IsNullOrWhiteSpace($choice)) { $choice = "1" } + +$skipRepoUpdate = $false +switch ($choice) { + "2" { $skipRepoUpdate = $true } + "1" { } + default { + Write-Warn "无效选择,将使用默认:更新并拉取仓库" + $skipRepoUpdate = $false + } +} + +# ==================== 拉取仓库 ==================== +if (-not $skipRepoUpdate) { + Write-Host "" + Write-Host "===========================" + Write-Host "📥 拉取仓库最新代码" + Write-Host "===========================" + + if (-not (Test-Path ".git")) { + Write-Err "当前目录不是 Git 仓库,请使用 git clone 克隆项目后使用 update.ps1" + } + + Write-Step "📥 正在执行 git pull..." + try { + $output = git pull 2>&1 + if ($LASTEXITCODE -ne 0) { throw "git pull 返回 $LASTEXITCODE" } + Write-Ok "仓库已更新到最新版本" + } catch { + Write-Err "git pull 失败,请检查网络或远程仓库配置" + } + + # 确保环境配置文件存在 + Write-Host "" + Write-Step "📝 检查环境配置文件..." + if (-not (Test-Path ".env") -and (Test-Path ".env.sample")) { + Copy-Item ".env.sample" ".env" + Write-Ok ".env" + } + if (-not (Test-Path ".env.tools") -and (Test-Path ".env.tools.sample")) { + Copy-Item ".env.tools.sample" ".env.tools" + Write-Ok ".env.tools" + } + if (-not (Test-Path ".env.ASG") -and (Test-Path ".env.ASG.sample")) { + Copy-Item ".env.ASG.sample" ".env.ASG" + Write-Ok ".env.ASG" + } + if (-not (Test-Path ".env.AMS") -and (Test-Path ".env.AMS.sample")) { + Copy-Item ".env.AMS.sample" ".env.AMS" + Write-Ok ".env.AMS" + } + + Write-Host "" +} else { + Write-Host "" + Write-Step "⏭️ 跳过仓库更新,仅更新镜像并重启" + Write-Host "" +} + +# ==================== Docker 检查 ==================== +function Test-DockerInstalled { + $docker = Get-Command docker -ErrorAction SilentlyContinue + if (-not $docker) { return $false } + try { $null = & docker --version 2>&1; return $true } catch { return $false } +} + +function Test-DockerRunning { + param([int]$TimeoutSeconds = 10) + try { + $psi = New-Object System.Diagnostics.ProcessStartInfo + $psi.FileName = "docker"; $psi.Arguments = "info" + $psi.RedirectStandardOutput = $true; $psi.RedirectStandardError = $true + $psi.UseShellExecute = $false; $psi.CreateNoWindow = $true + $p = [System.Diagnostics.Process]::Start($psi) + $exited = $p.WaitForExit($TimeoutSeconds * 1000) + if (-not $exited) { try { $p.Kill() } catch { }; return $false } + return ($p.ExitCode -eq 0) + } catch { return $false } +} + +function Ensure-DockerRunning { + if (-not (Test-DockerInstalled)) { return $false } + if (Test-DockerRunning) { + Write-Ok "Docker 引擎已运行" + $v = docker --version 2>$null; if ($v) { Write-Host " $v" } + return $true + } + Write-Warn "Docker 未运行,请手动启动 Docker Desktop 后重新执行" + return $false +} + +Write-Host "===========================" +Write-Host "🚀 检查 Docker" +Write-Host "===========================" +Write-Host "" + +if (-not (Test-DockerInstalled)) { + Write-Err "未检测到 Docker,请先运行 start.ps1 完成首次部署" +} + +if (-not (Ensure-DockerRunning)) { + Write-Host "" + Write-Host "请启动 Docker Desktop,确认其完全就绪后再重新运行 update.ps1" + Wait-ForExit + exit 1 +} + +# 检测 docker compose +$hasComposeV2 = $false +try { $null = docker compose version 2>&1; $hasComposeV2 = $true } catch { } + +# ==================== 更新并启动 ==================== +Write-Host "" +Write-Step "🚀 重新启动 EasyAI..." +if ($hasComposeV2) { + docker compose pull + if ($LASTEXITCODE -ne 0) { Write-Err "docker compose pull 失败" } + docker compose up -d + if ($LASTEXITCODE -ne 0) { Write-Err "docker compose up 失败" } +} else { + docker-compose pull + if ($LASTEXITCODE -ne 0) { Write-Err "docker-compose pull 失败" } + docker-compose up -d + if ($LASTEXITCODE -ne 0) { Write-Err "docker-compose up 失败" } +} + +Write-Host "" +Write-Host "================================" +Write-Host " 更新完成" +Write-Host "================================" +Write-Host "🎉 EasyAI 应用更新成功" +Write-Host "访问地址: http://127.0.0.1:3010" +Write-Host "" +Write-Log "=== 更新完成 ===" +Wait-ForExit diff --git a/update.sh b/update.sh index 04c5468..ec1289a 100755 --- a/update.sh +++ b/update.sh @@ -2,75 +2,65 @@ set -e # 发生错误时终止脚本执行 -# 参数解析 -SKIP_COMPOSE_UPDATE=false +# 仅支持 -h/--help 快速查看 +if [[ "${1:-}" =~ ^(-h|--help)$ ]]; then + echo "用法: $0" + echo "" + echo "脚本将提示选择更新方式,默认拉取仓库并更新镜像。" + exit 0 +fi -# 解析命令行参数 -while [[ $# -gt 0 ]]; do - case $1 in - --skip-compose-update|-s) - SKIP_COMPOSE_UPDATE=true - shift - ;; - --help|-h) - echo "用法: $0 [选项]" - echo "" - echo "选项:" - echo " -s, --skip-compose-update 跳过 docker-compose.yml 的更新" - echo " -h, --help 显示此帮助信息" - echo "" - exit 0 - ;; - *) - echo "❌ 未知参数: $1" - echo "使用 --help 或 -h 查看帮助信息" - exit 1 - ;; - esac -done +# 进入脚本所在目录(项目根目录) +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]:-$0}")" && pwd)" +cd "$SCRIPT_DIR" -# 更新 docker-compose.yml 文件 -if [ "$SKIP_COMPOSE_UPDATE" = false ]; then +# 命令行内选择更新方式(默认:更新并拉取仓库) +echo "" +echo "请选择更新方式:" +echo " [1] 更新并拉取仓库(git pull)+ 更新镜像并重启(默认)" +echo " [2] 仅更新镜像并重启(跳过 git pull)" +read -r -p "请选择 [1/2,回车默认 1]: " choice +choice="${choice:-1}" +SKIP_REPO_UPDATE=false +case "$choice" in + 2) SKIP_REPO_UPDATE=true ;; + 1) ;; + *) echo "❌ 无效选择,将使用默认:更新并拉取仓库"; SKIP_REPO_UPDATE=false ;; +esac + +# 拉取整个仓库更新 +if [ "$SKIP_REPO_UPDATE" = false ]; then echo "" echo "===========================" - echo "📄 检查并更新 docker-compose.yml" + echo "📥 拉取仓库最新代码" echo "===========================" - COMPOSE_FILE="docker-compose.yml" - COMPOSE_URL="https://git.51easyai.com/wangbo/easyai/raw/main/docker-compose.yml" - TEMP_FILE=$(mktemp) - - # 检查本地文件是否存在 - if [ ! -f "$COMPOSE_FILE" ]; then - echo "⚠️ 本地 $COMPOSE_FILE 不存在,直接下载最新版本..." - curl -fsSL "$COMPOSE_URL" -o "$COMPOSE_FILE" - echo "✅ $COMPOSE_FILE 已下载" - else - echo "📥 正在下载远程 $COMPOSE_FILE..." - if curl -fsSL "$COMPOSE_URL" -o "$TEMP_FILE"; then - # 比较本地文件和远程文件的内容 - if cmp -s "$COMPOSE_FILE" "$TEMP_FILE"; then - echo "✅ 本地 $COMPOSE_FILE 已是最新版本,无需更新" - rm -f "$TEMP_FILE" - else - echo "🔄 检测到新版本,正在更新..." - # 备份原文件 - BACKUP_FILE="${COMPOSE_FILE}.bak" - cp "$COMPOSE_FILE" "$BACKUP_FILE" - echo "💾 原文件已备份为 $BACKUP_FILE" - # 替换为新文件 - mv "$TEMP_FILE" "$COMPOSE_FILE" - echo "✅ $COMPOSE_FILE 已更新到最新版本" - fi - else - echo "❌ 无法下载远程文件,跳过更新步骤" - rm -f "$TEMP_FILE" - fi + if [ ! -d .git ]; then + echo "❌ 当前目录不是 Git 仓库,无法执行 git pull" + echo " 请使用 git clone 克隆项目后即可使用 update.sh 更新" + echo " 克隆命令: git clone https://git.51easyai.com/wangbo/easyai && cd easyai" + exit 1 fi + echo "📥 正在执行 git pull..." + if git pull; then + echo "✅ 仓库已更新到最新版本" + else + echo "❌ git pull 失败,请检查网络或远程仓库配置" + exit 1 + fi + + # 确保环境配置文件存在(从 .sample 生成,不覆盖已有文件) + echo "" + echo "📝 检查环境配置文件..." + [ ! -f .env ] && [ -f .env.sample ] && cp .env.sample .env && echo " ✓ .env" + [ ! -f .env.tools ] && [ -f .env.tools.sample ] && cp .env.tools.sample .env.tools && echo " ✓ .env.tools" + [ ! -f .env.ASG ] && [ -f .env.ASG.sample ] && cp .env.ASG.sample .env.ASG && echo " ✓ .env.ASG" + [ ! -f .env.AMS ] && [ -f .env.AMS.sample ] && cp .env.AMS.sample .env.AMS && echo " ✓ .env.AMS" + echo "" else - echo "⏭️ 跳过 docker-compose.yml 更新(已使用 --skip-compose-update 参数)" + echo "⏭️ 跳过仓库更新,仅更新镜像并重启" echo "" fi