// Run with go run ./examples/configuration -format xml, or -config /path/to/app.yaml. package main import ( "embed" "flag" "fmt" "os" "path/filepath" "time" "git.yuntuo.hk/k2safe/go-omni/config" ) //go:embed config.json config.yaml config.xml var examples embed.FS type ClientConfig struct { Endpoint string `json:"endpoint"` Timeout time.Duration `json:"timeout" envDefault:"3s"` // This field is deliberately unavailable to configuration files. Token string `json:"-" env:"DEMO_CLIENT_TOKEN,secret"` } type Config struct { Client ClientConfig `json:"client"` MaxItems int `json:"maxItems" envDefault:"20"` Allowed []string `json:"allowed"` } func (c Config) Validate() error { if c.Client.Timeout <= 0 { return config.Invalid("client.timeout", "must be positive") } if c.MaxItems < 0 { return config.Invalid("maxItems", "must not be negative") } return nil } func newLoader() (*config.Loader, error) { // Example of an instance-local extension. A TOML/etc. adapter can implement // Decoder and return Document using that parser instead; no global registry. return config.NewLoader(config.WithDecoder("custom", config.DecoderFunc(func(data []byte) (config.Document, error) { return (config.JSONDecoder{}).Decode(data) }))) } func load(path string) (Config, error) { loader, err := newLoader() if err != nil { return Config{}, err } return config.LoadProject(path, Config{}, config.EnvOptions{Prefix: "DEMO_", Empty: "reject"}, loader) } func run() error { path := flag.String("config", "", "external configuration file") format := flag.String("format", "yaml", "embedded example: json, yaml, xml") flag.Parse() if *path == "" { data, err := examples.ReadFile("config." + *format) if err != nil { return fmt.Errorf("choose json, yaml or xml") } dir, err := os.MkdirTemp("", "goOmniConfiguration-") if err != nil { return err } defer os.RemoveAll(dir) *path = filepath.Join(dir, "config."+*format) if err = os.WriteFile(*path, data, 0600); err != nil { return err } } cfg, err := load(*path) if err != nil { return err } // Print selected non-sensitive fields, never the whole configuration. fmt.Printf("timeout=%s maxItems=%d allowed=%v\n", cfg.Client.Timeout, cfg.MaxItems, cfg.Allowed) return nil } func main() { if err := run(); err != nil { fmt.Fprintln(os.Stderr, err) os.Exit(1) } }