feat(config): some additional config options, and config migration from deprecated keys

This commit is contained in:
Lewis Wynne 2026-02-12 19:31:24 +00:00
parent 629358a81b
commit 4e78cefd56
16 changed files with 363 additions and 51 deletions

92
cmd/config_migrate.go Normal file
View file

@ -0,0 +1,92 @@
package cmd
import "strings"
type deprecation struct {
Old string // e.g. "list.list_all_stores"
New string // e.g. "list.always_show_all_stores"
}
type migration struct {
Old string // key that was removed
New string // key that holds the value
Conflict bool // both old and new were present; new key wins
}
var deprecations = []deprecation{
{"list.list_all_stores", "list.always_show_all_stores"},
}
func migrateRawConfig(raw map[string]any) []migration {
var migrations []migration
for _, dep := range deprecations {
oldParts := strings.Split(dep.Old, ".")
newParts := strings.Split(dep.New, ".")
_, ok := nestedGet(raw, oldParts)
if !ok {
continue
}
m := migration{Old: dep.Old, New: dep.New}
if _, exists := nestedGet(raw, newParts); exists {
m.Conflict = true
} else {
nestedSet(raw, newParts, nestedMustGet(raw, oldParts))
}
nestedDelete(raw, oldParts)
migrations = append(migrations, m)
}
return migrations
}
func nestedMustGet(m map[string]any, parts []string) any {
v, _ := nestedGet(m, parts)
return v
}
func nestedGet(m map[string]any, parts []string) (any, bool) {
for i, p := range parts {
v, ok := m[p]
if !ok {
return nil, false
}
if i == len(parts)-1 {
return v, true
}
sub, ok := v.(map[string]any)
if !ok {
return nil, false
}
m = sub
}
return nil, false
}
func nestedSet(m map[string]any, parts []string, val any) {
for i, p := range parts {
if i == len(parts)-1 {
m[p] = val
return
}
sub, ok := m[p].(map[string]any)
if !ok {
sub = make(map[string]any)
m[p] = sub
}
m = sub
}
}
func nestedDelete(m map[string]any, parts []string) {
for i, p := range parts {
if i == len(parts)-1 {
delete(m, p)
return
}
sub, ok := m[p].(map[string]any)
if !ok {
return
}
m = sub
}
}