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 }