github.com/blend/go-sdk@v1.20220411.3/env/vars.go (about) 1 /* 2 3 Copyright (c) 2022 - Present. Blend Labs, Inc. All rights reserved 4 Use of this source code is governed by a MIT license that can be found in the LICENSE file. 5 6 */ 7 8 package env 9 10 import ( 11 "encoding/base64" 12 "fmt" 13 "os" 14 "strconv" 15 "strings" 16 "time" 17 18 "github.com/blend/go-sdk/ex" 19 "github.com/blend/go-sdk/reflectutil" 20 "github.com/blend/go-sdk/stringutil" 21 ) 22 23 // New returns a new env var set. 24 // 25 /* By default, it is empty. In order to populate it with the current 26 runtime environment variables, you need to pass in options: 27 vars := env.New(env.OptEnviron(os.Environ()...)) 28 */ 29 func New(opts ...Option) Vars { 30 vars := make(Vars) 31 for _, opt := range opts { 32 opt(vars) 33 } 34 return vars 35 } 36 37 // Vars is a set of environment variables. 38 type Vars map[string]string 39 40 // Get gets a variable as a string. 41 // It mirrors os.Getenv. 42 func (ev Vars) Get(envVar string) string { 43 if value, ok := ev[envVar]; ok { 44 return value 45 } 46 return "" 47 } 48 49 // Set sets a value for a key. 50 func (ev Vars) Set(envVar, value string) { 51 ev[envVar] = value 52 } 53 54 // Restore resets an environment variable to it's environment value. 55 func (ev Vars) Restore(key string) { 56 ev[key] = os.Getenv(key) 57 } 58 59 // Delete removes a key from the set. 60 func (ev Vars) Delete(key string) { 61 delete(ev, key) 62 } 63 64 // String returns a string value for a given key, with an optional default vaule. 65 func (ev Vars) String(envVar string, defaults ...string) string { 66 if value, hasValue := ev[envVar]; hasValue { 67 return value 68 } 69 for _, defaultValue := range defaults { 70 if defaultValue != "" { 71 return defaultValue 72 } 73 } 74 return "" 75 } 76 77 // CSV returns a string array for a given string var. 78 func (ev Vars) CSV(envVar string, defaults ...string) []string { 79 if value, hasValue := ev[envVar]; hasValue && len(value) > 0 { 80 return strings.Split(value, ",") 81 } 82 return defaults 83 } 84 85 // Bool returns a boolean value for a key, defaulting to false. 86 // Valid "truthy" values are `true`, `yes`, and `1`. 87 // Everything else is false, including `REEEEEEEEEEEEEEE`. 88 func (ev Vars) Bool(envVar string, defaults ...bool) bool { 89 if value, hasValue := ev[envVar]; hasValue { 90 boolValue, err := stringutil.ParseBool(value) 91 if err == nil { 92 return boolValue 93 } 94 } 95 if len(defaults) > 0 { 96 return defaults[0] 97 } 98 return false 99 } 100 101 // Int returns an integer value for a given key. 102 func (ev Vars) Int(envVar string, defaults ...int) (int, error) { 103 if value, hasValue := ev[envVar]; hasValue { 104 parsedValue, err := strconv.Atoi(value) 105 if err != nil { 106 return 0, ex.New(err, ex.OptMessagef("var: %q", envVar)) 107 } 108 return parsedValue, nil 109 } 110 for _, defaultValue := range defaults { 111 if defaultValue > 0 { 112 return defaultValue, nil 113 } 114 } 115 return 0, nil 116 } 117 118 // MustInt returns an integer value for a given key and panics if it is malformed. 119 func (ev Vars) MustInt(envVar string, defaults ...int) int { 120 value, err := ev.Int(envVar, defaults...) 121 if err != nil { 122 panic(err) 123 } 124 return value 125 } 126 127 // Int32 returns an integer value for a given key. 128 func (ev Vars) Int32(envVar string, defaults ...int32) (int32, error) { 129 if value, hasValue := ev[envVar]; hasValue { 130 parsedValue, err := strconv.ParseInt(value, 10, 32) 131 if err != nil { 132 return 0, ex.New(err, ex.OptMessagef("var: %q", envVar)) 133 } 134 return int32(parsedValue), nil 135 } 136 for _, defaultValue := range defaults { 137 if defaultValue > 0 { 138 return defaultValue, nil 139 } 140 } 141 return 0, nil 142 } 143 144 // MustInt32 returns an integer value for a given key and panics if it is malformed. 145 func (ev Vars) MustInt32(envVar string, defaults ...int32) int32 { 146 value, err := ev.Int32(envVar, defaults...) 147 if err != nil { 148 panic(err) 149 } 150 return value 151 } 152 153 // Int64 returns an int64 value for a given key. 154 func (ev Vars) Int64(envVar string, defaults ...int64) (int64, error) { 155 if value, hasValue := ev[envVar]; hasValue { 156 parsedValue, err := strconv.ParseInt(value, 10, 64) 157 if err != nil { 158 return 0, ex.New(err, ex.OptMessagef("var: %q", envVar)) 159 } 160 return parsedValue, nil 161 } 162 for _, defaultValue := range defaults { 163 if defaultValue > 0 { 164 return defaultValue, nil 165 } 166 } 167 return 0, nil 168 } 169 170 // MustInt64 returns an int64 value for a given key and panics if it is malformed. 171 func (ev Vars) MustInt64(envVar string, defaults ...int64) int64 { 172 value, err := ev.Int64(envVar, defaults...) 173 if err != nil { 174 panic(err) 175 } 176 return value 177 } 178 179 // Uint32 returns an uint32 value for a given key. 180 func (ev Vars) Uint32(envVar string, defaults ...uint32) (uint32, error) { 181 if value, hasValue := ev[envVar]; hasValue { 182 parsedValue, err := strconv.ParseUint(value, 10, 32) 183 if err != nil { 184 return 0, ex.New(err, ex.OptMessagef("var: %q", envVar)) 185 } 186 return uint32(parsedValue), nil 187 } 188 for _, defaultValue := range defaults { 189 if defaultValue > 0 { 190 return defaultValue, nil 191 } 192 } 193 return 0, nil 194 } 195 196 // MustUint32 returns an uint32 value for a given key and panics if it is malformed. 197 func (ev Vars) MustUint32(envVar string, defaults ...uint32) uint32 { 198 value, err := ev.Uint32(envVar, defaults...) 199 if err != nil { 200 panic(err) 201 } 202 return value 203 } 204 205 // Uint64 returns an uint64 value for a given key. 206 func (ev Vars) Uint64(envVar string, defaults ...uint64) (uint64, error) { 207 if value, hasValue := ev[envVar]; hasValue { 208 parsedValue, err := strconv.ParseUint(value, 10, 64) 209 if err != nil { 210 return 0, ex.New(err, ex.OptMessagef("var: %q", envVar)) 211 } 212 return parsedValue, nil 213 } 214 for _, defaultValue := range defaults { 215 if defaultValue > 0 { 216 return defaultValue, nil 217 } 218 } 219 return 0, nil 220 } 221 222 // MustUint64 returns an uint64 value for a given key and panics if it is malformed. 223 func (ev Vars) MustUint64(envVar string, defaults ...uint64) uint64 { 224 value, err := ev.Uint64(envVar, defaults...) 225 if err != nil { 226 panic(err) 227 } 228 return value 229 } 230 231 // Float32 returns an float32 value for a given key. 232 func (ev Vars) Float32(envVar string, defaults ...float32) (float32, error) { 233 if value, hasValue := ev[envVar]; hasValue { 234 parsedValue, err := strconv.ParseFloat(value, 32) 235 if err != nil { 236 return 0, ex.New(err, ex.OptMessagef("var: %q", envVar)) 237 } 238 return float32(parsedValue), nil 239 } 240 for _, defaultValue := range defaults { 241 if defaultValue > 0 { 242 return defaultValue, nil 243 } 244 } 245 return 0, nil 246 } 247 248 // MustFloat32 returns an float64 value for a given key and panics if it is malformed. 249 func (ev Vars) MustFloat32(envVar string, defaults ...float32) float32 { 250 value, err := ev.Float32(envVar, defaults...) 251 if err != nil { 252 panic(err) 253 } 254 return value 255 } 256 257 // Float64 returns an float64 value for a given key. 258 func (ev Vars) Float64(envVar string, defaults ...float64) (float64, error) { 259 if value, hasValue := ev[envVar]; hasValue { 260 parsedValue, err := strconv.ParseFloat(value, 64) 261 if err != nil { 262 return 0, ex.New(err, ex.OptMessagef("var: %q", envVar)) 263 } 264 return parsedValue, nil 265 } 266 for _, defaultValue := range defaults { 267 if defaultValue > 0 { 268 return defaultValue, nil 269 } 270 } 271 return 0, nil 272 } 273 274 // MustFloat64 returns an float64 value for a given key and panics if it is malformed. 275 func (ev Vars) MustFloat64(envVar string, defaults ...float64) float64 { 276 value, err := ev.Float64(envVar, defaults...) 277 if err != nil { 278 panic(err) 279 } 280 return value 281 } 282 283 // Duration returns a duration value for a given key. 284 func (ev Vars) Duration(envVar string, defaults ...time.Duration) (time.Duration, error) { 285 if value, hasValue := ev[envVar]; hasValue { 286 return time.ParseDuration(value) 287 } 288 for _, defaultValue := range defaults { 289 if defaultValue > 0 { 290 return defaultValue, nil 291 } 292 } 293 return 0, nil 294 } 295 296 // MustDuration returnss a duration value for a given key and panics if malformed. 297 func (ev Vars) MustDuration(envVar string, defaults ...time.Duration) time.Duration { 298 value, err := ev.Duration(envVar, defaults...) 299 if err != nil { 300 panic(err) 301 } 302 return value 303 } 304 305 // Bytes returns a []byte value for a given key. 306 func (ev Vars) Bytes(envVar string, defaults ...[]byte) []byte { 307 if value, hasValue := ev[envVar]; hasValue && len(value) > 0 { 308 return []byte(value) 309 } 310 for _, defaultValue := range defaults { 311 if len(defaultValue) > 0 { 312 return defaultValue 313 } 314 } 315 return nil 316 } 317 318 // Base64 returns a []byte value for a given key whose value is encoded in base64. 319 func (ev Vars) Base64(envVar string, defaults ...[]byte) ([]byte, error) { 320 if value, hasValue := ev[envVar]; hasValue && len(value) > 0 { 321 return base64.StdEncoding.DecodeString(value) 322 } 323 for _, defaultValue := range defaults { 324 if len(defaultValue) > 0 { 325 return defaultValue, nil 326 } 327 } 328 return nil, nil 329 } 330 331 // MustBase64 returns a []byte value for a given key encoded with base64, and panics if malformed. 332 func (ev Vars) MustBase64(envVar string, defaults ...[]byte) []byte { 333 value, err := ev.Base64(envVar, defaults...) 334 if err != nil { 335 panic(err) 336 } 337 return value 338 } 339 340 // Has returns if a key is present in the set. 341 func (ev Vars) Has(envVar string) bool { 342 _, hasKey := ev[envVar] 343 return hasKey 344 } 345 346 // HasAll returns if all of the given vars are present in the set. 347 func (ev Vars) HasAll(envVars ...string) bool { 348 if len(envVars) == 0 { 349 return false 350 } 351 for _, envVar := range envVars { 352 if !ev.Has(envVar) { 353 return false 354 } 355 } 356 return true 357 } 358 359 // HasAny returns if any of the given vars are present in the set. 360 func (ev Vars) HasAny(envVars ...string) bool { 361 for _, envVar := range envVars { 362 if ev.Has(envVar) { 363 return true 364 } 365 } 366 return false 367 } 368 369 // Require enforces that a given set of environment variables are present. 370 func (ev Vars) Require(keys ...string) error { 371 for _, key := range keys { 372 if !ev.Has(key) { 373 return fmt.Errorf("the following environment variables are required: `%s`", strings.Join(keys, ",")) 374 } 375 } 376 return nil 377 } 378 379 // Must enforces that a given set of environment variables are present and panics 380 // if they're not present. 381 func (ev Vars) Must(keys ...string) { 382 for _, key := range keys { 383 if !ev.Has(key) { 384 panic(fmt.Sprintf("the following environment variables are required: `%s`", strings.Join(keys, ","))) 385 } 386 } 387 } 388 389 // Union returns the union of the two sets, other replacing conflicts. 390 func (ev Vars) Union(other Vars) Vars { 391 newSet := New() 392 for key, value := range ev { 393 newSet[key] = value 394 } 395 for key, value := range other { 396 newSet[key] = value 397 } 398 return newSet 399 } 400 401 // Vars returns all the vars stored in the env var set. 402 func (ev Vars) Vars() []string { 403 var envVars = make([]string, len(ev)) 404 var index int 405 for envVar := range ev { 406 envVars[index] = envVar 407 index++ 408 } 409 return envVars 410 } 411 412 // Raw returns a raw KEY=VALUE form of the vars. 413 func (ev Vars) Raw() []string { 414 var raw []string 415 for key, value := range ev { 416 raw = append(raw, fmt.Sprintf("%s=%s", key, value)) 417 } 418 return raw 419 } 420 421 // ReadInto sets an object based on the fields in the env vars set. 422 func (ev Vars) ReadInto(obj interface{}) error { 423 if typed, isTyped := obj.(Unmarshaler); isTyped { 424 return typed.UnmarshalEnv(ev) 425 } 426 return reflectutil.PatchStrings(ReflectTagName, ev, obj) 427 } 428 429 // Expand calls os.Expand with the variable set as the environment value resolver. 430 func (ev Vars) Expand(value string) string { 431 return os.Expand(value, ev.Get) 432 } 433 434 // -------------------------------------------------------------------------------- 435 // Service Specific helpers 436 // -------------------------------------------------------------------------------- 437 438 // ServiceEnv is a common environment variable for the services environment. 439 // Common values include "dev", "ci", "sandbox", "preprod", "beta", and "prod". 440 func (ev Vars) ServiceEnv(defaults ...string) string { 441 return ev.String(VarServiceEnv, defaults...) 442 } 443 444 // IsProduction returns if the ServiceEnv is a production environment. 445 func (ev Vars) IsProduction() bool { 446 return IsProduction(ev.ServiceEnv()) 447 } 448 449 // IsProdlike returns if the ServiceEnv is "prodlike". 450 func (ev Vars) IsProdlike() bool { 451 return IsProdlike(ev.ServiceEnv()) 452 } 453 454 // IsDev returns if the ServiceEnv is the local development environment. 455 func (ev Vars) IsDev() bool { 456 return IsDev(ev.ServiceEnv()) 457 } 458 459 // IsDevlike returns if the ServiceEnv is strictly the inverse of `IsProdlike`. 460 func (ev Vars) IsDevlike() bool { 461 return !IsProdlike(ev.ServiceEnv()) 462 } 463 464 // ServiceName is a common environment variable for the service's name. 465 func (ev Vars) ServiceName(defaults ...string) string { 466 return ev.String(VarServiceName, defaults...) 467 } 468 469 // Hostname is a common environment variable for the machine's hostname. 470 func (ev Vars) Hostname(defaults ...string) string { 471 return ev.String(VarHostname, defaults...) 472 } 473 474 // Version is a common environment variable for the service version. 475 func (ev Vars) Version(defaults ...string) string { 476 return ev.String(VarVersion, defaults...) 477 }