// Package config provides shared config loading and environment override helpers. package config import ( "errors" "os" "strconv" "strings" "time" "hyapp/pkg/configx" ) // Validator lets a service config enforce cross-field invariants after file and env overrides are applied. type Validator interface { Validate() error } // LoadYAML loads YAML into out and calls Validate when the target config implements Validator. func LoadYAML(path string, out any) error { if strings.TrimSpace(path) == "" { return errors.New("config path is required") } if out == nil { return errors.New("config target is required") } if err := configx.LoadYAML(path, out); err != nil { return err } if validator, ok := out.(Validator); ok { return validator.Validate() } return nil } // OverrideStringFromEnv replaces target when envName exists and is not blank. func OverrideStringFromEnv(target *string, envName string) { if target == nil || strings.TrimSpace(envName) == "" { return } if value, ok := os.LookupEnv(envName); ok && strings.TrimSpace(value) != "" { *target = strings.TrimSpace(value) } } // OverrideBoolFromEnv parses a bool environment value into target when envName exists. func OverrideBoolFromEnv(target *bool, envName string) error { if target == nil || strings.TrimSpace(envName) == "" { return nil } value, ok := os.LookupEnv(envName) if !ok || strings.TrimSpace(value) == "" { return nil } parsed, err := strconv.ParseBool(strings.TrimSpace(value)) if err != nil { return err } *target = parsed return nil } // OverrideDurationFromEnv parses a Go duration environment value into target when envName exists. func OverrideDurationFromEnv(target *time.Duration, envName string) error { if target == nil || strings.TrimSpace(envName) == "" { return nil } value, ok := os.LookupEnv(envName) if !ok || strings.TrimSpace(value) == "" { return nil } parsed, err := time.ParseDuration(strings.TrimSpace(value)) if err != nil { return err } *target = parsed return nil }