🔧 chore(driver): 自动生成驱动代理 revision

- 新增脚本按 optional driver-agent 源码依赖生成 revision 指纹
- 构建脚本与 dev/release workflow 在打包前自动刷新 revision
- 生成驱动 revision 映射并补充 optional driver 覆盖校验
This commit is contained in:
Syngnat
2026-04-29 17:20:47 +08:00
parent 0c1586d7a4
commit 824aafbdea
8 changed files with 309 additions and 0 deletions

View File

@@ -246,6 +246,7 @@ jobs:
run: |
set -euo pipefail
DEV_VERSION="${{ steps.version.outputs.version }}"
./tools/generate-driver-agent-revisions.sh --platform "${{ matrix.platform }}"
if [ -n "${{ matrix.wails_tags }}" ]; then
wails build -platform ${{ matrix.platform }} -clean -o ${{ matrix.build_name }} -tags "${{ matrix.wails_tags }}" -ldflags "-s -w -X GoNavi-Wails/internal/app.AppVersion=${DEV_VERSION}"
else

View File

@@ -237,6 +237,7 @@ jobs:
shell: bash
run: |
set -euo pipefail
./tools/generate-driver-agent-revisions.sh --platform "${{ matrix.platform }}"
if [ -n "${{ matrix.wails_tags }}" ]; then
wails build -platform ${{ matrix.platform }} -clean -o ${{ matrix.build_name }} -tags "${{ matrix.wails_tags }}" -ldflags "-s -w -X GoNavi-Wails/internal/app.AppVersion=${{ github.ref_name }}"
else

View File

@@ -152,6 +152,8 @@ echo "🚀 开始构建 optional-driver-agent"
echo " 平台:$goos/$goarch"
echo " 输出目录:$output_dir_abs"
echo " 驱动列表:${drivers[*]}"
echo "🧭 生成 driver-agent revision 指纹"
"$SCRIPT_DIR/tools/generate-driver-agent-revisions.sh" --platform "$target_platform"
for driver in "${drivers[@]}"; do
if [[ "$driver" == "duckdb" && "$goos" == "windows" && "$goarch" != "amd64" ]]; then

View File

