Documentation
¶
Overview ¶
Package cleanenv gives you a single tool to read application configuration from several sources with ease.
Features ¶
- read from several file formats (YAML, JSON, TOML, ENV, EDN) and parse into the internal structure;
- read environment variables into the internal structure;
- output environment variable list with descriptions into help output;
- custom variable readers (e.g. if you want to read from remote config server, etc).
Usage ¶
You can just prepare the config structure and fill it from the config file and environment variables.
type Config struct { Port string `yaml:"port" env:"PORT" env-default:"8080"` Host string `yaml:"host" env:"HOST" env-default:"localhost"` } var cfg Config ReadConfig("config.yml", &cfg)
Help output ¶
You can list all of your environment variables by means of help output:
type ConfigServer struct { Port string `env:"PORT" env-description:"server port"` Host string `env:"HOST" env-description:"server host"` } var cfg ConfigRemote help, err := cleanenv.GetDescription(&cfg, nil) if err != nil { ... } // setup help output f := flag.NewFlagSet("Example app", 1) fu := f.Usage f.Usage = func() { fu() envHelp, _ := cleanenv.GetDescription(&cfg, nil) fmt.Fprintln(f.Output()) fmt.Fprintln(f.Output(), envHelp) } f.Parse(os.Args[1:])
Then run go run main.go -h and the output will include:
Environment variables: PORT server port HOST server host
For more detailed information check examples and example tests.
Example (Setter) ¶
Example_setter uses type with a custom setter to parse environment variable data
package main import ( "fmt" "os" "github.com/aliy-turkois/cleanenv" ) // MyField is an example type with a custom setter type MyField string func (f *MyField) SetValue(s string) error { if s == "" { return fmt.Errorf("field value can't be empty") } *f = MyField("my field is: " + s) return nil } func (f MyField) String() string { return string(f) } func main() { type config struct { Default string `env:"ONE"` Custom MyField `env:"TWO"` } var cfg config os.Setenv("ONE", "test1") os.Setenv("TWO", "test2") cleanenv.ReadEnv(&cfg) fmt.Printf("%+v\n", cfg) }
Output: {Default:test1 Custom:my field is: test2}
Example (Updater) ¶
Example_updater uses a type with a custom updater
package main import ( "fmt" "os" "github.com/aliy-turkois/cleanenv" ) // ConfigUpdate is a type with a custom updater type ConfigUpdate struct { Default string `env:"DEFAULT"` Custom string } func (c *ConfigUpdate) Update() error { c.Custom = "custom" return nil } func main() { var cfg ConfigUpdate os.Setenv("DEFAULT", "default") cleanenv.ReadEnv(&cfg) fmt.Printf("%+v\n", cfg) }
Output: {Default:default Custom:custom}
Index ¶
- Constants
- func FUsage(w io.Writer, cfg interface{}, headerText *string, usageFuncs ...func()) func()
- func GetDescription(cfg interface{}, headerText *string) (string, error)
- func ReadConfig(path string, cfg interface{}) error
- func ReadConfigFS(fs fs.FS, path string, cfg interface{}) error
- func ReadEnv(cfg interface{}) error
- func UpdateEnv(cfg interface{}) error
- func Usage(cfg interface{}, headerText *string, usageFuncs ...func()) func()
- type Setter
- type Updater
Examples ¶
Constants ¶
const ( // Name of the environment variable or a list of names TagEnv = "env" // Value parsing layout (for types like time.Time) TagEnvLayout = "env-layout" // Default value TagEnvDefault = "env-default" // Custom list and map separator TagEnvSeparator = "env-separator" // Environment variable description TagEnvDescription = "env-description" // Flag to mark a field as updatable TagEnvUpd = "env-upd" // Flag to mark a field as required TagEnvRequired = "env-required" // Flag to specify prefix for structure fields TagEnvPrefix = "env-prefix" )
Supported tags
const (
// DefaultSeparator is a default list and map separator character
DefaultSeparator = ","
)
Variables ¶
This section is empty.
Functions ¶
func FUsage ¶
FUsage prints configuration help into the custom output. Other usage instructions can be wrapped in and executed before this usage function
func GetDescription ¶
GetDescription returns a description of environment variables. You can provide a custom header text.
Example ¶
ExampleGetDescription builds a description text from structure tags
package main import ( "fmt" "github.com/aliy-turkois/cleanenv" ) func main() { type config struct { One int64 `env:"ONE" env-description:"first parameter"` Two float64 `env:"TWO" env-description:"second parameter"` Three string `env:"THREE" env-description:"third parameter"` } var cfg config text, err := cleanenv.GetDescription(&cfg, nil) if err != nil { panic(err) } fmt.Println(text) }
Output: Environment variables: ONE int64 first parameter TWO float64 second parameter THREE string third parameter
Example (CustomHeaderText) ¶
ExampleGetDescription_customHeaderText builds a description text from structure tags with custom header string
package main import ( "fmt" "github.com/aliy-turkois/cleanenv" ) func main() { type config struct { One int64 `env:"ONE" env-description:"first parameter"` Two float64 `env:"TWO" env-description:"second parameter"` Three string `env:"THREE" env-description:"third parameter"` } var cfg config header := "Custom header text:" text, err := cleanenv.GetDescription(&cfg, &header) if err != nil { panic(err) } fmt.Println(text) }
Output: Custom header text: ONE int64 first parameter TWO float64 second parameter THREE string third parameter
Example (Defaults) ¶
ExampleGetDescription_defaults builds a description text from structure tags with description of default values
package main import ( "fmt" "github.com/aliy-turkois/cleanenv" ) func main() { type config struct { One int64 `env:"ONE" env-description:"first parameter" env-default:"1"` Two float64 `env:"TWO" env-description:"second parameter" env-default:"2.2"` Three string `env:"THREE" env-description:"third parameter" env-default:"test"` } var cfg config text, err := cleanenv.GetDescription(&cfg, nil) if err != nil { panic(err) } fmt.Println(text) }
Output: Environment variables: ONE int64 first parameter (default "1") TWO float64 second parameter (default "2.2") THREE string third parameter (default "test")
Example (VariableList) ¶
ExampleGetDescription_variableList builds a description text from structure tags with description of alternative variables
package main import ( "fmt" "github.com/aliy-turkois/cleanenv" ) func main() { type config struct { FirstVar int64 `env:"ONE,TWO,THREE" env-description:"first found parameter"` } var cfg config text, err := cleanenv.GetDescription(&cfg, nil) if err != nil { panic(err) } fmt.Println(text) }
Output: Environment variables: ONE int64 first found parameter TWO int64 (alternative to ONE) first found parameter THREE int64 (alternative to ONE) first found parameter
func ReadConfig ¶
ReadConfig reads configuration file and parses it depending on tags in structure provided. Then it reads and parses
Example:
type ConfigDatabase struct { Port string `yaml:"port" env:"PORT" env-default:"5432"` Host string `yaml:"host" env:"HOST" env-default:"localhost"` Name string `yaml:"name" env:"NAME" env-default:"postgres"` User string `yaml:"user" env:"USER" env-default:"user"` Password string `yaml:"password" env:"PASSWORD"` } var cfg ConfigDatabase err := cleanenv.ReadConfig("config.yml", &cfg) if err != nil { ... }
func ReadEnv ¶
func ReadEnv(cfg interface{}) error
ReadEnv reads environment variables into the structure.
Example ¶
ExampleReadEnv reads environment variables or default values into the structure
package main import ( "fmt" "os" "github.com/aliy-turkois/cleanenv" ) func main() { type config struct { Port string `env:"PORT" env-default:"5432"` Host string `env:"HOST" env-default:"localhost"` Name string `env:"NAME" env-default:"postgres"` User string `env:"USER" env-default:"user"` Password string `env:"PASSWORD"` } var cfg config os.Setenv("PORT", "5050") os.Setenv("NAME", "redis") os.Setenv("USER", "tester") os.Setenv("PASSWORD", "*****") cleanenv.ReadEnv(&cfg) fmt.Printf("%+v\n", cfg) }
Output: {Port:5050 Host:localhost Name:redis User:tester Password:*****}
func UpdateEnv ¶
func UpdateEnv(cfg interface{}) error
UpdateEnv rereads (updates) environment variables in the structure.
Example ¶
ExampleUpdateEnv updates variables in the configuration structure. Only variables with `env-upd:""` tag will be updated
package main import ( "fmt" "os" "github.com/aliy-turkois/cleanenv" ) func main() { type config struct { One int64 `env:"ONE"` Two int64 `env:"TWO" env-upd:""` } var cfg config // set environment variables os.Setenv("ONE", "1") os.Setenv("TWO", "2") // read environment variables into the structure cleanenv.ReadEnv(&cfg) fmt.Printf("%+v\n", cfg) // update environment variables os.Setenv("ONE", "11") os.Setenv("TWO", "22") // update only updatable environment variables in the structure cleanenv.UpdateEnv(&cfg) fmt.Printf("%+v\n", cfg) }
Output: {One:1 Two:2} {One:1 Two:22}
func Usage ¶
func Usage(cfg interface{}, headerText *string, usageFuncs ...func()) func()
Usage returns a configuration usage help. Other usage instructions can be wrapped in and executed before this usage function. The default output is STDERR.
Example ¶
package main import ( "flag" "os" "github.com/aliy-turkois/cleanenv" ) func main() { os.Stderr = os.Stdout //replace STDERR with STDOUT for test type config struct { One int64 `env:"ONE" env-description:"first parameter"` Two float64 `env:"TWO" env-description:"second parameter"` Three string `env:"THREE" env-description:"third parameter"` } // setup flags fset := flag.NewFlagSet("Example", flag.ContinueOnError) fset.String("p", "8080", "service port") fset.String("h", "localhost", "service host") var cfg config customHeader := "My sweet variables:" // get config usage with wrapped flag usage and custom header string u := cleanenv.Usage(&cfg, &customHeader, fset.Usage) // print usage to STDERR u() }
Output: Usage of Example: -h string service host (default "localhost") -p string service port (default "8080") My sweet variables: ONE int64 first parameter TWO float64 second parameter THREE string third parameter
Types ¶
type Setter ¶
Setter is an interface for a custom value setter.
To implement a custom value setter you need to add a SetValue function to your type that will receive a string raw value:
type MyField string func (f *MyField) SetValue(s string) error { if s == "" { return fmt.Errorf("field value can't be empty") } *f = MyField("my field is: " + s) return nil }