package config import ( "errors" "fmt" "os" "reflect" "strconv" "strings" ) func getEnvVar(value reflect.Value, rtype reflect.Type, counter int, prefix string) error { if value.Kind() != reflect.Ptr { return errors.New("not a pointer value") } f := reflect.StructField{} if counter != -1 { f = rtype.Field(counter) } value = reflect.Indirect(value) fName := strings.ToUpper(f.Name) if prefix != "" { prefix = strings.TrimLeft(prefix, "_") } env := os.Getenv(prefix + fName) if err := selector(env, &value); err != nil { return fmt.Errorf("could set value: %w", err) } if value.Kind() == reflect.Struct { for i := 0; i < value.NumField(); i++ { if err := getEnvVar(value.Field(i).Addr(), value.Type(), i, prefix+fName+"_"); err != nil { return fmt.Errorf("could not apply env var: %w", err) } } } return nil } func parseToStruct(value reflect.Value, rtype reflect.Type, counter int, prefix string, index map[string]string) error { if value.Kind() != reflect.Ptr { return errors.New("not a pointer value") } f := reflect.StructField{} if counter != -1 { f = rtype.Field(counter) } value = reflect.Indirect(value) fName := strings.ToLower(f.Name) if prefix != "" { prefix = strings.TrimLeft(prefix, ".") } env := index[prefix+fName] if err := selector(env, &value); err != nil { return fmt.Errorf("could set value: %w", err) } if value.Kind() == reflect.Struct { for i := 0; i < value.NumField(); i++ { if err := parseToStruct(value.Field(i).Addr(), value.Type(), i, prefix+fName+".", index); err != nil { return fmt.Errorf("could not apply env var: %w", err) } } } return nil } func selector(env string, value *reflect.Value) error { if env != "" { //nolint:exhaustive switch value.Kind() { case reflect.Int: envI, err := strconv.Atoi(env) if err != nil { return fmt.Errorf("could not parse to int: %w", err) } value.SetInt(int64(envI)) case reflect.String: value.SetString(env) case reflect.Bool: envB, err := strconv.ParseBool(env) if err != nil { return fmt.Errorf("could not parse bool: %w", err) } value.SetBool(envB) } } return nil }