Skip to content

Commit

Permalink
feat(sources/env): add RetroKeys option
Browse files Browse the repository at this point in the history
- change: `New` takes `handleDeprecatedKey` functional argument
  • Loading branch information
qdm12 committed Jun 2, 2023
1 parent c49adb3 commit e3fac87
Show file tree
Hide file tree
Showing 5 changed files with 64 additions and 9 deletions.
35 changes: 31 additions & 4 deletions sources/env/builtin.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,40 @@ import (
func (e *Env) Get(envKey string, options ...Option) (value *string) {
settings := settingsFromOptions(options)

envValue, isSet := e.environ[envKey]
if !isSet || (!*settings.acceptEmpty && envValue == "") {
keysToTry := make([]string, 0, 1+len(settings.retroKeys))
keysToTry = append(keysToTry, settings.retroKeys...)
// Note we try the current environment variable key last
// because it might be set in a Docker image so we want to
// take the older configuration from the user first.
keysToTry = append(keysToTry, envKey)

var firstEnvKeySet string
for _, keyToTry := range keysToTry {
envValue, isSet := e.environ[keyToTry]
if !isSet {
continue
}
firstEnvKeySet = envKey
value = new(string)
*value = envValue
break
}

if firstEnvKeySet == "" { // All keys are unset
return nil
}

if firstEnvKeySet != envKey {
e.handleDeprecatedKey(firstEnvKeySet, envKey)
}

if !*settings.acceptEmpty && *value == "" {
// environment variable value is set to the empty string,
// but the empty string is not accepted so return nil.
return nil
}

value = new(string)
*value = postProcessValue(envValue, settings)
*value = postProcessValue(*value, settings)
return value
}

Expand Down
18 changes: 14 additions & 4 deletions sources/env/env.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,19 @@ import "strings"
// Env is an environment variables reader
// with helping methods to parse values.
type Env struct {
environ map[string]string
environ map[string]string
handleDeprecatedKey func(oldKey string, currentKey string)
}

// New creates a new environment variables reader
// and initializes it with the given slice of environment
// variable strings, where each string is in the form
// "key=value".
func New(environ []string) *Env {
// "key=value". The functional argument `handleDeprecatedKey`
// is called when encountering a deprecated environment variable
// key, and defaults to a no-op function if left to `nil`.
func New(environ []string,
handleDeprecatedKey func(deprecatedKey string, currentKey string),
) *Env {
environMap := make(map[string]string, len(environ))
for _, keyValue := range environ {
const maxParts = 2
Expand All @@ -23,7 +28,12 @@ func New(environ []string) *Env {
environMap[parts[0]] = parts[1]
}

if handleDeprecatedKey == nil {
handleDeprecatedKey = func(oldKey string, currentKey string) {}
}

return &Env{
environ: environMap,
environ: environMap,
handleDeprecatedKey: handleDeprecatedKey,
}
}
8 changes: 7 additions & 1 deletion sources/env/env_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,8 @@ func Test_New(t *testing.T) {
}
testKeys[notExistsKey] = struct{}{}

env := New(os.Environ())
handleDeprecatedKey := (func(oldKey string, currentKey string))(nil)
env := New(os.Environ(), handleDeprecatedKey)

// Remove other test irrelevant environment variables
for k := range env.environ {
Expand All @@ -61,6 +62,11 @@ func Test_New(t *testing.T) {
}
}

if env.handleDeprecatedKey == nil {
t.Error("expected handleDeprecatedKey to be set")
}
env.handleDeprecatedKey = nil

expectedEnv := &Env{
environ: map[string]string{
emptyKey: "",
Expand Down
11 changes: 11 additions & 0 deletions sources/env/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,14 @@ func AcceptEmpty(accept bool) Option {
s.acceptEmpty = &accept
}
}

// RetroKeys specifies a list of environment variable keys
// that are deprecated and replaced by the current key.
// The `handleDeprecatedKey` function is called when a deprecated
// key is used, with the deprecated key and the current key as
// arguments.
func RetroKeys(retroKeys ...string) Option {
return func(s *settings) {
s.retroKeys = retroKeys
}
}
1 change: 1 addition & 0 deletions sources/env/settings.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ type settings struct {
trimQuotes *bool
forceLowercase *bool
acceptEmpty *bool
retroKeys []string
}

func settingsFromOptions(options []Option) (s settings) {
Expand Down

0 comments on commit e3fac87

Please sign in to comment.