envi

package module
v1.0.2 Latest Latest
Warning

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

Go to latest
Published: Mar 2, 2018 License: BSD-3-Clause Imports: 9 Imported by: 1

README

envi

GoDoc Build Status Coverage Status

envi is a library for loading data from structured environment variables and maps of strings (e.g., envi.Values) into structs, slices, and general scalars (strings, ints, bools, etc.).

Currently, you can unmarshal into the following types out of the box:

  • Integers (minus uintptr)
  • Floats
  • Bools
  • time.Duration
  • Strings and byte slices (treated equivalently)
  • url.URL
  • Anything that implements encoding.TextUnmarshaler or envi.Unmarshaler
  • Slices of the above
  • Structs with exported fields of the above (including nested structs)

License

envi is licensed under a BSD-3 clause license, the same as Go and can also be read in the LICENSE.txt file:

Copyright (c) 2015 Kochava. All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

  1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.

  2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.

  3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

Some code in envi, specifically code under indirect.go, is borrowed and modified from the Go standard library and is under Go's license, reproduced below:

Copyright (c) 2009 The Go Authors. All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

  • Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
  • Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
  • Neither the name of Google Inc. nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

Documentation

Overview

Package envi contains functions for unmarshaling data / configuration info from environment variables. These are primarily strings and other scalars, but can also include structs and slices.

Envi unmarshals structs by walking each field and concatenating them by a separator, configured as part of the Reader. It unmarshals slices by attempting to either split their explicit environment variable's value using a delimiter (defaults to whitespace) or by walking var_1 through var_N, determined by the Reader's MaxSliceLen.

Index

Examples

Constants

View Source
const DefaultMaxDepth = 8

DefaultMaxDepth is the default maximum depth of parsing nested struct values.

View Source
const DefaultMaxSliceLen = 1000

DefaultMaxSliceLen is the default maximum slice length used when parsing NAME_N slice values.

View Source
const OSEnv osenv = 0

OSEnv is an Env implementation that can be used to simply return os.Getenv values. This will allow empty values provided the environment variable is defined (i.e., LookupEnv returns a value and OK=true).

Variables

View Source
var DefaultReader = &Reader{Sep: "_"}

DefaultReader is the default envi *Reader used by the Getenv and Load functions. It may be changed, but it is not safe to modify it while in use.

View Source
var ErrInvalidBool = errors.New("bool is not valid")

ErrInvalidBool is returned if a boolean is not valid.

View Source
var ErrNoValue = errors.New("no value")

ErrNoValue is returned if a key has no value.

Functions

func Getenv

func Getenv(dst interface{}, key string) error

Getenv attempts to load the value held by the environment variable key into dst using the DefaultReader. If an error occurs, that error is returned. See Reader.Getenv for more information.

Example
// environment is used in this example to provide a consistent source of environment values.
// By default, envi will use the process's environment.
environment := Values{
	"ENVI_INTEGER":        {"0xff"},
	"ENVI_STR":            {"This is a normal string, nothing special"},
	"ENVI_INTEGERS":       {"1", "2", "3", "5", "8", "13", "21", "34"},
	"ENVI_STRS_1":         {"foo"},
	"ENVI_STRS_2":         {"bar"},
	"ENVI_STRS_3":         {"baz"},
	"ENVI_STRS_5":         {"wub"}, // No 4th index, so this is ignored
	"ENVI_STRUCT_VALID":   {"1234567"},
	"ENVI_STRUCT_INVALID": {"caterpillar"},
	"ENVI_STRUCT_IGNORED": {"1234567"},
}

// You can either allocate your own Reader or use the default one. The default
// separates fields in structs by underscores and gets its values from the process
// environment. This example uses a hardcoded Env and an _ separator for fields and
// indices.
reader := Reader{
	Source: environment,
	Sep:    "_",
}

var (
	integer  int
	str      string
	integers []int
	strs     []string
	novalue  int = -1

	structured struct {
		Valid   int `envi:"VALID"`
		Invalid int `envi:"INVALID,quiet"` // Ignore invalid values (caterpillar)
		Ignored int `envi:"-"`
	}
)

reader.Getenv(&integer, "ENVI_INTEGER")
fmt.Println(integer)
reader.Getenv(&str, "ENVI_STR")
fmt.Println(str)
reader.Getenv(&integers, "ENVI_INTEGERS")
fmt.Println(integers)
reader.Getenv(&strs, "ENVI_STRS")
fmt.Println(strs)

if err := reader.Getenv(&structured, "ENVI_STRUCT"); err != nil {
	panic(fmt.Errorf("Error unmarshaling structured value: %v", err))
}
fmt.Println(structured)

