env

package module
Version: v0.5.1 Latest Latest
Warning

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

Go to latest
Published: Jul 31, 2020 License: MIT Imports: 10 Imported by: 2

README

go-env

Build Status Go Report Card Codacy coverage GitHub licence GoDoc

Access environment variables from Go, and populate structs from them.

Usage

Import path is go.deanishe.net/env.

You can directly access environment variables, or populate your structs from them using struct tags and env.Bind().

Access environment variables

Read int, float64, duration and string values from environment variables, with optional fallback values for unset variables.

import "go.deanishe.net/env"

// Get value for key or return empty string
s := env.Get("SHELL")

// Get value for key or return a specified default
s := env.Get("DOES_NOT_EXIST", "fallback value")

// Get an int (or 0 if SOME_NUMBER is unset or empty)
i := env.GetInt("SOME_NUMBER")

// Int with a fallback
i := env.GetInt("SOME_UNSET_NUMBER", 10)

Binding

You can also populate a struct directly from the environment by appropriately tagging it and calling env.Bind():

// Simple configuration struct
type config struct {
    HostName string `env:"HOSTNAME"` // default would be HOST_NAME
    Port     int    // leave as default (PORT)
    SSL      bool   `env:"USE_SSL"` // default would be SSL
    Online   bool   `env:"-"`       // ignore this field
}

// Set some values in the environment for test purposes
os.Setenv("HOSTNAME", "api.example.com")
os.Setenv("PORT", "443")
os.Setenv("USE_SSL", "1")
os.Setenv("ONLINE", "1") // will be ignored

// Create a config and bind it to the environment
c := &config{}
if err := Bind(c); err != nil {
    // handle error...
}

// config struct now populated from the environment
fmt.Println(c.HostName)
fmt.Printf("%d\n", c.Port)
fmt.Printf("%v\n", c.SSL)
fmt.Printf("%v\n", c.Online)
// Output:
// api.example.com
// 443
// true
// false

Customisation

Variables are retrieved via implementors of the env.Env interface (which env.Bind() accepts as a second, optional parameter):

type Env interface {
	// Lookup retrieves the value of the variable named by key.
	//
	// It follows the same semantics as os.LookupEnv(). If a variable
	// is unset, the boolean will be false. If a variable is set, the
	// boolean will be true, but the variable may still be an empty
	// string.
	Lookup(key string) (string, bool)
}

So you can pass a custom Env implementation to Bind() in order to populate structs from a source other than environment variables.

See _examples/docopt to see how to implement a custom Env that populates a struct from docopt command-line options.

Dumping

Dump a struct to a map[string]string by passing it to Dump():

type options struct {
    Hostname string
    Port int
}

o := options{
    Hostname: "www.example.com",
    Port: 22,
}

vars, err := Dump(o)
if err != nil {
     // handler err
}

fmt.Println(vars["HOSTNAME"]) // -> www.example.com
fmt.Println(vars["PORT"])     // -> 22

Installation

go get go.deanishe.net/env

Documentation

Read the documentation on GoDoc.

Licence

This library is released under the MIT Licence.

Documentation

Overview

Package env maps environment variables to struct fields and vice versa.

It is heavily based on github.com/caarlos0/env, but has different semantics, and also allows the dumping of a struct to environment variables, not just populating a struct from environment variables.

Reading variables

Read environment variables with the Get* functions:

// String
s := env.Get("HOME")
// String with fallback
s = env.Get("NON_EXISTENT_VAR", "default") // -> default

// Int
i := env.GetInt("SOME_COUNT")
// Int with fallback
i = env.GetInt("NON_EXISTENT_VAR", 10) // -> 10

// Duration (e.g. "1m", "2h30m", "5.3s")
d := env.GetDuration("SOME_TIME")
// Duration with fallback
d = env.GetDuration("NON_EXISTENT_VAR", time.Minute * 120) // -> 2h0m

Populating structs

Populate a struct from the environment by passing it to Bind():

type options struct {
	Hostname string
	Port     int
}

o := &options{}
if err := env.Bind(o); err != nil {
	// handle error...
}

