提交
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1 +1,2 @@
|
|||||||
.DS_Store
|
.DS_Store
|
||||||
|
bin/
|
||||||
|
|||||||
5
Makefile
5
Makefile
@@ -1,4 +1,4 @@
|
|||||||
.PHONY: build build-linux clean
|
.PHONY: build build-linux build-all clean
|
||||||
|
|
||||||
build:
|
build:
|
||||||
go build -o bin/linkmaster-node ./cmd/agent
|
go build -o bin/linkmaster-node ./cmd/agent
|
||||||
@@ -6,6 +6,9 @@ build:
|
|||||||
build-linux:
|
build-linux:
|
||||||
GOOS=linux GOARCH=amd64 go build -o bin/linkmaster-node-linux ./cmd/agent
|
GOOS=linux GOARCH=amd64 go build -o bin/linkmaster-node-linux ./cmd/agent
|
||||||
|
|
||||||
|
build-all:
|
||||||
|
@./build-all.sh
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -rf bin/
|
rm -rf bin/
|
||||||
|
|
||||||
|
|||||||
269
build-all.sh
Executable file
269
build-all.sh
Executable file
@@ -0,0 +1,269 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# 跨平台编译脚本
|
||||||
|
# 支持编译多个操作系统和架构的版本
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# 颜色输出
|
||||||
|
RED='\033[0;31m'
|
||||||
|
GREEN='\033[0;32m'
|
||||||
|
YELLOW='\033[1;33m'
|
||||||
|
BLUE='\033[0;34m'
|
||||||
|
NC='\033[0m' # No Color
|
||||||
|
|
||||||
|
# 项目信息
|
||||||
|
PROJECT_NAME="agent"
|
||||||
|
BUILD_DIR="bin"
|
||||||
|
VERSION="${VERSION:-$(date +%Y%m%d-%H%M%S)}"
|
||||||
|
MAIN_PACKAGE="./cmd/agent"
|
||||||
|
|
||||||
|
# 支持的平台列表
|
||||||
|
# 格式: OS/ARCH
|
||||||
|
PLATFORMS=(
|
||||||
|
"linux/amd64"
|
||||||
|
"linux/arm64"
|
||||||
|
"darwin/amd64"
|
||||||
|
"darwin/arm64"
|
||||||
|
"windows/amd64"
|
||||||
|
"windows/arm64"
|
||||||
|
)
|
||||||
|
|
||||||
|
# 显示使用说明
|
||||||
|
usage() {
|
||||||
|
echo -e "${BLUE}使用方法:${NC}"
|
||||||
|
echo " $0 [选项]"
|
||||||
|
echo ""
|
||||||
|
echo -e "${BLUE}选项:${NC}"
|
||||||
|
echo " -h, --help 显示帮助信息"
|
||||||
|
echo " -p, --platform PLATFORM 只编译指定平台 (例如: linux/amd64)"
|
||||||
|
echo " -l, --list 列出所有支持的平台"
|
||||||
|
echo " -c, --clean 编译前清理输出目录"
|
||||||
|
echo " -j, --jobs N 并行编译数量 (默认: 4)"
|
||||||
|
echo " -v, --version VERSION 设置版本号 (默认: 时间戳)"
|
||||||
|
echo " -s, --simple-only 只生成不带版本号的文件(默认生成两个)"
|
||||||
|
echo ""
|
||||||
|
echo -e "${BLUE}示例:${NC}"
|
||||||
|
echo " $0 # 编译所有平台"
|
||||||
|
echo " $0 -p linux/amd64 # 只编译 Linux AMD64"
|
||||||
|
echo " $0 -j 2 # 使用2个并行任务"
|
||||||
|
echo " $0 -c # 清理后编译"
|
||||||
|
}
|
||||||
|
|
||||||
|
# 列出所有平台
|
||||||
|
list_platforms() {
|
||||||
|
echo -e "${BLUE}支持的平台:${NC}"
|
||||||
|
for platform in "${PLATFORMS[@]}"; do
|
||||||
|
echo " - $platform"
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
# 清理输出目录
|
||||||
|
clean_build() {
|
||||||
|
if [ -d "$BUILD_DIR" ]; then
|
||||||
|
echo -e "${YELLOW}清理输出目录...${NC}"
|
||||||
|
rm -rf "$BUILD_DIR"
|
||||||
|
fi
|
||||||
|
mkdir -p "$BUILD_DIR"
|
||||||
|
}
|
||||||
|
|
||||||
|
# 编译单个平台
|
||||||
|
build_platform() {
|
||||||
|
local os_arch=$1
|
||||||
|
local simple_only=$2 # 是否只生成不带版本号的文件
|
||||||
|
local os=$(echo $os_arch | cut -d'/' -f1)
|
||||||
|
local arch=$(echo $os_arch | cut -d'/' -f2)
|
||||||
|
|
||||||
|
local output_path
|
||||||
|
if [ "$simple_only" = "true" ]; then
|
||||||
|
# 只生成不带版本号的文件
|
||||||
|
output_path="${BUILD_DIR}/${PROJECT_NAME}-${os}-${arch}"
|
||||||
|
if [ "$os" = "windows" ]; then
|
||||||
|
output_path="${output_path}.exe"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
# 生成带版本号的文件
|
||||||
|
output_path="${BUILD_DIR}/${PROJECT_NAME}-${os}-${arch}-${VERSION}"
|
||||||
|
if [ "$os" = "windows" ]; then
|
||||||
|
output_path="${output_path}.exe"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo -e "${BLUE}[编译]${NC} ${os}/${arch} -> ${output_path}"
|
||||||
|
|
||||||
|
if GOOS=$os GOARCH=$arch go build -ldflags "-s -w -X main.version=${VERSION}" \
|
||||||
|
-o "$output_path" "$MAIN_PACKAGE" 2>&1; then
|
||||||
|
echo -e "${GREEN}[成功]${NC} ${os}/${arch}"
|
||||||
|
|
||||||
|
# 如果不是只生成简单版本,则创建不带版本号的副本(方便使用)
|
||||||
|
if [ "$simple_only" != "true" ]; then
|
||||||
|
local simple_name="${BUILD_DIR}/${PROJECT_NAME}-${os}-${arch}"
|
||||||
|
if [ "$os" = "windows" ]; then
|
||||||
|
simple_name="${simple_name}.exe"
|
||||||
|
fi
|
||||||
|
cp "$output_path" "$simple_name" 2>/dev/null || true
|
||||||
|
fi
|
||||||
|
return 0
|
||||||
|
else
|
||||||
|
echo -e "${RED}[失败]${NC} ${os}/${arch}"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# 主函数
|
||||||
|
main() {
|
||||||
|
local selected_platforms=()
|
||||||
|
local clean=false
|
||||||
|
local jobs=4
|
||||||
|
local list_only=false
|
||||||
|
local simple_only=false
|
||||||
|
|
||||||
|
# 解析参数
|
||||||
|
while [[ $# -gt 0 ]]; do
|
||||||
|
case $1 in
|
||||||
|
-h|--help)
|
||||||
|
usage
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
-p|--platform)
|
||||||
|
selected_platforms+=("$2")
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
-l|--list)
|
||||||
|
list_only=true
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
-c|--clean)
|
||||||
|
clean=true
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
-j|--jobs)
|
||||||
|
jobs="$2"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
-v|--version)
|
||||||
|
VERSION="$2"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
-s|--simple-only)
|
||||||
|
simple_only=true
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo -e "${RED}未知参数: $1${NC}"
|
||||||
|
usage
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
# 如果只是列出平台,则退出
|
||||||
|
if [ "$list_only" = true ]; then
|
||||||
|
list_platforms
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 确定要编译的平台
|
||||||
|
if [ ${#selected_platforms[@]} -eq 0 ]; then
|
||||||
|
selected_platforms=("${PLATFORMS[@]}")
|
||||||
|
else
|
||||||
|
# 验证平台是否支持
|
||||||
|
for platform in "${selected_platforms[@]}"; do
|
||||||
|
local found=false
|
||||||
|
for p in "${PLATFORMS[@]}"; do
|
||||||
|
if [ "$p" = "$platform" ]; then
|
||||||
|
found=true
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
if [ "$found" = false ]; then
|
||||||
|
echo -e "${RED}错误: 不支持的平台 '$platform'${NC}"
|
||||||
|
echo ""
|
||||||
|
list_platforms
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 清理(如果需要)
|
||||||
|
if [ "$clean" = true ]; then
|
||||||
|
clean_build
|
||||||
|
else
|
||||||
|
mkdir -p "$BUILD_DIR"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo -e "${GREEN}========================================${NC}"
|
||||||
|
echo -e "${GREEN}开始跨平台编译${NC}"
|
||||||
|
echo -e "${GREEN}========================================${NC}"
|
||||||
|
echo -e "项目名称: ${BLUE}${PROJECT_NAME}${NC}"
|
||||||
|
echo -e "版本号: ${BLUE}${VERSION}${NC}"
|
||||||
|
echo -e "输出目录: ${BLUE}${BUILD_DIR}${NC}"
|
||||||
|
echo -e "并行任务数: ${BLUE}${jobs}${NC}"
|
||||||
|
echo -e "平台数量: ${BLUE}${#selected_platforms[@]}${NC}"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# 导出函数和变量供后台任务使用
|
||||||
|
export -f build_platform
|
||||||
|
export PROJECT_NAME BUILD_DIR VERSION MAIN_PACKAGE RED GREEN YELLOW BLUE NC
|
||||||
|
|
||||||
|
# 使用后台任务进行并行编译
|
||||||
|
local success_count=0
|
||||||
|
local fail_count=0
|
||||||
|
local temp_file=$(mktemp)
|
||||||
|
|
||||||
|
# 导出变量供后台任务使用
|
||||||
|
export simple_only
|
||||||
|
|
||||||
|
# 启动编译任务
|
||||||
|
for platform in "${selected_platforms[@]}"; do
|
||||||
|
(
|
||||||
|
if build_platform "$platform" "$simple_only"; then
|
||||||
|
echo "SUCCESS $platform" >> "$temp_file"
|
||||||
|
else
|
||||||
|
echo "FAIL $platform" >> "$temp_file"
|
||||||
|
fi
|
||||||
|
) &
|
||||||
|
|
||||||
|
# 控制并行数量
|
||||||
|
while [ $(jobs -r | wc -l | tr -d ' ') -ge "$jobs" ]; do
|
||||||
|
sleep 0.1
|
||||||
|
done
|
||||||
|
done
|
||||||
|
|
||||||
|
# 等待所有后台任务完成
|
||||||
|
wait
|
||||||
|
|
||||||
|
# 统计结果
|
||||||
|
if [ -f "$temp_file" ]; then
|
||||||
|
while IFS= read -r line; do
|
||||||
|
if [[ $line == SUCCESS* ]]; then
|
||||||
|
((success_count++))
|
||||||
|
elif [[ $line == FAIL* ]]; then
|
||||||
|
((fail_count++))
|
||||||
|
fi
|
||||||
|
done < "$temp_file"
|
||||||
|
rm -f "$temp_file"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo -e "${GREEN}========================================${NC}"
|
||||||
|
echo -e "${GREEN}编译完成${NC}"
|
||||||
|
echo -e "${GREEN}========================================${NC}"
|
||||||
|
echo -e "成功: ${GREEN}${success_count}${NC}"
|
||||||
|
echo -e "失败: ${RED}${fail_count}${NC}"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
if [ $fail_count -eq 0 ]; then
|
||||||
|
echo -e "${GREEN}所有平台编译成功!${NC}"
|
||||||
|
echo ""
|
||||||
|
echo -e "${BLUE}编译输出文件:${NC}"
|
||||||
|
ls -lh "$BUILD_DIR" | grep "$PROJECT_NAME" | awk '{print " " $9 " (" $5 ")"}'
|
||||||
|
else
|
||||||
|
echo -e "${RED}部分平台编译失败,请检查错误信息${NC}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# 运行主函数
|
||||||
|
main "$@"
|
||||||
|
|
||||||
311
install.sh
311
install.sh
@@ -48,14 +48,30 @@ fi
|
|||||||
|
|
||||||
# 检测系统类型和架构
|
# 检测系统类型和架构
|
||||||
detect_system() {
|
detect_system() {
|
||||||
if [ -f /etc/os-release ]; then
|
# 检测操作系统类型(linux/darwin/windows)
|
||||||
. /etc/os-release
|
OS_TYPE=$(uname -s | tr '[:upper:]' '[:lower:]')
|
||||||
OS=$ID
|
case $OS_TYPE in
|
||||||
OS_VERSION=$VERSION_ID
|
linux)
|
||||||
else
|
OS_TYPE="linux"
|
||||||
echo -e "${RED}无法检测系统类型${NC}"
|
if [ -f /etc/os-release ]; then
|
||||||
exit 1
|
. /etc/os-release
|
||||||
fi
|
OS=$ID
|
||||||
|
OS_VERSION=$VERSION_ID
|
||||||
|
else
|
||||||
|
OS="linux"
|
||||||
|
OS_VERSION=""
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
darwin)
|
||||||
|
OS_TYPE="darwin"
|
||||||
|
OS="darwin"
|
||||||
|
OS_VERSION=$(sw_vers -productVersion 2>/dev/null || echo "")
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo -e "${RED}不支持的操作系统: $OS_TYPE${NC}"
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
ARCH=$(uname -m)
|
ARCH=$(uname -m)
|
||||||
case $ARCH in
|
case $ARCH in
|
||||||
@@ -71,7 +87,7 @@ detect_system() {
|
|||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
echo -e "${BLUE}检测到系统: $OS $OS_VERSION ($ARCH)${NC}"
|
echo -e "${BLUE}检测到系统: $OS_TYPE $OS_VERSION ($ARCH)${NC}"
|
||||||
}
|
}
|
||||||
|
|
||||||
# 检测并选择最快的镜像源
|
# 检测并选择最快的镜像源
|
||||||
@@ -628,6 +644,256 @@ uninstall_service() {
|
|||||||
echo ""
|
echo ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# 尝试从 Releases 下载二进制文件
|
||||||
|
download_binary_from_releases() {
|
||||||
|
echo -e "${BLUE}尝试从 Releases 下载预编译二进制文件...${NC}"
|
||||||
|
|
||||||
|
# Gitea API 地址
|
||||||
|
local api_base="https://gitee.nas.cpolar.cn/api/v1"
|
||||||
|
local repo_api="${api_base}/repos/${GITHUB_REPO}"
|
||||||
|
|
||||||
|
# 获取所有 releases(按创建时间排序,最新的在前)
|
||||||
|
echo -e "${BLUE}获取最新 release 信息...${NC}"
|
||||||
|
local releases_response=$(curl -s -X GET "${repo_api}/releases?limit=10" 2>/dev/null)
|
||||||
|
|
||||||
|
if [ $? -ne 0 ] || [ -z "$releases_response" ]; then
|
||||||
|
echo -e "${YELLOW}⚠ 无法获取 releases 信息,将使用源码编译${NC}"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 解析所有 releases,找到最新的(按创建时间或版本号)
|
||||||
|
# Gitea API 返回的 releases 通常已经按创建时间倒序排列
|
||||||
|
# 但我们还是需要解析并验证
|
||||||
|
|
||||||
|
# 提取所有 tag 和对应的 release_id、创建时间
|
||||||
|
local latest_tag=""
|
||||||
|
local latest_release_id=""
|
||||||
|
local latest_created_at=""
|
||||||
|
|
||||||
|
# 使用更健壮的方式解析 JSON(虽然简单,但能工作)
|
||||||
|
# 查找第一个有效的 release(非 draft,非 prerelease)
|
||||||
|
local tag_line=$(echo "$releases_response" | grep -o '"tag_name":"[^"]*"' | head -1)
|
||||||
|
local id_line=$(echo "$releases_response" | grep -o '"id":[0-9]*' | head -1)
|
||||||
|
local created_line=$(echo "$releases_response" | grep -o '"created_at":"[^"]*"' | head -1)
|
||||||
|
local draft_line=$(echo "$releases_response" | grep -o '"draft":[^,}]*' | head -1)
|
||||||
|
local prerelease_line=$(echo "$releases_response" | grep -o '"prerelease":[^,}]*' | head -1)
|
||||||
|
|
||||||
|
# 检查是否是 draft 或 prerelease
|
||||||
|
if echo "$draft_line" | grep -q "true" || echo "$prerelease_line" | grep -q "true"; then
|
||||||
|
# 如果是 draft 或 prerelease,尝试找下一个
|
||||||
|
echo -e "${YELLOW}⚠ 第一个 release 是草稿或预发布版本,查找正式版本...${NC}"
|
||||||
|
# 简化处理:如果第一个是预发布,仍然使用它(因为可能是最新的)
|
||||||
|
fi
|
||||||
|
|
||||||
|
latest_tag=$(echo "$tag_line" | cut -d'"' -f4)
|
||||||
|
latest_release_id=$(echo "$id_line" | cut -d':' -f2)
|
||||||
|
latest_created_at=$(echo "$created_line" | cut -d'"' -f4)
|
||||||
|
|
||||||
|
if [ -z "$latest_tag" ] || [ -z "$latest_release_id" ]; then
|
||||||
|
echo -e "${YELLOW}⚠ 无法解析 release 信息,将使用源码编译${NC}"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 显示找到的版本信息
|
||||||
|
echo -e "${GREEN}✓ 找到最新版本: ${latest_tag}${NC}"
|
||||||
|
if [ -n "$latest_created_at" ]; then
|
||||||
|
echo -e "${BLUE} 发布日期: ${latest_created_at}${NC}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 构建文件名(根据系统类型)
|
||||||
|
local file_name="agent-${OS_TYPE}-${ARCH}-${latest_tag}"
|
||||||
|
local file_ext="tar.gz"
|
||||||
|
if [ "$OS_TYPE" = "windows" ]; then
|
||||||
|
file_ext="zip"
|
||||||
|
fi
|
||||||
|
local full_file_name="${file_name}.${file_ext}"
|
||||||
|
|
||||||
|
# 获取 release 的详细信息(包含 commit hash)
|
||||||
|
local release_detail=$(curl -s -X GET "${repo_api}/releases/${latest_release_id}" 2>/dev/null)
|
||||||
|
|
||||||
|
if [ $? -ne 0 ] || [ -z "$release_detail" ]; then
|
||||||
|
echo -e "${YELLOW}⚠ 无法获取 release 详细信息,将使用源码编译${NC}"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 解析 release 对应的 commit hash(target_commitish)
|
||||||
|
local release_commit=$(echo "$release_detail" | grep -o '"target_commitish":"[^"]*"' | head -1 | cut -d'"' -f4)
|
||||||
|
|
||||||
|
# 如果 release_detail 中没有 target_commitish,尝试通过 tag 获取 commit hash
|
||||||
|
if [ -z "$release_commit" ]; then
|
||||||
|
# 通过 tag API 获取 commit hash
|
||||||
|
local tag_info=$(curl -s -X GET "${repo_api}/git/tags/${latest_tag}" 2>/dev/null)
|
||||||
|
if [ $? -eq 0 ] && [ -n "$tag_info" ]; then
|
||||||
|
release_commit=$(echo "$tag_info" | grep -o '"sha":"[^"]*"' | head -1 | cut -d'"' -f4)
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 如果还是无法获取 commit hash,使用 assets_response 继续(不强制要求 commit)
|
||||||
|
local assets_response="$release_detail"
|
||||||
|
|
||||||
|
# 查找匹配的二进制文件
|
||||||
|
local download_url=$(echo "$assets_response" | grep -o "\"browser_download_url\":\"[^\"]*${full_file_name}[^\"]*\"" | head -1 | cut -d'"' -f4)
|
||||||
|
|
||||||
|
if [ -z "$download_url" ]; then
|
||||||
|
echo -e "${YELLOW}⚠ 未找到匹配的二进制文件: ${full_file_name}${NC}"
|
||||||
|
echo -e "${YELLOW} 将使用源码编译${NC}"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo -e "${BLUE}下载二进制文件: ${full_file_name}...${NC}"
|
||||||
|
|
||||||
|
# 创建临时目录
|
||||||
|
local temp_dir=$(mktemp -d)
|
||||||
|
local download_file="${temp_dir}/${full_file_name}"
|
||||||
|
|
||||||
|
# 下载文件
|
||||||
|
if ! curl -fsSL -o "$download_file" "$download_url" 2>/dev/null; then
|
||||||
|
echo -e "${YELLOW}⚠ 下载失败,将使用源码编译${NC}"
|
||||||
|
rm -rf "$temp_dir"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 检查文件大小(至少应该大于 1MB)
|
||||||
|
local file_size=$(stat -f%z "$download_file" 2>/dev/null || stat -c%s "$download_file" 2>/dev/null || echo "0")
|
||||||
|
if [ "$file_size" -lt 1048576 ]; then
|
||||||
|
echo -e "${YELLOW}⚠ 下载的文件大小异常,将使用源码编译${NC}"
|
||||||
|
rm -rf "$temp_dir"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 解压文件
|
||||||
|
echo -e "${BLUE}解压二进制文件...${NC}"
|
||||||
|
cd "$temp_dir"
|
||||||
|
|
||||||
|
if [ "$file_ext" = "tar.gz" ]; then
|
||||||
|
if ! tar -xzf "$download_file" 2>/dev/null; then
|
||||||
|
echo -e "${YELLOW}⚠ 解压失败,将使用源码编译${NC}"
|
||||||
|
rm -rf "$temp_dir"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
# 查找解压后的二进制文件(优先查找 agent,然后是 agent-*)
|
||||||
|
local binary_file=""
|
||||||
|
if [ -f "./agent" ] && [ -x "./agent" ]; then
|
||||||
|
binary_file="./agent"
|
||||||
|
else
|
||||||
|
binary_file=$(find . -maxdepth 1 -type f \( -name "agent" -o -name "agent-*" -o -name "Agent" -o -name "Agent-*" \) ! -name "*.tar.gz" ! -name "*.zip" 2>/dev/null | head -1)
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
# Windows zip 文件(虽然脚本主要在 Linux 上运行,但保留兼容性)
|
||||||
|
if ! unzip -q "$download_file" 2>/dev/null; then
|
||||||
|
echo -e "${YELLOW}⚠ 解压失败,将使用源码编译${NC}"
|
||||||
|
rm -rf "$temp_dir"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
local binary_file=$(find . -maxdepth 1 -type f \( -name "agent*.exe" -o -name "Agent*.exe" \) 2>/dev/null | head -1)
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$binary_file" ] || [ ! -f "$binary_file" ]; then
|
||||||
|
echo -e "${YELLOW}⚠ 未找到解压后的二进制文件,将使用源码编译${NC}"
|
||||||
|
echo -e "${YELLOW} 解压目录内容:${NC}"
|
||||||
|
ls -la "$temp_dir" 2>/dev/null || true
|
||||||
|
rm -rf "$temp_dir"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 验证二进制文件是否可执行
|
||||||
|
if [ ! -x "$binary_file" ]; then
|
||||||
|
chmod +x "$binary_file" 2>/dev/null || true
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 验证二进制文件类型(Linux 应该是 ELF 文件)
|
||||||
|
if [ "$OS_TYPE" = "linux" ]; then
|
||||||
|
if command -v file > /dev/null 2>&1; then
|
||||||
|
local file_type=$(file "$binary_file" 2>/dev/null || echo "")
|
||||||
|
if [ -n "$file_type" ] && ! echo "$file_type" | grep -qi "ELF"; then
|
||||||
|
echo -e "${YELLOW}⚠ 二进制文件类型异常: ${file_type}${NC}"
|
||||||
|
echo -e "${YELLOW} 将使用源码编译${NC}"
|
||||||
|
rm -rf "$temp_dir"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 保存下载的二进制文件到临时位置
|
||||||
|
local downloaded_binary="${temp_dir}/downloaded_agent"
|
||||||
|
sudo cp "$binary_file" "$downloaded_binary"
|
||||||
|
sudo chmod +x "$downloaded_binary"
|
||||||
|
|
||||||
|
# 验证复制后的文件
|
||||||
|
if [ ! -f "$downloaded_binary" ] || [ ! -x "$downloaded_binary" ]; then
|
||||||
|
echo -e "${YELLOW}⚠ 二进制文件验证失败,将使用源码编译${NC}"
|
||||||
|
rm -rf "$temp_dir"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 清理临时下载文件
|
||||||
|
rm -f "$download_file"
|
||||||
|
|
||||||
|
# 克隆仓库(用于获取 run.sh 和 start-systemd.sh 等脚本)
|
||||||
|
echo -e "${BLUE}克隆仓库以获取启动脚本...${NC}"
|
||||||
|
if [ -d "$SOURCE_DIR" ]; then
|
||||||
|
sudo rm -rf "$SOURCE_DIR"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! sudo git clone --branch "${GITHUB_BRANCH}" "https://gitee.nas.cpolar.cn/${GITHUB_REPO}.git" "$SOURCE_DIR" 2>&1; then
|
||||||
|
echo -e "${YELLOW}⚠ 克隆仓库失败,将使用源码编译${NC}"
|
||||||
|
rm -rf "$temp_dir"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 对比 Git commit hash
|
||||||
|
if [ -n "$release_commit" ]; then
|
||||||
|
echo -e "${BLUE}验证 Git commit 版本...${NC}"
|
||||||
|
cd "$SOURCE_DIR"
|
||||||
|
|
||||||
|
# 获取当前分支的最新 commit hash
|
||||||
|
local current_commit=$(git rev-parse HEAD 2>/dev/null || echo "")
|
||||||
|
|
||||||
|
if [ -n "$current_commit" ]; then
|
||||||
|
# 截取短 commit hash 用于显示(前7位)
|
||||||
|
local release_commit_short=$(echo "$release_commit" | cut -c1-7)
|
||||||
|
local current_commit_short=$(echo "$current_commit" | cut -c1-7)
|
||||||
|
|
||||||
|
echo -e "${BLUE} Release commit: ${release_commit_short}${NC}"
|
||||||
|
echo -e "${BLUE} 当前代码 commit: ${current_commit_short}${NC}"
|
||||||
|
|
||||||
|
# 对比 commit hash
|
||||||
|
if [ "$release_commit" != "$current_commit" ]; then
|
||||||
|
echo -e "${YELLOW}⚠ Commit hash 不匹配,二进制文件可能不是最新代码编译的${NC}"
|
||||||
|
echo -e "${YELLOW} Release 基于较旧的代码,将使用源码编译最新版本${NC}"
|
||||||
|
rm -rf "$temp_dir"
|
||||||
|
return 1
|
||||||
|
else
|
||||||
|
echo -e "${GREEN}✓ Commit hash 匹配,二进制文件是最新代码编译的${NC}"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo -e "${YELLOW}⚠ 无法获取当前代码的 commit hash,跳过验证${NC}"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo -e "${YELLOW}⚠ 无法获取 release 的 commit hash,跳过验证${NC}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 用下载的二进制文件覆盖克隆目录中的文件
|
||||||
|
sudo cp "$downloaded_binary" "$SOURCE_DIR/agent"
|
||||||
|
sudo chmod +x "$SOURCE_DIR/agent"
|
||||||
|
|
||||||
|
# 复制到安装目录
|
||||||
|
sudo mkdir -p "$INSTALL_DIR"
|
||||||
|
sudo cp "$SOURCE_DIR/agent" "$INSTALL_DIR/$BINARY_NAME"
|
||||||
|
sudo chmod +x "$INSTALL_DIR/$BINARY_NAME"
|
||||||
|
|
||||||
|
# 清理临时文件
|
||||||
|
rm -rf "$temp_dir"
|
||||||
|
|
||||||
|
# 显示文件信息
|
||||||
|
local binary_size=$(du -h "$SOURCE_DIR/agent" | cut -f1)
|
||||||
|
echo -e "${GREEN}✓ 二进制文件下载完成 (文件大小: ${binary_size})${NC}"
|
||||||
|
echo -e "${BLUE}版本: ${latest_tag}${NC}"
|
||||||
|
echo -e "${BLUE}二进制文件: ${SOURCE_DIR}/agent${NC}"
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
# 从源码编译安装
|
# 从源码编译安装
|
||||||
build_from_source() {
|
build_from_source() {
|
||||||
echo -e "${BLUE}从源码编译安装节点端...${NC}"
|
echo -e "${BLUE}从源码编译安装节点端...${NC}"
|
||||||
@@ -779,6 +1045,22 @@ create_service() {
|
|||||||
sudo chmod +x "$SOURCE_DIR/run.sh"
|
sudo chmod +x "$SOURCE_DIR/run.sh"
|
||||||
sudo chmod +x "$SOURCE_DIR/start-systemd.sh"
|
sudo chmod +x "$SOURCE_DIR/start-systemd.sh"
|
||||||
|
|
||||||
|
# 检测 Go 的安装路径
|
||||||
|
GO_PATH=""
|
||||||
|
if [ -d "/usr/local/go/bin" ]; then
|
||||||
|
GO_PATH="/usr/local/go/bin"
|
||||||
|
elif command -v go > /dev/null 2>&1; then
|
||||||
|
GO_BIN=$(command -v go)
|
||||||
|
GO_PATH=$(dirname "$GO_BIN")
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 构建 PATH 环境变量
|
||||||
|
if [ -n "$GO_PATH" ]; then
|
||||||
|
ENV_PATH="PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:${GO_PATH}"
|
||||||
|
else
|
||||||
|
ENV_PATH="PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
|
||||||
|
fi
|
||||||
|
|
||||||
sudo tee /etc/systemd/system/${SERVICE_NAME}.service > /dev/null <<EOF
|
sudo tee /etc/systemd/system/${SERVICE_NAME}.service > /dev/null <<EOF
|
||||||
[Unit]
|
[Unit]
|
||||||
Description=LinkMaster Node Service
|
Description=LinkMaster Node Service
|
||||||
@@ -792,6 +1074,7 @@ ExecStart=$SOURCE_DIR/start-systemd.sh
|
|||||||
Restart=always
|
Restart=always
|
||||||
RestartSec=5
|
RestartSec=5
|
||||||
Environment="BACKEND_URL=$BACKEND_URL"
|
Environment="BACKEND_URL=$BACKEND_URL"
|
||||||
|
Environment="$ENV_PATH"
|
||||||
|
|
||||||
[Install]
|
[Install]
|
||||||
WantedBy=multi-user.target
|
WantedBy=multi-user.target
|
||||||
@@ -1032,7 +1315,15 @@ main() {
|
|||||||
detect_fastest_mirror
|
detect_fastest_mirror
|
||||||
|
|
||||||
install_dependencies
|
install_dependencies
|
||||||
build_from_source
|
|
||||||
|
# 优先尝试从 Releases 下载二进制文件
|
||||||
|
if ! download_binary_from_releases; then
|
||||||
|
echo -e "${BLUE}从 Releases 下载失败,开始从源码编译...${NC}"
|
||||||
|
build_from_source
|
||||||
|
else
|
||||||
|
echo -e "${GREEN}✓ 使用预编译二进制文件,跳过编译步骤${NC}"
|
||||||
|
fi
|
||||||
|
|
||||||
create_service
|
create_service
|
||||||
configure_firewall
|
configure_firewall
|
||||||
register_node
|
register_node
|
||||||
|
|||||||
@@ -31,9 +31,16 @@ update_and_build() {
|
|||||||
echo "代码更新完成"
|
echo "代码更新完成"
|
||||||
fi
|
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 环境
|
# 检查 Go 环境
|
||||||
if ! command -v go > /dev/null 2>&1; then
|
if ! command -v go > /dev/null 2>&1; then
|
||||||
echo "错误: 未找到 Go 环境,无法编译" >&2
|
echo "错误: 未找到 Go 环境,无法编译" >&2
|
||||||
|
echo "PATH: $PATH" >&2
|
||||||
|
echo "请确保 Go 已安装: /usr/local/go/bin 或系统 PATH 中包含 go 命令" >&2
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|||||||
898
upload.sh
Executable file
898
upload.sh
Executable file
@@ -0,0 +1,898 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# 发布上传脚本
|
||||||
|
# 支持多种上传方式:GitHub Releases、Gitea Releases、SCP、FTP、本地复制
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# 颜色输出
|
||||||
|
RED='\033[0;31m'
|
||||||
|
GREEN='\033[0;32m'
|
||||||
|
YELLOW='\033[1;33m'
|
||||||
|
BLUE='\033[0;34m'
|
||||||
|
CYAN='\033[0;36m'
|
||||||
|
NC='\033[0m' # No Color
|
||||||
|
|
||||||
|
# 项目信息
|
||||||
|
PROJECT_NAME="agent"
|
||||||
|
BUILD_DIR="bin"
|
||||||
|
VERSION="${VERSION:-$(date +%Y%m%d-%H%M%S)}"
|
||||||
|
RELEASE_DIR="release"
|
||||||
|
TEMP_DIR=$(mktemp -d)
|
||||||
|
|
||||||
|
# 支持的平台列表
|
||||||
|
PLATFORMS=(
|
||||||
|
"linux/amd64"
|
||||||
|
"linux/arm64"
|
||||||
|
"darwin/amd64"
|
||||||
|
"darwin/arm64"
|
||||||
|
"windows/amd64"
|
||||||
|
"windows/arm64"
|
||||||
|
)
|
||||||
|
|
||||||
|
# 清理函数
|
||||||
|
cleanup() {
|
||||||
|
if [ -d "$TEMP_DIR" ]; then
|
||||||
|
rm -rf "$TEMP_DIR"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
trap cleanup EXIT
|
||||||
|
|
||||||
|
# 显示使用说明
|
||||||
|
usage() {
|
||||||
|
echo -e "${BLUE}使用方法:${NC}"
|
||||||
|
echo " $0 [选项]"
|
||||||
|
echo ""
|
||||||
|
echo -e "${BLUE}选项:${NC}"
|
||||||
|
echo " -h, --help 显示帮助信息"
|
||||||
|
echo " -m, --method METHOD 上传方式: github|gitea|scp|ftp|local (默认: gitea)"
|
||||||
|
echo " -v, --version VERSION 版本号 (默认: 时间戳)"
|
||||||
|
echo " -p, --platform PLATFORM 只上传指定平台 (例如: linux/amd64)"
|
||||||
|
echo " -t, --tag TAG Git标签 (GitHub/Gitea Releases需要)"
|
||||||
|
echo " -r, --repo REPO 仓库 (格式: owner/repo,默认从.git/config读取)"
|
||||||
|
echo " -b, --base-url URL Gitea基础URL (默认从.git/config读取)"
|
||||||
|
echo " -T, --token TOKEN 访问令牌 (Gitea需要,也可通过GITEA_TOKEN环境变量)"
|
||||||
|
echo " -d, --dest DEST 目标路径 (SCP/FTP/local需要)"
|
||||||
|
echo " -H, --host HOST 主机地址 (SCP/FTP需要)"
|
||||||
|
echo " -u, --user USER 用户名 (SCP/FTP需要)"
|
||||||
|
echo " -P, --port PORT 端口号 (SCP/FTP需要,默认: SCP=22, FTP=21)"
|
||||||
|
echo " -k, --key KEY 私钥路径 (SCP需要)"
|
||||||
|
echo " --pack-only 只打包不上传"
|
||||||
|
echo " --no-pack 不上传压缩包,直接上传二进制文件"
|
||||||
|
echo " --notes NOTES 发布说明 (GitHub/Gitea Releases)"
|
||||||
|
echo " --notes-file FILE 从文件读取发布说明"
|
||||||
|
echo ""
|
||||||
|
echo -e "${BLUE}上传方式说明:${NC}"
|
||||||
|
echo ""
|
||||||
|
echo -e "${CYAN}Gitea Releases (自动从.git/config读取):${NC}"
|
||||||
|
echo " $0 -m gitea -t v1.0.0 -v 1.0.0"
|
||||||
|
echo " $0 -m gitea -t v1.0.0 -v 1.0.0 -T your_token"
|
||||||
|
echo ""
|
||||||
|
echo -e "${CYAN}GitHub Releases:${NC}"
|
||||||
|
echo " $0 -m github -r owner/repo -t v1.0.0 -v 1.0.0"
|
||||||
|
echo ""
|
||||||
|
echo -e "${CYAN}SCP上传:${NC}"
|
||||||
|
echo " $0 -m scp -H example.com -u user -d /path/to/release"
|
||||||
|
echo " $0 -m scp -H example.com -u user -d /path/to/release -k ~/.ssh/id_rsa"
|
||||||
|
echo ""
|
||||||
|
echo -e "${CYAN}FTP上传:${NC}"
|
||||||
|
echo " $0 -m ftp -H ftp.example.com -u user -d /path/to/release"
|
||||||
|
echo ""
|
||||||
|
echo -e "${CYAN}本地复制:${NC}"
|
||||||
|
echo " $0 -m local -d /path/to/release"
|
||||||
|
echo ""
|
||||||
|
echo -e "${CYAN}只打包:${NC}"
|
||||||
|
echo " $0 --pack-only -v 1.0.0"
|
||||||
|
}
|
||||||
|
|
||||||
|
# 从 .git/config 读取 Git 信息
|
||||||
|
read_git_info() {
|
||||||
|
local git_config=".git/config"
|
||||||
|
|
||||||
|
if [ ! -f "$git_config" ]; then
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 读取 origin URL
|
||||||
|
local url=$(git config --get remote.origin.url 2>/dev/null || echo "")
|
||||||
|
|
||||||
|
if [ -z "$url" ]; then
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 解析 URL
|
||||||
|
# 支持格式:
|
||||||
|
# - https://user:pass@host/owner/repo.git
|
||||||
|
# - https://host/owner/repo.git
|
||||||
|
# - git@host:owner/repo.git
|
||||||
|
# - ssh://user@host/owner/repo.git
|
||||||
|
|
||||||
|
local base_url=""
|
||||||
|
local owner=""
|
||||||
|
local repo_name=""
|
||||||
|
local token=""
|
||||||
|
|
||||||
|
# 提取 token (如果有)
|
||||||
|
if [[ "$url" =~ https://([^:]+):([^@]+)@(.+) ]]; then
|
||||||
|
token="${BASH_REMATCH[2]}"
|
||||||
|
url="https://${BASH_REMATCH[1]}@${BASH_REMATCH[3]}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 提取 base_url, owner, repo
|
||||||
|
if [[ "$url" =~ https://([^/]+)/([^/]+)/([^/]+)\.git ]]; then
|
||||||
|
base_url="https://${BASH_REMATCH[1]}"
|
||||||
|
owner="${BASH_REMATCH[2]}"
|
||||||
|
repo_name="${BASH_REMATCH[3]}"
|
||||||
|
elif [[ "$url" =~ git@([^:]+):([^/]+)/([^/]+)\.git ]]; then
|
||||||
|
base_url="https://${BASH_REMATCH[1]}"
|
||||||
|
owner="${BASH_REMATCH[2]}"
|
||||||
|
repo_name="${BASH_REMATCH[3]}"
|
||||||
|
elif [[ "$url" =~ ssh://[^@]+@([^/]+)/([^/]+)/([^/]+)\.git ]]; then
|
||||||
|
base_url="https://${BASH_REMATCH[1]}"
|
||||||
|
owner="${BASH_REMATCH[2]}"
|
||||||
|
repo_name="${BASH_REMATCH[3]}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -n "$base_url" ] && [ -n "$owner" ] && [ -n "$repo_name" ]; then
|
||||||
|
echo "$base_url|$owner|$repo_name|$token"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# 检查必要的工具
|
||||||
|
check_dependencies() {
|
||||||
|
local method=$1
|
||||||
|
local missing_tools=()
|
||||||
|
|
||||||
|
case $method in
|
||||||
|
github)
|
||||||
|
if ! command -v gh &> /dev/null; then
|
||||||
|
missing_tools+=("gh (GitHub CLI)")
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
gitea)
|
||||||
|
if ! command -v curl &> /dev/null; then
|
||||||
|
missing_tools+=("curl")
|
||||||
|
fi
|
||||||
|
if ! command -v jq &> /dev/null; then
|
||||||
|
echo -e "${YELLOW}警告: jq 未安装,某些功能可能受限${NC}"
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
scp)
|
||||||
|
if ! command -v scp &> /dev/null; then
|
||||||
|
missing_tools+=("scp")
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
ftp)
|
||||||
|
if ! command -v curl &> /dev/null && ! command -v ftp &> /dev/null; then
|
||||||
|
missing_tools+=("curl 或 ftp")
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
if [ ${#missing_tools[@]} -gt 0 ]; then
|
||||||
|
echo -e "${RED}错误: 缺少必要的工具:${NC}"
|
||||||
|
for tool in "${missing_tools[@]}"; do
|
||||||
|
echo " - $tool"
|
||||||
|
done
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# 检查构建文件是否存在
|
||||||
|
check_build_files() {
|
||||||
|
if [ ! -d "$BUILD_DIR" ] || [ -z "$(ls -A $BUILD_DIR 2>/dev/null)" ]; then
|
||||||
|
echo -e "${RED}错误: 构建目录为空或不存在${NC}"
|
||||||
|
echo "请先运行 ./build-all.sh 编译项目"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
local found=0
|
||||||
|
for platform in "${PLATFORMS[@]}"; do
|
||||||
|
local os=$(echo $platform | cut -d'/' -f1)
|
||||||
|
local arch=$(echo $platform | cut -d'/' -f2)
|
||||||
|
local file="${BUILD_DIR}/${PROJECT_NAME}-${os}-${arch}"
|
||||||
|
if [ "$os" = "windows" ]; then
|
||||||
|
file="${file}.exe"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -f "$file" ]; then
|
||||||
|
found=1
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ $found -eq 0 ]; then
|
||||||
|
echo -e "${RED}错误: 未找到任何构建文件${NC}"
|
||||||
|
echo "请先运行 ./build-all.sh 编译项目"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# 打包文件
|
||||||
|
pack_files() {
|
||||||
|
local platform=$1
|
||||||
|
local os=$(echo $platform | cut -d'/' -f1)
|
||||||
|
local arch=$(echo $platform | cut -d'/' -f2)
|
||||||
|
local binary="${BUILD_DIR}/${PROJECT_NAME}-${os}-${arch}"
|
||||||
|
|
||||||
|
if [ "$os" = "windows" ]; then
|
||||||
|
binary="${binary}.exe"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ ! -f "$binary" ]; then
|
||||||
|
echo -e "${YELLOW}[跳过]${NC} ${platform} - 文件不存在"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
local pack_name="${PROJECT_NAME}-${os}-${arch}-${VERSION}"
|
||||||
|
local pack_file
|
||||||
|
|
||||||
|
if [ "$os" = "windows" ]; then
|
||||||
|
pack_file="${TEMP_DIR}/${pack_name}.zip"
|
||||||
|
echo -e "${BLUE}[打包]${NC} ${platform} -> ${pack_name}.zip"
|
||||||
|
(cd "$BUILD_DIR" && zip -q "${pack_file}" "$(basename $binary)")
|
||||||
|
else
|
||||||
|
pack_file="${TEMP_DIR}/${pack_name}.tar.gz"
|
||||||
|
echo -e "${BLUE}[打包]${NC} ${platform} -> ${pack_name}.tar.gz"
|
||||||
|
tar -czf "$pack_file" -C "$BUILD_DIR" "$(basename $binary)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "$pack_file"
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
# 创建发布说明
|
||||||
|
create_release_notes() {
|
||||||
|
local notes_file="${TEMP_DIR}/release_notes.md"
|
||||||
|
cat > "$notes_file" <<EOF
|
||||||
|
# ${PROJECT_NAME} ${VERSION}
|
||||||
|
|
||||||
|
## 版本信息
|
||||||
|
- **版本号**: ${VERSION}
|
||||||
|
- **发布日期**: $(date '+%Y-%m-%d %H:%M:%S')
|
||||||
|
- **Git提交**: $(git rev-parse --short HEAD 2>/dev/null || echo "N/A")
|
||||||
|
- **Git分支**: $(git rev-parse --abbrev-ref HEAD 2>/dev/null || echo "N/A")
|
||||||
|
|
||||||
|
## 支持的平台
|
||||||
|
EOF
|
||||||
|
|
||||||
|
for platform in "${PLATFORMS[@]}"; do
|
||||||
|
local os=$(echo $platform | cut -d'/' -f1)
|
||||||
|
local arch=$(echo $platform | cut -d'/' -f2)
|
||||||
|
local binary="${BUILD_DIR}/${PROJECT_NAME}-${os}-${arch}"
|
||||||
|
if [ "$os" = "windows" ]; then
|
||||||
|
binary="${binary}.exe"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -f "$binary" ]; then
|
||||||
|
local size=$(ls -lh "$binary" | awk '{print $5}')
|
||||||
|
echo "- ${os}/${arch} (${size})" >> "$notes_file"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "" >> "$notes_file"
|
||||||
|
echo "## 安装说明" >> "$notes_file"
|
||||||
|
echo "" >> "$notes_file"
|
||||||
|
echo "### Linux/macOS" >> "$notes_file"
|
||||||
|
echo "\`\`\`bash" >> "$notes_file"
|
||||||
|
echo "tar -xzf ${PROJECT_NAME}-linux-amd64-${VERSION}.tar.gz" >> "$notes_file"
|
||||||
|
echo "chmod +x ${PROJECT_NAME}-linux-amd64" >> "$notes_file"
|
||||||
|
echo "./${PROJECT_NAME}-linux-amd64" >> "$notes_file"
|
||||||
|
echo "\`\`\`" >> "$notes_file"
|
||||||
|
echo "" >> "$notes_file"
|
||||||
|
echo "### Windows" >> "$notes_file"
|
||||||
|
echo "\`\`\`powershell" >> "$notes_file"
|
||||||
|
echo "Expand-Archive ${PROJECT_NAME}-windows-amd64-${VERSION}.zip" >> "$notes_file"
|
||||||
|
echo ".\\${PROJECT_NAME}-windows-amd64.exe" >> "$notes_file"
|
||||||
|
echo "\`\`\`" >> "$notes_file"
|
||||||
|
|
||||||
|
echo "$notes_file"
|
||||||
|
}
|
||||||
|
|
||||||
|
# GitHub Releases 上传
|
||||||
|
upload_github() {
|
||||||
|
local repo=$1
|
||||||
|
local tag=$2
|
||||||
|
local notes_file=$3
|
||||||
|
|
||||||
|
if [ -z "$repo" ]; then
|
||||||
|
echo -e "${RED}错误: GitHub仓库未指定,使用 -r owner/repo${NC}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$tag" ]; then
|
||||||
|
echo -e "${RED}错误: Git标签未指定,使用 -t TAG${NC}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo -e "${GREEN}========================================${NC}"
|
||||||
|
echo -e "${GREEN}上传到 GitHub Releases${NC}"
|
||||||
|
echo -e "${GREEN}========================================${NC}"
|
||||||
|
echo -e "仓库: ${BLUE}${repo}${NC}"
|
||||||
|
echo -e "标签: ${BLUE}${tag}${NC}"
|
||||||
|
echo -e "版本: ${BLUE}${VERSION}${NC}"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# 检查是否已存在release
|
||||||
|
if gh release view "$tag" --repo "$repo" &>/dev/null; then
|
||||||
|
echo -e "${YELLOW}警告: Release ${tag} 已存在${NC}"
|
||||||
|
read -p "是否删除并重新创建? (y/N): " confirm
|
||||||
|
if [[ "$confirm" =~ ^[Yy]$ ]]; then
|
||||||
|
gh release delete "$tag" --repo "$repo" --yes
|
||||||
|
else
|
||||||
|
echo "取消上传"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 创建release
|
||||||
|
echo -e "${BLUE}[创建Release]${NC} ${tag}"
|
||||||
|
if [ -f "$notes_file" ]; then
|
||||||
|
gh release create "$tag" \
|
||||||
|
--repo "$repo" \
|
||||||
|
--title "${PROJECT_NAME} ${VERSION}" \
|
||||||
|
--notes-file "$notes_file" \
|
||||||
|
--draft=false \
|
||||||
|
--prerelease=false
|
||||||
|
else
|
||||||
|
gh release create "$tag" \
|
||||||
|
--repo "$repo" \
|
||||||
|
--title "${PROJECT_NAME} ${VERSION}" \
|
||||||
|
--notes "Release ${VERSION}" \
|
||||||
|
--draft=false \
|
||||||
|
--prerelease=false
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 上传文件
|
||||||
|
local upload_count=0
|
||||||
|
shopt -s nullglob
|
||||||
|
for file in "${TEMP_DIR}"/*.tar.gz "${TEMP_DIR}"/*.zip; do
|
||||||
|
if [ -f "$file" ]; then
|
||||||
|
echo -e "${BLUE}[上传]${NC} $(basename $file)"
|
||||||
|
gh release upload "$tag" "$file" --repo "$repo" --clobber
|
||||||
|
((upload_count++))
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
shopt -u nullglob
|
||||||
|
|
||||||
|
if [ $upload_count -eq 0 ] && [ "$NO_PACK" != "true" ]; then
|
||||||
|
echo -e "${YELLOW}警告: 没有找到要上传的文件${NC}"
|
||||||
|
else
|
||||||
|
echo -e "${GREEN}[完成]${NC} 已上传 ${upload_count} 个文件"
|
||||||
|
echo -e "${CYAN}Release链接:${NC} https://github.com/${repo}/releases/tag/${tag}"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Gitea Releases 上传
|
||||||
|
upload_gitea() {
|
||||||
|
local base_url=$1
|
||||||
|
local owner=$2
|
||||||
|
local repo=$3
|
||||||
|
local tag=$4
|
||||||
|
local token=$5
|
||||||
|
local notes_file=$6
|
||||||
|
|
||||||
|
if [ -z "$base_url" ] || [ -z "$owner" ] || [ -z "$repo" ]; then
|
||||||
|
echo -e "${RED}错误: Gitea仓库信息不完整${NC}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$tag" ]; then
|
||||||
|
echo -e "${RED}错误: Git标签未指定,使用 -t TAG${NC}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$token" ]; then
|
||||||
|
token="${GITEA_TOKEN}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$token" ]; then
|
||||||
|
echo -e "${RED}错误: 访问令牌未指定,使用 -T TOKEN 或设置 GITEA_TOKEN 环境变量${NC}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo -e "${GREEN}========================================${NC}"
|
||||||
|
echo -e "${GREEN}上传到 Gitea Releases${NC}"
|
||||||
|
echo -e "${GREEN}========================================${NC}"
|
||||||
|
echo -e "基础URL: ${BLUE}${base_url}${NC}"
|
||||||
|
echo -e "仓库: ${BLUE}${owner}/${repo}${NC}"
|
||||||
|
echo -e "标签: ${BLUE}${tag}${NC}"
|
||||||
|
echo -e "版本: ${BLUE}${VERSION}${NC}"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
local api_base="${base_url}/api/v1"
|
||||||
|
local repo_api="${api_base}/repos/${owner}/${repo}"
|
||||||
|
|
||||||
|
# 读取发布说明
|
||||||
|
local notes="Release ${VERSION}"
|
||||||
|
if [ -f "$notes_file" ]; then
|
||||||
|
notes=$(cat "$notes_file")
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 转义 JSON 字符串(不使用 jq)
|
||||||
|
local notes_escaped=$(echo "$notes" | sed 's/\\/\\\\/g' | sed 's/"/\\"/g' | sed ':a;N;$!ba;s/\n/\\n/g')
|
||||||
|
|
||||||
|
# 检查是否已存在release
|
||||||
|
local existing_release=$(curl -s -X GET \
|
||||||
|
"${repo_api}/releases/tags/${tag}" \
|
||||||
|
-H "Authorization: token ${token}" \
|
||||||
|
-H "Content-Type: application/json" 2>/dev/null)
|
||||||
|
|
||||||
|
if echo "$existing_release" | grep -q '"id"'; then
|
||||||
|
echo -e "${YELLOW}警告: Release ${tag} 已存在${NC}"
|
||||||
|
read -p "是否删除并重新创建? (y/N): " confirm
|
||||||
|
if [[ "$confirm" =~ ^[Yy]$ ]]; then
|
||||||
|
local release_id=$(echo "$existing_release" | grep -o '"id":[0-9]*' | head -1 | cut -d':' -f2)
|
||||||
|
if [ -n "$release_id" ]; then
|
||||||
|
curl -s -X DELETE \
|
||||||
|
"${repo_api}/releases/${release_id}" \
|
||||||
|
-H "Authorization: token ${token}" > /dev/null
|
||||||
|
echo -e "${BLUE}[删除]${NC} 已删除现有 Release"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "取消上传"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 创建release
|
||||||
|
echo -e "${BLUE}[创建Release]${NC} ${tag}"
|
||||||
|
local release_data=$(cat <<EOF
|
||||||
|
{
|
||||||
|
"tag_name": "${tag}",
|
||||||
|
"target_commitish": "main",
|
||||||
|
"name": "${PROJECT_NAME} ${VERSION}",
|
||||||
|
"body": "${notes_escaped}",
|
||||||
|
"draft": false,
|
||||||
|
"prerelease": false
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
)
|
||||||
|
|
||||||
|
local create_response=$(curl -s -X POST \
|
||||||
|
"${repo_api}/releases" \
|
||||||
|
-H "Authorization: token ${token}" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d "$release_data")
|
||||||
|
|
||||||
|
if echo "$create_response" | grep -q '"id"'; then
|
||||||
|
local release_id=$(echo "$create_response" | grep -o '"id":[0-9]*' | head -1 | cut -d':' -f2)
|
||||||
|
echo -e "${GREEN}[成功]${NC} Release 已创建 (ID: ${release_id})"
|
||||||
|
else
|
||||||
|
echo -e "${RED}[失败]${NC} 创建 Release 失败"
|
||||||
|
echo "$create_response" | head -20
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 上传文件
|
||||||
|
local upload_count=0
|
||||||
|
shopt -s nullglob
|
||||||
|
for file in "${TEMP_DIR}"/*.tar.gz "${TEMP_DIR}"/*.zip; do
|
||||||
|
if [ -f "$file" ]; then
|
||||||
|
echo -e "${BLUE}[上传]${NC} $(basename $file)"
|
||||||
|
local upload_response=$(curl -s -X POST \
|
||||||
|
"${repo_api}/releases/${release_id}/assets?name=$(basename $file)" \
|
||||||
|
-H "Authorization: token ${token}" \
|
||||||
|
-H "Content-Type: application/octet-stream" \
|
||||||
|
--data-binary "@${file}")
|
||||||
|
|
||||||
|
if echo "$upload_response" | grep -q '"id"'; then
|
||||||
|
echo -e " ${GREEN}✓${NC} 上传成功"
|
||||||
|
((upload_count++))
|
||||||
|
else
|
||||||
|
echo -e " ${RED}✗${NC} 上传失败"
|
||||||
|
echo "$upload_response" | head -5
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
shopt -u nullglob
|
||||||
|
|
||||||
|
if [ $upload_count -eq 0 ] && [ "$NO_PACK" != "true" ]; then
|
||||||
|
echo -e "${YELLOW}警告: 没有找到要上传的文件${NC}"
|
||||||
|
else
|
||||||
|
echo -e "${GREEN}[完成]${NC} 已上传 ${upload_count} 个文件"
|
||||||
|
echo -e "${CYAN}Release链接:${NC} ${base_url}/${owner}/${repo}/releases/tag/${tag}"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# SCP上传
|
||||||
|
upload_scp() {
|
||||||
|
local host=$1
|
||||||
|
local user=$2
|
||||||
|
local dest=$3
|
||||||
|
local port=${4:-22}
|
||||||
|
local key=$5
|
||||||
|
|
||||||
|
if [ -z "$host" ] || [ -z "$user" ] || [ -z "$dest" ]; then
|
||||||
|
echo -e "${RED}错误: SCP需要指定主机(-H)、用户(-u)和目标路径(-d)${NC}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo -e "${GREEN}========================================${NC}"
|
||||||
|
echo -e "${GREEN}上传到 SCP${NC}"
|
||||||
|
echo -e "${GREEN}========================================${NC}"
|
||||||
|
echo -e "主机: ${BLUE}${user}@${host}:${port}${NC}"
|
||||||
|
echo -e "目标: ${BLUE}${dest}${NC}"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
local scp_opts="-P $port"
|
||||||
|
if [ -n "$key" ]; then
|
||||||
|
scp_opts="$scp_opts -i $key"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 创建远程目录
|
||||||
|
local ssh_cmd="ssh"
|
||||||
|
if [ -n "$key" ]; then
|
||||||
|
ssh_cmd="$ssh_cmd -i $key"
|
||||||
|
fi
|
||||||
|
ssh -p "$port" $([ -n "$key" ] && echo "-i $key") "$user@$host" "mkdir -p $dest" || true
|
||||||
|
|
||||||
|
# 上传文件
|
||||||
|
local upload_count=0
|
||||||
|
if [ "$NO_PACK" = "true" ]; then
|
||||||
|
# 直接上传二进制文件
|
||||||
|
for platform in "${SELECTED_PLATFORMS[@]}"; do
|
||||||
|
local os=$(echo $platform | cut -d'/' -f1)
|
||||||
|
local arch=$(echo $platform | cut -d'/' -f2)
|
||||||
|
local binary="${BUILD_DIR}/${PROJECT_NAME}-${os}-${arch}"
|
||||||
|
if [ "$os" = "windows" ]; then
|
||||||
|
binary="${binary}.exe"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -f "$binary" ]; then
|
||||||
|
echo -e "${BLUE}[上传]${NC} $(basename $binary)"
|
||||||
|
scp $scp_opts "$binary" "$user@$host:$dest/"
|
||||||
|
((upload_count++))
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
else
|
||||||
|
# 上传压缩包
|
||||||
|
shopt -s nullglob
|
||||||
|
for file in "${TEMP_DIR}"/*.tar.gz "${TEMP_DIR}"/*.zip; do
|
||||||
|
if [ -f "$file" ]; then
|
||||||
|
echo -e "${BLUE}[上传]${NC} $(basename $file)"
|
||||||
|
scp $scp_opts "$file" "$user@$host:$dest/"
|
||||||
|
((upload_count++))
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
shopt -u nullglob
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo -e "${GREEN}[完成]${NC} 已上传 ${upload_count} 个文件"
|
||||||
|
}
|
||||||
|
|
||||||
|
# FTP上传
|
||||||
|
upload_ftp() {
|
||||||
|
local host=$1
|
||||||
|
local user=$2
|
||||||
|
local dest=$3
|
||||||
|
local port=${4:-21}
|
||||||
|
|
||||||
|
if [ -z "$host" ] || [ -z "$user" ] || [ -z "$dest" ]; then
|
||||||
|
echo -e "${RED}错误: FTP需要指定主机(-H)、用户(-u)和目标路径(-d)${NC}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo -e "${GREEN}========================================${NC}"
|
||||||
|
echo -e "${GREEN}上传到 FTP${NC}"
|
||||||
|
echo -e "${GREEN}========================================${NC}"
|
||||||
|
echo -e "主机: ${BLUE}${host}:${port}${NC}"
|
||||||
|
echo -e "用户: ${BLUE}${user}${NC}"
|
||||||
|
echo -e "目标: ${BLUE}${dest}${NC}"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
read -sp "请输入FTP密码: " ftp_pass
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
local upload_count=0
|
||||||
|
|
||||||
|
if [ "$NO_PACK" = "true" ]; then
|
||||||
|
# 直接上传二进制文件
|
||||||
|
for platform in "${SELECTED_PLATFORMS[@]}"; do
|
||||||
|
local os=$(echo $platform | cut -d'/' -f1)
|
||||||
|
local arch=$(echo $platform | cut -d'/' -f2)
|
||||||
|
local binary="${BUILD_DIR}/${PROJECT_NAME}-${os}-${arch}"
|
||||||
|
if [ "$os" = "windows" ]; then
|
||||||
|
binary="${binary}.exe"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -f "$binary" ]; then
|
||||||
|
echo -e "${BLUE}[上传]${NC} $(basename $binary)"
|
||||||
|
curl -T "$binary" \
|
||||||
|
"ftp://${host}:${port}${dest}/$(basename $binary)" \
|
||||||
|
--user "${user}:${ftp_pass}" \
|
||||||
|
--ftp-create-dirs
|
||||||
|
((upload_count++))
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
else
|
||||||
|
# 上传压缩包
|
||||||
|
shopt -s nullglob
|
||||||
|
for file in "${TEMP_DIR}"/*.tar.gz "${TEMP_DIR}"/*.zip; do
|
||||||
|
if [ -f "$file" ]; then
|
||||||
|
echo -e "${BLUE}[上传]${NC} $(basename $file)"
|
||||||
|
curl -T "$file" \
|
||||||
|
"ftp://${host}:${port}${dest}/$(basename $file)" \
|
||||||
|
--user "${user}:${ftp_pass}" \
|
||||||
|
--ftp-create-dirs
|
||||||
|
((upload_count++))
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
shopt -u nullglob
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo -e "${GREEN}[完成]${NC} 已上传 ${upload_count} 个文件"
|
||||||
|
}
|
||||||
|
|
||||||
|
# 本地复制
|
||||||
|
upload_local() {
|
||||||
|
local dest=$1
|
||||||
|
|
||||||
|
if [ -z "$dest" ]; then
|
||||||
|
echo -e "${RED}错误: 本地复制需要指定目标路径(-d)${NC}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo -e "${GREEN}========================================${NC}"
|
||||||
|
echo -e "${GREEN}复制到本地目录${NC}"
|
||||||
|
echo -e "${GREEN}========================================${NC}"
|
||||||
|
echo -e "目标: ${BLUE}${dest}${NC}"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
mkdir -p "$dest"
|
||||||
|
|
||||||
|
local copy_count=0
|
||||||
|
|
||||||
|
if [ "$NO_PACK" = "true" ]; then
|
||||||
|
# 直接复制二进制文件
|
||||||
|
for platform in "${SELECTED_PLATFORMS[@]}"; do
|
||||||
|
local os=$(echo $platform | cut -d'/' -f1)
|
||||||
|
local arch=$(echo $platform | cut -d'/' -f2)
|
||||||
|
local binary="${BUILD_DIR}/${PROJECT_NAME}-${os}-${arch}"
|
||||||
|
if [ "$os" = "windows" ]; then
|
||||||
|
binary="${binary}.exe"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -f "$binary" ]; then
|
||||||
|
echo -e "${BLUE}[复制]${NC} $(basename $binary)"
|
||||||
|
cp "$binary" "$dest/"
|
||||||
|
((copy_count++))
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
else
|
||||||
|
# 复制压缩包
|
||||||
|
shopt -s nullglob
|
||||||
|
for file in "${TEMP_DIR}"/*.tar.gz "${TEMP_DIR}"/*.zip; do
|
||||||
|
if [ -f "$file" ]; then
|
||||||
|
echo -e "${BLUE}[复制]${NC} $(basename $file)"
|
||||||
|
cp "$file" "$dest/"
|
||||||
|
((copy_count++))
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
shopt -u nullglob
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo -e "${GREEN}[完成]${NC} 已复制 ${copy_count} 个文件"
|
||||||
|
}
|
||||||
|
|
||||||
|
# 主函数
|
||||||
|
main() {
|
||||||
|
local method="gitea"
|
||||||
|
local selected_platforms=()
|
||||||
|
local tag=""
|
||||||
|
local repo=""
|
||||||
|
local base_url=""
|
||||||
|
local token=""
|
||||||
|
local dest=""
|
||||||
|
local host=""
|
||||||
|
local user=""
|
||||||
|
local port=""
|
||||||
|
local key=""
|
||||||
|
local pack_only=false
|
||||||
|
local notes=""
|
||||||
|
local notes_file=""
|
||||||
|
|
||||||
|
# 解析参数
|
||||||
|
while [[ $# -gt 0 ]]; do
|
||||||
|
case $1 in
|
||||||
|
-h|--help)
|
||||||
|
usage
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
-m|--method)
|
||||||
|
method="$2"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
-v|--version)
|
||||||
|
VERSION="$2"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
-p|--platform)
|
||||||
|
selected_platforms+=("$2")
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
-t|--tag)
|
||||||
|
tag="$2"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
-r|--repo)
|
||||||
|
repo="$2"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
-b|--base-url)
|
||||||
|
base_url="$2"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
-T|--token)
|
||||||
|
token="$2"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
-d|--dest)
|
||||||
|
dest="$2"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
-H|--host)
|
||||||
|
host="$2"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
-u|--user)
|
||||||
|
user="$2"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
-P|--port)
|
||||||
|
port="$2"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
-k|--key)
|
||||||
|
key="$2"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
--pack-only)
|
||||||
|
pack_only=true
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
--no-pack)
|
||||||
|
NO_PACK=true
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
--notes)
|
||||||
|
notes="$2"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
--notes-file)
|
||||||
|
notes_file="$2"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo -e "${RED}未知参数: $1${NC}"
|
||||||
|
usage
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
# 确定要处理的平台
|
||||||
|
if [ ${#selected_platforms[@]} -eq 0 ]; then
|
||||||
|
SELECTED_PLATFORMS=("${PLATFORMS[@]}")
|
||||||
|
else
|
||||||
|
SELECTED_PLATFORMS=("${selected_platforms[@]}")
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 检查构建文件
|
||||||
|
check_build_files
|
||||||
|
|
||||||
|
# 检查依赖
|
||||||
|
if [ "$pack_only" != "true" ]; then
|
||||||
|
check_dependencies "$method"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 打包文件
|
||||||
|
if [ "$NO_PACK" != "true" ]; then
|
||||||
|
echo -e "${GREEN}========================================${NC}"
|
||||||
|
echo -e "${GREEN}开始打包${NC}"
|
||||||
|
echo -e "${GREEN}========================================${NC}"
|
||||||
|
echo -e "版本: ${BLUE}${VERSION}${NC}"
|
||||||
|
echo -e "平台数量: ${BLUE}${#SELECTED_PLATFORMS[@]}${NC}"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
for platform in "${SELECTED_PLATFORMS[@]}"; do
|
||||||
|
pack_files "$platform" > /dev/null
|
||||||
|
done
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo -e "${GREEN}打包完成${NC}"
|
||||||
|
echo -e "${BLUE}打包文件:${NC}"
|
||||||
|
shopt -s nullglob
|
||||||
|
ls -lh "${TEMP_DIR}"/*.tar.gz "${TEMP_DIR}"/*.zip 2>/dev/null | awk '{print " " $9 " (" $5 ")"}'
|
||||||
|
shopt -u nullglob
|
||||||
|
echo ""
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 如果只是打包,则复制到release目录
|
||||||
|
if [ "$pack_only" = "true" ]; then
|
||||||
|
mkdir -p "$RELEASE_DIR"
|
||||||
|
shopt -s nullglob
|
||||||
|
cp "${TEMP_DIR}"/*.tar.gz "${TEMP_DIR}"/*.zip "$RELEASE_DIR/" 2>/dev/null || true
|
||||||
|
shopt -u nullglob
|
||||||
|
echo -e "${GREEN}文件已复制到 ${RELEASE_DIR} 目录${NC}"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 创建发布说明
|
||||||
|
local release_notes=""
|
||||||
|
if [ -n "$notes_file" ] && [ -f "$notes_file" ]; then
|
||||||
|
release_notes="$notes_file"
|
||||||
|
elif [ -n "$notes" ]; then
|
||||||
|
echo "$notes" > "${TEMP_DIR}/release_notes.md"
|
||||||
|
release_notes="${TEMP_DIR}/release_notes.md"
|
||||||
|
elif [ "$method" = "github" ] || [ "$method" = "gitea" ]; then
|
||||||
|
release_notes=$(create_release_notes)
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 根据方法上传
|
||||||
|
case $method in
|
||||||
|
gitea)
|
||||||
|
# 从 .git/config 读取信息(如果未指定)
|
||||||
|
local git_info=""
|
||||||
|
if [ -z "$base_url" ] || [ -z "$repo" ]; then
|
||||||
|
git_info=$(read_git_info)
|
||||||
|
if [ $? -eq 0 ] && [ -n "$git_info" ]; then
|
||||||
|
IFS='|' read -r git_base_url git_owner git_repo_name git_token <<< "$git_info"
|
||||||
|
if [ -z "$base_url" ]; then
|
||||||
|
base_url="$git_base_url"
|
||||||
|
fi
|
||||||
|
if [ -z "$repo" ]; then
|
||||||
|
repo="${git_owner}/${git_repo_name}"
|
||||||
|
fi
|
||||||
|
if [ -z "$token" ] && [ -n "$git_token" ]; then
|
||||||
|
token="$git_token"
|
||||||
|
fi
|
||||||
|
echo -e "${CYAN}[信息]${NC} 从 .git/config 读取仓库信息: ${repo}"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$base_url" ] || [ -z "$repo" ]; then
|
||||||
|
echo -e "${RED}错误: Gitea仓库信息不完整${NC}"
|
||||||
|
echo "请指定 -b BASE_URL 和 -r owner/repo,或确保 .git/config 中有正确的远程仓库配置"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
IFS='/' read -r owner repo_name <<< "$repo"
|
||||||
|
if [ -z "$owner" ] || [ -z "$repo_name" ]; then
|
||||||
|
echo -e "${RED}错误: 仓库格式不正确,应为 owner/repo${NC}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
upload_gitea "$base_url" "$owner" "$repo_name" "$tag" "$token" "$release_notes"
|
||||||
|
;;
|
||||||
|
github)
|
||||||
|
upload_github "$repo" "$tag" "$release_notes"
|
||||||
|
;;
|
||||||
|
scp)
|
||||||
|
upload_scp "$host" "$user" "$dest" "$port" "$key"
|
||||||
|
;;
|
||||||
|
ftp)
|
||||||
|
upload_ftp "$host" "$user" "$dest" "$port"
|
||||||
|
;;
|
||||||
|
local)
|
||||||
|
upload_local "$dest"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo -e "${RED}错误: 不支持的上传方式: ${method}${NC}"
|
||||||
|
echo "支持的方式: gitea, github, scp, ftp, local"
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo -e "${GREEN}========================================${NC}"
|
||||||
|
echo -e "${GREEN}发布完成${NC}"
|
||||||
|
echo -e "${GREEN}========================================${NC}"
|
||||||
|
}
|
||||||
|
|
||||||
|
# 运行主函数
|
||||||
|
main "$@"
|
||||||
|
|
||||||
Reference in New Issue
Block a user