envconfig

package module
v1.0.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 6, 2024 License: Apache-2.0 Imports: 14 Imported by: 309

README

Envconfig

GoDoc

Envconfig populates struct field values based on environment variables or arbitrary lookup functions. It supports pre-setting mutations, which is useful for things like converting values to uppercase, trimming whitespace, or looking up secrets.

Usage

Define a struct with fields using the env tag:

type MyConfig struct {
  Port     string `env:"PORT"`
  Username string `env:"USERNAME"`
}

Set some environment variables:

export PORT=5555
export USERNAME=yoyo

Process it using envconfig:

package main

import (
  "context"
  "log"

  "github.com/sethvargo/go-envconfig"
)

func main() {
  ctx := context.Background()

  var c MyConfig
  if err := envconfig.Process(ctx, &c); err != nil {
    log.Fatal(err)
  }

  // c.Port = 5555
  // c.Username = "yoyo"
}

You can also use nested structs, just remember that any fields you want to process must be public:

type MyConfig struct {
  Database *DatabaseConfig
}

type DatabaseConfig struct {
  Port     string `env:"PORT"`
  Username string `env:"USERNAME"`
}

Configuration

Use the env struct tag to define configuration. See the godoc for usage examples.

  • required - marks a field as required. If a field is required, decoding will error if the environment variable is unset.

    type MyStruct struct {
      Port string `env:"PORT, required"`
    }
    
  • default - sets the default value for the environment variable is not set. The environment variable must not be set (e.g. unset PORT). If the environment variable is the empty string, envconfig considers that a "value" and the default will not be used.

    You can also set the default value to the value from another field or a value from a different environment variable.

    type MyStruct struct {
      Port string `env:"PORT, default=5555"`
      User string `env:"USER, default=$CURRENT_USER"`
    }
    
  • prefix - sets the prefix to use for looking up environment variable keys on child structs and fields. This is useful for shared configurations:

    type RedisConfig struct {
      Host string `env:"REDIS_HOST"`
      User string `env:"REDIS_USER"`
    }
    
    type ServerConfig struct {
      // CacheConfig will process values from $CACHE_REDIS_HOST and
      // $CACHE_REDIS respectively.
      CacheConfig *RedisConfig `env:", prefix=CACHE_"`
    
      // RateLimitConfig will process values from $RATE_LIMIT_REDIS_HOST and
      // $RATE_LIMIT_REDIS respectively.
      RateLimitConfig *RedisConfig `env:", prefix=RATE_LIMIT_"`
    }
    
  • overwrite - force overwriting existing non-zero struct values if the environment variable was provided.

    type MyStruct struct {
      Port string `env:"PORT, overwrite"`
    }
    

    The rules for overwrite + default are:

    • If the struct field has the zero value and a default is set:

      • If no environment variable is specified, the struct field will be populated with the default value.

      • If an environment variable is specified, the struct field will be populate with the environment variable value.

    • If the struct field has a non-zero value and a default is set:

      • If no environment variable is specified, the struct field's existing value will be used (the default is ignored).

      • If an environment variable is specified, the struct field's existing value will be overwritten with the environment variable value.

  • delimiter - choose a custom character to denote individual slice and map entries. The default value is the comma (,).

    type MyStruct struct {
      MyVar []string `env:"MYVAR, delimiter=;"`
    
    export MYVAR="a;b;c;d" # []string{"a", "b", "c", "d"}
    
  • separator - choose a custom character to denote the separation between keys and values in map entries. The default value is the colon (:) Define a separator with separator:

    type MyStruct struct {
      MyVar map[string]string `env:"MYVAR, separator=|"`
    }
    
    export MYVAR="a|b,c|d" # map[string]string{"a":"b", "c":"d"}
    
  • noinit - do not initialize struct fields unless environment variables were provided. The default behavior is to deeply initialize all fields to their default (zero) value.

    type MyStruct struct {
      MyVar *url.URL `env:"MYVAR, noinit"`
    }
    
  • decodeunset - force envconfig to run decoders even on unset environment variable values. The default behavior is to skip running decoders on unset environment variable values.

    type MyStruct struct {
      MyVar *url.URL `env:"MYVAR, decodeunset"`
    }
    

Decoding

[!NOTE]

Complex types are only decoded or unmarshalled when the environment variable is defined or a default value is specified.

Durations

In the environment, time.Duration values are specified as a parsable Go duration:

type MyStruct struct {
  MyVar time.Duration `env:"MYVAR"`
}
export MYVAR="10m" # 10 * time.Minute
TextUnmarshaler / BinaryUnmarshaler

Types that implement TextUnmarshaler or BinaryUnmarshaler are processed as such.

json.Unmarshaler

Types that implement json.Unmarshaler are processed as such.

gob.Decoder

Types that implement gob.Decoder are processed as such.

Slices

Slices are specified as comma-separated values.

type MyStruct struct {
  MyVar []string `env:"MYVAR"`
}
export MYVAR="a,b,c,d" # []string{"a", "b", "c", "d"}

Note that byte slices are special cased and interpreted as strings from the environment.

Maps

Maps are specified as comma-separated key:value pairs:

type MyStruct struct {
  MyVar map[string]string `env:"MYVAR"`
}
export MYVAR="a:b,c:d" # map[string]string{"a":"b", "c":"d"}
Structs

Envconfig walks the entire struct, including nested structs, so deeply-nested fields are also supported.

If a nested struct is a pointer type, it will automatically be instantianted to the non-nil value. To change this behavior, see Initialization.

Custom Decoders

You can also define your own decoders. See the godoc for more information.

Testing

Relying on the environment in tests can be troublesome because environment variables are global, which makes it difficult to parallelize the tests. Envconfig supports extracting data from anything that returns a value:

lookuper := envconfig.MapLookuper(map[string]string{
  "FOO": "bar",
  "ZIP": "zap",
})

var config Config
envconfig.ProcessWith(ctx, &config, &envconfig.Config{
  Lookuper: lookuper,
})

Now you can parallelize all your tests by providing a map for the lookup function. In fact, that's how the tests in this repo work, so check there for an example.

You can also combine multiple lookupers with MultiLookuper. See the GoDoc for more information and examples.

Documentation

Overview

Package envconfig populates struct fields based on environment variable values (or anything that responds to "Lookup"). Structs declare their environment dependencies using the "env" tag with the key being the name of the environment variable, case sensitive.

type MyStruct struct {
  A string `env:"A"` // resolves A to $A
  B string `env:"B,required"` // resolves B to $B, errors if $B is unset
  C string `env:"C,default=foo"` // resolves C to $C, defaults to "foo"

  D string `env:"D,required,default=foo"` // error, cannot be required and default
  E string `env:""` // error, must specify key
}

All built-in types are supported except Func and Chan. If you need to define a custom decoder, implement Decoder:

type MyStruct struct {
  field string
}

func (v *MyStruct) EnvDecode(val string) error {
  v.field = fmt.Sprintf("PREFIX-%s", val)
  return nil
}

In the environment, slices are specified as comma-separated values:

export MYVAR="a,b,c,d" // []string{"a", "b", "c", "d"}

In the environment, maps are specified as comma-separated key:value pairs:

export MYVAR="a:b,c:d" // map[string]string{"a":"b", "c":"d"}

For more configuration options and examples, see the documentation.

Example (Basic)
// This example demonstrates the basic usage for envconfig.

type MyStruct struct {
	Port     int    `env:"PORT"`
	Username string `env:"USERNAME"`
}

// Set some environment variables in the process:
//
//     export PORT=5555
//     export USERNAME=yoyo
//

var s MyStruct
if err := envconfig.Process(ctx, &s); err != nil {
	panic(err) // TODO: handle error
}

// c.Port = 5555
// c.Username = "yoyo"
Output:

Example (CustomConfiguration)
// This example demonstrates how to set global configuration options that
// apply to all decoding (unless overridden at the field level).

type HTTPConfig struct {
	AllowedHeaders  map[string]string `env:"ALLOWED_HEADERS"`
	RejectedHeaders map[string]string `env:"REJECTED_HEADERS, delimiter=|"`
}

var httpConfig HTTPConfig
if err := envconfig.ProcessWith(ctx, &envconfig.Config{
	Target: &httpConfig,

	// All fields will use a ";" delimiter and "@" separator, unless locally
	// overridden.
	DefaultDelimiter: ";",
	DefaultSeparator: "@",

	Lookuper: envconfig.MapLookuper(map[string]string{
		"ALLOWED_HEADERS":  "header1@value1;header2@value2",
		"REJECTED_HEADERS": "header3@value3|header4@value4",
	}),
}); err != nil {
	panic(err)
}

fmt.Printf("allowed: %v\n", httpConfig.AllowedHeaders)
fmt.Printf("rejected: %v\n", httpConfig.RejectedHeaders)
Output:

allowed: map[header1:value1 header2:value2]
rejected: map[header3:value3 header4:value4]
Example (Decoder)
package main

import (
	"encoding/json"
	"fmt"

	"github.com/sethvargo/go-envconfig"
)

type CustomStruct struct {
	Port string `json:"port"`
	User string `json:"user"`
	Max  int    `json:"max"`
}

func (s *CustomStruct) EnvDecode(val string) error {
	return json.Unmarshal([]byte(val), s)
}

func main() {
	// This example demonstrates defining a custom decoder function.

	type MyStruct struct {
		Config CustomStruct `env:"CONFIG"`
	}

	var s MyStruct
	if err := envconfig.ProcessWith(ctx, &envconfig.Config{
		Target: &s,
		Lookuper: envconfig.MapLookuper(map[string]string{
			"CONFIG": `{
				"port": "8080",
				"user": "yoyo",
				"max": 51
			}`,
		}),
	}); err != nil {
		panic(err) // TODO: handle error
	}

	fmt.Printf("port: %v\n", s.Config.Port)
	fmt.Printf("user: %v\n", s.Config.User)
	fmt.Printf("max: %v\n", s.Config.Max)

}
Output:

port: 8080
user: yoyo
max: 51
Example (Decodeunset)
// This example demonstrates forcing envconfig to run decoders, even on unset
// environment variables.

type MyStruct struct {
	UrlA *url.URL `env:"URL_A"`
	UrlB *url.URL `env:"URL_B, decodeunset"`
}

var s MyStruct
if err := envconfig.Process(ctx, &s); err != nil {
	panic(err)
}

fmt.Printf("urlA: %s\n", s.UrlA)
fmt.Printf("urlB: %s\n", s.UrlB)
Output:

urlA: //@
urlB:
Example (Defaults)
// This example demonstrates how to set default values for fields. Fields will
// use their default value if no value is provided for that key in the
// environment.

type MyStruct struct {
	Port     int    `env:"PORT, default=8080"`
	Username string `env:"USERNAME, default=$OTHER_ENV"`
}

var s MyStruct
if err := envconfig.Process(ctx, &s); err != nil {
	panic(err) // TODO: handle error
}

fmt.Printf("port: %d\n", s.Port)
Output:

port: 8080
Example (InheritedConfiguration)
// This example demonstrates how struct-level configuration options are
// propagated to child fields and structs.

type Credentials struct {
	Username string `env:"USERNAME"`
	Password string `env:"PASSWORD"`
}

type Metadata struct {
	Headers map[string]string  `env:"HEADERS"`
	Footers []string           `env:"FOOTERS"`
	Margins map[string]float64 `env:"MARGINS, delimiter=\\,, separator=:"`
}

type ConnectionInfo struct {
	Address string `env:"ADDRESS"`

	// All child fields will be required.
	Credentials *Credentials `env:",required"`

	// All child fields will use a ";" delimiter and "@" separator, unless
	// locally overridden.
	Metadata *Metadata `env:",delimiter=;, separator=@"`
}

var conn ConnectionInfo
if err := envconfig.ProcessWith(ctx, &envconfig.Config{
	Target: &conn,
	Lookuper: envconfig.MapLookuper(map[string]string{
		"ADDRESS":  "127.0.0.1",
		"USERNAME": "user",
		"PASSWORD": "pass",
		"HEADERS":  "header1@value1;header2@value2",
		"FOOTERS":  "footer1; footer2",
		"MARGINS":  "top:0.5, bottom:1.5",
	}),
}); err != nil {
	panic(err)
}

fmt.Printf("address: %q\n", conn.Address)
fmt.Printf("username: %q\n", conn.Credentials.Username)
fmt.Printf("password: %q\n", conn.Credentials.Password)
fmt.Printf("headers: %v\n", conn.Metadata.Headers)
fmt.Printf("footers: %q\n", conn.Metadata.Footers)
fmt.Printf("margins: %v\n", conn.Metadata.Margins)
Output:

address: "127.0.0.1"
username: "user"
password: "pass"
headers: map[header1:value1 header2:value2]
footers: ["footer1" "footer2"]
margins: map[bottom:1.5 top:0.5]
Example (MapLookuper)
// This example demonstrates using a [MapLookuper] to source environment
// variables from a map instead of the environment. The map will always be of
// type string=string, because environment variables are always string types.

type MyStruct struct {
	Port     int    `env:"PORT"`
	Username string `env:"USERNAME"`
}

var s MyStruct
if err := envconfig.ProcessWith(ctx, &envconfig.Config{
	Target: &s,
	Lookuper: envconfig.MapLookuper(map[string]string{
		"PORT":     "5555",
		"USERNAME": "yoyo",
	}),
}); err != nil {
	panic(err) // TODO: handle error
}

fmt.Printf("port: %d\n", s.Port)
fmt.Printf("username: %q\n", s.Username)
Output:

port: 5555
username: "yoyo"
Example (Mutator)
package main

import (
	"context"
	"fmt"

	"github.com/sethvargo/go-envconfig"
)

// MyMutator is a mutator that keeps a count of all mutated values, appending
// the current count to each environment variable that is processed.
type MyMutator struct {
	counter int
}

func (m *MyMutator) EnvMutate(ctx context.Context, originalKey, resolvedKey, originalValue, currentValue string) (newValue string, stop bool, err error) {
	m.counter++
	return fmt.Sprintf("%s-%d", currentValue, m.counter), false, nil
}

func main() {
	// This exmaple demonstrates authoring a complex mutator that modifies
	// environment variable values before processing.

	type MyStruct struct {
		FieldA string `env:"FIELD_A"`
		FieldB string `env:"FIELD_B"`
		FieldC string `env:"FIELD_C"`
		FieldD string `env:"FIELD_D"`
	}

	var s MyStruct
	if err := envconfig.ProcessWith(ctx, &envconfig.Config{
		Target: &s,
		Lookuper: envconfig.MapLookuper(map[string]string{
			"FIELD_A": "a",
			"FIELD_B": "b",
			"FIELD_C": "c",
		}),
		Mutators: []envconfig.Mutator{&MyMutator{}},
	}); err != nil {
		panic(err) // TODO: handle error
	}

	fmt.Printf("field a: %q\n", s.FieldA)
	fmt.Printf("field b: %q\n", s.FieldB)
	fmt.Printf("field c: %q\n", s.FieldC)
	fmt.Printf("field d: %q\n", s.FieldD)

}
Output:

field a: "a-1"
field b: "b-2"
field c: "c-3"
field d: ""
Example (MutatorFunc)
// This example demonstrates authoring mutator functions to modify environment
// variable values before processing.

type MyStruct struct {
	Password string `env:"PASSWORD"`
}

resolveSecretFunc := envconfig.MutatorFunc(func(ctx context.Context, originalKey, resolvedKey, originalValue, resolvedValue string) (newValue string, stop bool, err error) {
	if strings.HasPrefix(resolvedValue, "secret://") {
		v, err := secretmanager.Resolve(ctx, resolvedValue)
		if err != nil {
			return resolvedValue, true, fmt.Errorf("failed to access secret: %w", err)
		}
		return v, false, nil
	}
	return resolvedValue, false, nil
})

var s MyStruct
if err := envconfig.ProcessWith(ctx, &envconfig.Config{
	Target:   &s,
	Lookuper: envconfig.OsLookuper(),
	Mutators: []envconfig.Mutator{resolveSecretFunc},
}); err != nil {
	panic(err) // TODO: handle error
}
Output:

Example (Noinit)
// This example demonstrates setting the "noinit" tag to bypass
// initialization.

type MyStruct struct {
	SecureA *bool `env:"SECURE_A"`
	SecureB *bool `env:"SECURE_B, noinit"`
}

var s MyStruct
if err := envconfig.Process(ctx, &s); err != nil {
	panic(err)
}

printVal := func(v *bool) string {
	if v != nil {
		return strconv.FormatBool(*v)
	}
	return "<nil>"
}

fmt.Printf("secureA: %s\n", printVal(s.SecureA))
fmt.Printf("secureB: %s\n", printVal(s.SecureB))
Output:

secureA: false
secureB: <nil>
Example (Overwrite)
// This example demonstrates how to tell envconfig to overwrite existing
// struct values.

type MyStruct struct {
	Port int `env:"PORT, overwrite"`
}

s := &MyStruct{
	Port: 1234,
}
if err := envconfig.ProcessWith(ctx, &envconfig.Config{
	Target: s,
	Lookuper: envconfig.MapLookuper(map[string]string{
		"PORT": "8080",
	}),
}); err != nil {
	panic(err) // TODO: handle error
}

fmt.Printf("port: %d\n", s.Port)
Output:

port: 8080
Example (Prefix)
// This example demonstrates using prefixes to share structures.

type RedisConfig struct {
	Host string `env:"REDIS_HOST"`
	User string `env:"REDIS_USER"`
}

type ServerConfig struct {
	// CacheConfig will process values from $CACHE_REDIS_HOST and
	// $CACHE_REDIS respectively.
	CacheConfig *RedisConfig `env:", prefix=CACHE_"`

	// RateLimitConfig will process values from $RATE_LIMIT_REDIS_HOST and
	// $RATE_LIMIT_REDIS respectively.
	RateLimitConfig *RedisConfig `env:", prefix=RATE_LIMIT_"`
}

var s ServerConfig
if err := envconfig.ProcessWith(ctx, &envconfig.Config{
	Target: &s,
	Lookuper: envconfig.MapLookuper(map[string]string{
		"CACHE_REDIS_HOST":      "https://cache.host.internal",
		"CACHE_REDIS_USER":      "cacher",
		"RATE_LIMIT_REDIS_HOST": "https://limiter.host.internal",
		"RATE_LIMIT_REDIS_USER": "limiter",
	}),
}); err != nil {
	panic(err) // TODO: handle error
}

fmt.Printf("cache redis host: %s\n", s.CacheConfig.Host)
fmt.Printf("cache redis user: %s\n", s.CacheConfig.User)
fmt.Printf("rate limit redis host: %s\n", s.RateLimitConfig.Host)
fmt.Printf("rate limit redis user: %s\n", s.RateLimitConfig.User)
Output:

cache redis host: https://cache.host.internal
cache redis user: cacher
rate limit redis host: https://limiter.host.internal
rate limit redis user: limiter
Example (PrefixLookuper)
// This example demonstrates using a [PrefixLookuper] to programatically alter
// environment variable keys to include the given prefix.

type MyStruct struct {
	Port int `env:"PORT"`
}

var s MyStruct
if err := envconfig.ProcessWith(ctx, &envconfig.Config{
	Target: &s,
	Lookuper: envconfig.PrefixLookuper("APP_", envconfig.MapLookuper(map[string]string{
		"APP_PORT": "1234",
	})),
}); err != nil {
	panic(err)
}

fmt.Printf("port: %d\n", s.Port)
Output:

port: 1234
Example (Required)
// This example demonstrates how to set fields as required. Required fields
// will error if unset.

type MyStruct struct {
	Port int `env:"PORT, required"`
}

var s MyStruct
if err := envconfig.Process(ctx, &s); err != nil {
	fmt.Printf("error: %s\n", err)
}
Output:

error: Port: missing required value: PORT

Index

Examples

Constants

View Source
const (
	ErrInvalidEnvvarName  = internalError("invalid environment variable name")
	ErrInvalidMapItem     = internalError("invalid map item")
	ErrLookuperNil        = internalError("lookuper cannot be nil")
	ErrMissingKey         = internalError("missing key")
	ErrMissingRequired    = internalError("missing required value")
	ErrNoInitNotPtr       = internalError("field must be a pointer to have noinit")
	ErrNotPtr             = internalError("input must be a pointer")
	ErrNotStruct          = internalError("input must be a struct")
	ErrPrefixNotStruct    = internalError("prefix is only valid on struct types")
	ErrPrivateField       = internalError("cannot parse private fields")
	ErrRequiredAndDefault = internalError("field cannot be required and have a default value")
	ErrUnknownOption      = internalError("unknown option")
)

Variables

This section is empty.

Functions

func Process

func Process(ctx context.Context, i any, mus ...Mutator) error

Process decodes the struct using values from environment variables. See ProcessWith for a more customizable version.

func ProcessWith

func ProcessWith(ctx context.Context, c *Config) error

ProcessWith executes the decoding process using the provided Config.

Types

type Base64Bytes added in v0.3.0

type Base64Bytes []byte

Base64Bytes is a slice of bytes where the information is base64-encoded in the environment variable.

func (Base64Bytes) Bytes added in v0.3.0

func (b Base64Bytes) Bytes() []byte

Bytes returns the underlying bytes.

func (*Base64Bytes) EnvDecode added in v0.3.0

func (b *Base64Bytes) EnvDecode(val string) error

EnvDecode implements env.Decoder.

type Config added in v1.0.0

type Config struct {
	// Target is the destination structure to decode. This value is required, and
	// it must be a pointer to a struct.
	Target any

	// Lookuper is the lookuper implementation to use. If not provided, it
	// defaults to the OS Lookuper.
	Lookuper Lookuper

	// DefaultDelimiter is the default value to use for the delimiter in maps and
	// slices. This can be overridden on a per-field basis, which takes
	// precedence. The default value is ",".
	DefaultDelimiter string

	// DefaultSeparator is the default value to use for the separator in maps.
	// This can be overridden on a per-field basis, which takes precedence. The
	// default value is ":".
	DefaultSeparator string

	// DefaultNoInit is the default value for skipping initialization of
	// unprovided fields. The default value is false (deeply initialize all
	// fields and nested structs).
	DefaultNoInit bool

	// DefaultOverwrite is the default value for overwriting an existing value set
	// on the struct before processing. The default value is false.
	DefaultOverwrite bool

	// DefaultDecodeUnset is the default value for running decoders even when no
	// value was given for the environment variable.
	DefaultDecodeUnset bool

	// DefaultRequired is the default value for marking a field as required. The
	// default value is false.
	DefaultRequired bool

	// Mutators is an optiona list of mutators to apply to lookups.
	Mutators []Mutator
}

Config represent inputs to the envconfig decoding.

type Decoder

type Decoder interface {
	EnvDecode(val string) error
}

Decoder is an interface that custom types/fields can implement to control how decoding takes place. For example:

type MyType string

func (mt MyType) EnvDecode(val string) error {
    return "CUSTOM-"+val
}

type HexBytes added in v0.3.0

type HexBytes []byte

HexBytes is a slice of bytes where the information is hex-encoded in the environment variable.

func (HexBytes) Bytes added in v0.3.0

func (b HexBytes) Bytes() []byte

Bytes returns the underlying bytes.

func (*HexBytes) EnvDecode added in v0.3.0

func (b *HexBytes) EnvDecode(val string) error

EnvDecode implements env.Decoder.

type Lookuper

type Lookuper interface {
	// Lookup searches for the given key and returns the corresponding string
	// value. If a value is found, it returns the value and true. If a value is
	// not found, it returns the empty string and false.
	Lookup(key string) (string, bool)
}

Lookuper is an interface that provides a lookup for a string-based key.

func MapLookuper

func MapLookuper(m map[string]string) Lookuper

MapLookuper looks up environment configuration from a provided map. This is useful for testing, especially in parallel, since it does not require you to mutate the parent environment (which is stateful).

func MultiLookuper

func MultiLookuper(lookupers ...Lookuper) Lookuper

MultiLookuper wraps a collection of lookupers. It does not combine them, and lookups appear in the order in which they are provided to the initializer.

func OsLookuper

func OsLookuper() Lookuper

OsLookuper returns a lookuper that uses the environment (os.LookupEnv) to resolve values.

func PrefixLookuper

func PrefixLookuper(prefix string, l Lookuper) Lookuper

PrefixLookuper looks up environment configuration using the specified prefix. This is useful if you want all your variables to start with a particular prefix like "MY_APP_".

type Mutator added in v1.0.0

type Mutator interface {
	// EnvMutate is called to alter the environment variable value.
	//
	//   - `originalKey` is the unmodified environment variable name as it was defined
	//     on the struct.
	//
	//   - `resolvedKey` is the fully-resolved environment variable name, which may
	//     include prefixes or modifications from processing. When there are
	//     no modifications, this will be equivalent to `originalKey`.
	//
	//   - `originalValue` is the unmodified environment variable's value before any
	//     mutations were run.
	//
	//   - `currentValue` is the currently-resolved value, which may have been
	//     modified by previous mutators and may be modified in the future by
	//     subsequent mutators in the stack.
	//
	// The function returns (in order):
	//
	//   - The new value to use in both future mutations and final processing.
	//
	//   - A boolean which indicates whether future mutations in the stack should be
	//     applied.
	//
	//   - Any errors that occurred.
	//
	EnvMutate(ctx context.Context, originalKey, resolvedKey, originalValue, currentValue string) (newValue string, stop bool, err error)
}

Mutator is the interface for a mutator function. Mutators act like middleware and alter values for subsequent processing. This is useful if you want to mutate the environment variable value before it's converted to the proper type.

Mutators are only called on defined values (or when decodeunset is true).

type MutatorFunc

type MutatorFunc func(ctx context.Context, originalKey, resolvedKey, originalValue, currentValue string) (newValue string, stop bool, err error)

MutatorFunc implements the Mutator and provides a quick way to create an anonymous function.

func LegacyMutatorFunc deprecated added in v1.0.0

func LegacyMutatorFunc(fn func(ctx context.Context, key, value string) (string, error)) MutatorFunc

LegacyMutatorFunc is a helper that eases the transition from the previous MutatorFunc signature. It wraps the previous-style mutator function and returns a new one. Since the former mutator function had less data, this is inherently lossy.

Deprecated: Use MutatorFunc instead.

func (MutatorFunc) EnvMutate added in v1.0.0

func (m MutatorFunc) EnvMutate(ctx context.Context, originalKey, resolvedKey, originalValue, currentValue string) (newValue string, stop bool, err error)

EnvMutate implements Mutator.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL