🎨 Modify configuration migration policy

This commit is contained in:
2025-09-05 22:07:00 +08:00
parent 97ee3b0667
commit a257d30dba
4 changed files with 102 additions and 46 deletions

View File

@@ -8,7 +8,6 @@ import (
"github.com/wailsapp/wails/v3/pkg/services/log"
"os"
"path/filepath"
"strings"
"time"
)
@@ -54,7 +53,6 @@ func NewConfigMigrator(
// AutoMigrate automatically detects and migrates missing configuration fields
func (cm *ConfigMigrator) AutoMigrate(defaultConfig interface{}, currentConfig *koanf.Koanf) (*MigrationResult, error) {
// Load default config into temporary koanf instance
defaultKoanf := koanf.New(".")
if err := defaultKoanf.Load(structs.Provider(defaultConfig, "json"), nil); err != nil {
return nil, fmt.Errorf("failed to load default config: %w", err)
@@ -137,14 +135,12 @@ func (cm *ConfigMigrator) mergeDefaultFields(current, defaultConfig *koanf.Koanf
actuallyMerged := 0
for _, field := range missingFields {
// Use Exists() for better semantic checking
if !current.Exists(field) && defaultConfig.Exists(field) {
// Check if setting this field would conflict with existing user values
if !cm.wouldCreateTypeConflict(current, field) {
if defaultValue := defaultConfig.Get(field); defaultValue != nil {
current.Set(field, defaultValue)
actuallyMerged++
}
if defaultConfig.Exists(field) {
if defaultValue := defaultConfig.Get(field); defaultValue != nil {
// Always set the field, even if it causes type conflicts
// This allows configuration structure evolution during upgrades
current.Set(field, defaultValue)
actuallyMerged++
}
}
}
@@ -157,28 +153,6 @@ func (cm *ConfigMigrator) mergeDefaultFields(current, defaultConfig *koanf.Koanf
return nil
}
// wouldCreateTypeConflict checks if setting a field would overwrite existing user data
func (cm *ConfigMigrator) wouldCreateTypeConflict(current *koanf.Koanf, fieldPath string) bool {
parts := strings.Split(fieldPath, ".")
// Check each parent path to see if user has a non-map value there
for i := 1; i < len(parts); i++ {
parentPath := strings.Join(parts[:i], ".")
// Use Exists() for better semantic checking
if current.Exists(parentPath) {
if parentValue := current.Get(parentPath); parentValue != nil {
// If parent exists and is not a map, setting this field would overwrite it
if _, isMap := parentValue.(map[string]interface{}); !isMap {
return true
}
}
}
}
return false
}
// createBackup creates a backup of the configuration file
func (cm *ConfigMigrator) createBackup() (string, error) {
if _, err := os.Stat(cm.configPath); os.IsNotExist(err) {