fix: resolve golangci-lint issues in migrate_engine.go and loader.go
- Break long lines in mapping table - Reduce cyclomatic complexity by extracting helpers - Fix error string ending with punctuation - Remove orphaned webkit_stack_test.go
- commit
- 75beae6f66d3cacc5f6da9ad310fbec99859b464
- author
- brice · · 2026-03-15 18:00 UTC
- parent
- d0fe704
- signature
- GPG Verified
CD88F9E564E0102646FB6077A1A07C7C7C3E349D· arch-gpg Verified for the committer email
2 files · +88 -69
M internal/infrastructure/config/loader.go +2 -2
| @@ -171,8 +171,8 @@ func (m *Manager) checkLegacyFormat() error { | |||
| 171 | 171 | if hasOldSections && !hasEngineSection { | |
| 172 | 172 | return fmt.Errorf( | |
| 173 | 173 | "config format outdated: [rendering], [performance], [privacy] sections " + | |
| 174 | - | "have moved to [engine]/[engine.webkit].\n" + | |
| 175 | - | "Run \"dumber migrate\" to update your config file.", | |
| 174 | + | "have moved to [engine]/[engine.webkit] — " + | |
| 175 | + | "run \"dumber migrate\" to update your config file", | |
| 176 | 176 | ) | |
| 177 | 177 | } | |
| 178 | 178 | return nil | |
| @@ -171,8 +171,8 @@ func (m *Manager) checkLegacyFormat() error { | |||||
| 171 | if hasOldSections && !hasEngineSection { | 171 | if hasOldSections && !hasEngineSection { | ||
| 172 | return fmt.Errorf( | 172 | return fmt.Errorf( | ||
| 173 | "config format outdated: [rendering], [performance], [privacy] sections " + | 173 | "config format outdated: [rendering], [performance], [privacy] sections " + | ||
| 174 | - | "have moved to [engine]/[engine.webkit].\n" + | 174 | + | "have moved to [engine]/[engine.webkit] — " + |
| 175 | - | "Run \"dumber migrate\" to update your config file.", | 175 | + | "run \"dumber migrate\" to update your config file", |
| 176 | ) | 176 | ) | ||
| 177 | } | 177 | } | ||
| 178 | return nil | 178 | return nil | ||
M internal/infrastructure/config/migrate_engine.go +86 -67
| @@ -1,11 +1,15 @@ | |||
| 1 | 1 | package config | |
| 2 | 2 | ||
| 3 | 3 | import ( | |
| 4 | + | "io/fs" | |
| 4 | 5 | "os" | |
| 5 | 6 | ||
| 6 | 7 | "github.com/pelletier/go-toml/v2" | |
| 7 | 8 | ) | |
| 8 | 9 | ||
| 10 | + | // configFilePermissions is the file permission used when writing migrated config files. | |
| 11 | + | const configFilePermissions fs.FileMode = 0o644 | |
| 12 | + | ||
| 9 | 13 | // engineMigrationMapping defines old key -> new key mappings for the engine migration. | |
| 10 | 14 | // Keys with empty new key ("") are dropped (not migrated). | |
| 11 | 15 | // The source section is the first part of the old key. | |
| @@ -43,18 +47,29 @@ var engineWebkitMappings = []engineFieldMapping{ | |||
| 43 | 47 | {oldSection: "rendering", oldField: "sample_memory", newSection: "engine.webkit", newField: "sample_memory"}, | |
| 44 | 48 | {oldSection: "rendering", oldField: "debug_frames", newSection: "engine.webkit", newField: "debug_frames"}, | |
| 45 | 49 | ||
| 46 | - | // [performance] -> [engine.webkit] (webkit-specific) | |
| 47 | - | {oldSection: "performance", oldField: "skia_cpu_painting_threads", newSection: "engine.webkit", newField: "skia_cpu_painting_threads"}, | |
| 48 | - | {oldSection: "performance", oldField: "skia_gpu_painting_threads", newSection: "engine.webkit", newField: "skia_gpu_painting_threads"}, | |
| 49 | - | {oldSection: "performance", oldField: "skia_enable_cpu_rendering", newSection: "engine.webkit", newField: "skia_enable_cpu_rendering"}, | |
| 50 | - | {oldSection: "performance", oldField: "web_process_memory_limit_mb", newSection: "engine.webkit", newField: "web_process_memory_limit_mb"}, | |
| 51 | - | {oldSection: "performance", oldField: "web_process_memory_poll_interval_sec", newSection: "engine.webkit", newField: "web_process_memory_poll_interval_sec"}, | |
| 52 | - | {oldSection: "performance", oldField: "web_process_memory_conservative_threshold", newSection: "engine.webkit", newField: "web_process_memory_conservative_threshold"}, | |
| 53 | - | {oldSection: "performance", oldField: "web_process_memory_strict_threshold", newSection: "engine.webkit", newField: "web_process_memory_strict_threshold"}, | |
| 54 | - | {oldSection: "performance", oldField: "network_process_memory_limit_mb", newSection: "engine.webkit", newField: "network_process_memory_limit_mb"}, | |
| 55 | - | {oldSection: "performance", oldField: "network_process_memory_poll_interval_sec", newSection: "engine.webkit", newField: "network_process_memory_poll_interval_sec"}, | |
| 56 | - | {oldSection: "performance", oldField: "network_process_memory_conservative_threshold", newSection: "engine.webkit", newField: "network_process_memory_conservative_threshold"}, | |
| 57 | - | {oldSection: "performance", oldField: "network_process_memory_strict_threshold", newSection: "engine.webkit", newField: "network_process_memory_strict_threshold"}, | |
| 50 | + | // [performance] -> [engine.webkit] (webkit-specific) — field names are identical | |
| 51 | + | {oldSection: "performance", oldField: "skia_cpu_painting_threads", | |
| 52 | + | newSection: "engine.webkit", newField: "skia_cpu_painting_threads"}, | |
| 53 | + | {oldSection: "performance", oldField: "skia_gpu_painting_threads", | |
| 54 | + | newSection: "engine.webkit", newField: "skia_gpu_painting_threads"}, | |
| 55 | + | {oldSection: "performance", oldField: "skia_enable_cpu_rendering", | |
| 56 | + | newSection: "engine.webkit", newField: "skia_enable_cpu_rendering"}, | |
| 57 | + | {oldSection: "performance", oldField: "web_process_memory_limit_mb", | |
| 58 | + | newSection: "engine.webkit", newField: "web_process_memory_limit_mb"}, | |
| 59 | + | {oldSection: "performance", oldField: "web_process_memory_poll_interval_sec", | |
| 60 | + | newSection: "engine.webkit", newField: "web_process_memory_poll_interval_sec"}, | |
| 61 | + | {oldSection: "performance", oldField: "web_process_memory_conservative_threshold", | |
| 62 | + | newSection: "engine.webkit", newField: "web_process_memory_conservative_threshold"}, | |
| 63 | + | {oldSection: "performance", oldField: "web_process_memory_strict_threshold", | |
| 64 | + | newSection: "engine.webkit", newField: "web_process_memory_strict_threshold"}, | |
| 65 | + | {oldSection: "performance", oldField: "network_process_memory_limit_mb", | |
| 66 | + | newSection: "engine.webkit", newField: "network_process_memory_limit_mb"}, | |
| 67 | + | {oldSection: "performance", oldField: "network_process_memory_poll_interval_sec", | |
| 68 | + | newSection: "engine.webkit", newField: "network_process_memory_poll_interval_sec"}, | |
| 69 | + | {oldSection: "performance", oldField: "network_process_memory_conservative_threshold", | |
| 70 | + | newSection: "engine.webkit", newField: "network_process_memory_conservative_threshold"}, | |
| 71 | + | {oldSection: "performance", oldField: "network_process_memory_strict_threshold", | |
| 72 | + | newSection: "engine.webkit", newField: "network_process_memory_strict_threshold"}, | |
| 58 | 73 | ||
| 59 | 74 | // [media] GStreamer fields -> [engine.webkit] | |
| 60 | 75 | {oldSection: "media", oldField: "force_vsync", newSection: "engine.webkit", newField: "force_vsync"}, | |
| @@ -72,106 +87,110 @@ var oldSectionsToRemove = []string{"rendering", "performance", "privacy", "runti | |||
| 72 | 87 | // MigrateToEngineConfig restructures old top-level config sections into [engine]/[engine.webkit]. | |
| 73 | 88 | // Returns true if migration was performed, false if already migrated or no old sections found. | |
| 74 | 89 | func MigrateToEngineConfig(configFile string) (bool, error) { | |
| 75 | - | data, err := os.ReadFile(configFile) | |
| 90 | + | raw, err := readRawTOML(configFile) | |
| 76 | 91 | if err != nil { | |
| 77 | 92 | return false, err | |
| 78 | 93 | } | |
| 79 | 94 | ||
| 80 | - | var raw map[string]any | |
| 81 | - | if err := toml.Unmarshal(data, &raw); err != nil { | |
| 82 | - | return false, err | |
| 95 | + | if _, exists := raw["engine"]; exists { | |
| 96 | + | return false, nil // already migrated | |
| 83 | 97 | } | |
| 84 | 98 | ||
| 85 | - | // If "engine" key already exists, already migrated. | |
| 86 | - | if _, exists := raw["engine"]; exists { | |
| 99 | + | if !hasOldEngineSections(raw) { | |
| 87 | 100 | return false, nil | |
| 88 | 101 | } | |
| 89 | 102 | ||
| 90 | - | // Check if any old sections exist. | |
| 91 | - | hasOldSections := false | |
| 103 | + | applyEngineMappings(raw) | |
| 104 | + | ||
| 105 | + | out, marshalErr := toml.Marshal(raw) | |
| 106 | + | if marshalErr != nil { | |
| 107 | + | return false, marshalErr | |
| 108 | + | } | |
| 109 | + | ||
| 110 | + | if writeErr := os.WriteFile(configFile, out, configFilePermissions); writeErr != nil { | |
| 111 | + | return false, writeErr | |
| 112 | + | } | |
| 113 | + | ||
| 114 | + | return true, nil | |
| 115 | + | } | |
| 116 | + | ||
| 117 | + | // readRawTOML reads a TOML file into a generic map. | |
| 118 | + | func readRawTOML(path string) (map[string]any, error) { | |
| 119 | + | data, err := os.ReadFile(path) | |
| 120 | + | if err != nil { | |
| 121 | + | return nil, err | |
| 122 | + | } | |
| 123 | + | var raw map[string]any | |
| 124 | + | if err := toml.Unmarshal(data, &raw); err != nil { | |
| 125 | + | return nil, err | |
| 126 | + | } | |
| 127 | + | return raw, nil | |
| 128 | + | } | |
| 129 | + | ||
| 130 | + | // hasOldEngineSections checks if the raw config has old sections that need migration. | |
| 131 | + | func hasOldEngineSections(raw map[string]any) bool { | |
| 92 | 132 | for _, section := range []string{"rendering", "performance", "privacy", "runtime"} { | |
| 93 | 133 | if _, exists := raw[section]; exists { | |
| 94 | - | hasOldSections = true | |
| 95 | - | break | |
| 134 | + | return true | |
| 96 | 135 | } | |
| 97 | 136 | } | |
| 98 | - | // Also check media for GStreamer fields that migrate. | |
| 99 | - | if !hasOldSections { | |
| 100 | - | if mediaAny, exists := raw["media"]; exists { | |
| 101 | - | if media, ok := mediaAny.(map[string]any); ok { | |
| 102 | - | for _, f := range []string{"force_vsync", "gl_rendering_mode", "gstreamer_debug_level"} { | |
| 103 | - | if _, has := media[f]; has { | |
| 104 | - | hasOldSections = true | |
| 105 | - | break | |
| 106 | - | } | |
| 137 | + | if mediaAny, exists := raw["media"]; exists { | |
| 138 | + | if media, ok := mediaAny.(map[string]any); ok { | |
| 139 | + | for _, f := range []string{"force_vsync", "gl_rendering_mode", "gstreamer_debug_level"} { | |
| 140 | + | if _, has := media[f]; has { | |
| 141 | + | return true | |
| 107 | 142 | } | |
| 108 | 143 | } | |
| 109 | 144 | } | |
| 110 | 145 | } | |
| 146 | + | return false | |
| 147 | + | } | |
| 111 | 148 | ||
| 112 | - | if !hasOldSections { | |
| 113 | - | return false, nil | |
| 114 | - | } | |
| 115 | - | ||
| 116 | - | // Build engine and engine.webkit maps. | |
| 149 | + | // applyEngineMappings builds [engine]/[engine.webkit] from old sections and cleans up. | |
| 150 | + | func applyEngineMappings(raw map[string]any) { | |
| 117 | 151 | engineMap := make(map[string]any) | |
| 118 | 152 | webkitMap := make(map[string]any) | |
| 119 | 153 | ||
| 120 | - | // Apply universal mappings -> engine. | |
| 121 | 154 | for _, m := range engineUniversalMappings { | |
| 122 | 155 | if val := getSectionField(raw, m.oldSection, m.oldField); val != nil { | |
| 123 | 156 | engineMap[m.newField] = val | |
| 124 | 157 | } | |
| 125 | 158 | } | |
| 126 | - | ||
| 127 | - | // Apply webkit mappings -> engine.webkit. | |
| 128 | 159 | for _, m := range engineWebkitMappings { | |
| 129 | 160 | if val := getSectionField(raw, m.oldSection, m.oldField); val != nil { | |
| 130 | 161 | webkitMap[m.newField] = val | |
| 131 | 162 | } | |
| 132 | 163 | } | |
| 133 | 164 | ||
| 134 | - | // Set engine.type default. | |
| 135 | 165 | engineMap["type"] = "webkit" | |
| 136 | - | ||
| 137 | - | // Attach webkit sub-map. | |
| 138 | 166 | if len(webkitMap) > 0 { | |
| 139 | 167 | engineMap["webkit"] = webkitMap | |
| 140 | 168 | } | |
| 141 | - | ||
| 142 | - | // Set engine in raw map. | |
| 143 | 169 | raw["engine"] = engineMap | |
| 144 | 170 | ||
| 145 | - | // Remove old sections entirely. | |
| 146 | 171 | for _, section := range oldSectionsToRemove { | |
| 147 | 172 | delete(raw, section) | |
| 148 | 173 | } | |
| 149 | 174 | ||
| 150 | - | // Remove migrated fields from media (but keep non-migrated ones). | |
| 151 | - | if mediaAny, exists := raw["media"]; exists { | |
| 152 | - | if media, ok := mediaAny.(map[string]any); ok { | |
| 153 | - | delete(media, "force_vsync") | |
| 154 | - | delete(media, "gl_rendering_mode") | |
| 155 | - | delete(media, "gstreamer_debug_level") | |
| 156 | - | if len(media) == 0 { | |
| 157 | - | delete(raw, "media") | |
| 158 | - | } else { | |
| 159 | - | raw["media"] = media | |
| 160 | - | } | |
| 161 | - | } | |
| 162 | - | } | |
| 175 | + | stripMigratedMediaFields(raw) | |
| 176 | + | } | |
| 163 | 177 | ||
| 164 | - | // Write back. | |
| 165 | - | out, err := toml.Marshal(raw) | |
| 166 | - | if err != nil { | |
| 167 | - | return false, err | |
| 178 | + | // stripMigratedMediaFields removes GStreamer fields from [media] while keeping the rest. | |
| 179 | + | func stripMigratedMediaFields(raw map[string]any) { | |
| 180 | + | mediaAny, exists := raw["media"] | |
| 181 | + | if !exists { | |
| 182 | + | return | |
| 168 | 183 | } | |
| 169 | - | ||
| 170 | - | if err := os.WriteFile(configFile, out, 0o644); err != nil { | |
| 171 | - | return false, err | |
| 184 | + | media, ok := mediaAny.(map[string]any) | |
| 185 | + | if !ok { | |
| 186 | + | return | |
| 187 | + | } | |
| 188 | + | delete(media, "force_vsync") | |
| 189 | + | delete(media, "gl_rendering_mode") | |
| 190 | + | delete(media, "gstreamer_debug_level") | |
| 191 | + | if len(media) == 0 { | |
| 192 | + | delete(raw, "media") | |
| 172 | 193 | } | |
| 173 | - | ||
| 174 | - | return true, nil | |
| 175 | 194 | } | |
| 176 | 195 | ||
| 177 | 196 | // getSectionField retrieves a field value from a named section in the raw config map. | |
| @@ -1,11 +1,15 @@ | |||||
| 1 | package config | 1 | package config | ||
| 2 | 2 | ||||
| 3 | import ( | 3 | import ( | ||
| 4 | + | "io/fs" | |||
| 4 | "os" | 5 | "os" | ||
| 5 | 6 | ||||
| 6 | "github.com/pelletier/go-toml/v2" | 7 | "github.com/pelletier/go-toml/v2" | ||
| 7 | ) | 8 | ) | ||
| 8 | 9 | ||||
| 10 | + | // configFilePermissions is the file permission used when writing migrated config files. | |||
| 11 | + | const configFilePermissions fs.FileMode = 0o644 | |||
| 12 | + | ||||
| 9 | // engineMigrationMapping defines old key -> new key mappings for the engine migration. | 13 | // engineMigrationMapping defines old key -> new key mappings for the engine migration. | ||
| 10 | // Keys with empty new key ("") are dropped (not migrated). | 14 | // Keys with empty new key ("") are dropped (not migrated). | ||
| 11 | // The source section is the first part of the old key. | 15 | // The source section is the first part of the old key. | ||
| @@ -43,18 +47,29 @@ var engineWebkitMappings = []engineFieldMapping{ | |||||
| 43 | {oldSection: "rendering", oldField: "sample_memory", newSection: "engine.webkit", newField: "sample_memory"}, | 47 | {oldSection: "rendering", oldField: "sample_memory", newSection: "engine.webkit", newField: "sample_memory"}, | ||
| 44 | {oldSection: "rendering", oldField: "debug_frames", newSection: "engine.webkit", newField: "debug_frames"}, | 48 | {oldSection: "rendering", oldField: "debug_frames", newSection: "engine.webkit", newField: "debug_frames"}, | ||
| 45 | 49 | ||||
| 46 | - | // [performance] -> [engine.webkit] (webkit-specific) | 50 | + | // [performance] -> [engine.webkit] (webkit-specific) — field names are identical |
| 47 | - | {oldSection: "performance", oldField: "skia_cpu_painting_threads", newSection: "engine.webkit", newField: "skia_cpu_painting_threads"}, | 51 | + | {oldSection: "performance", oldField: "skia_cpu_painting_threads", |
| 48 | - | {oldSection: "performance", oldField: "skia_gpu_painting_threads", newSection: "engine.webkit", newField: "skia_gpu_painting_threads"}, | 52 | + | newSection: "engine.webkit", newField: "skia_cpu_painting_threads"}, |
| 49 | - | {oldSection: "performance", oldField: "skia_enable_cpu_rendering", newSection: "engine.webkit", newField: "skia_enable_cpu_rendering"}, | 53 | + | {oldSection: "performance", oldField: "skia_gpu_painting_threads", |
| 50 | - | {oldSection: "performance", oldField: "web_process_memory_limit_mb", newSection: "engine.webkit", newField: "web_process_memory_limit_mb"}, | 54 | + | newSection: "engine.webkit", newField: "skia_gpu_painting_threads"}, |
| 51 | - | {oldSection: "performance", oldField: "web_process_memory_poll_interval_sec", newSection: "engine.webkit", newField: "web_process_memory_poll_interval_sec"}, | 55 | + | {oldSection: "performance", oldField: "skia_enable_cpu_rendering", |
| 52 | - | {oldSection: "performance", oldField: "web_process_memory_conservative_threshold", newSection: "engine.webkit", newField: "web_process_memory_conservative_threshold"}, | 56 | + | newSection: "engine.webkit", newField: "skia_enable_cpu_rendering"}, |
| 53 | - | {oldSection: "performance", oldField: "web_process_memory_strict_threshold", newSection: "engine.webkit", newField: "web_process_memory_strict_threshold"}, | 57 | + | {oldSection: "performance", oldField: "web_process_memory_limit_mb", |
| 54 | - | {oldSection: "performance", oldField: "network_process_memory_limit_mb", newSection: "engine.webkit", newField: "network_process_memory_limit_mb"}, | 58 | + | newSection: "engine.webkit", newField: "web_process_memory_limit_mb"}, |
| 55 | - | {oldSection: "performance", oldField: "network_process_memory_poll_interval_sec", newSection: "engine.webkit", newField: "network_process_memory_poll_interval_sec"}, | 59 | + | {oldSection: "performance", oldField: "web_process_memory_poll_interval_sec", |
| 56 | - | {oldSection: "performance", oldField: "network_process_memory_conservative_threshold", newSection: "engine.webkit", newField: "network_process_memory_conservative_threshold"}, | 60 | + | newSection: "engine.webkit", newField: "web_process_memory_poll_interval_sec"}, |
| 57 | - | {oldSection: "performance", oldField: "network_process_memory_strict_threshold", newSection: "engine.webkit", newField: "network_process_memory_strict_threshold"}, | 61 | + | {oldSection: "performance", oldField: "web_process_memory_conservative_threshold", |
| 62 | + | newSection: "engine.webkit", newField: "web_process_memory_conservative_threshold"}, | |||
| 63 | + | {oldSection: "performance", oldField: "web_process_memory_strict_threshold", | |||
| 64 | + | newSection: "engine.webkit", newField: "web_process_memory_strict_threshold"}, | |||
| 65 | + | {oldSection: "performance", oldField: "network_process_memory_limit_mb", | |||
| 66 | + | newSection: "engine.webkit", newField: "network_process_memory_limit_mb"}, | |||
| 67 | + | {oldSection: "performance", oldField: "network_process_memory_poll_interval_sec", | |||
| 68 | + | newSection: "engine.webkit", newField: "network_process_memory_poll_interval_sec"}, | |||
| 69 | + | {oldSection: "performance", oldField: "network_process_memory_conservative_threshold", | |||
| 70 | + | newSection: "engine.webkit", newField: "network_process_memory_conservative_threshold"}, | |||
| 71 | + | {oldSection: "performance", oldField: "network_process_memory_strict_threshold", | |||
| 72 | + | newSection: "engine.webkit", newField: "network_process_memory_strict_threshold"}, | |||
| 58 | 73 | ||||
| 59 | // [media] GStreamer fields -> [engine.webkit] | 74 | // [media] GStreamer fields -> [engine.webkit] | ||
| 60 | {oldSection: "media", oldField: "force_vsync", newSection: "engine.webkit", newField: "force_vsync"}, | 75 | {oldSection: "media", oldField: "force_vsync", newSection: "engine.webkit", newField: "force_vsync"}, | ||
| @@ -72,106 +87,110 @@ var oldSectionsToRemove = []string{"rendering", "performance", "privacy", "runti | |||||
| 72 | // MigrateToEngineConfig restructures old top-level config sections into [engine]/[engine.webkit]. | 87 | // MigrateToEngineConfig restructures old top-level config sections into [engine]/[engine.webkit]. | ||
| 73 | // Returns true if migration was performed, false if already migrated or no old sections found. | 88 | // Returns true if migration was performed, false if already migrated or no old sections found. | ||
| 74 | func MigrateToEngineConfig(configFile string) (bool, error) { | 89 | func MigrateToEngineConfig(configFile string) (bool, error) { | ||
| 75 | - | data, err := os.ReadFile(configFile) | 90 | + | raw, err := readRawTOML(configFile) |
| 76 | if err != nil { | 91 | if err != nil { | ||
| 77 | return false, err | 92 | return false, err | ||
| 78 | } | 93 | } | ||
| 79 | 94 | ||||
| 80 | - | var raw map[string]any | 95 | + | if _, exists := raw["engine"]; exists { |
| 81 | - | if err := toml.Unmarshal(data, &raw); err != nil { | 96 | + | return false, nil // already migrated |
| 82 | - | return false, err | |||
| 83 | } | 97 | } | ||
| 84 | 98 | ||||
| 85 | - | // If "engine" key already exists, already migrated. | 99 | + | if !hasOldEngineSections(raw) { |
| 86 | - | if _, exists := raw["engine"]; exists { | |||
| 87 | return false, nil | 100 | return false, nil | ||
| 88 | } | 101 | } | ||
| 89 | 102 | ||||
| 90 | - | // Check if any old sections exist. | 103 | + | applyEngineMappings(raw) |
| 91 | - | hasOldSections := false | 104 | + | |
| 105 | + | out, marshalErr := toml.Marshal(raw) | |||
| 106 | + | if marshalErr != nil { | |||
| 107 | + | return false, marshalErr | |||
| 108 | + | } | |||
| 109 | + | ||||
| 110 | + | if writeErr := os.WriteFile(configFile, out, configFilePermissions); writeErr != nil { | |||
| 111 | + | return false, writeErr | |||
| 112 | + | } | |||
| 113 | + | ||||
| 114 | + | return true, nil | |||
| 115 | + | } | |||
| 116 | + | ||||
| 117 | + | // readRawTOML reads a TOML file into a generic map. | |||
| 118 | + | func readRawTOML(path string) (map[string]any, error) { | |||
| 119 | + | data, err := os.ReadFile(path) | |||
| 120 | + | if err != nil { | |||
| 121 | + | return nil, err | |||
| 122 | + | } | |||
| 123 | + | var raw map[string]any | |||
| 124 | + | if err := toml.Unmarshal(data, &raw); err != nil { | |||
| 125 | + | return nil, err | |||
| 126 | + | } | |||
| 127 | + | return raw, nil | |||
| 128 | + | } | |||
| 129 | + | ||||
| 130 | + | // hasOldEngineSections checks if the raw config has old sections that need migration. | |||
| 131 | + | func hasOldEngineSections(raw map[string]any) bool { | |||
| 92 | for _, section := range []string{"rendering", "performance", "privacy", "runtime"} { | 132 | for _, section := range []string{"rendering", "performance", "privacy", "runtime"} { | ||
| 93 | if _, exists := raw[section]; exists { | 133 | if _, exists := raw[section]; exists { | ||
| 94 | - | hasOldSections = true | 134 | + | return true |
| 95 | - | break | |||
| 96 | } | 135 | } | ||
| 97 | } | 136 | } | ||
| 98 | - | // Also check media for GStreamer fields that migrate. | 137 | + | if mediaAny, exists := raw["media"]; exists { |
| 99 | - | if !hasOldSections { | 138 | + | if media, ok := mediaAny.(map[string]any); ok { |
| 100 | - | if mediaAny, exists := raw["media"]; exists { | 139 | + | for _, f := range []string{"force_vsync", "gl_rendering_mode", "gstreamer_debug_level"} { |
| 101 | - | if media, ok := mediaAny.(map[string]any); ok { | 140 | + | if _, has := media[f]; has { |
| 102 | - | for _, f := range []string{"force_vsync", "gl_rendering_mode", "gstreamer_debug_level"} { | 141 | + | return true |
| 103 | - | if _, has := media[f]; has { | |||
| 104 | - | hasOldSections = true | |||
| 105 | - | break | |||
| 106 | - | } | |||
| 107 | } | 142 | } | ||
| 108 | } | 143 | } | ||
| 109 | } | 144 | } | ||
| 110 | } | 145 | } | ||
| 146 | + | return false | |||
| 147 | + | } | |||
| 111 | 148 | ||||
| 112 | - | if !hasOldSections { | 149 | + | // applyEngineMappings builds [engine]/[engine.webkit] from old sections and cleans up. |
| 113 | - | return false, nil | 150 | + | func applyEngineMappings(raw map[string]any) { |
| 114 | - | } | |||
| 115 | - | ||||
| 116 | - | // Build engine and engine.webkit maps. | |||
| 117 | engineMap := make(map[string]any) | 151 | engineMap := make(map[string]any) | ||
| 118 | webkitMap := make(map[string]any) | 152 | webkitMap := make(map[string]any) | ||
| 119 | 153 | ||||
| 120 | - | // Apply universal mappings -> engine. | |||
| 121 | for _, m := range engineUniversalMappings { | 154 | for _, m := range engineUniversalMappings { | ||
| 122 | if val := getSectionField(raw, m.oldSection, m.oldField); val != nil { | 155 | if val := getSectionField(raw, m.oldSection, m.oldField); val != nil { | ||
| 123 | engineMap[m.newField] = val | 156 | engineMap[m.newField] = val | ||
| 124 | } | 157 | } | ||
| 125 | } | 158 | } | ||
| 126 | - | ||||
| 127 | - | // Apply webkit mappings -> engine.webkit. | |||
| 128 | for _, m := range engineWebkitMappings { | 159 | for _, m := range engineWebkitMappings { | ||
| 129 | if val := getSectionField(raw, m.oldSection, m.oldField); val != nil { | 160 | if val := getSectionField(raw, m.oldSection, m.oldField); val != nil { | ||
| 130 | webkitMap[m.newField] = val | 161 | webkitMap[m.newField] = val | ||
| 131 | } | 162 | } | ||
| 132 | } | 163 | } | ||
| 133 | 164 | ||||
| 134 | - | // Set engine.type default. | |||
| 135 | engineMap["type"] = "webkit" | 165 | engineMap["type"] = "webkit" | ||
| 136 | - | ||||
| 137 | - | // Attach webkit sub-map. | |||
| 138 | if len(webkitMap) > 0 { | 166 | if len(webkitMap) > 0 { | ||
| 139 | engineMap["webkit"] = webkitMap | 167 | engineMap["webkit"] = webkitMap | ||
| 140 | } | 168 | } | ||
| 141 | - | ||||
| 142 | - | // Set engine in raw map. | |||
| 143 | raw["engine"] = engineMap | 169 | raw["engine"] = engineMap | ||
| 144 | 170 | ||||
| 145 | - | // Remove old sections entirely. | |||
| 146 | for _, section := range oldSectionsToRemove { | 171 | for _, section := range oldSectionsToRemove { | ||
| 147 | delete(raw, section) | 172 | delete(raw, section) | ||
| 148 | } | 173 | } | ||
| 149 | 174 | ||||
| 150 | - | // Remove migrated fields from media (but keep non-migrated ones). | 175 | + | stripMigratedMediaFields(raw) |
| 151 | - | if mediaAny, exists := raw["media"]; exists { | 176 | + | } |
| 152 | - | if media, ok := mediaAny.(map[string]any); ok { | |||
| 153 | - | delete(media, "force_vsync") | |||
| 154 | - | delete(media, "gl_rendering_mode") | |||
| 155 | - | delete(media, "gstreamer_debug_level") | |||
| 156 | - | if len(media) == 0 { | |||
| 157 | - | delete(raw, "media") | |||
| 158 | - | } else { | |||
| 159 | - | raw["media"] = media | |||
| 160 | - | } | |||
| 161 | - | } | |||
| 162 | - | } | |||
| 163 | 177 | ||||
| 164 | - | // Write back. | 178 | + | // stripMigratedMediaFields removes GStreamer fields from [media] while keeping the rest. |
| 165 | - | out, err := toml.Marshal(raw) | 179 | + | func stripMigratedMediaFields(raw map[string]any) { |
| 166 | - | if err != nil { | 180 | + | mediaAny, exists := raw["media"] |
| 167 | - | return false, err | 181 | + | if !exists { |
| 182 | + | return | |||
| 168 | } | 183 | } | ||
| 169 | - | 184 | + | media, ok := mediaAny.(map[string]any) | |
| 170 | - | if err := os.WriteFile(configFile, out, 0o644); err != nil { | 185 | + | if !ok { |
| 171 | - | return false, err | 186 | + | return |
| 187 | + | } | |||
| 188 | + | delete(media, "force_vsync") | |||
| 189 | + | delete(media, "gl_rendering_mode") | |||
| 190 | + | delete(media, "gstreamer_debug_level") | |||
| 191 | + | if len(media) == 0 { | |||
| 192 | + | delete(raw, "media") | |||
| 172 | } | 193 | } | ||
| 173 | - | ||||
| 174 | - | return true, nil | |||
| 175 | } | 194 | } | ||
| 176 | 195 | ||||
| 177 | // getSectionField retrieves a field value from a named section in the raw config map. | 196 | // getSectionField retrieves a field value from a named section in the raw config map. | ||