fmt.Println(o.Hostname) // -> value of HOSTNAME environment variable
fmt.Println(o.Port)     // -> value of PORT environment variable

Use tags to specify a variable name or ignore a field:

type options {
	HostName string `env:"HOSTNAME"` // default would be HOST_NAME
	Port     int
	Online   bool `env:"-"` // ignored
}

Dumping structs

Dump a struct to a map[string]string by passing it to Dump():

type options struct {
    Hostname string
    Port int
}

o := options{
    Hostname: "www.example.com",
    Port: 22,
}

vars, err := Dump(o)
if err != nil {
     // handler err
}

fmt.Println(vars["HOSTNAME"]) // -> www.example.com
fmt.Println(vars["PORT"])     // -> 22

Tags

Add `env:"..."` tags to your struct fields to bind them to specific environment variables or ignore them. `env:"-"` tells Bind() to ignore the field:

type options {
	UserName      string
	LastUpdatedAt string `env:"-"` // Not loaded from environment
}

Add `env:"VARNAME"` to bind a field to the variable VARNAME:

type options {
	UserName string `env:"USERNAME"`   // default = USER_NAME
	APIKey   string `env:"APP_SECRET"` // default = API_KEY
}

Customisation

Variables are retrieved via implementors of the Env interface, which Bind() accepts as a second, optional parameter.

So you can pass a custom Env implementation to Bind() to populate structs from a source other than environment variables.

See _examples/docopt to see a custom Env implementation used to populate a struct from docopt command-line options.

You can also customise the map keys used when dumping a struct by passing VarNameFunc to Dump().

Licence

This library is released under the MIT Licence.

Index

Examples

Constants

This section is empty.

Variables

View Source
var (
	ErrNotStruct    = errors.New("not a struct")
	ErrNotStructPtr = errors.New("not a pointer to a struct")
)

Errors returned by Dump and Bind if they are called with inappropriate values. Bind() requires a pointer to a struct, while Dump requires either a struct or a pointer to a struct.

Functions

func Bind

func Bind(v interface{}, env ...Env) error

Bind populates the fields of a struct from environment variables.

Variables are mapped to fields using `env:"..."` tags, and the struct is populated by passing it to Bind(). Unset or empty environment variables are ignored.

Untagged fields have a default environment variable assigned to them. See VarName() for details of how names are generated.

Bind accepts an optional Env argument. If provided, values will be looked up via that Env instead of the program's environment.

Example

Populate a struct from environment variables.

// Simple configuration struct
type config struct {
	HostName     string        `env:"HOSTNAME"` // default: HOST_NAME
	UserName     string        `env:"USERNAME"` // default: USER_NAME
	SSL          bool          `env:"USE_SSL"`  // default: SSL
	Port         int           // leave as default (PORT)
	PingInterval time.Duration `env:"PING"` // default: PING_INTERVAL
	Online       bool          `env:"-"`    // ignore this field
}

// Set some values in the environment for test purposes
_ = os.Setenv("HOSTNAME", "api.example.com")
_ = os.Setenv("USERNAME", "") // empty
_ = os.Setenv("PORT", "443")
_ = os.Setenv("USE_SSL", "1")
_ = os.Setenv("PING", "5m")
_ = os.Setenv("ONLINE", "1") // will be ignored

// Create a config and bind it to the environment
c := &config{}
if err := Bind(c); err != nil {
	// handle error...
}

// config struct now populated from the environment
fmt.Println(c.HostName)
fmt.Println(c.UserName)
fmt.Printf("%d\n", c.Port)
fmt.Printf("%v\n", c.SSL)
fmt.Printf("%v\n", c.Online)
fmt.Printf("%v\n", c.PingInterval*4) // it's not a string!
Output:

api.example.com

443
true
false
20m0s
Example (EmptyVars)

In contrast to the Get* functions, Bind treats empty variables the same as unset ones and ignores them.

type config struct {
	Username string
	Email    string
}

// Defaults
c := &config{
	Username: "bob",
	Email:    "bob@aol.com",
}

_ = os.Setenv("USERNAME", "dave") // different value
_ = os.Setenv("EMAIL", "")        // empty value, ignored by Bind()

