修复一键部署bug

This commit is contained in:
dekun
2026-05-21 15:11:11 +08:00
parent 39815c1df6
commit 576e8b0b12
3 changed files with 268 additions and 252 deletions
+3
View File
@@ -0,0 +1,3 @@
# Shell 脚本在仓库内统一 LF,避免 Linux 上 bash: pipefail: invalid option nameCRLF
*.sh text eol=lf
deploy/** text eol=lf
+76 -68
View File
@@ -1,68 +1,76 @@
# 环境一键部署 # 环境一键部署
为仓库内各子项目创建 Python 虚拟环境、安装依赖、初始化 `.env` 与静态目录。 为仓库内各子项目创建 Python 虚拟环境、安装依赖、初始化 `.env` 与静态目录。
## Windows(推荐) ## Windows(推荐)
双击仓库根目录 **`一键部署.bat`**,或在 PowerShell 中: 双击仓库根目录 **`一键部署.bat`**,或在 PowerShell 中:
```powershell ```powershell
cd C:\path\to\crypto_monitor cd C:\path\to\crypto_monitor
.\deploy\setup_env.ps1 .\deploy\setup_env.ps1
``` ```
仅部署部分项目: 仅部署部分项目:
```powershell ```powershell
.\deploy\setup_env.ps1 -Only binance,gate_bot .\deploy\setup_env.ps1 -Only binance,gate_bot
``` ```
重建虚拟环境: 重建虚拟环境:
```powershell ```powershell
.\deploy\setup_env.ps1 -RecreateVenv .\deploy\setup_env.ps1 -RecreateVenv
``` ```
跳过 PM2、跳过复制 `.env` 跳过 PM2、跳过复制 `.env`
```powershell ```powershell
.\deploy\setup_env.ps1 -SkipPm2 -SkipEnvCopy .\deploy\setup_env.ps1 -SkipPm2 -SkipEnvCopy
``` ```
## Linux / macOS ## Linux / macOS
```bash ```bash
cd /opt/crypto_monitor cd /opt/crypto_monitor
bash deploy/setup_env.sh bash deploy/setup_env.sh
bash deploy/setup_env.sh --only binance,gate bash deploy/setup_env.sh --only binance,gate
bash deploy/setup_env.sh --recreate-venv bash deploy/setup_env.sh --recreate-venv
``` ```
## 脚本会做什么 若在 Windows 编辑过脚本后在 Linux 报错 `set: pipefail: invalid option name`,先去掉 CRLF 再执行:
| 步骤 | 说明 | ```bash
|------|------| sed -i 's/\r$//' deploy/setup_env.sh
| 检查 Python | 需要 **3.10+** | # 或: apt install -y dos2unix && dos2unix deploy/setup_env.sh
| `crypto_monitor_*` | 各目录 `.venv` + `pip install -r ../requirements.txt` | bash deploy/setup_env.sh
| `manual_trading_hub` | 独立 `requirements.txt` | ```
| `.env` | 若不存在则从 `.env.example` 复制(**不覆盖**已有) |
| 目录 | 创建 `static/images``static/images/order_charts` | ## 脚本会做什么
| PM2 | 若已装 Node.js 且未 `-SkipPm2`,尝试 `npm install -g pm2` |
| 步骤 | 说明 |
## 部署之后 |------|------|
| 检查 Python | 需要 **3.10+** |
1. 编辑各子目录 **`.env`**(API、登录密码、SOCKS 代理等)。 | `crypto_monitor_*` | 各目录 `.venv` + `pip install -r ../requirements.txt` |
2. 本地试运行(以 Binance 为例): | `manual_trading_hub` | 独立 `requirements.txt` |
| `.env` | 若不存在则从 `.env.example` 复制(**不覆盖**已有) |
```bash | 目录 | 创建 `static/images``static/images/order_charts` |
cd crypto_monitor_binance | PM2 | 若已装 Node.js 且未 `-SkipPm2`,尝试 `npm install -g pm2` |
source .venv/bin/activate # Windows: .\.venv\Scripts\activate
python app.py ## 部署之后
```
1. 编辑各子目录 **`.env`**(API、登录密码、SOCKS 代理等)。
3. 服务器长期运行见各目录 **《部署文档.md》**SSH SOCKS、PM2)。 2. 本地试运行(以 Binance 为例):
## 依赖说明 ```bash
cd crypto_monitor_binance
- 四个监控子项目共用仓库根目录 **[requirements.txt](../requirements.txt)**。 source .venv/bin/activate # Windows: .\.venv\Scripts\activate
- 走 SOCKS 代理时必须安装 **PySocks**(已包含在 requirements 中)。 python app.py
```
3. 服务器长期运行见各目录 **《部署文档.md》**SSH SOCKS、PM2)。
## 依赖说明
- 四个监控子项目共用仓库根目录 **[requirements.txt](../requirements.txt)**。
- 走 SOCKS 代理时必须安装 **PySocks**(已包含在 requirements 中)。
+189 -184
View File
@@ -1,184 +1,189 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# crypto_monitor 一键环境部署(Linux / macOS / Git Bash # crypto_monitor 一键环境部署(Linux / macOS / Git Bash
# #
# 用法: # 用法:
# bash deploy/setup_env.sh # bash deploy/setup_env.sh
# bash deploy/setup_env.sh --only binance,gate_bot # bash deploy/setup_env.sh --only binance,gate_bot
# bash deploy/setup_env.sh --skip-pm2 # bash deploy/setup_env.sh --skip-pm2
# bash deploy/setup_env.sh --recreate-venv # bash deploy/setup_env.sh --recreate-venv
# #
set -euo pipefail set -e
set -u
DEPLOY_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" # 避免 Windows CRLF 导致 set -euo pipefail 一行报错;pipefail 仅 bash 支持
REPO_ROOT="$(cd "${DEPLOY_DIR}/.." && pwd)" if [ -n "${BASH_VERSION:-}" ]; then
REQ_FILE="${REPO_ROOT}/requirements.txt" set -o pipefail
HUB_REQ="${REPO_ROOT}/manual_trading_hub/requirements.txt" fi
ONLY="all" DEPLOY_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
SKIP_PM2=0 REPO_ROOT="$(cd "${DEPLOY_DIR}/.." && pwd)"
SKIP_ENV_COPY=0 REQ_FILE="${REPO_ROOT}/requirements.txt"
RECREATE_VENV=0 HUB_REQ="${REPO_ROOT}/manual_trading_hub/requirements.txt"
usage() { ONLY="all"
sed -n '2,12p' "$0" | sed 's/^# \?//' SKIP_PM2=0
exit "${1:-0}" SKIP_ENV_COPY=0
} RECREATE_VENV=0
while [[ $# -gt 0 ]]; do usage() {
case "$1" in sed -n '2,12p' "$0" | sed 's/^# \?//'
--only) ONLY="${2:-all}"; shift 2 ;; exit "${1:-0}"
--skip-pm2) SKIP_PM2=1; shift ;; }
--skip-env-copy) SKIP_ENV_COPY=1; shift ;;
--recreate-venv) RECREATE_VENV=1; shift ;; while [[ $# -gt 0 ]]; do
-h|--help) usage 0 ;; case "$1" in
*) echo "未知参数: $1" >&2; usage 1 ;; --only) ONLY="${2:-all}"; shift 2 ;;
esac --skip-pm2) SKIP_PM2=1; shift ;;
done --skip-env-copy) SKIP_ENV_COPY=1; shift ;;
--recreate-venv) RECREATE_VENV=1; shift ;;
step() { echo ""; echo "==> $*"; } -h|--help) usage 0 ;;
*) echo "未知参数: $1" >&2; usage 1 ;;
should_include() { esac
local key="$1" done
if [[ "${ONLY}" == "all" ]]; then
return 0 step() { echo ""; echo "==> $*"; }
fi
local item should_include() {
IFS=',' read -ra PARTS <<< "${ONLY}" local key="$1"
for item in "${PARTS[@]}"; do if [[ "${ONLY}" == "all" ]]; then
item="$(echo "${item}" | tr '[:upper:]' '[:lower:]' | xargs)" return 0
[[ "${item}" == "${key}" ]] && return 0 fi
done local item
return 1 IFS=',' read -ra PARTS <<< "${ONLY}"
} for item in "${PARTS[@]}"; do
item="$(echo "${item}" | tr '[:upper:]' '[:lower:]' | xargs)"
find_python() { [[ "${item}" == "${key}" ]] && return 0
if command -v python3 >/dev/null 2>&1; then done
echo python3 return 1
return }
fi
if command -v python >/dev/null 2>&1; then find_python() {
echo python if command -v python3 >/dev/null 2>&1; then
return echo python3
fi return
echo "未找到 python3/python,请先安装 Python 3.10+" >&2 fi
exit 1 if command -v python >/dev/null 2>&1; then
} echo python
return
check_python_version() { fi
local py="$1" echo "未找到 python3/python,请先安装 Python 3.10+" >&2
local ver exit 1
ver="$("${py}" -c 'import sys; print(f"{sys.version_info.major}.{sys.version_info.minor}")')" }
local major minor
major="${ver%%.*}" check_python_version() {
minor="${ver#*.}" local py="$1"
if [[ "${major}" -lt 3 ]] || [[ "${major}" -eq 3 && "${minor}" -lt 10 ]]; then local ver
echo "需要 Python 3.10+,当前: ${ver}" >&2 ver="$("${py}" -c 'import sys; print(f"{sys.version_info.major}.{sys.version_info.minor}")')"
exit 1 local major minor
fi major="${ver%%.*}"
echo "Python: $("${py}" --version 2>&1)" minor="${ver#*.}"
} if [[ "${major}" -lt 3 ]] || [[ "${major}" -eq 3 && "${minor}" -lt 10 ]]; then
echo "需要 Python 3.10+,当前: ${ver}" >&2
setup_monitor() { exit 1
local dir_name="$1" fi
local proj="${REPO_ROOT}/${dir_name}" echo "Python: $("${py}" --version 2>&1)"
if [[ ! -d "${proj}" ]]; then }
echo " 跳过(目录不存在): ${dir_name}"
return setup_monitor() {
fi local dir_name="$1"
step "${dir_name}" local proj="${REPO_ROOT}/${dir_name}"
cd "${proj}" if [[ ! -d "${proj}" ]]; then
local py echo " 跳过(目录不存在): ${dir_name}"
py="$(find_python)" return
if [[ "${RECREATE_VENV}" -eq 1 && -d .venv ]]; then fi
echo " 删除旧 venv ..." step "${dir_name}"
rm -rf .venv cd "${proj}"
fi local py
if [[ ! -x .venv/bin/python ]]; then py="$(find_python)"
echo " 创建 venv ..." if [[ "${RECREATE_VENV}" -eq 1 && -d .venv ]]; then
"${py}" -m venv .venv echo " 删除旧 venv ..."
fi rm -rf .venv
echo " 升级 pip ..." fi
.venv/bin/python -m pip install -U pip setuptools wheel -q if [[ ! -x .venv/bin/python ]]; then
echo " 安装依赖 ..." echo " 创建 venv ..."
.venv/bin/pip install -r "${REQ_FILE}" -q "${py}" -m venv .venv
if [[ "${SKIP_ENV_COPY}" -eq 0 ]]; then fi
if [[ -f .env.example && ! -f .env ]]; then echo " 升级 pip ..."
cp -n .env.example .env 2>/dev/null || cp .env.example .env .venv/bin/python -m pip install -U pip setuptools wheel -q
echo " 已复制 .env.example -> .env" echo " 安装依赖 ..."
elif [[ -f .env ]]; then .venv/bin/pip install -r "${REQ_FILE}" -q
echo " 保留已有 .env" if [[ "${SKIP_ENV_COPY}" -eq 0 ]]; then
else if [[ -f .env.example && ! -f .env ]]; then
echo " 无 .env.example,请手动配置 .env" cp -n .env.example .env 2>/dev/null || cp .env.example .env
fi echo " 已复制 .env.example -> .env"
fi elif [[ -f .env ]]; then
mkdir -p static/images/order_charts echo " 保留已有 .env"
echo " 完成: ${proj}/.venv/bin/python" else
} echo " 无 .env.example,请手动配置 .env"
fi
setup_hub() { fi
local proj="${REPO_ROOT}/manual_trading_hub" mkdir -p static/images/order_charts
if [[ ! -d "${proj}" ]]; then echo " 完成: ${proj}/.venv/bin/python"
echo " 跳过 hub(目录不存在)" }
return
fi setup_hub() {
step "manual_trading_hub" local proj="${REPO_ROOT}/manual_trading_hub"
cd "${proj}" if [[ ! -d "${proj}" ]]; then
local py echo " 跳过 hub(目录不存在)"
py="$(find_python)" return
if [[ "${RECREATE_VENV}" -eq 1 && -d .venv ]]; then fi
rm -rf .venv step "manual_trading_hub"
fi cd "${proj}"
if [[ ! -x .venv/bin/python ]]; then local py
"${py}" -m venv .venv py="$(find_python)"
fi if [[ "${RECREATE_VENV}" -eq 1 && -d .venv ]]; then
.venv/bin/python -m pip install -U pip setuptools wheel -q rm -rf .venv
if [[ -f "${HUB_REQ}" ]]; then fi
.venv/bin/pip install -r "${HUB_REQ}" -q if [[ ! -x .venv/bin/python ]]; then
fi "${py}" -m venv .venv
if [[ "${SKIP_ENV_COPY}" -eq 0 && -f .env.example && ! -f .env ]]; then fi
cp -n .env.example .env 2>/dev/null || cp .env.example .env .venv/bin/python -m pip install -U pip setuptools wheel -q
echo " 已复制 .env.example -> .env" if [[ -f "${HUB_REQ}" ]]; then
fi .venv/bin/pip install -r "${HUB_REQ}" -q
echo " 完成: ${proj}/.venv/bin/python" fi
} if [[ "${SKIP_ENV_COPY}" -eq 0 && -f .env.example && ! -f .env ]]; then
cp -n .env.example .env 2>/dev/null || cp .env.example .env
install_pm2() { echo " 已复制 .env.example -> .env"
if [[ "${SKIP_PM2}" -eq 1 ]]; then fi
return echo " 完成: ${proj}/.venv/bin/python"
fi }
step "PM2(可选)"
if ! command -v node >/dev/null 2>&1; then install_pm2() {
echo " 未检测到 Node.js,跳过。安装后执行: npm install -g pm2" if [[ "${SKIP_PM2}" -eq 1 ]]; then
return return
fi fi
if command -v pm2 >/dev/null 2>&1; then step "PM2(可选)"
echo " PM2 已安装: $(pm2 -v)" if ! command -v node >/dev/null 2>&1; then
return echo " 未检测到 Node.js,跳过。安装后执行: npm install -g pm2"
fi return
echo " 正在安装 pm2 ..." fi
npm install -g pm2 if command -v pm2 >/dev/null 2>&1; then
echo " 各子目录: pm2 start ecosystem.config.cjs" echo " PM2 已安装: $(pm2 -v)"
} return
fi
echo "crypto_monitor 环境部署" echo " 正在安装 pm2 ..."
echo "仓库根目录: ${REPO_ROOT}" npm install -g pm2
echo " 各子目录: pm2 start ecosystem.config.cjs"
[[ -f "${REQ_FILE}" ]] || { echo "缺少 ${REQ_FILE}" >&2; exit 1; } }
PY="$(find_python)" echo "crypto_monitor 环境部署"
check_python_version "${PY}" echo "仓库根目录: ${REPO_ROOT}"
should_include binance && setup_monitor crypto_monitor_binance [[ -f "${REQ_FILE}" ]] || { echo "缺少 ${REQ_FILE}" >&2; exit 1; }
should_include gate && setup_monitor crypto_monitor_gate
should_include gate_bot && setup_monitor crypto_monitor_gate_bot PY="$(find_python)"
should_include okx && setup_monitor crypto_monitor_okx check_python_version "${PY}"
should_include hub && setup_hub
should_include binance && setup_monitor crypto_monitor_binance
install_pm2 should_include gate && setup_monitor crypto_monitor_gate
should_include gate_bot && setup_monitor crypto_monitor_gate_bot
echo "" should_include okx && setup_monitor crypto_monitor_okx
echo "部署完成。下一步:" should_include hub && setup_hub
echo " 1. 编辑各子目录 .env"
echo " 2. 启动示例: cd crypto_monitor_binance && source .venv/bin/activate && python app.py" install_pm2
echo " 3. Windows 可用: powershell -File deploy/setup_env.ps1"
echo "" echo ""
echo "部署完成。下一步:"
echo " 1. 编辑各子目录 .env"
echo " 2. 启动示例: cd crypto_monitor_binance && source .venv/bin/activate && python app.py"
echo " 3. Windows 可用: powershell -File deploy/setup_env.ps1"
echo ""