├── README.md ├── envconfig_test.go ├── value.go └── envconfig.go /README.md: -------------------------------------------------------------------------------- 1 | # envconfig 2 | Package for defining configuration based on environment variables. Sort of a cross between `kelseyhightower/envconfig` and the `flag` package. 3 | 4 | Unlike `flag` envconfig does not need to parse os.Args. This means that envconfig reads the environment and sets values immediately. 5 | 6 | Note: All variable names are normalized to uppercase when reading the environment. 7 | 8 | ## Example Usage 9 | 10 | ``` 11 | import "github.com/mattaitchison/envconfig" 12 | 13 | // Basic types 14 | var hostIP = envconfig.String("registrator_ip", "", "IP for ports mapped to the host") 15 | var internal = envconfig.Bool("registrator_internal", false, "Use internal ports instead of published ones") 16 | var ttlRefresh = envconfig.Int("registrator_ttl_refresh", 0, 17 | "Frequency with which service TTLs are refreshed") 18 | var velocity = envconfig.Float64("velocity", 1.23, 19 | "Floating point value with no prefix") 20 | 21 | // Convenience + validation 22 | var deregister = envconfig.StringOption("registrator_deregister", "always", 23 | []string{"always", "never", "on-success"}, 24 | "Deregister mode") 25 | ``` 26 | 27 | # License 28 | 29 | MIT 30 | -------------------------------------------------------------------------------- /envconfig_test.go: -------------------------------------------------------------------------------- 1 | package envconfig 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "testing" 7 | ) 8 | 9 | func boolString(s string) string { 10 | if s == "0" { 11 | return "false" 12 | } 13 | return "true" 14 | } 15 | 16 | func ResetForTesting() { 17 | DefaultEnv = NewEnvSet(os.Args[0]) 18 | } 19 | 20 | func TestEverything(t *testing.T) { 21 | ResetForTesting() 22 | Bool("test_bool", false, "bool value") 23 | Int("test_int", 0, "int value") 24 | Int64("test_int64", 0, "int64 value") 25 | Uint("test_uint", 0, "uint value") 26 | Uint64("test_uint64", 0, "uint64 value") 27 | String("test_string", "0", "string value") 28 | StringOption("test_string_opt", "0", []string{"0", "2"}, "string opt") 29 | Float64("test_float64", 0, "float64 value") 30 | Duration("test_duration", 0, "time.Duration value") 31 | 32 | desired := "0" 33 | visitor := func(c *ConfigVar) { 34 | if len(c.Name) > 5 && c.Name[0:5] == "TEST_" { 35 | ok := false 36 | switch { 37 | case c.Value.String() == desired: 38 | ok = true 39 | case c.Name == "TEST_BOOL" && c.Value.String() == boolString(desired): 40 | ok = true 41 | case c.Name == "TEST_DURATION" && c.Value.String() == desired+"s": 42 | ok = true 43 | } 44 | if !ok { 45 | t.Error(c.Value.String(), c.Name) 46 | } 47 | } 48 | } 49 | VisitAll(visitor) 50 | } 51 | 52 | func TestEnvSet(t *testing.T) { 53 | ResetForTesting() 54 | String("test_string", "0", "string value") 55 | set := NewEnvSet("test") 56 | 57 | str := set.String("test_string_set", "hello", "string value") 58 | if str != "hello" { 59 | t.Error("env set string should be `hello`, is ", str) 60 | } 61 | 62 | } 63 | 64 | func TestString(t *testing.T) { 65 | ResetForTesting() 66 | s := String("conf_string", "foo", "test string") 67 | if s != "foo" { 68 | t.Errorf("expected: %s got: %s", "foo", s) 69 | } 70 | } 71 | 72 | func TestStringOption(t *testing.T) { 73 | ResetForTesting() 74 | s := StringOption("conf_string_opt", "foo", []string{"foo", "bar"}, "set value must be an option") 75 | if s != "foo" { 76 | t.Errorf("expected: %s got: %s", "foo", s) 77 | } 78 | } 79 | 80 | func TestStringOptionModify(t *testing.T) { 81 | ResetForTesting() 82 | os.Setenv("CONF_STRING_OPT", "bar") 83 | s := StringOption("conf_string_opt", "foo", []string{"foo", "bar"}, "set value must be an option") 84 | if s != "bar" { 85 | t.Errorf("expected: %s got: %s", "bar", s) 86 | } 87 | } 88 | 89 | func TestStringOptionInvalid(t *testing.T) { 90 | ResetForTesting() 91 | os.Setenv("CONF_STRING_OPT", "foobar") 92 | s := StringOption("conf_string_opt", "foo", []string{"foo", "bar"}, "set value must be an option") 93 | if s != "foo" { 94 | t.Errorf("expected: %s got: %s", "bar", s) 95 | } 96 | } 97 | 98 | func TestSecret(t *testing.T) { 99 | ResetForTesting() 100 | os.Setenv("CONF_SECRET", "12345678") 101 | s := Secret("conf_secret", "test secret") 102 | if s != "12345678" { 103 | t.Errorf("expected: %s got: %s", "12345678", s) 104 | } 105 | if fmt.Sprintf("%s", Var("conf_secret").Value) != "XXXX5678" { 106 | t.Errorf("expected: %s got: %s", "XXXX5678", s) 107 | } 108 | } 109 | 110 | func TestRace(t *testing.T) { 111 | ResetForTesting() 112 | done := make(chan struct{}) 113 | go func() { 114 | s := String("conf_string_go", "foo", "") 115 | if s != "foo" { 116 | t.Errorf("expected: %s got: %s", "bar", s) 117 | } 118 | close(done) 119 | }() 120 | 121 | s := String("conf_string", "foo", "") 122 | if s != "foo" { 123 | t.Errorf("expected: %s got: %s", "bar", s) 124 | } 125 | 126 | <-done 127 | } 128 | 129 | func TestPrintDefaults(t *testing.T) { 130 | ResetForTesting() 131 | PrintDefaults(nil) // TODO: replace with buffer and actually test 132 | } 133 | 134 | func TestPrintEnv(t *testing.T) { 135 | ResetForTesting() 136 | PrintEnv(nil, false, false) // TODO: replace with buffer and actually test 137 | } 138 | -------------------------------------------------------------------------------- /value.go: -------------------------------------------------------------------------------- 1 | package envconfig 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "net" 7 | "strconv" 8 | "time" 9 | ) 10 | 11 | type Value interface { 12 | String() string 13 | Set(string) error 14 | Get() interface{} 15 | } 16 | 17 | // -- string Value 18 | type stringValue string 19 | 20 | func newStringValue(val string) *stringValue { 21 | return (*stringValue)(&val) 22 | } 23 | func (s *stringValue) Set(val string) error { 24 | *s = stringValue(val) 25 | return nil 26 | } 27 | 28 | func (s *stringValue) Get() interface{} { return string(*s) } 29 | 30 | func (s *stringValue) String() string { return fmt.Sprintf("%s", *s) } 31 | 32 | // -- secret Value 33 | type secretValue stringValue 34 | 35 | func newSecretValue(val string) *secretValue { 36 | return (*secretValue)(&val) 37 | } 38 | func (s *secretValue) Set(val string) error { 39 | *s = secretValue(val) 40 | return nil 41 | } 42 | 43 | func (s *secretValue) Get() interface{} { return string(*s) } 44 | 45 | func (s *secretValue) String() string { 46 | hiddenValue := []byte(*s) 47 | var hideLen int 48 | if len(hiddenValue) > 4 { 49 | hideLen = len(hiddenValue) - 4 50 | } else { 51 | hideLen = 1 52 | } 53 | for i := range hiddenValue { 54 | if i < hideLen { 55 | hiddenValue[i] = 88 // X 56 | } 57 | } 58 | if len(hiddenValue) > 20 { 59 | hiddenValue = hiddenValue[len(hiddenValue)-20:] 60 | } 61 | return string(hiddenValue) 62 | } 63 | 64 | // -- bool Value 65 | type boolValue bool 66 | 67 | func newBoolValue(val bool) *boolValue { 68 | return (*boolValue)(&val) 69 | } 70 | 71 | func (b *boolValue) Set(s string) error { 72 | v, err := strconv.ParseBool(s) 73 | *b = boolValue(v) 74 | return err 75 | } 76 | 77 | func (b *boolValue) Get() interface{} { return bool(*b) } 78 | 79 | func (b *boolValue) String() string { return fmt.Sprintf("%v", *b) } 80 | 81 | func (b *boolValue) IsBoolFlag() bool { return true } 82 | 83 | // -- int Value 84 | type intValue int 85 | 86 | func newIntValue(val int) *intValue { 87 | return (*intValue)(&val) 88 | } 89 | 90 | func (i *intValue) Set(s string) error { 91 | v, err := strconv.ParseInt(s, 0, 64) 92 | *i = intValue(v) 93 | return err 94 | } 95 | 96 | func (i *intValue) Get() interface{} { return int(*i) } 97 | 98 | func (i *intValue) String() string { return fmt.Sprintf("%v", *i) } 99 | 100 | // -- int64 Value 101 | type int64Value int64 102 | 103 | func newInt64Value(val int64) *int64Value { 104 | return (*int64Value)(&val) 105 | } 106 | 107 | func (i *int64Value) Set(s string) error { 108 | v, err := strconv.ParseInt(s, 0, 64) 109 | *i = int64Value(v) 110 | return err 111 | } 112 | 113 | func (i *int64Value) Get() interface{} { return int64(*i) } 114 | 115 | func (i *int64Value) String() string { return fmt.Sprintf("%v", *i) } 116 | 117 | // -- uint Value 118 | type uintValue uint 119 | 120 | func newUintValue(val uint) *uintValue { 121 | return (*uintValue)(&val) 122 | } 123 | 124 | func (i *uintValue) Set(s string) error { 125 | v, err := strconv.ParseUint(s, 0, 64) 126 | *i = uintValue(v) 127 | return err 128 | } 129 | 130 | func (i *uintValue) Get() interface{} { return uint(*i) } 131 | 132 | func (i *uintValue) String() string { return fmt.Sprintf("%v", *i) } 133 | 134 | // -- uint64 Value 135 | type uint64Value uint64 136 | 137 | func newUint64Value(val uint64) *uint64Value { 138 | return (*uint64Value)(&val) 139 | } 140 | 141 | func (i *uint64Value) Set(s string) error { 142 | v, err := strconv.ParseUint(s, 0, 64) 143 | *i = uint64Value(v) 144 | return err 145 | } 146 | 147 | func (i *uint64Value) Get() interface{} { return uint64(*i) } 148 | 149 | func (i *uint64Value) String() string { return fmt.Sprintf("%v", *i) } 150 | 151 | // -- float64 Value 152 | type float64Value float64 153 | 154 | func newFloat64Value(val float64) *float64Value { 155 | return (*float64Value)(&val) 156 | } 157 | 158 | func (f *float64Value) Set(s string) error { 159 | v, err := strconv.ParseFloat(s, 64) 160 | *f = float64Value(v) 161 | return err 162 | } 163 | 164 | func (f *float64Value) Get() interface{} { return float64(*f) } 165 | 166 | func (f *float64Value) String() string { return fmt.Sprintf("%v", *f) } 167 | 168 | // -- time.Duration Value 169 | type durationValue time.Duration 170 | 171 | func newDurationValue(val time.Duration) *durationValue { 172 | return (*durationValue)(&val) 173 | } 174 | 175 | func (d *durationValue) Set(s string) error { 176 | v, err := time.ParseDuration(s) 177 | *d = durationValue(v) 178 | return err 179 | } 180 | 181 | func (d *durationValue) Get() interface{} { return time.Duration(*d) } 182 | 183 | func (d *durationValue) String() string { return (*time.Duration)(d).String() } 184 | 185 | // -- float64 Value 186 | type ipValue net.IP 187 | 188 | func newIPValue(val net.IP) *ipValue { 189 | return (*ipValue)(&val) 190 | } 191 | 192 | func (f *ipValue) Set(s string) error { 193 | v := net.ParseIP(s) 194 | *f = ipValue(v) 195 | if v != nil { 196 | return errors.New("invalid IP") 197 | } 198 | return nil 199 | } 200 | 201 | func (f *ipValue) Get() interface{} { return net.IP(*f) } 202 | 203 | func (f *ipValue) String() string { return fmt.Sprintf("%v", *f) } 204 | -------------------------------------------------------------------------------- /envconfig.go: -------------------------------------------------------------------------------- 1 | package envconfig 2 | 3 | import ( 4 | "fmt" 5 | "io" 6 | "net" 7 | "os" 8 | "strings" 9 | "sync" 10 | "time" 11 | ) 12 | 13 | type EnvSet struct { 14 | sync.Mutex 15 | name string 16 | vars map[string]*ConfigVar 17 | } 18 | 19 | // ConfigVar represents a value from the environment. 20 | type ConfigVar struct { 21 | Name string 22 | Description string 23 | Value Value // value as set 24 | Default string // default value (as text); for description message 25 | Secret bool 26 | } 27 | 28 | // String retrieves a environment variable by name and parses it to a string 29 | // defaultVal will be returned if the variable is not found. 30 | func (e *EnvSet) String(name string, defaultVal string, description string) string { 31 | v := e.NewVar(newStringValue(defaultVal), name, description) 32 | return v.Value.Get().(string) 33 | } 34 | 35 | // String retrieves a environment variable by name and parses it to a string 36 | // defaultVal will be returned if the variable is not found. 37 | func String(name string, defaultVal string, description string) string { 38 | return DefaultEnv.String(name, defaultVal, description) 39 | } 40 | 41 | // StringOption like String except the value must be in options. 42 | // defaultVal will be returned if the variable is not found or is not a valid option. 43 | func (e *EnvSet) StringOption(name string, defaultVal string, options []string, description string) string { 44 | v := e.NewVar(newStringValue(defaultVal), name, description) 45 | for _, option := range options { 46 | if option == v.Value.Get().(string) { 47 | return v.Value.Get().(string) 48 | } 49 | } 50 | return defaultVal 51 | } 52 | 53 | // StringOption like String except the value must be in options. 54 | // defaultVal will be returned if the variable is not found or is not a valid option. 55 | func StringOption(name string, defaultVal string, options []string, description string) string { 56 | return DefaultEnv.StringOption(name, defaultVal, options, description) 57 | } 58 | 59 | // Secret retrieves a environment variable by name and parses it to a secret string 60 | // defaultVal will be returned if the variable is not found. 61 | func (e *EnvSet) Secret(name string, description string) string { 62 | v := e.NewVar(newSecretValue(""), name, description) 63 | v.Secret = true 64 | return v.Value.Get().(string) 65 | } 66 | 67 | // Secret retrieves a environment variable by name and parses it to a secret string 68 | // defaultVal will be returned if the variable is not found. 69 | func Secret(name string, description string) string { 70 | return DefaultEnv.Secret(name, description) 71 | } 72 | 73 | // Bool retrieves a environment variable by name and parses it to a bool 74 | // defaultVal will be returned if the variable is not found. 75 | func (e *EnvSet) Bool(name string, defaultVal bool, description string) bool { 76 | v := e.NewVar(newBoolValue(defaultVal), name, description) 77 | return v.Value.Get().(bool) 78 | } 79 | 80 | // Bool retrieves a environment variable by name and parses it to a bool 81 | // defaultVal will be returned if the variable is not found. 82 | func Bool(name string, defaultVal bool, description string) bool { 83 | return DefaultEnv.Bool(name, defaultVal, description) 84 | } 85 | 86 | // Float64 retrieves a environment variable by name and parses it to a float64 87 | // defaultVal will be returned if the variable is not found. 88 | func (e *EnvSet) Float64(name string, defaultVal float64, description string) float64 { 89 | v := e.NewVar(newFloat64Value(defaultVal), name, description) 90 | return v.Value.Get().(float64) 91 | } 92 | 93 | // Float64 retrieves a environment variable by name and parses it to a float64 94 | // defaultVal will be returned if the variable is not found. 95 | func Float64(name string, defaultVal float64, description string) float64 { 96 | return DefaultEnv.Float64(name, defaultVal, description) 97 | } 98 | 99 | // Float64Option like Float64 except the value must be in options. 100 | // defaultVal will be returned if the variable is not found or is not a valid option. 101 | func (e *EnvSet) Float64Option(name string, defaultVal float64, options []float64, description string) float64 { 102 | v := e.NewVar(newFloat64Value(defaultVal), name, description) 103 | for _, option := range options { 104 | if option == v.Value.Get().(float64) { 105 | return v.Value.Get().(float64) 106 | } 107 | } 108 | return defaultVal 109 | } 110 | 111 | // Int retrieves a environment variable by name and parses it to a int 112 | // defaultVal will be returned if the variable is not found. 113 | func (e *EnvSet) Int(name string, defaultVal int, description string) int { 114 | v := e.NewVar(newIntValue(defaultVal), name, description) 115 | return v.Value.Get().(int) 116 | } 117 | 118 | // Int retrieves a environment variable by name and parses it to a int 119 | // defaultVal will be returned if the variable is not found. 120 | func Int(name string, defaultVal int, description string) int { 121 | return DefaultEnv.Int(name, defaultVal, description) 122 | } 123 | 124 | // IntOption like Int except the value must be in options. 125 | // defaultVal will be returned if the variable is not found or is not a valid option. 126 | func (e *EnvSet) IntOption(name string, defaultVal int, options []int, description string) int { 127 | v := e.NewVar(newIntValue(defaultVal), name, description) 128 | for _, option := range options { 129 | if option == v.Value.Get().(int) { 130 | return v.Value.Get().(int) 131 | } 132 | } 133 | return defaultVal 134 | } 135 | 136 | // Int64 retrieves a environment variable by name and parses it to a int64 137 | // defaultVal will be returned if the variable is not found. 138 | func (e *EnvSet) Int64(name string, defaultVal int64, description string) int64 { 139 | v := e.NewVar(newInt64Value(defaultVal), name, description) 140 | return v.Value.Get().(int64) 141 | } 142 | 143 | // Int64 retrieves a environment variable by name and parses it to a int64 144 | // defaultVal will be returned if the variable is not found. 145 | func Int64(name string, defaultVal int64, description string) int64 { 146 | return DefaultEnv.Int64(name, defaultVal, description) 147 | } 148 | 149 | // Int64Option like Int64 except the value must be in options. 150 | // defaultVal will be returned if the variable is not found or is not a valid option. 151 | func (e *EnvSet) Int64Option(name string, defaultVal int64, options []int64, description string) int64 { 152 | v := e.NewVar(newInt64Value(defaultVal), name, description) 153 | for _, option := range options { 154 | if option == v.Value.Get().(int64) { 155 | return v.Value.Get().(int64) 156 | } 157 | } 158 | return defaultVal 159 | } 160 | 161 | // Uint retrieves a environment variable by name and parses it to a uint 162 | // defaultVal will be returned if the variable is not found. 163 | func (e *EnvSet) Uint(name string, defaultVal uint, description string) uint { 164 | v := e.NewVar(newUintValue(defaultVal), name, description) 165 | return v.Value.Get().(uint) 166 | } 167 | 168 | // Uint retrieves a environment variable by name and parses it to a uint 169 | // defaultVal will be returned if the variable is not found. 170 | func Uint(name string, defaultVal uint, description string) uint { 171 | return DefaultEnv.Uint(name, defaultVal, description) 172 | } 173 | 174 | // UintOption like Uint except the value must be in options. 175 | // defaultVal will be returned if the variable is not found or is not a valid option. 176 | func (e *EnvSet) UintOption(name string, defaultVal uint, options []uint, description string) uint { 177 | v := e.NewVar(newUintValue(defaultVal), name, description) 178 | for _, option := range options { 179 | if option == v.Value.Get().(uint) { 180 | return v.Value.Get().(uint) 181 | } 182 | } 183 | return defaultVal 184 | } 185 | 186 | // Uint64 retrieves a environment variable by name and parses it to a uint64 187 | // defaultVal will be returned if the variable is not found. 188 | func (e *EnvSet) Uint64(name string, defaultVal uint64, description string) uint64 { 189 | v := e.NewVar(newUint64Value(defaultVal), name, description) 190 | return v.Value.Get().(uint64) 191 | } 192 | 193 | // Uint64 retrieves a environment variable by name and parses it to a uint64 194 | // defaultVal will be returned if the variable is not found. 195 | func Uint64(name string, defaultVal uint64, description string) uint64 { 196 | return DefaultEnv.Uint64(name, defaultVal, description) 197 | } 198 | 199 | // Uint64Option like Uint64 except the value must be in options. 200 | // defaultVal will be returned if the variable is not found or is not a valid option. 201 | func (e *EnvSet) Uint64Option(name string, defaultVal uint64, options []uint64, description string) uint64 { 202 | v := e.NewVar(newUint64Value(defaultVal), name, description) 203 | for _, option := range options { 204 | if option == v.Value.Get().(uint64) { 205 | return v.Value.Get().(uint64) 206 | } 207 | } 208 | return defaultVal 209 | } 210 | 211 | func (e *EnvSet) Duration(name string, defaultVal time.Duration, description string) time.Duration { 212 | v := e.NewVar(newDurationValue(defaultVal), name, description) 213 | return v.Value.Get().(time.Duration) 214 | } 215 | 216 | func Duration(name string, defaultVal time.Duration, description string) time.Duration { 217 | return DefaultEnv.Duration(name, defaultVal, description) 218 | } 219 | 220 | // IP retrieves a environment variable by name and parses it to a net.IP 221 | // defaultVal will be returned if the variable is not found. 222 | func (e *EnvSet) IP(name string, defaultVal net.IP, description string) net.IP { 223 | v := e.NewVar(newIPValue(defaultVal), name, description) 224 | return v.Value.Get().(net.IP) 225 | } 226 | 227 | // IP retrieves a environment variable by name and parses it to a net.IP 228 | // defaultVal will be returned if the variable is not found. 229 | func IP(name string, defaultVal net.IP, description string) net.IP { 230 | return DefaultEnv.IP(name, defaultVal, description) 231 | } 232 | 233 | func (e *EnvSet) VisitAll(fn func(*ConfigVar)) { 234 | for _, cfg := range e.vars { 235 | fn(cfg) 236 | } 237 | } 238 | 239 | func VisitAll(fn func(*ConfigVar)) { 240 | DefaultEnv.VisitAll(fn) 241 | } 242 | 243 | // NewVar retrieves a variable from the environment that is of type Value. 244 | func (e *EnvSet) NewVar(value Value, name string, description string) *ConfigVar { 245 | e.Lock() 246 | defer e.Unlock() 247 | envVar := &ConfigVar{ 248 | Name: strings.ToUpper(name), 249 | Description: description, 250 | Value: value, 251 | Default: value.String(), 252 | } 253 | _, defined := e.vars[name] 254 | if defined { 255 | panic("env: " + name + " already defined.") 256 | } 257 | 258 | // This step is part of Parse() in flags pkg. 259 | if v := os.Getenv(envVar.Name); v != "" { 260 | envVar.Value.Set(v) 261 | } 262 | 263 | if e.vars == nil { 264 | e.vars = make(map[string]*ConfigVar) 265 | } 266 | e.vars[name] = envVar 267 | 268 | return envVar 269 | } 270 | 271 | // NewVar retrieves a variable from the environment that is of type Value. 272 | func NewVar(value Value, name string, description string) *ConfigVar { 273 | return DefaultEnv.NewVar(value, name, description) 274 | } 275 | 276 | // Var retrieves a ConfigVar by name from the ConfigVar map. 277 | func (e *EnvSet) Var(name string) *ConfigVar { 278 | e.Lock() 279 | defer e.Unlock() 280 | if v, ok := e.vars[name]; ok { 281 | return v 282 | } 283 | return nil 284 | } 285 | 286 | // Var retrieves a ConfigVar by name from the ConfigVar map. 287 | func Var(name string) *ConfigVar { 288 | return DefaultEnv.Var(name) 289 | } 290 | 291 | // Vars retrieve all ConfigVars from the ConfigVar map. 292 | func (e *EnvSet) Vars() map[string]*ConfigVar { 293 | e.Lock() 294 | defer e.Unlock() 295 | // TODO: this should return a copy of the map 296 | return e.vars 297 | } 298 | 299 | // Vars retrieve all ConfigVars from the ConfigVar map. 300 | func Vars() map[string]*ConfigVar { 301 | return DefaultEnv.Vars() 302 | } 303 | 304 | // PrintDefaults prints the default values of all defined ConfigVars. 305 | func (e *EnvSet) PrintDefaults(out io.Writer) { 306 | e.Lock() 307 | defer e.Unlock() 308 | // TODO: locking could be removed if this used Vars after copying is done 309 | for _, v := range e.vars { 310 | env := fmt.Sprintf("%s=%q", v.Name, v.Default) 311 | fmt.Fprintf(out, "%-40s # %s\n", env, v.Description) 312 | } 313 | } 314 | 315 | // PrintDefaults prints the default values of all defined ConfigVars. 316 | func PrintDefaults(out io.Writer) { 317 | DefaultEnv.PrintDefaults(out) 318 | } 319 | 320 | // PrintEnv prints the set values of all defined ConfigVars. 321 | func (e *EnvSet) PrintEnv(out io.Writer, export, secrets bool) { 322 | e.Lock() 323 | defer e.Unlock() 324 | // TODO: locking could be removed if this used Vars after copying is done 325 | for _, v := range e.vars { 326 | printVar(out, v, export, secrets) 327 | } 328 | } 329 | 330 | // PrintEnv prints the set values of all defined ConfigVars. 331 | func PrintEnv(out io.Writer, export, secrets bool) { 332 | DefaultEnv.PrintEnv(out, export, secrets) 333 | } 334 | 335 | func printVar(out io.Writer, v *ConfigVar, export, secrets bool) { 336 | value := v.Value.String() 337 | if v.Secret { 338 | if secrets { 339 | value = v.Value.Get().(string) 340 | } else { 341 | if export { 342 | return 343 | } 344 | } 345 | } 346 | if export { 347 | fmt.Fprintf(out, "export %s=\"%s\"\n", v.Name, value) 348 | } else { 349 | kv := fmt.Sprintf("%s=\"%s\"", v.Name, value) 350 | fmt.Fprintf(out, "%-40s # %s\n", kv, v.Description) 351 | } 352 | } 353 | 354 | var DefaultEnv = NewEnvSet(os.Args[0]) 355 | 356 | func NewEnvSet(name string) *EnvSet { 357 | e := &EnvSet{ 358 | name: name, 359 | } 360 | return e 361 | } 362 | --------------------------------------------------------------------------------