mirror of
https://github.com/fnproject/fn.git
synced 2022-10-28 21:29:17 +03:00
200 lines
5.2 KiB
Go
200 lines
5.2 KiB
Go
/*
|
|
Package envconfig implements a configuration reader which reads each value from an environment variable.
|
|
|
|
The basic idea is that you define a configuration struct, like this:
|
|
|
|
var conf struct {
|
|
Addr string
|
|
Port int
|
|
Auth struct {
|
|
Key string
|
|
Endpoint string
|
|
}
|
|
Partitions []int
|
|
Shards []struct {
|
|
Name string
|
|
Id int
|
|
}
|
|
}
|
|
|
|
Once you have that, you need to initialize the configuration:
|
|
|
|
if err := envconfig.Init(&conf); err != nil {
|
|
log.Fatalln(err)
|
|
}
|
|
|
|
Then it's just a matter of setting the environment variables when calling your binary:
|
|
|
|
ADDR=localhost PORT=6379 AUTH_KEY=foobar ./mybinary
|
|
|
|
Layout of the conf struct
|
|
|
|
Your conf struct must follow the following rules:
|
|
- no unexported fields by default (can turn off with Options.AllowUnexported)
|
|
- only supported types (no map fields for example)
|
|
|
|
Naming of the keys
|
|
|
|
By default, envconfig generates all possible keys based on the field chain according to a flexible naming scheme.
|
|
|
|
The field chain is how you access your field in the configuration struct. For example:
|
|
|
|
var conf struct {
|
|
Shard struct {
|
|
Name string
|
|
}
|
|
}
|
|
|
|
With that struct, you access the name field via the chain *Shard.Name*
|
|
|
|
The default naming scheme takes that and transforms it into the following:
|
|
- SHARD_NAME
|
|
- shard_name
|
|
|
|
It can handles more complicated cases, with multiple words in one field name. It needs to be in the correct case though, for example:
|
|
|
|
var conf struct {
|
|
Cassandra struct {
|
|
SSLCert string
|
|
SslKey string
|
|
}
|
|
}
|
|
|
|
With that struct, you access the name field via the chain *Cassandra.SSLCert* or *Cassandra.SslKey*
|
|
|
|
The default naming scheme takes that and transforms it into the following:
|
|
- CASSANDRA_SSL_CERT, cassandra_ssl_cert, CASSANDRA_SSLCERT, cassandra_sslcert
|
|
- CASSANDRA_SSL_KEY, cassandra_ssl_key, CASSANDRA_SSLKEY, cassandra_sslkey
|
|
|
|
And, if that is not good enough for you, you always have the option to use a custom key:
|
|
|
|
var conf struct {
|
|
Cassandra struct {
|
|
Name string `envconfig:"cassandraMyName"`
|
|
}
|
|
}
|
|
|
|
Now envconfig will only ever checks the environment variable _cassandraMyName_.
|
|
|
|
|
|
Content of the variables
|
|
|
|
There are three types of content for a single variable:
|
|
- for simple types, a single string representing the value, and parseable into the type.
|
|
- for slices or arrays, a comma-separated list of strings. Each string must be parseable into the element type of the slice or array.
|
|
- for structs, a comma-separated list of specially formatted strings representing structs.
|
|
|
|
Example of a valid slice value:
|
|
foo,bar,baz
|
|
|
|
The format for a struct is as follow:
|
|
- prefixed with {
|
|
- suffixed with }
|
|
- contains a comma-separated list of field values, in the order in which they are defined in the struct
|
|
|
|
Example of a valid struct value:
|
|
type MyStruct struct {
|
|
Name string
|
|
Id int
|
|
Timeout time.Duration
|
|
}
|
|
|
|
{foobar,10,120s}
|
|
|
|
Example of a valid slice of struct values:
|
|
{foobar,10,120s},{barbaz,20,50s}
|
|
|
|
Special case for bytes slices
|
|
|
|
For bytes slices, you generally don't want to type out a comma-separated list of byte values.
|
|
|
|
For this use case, we support base64 encoded values.
|
|
|
|
Here's an example:
|
|
|
|
var conf struct {
|
|
Data []byte
|
|
}
|
|
|
|
os.Setenv("DATA", "Rk9PQkFS")
|
|
|
|
This will decode DATA to FOOBAR and put that into conf.Data.
|
|
|
|
Optional values
|
|
|
|
Sometimes you don't absolutely need a value. Here's how we tell envconfig a value is optional:
|
|
|
|
var conf struct {
|
|
Name string `envconfig:"optional"`
|
|
Age int `envconfig:"-"`
|
|
}
|
|
|
|
The two syntax are equivalent.
|
|
|
|
Default values
|
|
|
|
Often times you have configuration keys which almost never changes, but you still want to be able to change them.
|
|
|
|
In such cases, you might want to provide a default value.
|
|
|
|
Here's to do this with envconfig:
|
|
|
|
var conf struct {
|
|
Timeout time.Duration `envconfig:"default=1m"`
|
|
}
|
|
|
|
Combining options
|
|
|
|
You can of course combine multiple options. The syntax is simple enough, separate each option with a comma.
|
|
|
|
For example:
|
|
|
|
var conf struct {
|
|
Timeout time.Duration `envconfig:"default=1m,myTimeout"`
|
|
}
|
|
|
|
This would give you the default timeout of 1 minute, and lookup the myTimeout environment variable.
|
|
|
|
Supported types
|
|
|
|
envconfig supports the following list of types:
|
|
|
|
- bool
|
|
- string
|
|
- intX
|
|
- uintX
|
|
- floatX
|
|
- time.Duration
|
|
- pointers to all of the above types
|
|
|
|
Notably, we don't (yet) support complex types simply because I had no use for it yet.
|
|
|
|
Custom unmarshaler
|
|
|
|
When the standard types are not enough, you will want to use a custom unmarshaler for your types.
|
|
|
|
You do this by implementing Unmarshaler on your type. Here's an example:
|
|
|
|
type connectionType uint
|
|
|
|
const (
|
|
tlsConnection connectionType = iota
|
|
insecureConnection
|
|
)
|
|
|
|
func (t *connectionType) Unmarshal(s string) error {
|
|
switch s {
|
|
case "tls":
|
|
*t = tlsConnection
|
|
case "insecure":
|
|
*t = insecureConnection
|
|
default:
|
|
return fmt.Errorf("unable to unmarshal %s to a connection type", s)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
*/
|
|
package envconfig
|