@@ -155,6 +155,7 @@ package_macos_release() {
local archive_suffix="$2"
echo -e "${GREEN}🍎 正在构建 macOS (${platform})...${NC}"
generate_driver_agent_revisions "darwin/${platform}"
wails build -platform "darwin/${platform}" -clean -ldflags "$LDFLAGS"
if [ $? -ne 0 ]; then
echo -e "${RED} ❌ macOS ${platform} 构建失败。${NC}"
@@ -185,6 +186,12 @@ package_macos_release() {
echo " ✅ 已生成 $zip_name"
}
generate_driver_agent_revisions() {
local platform="$1"
echo " 🧭 正在生成 driver-agent revision 指纹 (${platform})..."
./tools/generate-driver-agent-revisions.sh --platform "$platform"
}
echo -e "${GREEN}🚀 开始构建 $APP_NAME $VERSION...${NC}"
# 清理并创建输出目录
@@ -197,6 +204,7 @@ package_macos_release "amd64" "mac-amd64"
# --- Windows AMD64 构建 ---
echo -e "${GREEN}🪟 正在构建 Windows (amd64)...${NC}"
if command -v x86_64-w64-mingw32-gcc &> /dev/null; then
generate_driver_agent_revisions "windows/amd64"
wails build -platform windows/amd64 -clean -ldflags "$LDFLAGS"
if [ $? -eq 0 ]; then
TARGET_EXE="$DIST_DIR/${APP_NAME}-${VERSION}-windows-amd64.exe"
@@ -213,6 +221,7 @@ fi
# --- Windows ARM64 构建 ---
echo -e "${GREEN}🪟 正在构建 Windows (arm64)...${NC}"
if command -v aarch64-w64-mingw32-gcc &> /dev/null; then
generate_driver_agent_revisions "windows/arm64"
wails build -platform windows/arm64 -clean -ldflags "$LDFLAGS"
if [ $? -eq 0 ]; then
TARGET_EXE="$DIST_DIR/${APP_NAME}-${VERSION}-windows-arm64.exe"
@@ -235,6 +244,7 @@ CURRENT_ARCH=$(uname -m)
if [ "$CURRENT_OS" = "Linux" ] && [ "$CURRENT_ARCH" = "x86_64" ]; then
# 本机 Linux amd64直接构建
generate_driver_agent_revisions "linux/amd64"
wails build -platform linux/amd64 -clean -ldflags "$LDFLAGS"
if [ $? -eq 0 ]; then
TARGET_LINUX_BIN="$DIST_DIR/${APP_NAME}-${VERSION}-linux-amd64"
@@ -255,6 +265,7 @@ elif command -v x86_64-linux-gnu-gcc &> /dev/null; then
export CC=x86_64-linux-gnu-gcc
export CXX=x86_64-linux-gnu-g++
export CGO_ENABLED=1
generate_driver_agent_revisions "linux/amd64"
wails build -platform linux/amd64 -clean -ldflags "$LDFLAGS"
if [ $? -eq 0 ]; then
TARGET_LINUX_BIN="$DIST_DIR/${APP_NAME}-${VERSION}-linux-amd64"
@@ -279,6 +290,7 @@ fi
echo -e "${GREEN}🐧 正在构建 Linux (arm64)...${NC}"
if [ "$CURRENT_OS" = "Linux" ] && [ "$CURRENT_ARCH" = "aarch64" ]; then
# 本机 Linux arm64直接构建
generate_driver_agent_revisions "linux/arm64"
wails build -platform linux/arm64 -clean -ldflags "$LDFLAGS"
if [ $? -eq 0 ]; then
TARGET_LINUX_BIN="$DIST_DIR/${APP_NAME}-${VERSION}-linux-arm64"
@@ -298,6 +310,7 @@ elif command -v aarch64-linux-gnu-gcc &> /dev/null; then
export CC=aarch64-linux-gnu-gcc
export CXX=aarch64-linux-gnu-g++
export CGO_ENABLED=1
generate_driver_agent_revisions "linux/arm64"
wails build -platform linux/arm64 -clean -ldflags "$LDFLAGS"
if [ $? -eq 0 ]; then
TARGET_LINUX_BIN="$DIST_DIR/${APP_NAME}-${VERSION}-linux-arm64"

View File

@@ -0,0 +1,21 @@
// Code generated by tools/generate-driver-agent-revisions.sh; DO NOT EDIT.
package db
func init() {
optionalDriverAgentRevisions = map[string]string{
"mariadb": "src-d6c5c6717338834c",
"diros": "src-ed4f0f64ed28d3fa",
"sphinx": "src-f52324f0a812d7c8",
"sqlserver": "src-ec165f18de9cd8b3",
"sqlite": "src-9dea6c76bc931114",
"duckdb": "src-14027ac1de3c50c7",
"dameng": "src-1a08880ff5bbcf31",
"kingbase": "src-28eed0e4d942b724",
"highgo": "src-76146bf97f07f25c",
"vastbase": "src-555b60c4863542b6",
"mongodb": "src-2540a7350c4243aa",
"tdengine": "src-ce3e4a9c46f6b92d",
"clickhouse": "src-78e5ada4da56704d",
}
}

View File

@@ -36,6 +36,11 @@ var optionalGoDrivers = map[string]struct{}{
"clickhouse": {},
}
// optionalDriverAgentRevisions 记录 GoNavi 对各可选 driver-agent 包装逻辑的兼容版本。
// 该 map 由 tools/generate-driver-agent-revisions.sh 按 driver-agent 源码依赖自动生成,
// 避免人工判断需要 bump 哪个驱动 revision。
var optionalDriverAgentRevisions = map[string]string{}
var (
externalDriverDirMu sync.RWMutex
externalDriverDir string
@@ -105,6 +110,10 @@ func IsOptionalGoDriverBuildIncluded(driverType string) bool {
return optionalGoDriverBuildIncluded(normalizeRuntimeDriverType(driverType))
}
func OptionalDriverAgentRevision(driverType string) string {
return strings.TrimSpace(optionalDriverAgentRevisions[normalizeRuntimeDriverType(driverType)])
}
// IsBuiltinDriver 返回指定驱动类型是否为核心内置驱动(始终可用,无需安装)。
func IsBuiltinDriver(driverType string) bool {
_, ok := coreBuiltinDrivers[normalizeRuntimeDriverType(driverType)]

View File

@@ -31,6 +31,17 @@ func TestBuiltinLikeDriversRemainAvailable(t *testing.T) {
}
}
func TestOptionalDriverAgentRevisionsGeneratedForOptionalDrivers(t *testing.T) {
for driverType := range optionalGoDrivers {
if revision := OptionalDriverAgentRevision(driverType); revision == "" {
t.Fatalf("%s 缺少自动生成的 driver-agent revision", driverType)
}
}
if OptionalDriverAgentRevision("doris") != OptionalDriverAgentRevision("diros") {
t.Fatalf("doris/diros revision 应归一一致")
}
}
func TestManagedDriverRequiresInstallMarker(t *testing.T) {
tmpDir := t.TempDir()
SetExternalDriverDownloadDirectory(tmpDir)

View File

@@ -0,0 +1,251 @@
#!/usr/bin/env bash
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
cd "$SCRIPT_DIR"
DEFAULT_DRIVERS=(mariadb diros sphinx sqlserver sqlite duckdb dameng kingbase highgo vastbase mongodb tdengine clickhouse)
OUTPUT_FILE="internal/db/driver_agent_revisions_gen.go"
usage() {
cat <<'EOF'
用法:
./tools/generate-driver-agent-revisions.sh [选项]
选项:
--platform <GOOS/GOARCH> 按目标平台解析 Go build tags默认使用当前 Go 环境
--drivers <列表> 指定驱动列表(逗号分隔),默认生成所有 optional driver
-h, --help 显示帮助
EOF
}
normalize_driver() {
local value
value="$(printf '%s' "$1" | tr '[:upper:]' '[:lower:]' | tr -d '[:space:]')"
case "$value" in
doris|diros) echo "diros" ;;
mariadb|diros|sphinx|sqlserver|sqlite|duckdb|dameng|kingbase|highgo|vastbase|mongodb|tdengine|clickhouse)
echo "$value"
;;
*)
return 1
;;
esac
}
build_driver_name() {
echo "$1"
}
hash_file() {
local target="$1"
if command -v sha256sum >/dev/null 2>&1; then
sha256sum "$target" | awk '{print $1}'
return
fi
if command -v shasum >/dev/null 2>&1; then
shasum -a 256 "$target" | awk '{print $1}'
return
fi
echo "未找到 sha256sum 或 shasum" >&2
exit 1
}
should_include_internal_db_file() {
local driver="$1"
local identity="$2"
case "$identity" in
internal/db/agent_process_stub.go|\
internal/db/agent_process_windows.go|\
internal/db/database.go|\
internal/db/database_optional_factories_full.go|\
internal/db/database_optional_factories_lite.go|\
internal/db/driver_agent_binary_check.go|\
internal/db/driver_support.go|\
internal/db/json_decode.go|\
internal/db/mysql_agent_path.go|\
internal/db/optional_driver_agent_impl.go|\
internal/db/optional_driver_build_full.go|\
internal/db/optional_driver_build_lite.go|\
internal/db/query_value.go|\
internal/db/scan_rows.go|\
internal/db/ssl_mode.go|\
internal/db/timeout.go)
return 0
;;
esac
case "$driver:$identity" in
mariadb:internal/db/mariadb_impl.go|\
diros:internal/db/diros_impl.go|\
diros:internal/db/mysql_impl.go|\
sphinx:internal/db/sphinx_impl.go|\
sphinx:internal/db/mysql_impl.go|\
sqlserver:internal/db/sqlserver_impl.go|\
sqlite:internal/db/sqlite_impl.go|\
duckdb:internal/db/duckdb_impl.go|\
duckdb:internal/db/duckdb_driver_import.go|\
duckdb:internal/db/duckdb_platform_supported.go|\
duckdb:internal/db/duckdb_platform_unsupported.go|\
dameng:internal/db/dameng_impl.go|\
dameng:internal/db/dameng_metadata.go|\
kingbase:internal/db/kingbase_impl.go|\
kingbase:internal/db/kingbase_identifier_utils.go|\
highgo:internal/db/highgo_impl.go|\
vastbase:internal/db/vastbase_impl.go|\
mongodb:internal/db/mongodb_impl.go|\
mongodb:internal/db/mongodb_impl_v1.go|\
tdengine:internal/db/tdengine_impl.go|\
clickhouse:internal/db/clickhouse_impl.go)
return 0
;;
esac
return 1
}
should_include_source_file() {
local driver="$1"
local identity="$2"
if [[ "$identity" == internal/db/* ]]; then
should_include_internal_db_file "$driver" "$identity"
return
fi
return 0
}
target_platform=""
driver_csv=""
while [[ $# -gt 0 ]]; do
case "$1" in
--platform)
target_platform="${2:-}"
shift 2
;;
--drivers)
driver_csv="${2:-}"
shift 2
;;
-h|--help)
usage
exit 0
;;
*)
echo "未知参数:$1" >&2
usage
exit 1
;;
esac
done
if ! command -v go >/dev/null 2>&1; then
echo "未找到 Go请先安装 Go 并确保 go 在 PATH 中。" >&2
exit 1
fi
if [[ -z "$target_platform" ]]; then
target_platform="$(go env GOOS)/$(go env GOARCH)"
fi
if [[ "$target_platform" != */* ]]; then
echo "--platform 参数格式错误,应为 GOOS/GOARCH例如 darwin/arm64" >&2
exit 1
fi
goos="${target_platform%%/*}"
goarch="${target_platform##*/}"
gomodcache="$(go env GOMODCACHE)"
declare -a drivers=()
if [[ -n "$driver_csv" ]]; then
IFS=',' read -r -a raw_drivers <<<"$driver_csv"
for item in "${raw_drivers[@]}"; do
drivers+=("$(normalize_driver "$item")")
done
else
drivers=("${DEFAULT_DRIVERS[@]}")
fi
fingerprint_driver() {
local driver="$1"
local build_driver tag cgo_enabled tmp file identity file_hash revision
build_driver="$(build_driver_name "$driver")"
tag="gonavi_${build_driver}_driver"
cgo_enabled=0
if [[ "$driver" == "duckdb" ]]; then
cgo_enabled=1
fi
tmp="$(mktemp "${TMPDIR:-/tmp}/gonavi-agent-revision.XXXXXX")"
{
printf 'driver=%s\n' "$driver"
printf 'build_tag=%s\n' "$tag"
printf 'goos=%s\n' "$goos"
printf 'goarch=%s\n' "$goarch"
} >"$tmp"
while IFS= read -r file; do
[[ -n "$file" && -f "$file" ]] || continue
case "$file" in
"$SCRIPT_DIR"/*)
identity="${file#$SCRIPT_DIR/}"
;;
"$gomodcache"/*)
identity="gomod/${file#$gomodcache/}"
;;
*)
identity="$file"
;;
esac
if [[ "$identity" == "$OUTPUT_FILE" ]]; then
continue
fi
if ! should_include_source_file "$driver" "$identity"; then
continue
fi
file_hash="$(hash_file "$file")"
printf '%s %s\n' "$file_hash" "$identity"
done < <(
CGO_ENABLED="$cgo_enabled" GOOS="$goos" GOARCH="$goarch" GOTOOLCHAIN=auto \
go list -deps \
-tags "$tag" \
-f '{{if not .Standard}}{{range .GoFiles}}{{$.Dir}}/{{.}}{{"\n"}}{{end}}{{range .CgoFiles}}{{$.Dir}}/{{.}}{{"\n"}}{{end}}{{end}}' \
./cmd/optional-driver-agent | sort -u
) >>"$tmp"
revision="$(hash_file "$tmp" | cut -c1-16)"
rm -f "$tmp"
printf 'src-%s' "$revision"
}
tmp_output="$(mktemp "${TMPDIR:-/tmp}/gonavi-agent-revisions-go.XXXXXX")"
{
cat <<'EOF'
// Code generated by tools/generate-driver-agent-revisions.sh; DO NOT EDIT.
package db
func init() {
optionalDriverAgentRevisions = map[string]string{
EOF
for driver in "${drivers[@]}"; do
revision="$(fingerprint_driver "$driver")"
printf '\t\t"%s": "%s",\n' "$driver" "$revision"
done
cat <<'EOF'
}
}
EOF
} >"$tmp_output"
gofmt -w "$tmp_output"
if [[ -f "$OUTPUT_FILE" ]] && cmp -s "$tmp_output" "$OUTPUT_FILE"; then
rm -f "$tmp_output"
else
mv "$tmp_output" "$OUTPUT_FILE"
fi
echo "已生成 driver-agent revisions: $OUTPUT_FILE ($goos/$goarch)"