Files
at-container-registry/pkg/config/viper.go

81 lines
2.3 KiB
Go

package config
import (
"reflect"
"strings"
"time"
"github.com/go-viper/mapstructure/v2"
"github.com/spf13/viper"
)
// NewViper creates a configured Viper instance with common settings.
// prefix is the env var prefix (e.g., "ATCR" or "HOLD").
// yamlPath is the optional YAML config file path (empty = env-only).
func NewViper(prefix string, yamlPath string) *viper.Viper {
v := viper.New()
// Env prefix: ATCR_ or HOLD_
v.SetEnvPrefix(prefix)
// Map YAML dots/dashes to env underscores: server.base_url -> ATCR_SERVER_BASE_URL
v.SetEnvKeyReplacer(strings.NewReplacer(".", "_", "-", "_"))
// Enable automatic env var binding
v.AutomaticEnv()
// Bind shared log shipper env vars (no service prefix)
BindLogShipper(v)
// Load YAML config file if provided
if yamlPath != "" {
v.SetConfigFile(yamlPath)
// Ignore missing file — env-only is valid
_ = v.ReadInConfig()
}
return v
}
// BindLogShipper registers BindEnv calls for shared (unprefixed) log shipper env vars.
func BindLogShipper(v *viper.Viper) {
_ = v.BindEnv("log_shipper.backend", "LOG_SHIPPER_BACKEND")
_ = v.BindEnv("log_shipper.url", "LOG_SHIPPER_URL")
_ = v.BindEnv("log_shipper.batch_size", "LOG_SHIPPER_BATCH_SIZE")
_ = v.BindEnv("log_shipper.flush_interval", "LOG_SHIPPER_FLUSH_INTERVAL")
_ = v.BindEnv("log_shipper.username", "LOG_SHIPPER_USERNAME")
_ = v.BindEnv("log_shipper.password", "LOG_SHIPPER_PASSWORD")
}
// UnmarshalOption returns the Viper decoder option that uses yaml struct tags
// and supports time.Duration string parsing.
func UnmarshalOption() viper.DecoderConfigOption {
return viper.DecoderConfigOption(func(dc *mapstructure.DecoderConfig) {
dc.TagName = "yaml"
dc.DecodeHook = mapstructure.ComposeDecodeHookFunc(
dc.DecodeHook,
StringToTimeDurationHook(),
)
})
}
// StringToTimeDurationHook returns a mapstructure DecodeHookFunc that converts
// string values to time.Duration. This handles env vars like "15m" or "5s".
func StringToTimeDurationHook() mapstructure.DecodeHookFunc {
return func(from reflect.Type, to reflect.Type, data any) (any, error) {
if from.Kind() != reflect.String {
return data, nil
}
if to != reflect.TypeOf(time.Duration(0)) {
return data, nil
}
s := data.(string)
if s == "" {
return time.Duration(0), nil
}
return time.ParseDuration(s)
}
}