package config import ( "fmt" "github.com/urfave/cli/v2" "gopkg.in/yaml.v3" "os" "reflect" ) const cliMetaKey = "cli.config" type IConfig interface { Invalidate() error } func Invalidate(config IConfig) error { if config == nil { return fmt.Errorf("config must not be a nil") } val := reflect.ValueOf(config) if val.Kind() != reflect.Struct { if val.IsZero() { return fmt.Errorf("config is empty") } val = reflect.ValueOf(config).Elem() } for i := 0; i < val.NumField(); i++ { if !val.Field(i).CanInterface() || val.Field(i).IsZero() { continue } if elm, ok := val.Field(i).Interface().(IConfig); ok { if er := elm.Invalidate(); er != nil { return er } } } return nil } func ReadConfig[T IConfig](path string) (*T, error) { var ( cfg = new(T) fd []byte err error ) if fd, err = os.ReadFile(path); err != nil { return nil, err } if err = yaml.Unmarshal(fd, cfg); err != nil { return nil, err } if err = Invalidate(*cfg); err != nil { return nil, err } return cfg, nil } func LoadConfig[T IConfig](ctx *cli.Context, path cli.Path) error { cfg, err := ReadConfig[T](path) if err != nil { return fmt.Errorf("could not load config from: %s; %v", path, err) } if cfg == nil { return fmt.Errorf("could not load config from: %s", path) } ctx.App.Metadata[cliMetaKey] = cfg return nil }