mirror of
https://github.com/stashapp/stash.git
synced 2025-12-18 04:44:37 +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:
@@ -8,8 +8,10 @@ import (
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/knadh/koanf"
|
||||
"github.com/knadh/koanf/providers/env"
|
||||
"github.com/knadh/koanf/providers/posflag"
|
||||
"github.com/spf13/pflag"
|
||||
"github.com/spf13/viper"
|
||||
|
||||
"github.com/stashapp/stash/pkg/fsutil"
|
||||
"github.com/stashapp/stash/pkg/logger"
|
||||
@@ -20,7 +22,30 @@ type flagStruct struct {
|
||||
nobrowser bool
|
||||
}
|
||||
|
||||
var flags flagStruct
|
||||
var (
|
||||
flags flagStruct
|
||||
|
||||
homeDir, _ = os.UserHomeDir()
|
||||
|
||||
defaultConfigLocations = []string{
|
||||
"config.yml",
|
||||
filepath.Join(homeDir, ".stash", "config.yml"),
|
||||
}
|
||||
|
||||
// map of env vars to config keys
|
||||
envBinds = map[string]string{
|
||||
"host": Host,
|
||||
"port": Port,
|
||||
"external_host": ExternalHost,
|
||||
"generated": Generated,
|
||||
"metadata": Metadata,
|
||||
"cache": Cache,
|
||||
"stash": Stash,
|
||||
"ui": UILocation,
|
||||
}
|
||||
)
|
||||
|
||||
var errConfigNotFound = errors.New("config file not found")
|
||||
|
||||
func init() {
|
||||
pflag.IP("host", net.IPv4(0, 0, 0, 0), "ip address for the host")
|
||||
@@ -33,8 +58,8 @@ func init() {
|
||||
// Called at startup
|
||||
func Initialize() (*Config, error) {
|
||||
cfg := &Config{
|
||||
main: viper.New(),
|
||||
overrides: viper.New(),
|
||||
main: koanf.New("."),
|
||||
overrides: koanf.New("."),
|
||||
}
|
||||
|
||||
cfg.initOverrides()
|
||||
@@ -77,54 +102,49 @@ func Initialize() (*Config, error) {
|
||||
// Called by tests to initialize an empty config
|
||||
func InitializeEmpty() *Config {
|
||||
cfg := &Config{
|
||||
main: viper.New(),
|
||||
overrides: viper.New(),
|
||||
main: koanf.New("."),
|
||||
overrides: koanf.New("."),
|
||||
}
|
||||
instance = cfg
|
||||
return instance
|
||||
}
|
||||
|
||||
func bindEnv(v *viper.Viper, key ...string) {
|
||||
if err := v.BindEnv(key...); err != nil {
|
||||
panic(fmt.Sprintf("unable to set environment key (%v): %v", key, err))
|
||||
func (i *Config) loadFromCommandLine() {
|
||||
v := i.overrides
|
||||
|
||||
if err := v.Load(posflag.ProviderWithFlag(pflag.CommandLine, ".", v, func(f *pflag.Flag) (string, interface{}) {
|
||||
// ignore flags that have not been changed
|
||||
if !f.Changed {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
return f.Name, posflag.FlagVal(pflag.CommandLine, f)
|
||||
}), nil); err != nil {
|
||||
logger.Errorf("failed to load flags: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func (i *Config) loadFromEnv() {
|
||||
v := i.overrides
|
||||
|
||||
if err := v.Load(env.ProviderWithValue("STASH_", ".", func(key, value string) (string, interface{}) {
|
||||
key = strings.ToLower(strings.TrimPrefix(key, "STASH_"))
|
||||
if newKey, ok := envBinds[key]; ok {
|
||||
return newKey, value
|
||||
}
|
||||
|
||||
return "", nil
|
||||
}), nil); err != nil {
|
||||
logger.Errorf("failed to load envs: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func (i *Config) initOverrides() {
|
||||
v := i.overrides
|
||||
|
||||
// replace dashes with underscores in the flag names
|
||||
normalizeFn := pflag.CommandLine.GetNormalizeFunc()
|
||||
pflag.CommandLine.SetNormalizeFunc(func(f *pflag.FlagSet, name string) pflag.NormalizedName {
|
||||
result := normalizeFn(f, name)
|
||||
name = strings.ReplaceAll(string(result), "-", "_")
|
||||
return pflag.NormalizedName(name)
|
||||
})
|
||||
|
||||
if err := v.BindPFlags(pflag.CommandLine); err != nil {
|
||||
logger.Infof("failed to bind flags: %v", err)
|
||||
}
|
||||
|
||||
v.SetEnvPrefix("stash") // will be uppercased automatically
|
||||
bindEnv(v, "host") // STASH_HOST
|
||||
bindEnv(v, "port") // STASH_PORT
|
||||
bindEnv(v, "external_host") // STASH_EXTERNAL_HOST
|
||||
bindEnv(v, "generated") // STASH_GENERATED
|
||||
bindEnv(v, "metadata") // STASH_METADATA
|
||||
bindEnv(v, "cache") // STASH_CACHE
|
||||
bindEnv(v, "stash") // STASH_STASH
|
||||
bindEnv(v, "ui_location", "STASH_UI") // STASH_UI
|
||||
i.loadFromCommandLine()
|
||||
i.loadFromEnv()
|
||||
}
|
||||
|
||||
func (i *Config) initConfig() error {
|
||||
v := i.main
|
||||
|
||||
// The config file is called config. Leave off the file extension.
|
||||
v.SetConfigName("config")
|
||||
|
||||
v.AddConfigPath(".") // Look for config in the working directory
|
||||
v.AddConfigPath(filepath.FromSlash("$HOME/.stash")) // Look for the config in the home directory
|
||||
|
||||
configFile := ""
|
||||
envConfigFile := os.Getenv("STASH_CONFIG_FILE")
|
||||
|
||||
@@ -135,8 +155,6 @@ func (i *Config) initConfig() error {
|
||||
}
|
||||
|
||||
if configFile != "" {
|
||||
v.SetConfigFile(configFile)
|
||||
|
||||
// if file does not exist, assume it is a new system
|
||||
if exists, _ := fsutil.FileExists(configFile); !exists {
|
||||
i.isNewSystem = true
|
||||
@@ -150,18 +168,33 @@ func (i *Config) initConfig() error {
|
||||
}
|
||||
|
||||
return nil
|
||||
} else {
|
||||
// load from provided config file
|
||||
if err := i.loadFirstFromFiles([]string{configFile}); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// load from default locations
|
||||
if err := i.loadFirstFromFiles(defaultConfigLocations); err != nil {
|
||||
if errors.Is(err, errConfigNotFound) {
|
||||
i.isNewSystem = true
|
||||
return nil
|
||||
}
|
||||
|
||||
err := v.ReadInConfig() // Find and read the config file
|
||||
// if not found, assume its a new system
|
||||
var notFoundErr viper.ConfigFileNotFoundError
|
||||
if errors.As(err, ¬FoundErr) {
|
||||
i.isNewSystem = true
|
||||
return nil
|
||||
} else if err != nil {
|
||||
return err
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (i *Config) loadFirstFromFiles(f []string) error {
|
||||
for _, ff := range f {
|
||||
if exists, _ := fsutil.FileExists(ff); exists {
|
||||
return i.load(ff)
|
||||
}
|
||||
}
|
||||
|
||||
return errConfigNotFound
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user