112 lines
2.8 KiB
Go
112 lines
2.8 KiB
Go
package config
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"os/user"
|
|
"path/filepath"
|
|
"reflect"
|
|
|
|
"github.com/creasty/defaults"
|
|
"gopkg.in/yaml.v3"
|
|
"scm.yoorie.de/go-lib/util"
|
|
)
|
|
|
|
func GetConfigurationFiles(appName string) []string {
|
|
// First checking local config
|
|
executablePath, executableErr := os.Executable()
|
|
if executableErr != nil {
|
|
executablePath = os.Args[0]
|
|
}
|
|
fname := filepath.Base(executablePath)
|
|
fext := filepath.Ext(executablePath)
|
|
fdir := filepath.Dir(executablePath)
|
|
fnameWoExt := fname[0 : len(fname)-len(fext)]
|
|
ymlExts := [2]string{".yml", ".yaml"}
|
|
fileNames := make([]string, 0, 4)
|
|
for _, ext := range ymlExts {
|
|
fileNames = append(fileNames, filepath.Join(fdir, fnameWoExt+ext))
|
|
}
|
|
homeDir := "."
|
|
if usr, userErr := user.Current(); userErr == nil {
|
|
homeDir = usr.HomeDir
|
|
}
|
|
fileNames = append(fileNames, filepath.Join(homeDir, "."+appName, "config"))
|
|
// Check for global config
|
|
fileNames = append(fileNames, util.GetGlobalConfigurationFile(appName, "config"))
|
|
return fileNames
|
|
}
|
|
|
|
func GetConfigurationFile(appName string) string {
|
|
// First checking local config
|
|
files := GetConfigurationFiles(appName)
|
|
for _, localConfigFile := range files {
|
|
if util.FileExists(localConfigFile) {
|
|
return localConfigFile
|
|
}
|
|
}
|
|
return ""
|
|
}
|
|
|
|
func LoadConfiguration[T any](config T) error {
|
|
return LoadConfigurationFromFile(config, "")
|
|
}
|
|
|
|
func resolveConfigFile[T any](config T, configFile string) (string, error) {
|
|
if configFile != "" {
|
|
if !util.FileExists(configFile) {
|
|
return "", fmt.Errorf("given configuration file %s cannot be found", configFile)
|
|
}
|
|
return configFile, nil
|
|
}
|
|
|
|
appName := getAppNameFromConfig(config)
|
|
if appName == "" {
|
|
return "", nil
|
|
}
|
|
return GetConfigurationFile(appName), nil
|
|
}
|
|
|
|
func getAppNameFromConfig[T any](config T) string {
|
|
method := reflect.ValueOf(config).MethodByName("AppName")
|
|
if !method.IsValid() {
|
|
return ""
|
|
}
|
|
results := method.Call(nil)
|
|
if len(results) == 0 {
|
|
return ""
|
|
}
|
|
return results[0].String()
|
|
}
|
|
|
|
func IsStructPointer[T any](config T) bool {
|
|
value := reflect.ValueOf(config)
|
|
return value.Type().Kind() == reflect.Pointer && reflect.Indirect(value).Type().Kind() == reflect.Struct
|
|
}
|
|
|
|
func LoadConfigurationFromFile[T any](config T, configFile string) error {
|
|
if !IsStructPointer(config) {
|
|
genericType := reflect.TypeOf(config)
|
|
return fmt.Errorf("type: %s.%s is not a struct pointer", genericType.PkgPath(), genericType.Name())
|
|
}
|
|
defaults.Set(config)
|
|
|
|
resolvedConfigFile, err := resolveConfigFile(config, configFile)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if resolvedConfigFile == "" {
|
|
return nil
|
|
}
|
|
ymldata, err := os.ReadFile(resolvedConfigFile)
|
|
if err != nil {
|
|
return fmt.Errorf("cannot read configuration file %s: %w", resolvedConfigFile, err)
|
|
}
|
|
err = yaml.Unmarshal(ymldata, config)
|
|
if err != nil {
|
|
return fmt.Errorf("error unmarshalling configuration data: %w", err)
|
|
}
|
|
return nil
|
|
}
|