Fix CRLF in deploy shell scripts so Ubuntu bash can run updates.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
dekun
2026-07-26 22:07:44 +08:00
parent 8813fd3e37
commit bffbdafbfc
5 changed files with 545 additions and 545 deletions
+156 -156
View File
@@ -1,156 +1,156 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# deploy/lib/common.sh — 比特骆驼自动化对冲系统 部署公共函数 # deploy/lib/common.sh — 比特骆驼自动化对冲系统 部署公共函数
# 目标系统: Ubuntu 22.04 LTS # 目标系统: Ubuntu 22.04 LTS
set -e set -e
set -u set -u
if [ -n "${BASH_VERSION:-}" ]; then if [ -n "${BASH_VERSION:-}" ]; then
set -o pipefail set -o pipefail
fi fi
INSTALL_ROOT="${INSTALL_ROOT:-/opt/eth_hedge_sim}" INSTALL_ROOT="${INSTALL_ROOT:-/opt/eth_hedge_sim}"
GIT_URL="${GIT_URL:-https://git.bz121.com/dekun/eth_hedge_sim.git}" GIT_URL="${GIT_URL:-https://git.bz121.com/dekun/eth_hedge_sim.git}"
GIT_BRANCH="${GIT_BRANCH:-main}" GIT_BRANCH="${GIT_BRANCH:-main}"
BACKUP_ROOT="${BACKUP_ROOT:-/root/backups/eth_hedge_sim}" BACKUP_ROOT="${BACKUP_ROOT:-/root/backups/eth_hedge_sim}"
TZ_NAME="${EHS_TZ:-Asia/Shanghai}" TZ_NAME="${EHS_TZ:-Asia/Shanghai}"
NODE_MAJOR="${NODE_MAJOR:-20}" NODE_MAJOR="${NODE_MAJOR:-20}"
PM2_APP_NAME="${PM2_APP_NAME:-eth-hedge-api}" PM2_APP_NAME="${PM2_APP_NAME:-eth-hedge-api}"
API_PORT="${API_PORT:-5155}" API_PORT="${API_PORT:-5155}"
LIB_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" LIB_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
DEPLOY_DIR="$(cd "${LIB_DIR}/.." && pwd)" DEPLOY_DIR="$(cd "${LIB_DIR}/.." && pwd)"
REPO_ROOT="$(cd "${DEPLOY_DIR}/.." && pwd)" REPO_ROOT="$(cd "${DEPLOY_DIR}/.." && pwd)"
log() { printf '[%s] %s\n' "$(TZ="${TZ_NAME}" date '+%Y-%m-%d %H:%M:%S')" "$*"; } log() { printf '[%s] %s\n' "$(TZ="${TZ_NAME}" date '+%Y-%m-%d %H:%M:%S')" "$*"; }
step() { echo ""; log "==> $*"; } step() { echo ""; log "==> $*"; }
die() { die() {
echo "错误: $*" >&2 echo "错误: $*" >&2
exit 1 exit 1
} }
require_root() { require_root() {
if [[ "$(id -u)" -ne 0 ]]; then if [[ "$(id -u)" -ne 0 ]]; then
die "请使用 root 执行(推荐: sudo -i 后运行)" die "请使用 root 执行(推荐: sudo -i 后运行)"
fi fi
} }
detect_server_ip() { detect_server_ip() {
local ip="" local ip=""
if command -v hostname >/dev/null 2>&1; then if command -v hostname >/dev/null 2>&1; then
ip="$(hostname -I 2>/dev/null | awk '{print $1}')" ip="$(hostname -I 2>/dev/null | awk '{print $1}')"
fi fi
if [[ -z "${ip}" ]]; then if [[ -z "${ip}" ]]; then
ip="127.0.0.1" ip="127.0.0.1"
fi fi
echo "${ip}" echo "${ip}"
} }
# curl|bash 时 stdin 可能是管道,交互从 /dev/tty 读 # curl|bash 时 stdin 可能是管道,交互从 /dev/tty 读
cm_read() { cm_read() {
local __var="$1" local __var="$1"
local __prompt="${2:-}" local __prompt="${2:-}"
local __line="" local __line=""
if [[ -n "${__prompt}" ]]; then if [[ -n "${__prompt}" ]]; then
printf '%s' "${__prompt}" >/dev/tty 2>/dev/null || printf '%s' "${__prompt}" printf '%s' "${__prompt}" >/dev/tty 2>/dev/null || printf '%s' "${__prompt}"
fi fi
if [[ -r /dev/tty ]]; then if [[ -r /dev/tty ]]; then
IFS= read -r __line </dev/tty || true IFS= read -r __line </dev/tty || true
else else
IFS= read -r __line || true IFS= read -r __line || true
fi fi
printf -v "${__var}" '%s' "${__line}" printf -v "${__var}" '%s' "${__line}"
} }
confirm_yes() { confirm_yes() {
local msg="$1" local msg="$1"
local ans="" local ans=""
cm_read ans "${msg} [y/N] " cm_read ans "${msg} [y/N] "
[[ "${ans}" == [yY] || "${ans}" == [yY][eE][sS] ]] [[ "${ans}" == [yY] || "${ans}" == [yY][eE][sS] ]]
} }
repo_ready() { repo_ready() {
[[ -f "${1}/deploy/manage.sh" && -f "${1}/deploy/pull_and_restart.sh" ]] [[ -f "${1}/deploy/manage.sh" && -f "${1}/deploy/pull_and_restart.sh" ]]
} }
resolve_repo_root() { resolve_repo_root() {
if repo_ready "${INSTALL_ROOT}"; then if repo_ready "${INSTALL_ROOT}"; then
echo "${INSTALL_ROOT}" echo "${INSTALL_ROOT}"
return 0 return 0
fi fi
if [[ -n "${REPO_ROOT:-}" ]] && repo_ready "${REPO_ROOT}"; then if [[ -n "${REPO_ROOT:-}" ]] && repo_ready "${REPO_ROOT}"; then
echo "${REPO_ROOT}" echo "${REPO_ROOT}"
return 0 return 0
fi fi
return 1 return 1
} }
ensure_system_deps() { ensure_system_deps() {
step "检查系统依赖" step "检查系统依赖"
export DEBIAN_FRONTEND=noninteractive export DEBIAN_FRONTEND=noninteractive
if command -v apt-get >/dev/null 2>&1; then if command -v apt-get >/dev/null 2>&1; then
apt-get update -qq apt-get update -qq
apt-get install -y git ca-certificates curl python3 python3-venv python3-pip apt-get install -y git ca-certificates curl python3 python3-venv python3-pip
fi fi
if ! command -v node >/dev/null 2>&1; then if ! command -v node >/dev/null 2>&1; then
step "安装 Node.js ${NODE_MAJOR}" step "安装 Node.js ${NODE_MAJOR}"
curl -fsSL "https://deb.nodesource.com/setup_${NODE_MAJOR}.x" | bash - curl -fsSL "https://deb.nodesource.com/setup_${NODE_MAJOR}.x" | bash -
apt-get install -y nodejs apt-get install -y nodejs
fi fi
if ! command -v pm2 >/dev/null 2>&1; then if ! command -v pm2 >/dev/null 2>&1; then
step "安装 PM2" step "安装 PM2"
npm install -g pm2 npm install -g pm2
fi fi
} }
pm2_stop_project() { pm2_stop_project() {
if command -v pm2 >/dev/null 2>&1; then if command -v pm2 >/dev/null 2>&1; then
pm2 stop "${PM2_APP_NAME}" 2>/dev/null || true pm2 stop "${PM2_APP_NAME}" 2>/dev/null || true
fi fi
} }
pm2_delete_project() { pm2_delete_project() {
if command -v pm2 >/dev/null 2>&1; then if command -v pm2 >/dev/null 2>&1; then
pm2 delete "${PM2_APP_NAME}" 2>/dev/null || true pm2 delete "${PM2_APP_NAME}" 2>/dev/null || true
pm2 save 2>/dev/null || true pm2 save 2>/dev/null || true
fi fi
} }
pm2_save_startup() { pm2_save_startup() {
if command -v pm2 >/dev/null 2>&1; then if command -v pm2 >/dev/null 2>&1; then
pm2 save 2>/dev/null || true pm2 save 2>/dev/null || true
pm2 startup systemd -u root --hp /root 2>/dev/null || true pm2 startup systemd -u root --hp /root 2>/dev/null || true
fi fi
} }
verify_health() { verify_health() {
local port="${1:-${API_PORT}}" local port="${1:-${API_PORT}}"
local url="http://127.0.0.1:${port}/health" local url="http://127.0.0.1:${port}/health"
step "健康检查 ${url}" step "健康检查 ${url}"
local i local i
for i in 1 2 3 4 5 6 7 8 9 10; do for i in 1 2 3 4 5 6 7 8 9 10; do
if curl -fsS "${url}" >/dev/null 2>&1; then if curl -fsS "${url}" >/dev/null 2>&1; then
log "health OK" log "health OK"
curl -fsS "${url}" || true curl -fsS "${url}" || true
echo "" echo ""
return 0 return 0
fi fi
sleep 1 sleep 1
done done
log "警告: health 暂未就绪,请稍后检查 pm2 logs ${PM2_APP_NAME}" log "警告: health 暂未就绪,请稍后检查 pm2 logs ${PM2_APP_NAME}"
return 1 return 1
} }
print_post_install_guide() { print_post_install_guide() {
local ip local ip
ip="$(detect_server_ip)" ip="$(detect_server_ip)"
echo "" echo ""
echo "══════════════════════════════════════" echo "══════════════════════════════════════"
echo " 比特骆驼自动化对冲系统 部署完成" echo " 比特骆驼自动化对冲系统 部署完成"
echo " 目录: ${INSTALL_ROOT}" echo " 目录: ${INSTALL_ROOT}"
echo " 本机: http://${ip}:${API_PORT}/health" echo " 本机: http://${ip}:${API_PORT}/health"
echo " 进程: pm2 status → ${PM2_APP_NAME}" echo " 进程: pm2 status → ${PM2_APP_NAME}"
echo " 管理: bash ${INSTALL_ROOT}/deploy/manage.sh" echo " 管理: bash ${INSTALL_ROOT}/deploy/manage.sh"
echo " 配置: ${INSTALL_ROOT}/.env" echo " 配置: ${INSTALL_ROOT}/.env"
echo "══════════════════════════════════════" echo "══════════════════════════════════════"
echo "" echo ""
} }
+80 -80
View File
@@ -1,80 +1,80 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# deploy/lib/uninstall.sh — 一键卸载(仅本项目 PM2,不动其它进程) # deploy/lib/uninstall.sh — 一键卸载(仅本项目 PM2,不动其它进程)
set -e set -e
set -u set -u
if [ -n "${BASH_VERSION:-}" ]; then if [ -n "${BASH_VERSION:-}" ]; then
set -o pipefail set -o pipefail
fi fi
LIB_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" LIB_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# shellcheck source=common.sh # shellcheck source=common.sh
source "${LIB_DIR}/common.sh" source "${LIB_DIR}/common.sh"
main_uninstall() { main_uninstall() {
require_root require_root
local root="" local root=""
if ! root="$(resolve_repo_root)"; then if ! root="$(resolve_repo_root)"; then
if [[ -d "${INSTALL_ROOT}" ]]; then if [[ -d "${INSTALL_ROOT}" ]]; then
root="${INSTALL_ROOT}" root="${INSTALL_ROOT}"
else else
die "未找到安装目录 ${INSTALL_ROOT}" die "未找到安装目录 ${INSTALL_ROOT}"
fi fi
fi fi
REPO_ROOT="${root}" REPO_ROOT="${root}"
echo "" echo ""
echo "将卸载 比特骆驼自动化对冲系统 (eth_hedge_sim):" echo "将卸载 比特骆驼自动化对冲系统 (eth_hedge_sim):"
echo " - 停止并删除 PM2 进程: ${PM2_APP_NAME}" echo " - 停止并删除 PM2 进程: ${PM2_APP_NAME}"
echo " - 移走目录: ${INSTALL_ROOT}" echo " - 移走目录: ${INSTALL_ROOT}"
echo " - 备份 .env 到 ${BACKUP_ROOT}" echo " - 备份 .env 到 ${BACKUP_ROOT}"
echo " - 不影响其它 PM2 应用" echo " - 不影响其它 PM2 应用"
echo "" echo ""
if ! confirm_yes "确认卸载?"; then if ! confirm_yes "确认卸载?"; then
log "已取消卸载" log "已取消卸载"
return 0 return 0
fi fi
local stamp backup_dir removed_dir local stamp backup_dir removed_dir
stamp="$(TZ="${TZ_NAME}" date +%Y%m%d-%H%M%S)" stamp="$(TZ="${TZ_NAME}" date +%Y%m%d-%H%M%S)"
backup_dir="${BACKUP_ROOT}/pre-uninstall-${stamp}" backup_dir="${BACKUP_ROOT}/pre-uninstall-${stamp}"
removed_dir="${INSTALL_ROOT}.removed.${stamp}" removed_dir="${INSTALL_ROOT}.removed.${stamp}"
mkdir -p "${backup_dir}" mkdir -p "${backup_dir}"
step "备份配置" step "备份配置"
if [[ -f "${REPO_ROOT}/.env" ]]; then if [[ -f "${REPO_ROOT}/.env" ]]; then
cp -a "${REPO_ROOT}/.env" "${backup_dir}/.env" cp -a "${REPO_ROOT}/.env" "${backup_dir}/.env"
fi fi
if [[ -d "${REPO_ROOT}/backend/data" ]]; then if [[ -d "${REPO_ROOT}/backend/data" ]]; then
cp -a "${REPO_ROOT}/backend/data" "${backup_dir}/data" 2>/dev/null || true cp -a "${REPO_ROOT}/backend/data" "${backup_dir}/data" 2>/dev/null || true
fi fi
{ {
echo "created_at=${stamp}" echo "created_at=${stamp}"
echo "install_root=${INSTALL_ROOT}" echo "install_root=${INSTALL_ROOT}"
echo "removed_dir=${removed_dir}" echo "removed_dir=${removed_dir}"
echo "pm2_app=${PM2_APP_NAME}" echo "pm2_app=${PM2_APP_NAME}"
} >"${backup_dir}/uninstall.manifest" } >"${backup_dir}/uninstall.manifest"
step "停止并移除 PM2 进程 ${PM2_APP_NAME}" step "停止并移除 PM2 进程 ${PM2_APP_NAME}"
pm2_stop_project pm2_stop_project
pm2_delete_project pm2_delete_project
step "移走安装目录" step "移走安装目录"
if [[ -d "${INSTALL_ROOT}" ]]; then if [[ -d "${INSTALL_ROOT}" ]]; then
mv "${INSTALL_ROOT}" "${removed_dir}" mv "${INSTALL_ROOT}" "${removed_dir}"
log "已移动: ${INSTALL_ROOT} -> ${removed_dir}" log "已移动: ${INSTALL_ROOT} -> ${removed_dir}"
else else
log "安装目录不存在,跳过" log "安装目录不存在,跳过"
fi fi
echo "" echo ""
echo "卸载完成." echo "卸载完成."
echo " 配置备份: ${backup_dir}" echo " 配置备份: ${backup_dir}"
echo " 旧目录: ${removed_dir} (确认无误后可手动 rm -rf)" echo " 旧目录: ${removed_dir} (确认无误后可手动 rm -rf)"
echo "" echo ""
echo "回滚示例:" echo "回滚示例:"
echo " mv ${removed_dir} ${INSTALL_ROOT}" echo " mv ${removed_dir} ${INSTALL_ROOT}"
echo " bash ${INSTALL_ROOT}/deploy/manage.sh # 选 1 修复环境" echo " bash ${INSTALL_ROOT}/deploy/manage.sh # 选 1 修复环境"
} }
main_uninstall "$@" main_uninstall "$@"
+29 -29
View File
@@ -1,29 +1,29 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# deploy/lib/update.sh — 更新(仅 git pull,禁止 scp # deploy/lib/update.sh — 更新(仅 git pull,禁止 scp
set -e set -e
set -u set -u
if [ -n "${BASH_VERSION:-}" ]; then if [ -n "${BASH_VERSION:-}" ]; then
set -o pipefail set -o pipefail
fi fi
LIB_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" LIB_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# shellcheck source=common.sh # shellcheck source=common.sh
source "${LIB_DIR}/common.sh" source "${LIB_DIR}/common.sh"
main_update() { main_update() {
require_root require_root
if ! REPO_ROOT="$(resolve_repo_root)"; then if ! REPO_ROOT="$(resolve_repo_root)"; then
die "未找到安装目录 ${INSTALL_ROOT},请先执行「1) 一键部署」" die "未找到安装目录 ${INSTALL_ROOT},请先执行「1) 一键部署」"
fi fi
if ! repo_ready "${REPO_ROOT}"; then if ! repo_ready "${REPO_ROOT}"; then
die "安装不完整,请先执行「1) 一键部署」" die "安装不完整,请先执行「1) 一键部署」"
fi fi
step "更新 比特骆驼自动化对冲系统 (git pull + 构建 + pm2 reload)" step "更新 比特骆驼自动化对冲系统 (git pull + 构建 + pm2 reload)"
bash "${REPO_ROOT}/deploy/pull_and_restart.sh" bash "${REPO_ROOT}/deploy/pull_and_restart.sh"
verify_health || true verify_health || true
echo "" echo ""
log "更新完成" log "更新完成"
} }
main_update "$@" main_update "$@"
+225 -225
View File
@@ -1,225 +1,225 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# 比特骆驼自动化对冲系统 部署管理器(工程 eth_hedge_sim # 比特骆驼自动化对冲系统 部署管理器(工程 eth_hedge_sim
# 部署环境: Ubuntu 22.04 LTS # 部署环境: Ubuntu 22.04 LTS
# #
# 新服务器(免克隆): # 新服务器(免克隆):
# curl -fsSL https://git.bz121.com/dekun/eth_hedge_sim/raw/branch/main/deploy/manage.sh | bash # curl -fsSL https://git.bz121.com/dekun/eth_hedge_sim/raw/branch/main/deploy/manage.sh | bash
# #
# 已安装: # 已安装:
# bash /opt/eth_hedge_sim/deploy/manage.sh # bash /opt/eth_hedge_sim/deploy/manage.sh
# #
set -e set -e
if [ -n "${BASH_VERSION:-}" ]; then if [ -n "${BASH_VERSION:-}" ]; then
set -o pipefail set -o pipefail
fi fi
INSTALL_ROOT="${INSTALL_ROOT:-/opt/eth_hedge_sim}" INSTALL_ROOT="${INSTALL_ROOT:-/opt/eth_hedge_sim}"
GIT_URL="${GIT_URL:-https://git.bz121.com/dekun/eth_hedge_sim.git}" GIT_URL="${GIT_URL:-https://git.bz121.com/dekun/eth_hedge_sim.git}"
GIT_BRANCH="${GIT_BRANCH:-main}" GIT_BRANCH="${GIT_BRANCH:-main}"
# curl | bash 时脚本从 stdin 执行,BASH_SOURCE[0] 为空;须先安全探测再 set -u # curl | bash 时脚本从 stdin 执行,BASH_SOURCE[0] 为空;须先安全探测再 set -u
_script_src="${BASH_SOURCE[0]:-}" _script_src="${BASH_SOURCE[0]:-}"
if [[ -n "${_script_src}" && -f "${_script_src}" ]]; then if [[ -n "${_script_src}" && -f "${_script_src}" ]]; then
DEPLOY_DIR="$(cd "$(dirname "${_script_src}")" && pwd)" DEPLOY_DIR="$(cd "$(dirname "${_script_src}")" && pwd)"
REPO_ROOT="$(cd "${DEPLOY_DIR}/.." && pwd)" REPO_ROOT="$(cd "${DEPLOY_DIR}/.." && pwd)"
LIB_DIR="${DEPLOY_DIR}/lib" LIB_DIR="${DEPLOY_DIR}/lib"
else else
DEPLOY_DIR="" DEPLOY_DIR=""
REPO_ROOT="" REPO_ROOT=""
LIB_DIR="" LIB_DIR=""
fi fi
unset _script_src unset _script_src
set -u set -u
repo_ready() { repo_ready() {
[[ -f "${1}/deploy/manage.sh" && -f "${1}/deploy/pull_and_restart.sh" && -d "${1}/deploy/lib" ]] [[ -f "${1}/deploy/manage.sh" && -f "${1}/deploy/pull_and_restart.sh" && -d "${1}/deploy/lib" ]]
} }
ensure_git_cli() { ensure_git_cli() {
if command -v git >/dev/null 2>&1; then if command -v git >/dev/null 2>&1; then
return 0 return 0
fi fi
if command -v apt-get >/dev/null 2>&1; then if command -v apt-get >/dev/null 2>&1; then
export DEBIAN_FRONTEND=noninteractive export DEBIAN_FRONTEND=noninteractive
apt-get update -qq apt-get update -qq
apt-get install -y git ca-certificates curl apt-get install -y git ca-certificates curl
else else
echo "错误: 未找到 git" >&2 echo "错误: 未找到 git" >&2
exit 1 exit 1
fi fi
} }
sync_repo_if_present() { sync_repo_if_present() {
local root="$1" local root="$1"
if [[ -d "${root}/.git" ]] && command -v git >/dev/null 2>&1; then if [[ -d "${root}/.git" ]] && command -v git >/dev/null 2>&1; then
git -C "${root}" fetch --all --prune 2>/dev/null || true git -C "${root}" fetch --all --prune 2>/dev/null || true
git -C "${root}" checkout "${GIT_BRANCH}" 2>/dev/null || true git -C "${root}" checkout "${GIT_BRANCH}" 2>/dev/null || true
git -C "${root}" pull --ff-only origin "${GIT_BRANCH}" 2>/dev/null \ git -C "${root}" pull --ff-only origin "${GIT_BRANCH}" 2>/dev/null \
|| git -C "${root}" pull --ff-only 2>/dev/null \ || git -C "${root}" pull --ff-only 2>/dev/null \
|| true || true
fi fi
} }
# 旧目录已存在但缺 manage.sh:尽量 git pull / 修复后切到仓库内脚本 # 旧目录已存在但缺 manage.sh:尽量 git pull / 修复后切到仓库内脚本
heal_existing_install() { heal_existing_install() {
local root="$1" local root="$1"
echo "检测到已有目录但缺少管理脚本: ${root}" echo "检测到已有目录但缺少管理脚本: ${root}"
echo "尝试同步最新代码…" echo "尝试同步最新代码…"
ensure_git_cli ensure_git_cli
if [[ -d "${root}/.git" ]]; then if [[ -d "${root}/.git" ]]; then
sync_repo_if_present "${root}" sync_repo_if_present "${root}"
if repo_ready "${root}"; then if repo_ready "${root}"; then
echo "同步成功,切换到仓库内 manage.sh" echo "同步成功,切换到仓库内 manage.sh"
exec bash "${root}/deploy/manage.sh" "$@" </dev/tty exec bash "${root}/deploy/manage.sh" "$@" </dev/tty
fi fi
echo "git pull 后仍不完整,尝试强制对齐 origin/${GIT_BRANCH}" echo "git pull 后仍不完整,尝试强制对齐 origin/${GIT_BRANCH}"
git -C "${root}" fetch origin "${GIT_BRANCH}" || true git -C "${root}" fetch origin "${GIT_BRANCH}" || true
git -C "${root}" reset --hard "origin/${GIT_BRANCH}" || true git -C "${root}" reset --hard "origin/${GIT_BRANCH}" || true
if repo_ready "${root}"; then if repo_ready "${root}"; then
echo "对齐成功,切换到仓库内 manage.sh" echo "对齐成功,切换到仓库内 manage.sh"
exec bash "${root}/deploy/manage.sh" "$@" </dev/tty exec bash "${root}/deploy/manage.sh" "$@" </dev/tty
fi fi
fi fi
# 无 .git 或仍不可用:备份 .env/data 后重新 clone # 无 .git 或仍不可用:备份 .env/data 后重新 clone
echo "将备份配置并重新克隆到 ${root}" echo "将备份配置并重新克隆到 ${root}"
local stamp backup_dir local stamp backup_dir
stamp="$(date +%Y%m%d-%H%M%S)" stamp="$(date +%Y%m%d-%H%M%S)"
backup_dir="/root/backups/eth_hedge_sim/heal-${stamp}" backup_dir="/root/backups/eth_hedge_sim/heal-${stamp}"
mkdir -p "${backup_dir}" mkdir -p "${backup_dir}"
[[ -f "${root}/.env" ]] && cp -a "${root}/.env" "${backup_dir}/.env" [[ -f "${root}/.env" ]] && cp -a "${root}/.env" "${backup_dir}/.env"
[[ -d "${root}/backend/data" ]] && cp -a "${root}/backend/data" "${backup_dir}/data" || true [[ -d "${root}/backend/data" ]] && cp -a "${root}/backend/data" "${backup_dir}/data" || true
echo "备份目录: ${backup_dir}" echo "备份目录: ${backup_dir}"
local removed="${root}.old.${stamp}" local removed="${root}.old.${stamp}"
mv "${root}" "${removed}" mv "${root}" "${removed}"
echo "旧目录已移至: ${removed}" echo "旧目录已移至: ${removed}"
mkdir -p "$(dirname "${root}")" mkdir -p "$(dirname "${root}")"
git clone -b "${GIT_BRANCH}" "${GIT_URL}" "${root}" git clone -b "${GIT_BRANCH}" "${GIT_URL}" "${root}"
if [[ -f "${backup_dir}/.env" ]]; then if [[ -f "${backup_dir}/.env" ]]; then
cp -a "${backup_dir}/.env" "${root}/.env" cp -a "${backup_dir}/.env" "${root}/.env"
echo "已恢复 .env" echo "已恢复 .env"
fi fi
if [[ -d "${backup_dir}/data" ]]; then if [[ -d "${backup_dir}/data" ]]; then
mkdir -p "${root}/backend" mkdir -p "${root}/backend"
cp -a "${backup_dir}/data" "${root}/backend/data" cp -a "${backup_dir}/data" "${root}/backend/data"
echo "已恢复 backend/data" echo "已恢复 backend/data"
fi fi
exec bash "${root}/deploy/manage.sh" "$@" </dev/tty exec bash "${root}/deploy/manage.sh" "$@" </dev/tty
} }
bootstrap_repo() { bootstrap_repo() {
if repo_ready "${INSTALL_ROOT}"; then if repo_ready "${INSTALL_ROOT}"; then
REPO_ROOT="${INSTALL_ROOT}" REPO_ROOT="${INSTALL_ROOT}"
DEPLOY_DIR="${REPO_ROOT}/deploy" DEPLOY_DIR="${REPO_ROOT}/deploy"
LIB_DIR="${DEPLOY_DIR}/lib" LIB_DIR="${DEPLOY_DIR}/lib"
sync_repo_if_present "${REPO_ROOT}" sync_repo_if_present "${REPO_ROOT}"
# pull 后可能才有 lib,再校验一次 # pull 后可能才有 lib,再校验一次
if ! repo_ready "${REPO_ROOT}"; then if ! repo_ready "${REPO_ROOT}"; then
heal_existing_install "${INSTALL_ROOT}" "$@" heal_existing_install "${INSTALL_ROOT}" "$@"
fi fi
return 0 return 0
fi fi
if [[ -n "${REPO_ROOT}" ]] && repo_ready "${REPO_ROOT}"; then if [[ -n "${REPO_ROOT}" ]] && repo_ready "${REPO_ROOT}"; then
DEPLOY_DIR="${REPO_ROOT}/deploy" DEPLOY_DIR="${REPO_ROOT}/deploy"
LIB_DIR="${DEPLOY_DIR}/lib" LIB_DIR="${DEPLOY_DIR}/lib"
return 0 return 0
fi fi
# 目录在,但还是旧版(你当前的情况) # 目录在,但还是旧版(你当前的情况)
if [[ -d "${INSTALL_ROOT}" ]]; then if [[ -d "${INSTALL_ROOT}" ]]; then
if [[ "$(id -u)" -ne 0 ]]; then if [[ "$(id -u)" -ne 0 ]]; then
echo "错误: 请使用 root 执行" >&2 echo "错误: 请使用 root 执行" >&2
exit 1 exit 1
fi fi
heal_existing_install "${INSTALL_ROOT}" "$@" heal_existing_install "${INSTALL_ROOT}" "$@"
fi fi
echo "比特骆驼自动化对冲系统 部署管理器 — 首次自举" echo "比特骆驼自动化对冲系统 部署管理器 — 首次自举"
echo "将克隆到: ${INSTALL_ROOT}" echo "将克隆到: ${INSTALL_ROOT}"
if [[ "$(id -u)" -ne 0 ]]; then if [[ "$(id -u)" -ne 0 ]]; then
echo "错误: 请使用 root 执行" >&2 echo "错误: 请使用 root 执行" >&2
exit 1 exit 1
fi fi
ensure_git_cli ensure_git_cli
mkdir -p "$(dirname "${INSTALL_ROOT}")" mkdir -p "$(dirname "${INSTALL_ROOT}")"
git clone -b "${GIT_BRANCH}" "${GIT_URL}" "${INSTALL_ROOT}" git clone -b "${GIT_BRANCH}" "${GIT_URL}" "${INSTALL_ROOT}"
# clone 后用仓库内脚本 + 终端 stdin(管道已 EOF) # clone 后用仓库内脚本 + 终端 stdin(管道已 EOF)
exec bash "${INSTALL_ROOT}/deploy/manage.sh" "$@" </dev/tty exec bash "${INSTALL_ROOT}/deploy/manage.sh" "$@" </dev/tty
} }
show_banner() { show_banner() {
local path local path
path="${INSTALL_ROOT}" path="${INSTALL_ROOT}"
if [[ -n "${REPO_ROOT}" ]] && repo_ready "${REPO_ROOT}"; then if [[ -n "${REPO_ROOT}" ]] && repo_ready "${REPO_ROOT}"; then
path="${REPO_ROOT}" path="${REPO_ROOT}"
fi fi
echo "" echo ""
echo "╔══════════════════════════════════════╗" echo "╔══════════════════════════════════════╗"
echo "║ 比特骆驼自动化对冲系统 部署管理器 ║" echo "║ 比特骆驼自动化对冲系统 部署管理器 ║"
echo "║ 路径: ${path}" echo "║ 路径: ${path}"
echo "╚══════════════════════════════════════╝" echo "╚══════════════════════════════════════╝"
echo "" echo ""
} }
show_menu() { show_menu() {
echo " 1) 一键部署" echo " 1) 一键部署"
echo " 2) 一键卸载" echo " 2) 一键卸载"
echo " 3) 更新" echo " 3) 更新"
echo " 0) 退出" echo " 0) 退出"
echo "" echo ""
} }
# 交互读入(兼容 curl|bash # 交互读入(兼容 curl|bash
cm_read() { cm_read() {
local __var="$1" local __var="$1"
local __prompt="${2:-}" local __prompt="${2:-}"
local __line="" local __line=""
if [[ -n "${__prompt}" ]]; then if [[ -n "${__prompt}" ]]; then
printf '%s' "${__prompt}" >/dev/tty 2>/dev/null || printf '%s' "${__prompt}" printf '%s' "${__prompt}" >/dev/tty 2>/dev/null || printf '%s' "${__prompt}"
fi fi
if [[ -r /dev/tty ]]; then if [[ -r /dev/tty ]]; then
IFS= read -r __line </dev/tty || true IFS= read -r __line </dev/tty || true
else else
IFS= read -r __line || true IFS= read -r __line || true
fi fi
printf -v "${__var}" '%s' "${__line}" printf -v "${__var}" '%s' "${__line}"
} }
main_menu() { main_menu() {
bootstrap_repo bootstrap_repo
# shellcheck source=lib/common.sh # shellcheck source=lib/common.sh
source "${LIB_DIR}/common.sh" source "${LIB_DIR}/common.sh"
REPO_ROOT="$(resolve_repo_root || echo "${INSTALL_ROOT}")" REPO_ROOT="$(resolve_repo_root || echo "${INSTALL_ROOT}")"
while true; do while true; do
show_banner show_banner
show_menu show_menu
local choice="" local choice=""
cm_read choice "请选择 [0-3]: " cm_read choice "请选择 [0-3]: "
case "${choice}" in case "${choice}" in
1) 1)
bash "${LIB_DIR}/install.sh" bash "${LIB_DIR}/install.sh"
;; ;;
2) 2)
bash "${LIB_DIR}/uninstall.sh" bash "${LIB_DIR}/uninstall.sh"
;; ;;
3) 3)
bash "${LIB_DIR}/update.sh" bash "${LIB_DIR}/update.sh"
;; ;;
0) 0)
echo "再见." echo "再见."
exit 0 exit 0
;; ;;
*) *)
echo "无效选项,请输入 0-3" echo "无效选项,请输入 0-3"
;; ;;
esac esac
echo "" echo ""
cm_read _ "按 Enter 返回菜单..." cm_read _ "按 Enter 返回菜单..."
done done
} }
main_menu "$@" main_menu "$@"
+55 -55
View File
@@ -1,55 +1,55 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# 一键更新/部署:仅 git pull,禁止 scp 传代码。 # 一键更新/部署:仅 git pull,禁止 scp 传代码。
# 用法: # 用法:
# bash /opt/eth_hedge_sim/deploy/pull_and_restart.sh # bash /opt/eth_hedge_sim/deploy/pull_and_restart.sh
# 或通过 manage.sh 选 1/3 # 或通过 manage.sh 选 1/3
set -euo pipefail set -euo pipefail
ROOT="$(cd "$(dirname "$0")/.." && pwd)" ROOT="$(cd "$(dirname "$0")/.." && pwd)"
cd "$ROOT" cd "$ROOT"
echo "[比特骆驼] pull @ $ROOT" echo "[比特骆驼] pull @ $ROOT"
if [[ -d "$ROOT/.git" ]]; then if [[ -d "$ROOT/.git" ]]; then
git fetch --all --prune git fetch --all --prune
git pull --ff-only git pull --ff-only
fi fi
if [[ ! -f "$ROOT/.env" ]]; then if [[ ! -f "$ROOT/.env" ]]; then
echo "[比特骆驼] missing .env — copy from example" echo "[比特骆驼] missing .env — copy from example"
cp "$ROOT/.env.example" "$ROOT/.env" cp "$ROOT/.env.example" "$ROOT/.env"
# 云上测试机默认直连 OKX # 云上测试机默认直连 OKX
sed -i 's/^OKX_HTTP_PROXY=.*/OKX_HTTP_PROXY=/' "$ROOT/.env" || true sed -i 's/^OKX_HTTP_PROXY=.*/OKX_HTTP_PROXY=/' "$ROOT/.env" || true
sed -i 's/^API_PORT=.*/API_PORT=5155/' "$ROOT/.env" || true sed -i 's/^API_PORT=.*/API_PORT=5155/' "$ROOT/.env" || true
sed -i 's/^ENV_NAME=.*/ENV_NAME=test/' "$ROOT/.env" || true sed -i 's/^ENV_NAME=.*/ENV_NAME=test/' "$ROOT/.env" || true
sed -i 's/^EXCHANGE=.*/EXCHANGE=okx/' "$ROOT/.env" || true sed -i 's/^EXCHANGE=.*/EXCHANGE=okx/' "$ROOT/.env" || true
echo "[比特骆驼] wrote .env — please review AUTH_* secrets" echo "[比特骆驼] wrote .env — please review AUTH_* secrets"
fi fi
if [[ ! -d "$ROOT/.venv" ]]; then if [[ ! -d "$ROOT/.venv" ]]; then
python3 -m venv "$ROOT/.venv" python3 -m venv "$ROOT/.venv"
fi fi
# shellcheck disable=SC1091 # shellcheck disable=SC1091
source "$ROOT/.venv/bin/activate" source "$ROOT/.venv/bin/activate"
pip install -U pip pip install -U pip
pip install -r "$ROOT/requirements.txt" pip install -r "$ROOT/requirements.txt"
if ! command -v npm >/dev/null 2>&1; then if ! command -v npm >/dev/null 2>&1; then
echo "ERROR: npm not found. Install Node.js 18+ first (manage.sh 一键部署会自动装)." echo "ERROR: npm not found. Install Node.js 18+ first (manage.sh 一键部署会自动装)."
exit 1 exit 1
fi fi
( (
cd "$ROOT/frontend" cd "$ROOT/frontend"
if [[ -f package-lock.json ]]; then npm ci; else npm install; fi if [[ -f package-lock.json ]]; then npm ci; else npm install; fi
npm run build npm run build
) )
if ! command -v pm2 >/dev/null 2>&1; then if ! command -v pm2 >/dev/null 2>&1; then
npm install -g pm2 npm install -g pm2
fi fi
# 仅 reload 本项目进程,禁止 pm2 restart all # 仅 reload 本项目进程,禁止 pm2 restart all
pm2 startOrReload "$ROOT/deploy/ecosystem.config.cjs" --update-env pm2 startOrReload "$ROOT/deploy/ecosystem.config.cjs" --update-env
pm2 save pm2 save
echo "[比特骆驼] done. health: http://127.0.0.1:5155/health" echo "[比特骆驼] done. health: http://127.0.0.1:5155/health"