🐛 fix(driver): 修复可选驱动在线安装回归问题

Refs #388

- 修复 builtin 默认安装版本判定错误
- 恢复驱动总包 bundle 兜底路径
- 优化 Kingbase 安装策略,避免发行版优先本地构建
- 增强驱动安装日志与回归测试
This commit is contained in:
Syngnat
2026-04-16 15:05:16 +08:00
parent a90423c04c
commit d3a1c017da
7 changed files with 161 additions and 153 deletions

View File

@@ -1373,6 +1373,10 @@ func effectiveDriverEngine(definition driverDefinition) string {
}
func resolveDriverDefinition(driverType string) (driverDefinition, bool) {
effectivePackages, err := resolveEffectiveDriverPackages("")
if err == nil {
return resolveDriverDefinitionWithPackages(driverType, effectivePackages)
}
return resolveDriverDefinitionWithPackages(driverType, nil)
}
@@ -2313,7 +2317,7 @@ func inferDriverInstallVersionByDownloadURL(downloadURL string) string {
if err == nil && parsed != nil {
switch strings.ToLower(strings.TrimSpace(parsed.Scheme)) {
case "builtin":
return "go-embedded"
return ""
case "local":
return "local"
case "http", "https":
@@ -3060,6 +3064,54 @@ func installOptionalDriverAgentFromLocalZip(zipPath string, definition driverDef
return filepath.ToSlash(strings.TrimPrefix(strings.TrimSpace(entry.Name), "./")), nil
}
func buildOptionalDriverInstallPlanMessage(displayName string, selectedVersion string, forceSourceBuild bool, preferSourceBuildBeforeDownload bool, restrictToExplicitArtifact bool, directURLCount int, bundleURLCount int) string {
name := strings.TrimSpace(displayName)
if name == "" {
name = "驱动"
}
versionText := normalizeVersion(strings.TrimSpace(selectedVersion))
if versionText == "" {
versionText = "未标注版本"
}
if forceSourceBuild {
return fmt.Sprintf("准备安装 %s 驱动代理(版本 %s当前版本仅允许本地源码构建", name, versionText)
}
if preferSourceBuildBeforeDownload {
return fmt.Sprintf("准备安装 %s 驱动代理(版本 %s先尝试本地源码构建失败后继续下载兜底", name, versionText)
}
if directURLCount > 0 && !restrictToExplicitArtifact && bundleURLCount > 0 {
return fmt.Sprintf("准备安装 %s 驱动代理(版本 %s先尝试 %d 个预编译直链,失败后转入 %d 个驱动总包源", name, versionText, directURLCount, bundleURLCount)
}
if directURLCount > 0 && restrictToExplicitArtifact {
return fmt.Sprintf("准备安装 %s 驱动代理(版本 %s仅允许显式版本资产先尝试 %d 个预编译直链", name, versionText, directURLCount)
}
if directURLCount > 0 {
return fmt.Sprintf("准备安装 %s 驱动代理(版本 %s先尝试 %d 个预编译直链", name, versionText, directURLCount)
}
if !restrictToExplicitArtifact && bundleURLCount > 0 {
return fmt.Sprintf("准备安装 %s 驱动代理(版本 %s未提供预编译直链直接尝试 %d 个驱动总包源", name, versionText, bundleURLCount)
}
return fmt.Sprintf("准备安装 %s 驱动代理(版本 %s未命中发布资产时将回退到本地源码构建", name, versionText)
}
func buildOptionalDriverFallbackProgressMessage(displayName string, directURLCount int, bundleURLCount int, restrictToExplicitArtifact bool) string {
name := strings.TrimSpace(displayName)
if name == "" {
name = "驱动"
}
if directURLCount > 0 && !restrictToExplicitArtifact && bundleURLCount > 0 {
return fmt.Sprintf("预编译直链未命中,转入驱动总包兜底(%s剩余 %d 个总包源)", name, bundleURLCount)
}
if directURLCount > 0 && restrictToExplicitArtifact {
return fmt.Sprintf("预编译直链未命中;当前版本仅允许显式资产,跳过驱动总包(%s", name)
}
if !restrictToExplicitArtifact && bundleURLCount > 0 {
return fmt.Sprintf("直链不可用,转入驱动总包兜底(%s剩余 %d 个总包源)", name, bundleURLCount)
}
return fmt.Sprintf("发布资产未命中,准备回退到本地源码构建(%s", name)
}
func ensureOptionalDriverAgentBinary(a *App, definition driverDefinition, executablePath string, downloadURL string, selectedVersion string) (string, string, error) {
driverType := normalizeDriverType(definition.Type)
displayName := resolveDriverDisplayName(definition)
@@ -3067,6 +3119,16 @@ func ensureOptionalDriverAgentBinary(a *App, definition driverDefinition, execut
preferSourceBuildBeforeDownload := shouldPreferSourceBuildBeforeDownload(driverType, selectedVersion)
skipReuseCandidate := shouldSkipReusableAgentCandidate(driverType, selectedVersion)
restrictToExplicitArtifact := shouldRestrictToExplicitVersionArtifact(definition, selectedVersion)
downloadURLs := []string{}
bundleURLs := []string{}
if !forceSourceBuild {
downloadURLs = resolveOptionalDriverAgentDownloadURLs(definition, downloadURL, selectedVersion)
if !restrictToExplicitArtifact {
bundleURLs = resolveOptionalDriverBundleDownloadURLs()
}
}
planMessage := buildOptionalDriverInstallPlanMessage(displayName, selectedVersion, forceSourceBuild, preferSourceBuildBeforeDownload, restrictToExplicitArtifact, len(downloadURLs), len(bundleURLs))
logger.Infof("%sdriver=%s version=%s direct_candidates=%d bundle_candidates=%d force_source_build=%v restrict_explicit=%v prefer_source_first=%v", planMessage, driverType, normalizeVersion(selectedVersion), len(downloadURLs), len(bundleURLs), forceSourceBuild, restrictToExplicitArtifact, preferSourceBuildBeforeDownload)
info, err := os.Stat(executablePath)
if err == nil && !info.IsDir() {
@@ -3087,7 +3149,7 @@ func ensureOptionalDriverAgentBinary(a *App, definition driverDefinition, execut
return "", "", fmt.Errorf("创建 %s 驱动目录失败:%w", displayName, mkErr)
}
if a != nil {
a.emitDriverDownloadProgress(driverType, "downloading", 10, 100, "检查本地驱动代理缓存")
a.emitDriverDownloadProgress(driverType, "downloading", 10, 100, planMessage)
}
if !skipReuseCandidate {
if sourcePath, ok := findExistingOptionalDriverAgentCandidate(definition, executablePath); ok {
@@ -3124,7 +3186,6 @@ func ensureOptionalDriverAgentBinary(a *App, definition driverDefinition, execut
}
if !forceSourceBuild {
downloadURLs := resolveOptionalDriverAgentDownloadURLs(definition, downloadURL, selectedVersion)
if len(downloadURLs) > 0 {
for _, candidateURL := range downloadURLs {
if a != nil {
@@ -3134,11 +3195,16 @@ func ensureOptionalDriverAgentBinary(a *App, definition driverDefinition, execut
if dlErr == nil {
return candidateURL, hash, nil
}
logger.Warnf("下载预编译 %s 驱动代理失败url=%s err=%v", displayName, candidateURL, dlErr)
downloadErrs = append(downloadErrs, fmt.Sprintf("%s: %s", candidateURL, strings.TrimSpace(dlErr.Error())))
}
}
bundleURLs := resolveOptionalDriverBundleDownloadURLs()
if !restrictToExplicitArtifact && len(bundleURLs) > 0 {
if len(bundleURLs) > 0 {
fallbackMessage := buildOptionalDriverFallbackProgressMessage(displayName, len(downloadURLs), len(bundleURLs), restrictToExplicitArtifact)
logger.Infof("%sdriver=%s version=%s", fallbackMessage, driverType, normalizeVersion(selectedVersion))
if a != nil {
a.emitDriverDownloadProgress(driverType, "downloading", 20, 100, fallbackMessage)
}
for _, bundleURL := range bundleURLs {
if a != nil {
a.emitDriverDownloadProgress(driverType, "downloading", 20, 100, fmt.Sprintf("从驱动总包提取 %s 代理", displayName))
@@ -3147,8 +3213,15 @@ func ensureOptionalDriverAgentBinary(a *App, definition driverDefinition, execut
if bundleErr == nil {
return source, hash, nil
}
logger.Warnf("从驱动总包提取 %s 驱动代理失败url=%s err=%v", displayName, bundleURL, bundleErr)
downloadErrs = append(downloadErrs, fmt.Sprintf("%s: %s", bundleURL, strings.TrimSpace(bundleErr.Error())))
}
} else if len(downloadURLs) > 0 || restrictToExplicitArtifact {
fallbackMessage := buildOptionalDriverFallbackProgressMessage(displayName, len(downloadURLs), 0, restrictToExplicitArtifact)
logger.Infof("%sdriver=%s version=%s", fallbackMessage, driverType, normalizeVersion(selectedVersion))
if a != nil {
a.emitDriverDownloadProgress(driverType, "downloading", 20, 100, fallbackMessage)
}
}
}
if a != nil {
@@ -3401,9 +3474,6 @@ func shouldForceSourceBuildForResolvedDownload(driverType string, selectedVersio
func shouldPreferSourceBuildBeforeDownload(driverType string, selectedVersion string) bool {
_ = selectedVersion
switch normalizeDriverType(driverType) {
case "kingbase":
// 金仓迭代期优先本地源码构建,避免下载到旧版本预编译代理导致修复不生效。
return true
default:
return false
}

View File

@@ -150,6 +150,54 @@ func TestResolveOptionalDriverAgentDownloadURLsSkipsBundleOnlyDamengAsset(t *tes
}
}
func TestResolveDriverInstallVersionUsesPinnedVersionForBuiltinActivateURL(t *testing.T) {
definition, ok := resolveDriverDefinition("sqlserver")
if !ok {
t.Fatal("expected sqlserver driver definition")
}
if normalizeVersion(definition.PinnedVersion) == "" {
t.Fatal("expected sqlserver default definition to include builtin manifest pinned version")
}
got := resolveDriverInstallVersion("", "builtin://activate/sqlserver", definition)
want := normalizeVersion(definition.PinnedVersion)
if got != want {
t.Fatalf("expected builtin activate URL to fall back to pinned version %q, got %q", want, got)
}
}
func TestBuiltinActivatePinnedVersionDoesNotRestrictBundleFallback(t *testing.T) {
definition, ok := resolveDriverDefinition("sqlserver")
if !ok {
t.Fatal("expected sqlserver driver definition")
}
selectedVersion := resolveDriverInstallVersion("", "builtin://activate/sqlserver", definition)
if shouldRestrictToExplicitVersionArtifact(definition, selectedVersion) {
t.Fatalf("expected builtin activate default version %q not to restrict bundle fallback", selectedVersion)
}
}
func TestBuildOptionalDriverInstallPlanMessagePrefersDirectThenBundle(t *testing.T) {
message := buildOptionalDriverInstallPlanMessage("SQL Server", "1.9.6", false, false, false, 1, 2)
if !strings.Contains(message, "先尝试 1 个预编译直链") {
t.Fatalf("expected direct-download hint, got %q", message)
}
if !strings.Contains(message, "失败后转入 2 个驱动总包源") {
t.Fatalf("expected bundle fallback hint, got %q", message)
}
}
func TestBuildOptionalDriverFallbackProgressMessageReportsBundleFallback(t *testing.T) {
message := buildOptionalDriverFallbackProgressMessage("SQL Server", 1, 2, false)
if !strings.Contains(message, "预编译直链未命中") {
t.Fatalf("expected direct miss hint, got %q", message)
}
if !strings.Contains(message, "转入驱动总包兜底") {
t.Fatalf("expected bundle fallback hint, got %q", message)
}
}
func TestDownloadDriverPackageRejectsUnsupportedMongoVersion(t *testing.T) {
app := &App{}
@@ -247,6 +295,36 @@ func TestShouldForceSourceBuildForResolvedDownload(t *testing.T) {
}
}
func TestShouldPreferSourceBuildBeforeDownloadDoesNotPreferKingbase(t *testing.T) {
if shouldPreferSourceBuildBeforeDownload("kingbase", "0.0.0-20201021123113-29bd62a876c3") {
t.Fatal("expected kingbase release install not to prefer source build before download")
}
}
func TestResolveOptionalDriverAgentDownloadURLsIncludesPublishedKingbaseAsset(t *testing.T) {
definition, ok := resolveDriverDefinition("kingbase")
if !ok {
t.Fatal("expected kingbase driver definition")
}
version := normalizeVersion(definition.PinnedVersion)
assetName := optionalDriverReleaseAssetNameForVersion("kingbase", version)
publishedAssets := map[string]int64{
assetName: 18 << 20,
}
seedReleaseAssetCacheEntry(t, "tag:v"+version, publishedAssets, publishedAssets)
seedReleaseAssetCacheEntry(t, "latest", publishedAssets, publishedAssets)
urls := resolveOptionalDriverAgentDownloadURLs(definition, "builtin://activate/kingbase", version)
if len(urls) == 0 {
t.Fatal("expected kingbase pinned install to include published download candidates")
}
if !strings.Contains(urls[0], assetName) {
t.Fatalf("expected first kingbase download URL to contain %q, got %q", assetName, urls[0])
}
}
func TestInstallOptionalDriverAgentFromLocalPathSupportsMongoV1DirectoryImport(t *testing.T) {
definition, ok := resolveDriverDefinition("mongodb")
if !ok {