145 lines
4.4 KiB
Bash
145 lines
4.4 KiB
Bash
#!/bin/bash
|
||
|
||
# ============================================
|
||
# LinkMaster 节点端 systemd 启动脚本
|
||
# 用于 systemd 服务,直接运行二进制文件
|
||
# ============================================
|
||
|
||
set -e
|
||
|
||
# 脚本目录
|
||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||
cd "$SCRIPT_DIR"
|
||
|
||
# 配置
|
||
BINARY_NAME="agent"
|
||
BACKEND_URL="${BACKEND_URL:-http://localhost:8080}"
|
||
|
||
# 检查二进制文件是否存在且有效
|
||
check_binary() {
|
||
if [ -f "$BINARY_NAME" ] && [ -x "$BINARY_NAME" ] && [ -s "$BINARY_NAME" ]; then
|
||
# 验证二进制文件类型(Linux 应该是 ELF 文件)
|
||
if command -v file > /dev/null 2>&1; then
|
||
local file_type=$(file "$BINARY_NAME" 2>/dev/null || echo "")
|
||
if [ -n "$file_type" ] && echo "$file_type" | grep -qi "ELF"; then
|
||
return 0
|
||
fi
|
||
else
|
||
# 如果没有 file 命令,至少检查文件大小(应该大于 1MB)
|
||
local file_size=$(stat -c%s "$BINARY_NAME" 2>/dev/null || stat -f%z "$BINARY_NAME" 2>/dev/null || echo "0")
|
||
if [ "$file_size" -gt 1048576 ]; then
|
||
return 0
|
||
fi
|
||
fi
|
||
fi
|
||
return 1
|
||
}
|
||
|
||
# 拉取最新源码并编译
|
||
update_and_build() {
|
||
# 如果二进制文件已存在且有效,跳过编译
|
||
if check_binary; then
|
||
echo "二进制文件已存在,跳过编译步骤"
|
||
return 0
|
||
fi
|
||
|
||
# 检查是否在 Git 仓库中
|
||
if [ ! -d ".git" ]; then
|
||
echo "错误: 不在 Git 仓库中,无法更新代码" >&2
|
||
return 1
|
||
fi
|
||
|
||
# 配置 Git safe.directory,解决所有权问题
|
||
CURRENT_DIR=$(pwd)
|
||
git config --global --add safe.directory "$CURRENT_DIR" 2>/dev/null || true
|
||
|
||
# 拉取最新代码
|
||
if git pull 2>&1 > /dev/null; then
|
||
echo "代码更新完成"
|
||
fi
|
||
|
||
# 确保 Go 在 PATH 中(systemd 可能没有设置 PATH)
|
||
if [ -d "/usr/local/go/bin" ] && ! echo "$PATH" | grep -q "/usr/local/go/bin"; then
|
||
export PATH="/usr/local/go/bin:$PATH"
|
||
fi
|
||
|
||
# 检查 Go 环境
|
||
if ! command -v go > /dev/null 2>&1; then
|
||
echo "错误: 未找到 Go 环境,无法编译" >&2
|
||
echo "PATH: $PATH" >&2
|
||
echo "请确保 Go 已安装: /usr/local/go/bin 或系统 PATH 中包含 go 命令" >&2
|
||
exit 1
|
||
fi
|
||
|
||
# 检查是否有 vendor 目录
|
||
local use_vendor=false
|
||
if [ -d "./vendor" ] && [ -f "./vendor/modules.txt" ]; then
|
||
use_vendor=true
|
||
echo "使用 vendor 目录编译(无需网络连接)"
|
||
fi
|
||
|
||
# 更新依赖(仅在非 vendor 模式下,并设置超时避免卡住)
|
||
if [ "$use_vendor" != "true" ]; then
|
||
echo "更新 Go 依赖..."
|
||
# 使用 timeout 命令设置超时(30秒),如果系统没有 timeout 命令则直接执行
|
||
if command -v timeout > /dev/null 2>&1; then
|
||
timeout 30 go mod download 2>&1 > /dev/null || {
|
||
echo "警告: 依赖更新失败或超时,尝试继续编译" >&2
|
||
}
|
||
else
|
||
# 如果没有 timeout 命令,直接执行(可能卡住,但至少能工作)
|
||
go mod download 2>&1 > /dev/null || {
|
||
echo "警告: 依赖更新失败,尝试继续编译" >&2
|
||
}
|
||
fi
|
||
fi
|
||
|
||
# 编译
|
||
ARCH=$(uname -m)
|
||
case $ARCH in
|
||
x86_64)
|
||
ARCH="amd64"
|
||
;;
|
||
aarch64|arm64)
|
||
ARCH="arm64"
|
||
;;
|
||
*)
|
||
ARCH="amd64"
|
||
;;
|
||
esac
|
||
|
||
# 构建编译命令
|
||
local build_cmd="GOOS=linux GOARCH=${ARCH} CGO_ENABLED=0 go build -buildvcs=false -ldflags=\"-w -s\""
|
||
if [ "$use_vendor" = "true" ]; then
|
||
build_cmd="$build_cmd -mod=vendor"
|
||
fi
|
||
build_cmd="$build_cmd -o \"$BINARY_NAME\" ./cmd/agent"
|
||
|
||
echo "开始编译(架构: ${ARCH})..."
|
||
if eval "$build_cmd" 2>&1; then
|
||
if [ -f "$BINARY_NAME" ] && [ -s "$BINARY_NAME" ]; then
|
||
chmod +x "$BINARY_NAME"
|
||
echo "编译成功"
|
||
return 0
|
||
else
|
||
echo "错误: 编译失败,未生成二进制文件" >&2
|
||
return 1
|
||
fi
|
||
else
|
||
echo "错误: 编译失败" >&2
|
||
return 1
|
||
fi
|
||
}
|
||
|
||
# 检查并更新/编译
|
||
if ! check_binary; then
|
||
update_and_build
|
||
fi
|
||
|
||
# 设置环境变量
|
||
export BACKEND_URL="$BACKEND_URL"
|
||
|
||
# 直接运行二进制文件(systemd 会管理进程)
|
||
exec ./"$BINARY_NAME"
|
||
|