优化部署脚本非交互变量支持
This commit is contained in:
@@ -6,6 +6,41 @@
|
|||||||
git clone --depth 1 https://git.51easyai.com/wangbo/easyai.git && cd easyai && chmod +x start.sh && ./start.sh
|
git clone --depth 1 https://git.51easyai.com/wangbo/easyai.git && cd easyai && chmod +x start.sh && ./start.sh
|
||||||
```
|
```
|
||||||
|
|
||||||
|
也可以通过环境变量直接传入部署方式,脚本会跳过对应问答:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# IP 访问
|
||||||
|
DEPLOY_ACCESS=ip DEPLOY_IP=服务器IP ./start.sh
|
||||||
|
|
||||||
|
# 域名访问,不申请 HTTPS 证书
|
||||||
|
DEPLOY_ACCESS=domain DEPLOY_DOMAIN=demo.example.com DEPLOY_HTTPS=false ./start.sh
|
||||||
|
|
||||||
|
# 域名访问,并自动申请 HTTPS 证书
|
||||||
|
DEPLOY_ACCESS=domain DEPLOY_DOMAIN=demo.example.com DEPLOY_HTTPS=true CERTBOT_EMAIL=ops@example.com ./start.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
常用变量:
|
||||||
|
|
||||||
|
| 变量 | 说明 |
|
||||||
|
|------|------|
|
||||||
|
| `DEPLOY_ACCESS` | `ip` 或 `domain`;未传时进入问答选择 |
|
||||||
|
| `DEPLOY_IP` | IP 模式访问地址,如 `10.0.0.8` |
|
||||||
|
| `DEPLOY_DOMAIN` | 域名模式访问地址,可带 `http://` 或 `https://`,脚本会自动清理 |
|
||||||
|
| `DEPLOY_HTTPS` | `true/false`,域名模式下是否申请 HTTPS 证书 |
|
||||||
|
| `CERTBOT_EMAIL` | 申请 HTTPS 证书使用的邮箱,默认 `wangbo@51easyai.com` |
|
||||||
|
| `DEPLOY_FORCE_RECONFIG` | 非空时即使已有 `.env` 也重新生成部署配置 |
|
||||||
|
| `DEPLOY_DRY_RUN` | `1` 时只生成配置文件,不安装 Docker、不启动服务 |
|
||||||
|
| `DEPLOY_NON_INTERACTIVE` | `1` 时缺少必要变量会直接报错,不再进入问答 |
|
||||||
|
| `DEPLOY_MAC_DOCKER_INSTALL` | macOS 未安装 Docker 时使用,`auto` 自动安装或 `manual` 提示手动安装 |
|
||||||
|
|
||||||
|
`https.sh` 单独执行时也可以跳过域名选择:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
DEPLOY_DOMAIN=demo.example.com EASYAI_PROXY_CONF=demo.example.com.conf CERTBOT_EMAIL=ops@example.com ./https.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
如需对已有 Nginx 配置追加或替换域名,可设置 `EASYAI_PROXY_DOMAIN_ACTION=add|replace`;未设置时默认追加。
|
||||||
|
|
||||||
### Windows
|
### Windows
|
||||||
|
|
||||||
在 **PowerShell** 中执行:
|
在 **PowerShell** 中执行:
|
||||||
@@ -14,6 +49,24 @@ git clone --depth 1 https://git.51easyai.com/wangbo/easyai.git && cd easyai && c
|
|||||||
git clone --depth 1 "https://git.51easyai.com/wangbo/easyai.git" "easyai"; Set-Location "easyai"; powershell.exe -NoProfile -ExecutionPolicy Bypass -File ".\start.ps1"
|
git clone --depth 1 "https://git.51easyai.com/wangbo/easyai.git" "easyai"; Set-Location "easyai"; powershell.exe -NoProfile -ExecutionPolicy Bypass -File ".\start.ps1"
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Windows 也支持变量方式跳过选择:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
# 本机访问
|
||||||
|
$env:DEPLOY_ACCESS = "local"
|
||||||
|
powershell.exe -NoProfile -ExecutionPolicy Bypass -File ".\start.ps1"
|
||||||
|
|
||||||
|
# 局域网访问
|
||||||
|
$env:DEPLOY_IP = "192.168.1.10"
|
||||||
|
powershell.exe -NoProfile -ExecutionPolicy Bypass -File ".\start.ps1"
|
||||||
|
|
||||||
|
# 仅生成配置,不启动 Docker
|
||||||
|
$env:DEPLOY_IP = "127.0.0.1"
|
||||||
|
$env:DEPLOY_DRY_RUN = "1"
|
||||||
|
$env:DEPLOY_NO_WAIT = "1"
|
||||||
|
powershell.exe -NoProfile -ExecutionPolicy Bypass -File ".\start.ps1"
|
||||||
|
```
|
||||||
|
|
||||||
> **Windows 脚本权限说明**:PowerShell 默认禁止运行脚本,直接双击 `start.ps1` 会闪退。
|
> **Windows 脚本权限说明**:PowerShell 默认禁止运行脚本,直接双击 `start.ps1` 会闪退。
|
||||||
>
|
>
|
||||||
> - **推荐**:使用 `powershell.exe -NoProfile -ExecutionPolicy Bypass -File ".\start.ps1"` 执行,无需修改系统策略
|
> - **推荐**:使用 `powershell.exe -NoProfile -ExecutionPolicy Bypass -File ".\start.ps1"` 执行,无需修改系统策略
|
||||||
@@ -48,6 +101,12 @@ mv easyai easyai2
|
|||||||
```
|
```
|
||||||
|
|
||||||
3. 重新执行一键部署命令,按脚本提示完成初始化输入。
|
3. 重新执行一键部署命令,按脚本提示完成初始化输入。
|
||||||
|
如果希望跳过问答,可直接传入变量:
|
||||||
|
```bash
|
||||||
|
DEPLOY_ACCESS=ip DEPLOY_IP=服务器IP ./start.sh
|
||||||
|
# 或
|
||||||
|
DEPLOY_ACCESS=domain DEPLOY_DOMAIN=demo.example.com DEPLOY_HTTPS=false ./start.sh
|
||||||
|
```
|
||||||
|
|
||||||
4. 当脚本询问是否启用 HTTPS 时:
|
4. 当脚本询问是否启用 HTTPS 时:
|
||||||
- 如果你之前已经有可用证书,填写 `N`(不生成新证书)。
|
- 如果你之前已经有可用证书,填写 `N`(不生成新证书)。
|
||||||
@@ -80,6 +139,18 @@ chmod +x update.sh
|
|||||||
- `[2]` 仅更新镜像并重启(跳过 git pull,适用于有本地修改不想被覆盖的场景)
|
- `[2]` 仅更新镜像并重启(跳过 git pull,适用于有本地修改不想被覆盖的场景)
|
||||||
- 如果本次**不涉及配置文件更新**(如 `.env*`、`docker-compose.yml`、`easyai-proxy.conf*` 无变更),可直接选择 `[2]`,仅更新后台服务镜像并重启即可。
|
- 如果本次**不涉及配置文件更新**(如 `.env*`、`docker-compose.yml`、`easyai-proxy.conf*` 无变更),可直接选择 `[2]`,仅更新后台服务镜像并重启即可。
|
||||||
|
|
||||||
|
- 自动化更新可通过变量跳过选择:
|
||||||
|
```bash
|
||||||
|
# 更新仓库 + 拉取镜像 + 重启(等同默认选 1)
|
||||||
|
UPDATE_MODE=full ./update.sh
|
||||||
|
|
||||||
|
# 仅拉取镜像 + 重启(等同选 2)
|
||||||
|
UPDATE_MODE=image ./update.sh
|
||||||
|
|
||||||
|
# 或使用布尔变量
|
||||||
|
UPDATE_SKIP_REPO_UPDATE=true ./update.sh
|
||||||
|
```
|
||||||
|
|
||||||
- **查看帮助**:`./update.sh -h` 或 `./update.sh --help`
|
- **查看帮助**:`./update.sh -h` 或 `./update.sh --help`
|
||||||
|
|
||||||
### 更新说明
|
### 更新说明
|
||||||
@@ -94,6 +165,12 @@ Windows 下使用 `update.ps1`,功能与 Linux 版一致:
|
|||||||
```
|
```
|
||||||
- 执行后会**命令行内选择**:`[1]` 更新并拉取仓库 + 更新镜像(默认);`[2]` 仅更新镜像
|
- 执行后会**命令行内选择**:`[1]` 更新并拉取仓库 + 更新镜像(默认);`[2]` 仅更新镜像
|
||||||
- 需在 Git 克隆的 easyai 目录下运行
|
- 需在 Git 克隆的 easyai 目录下运行
|
||||||
|
- 也可通过变量跳过选择:
|
||||||
|
```powershell
|
||||||
|
$env:UPDATE_MODE = "image"
|
||||||
|
$env:UPDATE_NO_WAIT = "1"
|
||||||
|
.\update.ps1
|
||||||
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
+22
-9
@@ -7,6 +7,7 @@
|
|||||||
- **仅 IP 访问**:不含域名模式与 HTTPS
|
- **仅 IP 访问**:不含域名模式与 HTTPS
|
||||||
- **本地访问无需放行端口**:选择本地 (127.0.0.1) 时,不涉及防火墙配置
|
- **本地访问无需放行端口**:选择本地 (127.0.0.1) 时,不涉及防火墙配置
|
||||||
- **Docker 未安装时**:用户可选择手动或自动安装 **Docker Desktop for Windows**(winget/Chocolatey)
|
- **Docker 未安装时**:用户可选择手动或自动安装 **Docker Desktop for Windows**(winget/Chocolatey)
|
||||||
|
- **支持变量非交互部署**:通过 `DEPLOY_IP` 或 `DEPLOY_ACCESS=local` 可跳过访问方式选择
|
||||||
|
|
||||||
## 2. Linux start.sh 流程梳理
|
## 2. Linux start.sh 流程梳理
|
||||||
|
|
||||||
@@ -103,9 +104,13 @@ Windows 版**仅支持 IP 访问**,不包含域名模式与 HTTPS 配置。用
|
|||||||
|
|
||||||
| 变量 | 说明 |
|
| 变量 | 说明 |
|
||||||
|------|------|
|
|------|------|
|
||||||
|
| `DEPLOY_ACCESS` | `local` 时直接使用 `127.0.0.1`;`lan`/`ip` 需要同时传 `DEPLOY_IP` |
|
||||||
| `DEPLOY_IP` | 访问 IP(本地填 `127.0.0.1`,局域网填实际 IP) |
|
| `DEPLOY_IP` | 访问 IP(本地填 `127.0.0.1`,局域网填实际 IP) |
|
||||||
| `DEPLOY_DRY_RUN` | 1 时只生成配置,不安装/启动 Docker |
|
| `DEPLOY_DRY_RUN` | 1 时只生成配置,不安装/启动 Docker |
|
||||||
| `DEPLOY_FORCE_RECONFIG` | 非空时强制重新配置 |
|
| `DEPLOY_FORCE_RECONFIG` | 非空时强制重新配置 |
|
||||||
|
| `DEPLOY_NON_INTERACTIVE` | 1 时缺少必要变量会直接报错,不进入问答 |
|
||||||
|
| `DEPLOY_DOCKER_INSTALL` | Docker Desktop 未安装时使用,`manual` 打开下载地址,`auto` 使用 winget/choco 自动安装 |
|
||||||
|
| `DEPLOY_NO_WAIT` | 1 时脚本结束或失败不等待按 Enter |
|
||||||
|
|
||||||
### 5.4 配置文件修改实现(仅 IP 模式)
|
### 5.4 配置文件修改实现(仅 IP 模式)
|
||||||
|
|
||||||
@@ -126,6 +131,7 @@ Set-Content .env -Value $content -Encoding UTF8 -NoNewline
|
|||||||
- **未安装时**: prompt 让用户选择
|
- **未安装时**: prompt 让用户选择
|
||||||
- `[1] 手动安装`:输出安装说明及 Docker Desktop for Windows 下载链接,退出脚本
|
- `[1] 手动安装`:输出安装说明及 Docker Desktop for Windows 下载链接,退出脚本
|
||||||
- `[2] 自动安装`:通过 winget 或 Chocolatey 安装 Docker Desktop for Windows,安装后需用户重启终端/机器再继续
|
- `[2] 自动安装`:通过 winget 或 Chocolatey 安装 Docker Desktop for Windows,安装后需用户重启终端/机器再继续
|
||||||
|
- 若设置 `DEPLOY_DOCKER_INSTALL=manual|auto`,脚本会直接执行对应分支,不再提示选择
|
||||||
|
|
||||||
### 5.6 执行策略
|
### 5.6 执行策略
|
||||||
|
|
||||||
@@ -154,15 +160,16 @@ powershell -ExecutionPolicy Bypass -File .\start.ps1
|
|||||||
|
|
||||||
## 7. 实现清单
|
## 7. 实现清单
|
||||||
|
|
||||||
- [ ] 创建 `start.ps1` 主脚本
|
- [x] 创建 `start.ps1` 主脚本
|
||||||
- [ ] 实现 `Init-ProjectDir`:项目目录校验
|
- [x] 实现 `Init-ProjectDir`:项目目录校验
|
||||||
- [ ] 实现 `Run-DeployQuestions`:本地 / 局域网 IP 选择(无域名/HTTPS)
|
- [x] 实现 `Run-DeployQuestions`:本地 / 局域网 IP 选择(无域名/HTTPS)
|
||||||
- [ ] 实现 `Setup-EnvFiles`:配置文件生成与替换
|
- [x] 实现 `Setup-EnvFiles`:配置文件生成与替换
|
||||||
- [ ] 实现 `Test-Docker`:Docker 检测,未安装时 prompt「手动安装」或「自动安装」
|
- [x] 实现 `Test-Docker`:Docker 检测,未安装时 prompt「手动安装」或「自动安装」
|
||||||
- [ ] 实现 `Install-Docker`:自动安装 **Docker Desktop for Windows**(winget / Chocolatey)
|
- [x] 实现 `Install-Docker`:自动安装 **Docker Desktop for Windows**(winget / Chocolatey)
|
||||||
- [ ] 实现 `Start-Services`:`docker compose` 启动
|
- [x] 实现 `Start-Services`:`docker compose` 启动
|
||||||
- [ ] 实现 `Main`:主流程串联
|
- [x] 实现 `Main`:主流程串联
|
||||||
- [ ] 支持 `DEPLOY_DRY_RUN`、`DEPLOY_IP` 环境变量非交互模式
|
- [x] 支持 `DEPLOY_DRY_RUN`、`DEPLOY_IP` 环境变量非交互模式
|
||||||
|
- [x] 支持 `DEPLOY_ACCESS=local`、`DEPLOY_NON_INTERACTIVE`、`DEPLOY_DOCKER_INSTALL` 非交互控制
|
||||||
- [x] 在 README 或文档中补充 Windows 部署说明与执行策略
|
- [x] 在 README 或文档中补充 Windows 部署说明与执行策略
|
||||||
- [x] 创建 `scripts/test-start-ps1-env.py` 验证 .env 替换逻辑
|
- [x] 创建 `scripts/test-start-ps1-env.py` 验证 .env 替换逻辑
|
||||||
|
|
||||||
@@ -178,6 +185,12 @@ $env:DEPLOY_DRY_RUN = "1"
|
|||||||
$env:DEPLOY_IP = "127.0.0.1"
|
$env:DEPLOY_IP = "127.0.0.1"
|
||||||
.\start.ps1
|
.\start.ps1
|
||||||
|
|
||||||
|
# 或使用本机访问模式变量
|
||||||
|
$env:DEPLOY_DRY_RUN = "1"
|
||||||
|
$env:DEPLOY_ACCESS = "local"
|
||||||
|
$env:DEPLOY_NO_WAIT = "1"
|
||||||
|
.\start.ps1
|
||||||
|
|
||||||
# 检查 .env 是否已正确写入
|
# 检查 .env 是否已正确写入
|
||||||
Select-String -Path .env -Pattern "NUXT_PUBLIC_BASE"
|
Select-String -Path .env -Pattern "NUXT_PUBLIC_BASE"
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
if command -v nginx &> /dev/null; then
|
if command -v nginx &> /dev/null; then
|
||||||
echo "✅ Nginx 已安装,跳过安装步骤"
|
echo "✅ Nginx 已安装,跳过安装步骤"
|
||||||
else
|
else
|
||||||
@@ -104,12 +106,55 @@ else
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# ===== 域名配置交互与文件生成 =====
|
# ===== 域名配置交互与文件生成 =====
|
||||||
|
sanitize_domain() {
|
||||||
|
local domain=$1
|
||||||
|
domain="${domain#http://}"
|
||||||
|
domain="${domain#https://}"
|
||||||
|
domain="${domain%%/*}"
|
||||||
|
domain="${domain%;}"
|
||||||
|
echo "$domain" | xargs
|
||||||
|
}
|
||||||
|
|
||||||
|
validate_domain_value() {
|
||||||
|
local domain=$1
|
||||||
|
[[ "$domain" =~ ^[A-Za-z0-9]([A-Za-z0-9-]{0,61}[A-Za-z0-9])?(\.[A-Za-z0-9]([A-Za-z0-9-]{0,61}[A-Za-z0-9])?)+$ ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
get_env_domain() {
|
||||||
|
local domain="${HTTPS_DOMAIN:-${EASYAI_PROXY_DOMAIN:-${DEPLOY_DOMAIN:-}}}"
|
||||||
|
if [ -z "$domain" ]; then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
domain="$(sanitize_domain "$domain")"
|
||||||
|
if ! validate_domain_value "$domain"; then
|
||||||
|
echo "❌ 域名变量格式不正确: $domain" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo "$domain"
|
||||||
|
}
|
||||||
|
|
||||||
|
is_non_interactive() {
|
||||||
|
[ "${HTTPS_NON_INTERACTIVE:-${DEPLOY_NON_INTERACTIVE:-0}}" = "1" ] || [ "${CI:-}" = "true" ] || [ ! -t 0 ]
|
||||||
|
}
|
||||||
|
|
||||||
prompt_domain() {
|
prompt_domain() {
|
||||||
local domain
|
local domain
|
||||||
|
domain="$(get_env_domain)"
|
||||||
|
if [ -n "$domain" ]; then
|
||||||
|
echo "$domain"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
if is_non_interactive; then
|
||||||
|
echo "❌ 当前为非交互环境,HTTPS 配置需要传入域名变量" >&2
|
||||||
|
echo " 请设置 DEPLOY_DOMAIN=<域名> 或 EASYAI_PROXY_DOMAIN=<域名>" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
while true; do
|
while true; do
|
||||||
read -r -p "🌐 请输入域名(例如 demo.example.com): " domain
|
read -r -p "🌐 请输入域名(例如 demo.example.com): " domain
|
||||||
domain=$(echo "$domain" | xargs)
|
domain="$(sanitize_domain "$domain")"
|
||||||
if [ -n "$domain" ] && [[ "$domain" =~ ^[A-Za-z0-9]([A-Za-z0-9-]{0,61}[A-Za-z0-9])?(\.[A-Za-z0-9]([A-Za-z0-9-]{0,61}[A-Za-z0-9])?)+$ ]]; then
|
if [ -n "$domain" ] && validate_domain_value "$domain"; then
|
||||||
echo "$domain"
|
echo "$domain"
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
@@ -211,24 +256,59 @@ server {
|
|||||||
EOF
|
EOF
|
||||||
}
|
}
|
||||||
|
|
||||||
|
conf_contains_domain() {
|
||||||
|
local conf_file=$1
|
||||||
|
local domain=$2
|
||||||
|
grep -Eq "server_name[^;]*(^|[[:space:]])(www\\.)?${domain//./\\.}([[:space:];]|$)" "./$conf_file"
|
||||||
|
}
|
||||||
|
|
||||||
|
normalize_domain_action() {
|
||||||
|
local action=$1
|
||||||
|
action="$(printf '%s' "$action" | tr '[:upper:]' '[:lower:]')"
|
||||||
|
case "$action" in
|
||||||
|
1|replace) echo "1" ;;
|
||||||
|
2|add|"") echo "2" ;;
|
||||||
|
*)
|
||||||
|
echo "❌ EASYAI_PROXY_DOMAIN_ACTION 只能是 replace 或 add,当前为: $action" >&2
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
upsert_domain_for_conf() {
|
upsert_domain_for_conf() {
|
||||||
local conf_file=$1
|
local conf_file=$1
|
||||||
|
local env_domain="${2:-}"
|
||||||
|
local env_action="${3:-}"
|
||||||
local mode
|
local mode
|
||||||
local new_domain
|
local new_domain
|
||||||
|
|
||||||
echo "ℹ️ 检测到当前目录已有配置文件: $conf_file"
|
echo "ℹ️ 检测到当前目录已有配置文件: $conf_file"
|
||||||
while true; do
|
if [ -n "$env_domain" ]; then
|
||||||
echo "请选择域名处理方式:"
|
new_domain="$(sanitize_domain "$env_domain")"
|
||||||
echo " 1) 替换当前域名"
|
if ! validate_domain_value "$new_domain"; then
|
||||||
echo " 2) 新增一个域名"
|
echo "❌ 域名变量格式不正确: $new_domain"
|
||||||
read -r -p "请输入选项 (1/2): " mode
|
exit 1
|
||||||
case "$mode" in
|
fi
|
||||||
1|2) break ;;
|
if conf_contains_domain "$conf_file" "$new_domain"; then
|
||||||
*) echo "❌ 无效选项,请输入 1 或 2" ;;
|
echo "ℹ️ 配置文件已包含域名 $new_domain,无需修改。"
|
||||||
esac
|
return 0
|
||||||
done
|
fi
|
||||||
|
mode="$(normalize_domain_action "$env_action")"
|
||||||
|
echo "使用变量配置域名: $new_domain, action=$([ "$mode" = "1" ] && echo replace || echo add)"
|
||||||
|
else
|
||||||
|
while true; do
|
||||||
|
echo "请选择域名处理方式:"
|
||||||
|
echo " 1) 替换当前域名"
|
||||||
|
echo " 2) 新增一个域名"
|
||||||
|
read -r -p "请输入选项 (1/2): " mode
|
||||||
|
case "$mode" in
|
||||||
|
1|2) break ;;
|
||||||
|
*) echo "❌ 无效选项,请输入 1 或 2" ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
new_domain=$(prompt_domain)
|
new_domain=$(prompt_domain)
|
||||||
|
fi
|
||||||
|
|
||||||
if [ "$mode" = "1" ]; then
|
if [ "$mode" = "1" ]; then
|
||||||
local old_domain
|
local old_domain
|
||||||
@@ -268,7 +348,9 @@ upsert_domain_for_conf() {
|
|||||||
|
|
||||||
detect_existing_proxy_conf() {
|
detect_existing_proxy_conf() {
|
||||||
local preferred_file=$1
|
local preferred_file=$1
|
||||||
|
local domain_filter="${2:-}"
|
||||||
local -a candidates=()
|
local -a candidates=()
|
||||||
|
local -a matched_candidates=()
|
||||||
local conf
|
local conf
|
||||||
|
|
||||||
if [ -n "$preferred_file" ] && [ -f "./$preferred_file" ]; then
|
if [ -n "$preferred_file" ] && [ -f "./$preferred_file" ]; then
|
||||||
@@ -286,15 +368,36 @@ detect_existing_proxy_conf() {
|
|||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if [ -n "$domain_filter" ]; then
|
||||||
|
for conf in "${candidates[@]}"; do
|
||||||
|
if conf_contains_domain "$conf" "$domain_filter"; then
|
||||||
|
matched_candidates+=("$conf")
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
if [ "${#matched_candidates[@]}" -eq 1 ]; then
|
||||||
|
echo "${matched_candidates[0]}"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
if [ "${#matched_candidates[@]}" -gt 1 ] && is_non_interactive; then
|
||||||
|
echo "❌ 多个配置文件都包含 $domain_filter,请通过 EASYAI_PROXY_CONF 指定文件" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
if [ "${#candidates[@]}" -eq 1 ]; then
|
if [ "${#candidates[@]}" -eq 1 ]; then
|
||||||
echo "${candidates[0]}"
|
echo "${candidates[0]}"
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "⚠️ 检测到多个可用配置文件,请选择一个:"
|
if is_non_interactive; then
|
||||||
|
echo "❌ 检测到多个可用配置文件,请通过 EASYAI_PROXY_CONF 指定文件" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "⚠️ 检测到多个可用配置文件,请选择一个:" >&2
|
||||||
local i
|
local i
|
||||||
for i in "${!candidates[@]}"; do
|
for i in "${!candidates[@]}"; do
|
||||||
printf " %s) %s\n" "$((i + 1))" "${candidates[$i]}"
|
printf " %s) %s\n" "$((i + 1))" "${candidates[$i]}" >&2
|
||||||
done
|
done
|
||||||
while true; do
|
while true; do
|
||||||
read -r -p "请输入序号: " i
|
read -r -p "请输入序号: " i
|
||||||
@@ -310,9 +413,10 @@ echo "🚀 复制当前目录的配置文件到nginx配置文件目录"
|
|||||||
# 支持 EASYAI_PROXY_CONF 指定配置文件(如 51easyai.com.conf)
|
# 支持 EASYAI_PROXY_CONF 指定配置文件(如 51easyai.com.conf)
|
||||||
PREFERRED_CONF_FILE="${EASYAI_PROXY_CONF:-}"
|
PREFERRED_CONF_FILE="${EASYAI_PROXY_CONF:-}"
|
||||||
DEFAULT_NEW_CONF_FILE="${EASYAI_PROXY_CONF:-easyai-proxy.conf}"
|
DEFAULT_NEW_CONF_FILE="${EASYAI_PROXY_CONF:-easyai-proxy.conf}"
|
||||||
CONF_FILE=$(detect_existing_proxy_conf "$PREFERRED_CONF_FILE")
|
HTTPS_DOMAIN_INPUT="$(get_env_domain)"
|
||||||
|
CONF_FILE=$(detect_existing_proxy_conf "$PREFERRED_CONF_FILE" "$HTTPS_DOMAIN_INPUT")
|
||||||
if [ -n "$CONF_FILE" ]; then
|
if [ -n "$CONF_FILE" ]; then
|
||||||
upsert_domain_for_conf "$CONF_FILE"
|
upsert_domain_for_conf "$CONF_FILE" "$HTTPS_DOMAIN_INPUT" "${EASYAI_PROXY_DOMAIN_ACTION:-}"
|
||||||
else
|
else
|
||||||
CONF_FILE="$DEFAULT_NEW_CONF_FILE"
|
CONF_FILE="$DEFAULT_NEW_CONF_FILE"
|
||||||
echo "ℹ️ 当前目录未找到可用 nginx 配置文件(*.conf 且包含 server_name)"
|
echo "ℹ️ 当前目录未找到可用 nginx 配置文件(*.conf 且包含 server_name)"
|
||||||
@@ -363,7 +467,7 @@ if [ -n "$DOMAINS" ]; then
|
|||||||
sudo certbot --nginx \
|
sudo certbot --nginx \
|
||||||
--non-interactive \
|
--non-interactive \
|
||||||
--agree-tos \
|
--agree-tos \
|
||||||
--email wangbo@51easyai.com \
|
--email "${CERTBOT_EMAIL:-wangbo@51easyai.com}" \
|
||||||
--rsa-key-size 2048 \
|
--rsa-key-size 2048 \
|
||||||
--preferred-challenges http \
|
--preferred-challenges http \
|
||||||
--force-renewal \
|
--force-renewal \
|
||||||
|
|||||||
@@ -98,6 +98,27 @@ function Run-DeployQuestions {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($env:DEPLOY_ACCESS) {
|
||||||
|
$mode = $env:DEPLOY_ACCESS.Trim().ToLowerInvariant()
|
||||||
|
switch ($mode) {
|
||||||
|
{ $_ -in @("local", "localhost", "127.0.0.1") } {
|
||||||
|
$script:DeployIP = "127.0.0.1"
|
||||||
|
Step "Using DEPLOY_ACCESS=$($env:DEPLOY_ACCESS), IP=$($script:DeployIP)"
|
||||||
|
return
|
||||||
|
}
|
||||||
|
{ $_ -in @("lan", "ip") } {
|
||||||
|
Fail "DEPLOY_ACCESS=$($env:DEPLOY_ACCESS) requires DEPLOY_IP, for example: `$env:DEPLOY_IP='192.168.1.10'"
|
||||||
|
}
|
||||||
|
default {
|
||||||
|
Fail "DEPLOY_ACCESS only supports local or lan on Windows, current value: $($env:DEPLOY_ACCESS)"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($env:DEPLOY_NON_INTERACTIVE -eq "1" -or $env:CI -eq "true") {
|
||||||
|
Fail "Non-interactive deployment requires DEPLOY_IP or DEPLOY_ACCESS=local."
|
||||||
|
}
|
||||||
|
|
||||||
Write-Host "Choose mode:"
|
Write-Host "Choose mode:"
|
||||||
Write-Host " [1] Local only (127.0.0.1)"
|
Write-Host " [1] Local only (127.0.0.1)"
|
||||||
Write-Host " [2] LAN access"
|
Write-Host " [2] LAN access"
|
||||||
@@ -277,6 +298,19 @@ function Test-Docker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Warn "Docker Desktop not detected."
|
Warn "Docker Desktop not detected."
|
||||||
|
$installMode = if ($env:DEPLOY_DOCKER_INSTALL) { $env:DEPLOY_DOCKER_INSTALL.Trim().ToLowerInvariant() } else { "" }
|
||||||
|
if (-not [string]::IsNullOrWhiteSpace($installMode)) {
|
||||||
|
switch ($installMode) {
|
||||||
|
{ $_ -in @("manual", "1") } { Start-Process $script:DockerDesktopUrl; Wait-ForExit; exit 1 }
|
||||||
|
{ $_ -in @("auto", "2") } { Install-DockerDesktop }
|
||||||
|
default { Fail "DEPLOY_DOCKER_INSTALL only supports manual or auto, current value: $($env:DEPLOY_DOCKER_INSTALL)" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($env:DEPLOY_NON_INTERACTIVE -eq "1" -or $env:CI -eq "true") {
|
||||||
|
Fail "Docker Desktop not detected. Set DEPLOY_DOCKER_INSTALL=manual or DEPLOY_DOCKER_INSTALL=auto, or install Docker Desktop first."
|
||||||
|
}
|
||||||
|
|
||||||
Write-Host "Choose:"
|
Write-Host "Choose:"
|
||||||
Write-Host " [1] Manual install (open URL and exit)"
|
Write-Host " [1] Manual install (open URL and exit)"
|
||||||
Write-Host " [2] Auto install (winget/choco)"
|
Write-Host " [2] Auto install (winget/choco)"
|
||||||
@@ -311,14 +345,21 @@ function Start-Services {
|
|||||||
function Main {
|
function Main {
|
||||||
Init-ProjectDir
|
Init-ProjectDir
|
||||||
|
|
||||||
if ((Test-Path ".env") -and -not $env:DEPLOY_FORCE_RECONFIG -and -not $env:DEPLOY_IP) {
|
if ((Test-Path ".env") -and -not $env:DEPLOY_FORCE_RECONFIG -and -not $env:DEPLOY_IP -and -not $env:DEPLOY_ACCESS) {
|
||||||
$answer = (Read-Host "Existing .env found. Reconfigure? [y/N]").Trim().ToLower()
|
if ($env:DEPLOY_NON_INTERACTIVE -eq "1" -or $env:CI -eq "true") {
|
||||||
$yes = ($answer.Length -gt 0) -and ($answer[0] -eq [char]121)
|
|
||||||
if (-not $yes) {
|
|
||||||
$line = Get-Content ".env" -Encoding UTF8 | Where-Object { $_ -like "NUXT_PUBLIC_BASE_APIURL=*" } | Select-Object -First 1
|
$line = Get-Content ".env" -Encoding UTF8 | Where-Object { $_ -like "NUXT_PUBLIC_BASE_APIURL=*" } | Select-Object -First 1
|
||||||
if ($line -and $line -like "*:3001*") { $script:DeployIP = ($line -replace ".*http://", "" -replace ":3001.*", "").Trim() }
|
if ($line -and $line -like "*:3001*") { $script:DeployIP = ($line -replace ".*http://", "" -replace ":3001.*", "").Trim() }
|
||||||
$script:SkipDeployQuestions = $true
|
$script:SkipDeployQuestions = $true
|
||||||
Step "Using existing env config"
|
Step "Using existing env config"
|
||||||
|
} else {
|
||||||
|
$answer = (Read-Host "Existing .env found. Reconfigure? [y/N]").Trim().ToLower()
|
||||||
|
$yes = ($answer.Length -gt 0) -and ($answer[0] -eq [char]121)
|
||||||
|
if (-not $yes) {
|
||||||
|
$line = Get-Content ".env" -Encoding UTF8 | Where-Object { $_ -like "NUXT_PUBLIC_BASE_APIURL=*" } | Select-Object -First 1
|
||||||
|
if ($line -and $line -like "*:3001*") { $script:DeployIP = ($line -replace ".*http://", "" -replace ":3001.*", "").Trim() }
|
||||||
|
$script:SkipDeployQuestions = $true
|
||||||
|
Step "Using existing env config"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -23,11 +23,57 @@ init_project_dir() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
# ==================== 配置变量(支持环境变量非交互模式) ====================
|
# ==================== 配置变量(支持环境变量非交互模式) ====================
|
||||||
DEPLOY_MODE="" # ip | domain
|
DEPLOY_ACCESS="${DEPLOY_ACCESS:-}" # ip | domain
|
||||||
DEPLOY_IP=""
|
DEPLOY_MODE="" # ip | domain | skip
|
||||||
DEPLOY_DOMAIN=""
|
DEPLOY_IP="${DEPLOY_IP:-}"
|
||||||
|
DEPLOY_DOMAIN="${DEPLOY_DOMAIN:-}"
|
||||||
|
DEPLOY_HTTPS_ENV="${DEPLOY_HTTPS_INPUT:-${DEPLOY_HTTPS:-}}"
|
||||||
DEPLOY_HTTPS=false
|
DEPLOY_HTTPS=false
|
||||||
|
|
||||||
|
is_non_interactive() {
|
||||||
|
[ "${DEPLOY_NON_INTERACTIVE:-0}" = "1" ] || [ "${CI:-}" = "true" ] || [ ! -t 0 ]
|
||||||
|
}
|
||||||
|
|
||||||
|
require_interactive() {
|
||||||
|
local missing_hint=$1
|
||||||
|
if is_non_interactive; then
|
||||||
|
echo "❌ 当前为非交互环境,无法继续问答配置"
|
||||||
|
echo " 请通过环境变量传入: ${missing_hint}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
normalize_bool() {
|
||||||
|
local value
|
||||||
|
value="$(printf '%s' "$1" | tr '[:upper:]' '[:lower:]')"
|
||||||
|
case "$value" in
|
||||||
|
1|true|yes|y|on) echo "true" ;;
|
||||||
|
0|false|no|n|off|"") echo "false" ;;
|
||||||
|
*)
|
||||||
|
echo "❌ 布尔变量值不合法: $1(支持 true/false/1/0/yes/no/y/n/on/off)" >&2
|
||||||
|
return 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
set_deploy_https_from_env_or_default() {
|
||||||
|
local normalized
|
||||||
|
if ! normalized="$(normalize_bool "${DEPLOY_HTTPS_ENV:-false}")"; then
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
DEPLOY_HTTPS="$normalized"
|
||||||
|
}
|
||||||
|
|
||||||
|
infer_deploy_access_from_env() {
|
||||||
|
if [ -z "$DEPLOY_ACCESS" ]; then
|
||||||
|
if [ -n "$DEPLOY_DOMAIN" ]; then
|
||||||
|
DEPLOY_ACCESS="domain"
|
||||||
|
elif [ -n "$DEPLOY_IP" ]; then
|
||||||
|
DEPLOY_ACCESS="ip"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
sanitize_domain() {
|
sanitize_domain() {
|
||||||
local domain="$1"
|
local domain="$1"
|
||||||
domain="${domain#http://}"
|
domain="${domain#http://}"
|
||||||
@@ -66,6 +112,8 @@ prompt_or_env() {
|
|||||||
return
|
return
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
require_interactive "$env_name"
|
||||||
|
|
||||||
if [ -n "$default" ]; then
|
if [ -n "$default" ]; then
|
||||||
read -r -p "${prompt_text} [$default]: " input
|
read -r -p "${prompt_text} [$default]: " input
|
||||||
eval "$var_name=\"${input:-$default}\""
|
eval "$var_name=\"${input:-$default}\""
|
||||||
@@ -82,6 +130,8 @@ run_deploy_questions() {
|
|||||||
echo "================================"
|
echo "================================"
|
||||||
echo ""
|
echo ""
|
||||||
|
|
||||||
|
infer_deploy_access_from_env
|
||||||
|
|
||||||
# 非交互模式:环境变量已完整设置则直接使用(CI/自动化部署)
|
# 非交互模式:环境变量已完整设置则直接使用(CI/自动化部署)
|
||||||
if [ -n "$DEPLOY_ACCESS" ]; then
|
if [ -n "$DEPLOY_ACCESS" ]; then
|
||||||
if [ "$DEPLOY_ACCESS" = "ip" ] && [ -n "$DEPLOY_IP" ]; then
|
if [ "$DEPLOY_ACCESS" = "ip" ] && [ -n "$DEPLOY_IP" ]; then
|
||||||
@@ -96,14 +146,19 @@ run_deploy_questions() {
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
DEPLOY_MODE="domain"
|
DEPLOY_MODE="domain"
|
||||||
DEPLOY_HTTPS="${DEPLOY_HTTPS_INPUT:-false}"
|
set_deploy_https_from_env_or_default
|
||||||
echo "使用环境变量: 域名模式, 域名=$DEPLOY_DOMAIN"
|
echo "使用环境变量: 域名模式, 域名=$DEPLOY_DOMAIN"
|
||||||
return
|
return
|
||||||
fi
|
fi
|
||||||
|
if [ "$DEPLOY_ACCESS" != "ip" ] && [ "$DEPLOY_ACCESS" != "domain" ]; then
|
||||||
|
echo "❌ DEPLOY_ACCESS 只能是 ip 或 domain,当前为: $DEPLOY_ACCESS"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# 1. IP 或域名访问
|
# 1. IP 或域名访问
|
||||||
if [ -z "$DEPLOY_ACCESS" ]; then
|
if [ -z "$DEPLOY_ACCESS" ]; then
|
||||||
|
require_interactive "DEPLOY_ACCESS=ip DEPLOY_IP=<服务器IP> 或 DEPLOY_ACCESS=domain DEPLOY_DOMAIN=<域名>"
|
||||||
echo "1. 通过 IP 地址还是域名访问?"
|
echo "1. 通过 IP 地址还是域名访问?"
|
||||||
echo " [1] IP 地址(需开放 3001、3002、3003 端口)"
|
echo " [1] IP 地址(需开放 3001、3002、3003 端口)"
|
||||||
echo " [2] 域名"
|
echo " [2] 域名"
|
||||||
@@ -140,9 +195,10 @@ run_deploy_questions() {
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# 3.1 是否启用 HTTPS
|
# 3.1 是否启用 HTTPS
|
||||||
if [ -n "$DEPLOY_HTTPS_INPUT" ]; then
|
if [ -n "$DEPLOY_HTTPS_ENV" ]; then
|
||||||
DEPLOY_HTTPS=$DEPLOY_HTTPS_INPUT
|
set_deploy_https_from_env_or_default
|
||||||
else
|
else
|
||||||
|
require_interactive "DEPLOY_HTTPS=true 或 DEPLOY_HTTPS=false"
|
||||||
read -r -p "3.1 是否签名 HTTPS 证书?原来已经有 HTTPS 证书这里选择 N,第一次部署或者原来没有证书选 Y [y/N]: " https_choice
|
read -r -p "3.1 是否签名 HTTPS 证书?原来已经有 HTTPS 证书这里选择 N,第一次部署或者原来没有证书选 Y [y/N]: " https_choice
|
||||||
DEPLOY_HTTPS=false
|
DEPLOY_HTTPS=false
|
||||||
if [[ "$https_choice" =~ ^[yY] ]]; then
|
if [[ "$https_choice" =~ ^[yY] ]]; then
|
||||||
@@ -308,17 +364,22 @@ install_docker() {
|
|||||||
sudo yum install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
|
sudo yum install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
|
||||||
elif [[ "$OS_FAMILY" == "macOS" ]]; then
|
elif [[ "$OS_FAMILY" == "macOS" ]]; then
|
||||||
echo "⚠️ 检测到 macOS,未找到 Docker。"
|
echo "⚠️ 检测到 macOS,未找到 Docker。"
|
||||||
echo "请选择安装方式:"
|
mac_install_choice="${DEPLOY_MAC_DOCKER_INSTALL:-${DEPLOY_DOCKER_INSTALL:-}}"
|
||||||
echo " [1] 自动安装 Docker Desktop(需要 Homebrew)"
|
if [ -z "$mac_install_choice" ]; then
|
||||||
echo " [2] 手动安装(默认)"
|
require_interactive "DEPLOY_MAC_DOCKER_INSTALL=auto 或 DEPLOY_MAC_DOCKER_INSTALL=manual"
|
||||||
read -r -p "请选择 [1/2]: " mac_install_choice
|
echo "请选择安装方式:"
|
||||||
|
echo " [1] 自动安装 Docker Desktop(需要 Homebrew)"
|
||||||
|
echo " [2] 手动安装(默认)"
|
||||||
|
read -r -p "请选择 [1/2]: " mac_install_choice
|
||||||
|
fi
|
||||||
|
mac_install_choice="$(printf '%s' "$mac_install_choice" | tr '[:upper:]' '[:lower:]')"
|
||||||
case "${mac_install_choice:-2}" in
|
case "${mac_install_choice:-2}" in
|
||||||
1)
|
1|auto)
|
||||||
if ! install_docker_macos; then
|
if ! install_docker_macos; then
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
;;
|
;;
|
||||||
2)
|
2|manual)
|
||||||
echo " 请手动安装 Docker Desktop: https://www.docker.com/products/docker-desktop/"
|
echo " 请手动安装 Docker Desktop: https://www.docker.com/products/docker-desktop/"
|
||||||
echo " 安装并启动 Docker Desktop 后,重新运行 ./start.sh"
|
echo " 安装并启动 Docker Desktop 后,重新运行 ./start.sh"
|
||||||
exit 1
|
exit 1
|
||||||
@@ -379,14 +440,20 @@ run_https_setup() {
|
|||||||
# ==================== 主流程 ====================
|
# ==================== 主流程 ====================
|
||||||
main() {
|
main() {
|
||||||
init_project_dir
|
init_project_dir
|
||||||
|
infer_deploy_access_from_env
|
||||||
|
|
||||||
# 检查是否已有 .env 且非强制重新配置
|
# 检查是否已有 .env 且非强制重新配置
|
||||||
if [ -f .env ] && [ -z "$DEPLOY_FORCE_RECONFIG" ] && [ -z "$DEPLOY_ACCESS" ]; then
|
if [ -f .env ] && [ -z "$DEPLOY_FORCE_RECONFIG" ] && [ -z "$DEPLOY_ACCESS" ]; then
|
||||||
echo "📁 检测到已有 .env 配置"
|
echo "📁 检测到已有 .env 配置"
|
||||||
read -r -p "是否重新配置部署方式?[y/N]: " reconfigure
|
if is_non_interactive; then
|
||||||
if [[ ! "$reconfigure" =~ ^[yY] ]]; then
|
|
||||||
echo "⏭️ 使用现有配置继续..."
|
echo "⏭️ 使用现有配置继续..."
|
||||||
DEPLOY_MODE="skip"
|
DEPLOY_MODE="skip"
|
||||||
|
else
|
||||||
|
read -r -p "是否重新配置部署方式?[y/N]: " reconfigure
|
||||||
|
if [[ ! "$reconfigure" =~ ^[yY] ]]; then
|
||||||
|
echo "⏭️ 使用现有配置继续..."
|
||||||
|
DEPLOY_MODE="skip"
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -415,6 +482,7 @@ main() {
|
|||||||
else
|
else
|
||||||
install_docker
|
install_docker
|
||||||
start_services
|
start_services
|
||||||
|
export DEPLOY_DOMAIN
|
||||||
run_https_setup
|
run_https_setup
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|||||||
+65
-16
@@ -33,6 +33,7 @@ trap {
|
|||||||
|
|
||||||
function Wait-ForExit {
|
function Wait-ForExit {
|
||||||
if ($env:CI -eq "true") { return }
|
if ($env:CI -eq "true") { return }
|
||||||
|
if ($env:UPDATE_NO_WAIT -eq "1") { return }
|
||||||
Write-Host ""
|
Write-Host ""
|
||||||
Read-Host "按 Enter 键退出"
|
Read-Host "按 Enter 键退出"
|
||||||
}
|
}
|
||||||
@@ -46,7 +47,17 @@ function Write-Warn { param($Msg) Write-Host "⚠️ $Msg" -ForegroundColor Yell
|
|||||||
if ($args -contains "-h" -or $args -contains "--help") {
|
if ($args -contains "-h" -or $args -contains "--help") {
|
||||||
Write-Host "用法: .\update.ps1"
|
Write-Host "用法: .\update.ps1"
|
||||||
Write-Host ""
|
Write-Host ""
|
||||||
Write-Host "脚本将提示选择更新方式,默认拉取仓库并更新镜像。"
|
Write-Host "默认拉取仓库并更新镜像;也可通过环境变量跳过交互选择。"
|
||||||
|
Write-Host ""
|
||||||
|
Write-Host "环境变量:"
|
||||||
|
Write-Host " UPDATE_MODE=full|image"
|
||||||
|
Write-Host " full 更新并拉取仓库(git pull)+ 更新镜像并重启"
|
||||||
|
Write-Host " image 仅更新镜像并重启(跳过 git pull)"
|
||||||
|
Write-Host " UPDATE_SKIP_REPO_UPDATE=true|false"
|
||||||
|
Write-Host " true 等同 UPDATE_MODE=image"
|
||||||
|
Write-Host " false 等同 UPDATE_MODE=full"
|
||||||
|
Write-Host " UPDATE_NO_WAIT=1"
|
||||||
|
Write-Host " 结束或失败时不等待按 Enter"
|
||||||
exit 0
|
exit 0
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -58,24 +69,62 @@ if (-not (Test-Path $composePath)) { Write-Err "未找到 docker-compose.yml,
|
|||||||
Set-Location $scriptDir
|
Set-Location $scriptDir
|
||||||
Write-Step "📁 项目目录: $scriptDir"
|
Write-Step "📁 项目目录: $scriptDir"
|
||||||
|
|
||||||
# ==================== 命令行内选择 ====================
|
function ConvertTo-BoolEnv {
|
||||||
Write-Host ""
|
param([string]$Value)
|
||||||
Write-Host "请选择更新方式:"
|
$v = if ($null -eq $Value) { "" } else { $Value.Trim().ToLowerInvariant() }
|
||||||
Write-Host " [1] 更新并拉取仓库(git pull)+ 更新镜像并重启(默认)"
|
switch ($v) {
|
||||||
Write-Host " [2] 仅更新镜像并重启(跳过 git pull)"
|
{ $_ -in @("1", "true", "yes", "y", "on") } { return $true }
|
||||||
$choice = Read-Host "请选择 [1/2,回车默认 1]"
|
{ $_ -in @("0", "false", "no", "n", "off", "") } { return $false }
|
||||||
if ([string]::IsNullOrWhiteSpace($choice)) { $choice = "1" }
|
default { Write-Err "布尔变量值不合法: $Value(支持 true/false/1/0/yes/no/y/n/on/off)" }
|
||||||
|
|
||||||
$skipRepoUpdate = $false
|
|
||||||
switch ($choice) {
|
|
||||||
"2" { $skipRepoUpdate = $true }
|
|
||||||
"1" { }
|
|
||||||
default {
|
|
||||||
Write-Warn "无效选择,将使用默认:更新并拉取仓库"
|
|
||||||
$skipRepoUpdate = $false
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function Resolve-UpdateMode {
|
||||||
|
if (-not [string]::IsNullOrWhiteSpace($env:UPDATE_SKIP_REPO_UPDATE)) {
|
||||||
|
$skip = ConvertTo-BoolEnv $env:UPDATE_SKIP_REPO_UPDATE
|
||||||
|
Write-Step "使用环境变量: UPDATE_SKIP_REPO_UPDATE=$skip"
|
||||||
|
return $skip
|
||||||
|
}
|
||||||
|
|
||||||
|
if (-not [string]::IsNullOrWhiteSpace($env:UPDATE_MODE)) {
|
||||||
|
$mode = $env:UPDATE_MODE.Trim().ToLowerInvariant()
|
||||||
|
switch ($mode) {
|
||||||
|
{ $_ -in @("full", "repo", "pull", "git", "1") } {
|
||||||
|
Write-Step "使用环境变量: UPDATE_MODE=$($env:UPDATE_MODE)"
|
||||||
|
return $false
|
||||||
|
}
|
||||||
|
{ $_ -in @("image", "images", "docker", "skip-git", "skip_repo", "skip-repo", "2") } {
|
||||||
|
Write-Step "使用环境变量: UPDATE_MODE=$($env:UPDATE_MODE)"
|
||||||
|
return $true
|
||||||
|
}
|
||||||
|
default { Write-Err "UPDATE_MODE 只能是 full 或 image,当前为: $($env:UPDATE_MODE)" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($env:UPDATE_NON_INTERACTIVE -eq "1" -or $env:CI -eq "true") {
|
||||||
|
Write-Step "使用默认更新方式: 更新并拉取仓库(git pull)+ 更新镜像并重启"
|
||||||
|
return $false
|
||||||
|
}
|
||||||
|
|
||||||
|
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" }
|
||||||
|
|
||||||
|
switch ($choice) {
|
||||||
|
"2" { return $true }
|
||||||
|
"1" { return $false }
|
||||||
|
default {
|
||||||
|
Write-Warn "无效选择,将使用默认:更新并拉取仓库"
|
||||||
|
return $false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$skipRepoUpdate = Resolve-UpdateMode
|
||||||
|
|
||||||
# ==================== 拉取仓库 ====================
|
# ==================== 拉取仓库 ====================
|
||||||
if (-not $skipRepoUpdate) {
|
if (-not $skipRepoUpdate) {
|
||||||
Write-Host ""
|
Write-Host ""
|
||||||
|
|||||||
@@ -6,7 +6,15 @@ set -e # 发生错误时终止脚本执行
|
|||||||
if [[ "${1:-}" =~ ^(-h|--help)$ ]]; then
|
if [[ "${1:-}" =~ ^(-h|--help)$ ]]; then
|
||||||
echo "用法: $0"
|
echo "用法: $0"
|
||||||
echo ""
|
echo ""
|
||||||
echo "脚本将提示选择更新方式,默认拉取仓库并更新镜像。"
|
echo "默认拉取仓库并更新镜像;也可通过环境变量跳过交互选择。"
|
||||||
|
echo ""
|
||||||
|
echo "环境变量:"
|
||||||
|
echo " UPDATE_MODE=full|image"
|
||||||
|
echo " full 更新并拉取仓库(git pull)+ 更新镜像并重启"
|
||||||
|
echo " image 仅更新镜像并重启(跳过 git pull)"
|
||||||
|
echo " UPDATE_SKIP_REPO_UPDATE=true|false"
|
||||||
|
echo " true 等同 UPDATE_MODE=image"
|
||||||
|
echo " false 等同 UPDATE_MODE=full"
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -15,18 +23,68 @@ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]:-$0}")" && pwd)"
|
|||||||
cd "$SCRIPT_DIR"
|
cd "$SCRIPT_DIR"
|
||||||
|
|
||||||
# 命令行内选择更新方式(默认:更新并拉取仓库)
|
# 命令行内选择更新方式(默认:更新并拉取仓库)
|
||||||
echo ""
|
|
||||||
echo "请选择更新方式:"
|
|
||||||
echo " [1] 更新并拉取仓库(git pull)+ 更新镜像并重启(默认)"
|
|
||||||
echo " [2] 仅更新镜像并重启(跳过 git pull)"
|
|
||||||
read -r -p "请选择 [1/2,回车默认 1]: " choice
|
|
||||||
choice="${choice:-1}"
|
|
||||||
SKIP_REPO_UPDATE=false
|
SKIP_REPO_UPDATE=false
|
||||||
case "$choice" in
|
|
||||||
2) SKIP_REPO_UPDATE=true ;;
|
normalize_bool() {
|
||||||
1) ;;
|
local value
|
||||||
*) echo "❌ 无效选择,将使用默认:更新并拉取仓库"; SKIP_REPO_UPDATE=false ;;
|
value="$(printf '%s' "$1" | tr '[:upper:]' '[:lower:]')"
|
||||||
esac
|
case "$value" in
|
||||||
|
1|true|yes|y|on) echo "true" ;;
|
||||||
|
0|false|no|n|off|"") echo "false" ;;
|
||||||
|
*)
|
||||||
|
echo "❌ 布尔变量值不合法: $1(支持 true/false/1/0/yes/no/y/n/on/off)" >&2
|
||||||
|
return 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
resolve_update_mode() {
|
||||||
|
local mode
|
||||||
|
if [ -n "${UPDATE_SKIP_REPO_UPDATE:-}" ]; then
|
||||||
|
mode="$(normalize_bool "$UPDATE_SKIP_REPO_UPDATE")" || exit 1
|
||||||
|
SKIP_REPO_UPDATE="$mode"
|
||||||
|
echo "使用环境变量: UPDATE_SKIP_REPO_UPDATE=$SKIP_REPO_UPDATE"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -n "${UPDATE_MODE:-}" ]; then
|
||||||
|
mode="$(printf '%s' "$UPDATE_MODE" | tr '[:upper:]' '[:lower:]')"
|
||||||
|
case "$mode" in
|
||||||
|
full|repo|pull|git|1)
|
||||||
|
SKIP_REPO_UPDATE=false
|
||||||
|
;;
|
||||||
|
image|images|docker|skip-git|skip_repo|skip-repo|2)
|
||||||
|
SKIP_REPO_UPDATE=true
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "❌ UPDATE_MODE 只能是 full 或 image,当前为: $UPDATE_MODE"
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
echo "使用环境变量: UPDATE_MODE=$UPDATE_MODE"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "${UPDATE_NON_INTERACTIVE:-0}" = "1" ] || [ "${CI:-}" = "true" ] || [ ! -t 0 ]; then
|
||||||
|
echo "使用默认更新方式: 更新并拉取仓库(git pull)+ 更新镜像并重启"
|
||||||
|
SKIP_REPO_UPDATE=false
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "请选择更新方式:"
|
||||||
|
echo " [1] 更新并拉取仓库(git pull)+ 更新镜像并重启(默认)"
|
||||||
|
echo " [2] 仅更新镜像并重启(跳过 git pull)"
|
||||||
|
read -r -p "请选择 [1/2,回车默认 1]: " choice
|
||||||
|
choice="${choice:-1}"
|
||||||
|
case "$choice" in
|
||||||
|
2) SKIP_REPO_UPDATE=true ;;
|
||||||
|
1) ;;
|
||||||
|
*) echo "❌ 无效选择,将使用默认:更新并拉取仓库"; SKIP_REPO_UPDATE=false ;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
resolve_update_mode
|
||||||
|
|
||||||
# 拉取整个仓库更新
|
# 拉取整个仓库更新
|
||||||
if [ "$SKIP_REPO_UPDATE" = false ]; then
|
if [ "$SKIP_REPO_UPDATE" = false ]; then
|
||||||
|
|||||||
Reference in New Issue
Block a user