mirror of
https://github.com/stashapp/stash.git
synced 2025-12-16 20:07:05 +03:00
Replace viper with koanf (#4845)
* Migrate to koanf * Use temp logger for crashes before config is initialised * Remove snake case hacks * Add migration for config file keys * Add migration note for new migration * Renamed viper functions * Remove front-end viper workaround * Correctly default scan options
This commit is contained in:
@@ -30,7 +30,7 @@ const (
|
||||
dbConnTimeout = 30
|
||||
)
|
||||
|
||||
var appSchemaVersion uint = 57
|
||||
var appSchemaVersion uint = 58
|
||||
|
||||
//go:embed migrations/*.sql
|
||||
var migrationsBox embed.FS
|
||||
|
||||
1
pkg/sqlite/migrations/58_config_correct.up.sql
Normal file
1
pkg/sqlite/migrations/58_config_correct.up.sql
Normal file
@@ -0,0 +1 @@
|
||||
-- no schema changes
|
||||
143
pkg/sqlite/migrations/58_postmigrate.go
Normal file
143
pkg/sqlite/migrations/58_postmigrate.go
Normal file
@@ -0,0 +1,143 @@
|
||||
package migrations
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"time"
|
||||
"unicode"
|
||||
|
||||
"github.com/jmoiron/sqlx"
|
||||
"github.com/spf13/cast"
|
||||
"github.com/stashapp/stash/internal/manager/config"
|
||||
"github.com/stashapp/stash/pkg/logger"
|
||||
"github.com/stashapp/stash/pkg/sqlite"
|
||||
)
|
||||
|
||||
type schema58Migrator struct {
|
||||
migrator
|
||||
}
|
||||
|
||||
func post58(ctx context.Context, db *sqlx.DB) error {
|
||||
logger.Info("Running post-migration for schema version 58")
|
||||
|
||||
m := schema58Migrator{
|
||||
migrator: migrator{
|
||||
db: db,
|
||||
},
|
||||
}
|
||||
|
||||
return m.migrate()
|
||||
}
|
||||
|
||||
func (m *schema58Migrator) migrate() error {
|
||||
if err := m.migrateConfig(); err != nil {
|
||||
return fmt.Errorf("failed to migrate config: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// fromSnakeCase converts a string from snake_case to camelCase
|
||||
func (m *schema58Migrator) fromSnakeCase(v string) string {
|
||||
var buf bytes.Buffer
|
||||
leadingUnderscore := true
|
||||
capvar := false
|
||||
for i, c := range v {
|
||||
switch {
|
||||
case c == '_' && !leadingUnderscore && i > 0:
|
||||
capvar = true
|
||||
case c == '_' && leadingUnderscore:
|
||||
buf.WriteRune(c)
|
||||
case capvar:
|
||||
buf.WriteRune(unicode.ToUpper(c))
|
||||
capvar = false
|
||||
default:
|
||||
leadingUnderscore = false
|
||||
buf.WriteRune(c)
|
||||
}
|
||||
}
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
// fromSnakeCaseMap recursively converts a map using snake_case keys to camelCase keys
|
||||
func (m *schema58Migrator) fromSnakeCaseMap(mm map[string]interface{}) map[string]interface{} {
|
||||
return m.fromSnakeCaseValue(mm).(map[string]interface{})
|
||||
}
|
||||
|
||||
func (m *schema58Migrator) fromSnakeCaseValue(val interface{}) interface{} {
|
||||
switch v := val.(type) {
|
||||
case map[interface{}]interface{}:
|
||||
ret := cast.ToStringMap(v)
|
||||
for k, vv := range ret {
|
||||
adjKey := m.fromSnakeCase(k)
|
||||
ret[adjKey] = m.fromSnakeCaseValue(vv)
|
||||
}
|
||||
return ret
|
||||
case map[string]interface{}:
|
||||
ret := make(map[string]interface{})
|
||||
for k, vv := range v {
|
||||
adjKey := m.fromSnakeCase(k)
|
||||
ret[adjKey] = m.fromSnakeCaseValue(vv)
|
||||
}
|
||||
return ret
|
||||
case []interface{}:
|
||||
ret := make([]interface{}, len(v))
|
||||
for i, vv := range v {
|
||||
ret[i] = m.fromSnakeCaseValue(vv)
|
||||
}
|
||||
return ret
|
||||
default:
|
||||
return v
|
||||
}
|
||||
}
|
||||
|
||||
func (m *schema58Migrator) migrateConfig() error {
|
||||
c := config.GetInstance()
|
||||
|
||||
orgPath := c.GetConfigFile()
|
||||
|
||||
if orgPath == "" {
|
||||
// no config file to migrate (usually in a test)
|
||||
return nil
|
||||
}
|
||||
|
||||
// save a backup of the original config file
|
||||
backupPath := fmt.Sprintf("%s.57.%s", orgPath, time.Now().Format("20060102_150405"))
|
||||
|
||||
data, err := c.Marshal()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to marshal backup config: %w", err)
|
||||
}
|
||||
|
||||
logger.Infof("Backing up config to %s", backupPath)
|
||||
if err := os.WriteFile(backupPath, data, 0644); err != nil {
|
||||
return fmt.Errorf("failed to write backup config: %w", err)
|
||||
}
|
||||
|
||||
// migrate the plugin and UI configs from snake_case to camelCase
|
||||
ui := c.GetUIConfiguration()
|
||||
if ui != nil {
|
||||
ui = m.fromSnakeCaseMap(ui)
|
||||
c.SetUIConfiguration(ui)
|
||||
}
|
||||
|
||||
plugins := c.GetAllPluginConfiguration()
|
||||
newPlugins := make(map[string]interface{})
|
||||
for key, value := range plugins {
|
||||
key = m.fromSnakeCase(key)
|
||||
newPlugins[key] = m.fromSnakeCaseMap(value)
|
||||
}
|
||||
|
||||
c.Set(config.PluginsSetting, newPlugins)
|
||||
if err := c.Write(); err != nil {
|
||||
return fmt.Errorf("failed to write config: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func init() {
|
||||
sqlite.RegisterPostMigration(58, post58)
|
||||
}
|
||||
Reference in New Issue
Block a user