// Bind config to environment
if err := Bind(c); err != nil {
	panic(err)
}

fmt.Println(c.Username)
fmt.Println(c.Email)
Output:

dave
bob@aol.com

func Dump

func Dump(v interface{}, opt ...DumpOption) (map[string]string, error)

Dump extracts a struct's fields to a map of variables. By default, the names (map keys) of the variables are generated using VarName. Pass the VarNameFunc option to generate custom keys.

func Export

func Export(v interface{}, opt ...DumpOption) error

Export extracts a struct's fields' values (via Dump) and exports them to the environment (via os.Setenv). It accepts the same options as Dump.

func Get

func Get(key string, fallback ...string) string

Get returns the value for envvar "key". It accepts one optional "fallback" argument. If no envvar is set, returns fallback or an empty string.

If a variable is set, but empty, its value is used.

Example

Basic usage of Get. Returns an empty string if variable is unset.

// Set some test variables
_ = os.Setenv("TEST_NAME", "Bob Smith")
_ = os.Setenv("TEST_ADDRESS", "7, Dreary Lane")

fmt.Println(Get("TEST_NAME"))
fmt.Println(Get("TEST_ADDRESS"))
fmt.Println(Get("TEST_NONEXISTENT")) // unset variable

// GetString is a synonym
fmt.Println(GetString("TEST_NAME"))
Output:

Bob Smith
7, Dreary Lane

Bob Smith
Example (Fallback)

The fallback value is returned if the variable is unset.

// Set some test variables
_ = os.Setenv("TEST_NAME", "Bob Smith")
_ = os.Setenv("TEST_ADDRESS", "7, Dreary Lane")
_ = os.Setenv("TEST_EMAIL", "")

fmt.Println(Get("TEST_NAME", "default name"))       // fallback ignored
fmt.Println(Get("TEST_ADDRESS", "default address")) // fallback ignored
fmt.Println(Get("TEST_EMAIL", "test@example.com"))  // fallback ignored (var is empty, not unset)
fmt.Println(Get("TEST_NONEXISTENT", "hi there!"))   // unset variable
Output:

Bob Smith
7, Dreary Lane

hi there!

func GetBool

func GetBool(key string, fallback ...bool) bool

GetBool returns the value for envvar "key" as a boolean. It accepts one optional "fallback" argument. If no envvar is set, returns fallback or false.

Values are parsed with strconv.ParseBool().

Example

Strings are parsed using strconv.ParseBool().

// Set some test variables
_ = os.Setenv("LIKE_PEAS", "t")
_ = os.Setenv("LIKE_CARROTS", "true")
_ = os.Setenv("LIKE_BEANS", "1")
_ = os.Setenv("LIKE_LIVER", "f")
_ = os.Setenv("LIKE_TOMATOES", "0")
_ = os.Setenv("LIKE_BVB", "false")
_ = os.Setenv("LIKE_BAYERN", "FALSE")

// strconv.ParseBool() supports many formats
fmt.Println(GetBool("LIKE_PEAS"))
fmt.Println(GetBool("LIKE_CARROTS"))
fmt.Println(GetBool("LIKE_BEANS"))
fmt.Println(GetBool("LIKE_LIVER"))
fmt.Println(GetBool("LIKE_TOMATOES"))
fmt.Println(GetBool("LIKE_BVB"))
fmt.Println(GetBool("LIKE_BAYERN"))

// Fallback
fmt.Println(GetBool("LIKE_BEER", true))
Output:

true
true
true
false
false
false
false
true

func GetDuration

func GetDuration(key string, fallback ...time.Duration) time.Duration

GetDuration returns the value for envvar "key" as a time.Duration. It accepts one optional "fallback" argument. If no envvar is set, returns fallback or 0.

Values are parsed with time.ParseDuration().

Example

Durations are parsed using time.ParseDuration.

// Set some test variables
_ = os.Setenv("DURATION_NAP", "20m")
_ = os.Setenv("DURATION_EGG", "5m")
_ = os.Setenv("DURATION_BIG_EGG", "")
_ = os.Setenv("DURATION_MATCH", "1.5h")