// ENVI_NOVALUE has no value, so it won't change and Getenv will return an no-value error.
if err := reader.Getenv(&novalue, "ENVI_NOVALUE"); !IsNoValue(err) {
	panic("NOVALUE was set -- expected no value!")
}
Output:

255
This is a normal string, nothing special
[1 2 3 5 8 13 21 34]
[foo bar baz]
{1234567 0 0}

func IsNoValue

func IsNoValue(err error) bool

IsNoValue is a convenience function returning whether the given error is a no-value error (i.e., is either a ErrNoValue or a KeyError containing ErrNoValue).

func Load

func Load(dst interface{}, val, key string) error

Load attempts to load the given value identified by key into dst using the DefaultReader. See Reader.Load and Reader.Getenv for more information.

func NoValueError

func NoValueError(key string) error

NoValueError returns a new KeyError containing ErrNoValue and the given key. This is mainly used for implementations of Unmarshaler and Env.

Types

type Env

type Env interface {
	Getenv(key string) (string, error)
}

Env is an environment variable source. Given an identifying key, it must return a corresponding value. If the resulting value is the empty string, it is considered unset for certain types.

type EnvFunc

type EnvFunc func(string) (string, error)

EnvFunc is a callback implementing Env.

func (EnvFunc) Getenv

func (fn EnvFunc) Getenv(key string) (string, error)

Getenv implements Env.

type FormatSplitter

type FormatSplitter struct {
	Split  Splitter            // optional; defaults to strings.Fields
	Format func(string) string // optional; defaults to strings.TrimSpace
}

FormatSplitter is a Splitter that, after splitting a value, uses a Format function to reformat each value from the split. By default, the splitter used is strings.Fields and the format function is strings.TrimSpace -- defaults take effect when Split or Format is nil, respectively.

func (FormatSplitter) SplitString

func (t FormatSplitter) SplitString(key, val string) (dst []string)

SplitString splits the given string value using its Split field, or strings.Fields if nil, and then reformats the resulting strings using its Format function (strings.TrimSpace if nil). This implements Splitter.

type KeyError

type KeyError struct {
	Key string
	Err error
}

KeyError is any error encountered when unmarshaling a specific key.

func (*KeyError) Error

func (k *KeyError) Error() string

type MultiEnvFunc

type MultiEnvFunc func(string) ([]string, error)

MultiEnvFunc is a function to return multiple environment values. It implements Env by returning only the first value in the result slice. If the result slice is empty, it returns a no-value error.

func (MultiEnvFunc) Getenv

func (fn MultiEnvFunc) Getenv(key string) (string, error)

Getenv implements Env.

func (MultiEnvFunc) GetenvAll

func (fn MultiEnvFunc) GetenvAll(key string) ([]string, error)

GetenvAll implements Multienv.

type Multienv

type Multienv interface {
	Env
	GetenvAll(key string) ([]string, error)
}

Multienv is an environment variable source capable of returning multiple environment variables. It must conform to Env, but in those cases, it is better for Env to return only the first of all results. Results will not be split when an Env is also a Multienv.

type Reader

type Reader struct {
	// Source provides environment variable values. If Source is also a Multienv, its GetenvAll implementation is
	// used in place of Split to get multiple values from the environment.
	Source Env
	// Split is used to split a value from Source into multiple values. If Source is a Multienv, Split is unused.
	Split Splitter
	// Sep is the separator used to join the prefix key and field names when unmarshaling
	// structs (and only structs).
	Sep string
	// MaxSliceLen is the maximum number of environment variables that will be checked for slice
	// values. If MaxSliceLen is less than 1, this defaults to DefaultMaxSliceLen.
	MaxSliceLen int
	// MaxDepth is the maximum depth that an unknown struct can be parsed at. If a struct is
	// encountered that does not have known keys, field parsing is abandoned after this depth.
	// If MaxDepth is less than 1, it defaults to DefaultMaxDepth.
	MaxDepth int
}

Reader defines the instance type of an envi unmarshaler.

func (*Reader) Getenv

func (r *Reader) Getenv(dst interface{}, key string) (err error)

Getenv attempts to load the value held by the environment variable key into dst. If an error occurs, it will return that error. If the environment variable identified by key is not set, a no-value error is returned.

If the environment variable is empty for those types without interfaces available, the behavior depends on that type. Strings are assigned an empty string, and byte slices are truncated to an empty slice.

If the environment value cannot be read, it returns the error provided by the Env source. If the error is ErrNoValue, it is returned as a *KeyError with the key attached.

Decoding rules for structs and slices are described under (*Reader).Load.

func (*Reader) Load

