#!/bin/bash # 功能: # 非交互式用法: # ./build.sh <环境编号> [更新Excel] [发布] # 示例: # ./build.sh 1 1 0 # 使用当前分支,构建dev环境,更新Excel并导表,不发布 # make build 1 1 0 # 参数说明: # <环境编号> : 1=dev, 2=test, 3=dev&test, 4=prod # [更新Excel]: y/Y/1 表示更新并导表,其他值或省略表示跳过 # [发布] : y/Y/1 表示 push 发布仓库,其他值或省略表示跳过 # 特点: # - 默认使用当前 git 分支 # - 全程无需交互输入,适合脚本/CI 调用 # # 交互式用法: # ./build.sh # 交互步骤: # 1) 选择代码分支(默认当前分支),如选择其他分支则执行 git 切换 # 2) 选择是否更新 Excel 仓库及 commit/hash/branch,并在该引用上执行导表 # 并将生成/输出文件复制到项目的 etc/data 和 etc/data_map 下 # 3) 选择构建类型(dev/test/prod) # 4) 选择是否将 publish 内容推送到发布仓库 # # 注意: # - 假定脚本位于 e:\f1\server\etc\script 中,脚本会自动切换到仓库根目录以进行 git 操作 PUBLISH_GIT_URL="ssh://git@git.chun-pu.com:9022/f1/server-publish.git" EXCEL_GIT_URL="ssh://git@git.chun-pu.com:9022/f1/excel.git" _tmp_dirs=() cleanup() { for d in "${_tmp_dirs[@]:-}"; do [[ -d "$d" ]] && rm -rf "$d" done return 0 } trap cleanup EXIT # 检查并进入仓库根目录 repo_root=$(git rev-parse --show-toplevel 2>/dev/null || true) if [[ -z "$repo_root" ]]; then echo "未检测到 git 仓库,请在项目仓库内运行此脚本。" exit 1 fi cd "$repo_root" build_arg="${1:-}" #分支id update_excel_arg="${2:-}" #是否更新excel do_publish_arg="${3:-}" #是否发布到仓库 noninteractive=false if [[ -n "$build_arg" ]]; then noninteractive=true fi # 1) 分支选择与切换(默认当前分支) repo_branch_current=$(git rev-parse --abbrev-ref HEAD 2>/dev/null || true) if $noninteractive; then target_branch="$repo_branch_current" echo "非交互模式:使用当前分支 ${target_branch}" else read -p "请输入要编译的分支(回车使用当前分支 ${repo_branch_current}): " target_branch target_branch=${target_branch:-$repo_branch_current} fi if [[ "$target_branch" != "$repo_branch_current" ]]; then echo "切换到分支 ${target_branch} ..." git fetch origin || true if git rev-parse --verify --quiet "refs/heads/${target_branch}"; then git checkout "$target_branch" git pull origin "$target_branch" --rebase || true repo_branch_current=$(git rev-parse --abbrev-ref HEAD) echo "当前分支: ${repo_branch_current}" else echo "不存在该分支,脚本终止。" exit 1 fi fi # 获取当前分支的 hash repo_hash=$(git rev-parse HEAD 2>/dev/null || true) repo_branch=$(git rev-parse --abbrev-ref HEAD 2>/dev/null || true) # 2) Excel 导表:询问是否需要更新Excel,回车默认跳过 if $noninteractive; then case "$update_excel_arg" in y|Y|1) update_excel="y" ;; *) update_excel="" ;; esac echo "非交互模式:Excel 更新选项: ${update_excel:-跳过}" else read -p "是否需要更新 Excel 仓库?(y/n,回车跳过) " update_excel fi excel_hash="" excel_branch="" if [[ "$update_excel" =~ ^[Yy]$ ]]; then excel_tmp="$repo_root/_excel/" if [[ -d "$repo_root/_excel/" ]]; then echo "检测到已存在的 Excel 仓库,执行更新..." cd "$excel_tmp" || { echo "进入 Excel 仓库失败:${excel_tmp}" exit 2 } git pull --rebase || true else git clone "$EXCEL_GIT_URL" "$excel_tmp" || { echo "克隆 Excel 仓库失败:${EXCEL_GIT_URL}" exit 2 } cd "$excel_tmp" || { echo "进入 Excel 仓库失败:${excel_tmp}" exit 2 } fi # 提示输入分支号,回车使用远程默认分支 if $noninteractive; then excel_ref="" else read -p "请输入 Excel 仓库的 commit/hash/branch(回车使用远程默认分支): " excel_ref fi if [[ -z "${excel_ref}" ]]; then # 使用远程默认分支 default_branch=$(git rev-parse --abbrev-ref HEAD 2>/dev/null || true) if [[ -n "$default_branch" ]]; then echo "未输入引用,使用默认分支: ${default_branch}" else echo "默认分支未找到,终止脚本。" exit 2 fi else # 输入了引用,尝试检出:优先当作本地/commit/short-hash,再尝试远程分支/标签 echo "尝试检出指定引用: ${excel_ref} ..." if git rev-parse --verify --quiet "$excel_ref"; then git checkout -f "$excel_ref" else echo "无法检出指定引用: ${excel_ref},请确认输入是否正确" exit 2 fi fi excel_hash=$(git rev-parse HEAD 2>/dev/null || true) excel_branch=$(git rev-parse --abbrev-ref HEAD 2>/dev/null || true) echo "当前 Excel 仓库位于: ${excel_branch}" else echo "跳过 Excel 更新" fi # 执行导表,输出到output目录 if [[ -n "$update_excel" ]] && [[ "$update_excel" =~ ^[Yy]$ ]]; then if [[ -f "$repo_root/_excel/bin/ee_linux" ]]; then echo "检测到 $repo_root/_excel/bin/ee_linux,开始执行导表..." cd "$repo_root/_excel/bin/" || true if [[ "$(uname -s)" == "MINGW"* ]]; then ./ee.exe --path=./server.json else ./ee_linux --path=./server.json fi echo "导表完成,复制生成的文件到项目..." cp -r "$repo_root/_excel/output/server_go/"* "$repo_root/internal/data/" 2>/dev/null || true cp -r "$repo_root/_excel/output/server_json/"* "$repo_root/etc/data/" 2>/dev/null || true cp -r "$repo_root/_excel/data_map/"* "$repo_root/etc/data_map/" 2>/dev/null || true else echo "$repo_root/_excel/bin/ee_linux 未找到,导表失败。" exit 2 fi else echo "跳过导表步骤" fi cd "$repo_root" || true # 3) 编译源代码 os_name=$(expr substr $(uname -s) 1 5 || true) build_user=$(whoami || true) build_time=$(date +"%Y-%m-%d %H:%M:%S" || true) publish_dir="$repo_root/publish" publish_dir_etc="${publish_dir}/etc/" publish_dir_etc_data="${publish_dir_etc}data/" publish_dir_etc_data_map="${publish_dir_etc}data_map/" publish_dir_etc_lua="${publish_dir_etc}lua/" publish_dir_etc_profile="${publish_dir_etc}profile/" publish_dir_etc_profile_include="${publish_dir_etc}profile/include/" main_file="$repo_root/nodes/main.go" # 回到 etc/script 以保持原相对路径引用 cd "$repo_root/etc/script" || true # 构建相关函数(基于原脚本逻辑,使用绝对路径读取数据/文件) function clean_publish() { rm -rf "$publish_dir" 2>/dev/null || true mkdir -p "$publish_dir" "$publish_dir_etc" "$publish_dir_etc_data" "$publish_dir_etc_data_map" "$publish_dir_etc_lua" "$publish_dir_etc_profile" } function go_build() { local outname="$1" f_repo_hash="'f1-game/internal/version.RepoHash=${repo_hash}'" f_repo_branch="'f1-game/internal/version.RepoBranch=${repo_branch}'" f_excel_hash="'f1-game/internal/version.ExcelHash=${excel_hash}'" f_excel_branch="'f1-game/internal/version.ExcelBranch=${excel_branch}'" f_build_user="'f1-game/internal/version.BuildUser=${build_user}'" f_build_time="'f1-game/internal/version.BuildTime=${build_time}'" echo "[BUILD-${number}] ${f_repo_hash}" echo "[BUILD-${number}] ${f_repo_branch}" echo "[BUILD-${number}] ${f_excel_hash}" echo "[BUILD-${number}] ${f_excel_branch}" echo "[BUILD-${number}] ${f_build_user}" echo "[BUILD-${number}] ${f_build_time}" # 使用 $repo_root 相对的 main_file go build -ldflags "-X ${f_repo_hash} -X ${f_repo_branch} -X ${f_excel_hash} -X ${f_excel_branch} -X ${f_build_user} -X ${f_build_time}" -o "$publish_dir/${outname}" "$repo_root/nodes/main.go" echo "[BUILD-${number}] go build complete!" echo "" } function copy_etc_files() { echo "[BUILD-${number}] copy etc files." mkdir -p "$publish_dir_etc_data" "$publish_dir_etc_data_map" "$publish_dir_etc_lua" || true cp -r "$repo_root/etc/data/"* "$publish_dir_etc_data" 2>/dev/null || true cp -r "$repo_root/etc/data_embed/"* "$publish_dir_etc_data" 2>/dev/null || true cp -r "$repo_root/etc/data_map/"* "$publish_dir_etc_data_map" 2>/dev/null || true cp -r "$repo_root/etc/lua/"* "$publish_dir_etc_lua" 2>/dev/null || true } function build_dev() { clean_publish echo "[BUILD-${number}] dev profile..." export CGO_ENABLED=0 export GOOS=linux export GOARCH=amd64 go_build "node" copy_etc_files echo "[BUILD-${number}] copy profile include files." cp -r "$repo_root/etc/profile/include" "$publish_dir_etc_profile" 2>/dev/null || true echo "[BUILD-${number}] copy linux files." cp "$repo_root/etc/profile/dev.json" "$publish_dir_etc_profile" 2>/dev/null || true cp "$repo_root/etc/cli/cli.sh" "$publish_dir" 2>/dev/null || true cp "$repo_root/etc/cli/docker.sh" "$publish_dir" 2>/dev/null || true cp -r "$repo_root/tool/bin/"* "$publish_dir" 2>/dev/null || true cp "$repo_root/etc/docker/dev.yaml" "$publish_dir" 2>/dev/null || true cp "$repo_root/etc/docker/db.yaml" "$publish_dir" 2>/dev/null || true echo "[BUILD-${number}] exit." } function build_test() { clean_publish echo "[BUILD-${number}] test profile..." export CGO_ENABLED=0 export GOOS=linux export GOARCH=amd64 go_build "node" copy_etc_files echo "[BUILD-${number}] copy profile files." cp "$repo_root/etc/profile/test.json" "$publish_dir_etc_profile" 2>/dev/null || true echo "[BUILD-${number}] copy run script files." cp "$repo_root/etc/cli/docker.sh" "$publish_dir" 2>/dev/null || true cp -r "$repo_root/tool/bin/"* "$publish_dir" 2>/dev/null || true cp -r "$repo_root/etc/docker/test.yaml" "$publish_dir/test.yaml" 2>/dev/null || true cp "$repo_root/etc/docker/db.yaml" "$publish_dir" 2>/dev/null || true echo "[BUILD-${number}] exit." } function build_dev_test() { clean_publish echo "[BUILD-${number}] dev & test profile..." export CGO_ENABLED=0 export GOOS=linux export GOARCH=amd64 go_build "node" copy_etc_files echo "[BUILD-${number}] copy profile files." cp -r "$repo_root/etc/profile/include" "$publish_dir_etc_profile" 2>/dev/null || true cp "$repo_root/etc/profile/dev.json" "$publish_dir_etc_profile" 2>/dev/null || true cp "$repo_root/etc/profile/test.json" "$publish_dir_etc_profile" 2>/dev/null || true echo "[BUILD-${number}] copy run script files." cp "$repo_root/etc/cli/docker.sh" "$publish_dir" 2>/dev/null || true cp -r "$repo_root/tool/bin/"* "$publish_dir" 2>/dev/null || true cp -r "$repo_root/etc/docker/dev.yaml" "$publish_dir/dev.yaml" 2>/dev/null || true cp -r "$repo_root/etc/docker/test.yaml" "$publish_dir/test.yaml" 2>/dev/null || true cp "$repo_root/etc/docker/db.yaml" "$publish_dir" 2>/dev/null || true echo "[BUILD-${number}] exit." } # 若需,可实现 build_prod function build_prod() { clean_publish echo "[BUILD-${number}] prod profile..." export CGO_ENABLED=0 export GOOS=linux export GOARCH=amd64 go_build "node" copy_etc_files echo "[BUILD-${number}] copy profile files." cp "$repo_root/etc/profile/prod.json" "$publish_dir_etc_profile" 2>/dev/null || true cp -r "$repo_root/etc/profile/include" "$publish_dir_etc_profile" 2>/dev/null || true cp "$repo_root/etc/cli/cli.sh" "$publish_dir" 2>/dev/null || true cp -r "$repo_root/tool/bin/"* "$publish_dir" 2>/dev/null || true cp "$repo_root/etc/docker/prod.yaml" "$publish_dir" 2>/dev/null || true cp "$repo_root/etc/docker/db.yaml" "$publish_dir" 2>/dev/null || true echo "[BUILD-${number}] exit." } echo "------------------------------------------------------" echo "OS Name : ${os_name}" echo "Code Path : ${repo_root}" echo "Repo Hash : ${repo_hash}" echo "Repo Branch : ${repo_branch}" echo "Excel Hash : ${excel_hash}" echo "Excel Branch : ${excel_branch}" echo "Build User : ${build_user}" echo "Build Time : ${build_time}" echo "------------------------------------------------------" echo "" if $noninteractive; then number="$build_arg" echo "非交互模式:构建环境编号: ${number}" echo "" else echo "请选择构建的环境:" echo "[1] dev" echo "[2] test" echo "[3] dev & test" echo "[4] prod" echo "[9] exit" echo "" read -p "请输入选项编号: " number echo "" fi case $number in 1) build_dev ;; 2) build_test ;; 3) build_dev_test ;; 4) build_prod ;; 9) echo "退出" exit 0 ;; *) echo "输入不正确,退出。" exit 1 ;; esac # 5) 上传到发布仓库 echo "准备将 publish 内容推送到发布仓库: ${PUBLISH_GIT_URL}" echo "" if $noninteractive; then case "$do_publish_arg" in y|Y|1) do_publish="y" ;; *) do_publish="n" ;; esac echo "非交互模式:发布选项: ${do_publish}" else read -p "是否将本次编译结果push到发布仓库?(y/n,回车跳过)" do_publish fi if [[ "$do_publish" =~ ^[Yy]$ ]]; then echo "开始推送发布内容..." pub_tmp=$(mktemp -d -t publish_repo_XXXX) _tmp_dirs+=("$pub_tmp") git clone "$PUBLISH_GIT_URL" "$pub_tmp" rm -rf "$pub_tmp"/* cp -r "$publish_dir/"* "$pub_tmp"/ 2>/dev/null || true pushd "$pub_tmp" >/dev/null git add --all git commit -m "auto build from repo:${repo_branch}@${repo_hash}, excel:${excel_branch}@${excel_hash}" || echo "Nothing to commit" git push origin master || echo "git push 失败,请检查网络或权限。" popd >/dev/null else echo "取消发布。" exit 0 fi echo "exit" exit 0