// returns time.Duration
fmt.Println(GetDuration("DURATION_NAP"))
fmt.Println(GetDuration("DURATION_EGG") * 2)
// fallback with unset variable
fmt.Println(GetDuration("DURATION_POWERNAP", time.Minute*45))
// or an empty one
fmt.Println(GetDuration("DURATION_BIG_EGG", time.Minute*10))
fmt.Println(GetDuration("DURATION_MATCH").Minutes())
Output:

20m0s
10m0s
45m0s
10m0s
90

func GetFloat

func GetFloat(key string, fallback ...float64) float64

GetFloat returns the value for envvar "key" as a float. It accepts one optional "fallback" argument. If no envvar is set, returns fallback or 0.0.

Values are parsed with strconv.ParseFloat().

Example

Strings are parsed to floats using strconv.ParseFloat().

// Set some test variables
_ = os.Setenv("TOTAL_SCORE", "172.3")
_ = os.Setenv("AVERAGE_SCORE", "7.54")

fmt.Printf("%0.2f\n", GetFloat("TOTAL_SCORE"))
fmt.Printf("%0.1f\n", GetFloat("AVERAGE_SCORE"))
fmt.Println(GetFloat("NON_EXISTENT_SCORE", 120.5))
Output:

172.30
7.5
120.5

func GetInt

func GetInt(key string, fallback ...int) int

GetInt returns the value for envvar "key" as an int. It accepts one optional "fallback" argument. If no envvar is set, returns fallback or 0.

Values are parsed with strconv.ParseInt(). If strconv.ParseInt() fails, tries to parse the number with strconv.ParseFloat() and truncate it to an int.

Example

Getting int values with and without fallbacks.

// Set some test variables
_ = os.Setenv("PORT", "3000")
_ = os.Setenv("PING_INTERVAL", "")

fmt.Println(GetInt("PORT"))
fmt.Println(GetInt("PORT", 5000))        // fallback is ignored
fmt.Println(GetInt("PING_INTERVAL"))     // returns zero value
fmt.Println(GetInt("PING_INTERVAL", 60)) // returns fallback
Output:

3000
3000
0
60

func GetString

func GetString(key string, fallback ...string) string

GetString is a synonym for Get.

func GetUint

func GetUint(key string, fallback ...uint) uint

GetUint returns the value for envvar "key" as an int. It accepts one optional "fallback" argument. If no envvar is set, returns fallback or 0.

Values are parsed with strconv.ParseUint(). If strconv.ParseUint() fails, tries to parse the number with strconv.ParseFloat() and truncate it to a uint.

Example

Getting int values with and without fallbacks.

// Set some test variables
_ = os.Setenv("PORT", "3000")
_ = os.Setenv("PING_INTERVAL", "")

fmt.Println(GetUint("PORT"))
fmt.Println(GetUint("PORT", 5000))        // fallback is ignored
fmt.Println(GetUint("PING_INTERVAL"))     // returns zero value
fmt.Println(GetUint("PING_INTERVAL", 60)) // returns fallback
Output:

3000
3000
0
60

func VarName

func VarName(name string) string

VarName generates an environment variable name from a field name. This is documented to show how the automatic names are generated.

Example

Example output of VarName.

// single-case words are upper-cased
fmt.Println(VarName("URL"))
fmt.Println(VarName("name"))
// words that start with fewer than 3 uppercase chars are
// upper-cased
fmt.Println(VarName("Folder"))
fmt.Println(VarName("MTime"))
// but with 3+ uppercase chars, the last is treated as the first
// char of the next word
fmt.Println(VarName("VIPath"))
fmt.Println(VarName("URLEncoding"))
fmt.Println(VarName("SSLPort"))
// camel-case words are split on the case changes
fmt.Println(VarName("LastName"))
fmt.Println(VarName("LongHorse"))
fmt.Println(VarName("loginURL"))
fmt.Println(VarName("newHomeAddress"))
fmt.Println(VarName("PointA"))
// digits are considered as the end of a word, not the start
fmt.Println(VarName("b2B"))
Output:

URL
NAME
FOLDER
MTIME
VI_PATH
URL_ENCODING
SSL_PORT
LAST_NAME
LONG_HORSE
LOGIN_URL
NEW_HOME_ADDRESS
POINT_A
B2_B

