From ccc4f502dc5e93421fd291cb97d949001856fe20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AF=92=E5=AF=92?= <2596194220@qq.com> Date: Sun, 24 May 2026 22:42:03 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=20Docker=20=E5=8F=AF?= =?UTF-8?q?=E7=94=A8=E6=80=A7=E5=89=8D=E7=BD=AE=E6=A3=80=E6=9F=A5=EF=BC=8C?= =?UTF-8?q?=E6=9C=AC=E5=9C=B0=E5=BC=80=E5=8F=91=E6=97=B6=E7=BB=99=E5=87=BA?= =?UTF-8?q?=E5=8F=8B=E5=A5=BD=E6=8F=90=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/update.ts | 50 ++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 42 insertions(+), 8 deletions(-) diff --git a/lib/update.ts b/lib/update.ts index 9f05d2e..6907277 100644 --- a/lib/update.ts +++ b/lib/update.ts @@ -219,6 +219,31 @@ export async function checkForUpdate(): Promise { }; } +/** + * 检查 Docker 是否可用 + */ +function checkDockerAvailable(): { ok: boolean; message: string } { + try { + execSync("docker info", { + encoding: "utf-8", + timeout: 10000, + stdio: ["ignore", "pipe", "pipe"], + windowsHide: true, + }); + return { ok: true, message: "" }; + } catch { + return { + ok: false, + message: + "Docker 守护进程不可用。\n" + + "更新功能需要在 Docker 容器内运行,当前环境不支持。\n" + + "如需测试,请使用 Docker 部署后访问容器内的页面:\n" + + " docker compose -p recipe_tool up -d\n" + + "然后访问 http://localhost:3000/settings/update", + }; + } +} + /** * 执行 Docker 容器更新 * @param onLog 日志回调 @@ -234,19 +259,28 @@ export async function executeUpdate( try { onLog("开始更新流程...\n"); + // 0. 检查 Docker 是否可用 + onLog("[0/4] 检查 Docker 环境...\n"); + const dockerCheck = checkDockerAvailable(); + if (!dockerCheck.ok) { + onLog(`✗ ${dockerCheck.message}\n`); + return { success: false, message: dockerCheck.message }; + } + onLog("✓ Docker 环境正常\n"); + // 1. 拉取最新代码 const url = getAuthenticatedRemoteUrl(); - onLog(`[1/4] 克隆最新代码...\n`); + onLog("[1/4] 克隆最新代码...\n"); execSync(`git clone --depth 1 "${url}" "${tmpDir}"`, { encoding: "utf-8", timeout: 120000, windowsHide: true, stdio: ["ignore", "pipe", "pipe"], }); - onLog(`✓ 代码拉取完成\n`); + onLog("✓ 代码拉取完成\n"); // 2. 生成 .env 文件 - onLog(`[2/4] 准备环境变量...\n`); + onLog("[2/4] 准备环境变量...\n"); const envContent = [ `DB_HOST=${process.env.DB_HOST || "127.0.0.1"}`, `DB_PORT=${process.env.DB_PORT || "3306"}`, @@ -259,27 +293,27 @@ export async function executeUpdate( `ONEDEV_ACCESS_TOKEN=${process.env.ONEDEV_ACCESS_TOKEN || ""}`, ].join("\n"); fs.writeFileSync(path.join(tmpDir, ".env"), envContent, "utf-8"); - onLog(`✓ 环境变量已准备\n`); + onLog("✓ 环境变量已准备\n"); // 3. 构建新镜像 - onLog(`[3/4] 构建新 Docker 镜像...\n`); + onLog("[3/4] 构建新 Docker 镜像...\n"); execSync(`cd "${tmpDir}" && docker compose -p recipe_tool build`, { encoding: "utf-8", timeout: 600000, windowsHide: true, stdio: ["ignore", "pipe", "pipe"], }); - onLog(`✓ 镜像构建完成\n`); + onLog("✓ 镜像构建完成\n"); // 4. 重启服务 - onLog(`[4/4] 重启服务...\n`); + onLog("[4/4] 重启服务...\n"); execSync(`cd "${tmpDir}" && docker compose -p recipe_tool up -d`, { encoding: "utf-8", timeout: 60000, windowsHide: true, stdio: ["ignore", "pipe", "pipe"], }); - onLog(`✓ 服务已重启\n`); + onLog("✓ 服务已重启\n"); return { success: true, message: "更新完成" }; } catch (error) {