This commit is contained in:
2025-12-03 20:05:47 +08:00
parent 16ec3295ce
commit 26595e4e2f
3 changed files with 246 additions and 527 deletions

2
.gitignore vendored
View File

@@ -1 +1 @@
test.log
.DS_Store

View File

@@ -434,18 +434,8 @@ install_go_from_official() {
echo 'export PATH=$PATH:/usr/local/go/bin' | sudo tee -a /etc/profile > /dev/null
fi
# 配置 Go 代理(使用国内镜像)
if ! grep -q "GOPROXY" /etc/profile 2>/dev/null; then
echo '' | sudo tee -a /etc/profile > /dev/null
echo '# Go 代理配置(使用国内镜像加速)' | sudo tee -a /etc/profile > /dev/null
echo 'export GOPROXY=https://goproxy.cn,direct' | sudo tee -a /etc/profile > /dev/null
echo 'export GOSUMDB=off' | sudo tee -a /etc/profile > /dev/null
fi
# 设置当前会话的 PATH 和 GOPROXY
# 设置当前会话的 PATH
export PATH=$PATH:/usr/local/go/bin
export GOPROXY=https://goproxy.cn,direct
export GOSUMDB=off
# 验证安装
if command -v go > /dev/null 2>&1; then
@@ -477,17 +467,6 @@ install_go() {
# 检查 Go 版本是否可用(尝试运行 go version
if go version > /dev/null 2>&1; then
echo -e "${BLUE}Go 环境正常,跳过安装流程${NC}"
# 确保 GOPROXY 已配置(如果未配置则添加)
if ! grep -q "GOPROXY" /etc/profile 2>/dev/null; then
echo -e "${BLUE}配置 Go 代理环境变量...${NC}"
echo '' | sudo tee -a /etc/profile > /dev/null
echo '# Go 代理配置(使用国内镜像加速)' | sudo tee -a /etc/profile > /dev/null
echo 'export GOPROXY=https://goproxy.cn,direct' | sudo tee -a /etc/profile > /dev/null
echo 'export GOSUMDB=off' | sudo tee -a /etc/profile > /dev/null
fi
# 设置当前会话的环境变量
export GOPROXY=${GOPROXY:-https://goproxy.cn,direct}
export GOSUMDB=${GOSUMDB:-off}
return 0
else
echo -e "${YELLOW}⚠ Go 已安装但无法正常运行,尝试重新安装...${NC}"
@@ -529,19 +508,6 @@ install_go() {
if [ "$install_success" = true ] && command -v go > /dev/null 2>&1; then
GO_VERSION=$(go version 2>/dev/null | head -1)
echo -e "${GREEN}✓ Go 安装完成: ${GO_VERSION}${NC}"
# 配置 Go 代理(使用国内镜像)
if ! grep -q "GOPROXY" /etc/profile 2>/dev/null; then
echo '' | sudo tee -a /etc/profile > /dev/null
echo '# Go 代理配置(使用国内镜像加速)' | sudo tee -a /etc/profile > /dev/null
echo 'export GOPROXY=https://goproxy.cn,direct' | sudo tee -a /etc/profile > /dev/null
echo 'export GOSUMDB=off' | sudo tee -a /etc/profile > /dev/null
fi
# 设置当前会话的 GOPROXY
export GOPROXY=https://goproxy.cn,direct
export GOSUMDB=off
return 0
fi
@@ -712,511 +678,44 @@ build_from_source() {
sudo git config --global --add safe.directory "$SOURCE_DIR" 2>/dev/null || true
git config --global --add safe.directory "$SOURCE_DIR" 2>/dev/null || true
# 配置 Git 使用代理(加速 GitHub 访问
echo -e "${BLUE}配置 Git 代理(加速 GitHub 访问)...${NC}"
# GitHub 代理镜像列表(按优先级排序)
GITHUB_PROXIES=(
"https://gh-proxy.com"
"https://githubproxy.cc"
"https://ghproxy.com"
"https://mirror.ghproxy.com"
"https://github.com.cnpmjs.org"
)
# 测试并选择可用的 GitHub 代理
GITHUB_PROXY=""
for proxy in "${GITHUB_PROXIES[@]}"; do
echo -n " 测试 ${proxy}... "
# 测试代理是否可用(尝试访问 GitHub 主页)
if curl -sf --connect-timeout 3 --max-time 5 "${proxy}/https://github.com" > /dev/null 2>&1 || \
curl -sf --connect-timeout 3 --max-time 5 "${proxy}" > /dev/null 2>&1; then
GITHUB_PROXY="$proxy"
echo -e "${GREEN}可用${NC}"
break
else
echo -e "${RED}不可用${NC}"
fi
done
if [ -n "$GITHUB_PROXY" ]; then
# 配置 Git 使用代理
echo -e "${GREEN}✓ 使用 GitHub 代理: ${GITHUB_PROXY}${NC}"
# 根据不同的代理服务配置不同的 URL 格式
if echo "$GITHUB_PROXY" | grep -q "gh-proxy.com\|githubproxy.cc"; then
# gh-proxy.com 和 githubproxy.cc 使用 /https://github.com/ 格式
GIT_PROXY_URL="${GITHUB_PROXY}/https://github.com/"
sudo git config --global url."${GIT_PROXY_URL}".insteadOf "https://github.com/" 2>/dev/null || true
git config --global url."${GIT_PROXY_URL}".insteadOf "https://github.com/" 2>/dev/null || true
# 配置 Git HTTP/HTTPS 代理
sudo git config --global http.https://github.com.proxy "${GITHUB_PROXY}/" 2>/dev/null || true
git config --global http.https://github.com.proxy "${GITHUB_PROXY}/" 2>/dev/null || true
else
# 其他代理使用标准格式
sudo git config --global url."${GITHUB_PROXY}/https://github.com/".insteadOf "https://github.com/" 2>/dev/null || true
git config --global url."${GITHUB_PROXY}/https://github.com/".insteadOf "https://github.com/" 2>/dev/null || true
sudo git config --global http.https://github.com.proxy "${GITHUB_PROXY}/" 2>/dev/null || true
git config --global http.https://github.com.proxy "${GITHUB_PROXY}/" 2>/dev/null || true
# 检查 vendor 目录是否存在(必须存在
echo -e "${BLUE}检查 vendor 目录...${NC}"
if [ ! -d "$SOURCE_DIR/vendor" ] || [ ! -f "$SOURCE_DIR/vendor/modules.txt" ]; then
echo -e "${RED}错误: vendor 目录不存在或无效${NC}"
echo -e "${RED}请确保项目包含 vendor 目录,或先运行 ./vendor.sh 创建 vendor 目录${NC}"
echo -e "${YELLOW}vendor 目录路径: ${SOURCE_DIR}/vendor${NC}"
exit 1
fi
# 设置环境变量(供 Go 使用)
export HTTP_PROXY="${GITHUB_PROXY}/"
export HTTPS_PROXY="${GITHUB_PROXY}/"
export http_proxy="${GITHUB_PROXY}/"
export https_proxy="${GITHUB_PROXY}/"
# vendor 目录存在,显示信息
VENDOR_COUNT=$(find "$SOURCE_DIR/vendor" -type d -mindepth 2 2>/dev/null | wc -l | tr -d '\n' || echo "0")
VENDOR_COUNT=${VENDOR_COUNT:-0}
echo -e "${GREEN}✓ vendor 目录存在${NC}"
echo -e "${BLUE}vendor 目录包含 ${GREEN}${VENDOR_COUNT}${NC} 个依赖包"
echo -e "${BLUE}编译时将使用 -mod=vendor 标志,无需网络连接${NC}"
# 配置 Git 重写 golang.org 和 google.golang.org 的 URL通过 GitHub 代理)
# golang.org/x/* 包在 GitHub 上的镜像路径是 github.com/golang/x-*
# 例如golang.org/x/net -> github.com/golang/net
sudo git config --global url."${GITHUB_PROXY}/https://github.com/golang/".insteadOf "https://golang.org/x/" 2>/dev/null || true
git config --global url."${GITHUB_PROXY}/https://github.com/golang/".insteadOf "https://golang.org/x/" 2>/dev/null || true
# google.golang.org 也可以通过 GitHub 代理
# 例如google.golang.org/protobuf -> github.com/protocolbuffers/protobuf-go
sudo git config --global url."${GITHUB_PROXY}/https://github.com/protocolbuffers/".insteadOf "https://google.golang.org/protobuf" 2>/dev/null || true
git config --global url."${GITHUB_PROXY}/https://github.com/protocolbuffers/".insteadOf "https://google.golang.org/protobuf" 2>/dev/null || true
# 设置环境变量,让 Go 通过代理访问这些域名
# 注意:这需要 Go 支持 HTTP_PROXY我们已经设置了
# 添加到 Go 环境变量中
GO_ENV="$GO_ENV HTTP_PROXY=${GITHUB_PROXY}/ HTTPS_PROXY=${GITHUB_PROXY}/ http_proxy=${GITHUB_PROXY}/ https_proxy=${GITHUB_PROXY}/"
echo -e "${BLUE}已配置 golang.org 和 google.golang.org 通过 GitHub 代理访问${NC}"
echo -e "${BLUE}已配置 Git 和 Go 使用 GitHub 代理加速${NC}"
else
echo -e "${YELLOW}⚠ 未找到可用的 GitHub 代理,将直接访问 GitHub${NC}"
echo -e "${YELLOW}提示: 如果 GitHub 访问慢,可以手动设置代理${NC}"
fi
# 配置 Go 代理(使用国内镜像)
echo -e "${BLUE}配置 Go 代理(使用国内镜像加速)...${NC}"
# Go 代理镜像列表(按优先级排序,使用多个镜像以提高成功率)
# 注意:不包含 proxy.golang.org因为在中国大陆无法访问
GO_PROXY_MIRRORS=(
"https://goproxy.cn,https://goproxy.io,https://mirrors.aliyun.com/go-proxy/,direct"
"https://goproxy.io,https://goproxy.cn,https://mirrors.aliyun.com/go-proxy/,direct"
"https://mirrors.aliyun.com/go-proxy/,https://goproxy.cn,https://goproxy.io,direct"
)
# 测试并选择最快的 Go 代理(使用多个镜像作为备选)
GO_PROXY=""
for proxy_list in "${GO_PROXY_MIRRORS[@]}"; do
# 取第一个镜像进行测试
first_proxy=$(echo "$proxy_list" | cut -d',' -f1)
echo -n " 测试代理链: ${first_proxy}... "
# 使用 Go 代理的特定端点进行测试(访问一个已知的模块信息)
# goproxy.cn 等代理服务需要访问 /{module}/@v/list 这样的端点
# 这里测试访问 goproxy.cn 的根路径或使用 go env 测试
TEST_URL="${first_proxy}"
# 尝试多种测试方法
PROXY_AVAILABLE=false
# 方法1: 直接访问根路径
if curl -sf --connect-timeout 3 --max-time 5 "${TEST_URL}" > /dev/null 2>&1; then
PROXY_AVAILABLE=true
# 方法2: 访问 goproxy.cn 的统计页面(如果存在)
elif curl -sf --connect-timeout 3 --max-time 5 "${TEST_URL}/statistics" > /dev/null 2>&1; then
PROXY_AVAILABLE=true
# 方法3: 使用 go env 测试(如果 Go 已安装)
elif command -v go > /dev/null 2>&1; then
# 临时设置 GOPROXY 并测试
if GOPROXY="${first_proxy},direct" go env GOPROXY > /dev/null 2>&1; then
PROXY_AVAILABLE=true
fi
# 方法4: 尝试访问一个已知模块的列表端点
elif curl -sf --connect-timeout 3 --max-time 5 "${TEST_URL}/github.com/gin-gonic/gin/@v/list" > /dev/null 2>&1; then
PROXY_AVAILABLE=true
fi
if [ "$PROXY_AVAILABLE" = true ]; then
GO_PROXY="$proxy_list"
echo -e "${GREEN}可用${NC}"
break
else
echo -e "${RED}不可用${NC}"
fi
done
# 如果所有镜像都不可用,使用 direct 模式(直接从源码仓库下载)
if [ -z "$GO_PROXY" ]; then
GO_PROXY="direct"
echo -e "${YELLOW}⚠ 所有国内镜像不可用,使用 direct 模式(直接从 GitHub/GitLab 等下载)${NC}"
echo -e "${YELLOW}⚠ 注意: direct 模式可能较慢,建议检查网络连接${NC}"
else
echo -e "${GREEN}✓ 使用 Go 代理链: ${GO_PROXY}${NC}"
echo -e "${BLUE}说明: Go 会按顺序尝试代理列表中的镜像,最后使用 direct 模式${NC}"
echo -e "${BLUE}注意: 已禁用 GOSUMDB避免连接 proxy.golang.org${NC}"
fi
# 下载依赖(使用 sudo 以 root 用户执行,确保 PATH 包含 Go并设置 GOPROXY
echo -e "${BLUE}下载 Go 依赖...${NC}"
echo -e "${BLUE}使用代理: ${GO_PROXY}${NC}"
# 构建包含 Go PATH 和 GOPROXY 的环境变量
# 构建包含 Go PATH 的环境变量
GO_PATH_ENV="PATH=\$PATH:/usr/local/go/bin"
if [ -d "/usr/local/go/bin" ]; then
GO_PATH_ENV="PATH=/usr/local/go/bin:\$PATH"
fi
# 禁用 GOSUMDB 以避免连接 proxy.golang.org在中国大陆通常无法访问
# 如果必须启用校验和,可以使用 GOSUMDB=sum.golang.google.cn但可能仍有问题
# 如果配置了 GitHub 代理,添加到环境变量中
if [ -n "$GITHUB_PROXY" ]; then
GO_ENV="$GO_PATH_ENV GOPROXY=${GO_PROXY} GOSUMDB=off GOTIMEOUT=60 GONOPROXY= GONOSUMDB= GOPRIVATE=* HTTP_PROXY=${GITHUB_PROXY}/ HTTPS_PROXY=${GITHUB_PROXY}/ http_proxy=${GITHUB_PROXY}/ https_proxy=${GITHUB_PROXY}/"
else
GO_ENV="$GO_PATH_ENV GOPROXY=${GO_PROXY} GOSUMDB=off GOTIMEOUT=60 GONOPROXY= GONOSUMDB= GOPRIVATE=*"
fi
# 使用 go env -w 永久设置环境变量(避免被其他配置覆盖)
echo -e "${BLUE}永久设置 Go 环境变量(避免连接 proxy.golang.org...${NC}"
sudo bash -c "cd '$SOURCE_DIR' && $GO_PATH_ENV && go env -w GOPROXY=${GO_PROXY}" 2>/dev/null || true
sudo bash -c "cd '$SOURCE_DIR' && $GO_PATH_ENV && go env -w GOSUMDB=off" 2>/dev/null || true
sudo bash -c "cd '$SOURCE_DIR' && $GO_PATH_ENV && go env -w GOPRIVATE=*" 2>/dev/null || true
# 显示当前 Go 环境信息(验证设置是否生效)
echo -e "${BLUE}Go 环境信息:${NC}"
echo -e "${BLUE} 设置的 GOPROXY=${GO_PROXY}${NC}"
echo -e "${BLUE} 设置的 GOSUMDB=off (已禁用,避免连接 proxy.golang.org)${NC}"
echo -e "${BLUE} 实际生效的环境变量:${NC}"
sudo bash -c "cd '$SOURCE_DIR' && $GO_ENV && go env GOPROXY GOSUMDB GOPRIVATE" || true
echo ""
# 验证是否仍然会连接 proxy.golang.org
ACTUAL_GOPROXY=$(sudo bash -c "cd '$SOURCE_DIR' && $GO_ENV && go env GOPROXY" 2>/dev/null || echo "")
if echo "$ACTUAL_GOPROXY" | grep -q "proxy.golang.org"; then
echo -e "${RED}⚠ 警告: 检测到 GOPROXY 仍包含 proxy.golang.org${NC}"
echo -e "${YELLOW}正在强制移除 proxy.golang.org...${NC}"
CLEAN_PROXY=$(echo "$ACTUAL_GOPROXY" | sed 's|https://proxy.golang.org,||g' | sed 's|,https://proxy.golang.org||g' | sed 's|https://proxy.golang.org||g')
GO_PROXY="$CLEAN_PROXY"
GO_ENV="$GO_PATH_ENV GOPROXY=${GO_PROXY} GOSUMDB=off GOTIMEOUT=60 GONOPROXY= GONOSUMDB= GOPRIVATE=*"
sudo bash -c "cd '$SOURCE_DIR' && $GO_PATH_ENV && go env -w GOPROXY=${GO_PROXY}" 2>/dev/null || true
echo -e "${GREEN}✓ 已更新 GOPROXY: ${GO_PROXY}${NC}"
fi
# 先尝试整理依赖(显示详细信息)
echo -e "${BLUE}整理 Go 模块依赖...${NC}"
# 再次确认环境变量(防止被覆盖)
sudo bash -c "cd '$SOURCE_DIR' && $GO_PATH_ENV && go env -w GOPROXY=${GO_PROXY}" 2>/dev/null || true
sudo bash -c "cd '$SOURCE_DIR' && $GO_PATH_ENV && go env -w GOSUMDB=off" 2>/dev/null || true
sudo bash -c "cd '$SOURCE_DIR' && $GO_PATH_ENV && go env -w GOPRIVATE=*" 2>/dev/null || true
if ! sudo bash -c "cd '$SOURCE_DIR' && $GO_ENV && go mod tidy -v" 2>&1; then
echo -e "${YELLOW}⚠ go mod tidy 失败,继续尝试下载依赖...${NC}"
# 检查错误日志中是否包含 proxy.golang.org
TIDY_LOG=$(sudo bash -c "cd '$SOURCE_DIR' && $GO_ENV && go mod tidy -v" 2>&1 || true)
if echo "$TIDY_LOG" | grep -q "proxy.golang.org"; then
echo -e "${RED}错误: 检测到仍尝试连接 proxy.golang.org${NC}"
echo -e "${YELLOW}尝试清理 Go 模块缓存并重新设置...${NC}"
sudo bash -c "cd '$SOURCE_DIR' && $GO_PATH_ENV && go clean -modcache" 2>/dev/null || true
sudo bash -c "cd '$SOURCE_DIR' && $GO_PATH_ENV && go env -w GOPROXY=${GO_PROXY}" 2>/dev/null || true
sudo bash -c "cd '$SOURCE_DIR' && $GO_PATH_ENV && go env -w GOSUMDB=off" 2>/dev/null || true
sudo bash -c "cd '$SOURCE_DIR' && $GO_PATH_ENV && go env -w GOPRIVATE=*" 2>/dev/null || true
fi
fi
# 下载依赖(显示详细进度和速度)
echo -e "${BLUE}开始下载 Go 依赖包(这可能需要一些时间)...${NC}"
echo -e "${YELLOW}提示: 如果下载速度慢,请检查网络连接和代理设置${NC}"
echo ""
# 设置更长的超时时间和启用详细输出
DOWNLOAD_START_TIME=$(date +%s)
DOWNLOAD_LOG="/tmp/go_download_$$.log"
DOWNLOAD_PROGRESS_LOG="/tmp/go_progress_$$.log"
# 在下载前再次确认环境变量设置(强制所有包都通过代理)
sudo bash -c "cd '$SOURCE_DIR' && $GO_PATH_ENV && go env -w GOPROXY=${GO_PROXY}" 2>/dev/null || true
sudo bash -c "cd '$SOURCE_DIR' && $GO_PATH_ENV && go env -w GOSUMDB=off" 2>/dev/null || true
sudo bash -c "cd '$SOURCE_DIR' && $GO_PATH_ENV && go env -w GONOPROXY=" 2>/dev/null || true
sudo bash -c "cd '$SOURCE_DIR' && $GO_PATH_ENV && go env -w GONOSUMDB=" 2>/dev/null || true
sudo bash -c "cd '$SOURCE_DIR' && $GO_PATH_ENV && go env -w GOPRIVATE=*" 2>/dev/null || true
sudo bash -c "cd '$SOURCE_DIR' && $GO_PATH_ENV && go env -w GOTIMEOUT=60" 2>/dev/null || true
# 使用命名管道来实时监控输出
PIPE_FILE="/tmp/go_download_pipe_$$"
mkfifo "$PIPE_FILE" 2>/dev/null || true
# 后台进程显示实时进度
(
DOWNLOADED_COUNT=0
LAST_COUNT=0
LAST_PACKAGE=""
PACKAGES=()
# 从管道读取输出并实时显示
while IFS= read -r line || [ -n "$line" ]; do
# 检查是否结束
if [ -f "${DOWNLOAD_PROGRESS_LOG}.done" ]; then
break
fi
# 检测下载消息
if echo "$line" | grep -q "go: downloading"; then
DOWNLOADED_COUNT=$((DOWNLOADED_COUNT + 1))
CURRENT_TIME=$(date +%s)
ELAPSED=$((CURRENT_TIME - DOWNLOAD_START_TIME))
# 提取包名
PACKAGE_NAME=$(echo "$line" | sed 's/go: downloading //' | cut -d' ' -f1)
if [ -n "$PACKAGE_NAME" ] && [ "$PACKAGE_NAME" != "$LAST_PACKAGE" ]; then
PACKAGES+=("$PACKAGE_NAME")
LAST_PACKAGE=$PACKAGE_NAME
# 计算速度
if [ "$ELAPSED" -gt 0 ]; then
SPEED=$(echo "scale=2; $DOWNLOADED_COUNT / $ELAPSED" | bc 2>/dev/null || echo "0")
else
SPEED="0"
fi
# 显示进度(使用 \r 在同一行更新)
echo -ne "\r${BLUE}进度: 已下载 ${GREEN}${DOWNLOADED_COUNT}${NC} 个包 | 耗时: ${ELAPSED}秒 | 速度: ${GREEN}${SPEED}${NC} 包/秒 | 当前: ${GREEN}${PACKAGE_NAME}${NC} "
fi
fi
done < "$PIPE_FILE" &
# 等待主进程结束
while [ ! -f "${DOWNLOAD_PROGRESS_LOG}.done" ]; do
sleep 0.5
done
) &
PROGRESS_PID=$!
# 使用 -x 标志下载,显示详细输出,同时写入日志和管道
# 设置较短的超时时间,避免长时间卡住
echo -e "${BLUE}开始下载超时时间300秒...${NC}"
# 确保环境变量中包含代理设置
if [ -n "$GITHUB_PROXY" ]; then
GO_ENV="$GO_ENV HTTP_PROXY=${GITHUB_PROXY}/ HTTPS_PROXY=${GITHUB_PROXY}/ http_proxy=${GITHUB_PROXY}/ https_proxy=${GITHUB_PROXY}/"
fi
# 使用 timeout 命令设置总超时时间
if timeout 300 sudo bash -c "cd '$SOURCE_DIR' && $GO_ENV && go mod download -x" 2>&1 | tee "$DOWNLOAD_LOG" "$PIPE_FILE"; then
# 停止进度显示进程
touch "${DOWNLOAD_PROGRESS_LOG}.done"
sleep 2
kill "$PROGRESS_PID" 2>/dev/null || true
wait "$PROGRESS_PID" 2>/dev/null || true
# 清理管道文件
rm -f "$PIPE_FILE" 2>/dev/null || true
DOWNLOAD_END_TIME=$(date +%s)
DOWNLOAD_DURATION=$((DOWNLOAD_END_TIME - DOWNLOAD_START_TIME))
# 统计下载信息(从输出中统计,去除换行符)
TOTAL_PACKAGES=$(grep -c "go: downloading" "$DOWNLOAD_LOG" 2>/dev/null | tr -d '\n' || echo "0")
SUCCESS_COUNT=$(grep -c "go: downloading" "$DOWNLOAD_LOG" 2>/dev/null | tr -d '\n' || echo "0")
# 确保是数字
TOTAL_PACKAGES=${TOTAL_PACKAGES:-0}
SUCCESS_COUNT=${SUCCESS_COUNT:-0}
echo ""
echo -e "${GREEN}✓ 依赖下载完成${NC}"
echo -e "${BLUE}下载统计:${NC}"
echo -e " 总包数: ${GREEN}${TOTAL_PACKAGES}${NC}"
echo -e " 成功下载: ${GREEN}${SUCCESS_COUNT}${NC}"
echo -e " 总耗时: ${GREEN}${DOWNLOAD_DURATION}${NC}"
if [ "$DOWNLOAD_DURATION" -gt 0 ] && [ "$SUCCESS_COUNT" -gt 0 ] 2>/dev/null; then
AVG_SPEED=$(echo "scale=2; $SUCCESS_COUNT / $DOWNLOAD_DURATION" | bc 2>/dev/null || echo "0")
echo -e " 平均速度: ${GREEN}${AVG_SPEED}${NC} 包/秒"
fi
# 显示最后下载的几个包
echo -e "${BLUE}最后下载的包:${NC}"
grep "go: downloading" "$DOWNLOAD_LOG" 2>/dev/null | tail -10 | sed 's/go: downloading \([^ ]*\).*/ ✓ \1/' | while IFS= read -r line; do
echo "$line"
done || true
else
# 停止进度显示进程
touch "${DOWNLOAD_PROGRESS_LOG}.done"
sleep 2
kill "$PROGRESS_PID" 2>/dev/null || true
wait "$PROGRESS_PID" 2>/dev/null || true
# 清理管道文件
rm -f "$PIPE_FILE" 2>/dev/null || true
DOWNLOAD_EXIT_CODE=${DOWNLOAD_EXIT_CODE:-$?}
DOWNLOAD_END_TIME=$(date +%s)
DOWNLOAD_DURATION=$((DOWNLOAD_END_TIME - DOWNLOAD_START_TIME))
# 统计已下载的包(去除换行符)
DOWNLOADED_COUNT=$(grep -c "go: downloading" "$DOWNLOAD_LOG" 2>/dev/null | tr -d '\n' || echo "0")
DOWNLOADED_COUNT=${DOWNLOADED_COUNT:-0}
if [ "$DOWNLOAD_EXIT_CODE" = "124" ]; then
echo ""
echo -e "${YELLOW}⚠ 下载超时 (${DOWNLOAD_DURATION}秒)${NC}"
echo -e "${BLUE}已下载: ${GREEN}${DOWNLOADED_COUNT}${NC} 个包"
echo -e "${YELLOW}继续尝试编译,如果失败请检查网络连接${NC}"
else
echo ""
echo -e "${YELLOW}⚠ 使用国内镜像下载失败 (耗时: ${DOWNLOAD_DURATION}秒,退出码: ${DOWNLOAD_EXIT_CODE})${NC}"
echo -e "${BLUE}已下载: ${GREEN}${DOWNLOADED_COUNT}${NC} 个包"
echo -e "${YELLOW}最后30行日志:${NC}"
tail -30 "$DOWNLOAD_LOG" 2>/dev/null || true
echo ""
echo -e "${YELLOW}尝试使用 direct 模式(直接从 GitHub/GitLab 等下载)...${NC}"
# 如果失败,尝试使用 direct 模式,直接从源码仓库下载
# 注意:不使用 proxy.golang.org因为在中国大陆无法访问
GO_ENV="$GO_PATH_ENV GOPROXY=direct GOSUMDB=off GOTIMEOUT=60 GONOPROXY= GONOSUMDB= GOPRIVATE=*"
# 如果配置了 GitHub 代理,添加到环境变量
if [ -n "$GITHUB_PROXY" ]; then
GO_ENV="$GO_ENV HTTP_PROXY=${GITHUB_PROXY}/ HTTPS_PROXY=${GITHUB_PROXY}/ http_proxy=${GITHUB_PROXY}/ https_proxy=${GITHUB_PROXY}/"
fi
# 重新设置环境变量
sudo bash -c "cd '$SOURCE_DIR' && $GO_PATH_ENV && go env -w GOPROXY=direct" 2>/dev/null || true
sudo bash -c "cd '$SOURCE_DIR' && $GO_PATH_ENV && go env -w GOSUMDB=off" 2>/dev/null || true
sudo bash -c "cd '$SOURCE_DIR' && $GO_PATH_ENV && go env -w GONOPROXY=" 2>/dev/null || true
sudo bash -c "cd '$SOURCE_DIR' && $GO_PATH_ENV && go env -w GONOSUMDB=" 2>/dev/null || true
sudo bash -c "cd '$SOURCE_DIR' && $GO_PATH_ENV && go env -w GOPRIVATE=*" 2>/dev/null || true
sudo bash -c "cd '$SOURCE_DIR' && $GO_PATH_ENV && go env -w GOTIMEOUT=60" 2>/dev/null || true
# 重新启动进度显示
(
DOWNLOADED_COUNT=0
LAST_UPDATE_TIME=$(date +%s)
LAST_COUNT=0
while [ ! -f "$DOWNLOAD_PROGRESS_LOG.done2" ]; do
sleep 1
CURRENT_COUNT=$(grep -c "go: downloading" "$DOWNLOAD_LOG" 2>/dev/null || echo "0")
if [ "$CURRENT_COUNT" -gt "$LAST_COUNT" ]; then
DOWNLOADED_COUNT=$CURRENT_COUNT
CURRENT_TIME=$(date +%s)
ELAPSED=$((CURRENT_TIME - DOWNLOAD_START_TIME))
if [ "$ELAPSED" -gt 0 ]; then
SPEED=$(echo "scale=2; $DOWNLOADED_COUNT / $ELAPSED" | bc 2>/dev/null || echo "0")
echo -ne "\r${BLUE}进度: 已下载 ${GREEN}${DOWNLOADED_COUNT}${NC} 个包 | 耗时: ${ELAPSED}秒 | 速度: ${GREEN}${SPEED}${NC} 包/秒"
fi
LAST_COUNT=$CURRENT_COUNT
fi
CURRENT_PACKAGE=$(grep "go: downloading" "$DOWNLOAD_LOG" | tail -1 | sed 's/go: downloading //' | cut -d' ' -f1)
if [ -n "$CURRENT_PACKAGE" ] && [ "$CURRENT_PACKAGE" != "$LAST_PACKAGE" ]; then
echo ""
echo -e "${BLUE} → 正在下载: ${GREEN}${CURRENT_PACKAGE}${NC}"
LAST_PACKAGE=$CURRENT_PACKAGE
fi
done
) &
PROGRESS_PID2=$!
# 重新创建管道
rm -f "$PIPE_FILE" 2>/dev/null || true
mkfifo "$PIPE_FILE" 2>/dev/null || true
# 重新启动进度显示
(
DOWNLOADED_COUNT=0
LAST_COUNT=0
LAST_PACKAGE=""
while IFS= read -r line || [ -n "$line" ]; do
if [ -f "${DOWNLOAD_PROGRESS_LOG}.done2" ]; then
break
fi
if echo "$line" | grep -q "go: downloading"; then
DOWNLOADED_COUNT=$((DOWNLOADED_COUNT + 1))
CURRENT_TIME=$(date +%s)
ELAPSED=$((CURRENT_TIME - DOWNLOAD_START_TIME))
PACKAGE_NAME=$(echo "$line" | sed 's/go: downloading //' | cut -d' ' -f1)
if [ -n "$PACKAGE_NAME" ] && [ "$PACKAGE_NAME" != "$LAST_PACKAGE" ]; then
LAST_PACKAGE=$PACKAGE_NAME
if [ "$ELAPSED" -gt 0 ]; then
SPEED=$(echo "scale=2; $DOWNLOADED_COUNT / $ELAPSED" | bc 2>/dev/null || echo "0")
else
SPEED="0"
fi
echo -ne "\r${BLUE}进度: 已下载 ${GREEN}${DOWNLOADED_COUNT}${NC} 个包 | 耗时: ${ELAPSED}秒 | 速度: ${GREEN}${SPEED}${NC} 包/秒 | 当前: ${GREEN}${PACKAGE_NAME}${NC} "
fi
fi
done < "$PIPE_FILE" &
while [ ! -f "${DOWNLOAD_PROGRESS_LOG}.done2" ]; do
sleep 0.5
done
) &
PROGRESS_PID2=$!
DOWNLOAD_START_TIME=$(date +%s)
if sudo bash -c "cd '$SOURCE_DIR' && $GO_ENV && timeout 600 go mod download -x" 2>&1 | tee "$DOWNLOAD_LOG" "$PIPE_FILE"; then
# 停止进度显示进程
touch "${DOWNLOAD_PROGRESS_LOG}.done2"
sleep 2
kill "$PROGRESS_PID2" 2>/dev/null || true
wait "$PROGRESS_PID2" 2>/dev/null || true
rm -f "$PIPE_FILE" 2>/dev/null || true
DOWNLOAD_END_TIME=$(date +%s)
DOWNLOAD_DURATION=$((DOWNLOAD_END_TIME - DOWNLOAD_START_TIME))
# 统计下载信息(去除换行符)
TOTAL_PACKAGES=$(grep -c '"Path":' "$DOWNLOAD_LOG" 2>/dev/null | tr -d '\n' || echo "0")
SUCCESS_COUNT=$(grep -c '"Version":' "$DOWNLOAD_LOG" 2>/dev/null | tr -d '\n' || echo "0")
# 如果没有 JSON 格式,尝试从普通输出统计
if [ "$TOTAL_PACKAGES" = "0" ] || [ -z "$TOTAL_PACKAGES" ]; then
TOTAL_PACKAGES=$(grep -c "go: downloading" "$DOWNLOAD_LOG" 2>/dev/null | tr -d '\n' || echo "0")
SUCCESS_COUNT=$TOTAL_PACKAGES
fi
# 确保是数字
TOTAL_PACKAGES=${TOTAL_PACKAGES:-0}
SUCCESS_COUNT=${SUCCESS_COUNT:-0}
echo ""
echo -e "${GREEN}✓ 依赖下载完成${NC}"
echo -e "${BLUE}下载统计:${NC}"
echo -e " 总包数: ${GREEN}${TOTAL_PACKAGES}${NC}"
echo -e " 成功下载: ${GREEN}${SUCCESS_COUNT}${NC}"
echo -e " 总耗时: ${GREEN}${DOWNLOAD_DURATION}${NC}"
if [ "$DOWNLOAD_DURATION" -gt 0 ] && [ "$SUCCESS_COUNT" -gt 0 ] 2>/dev/null; then
AVG_SPEED=$(echo "scale=2; $SUCCESS_COUNT / $DOWNLOAD_DURATION" | bc 2>/dev/null || echo "0")
echo -e " 平均速度: ${GREEN}${AVG_SPEED}${NC} 包/秒"
fi
else
echo -e "${RED}下载依赖失败最后100行日志:${NC}"
tail -100 "$DOWNLOAD_LOG" 2>/dev/null || true
rm -f "$DOWNLOAD_LOG"
show_build_alternatives
exit 1
fi
fi
fi
rm -f "$DOWNLOAD_LOG" 2>/dev/null || true
# 设置 Go 环境变量(仅包含 PATH不使用代理
GO_ENV="$GO_PATH_ENV"
# 编译到临时文件(在用户有权限的目录),然后移动到目标位置
echo -e "${BLUE}编译二进制文件...${NC}"
TEMP_BINARY=$(mktemp)
BINARY_PATH="$SOURCE_DIR/agent"
# 使用 sudo 以 root 用户编译,直接输出到目标位置,确保 PATH 包含 Go并设置 GOPROXY
# 使用 sudo 以 root 用户编译,直接输出到目标位置,强制使用 vendor
echo -e "${BLUE}开始编译(架构: ${ARCH}...${NC}"
if sudo bash -c "cd '$SOURCE_DIR' && $GO_ENV && GOOS=linux GOARCH=${ARCH} CGO_ENABLED=0 go build -v -buildvcs=false -ldflags='-w -s' -o '$BINARY_PATH' ./cmd/agent" 2>&1 | tee /tmp/go_build.log; then
echo -e "${BLUE}使用 vendor 目录编译(无需网络连接)...${NC}"
# 强制使用 vendor 模式编译
BUILD_FLAGS="-mod=vendor -v -buildvcs=false -ldflags='-w -s'"
if sudo bash -c "cd '$SOURCE_DIR' && $GO_ENV && GOOS=linux GOARCH=${ARCH} CGO_ENABLED=0 go build $BUILD_FLAGS -o '$BINARY_PATH' ./cmd/agent" 2>&1 | tee /tmp/go_build.log; then
if [ -f "$BINARY_PATH" ] && [ -s "$BINARY_PATH" ]; then
sudo chmod +x "$BINARY_PATH"
BINARY_SIZE=$(du -h "$BINARY_PATH" | cut -f1)

220
vendor.sh Executable file
View File

@@ -0,0 +1,220 @@
#!/bin/bash
# ============================================
# LinkMaster Node Vendor 依赖打包脚本
# 用途:将项目依赖下载到 vendor 目录,客户端克隆后可直接编译,无需网络
# 使用方法: ./vendor.sh
# ============================================
set -e
# 颜色输出
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'
# 脚本目录
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
cd "$SCRIPT_DIR"
# 检查 Go 环境
check_go() {
if ! command -v go > /dev/null 2>&1; then
echo -e "${RED}错误: 未找到 Go 环境${NC}"
echo -e "${YELLOW}请先安装 Go: https://golang.org/dl/${NC}"
exit 1
fi
GO_VERSION=$(go version 2>/dev/null | head -1)
echo -e "${GREEN}✓ 检测到 Go: ${GO_VERSION}${NC}"
}
# 配置 Go 环境(海外网络,直接使用官方源)
setup_go_env() {
echo -e "${BLUE}配置 Go 环境(使用官方源)...${NC}"
# 海外网络可以直接使用官方源,无需代理
# 使用官方 Go 代理和校验和数据库
export GOPROXY="https://proxy.golang.org,direct"
export GOSUMDB="sum.golang.org"
# 使用 go env -w 永久设置
go env -w GOPROXY="https://proxy.golang.org,direct" 2>/dev/null || true
go env -w GOSUMDB="sum.golang.org" 2>/dev/null || true
echo -e "${GREEN}✓ Go 环境配置完成(使用官方源)${NC}"
echo -e "${BLUE} GOPROXY=https://proxy.golang.org,direct${NC}"
echo -e "${BLUE} GOSUMDB=sum.golang.org${NC}"
}
# 下载依赖
download_dependencies() {
echo -e "${BLUE}下载 Go 依赖包...${NC}"
# 先整理依赖
echo -e "${BLUE}整理 Go 模块依赖...${NC}"
if ! go mod tidy -v 2>&1; then
echo -e "${YELLOW}⚠ go mod tidy 失败,继续尝试下载依赖...${NC}"
fi
# 下载依赖
echo -e "${BLUE}下载所有依赖包(这可能需要一些时间)...${NC}"
DOWNLOAD_START_TIME=$(date +%s)
if go mod download -x 2>&1; then
DOWNLOAD_END_TIME=$(date +%s)
DOWNLOAD_DURATION=$((DOWNLOAD_END_TIME - DOWNLOAD_START_TIME))
echo -e "${GREEN}✓ 依赖下载完成 (耗时: ${DOWNLOAD_DURATION}秒)${NC}"
else
echo -e "${RED}✗ 依赖下载失败${NC}"
exit 1
fi
}
# 创建 vendor 目录
create_vendor() {
echo -e "${BLUE}创建 vendor 目录(打包所有依赖)...${NC}"
# 删除旧的 vendor 目录(如果存在)
if [ -d "vendor" ]; then
echo -e "${YELLOW}清理旧的 vendor 目录...${NC}"
rm -rf vendor
fi
# 创建 vendor 目录
if go mod vendor -v 2>&1; then
VENDOR_COUNT=$(find vendor -type d -mindepth 2 2>/dev/null | wc -l | tr -d '\n' || echo "0")
VENDOR_COUNT=${VENDOR_COUNT:-0}
# 计算 vendor 目录大小
VENDOR_SIZE=$(du -sh vendor 2>/dev/null | cut -f1 || echo "未知")
echo -e "${GREEN}✓ vendor 目录创建成功${NC}"
echo -e "${BLUE}统计信息:${NC}"
echo -e " 依赖包数量: ${GREEN}${VENDOR_COUNT}${NC}"
echo -e " 目录大小: ${GREEN}${VENDOR_SIZE}${NC}"
else
echo -e "${RED}✗ vendor 创建失败${NC}"
exit 1
fi
}
# 更新 .gitignore
update_gitignore() {
echo -e "${BLUE}更新 .gitignore...${NC}"
if [ ! -f ".gitignore" ]; then
echo -e "${BLUE}创建 .gitignore 文件...${NC}"
touch .gitignore
fi
# 检查 .gitignore 是否忽略了 vendor
if grep -q "^vendor$" .gitignore 2>/dev/null || grep -q "^vendor/" .gitignore 2>/dev/null; then
echo -e "${YELLOW}⚠ 检测到 .gitignore 中忽略了 vendor 目录${NC}"
echo -e "${BLUE}正在更新 .gitignore允许 vendor 目录被提交...${NC}"
# 移除 vendor 相关的忽略规则
sed -i.bak '/^vendor$/d; /^vendor\//d' .gitignore 2>/dev/null || \
sed -i '' '/^vendor$/d; /^vendor\//d' .gitignore 2>/dev/null || true
rm -f .gitignore.bak 2>/dev/null || true
echo -e "${GREEN}✓ 已更新 .gitignore${NC}"
else
echo -e "${GREEN}✓ .gitignore 配置正确${NC}"
fi
}
# 添加到 Git可选
add_to_git() {
if [ -d ".git" ]; then
echo -e "${BLUE}将 vendor 目录添加到 Git...${NC}"
# 检查是否有未提交的更改
if git status --porcelain vendor 2>/dev/null | grep -q vendor; then
git add vendor/ 2>/dev/null || true
echo -e "${GREEN}✓ vendor 目录已添加到 Git 暂存区${NC}"
echo -e "${YELLOW}提示: 请运行 'git commit -m \"chore: add vendor dependencies\"' 提交 vendor 目录${NC}"
else
echo -e "${BLUE}vendor 目录已在 Git 中${NC}"
fi
else
echo -e "${YELLOW}⚠ 当前目录不是 Git 仓库,跳过 Git 操作${NC}"
fi
}
# 显示进度显示
show_progress() {
echo -e "${BLUE}正在下载依赖包,显示进度...${NC}"
# 使用后台进程显示进度
(
DOWNLOADED_COUNT=0
LAST_COUNT=0
LAST_PACKAGE=""
START_TIME=$(date +%s)
while true; do
sleep 1
# 从 go mod download 的输出中统计
CURRENT_COUNT=$(ps aux | grep -c "[g]o mod download" || echo "0")
# 检查进程是否还在运行
if ! pgrep -f "go mod download" > /dev/null 2>&1; then
break
fi
CURRENT_TIME=$(date +%s)
ELAPSED=$((CURRENT_TIME - START_TIME))
if [ "$ELAPSED" -gt 0 ]; then
echo -ne "\r${BLUE}进度: 下载中... | 耗时: ${ELAPSED}"
fi
done
) &
PROGRESS_PID=$!
# 等待下载完成
wait $PROGRESS_PID 2>/dev/null || true
}
# 主函数
main() {
echo -e "${GREEN}========================================${NC}"
echo -e "${GREEN} LinkMaster Node Vendor 依赖打包工具${NC}"
echo -e "${GREEN}========================================${NC}"
echo ""
# 检查是否在项目根目录
if [ ! -f "go.mod" ]; then
echo -e "${RED}错误: 未找到 go.mod 文件${NC}"
echo -e "${YELLOW}请在项目根目录运行此脚本${NC}"
exit 1
fi
check_go
setup_go_env
download_dependencies
create_vendor
update_gitignore
add_to_git
echo ""
echo -e "${GREEN}========================================${NC}"
echo -e "${GREEN} ✓ Vendor 依赖打包完成!${NC}"
echo -e "${GREEN}========================================${NC}"
echo ""
echo -e "${BLUE}下一步操作:${NC}"
echo " 1. 检查 vendor 目录: ls -lh vendor/"
echo " 2. 提交到 Git: git add vendor/ && git commit -m \"chore: add vendor dependencies\""
echo " 3. 推送到远程: git push"
echo ""
echo -e "${BLUE}客户端使用:${NC}"
echo " 客户端克隆项目后,可以使用以下命令编译(无需网络):"
echo " go build -mod=vendor -o agent ./cmd/agent"
echo ""
}
# 执行主函数
main