Types

type DumpOption

type DumpOption func(d *dumper)

DumpOption is a configuration option to Dump.

var (
	// IgnoreZeroValues excludes zero values from the returned map of variables.
	// Non-nil slices are unaffected by the setting: an empty string is returned
	// for empty slices regardless.
	IgnoreZeroValues DumpOption = func(d *dumper) { d.noZero = true }
)

func VarNameFunc

func VarNameFunc(fun func(string) string) DumpOption

VarNameFunc specifies a different function to generate the names of the variables returned by Dump.

type Env

type Env interface {
	// Lookup retrieves the value of the variable named by key.
	//
	// It follows the same semantics as os.LookupEnv(). If a variable
	// is unset, the boolean will be false. If a variable is set, the
	// boolean will be true, but the variable may still be an empty
	// string.
	Lookup(key string) (string, bool)
}

Env is the data source for bindings and lookup. It is an optional parameter to Bind(). By specifying a custom Env, it's possible to populate a struct from an alternative source.

The demo program in _examples/docopt implements a custom Env to populate a struct from docopt options via Bind().

var (
	// System retrieves values from the system environment.
	System Env = systemEnv{}
)

type ErrUnsupported

type ErrUnsupported string

ErrUnsupported is returned by Bind if a field of an unsupported type is tagged for binding. Unsupported fields that are not tagged are ignored.

func (ErrUnsupported) Error

func (err ErrUnsupported) Error() string

implements error.Error.

type MapEnv

type MapEnv map[string]string

MapEnv is a string: string mapping that implements Env.

func (MapEnv) Lookup

func (env MapEnv) Lookup(key string) (string, bool)

Lookup implements Env.

type Reader

type Reader struct {
	// contains filtered or unexported fields
}

Reader converts values from Env into other types.

func New

func New(env Env) Reader

New creates a new Reader based on Env.

func (Reader) Get

func (r Reader) Get(key string, fallback ...string) string

Get returns the value for envvar "key". It accepts one optional "fallback" argument. If no envvar is set, returns fallback or an empty string.

If a variable is set, but empty, its value is used.

func (Reader) GetBool

func (r Reader) GetBool(key string, fallback ...bool) bool

GetBool returns the value for envvar "key" as a boolean. It accepts one optional "fallback" argument. If no envvar is set, returns fallback or false.

Values are parsed with strconv.ParseBool().

func (Reader) GetDuration

func (r Reader) GetDuration(key string, fallback ...time.Duration) time.Duration

GetDuration returns the value for envvar "key" as a time.Duration. It accepts one optional "fallback" argument. If no envvar is set, returns fallback or 0.

Values are parsed with time.ParseDuration().

func (Reader) GetFloat

func (r Reader) GetFloat(key string, fallback ...float64) float64

GetFloat returns the value for envvar "key" as a float. It accepts one optional "fallback" argument. If no envvar is set, returns fallback or 0.0.

Values are parsed with strconv.ParseFloat().

func (Reader) GetInt

func (r Reader) GetInt(key string, fallback ...int) int

GetInt returns the value for envvar "key" as an int. It accepts one optional "fallback" argument. If no envvar is set, returns fallback or 0.

Values are parsed with strconv.ParseInt(). If strconv.ParseInt() fails, tries to parse the number with strconv.ParseFloat() and truncate it to an int.

func (Reader) GetString

func (r Reader) GetString(key string, fallback ...string) string

GetString is a synonym for Get.

func (Reader) GetUint

func (r Reader) GetUint(key string, fallback ...uint) uint

GetUint returns the value for envvar "key" as an int. It accepts one optional "fallback" argument. If no envvar is set, returns fallback or 0.

Values are parsed with strconv.ParseUint(). If strconv.ParseUint() fails, tries to parse the number with strconv.ParseFloat() and truncate it to a uint.

Directories

Path Synopsis
_examples
docopt
Command docopt demonstrates binding docopt to a struct via env.
Command docopt demonstrates binding docopt to a struct via env.

Jump to

Keyboard shortcuts

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