func (r *Reader) Load(dst interface{}, val, key string) (err error)

Load attempts to parse the given value (identified as key, which is occasionally relevant when assigning names to file descriptors) and store the result in dst. This can be used to circumvent envi's standard data source and use your own (e.g., INI files) without overriding the reader's source, as it's unused inside of Load.

If dst is a slice and an error occurs, dst is still assigned the value of partially unmarshaling the slice (by default using strings.Fields to separate slice values in the environment variable). This is only relevant if, for example, you unmarshal a slice of files, connections, listeners, or something else that must be closed, as Getenv will not close anything that is the result of incorrectly unmarshaling a slice.

Struct field decoding can be configured by using the 'envi' field tag. The first value of a field tagis always the name of the environment variable suffix, after a separator. Subsequent fields are flags.

For example:

type Example struct {
    // Unmarshal from ${Prefix}${Sep}SUFFIX
    NamedField int `envi:"SUFFIX"`
    // Set a custom separator of "___" -- unmarshals from ${Prefix}___SepField
    SepField int `envi:",sep=___"`
    // Use the field name -- unmarshals from ${Prefix}${Sep}UseFieldName
    UseFieldName int `envi:""`
    // Skip this field entirely
    SkipField int `envi:"-"`
    // Ignore errors on this field
    QuietField int `envi:",quiet"
}

Flags may be specified in any order, and the last flag seen of its type is the one that is used. The quiet flag is used to ignore unmarshaling failures. The sep flag sets a custom separator -- this does not allow commas. Fields with the suffix "-" are not unmarshaled into, and fields with an empty suffix use their field name as the suffix (without any change in case).

Slices of slices are supported but will only ever contain slices of single values.

type Splitter

type Splitter interface {
	SplitString(key, value string) []string
}

Splitter is an interface used by a Reader when the environment source cannot provide multiple strings per key. In those cases, a key's value is split into multiple values using a Splitter.

type SplitterFunc

type SplitterFunc func(k, v string) []string

SplitterFunc is a callback Splitter.

func (SplitterFunc) SplitString

func (fn SplitterFunc) SplitString(key, val string) []string

SplitString invokes the underlying callback with the given key and value. This implements Splitter.

type SplitterFuncNoKey

type SplitterFuncNoKey func(v string) []string

SplitterFuncNoKey is a callback Splitter that does not receive a key argument.

func (SplitterFuncNoKey) SplitString

func (fn SplitterFuncNoKey) SplitString(_, val string) []string

SplitString invokes the underlying callback with the given value. This implements Splitter.

type StringSplitter

type StringSplitter string

StringSplitter is a splitter that splits strings on itself (via strings.Split).

For example, StringSplitter(",") will split input values on commas.

func (StringSplitter) SplitString

func (delim StringSplitter) SplitString(_, val string) []string

SplitString splits the input string, val, using the string form of the receiver, delim. This implements Splitter.

type SyntaxError

type SyntaxError struct {
	Str string
	Err error
}

SyntaxError is any syntax error encountered as a result of parsing values.

func (*SyntaxError) Error

func (e *SyntaxError) Error() string

type TypeError

type TypeError struct {
	Type reflect.Type
}

TypeError represents any error that occurs as a result of loading an environment variable into the error's Type.

func (*TypeError) Error

func (t *TypeError) Error() string

type Unmarshaler

type Unmarshaler interface {
	UnmarshalEnv(key, value string) error
}

Unmarshaler defines an interface that allows a type to declare it supports unmarshaling from environment variable text.

type Values

type Values map[string][]string

Values is an Env- and Multienv-conformant map of keys to strings. Getenv will only return the first value held by the key's slice. If the slice is empty but the key is set, it returns the empty string. GetenvAll will return nil and ErrNoValue only if the key is unset.

func (Values) Add

func (v Values) Add(key, value string)

Add appends the value to the slice of values held by key.

func (Values) Del

func (v Values) Del(key string)

Del deletes the key from the receiver.

func (Values) Getenv

func (v Values) Getenv(key string) (value string, err error)

Getenv returns the first value held by the key. If the key is defined, but the slice is empty, it returns the empty string. If the key is not set, it returns the empty string and ErrNoValue.

func (Values) GetenvAll

func (v Values) GetenvAll(key string) ([]string, error)

GetenvAll returns all values held by the key. If the key is undefined, it returns nil and ErrNoValue.

func (Values) Insert

func (v Values) Insert(key, value string)

Insert inserts a value at the front of a list of values for the given key.

func (Values) Set

func (v Values) Set(key, value string)

Set assigns the given value for the key, erasing any other values held by it.

Jump to

Keyboard shortcuts

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