forked from ebhomengo/niki
1
0
Fork 0
niki/vendor/github.com/knadh/koanf/providers/env/env.go

166 lines
2.7 KiB
Go
Raw Normal View History

2024-02-18 10:42:21 +00:00
// Package env implements a koanf.Provider that reads environment
2024-02-18 10:42:21 +00:00
// variables as conf maps.
2024-02-18 10:42:21 +00:00
package env
import (
"errors"
"os"
"strings"
"github.com/knadh/koanf/maps"
)
// Env implements an environment variables provider.
2024-02-18 10:42:21 +00:00
type Env struct {
prefix string
delim string
cb func(key string, value string) (string, interface{})
2024-02-18 10:42:21 +00:00
}
// Provider returns an environment variables provider that returns
2024-02-18 10:42:21 +00:00
// a nested map[string]interface{} of environment variable where the
2024-02-18 10:42:21 +00:00
// nesting hierarchy of keys is defined by delim. For instance, the
2024-02-18 10:42:21 +00:00
// delim "." will convert the key `parent.child.key: 1`
2024-02-18 10:42:21 +00:00
// to `{parent: {child: {key: 1}}}`.
2024-02-18 10:42:21 +00:00
//
2024-02-18 10:42:21 +00:00
// If prefix is specified (case-sensitive), only the env vars with
2024-02-18 10:42:21 +00:00
// the prefix are captured. cb is an optional callback that takes
2024-02-18 10:42:21 +00:00
// a string and returns a string (the env variable name) in case
2024-02-18 10:42:21 +00:00
// transformations have to be applied, for instance, to lowercase
2024-02-18 10:42:21 +00:00
// everything, strip prefixes and replace _ with . etc.
2024-02-18 10:42:21 +00:00
// If the callback returns an empty string, the variable will be
2024-02-18 10:42:21 +00:00
// ignored.
2024-02-18 10:42:21 +00:00
func Provider(prefix, delim string, cb func(s string) string) *Env {
2024-02-18 10:42:21 +00:00
e := &Env{
2024-02-18 10:42:21 +00:00
prefix: prefix,
delim: delim,
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
if cb != nil {
2024-02-18 10:42:21 +00:00
e.cb = func(key string, value string) (string, interface{}) {
2024-02-18 10:42:21 +00:00
return cb(key), value
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
return e
2024-02-18 10:42:21 +00:00
}
// ProviderWithValue works exactly the same as Provider except the callback
2024-02-18 10:42:21 +00:00
// takes a (key, value) with the variable name and value and allows you
2024-02-18 10:42:21 +00:00
// to modify both. This is useful for cases where you may want to return
2024-02-18 10:42:21 +00:00
// other types like a string slice instead of just a string.
2024-02-18 10:42:21 +00:00
func ProviderWithValue(prefix, delim string, cb func(key string, value string) (string, interface{})) *Env {
2024-02-18 10:42:21 +00:00
return &Env{
2024-02-18 10:42:21 +00:00
prefix: prefix,
delim: delim,
cb: cb,
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
}
// ReadBytes is not supported by the env provider.
2024-02-18 10:42:21 +00:00
func (e *Env) ReadBytes() ([]byte, error) {
2024-02-18 10:42:21 +00:00
return nil, errors.New("env provider does not support this method")
2024-02-18 10:42:21 +00:00
}
// Read reads all available environment variables into a key:value map
2024-02-18 10:42:21 +00:00
// and returns it.
2024-02-18 10:42:21 +00:00
func (e *Env) Read() (map[string]interface{}, error) {
2024-02-18 10:42:21 +00:00
// Collect the environment variable keys.
2024-02-18 10:42:21 +00:00
var keys []string
2024-02-18 10:42:21 +00:00
for _, k := range os.Environ() {
2024-02-18 10:42:21 +00:00
if e.prefix != "" {
2024-02-18 10:42:21 +00:00
if strings.HasPrefix(k, e.prefix) {
2024-02-18 10:42:21 +00:00
keys = append(keys, k)
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
} else {
2024-02-18 10:42:21 +00:00
keys = append(keys, k)
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
}
mp := make(map[string]interface{})
2024-02-18 10:42:21 +00:00
for _, k := range keys {
2024-02-18 10:42:21 +00:00
parts := strings.SplitN(k, "=", 2)
// If there's a transformation callback,
2024-02-18 10:42:21 +00:00
// run it through every key/value.
2024-02-18 10:42:21 +00:00
if e.cb != nil {
2024-02-18 10:42:21 +00:00
key, value := e.cb(parts[0], parts[1])
2024-02-18 10:42:21 +00:00
// If the callback blanked the key, it should be omitted
2024-02-18 10:42:21 +00:00
if key == "" {
2024-02-18 10:42:21 +00:00
continue
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
mp[key] = value
2024-02-18 10:42:21 +00:00
} else {
2024-02-18 10:42:21 +00:00
mp[parts[0]] = parts[1]
2024-02-18 10:42:21 +00:00
}
}
return maps.Unflatten(mp, e.delim), nil
2024-02-18 10:42:21 +00:00
}