config

package module
v0.0.0-...-9ad1e31 Latest Latest
Warning

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

Go to latest
Published: Mar 27, 2019 License: MIT Imports: 15 Imported by: 0

README

go-config

A Configuration Package for Go

Summary

go-config provides a convenient way to scan configuration settings from command line flags and environment variables into structs. Its aim is to provide logical organization of configuration parameters with minimal developer overhead.

It also provides for basic validation of configuration values by using struct tags, and parsing of single values.

Quick Start

type Auth struct {
    User     string
    Password string
}

type Options struct {
    Auth    *Auth
    URLs    []*url.URL `scheme:"^(http|https)$"`
    Verbose int        `min:"0" max:"8"`
}

opts := Options{Verbose: 1}
if err := config.Configure(&opts); err != nil {
    fmt.Fprintln(os.Stderr, err)
    os.Exit(1)
}
if opts.Auth != nil {
    fmt.Printf("Auth: %+v\n", *opts.Auth)
}
fmt.Printf("URLs: %s\nVerbose: %d\n", opts.URLs, opts.Verbose)

Running the program with -h demonstrates the generated command-line flags and environment variable settings:

Command Line Flags:
  -auth-password string
  -auth-user string
  -urls url
  -verbose int
         (default 1)

Environment Variables:
  AUTH_PASSWORD=string
  AUTH_USER=string
  URLS=url
  VERBOSE=int
         (default 1)

Help requested

Running the program with supported flags demonstrates how values are set:

prog -urls http://www.google.com/ -urls http://www.yahoo.com/ -auth-user user1
Auth: {User:user1 Password:}
URLs: [http://www.google.com/ http://www.yahoo.com/]
Verbose: 1

To set a default value, simply set the value in the struct before calling Configure. Struct tags can be used to specify permitted values. See the Validation section for details.

Detailed Usage

Supported Types

The following types are supported:

  • int
  • int8
  • int16
  • int32
  • int64
  • uint
  • uint8
  • uint16
  • uint32
  • uint64
  • float32
  • float64
  • string
  • bool
  • net.IP
  • net.IPNet
  • url.URL
  • time.Duration
  • time.Time
Pointers and Slices

Types that are pointer and/or slice types of a supported type are also supported. For example, []int, *int, *[]*int, or any other combination of slice and pointer indirection can be set.

Numeric types

int, int8, int16, int32, and int64, uint, uint8, uint16, uint32 and uint64 types are parsed as base 10, unless they have a leading zero or 0x, in which case they are parsed as, respectively, base 8 or base 16 values. Values which would overflow the type or discard a sign are considered invalid. For example, assigning a value larger than 255 to int8, or assigning a negative value to a uint.

float32 and float64 types are parsed using strconv.ParseFloat using the correct size (bits).

Booleans

bool values are parsed using strconv.ParseBool. 1, t, T, TRUE, true, and True are parsed as true. 0, f, F, FALSE, false, and False evaluate to false. Any other value is an error.

URLs

url.URL values are parsed using url.Parse.

IP Addresses

net.IP values are are parsed with net.ParseIP and accept, e.g., 192.168.1.1 or 2600:1700:5fa0:ef90:85e:79dc:5ea7:c711. net.IPNet values are parsed with net.ParseCIDR as address/bits, such as 169.254.0.0/16 or 2001:cdba:9abc:5678::/64. A value provided as a network address need not necessarily specify the 0 network address: 169.254.1.1/16 will be understood as 169.254.0.0/16.

Durations

time.Duration values are parsed using time.ParseDuration, e.g., 0.75s or 1h37m27s.

Times

A best effort is made to parse a time based on a static list of layouts:

  • "2006-01-02T15:04:05Z07:00"
  • "2006-01-02 15:04:05Z07:00"
  • "2006-01-02T15:04:05"
  • "2006-01-02 15:04:05"
  • "2006-01-02T15:04Z07:00"
  • "2006-01-02 15:04Z07:00"
  • "2006-01-02T15:04"
  • "2006-01-02 15:04"
  • "2006-01-02T15"
  • "2006-01-02 15"
  • "2006-01-02"
  • "2006-01"

If the time can not be parsed using any of the given layouts, it is an error.

Flag and Environment Variable Names

go-config attempts to generate human-friendly names by parsing the names of struct fields in a hierarchical way. For example, given

type UserAccount struct {
    Network struct {
        IPv6FriendlyName string
    }
}

go-config will generate the command line flag -user-account-network-ip-v6-friendly-name. See the section Overriding Names for details on how to change this behavior.

Validation

Note than for types in the below section, the validations also apply to other types that are pointer and/or slice types of the base type. For example, if a validation applies to int, it also applies to []int, *int, *[]*int, or any other combination of slice and pointer indirection.

Greater or Less Than Comparisons

Number types int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64, float32, float64 as well as time.Duration and time.Time support a number of struct tags for validation.

ge and min have the same meaning, and indicate a value must be greater than or equal to the argument. le and max similarly indicate a value must be less than or equal to a given value. Tags lt and gt indicate a strict less than or greater than comparison (not equal to).

All arguments to the above tags should be given in a valid string for the type. For example, 1s for a duration, 2001-01-01 11:59:59Z for a time, etc. The special value now may be used for time.Time values.

The above tags can be combined to require values within a range.

Examples:

type Example struct {
    Ratio   float64       `min:"0" lt:"1"`
    Timeout time.Duration `min:"0s"`
}
Regular Expressions

Fields of string type support the regexp tag. Only values that match the given regular expression will be accepted.

Similarly, url.URL fields support scheme, host and path struct tags to require that the URL scheme, host or path, respectively, match the given regular expression.

Go's regular expression matching will match any part of a string. To match the entire string, anchor the expression with ^ and $.

Struct tag values use quoted strings. This means that double quotes and backslahes must be backslash-escaped.

Examples:

type Example struct {
    BaseURL  *url.URL `scheme:"^(http|https)$"`
    Username string   `regexp:"^\\pL"` // usernames must start with a letter.
}
IP Addresses

net.IP and net.IPNet types support tags to validate a particular address.

is

The is tag can be used with values global unicast, interface local multicast, link local multicast, link local unicast, loopback, multicast, and unspecified. Each value matches the corresponding range of IP addresses. A negative match can be specified by prefixing with a !, and multiple values can be separated by commas. Validation succeeds if any non-negated term matches the value being set. Validation fails, however, if any negated term is matched.

Example:

type Example struct {
    IP net.IP `is:"multicast,!interface local multicast"`
}

The above field will accept a multicast address, but not if it is an interface local multicast.

net

The net tag can be used to specify restrictions for which networks an IP address can be part of. Network addresses are specified in address/bits notation, e.g., 169.254.0.0/16 or 2001:cdba:9abc:5678::/64. As with the net tag, a ! negates the match term, and multiple terms can be seprated by commas. Validation succeeds if any non-negated term matches, and fails if any negated term is matched.

Example:

type Example struct {
    IP net.IP `net:"192.168.0.0/16,!192.168.254.0/24"`
}
version

The version tag accepts values 4 or 6 to indicate that an address must be an IPv4 or IPv6 address.

Controlling Where Values are Loaded From

By default, values are parsed first from environment variables and then from command line flags. If a value is set by both an environment variable and a command line flag, the command line flag will overwrite the value set from the environment variable.

The from struct tag can be used to control where values are loaded from. The default is from:"flag,env". To prevent a field from being set from an environment variable, one could use from:"flag" in its struct tag.

The default loaders can also be overridden, either to change the order or to exclude defaults. For example, to cause environment variables to overwrite command line flags:

loaders := config.Loaders{new(config.FlagLoader), new(config.EnvLoader)}
config.DefaultConfig.SetLoaders(loaders)
Scanning Multiple Structs or Setting Individual Values

The Configuration function is convenient for scanning values from a single struct and then loading them. However, functions are also provided for loading values into more than one struct, or for setting individual variables. The functions Scan, Var and Load are available.

To scan more than one struct, simply call Scan for each struct. Call Var to add an individual variable. When finished, call Load to parse and set values from the command line and/or environment.

Note, however, that name collisions will cause a panic.

Using Non-global Configurations

For some cases, it may be desirable to avoid using the package global DefaultConfig. In order to support standalone or multiple configurations, simply use the config.Config type. The zero value is ready to use.

Overriding Names

The config struct tag can be used to skip fields or change the names that are generated for them. config:"-" will cause a field to be skipped. config:"OtherName" will cause go-config to use OtherName as the name for this field, which will be used in generating command line flag and environment variable names.

Using prefix:"-" will cause a child struct to use the same prefix as the parent struct. For example:

type Auth struct {
    User     string
    Password string
}

type Options struct {
    Auth    *Auth      `prefix:"-"`
    URLs    []*url.URL `scheme:"^(http|https)$"`
    Verbose int        `min:"0" max:"8"`
}

In this case, the command line flag for the User field will be simply -user, instead of -auth-user.

For even more control of naming, a struct can be passed to the Var function. See the documentation of that function for details.

Dependencies

Supports Go >= 1.10. go-config does not currently rely on any external packages.

License

go-config uses the MIT License.

Contributing

Pull requests and bug requests are welcome.

Please note that this project is released with a Contributor Code of Conduct. By participating in this project you agree to abide by its terms.

Documentation

Overview

Package config provides types and functions for managing application configuration. A set of command-line flags or environment variables to parse can be inferred from a struct's type. The values are then subject to validation and assigned to the struct fields.

Quick Start

The easiest way to use the package is to define a struct type and pass it to Configure. Struct tags can be used to control how fields are scanned or validated.

type Auth struct {
	User     string
	Password string
}

type Options struct {
	Auth    *Auth
	URLs    []*url.URL `scheme:"^(http|https)$"`
	Verbose int        `min:"0" max:"8"`
}

opts := Options{Verbose: 1}
if err := config.Configure(&opts); err != nil {
	fmt.Fprintln(os.Stderr, err)
	os.Exit(1)
}
if opts.Auth != nil {
	fmt.Printf("Auth: %+v\n", *opts.Auth)
}
fmt.Printf("URLs: %s\nVerbose: %d\n", opts.URLs, opts.Verbose)

If the program was given the -h flag, the following help would be written to stderr:

Command Line Flags:
  -auth-password string
  -auth-user string
  -urls url
  -verbose int
    	 (default 1)

Environment Variables:
  AUTH_PASSWORD=string
  AUTH_USER=string
  URLS=url
  VERBOSE=int
    	 (default 1)

Help requested

Running the program with no command line flags and none of the environment variables set would output:

URLs: []
Verbose: 1

Note that the entire Auth field is left as nil; nil pointers are only set if a value is configured for the field. Running the program again with flags

-urls http://www.google.com/ -urls http://www.yahoo.com/ -auth-user user1

provides the following:

Auth: {User:user1 Password:}
URLs: [http://www.google.com/ http://www.yahoo.com/]
Verbose: 1

Finally, some of the values have validation tags for their struct fields. If the validations are not met, an error is given:

invalid value "10" for flag -verbose: Validating 10 failed: 10 is not less than or equal to 8

Supported Types

The following types are supported by the package:

  • bool
  • float32, float64
  • int, int8, int16, int32, int64
  • net.IP, net.IPNet
  • string
  • time.Duration, time.Time
  • uint, uint8, uint16, uint32, uint64
  • url.URL

In addition, any types derived from pointers and slices to those types are also supported.

bool, float, int and uint values are parsed by strconv.ParseBool, strconv.ParseFloat, strconv.ParseInt and strconv.ParseUint. Trying to set a value that would overflow the type results in an error.

net.IP values are parsed using net.ParseIP. net.IPNet values are parsed using net.ParseCIDR. url.URL values are parsed using url.Parse. time.Duration values are parsed using time.ParseDuration.

time.Time values will be parsed using the following layouts until one is succesful or all have been tried:

  • "2006-01-02T15:04:05Z07:00"
  • "2006-01-02 15:04:05Z07:00"
  • "2006-01-02T15:04:05"
  • "2006-01-02 15:04:05"
  • "2006-01-02T15:04Z07:00"
  • "2006-01-02 15:04Z07:00"
  • "2006-01-02T15:04"
  • "2006-01-02 15:04"
  • "2006-01-02T15"
  • "2006-01-02 15"
  • "2006-01-02"
  • "2006-01"

Additional types can be supported either by implementing the Setter API on that type, or by implementing and registering a SetterCreator for that type. The latter option will enable the package to automatically wrap derived pointer and struct types.

Validation

Struct tags can be used to impose validation on parsed values.

`min:"x"` or `ge:"x"` sets a minimum value for int, float, uint, time.Duration and time.Time values. The value must be appropriate for the type, and is parsed the same as values of that type. For example

Timeout time.Duration `min:"30s"`

indicates that the Timeout value must be greater than or equal to 30 seconds.

`max:"x"“ or `le:"x"` indicates a maximum value for the above types. Similarly, `gt:"x"` or `lt:"x"` will require values greater than or less than the values specified.

Values can be combined to set ranges. Note, however, that it's possible to set impossible validations this way, e.g., `gt:"10" lt:"5"`.

`regexp:"x"` sets a regular expression for validating string values. A match can occur anywhere in the string. To match the whole string, anchor the expression with "^$". Also note that the value in the struct tag will be subject to string unquoting; backslashes and double-quotes must be escaped with a backslash.

`scheme:"x"`, `host:"x"` or `path:"x"` tags can be applied to url.URL values. They specify regular expressions that are used to validate the corresponding parts of the URL.

The `is:"x"` tag can be used to specify required or disallowed classes of IP addresses for the net.IP or net.IPNet types. Valid values are:

  • global unicast
  • interface local multicast
  • link local multicast
  • link local unicast
  • loopback
  • multicast
  • unspecified

The class name can be prefixed with an exclamation point to indicate that the class is disallowed. Multiple values can be combined by separating with commas. For example, `is:"!loopback,!link local unicast"` would allow addresses that are neither loopback nor link local unicast. If any disallowed class is matched, the validation will fail. The allowed classes are matched in an "or" fashion, however, and any one match will cause the validation to succeed.

The `net:"x"` tag can be used with net.IP or net.IPNet values to specify required or disallowed networks. Networks are specified in address/bits form, e.g., 169.254.0.0/16 or 2001:cdba:9abc:5678::/64. Disallowed networks are specified by prefixing with an exclamation point. Multiple values can be combined by separating with commas. The semantics are the same as for the 'is' tag: A match for any disallowed value fails validation; a match for any single allowed value causes validation to succeed.

The `version:"4"` or `version:"6"` tags can be used with net.IP and net.IPNet values to specify that the value must be an IPv4 or IPv6 address.

Other Struct Tags

`config:"X"` can be used to override the name of a struct field, instead of using the reflected name. The name will still be subjected to parsing with SplitName. Setting `config:"-"` will cause the struct field to be skipped, i.e., it will not be scanned or configured.

`prefix:"X"` can be used to override how nested structs are handled. If no prefix is set, the child struct uses the name of its field in the parent struct. If a name is given, that name will be used to group settings in the child struct. (`config:"X"` can be used for the same purpose.) If `prefix:"-"` is given, the child struct will use the same prefix as its parent, and names parsed from the child's fields will be added to the parent's level as if the fields had been parsed from the parent. For example:

type Options struct {
	Timeout time.Duration
	Auth struct {
		User string
		Pass string
	} `prefix:"-"`
}
var opts Options
config.Configure(&opts)

will result in command line flags being generated for -timeout, -user and -pass. Without the prefix tag, the names would have been -auth-user and -auth-pass.

`from:"X"` will cause the value to only be configured by the named loaders. For example

Interactive bool `from:"flag"`

will only let the Interactive value be set from a command line flag.

`append:"false"` or `append:"true"` (the default) can be used with slice types. When true, values are appended to existing values in a slice. When false, setting a new value will cause the slice to be overwritten. (Setting multiple values will still result in second and subsequent values being appended after the first new value).

`sep:"X" can be used with slice types. It indicates a string on which the value should be split on in order to populate a slice.

Index

Constants

This section is empty.

Variables

View Source
var DefaultConfig = new(Config)

DefaultConfig is a default, global Config.

Is is used by the package-level Scan, Var and Configure functions, or can be used directly by an application that doesn't require multiple configurations.

View Source
var DefaultSetterRegistry = SetterRegistry{}

DefaultSetterRegistry provides a default registry.

It supports SetterCreator instances for the built-in types, and is used by Config if no other registry is specified.

View Source
var ErrHelp = errors.New("Help requested")

ErrHelp is returned when help is requested via the -h command line flag.

Functions

func Configure

func Configure(strct interface{}) error

Configure calls DefaultConfig.Configure

func FriendlyTypeName

func FriendlyTypeName(x interface{}) string

FriendlyTypeName returns a descriptive name for a value's type.

It is primarily useful for generating placeholder names for paremeters in help output.

If types are element types, such as an array or pointer, they are dereferenced until a non-element type is found. If that type has a name, it is lowercased and returned. If the type is unnamed, the string "value" is returned.

func Load

func Load() error

Load calls DefaultConfig.Load

func PathCmp

func PathCmp(a, b *Path) int

PathCmp compares two Paths to determine ordering.

It returns -1 if a should order before b; 1 if a should order after b; or 0 if a and b are equivalent.

func Scan

func Scan(strct interface{}) error

Scan calls DefaultConfig.Scan.

func SplitName

func SplitName(name string) []string

SplitName splits a name into logical words.

It attempts to parse names into words based on Go conventions and how humans perceive them:

  • A capital letter following a lowercase one always starts a new word.
  • A series of capital letters are generally considered part of the same word. The last capital letter in the series will start a new word, except:
  • When it is followed by a lowercase letter and a digit, e.g., "v2".
  • When it is followed by a single lowercase letter and then the end of the string.

Examples:

"HTMLEntityID" -> {"HTML", "Entity", "ID"}
"UUID"         -> {"UUID"}
"UUIDv2"       -> {"UUID", "v2"}
"UUIDs"        -> {"UUIDs"}
"IPv6Network"  -> {"IP", "v6", "Network"}

The return values are useful for creating parameter names that are readily human-readable, such as for command line flags or environment variables.

func Var

func Var(value interface{}, tag reflect.StructTag, name ...string) error

Var calls DefaultConfig.Var

Types

type Config

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

Config represents a configuration for an application.

It can be used in lieu of the package-level functions or DefaultConfig if an application needs to manage multiple, separate configurations.

The zero value is ready to use.

func (*Config) AddLoader

func (c *Config) AddLoader(loader Loader)

AddLoader appends a loader to the set of loaders used by c.

func (*Config) Args

func (c *Config) Args() []string

Args returns the command-line arguments left after parsing.

Returns nil if Load has not been called, or if no flag loader was included in the config.

func (*Config) Configure

func (c *Config) Configure(strct interface{}) error

Configure scans the strct argument to generate a list of parameters and then loads them.

The strct parameter must be a non-nil pointer to a struct type. Any other value panics.

It is equivalent to calling c.Scan followed by c.Load. The return value, if not nil, will be of type Errors, and will contain the concatenated errors from both Scan and Load.

func (*Config) GetLoaders

func (c *Config) GetLoaders() Loaders

GetLoaders returns the current Loaders used by the Config.

It returns the last loaders set by SetLoaders, or a set of default loaders if none was set.

func (*Config) GetSetterRegistry

func (c *Config) GetSetterRegistry() SetterRegistry

GetSetterRegistry returns the SetterRegistry used by the Config.

It returns the last value passed to c.SetSetterRegistry, or DefaultSetterRegistry if none is set.

func (*Config) Load

func (c *Config) Load() error

Load calls loaders to parse and validate configuration.

This method is implicitly called by c.Configure. It is only necessary to call it if not calling c.Configure. This method will only do something useful if c.Scan or c.Var has been called to populate a list of values to set.

Any validation or load errors will result in a non-nil return status.

If one of the loaders is a *FlagLoader and the -h flag has not been overridden, calling Load with "-h" in the application's command line arguments will cause a list of settings and their descriptions to be printed to stderr.

func (*Config) Scan

func (c *Config) Scan(strct interface{}) error

Scan uses reflection to populate configuration settings from a struct.

The strct parameter must be a non-nil pointer to a struct type. Scan will panic if any other value is passed.

This method is implicitly called by calling c.Configure. This method can be used if multiple struct types are to be scanned; if additional settings are to be added with c.Var before calling c.Load; or if unsupported type errors are to be ignored. Note that any names scanned from the struct must be unique. If any name is duplicated, Scan panics. This can only happen when calling Scan multiple times or mixing calls to Var and Scan.

If the return value is non-nil, it will be of type Errors. Each element will in turn be of type *UnknownTypeError, one for each scanned field for which a Setter could not be created.

Only exported fields can be set. Unexported fields will be ignored. See the package-level documentation for information about which field types are supported by default and the effects of various struct tags.

func (*Config) SetLoaders

func (c *Config) SetLoaders(loaders Loaders)

SetLoaders sets loaders to be used by the Config.

It makes a copy of the parameter, so modifying the parameter after the function returns is safe. Similarly, subsequently calling c.AddLoader will not modify the parameter passed to this method.

Ordering is important, as subsequent loaders can overwrite configuration values from earlier ones.

Passing a nil value will cause Config to use a default set of loaders.

func (*Config) SetSetterRegistry

func (c *Config) SetSetterRegistry(reg SetterRegistry)

SetSetterRegistry sets a new SetterRegistry to be used by the Config.

This can be useful for providing custom SetterCreator implementations for new or existing types without changing the global DefaultSetterRegistry.

Passing nil will cause the Config to use the DefaultSetterRegistry.

func (*Config) Usage

func (c *Config) Usage(w io.Writer)

Usage dumps usage information to an io.Writer.

Usage writes a list of setting names and their descriptions to w. If w is nil, the list is dumped to os.Stderr.

func (*Config) Var

func (c *Config) Var(value interface{}, tag reflect.StructTag, name ...string) error

Var adds a single value to be set by Config.

The value parameter must be a non-nil pointer. Passing any other value will panic. The tag parameter can be used to set most tags as documented in the package-level documentation, with the exception of 'config' and 'prefix' tags.

If value points to a struct, the function is equivalent to calling Scan with value nested at the level indicated by name. For example:

opts := struct {
	Level1: struct {
		Level2: struct {
			X int
		}
	}
}
Scan(&opts)

is equivalent to

Var(&opts.Level1.Level2, "", "Level1", "Level2")

The remaining parameters are variadic, but at least one must be provided. If only one value is provided, it is a non-prefixed name. If multiple values are provided, leading values are prefixes. For example,

DefaultConfig.Var(&version, "", "version")

will parse command-line flag -version and environment variable VERSION, while

DefaultConfig.Var(&version, "", "api", "version")

parses command-line flag -api-version and environment variable API_VERSION.

Any name, with or without prefix, must be unique to the configuration. If it duplicates a name already set with Var or parsed by Scan, Var panics.

type ConversionError

type ConversionError struct {
	Value  interface{}
	ToType reflect.Type
	Path   *Path
}

ConversionError is returned for values which can not be convered by a Setter.

func (*ConversionError) Error

func (ce *ConversionError) Error() string

type EnvLoader

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

EnvLoader implements a Loader type to parse settings from environment variables.

Environment variable names are generated by expanding the path for each setting to a list of optional prefixes and ending with the setting's name:

opts := struct {
	HTMLParser struct {
		ElementIDs []string
		Name       string
	}
}{}

results in paths

["HTMLParser", "ElementIDs"]
["HTMLParser", "Name"]

Each element is then replaced with the result of passing it to SplitName:

["HTML", "Parser", "Element", "IDs"]
["HTML", "Parser", "Name"]

Any dashes or underscores in each word are removed, the words capitalized, and finally joined with underscores to produce the final names:

HTML_PARSER_ELEMENT_IDS
HTML_PARSER_NAME

The zero value is ready to use.

func (*EnvLoader) Init

func (el *EnvLoader) Init(settings []Setting)

Init initializes the loader with the given settings.

Init must be called before Load.

func (*EnvLoader) Load

func (el *EnvLoader) Load() error

Load attempts to parse the configured settings from environment variables.

The returned error, if non-nil, will be of type Errors. Each element will be of type *ConversionError or *ValidationError.

func (*EnvLoader) Name

func (*EnvLoader) Name() string

Name returns the name of the loader. It is always "env".

func (*EnvLoader) Usage

func (el *EnvLoader) Usage() string

Usage returns a string with a list of environment variables names and their descriptions.

type Errors

type Errors []error

Errors represents a collection of one or more errors.

func (*Errors) Append

func (e *Errors) Append(err error)

Append adds an error to the list of errors.

If err is of type *Errors, each element in it will be appended individually instead of nesting the *Errors values.

func (*Errors) AsError

func (e *Errors) AsError() error

AsError returns e as an error type.

If *e is empty, returns error(nil). This is a convenience to avoid a common pitfall:

func foo() error {
	var *errs Errors
	return &errs
}
if err != nil {
	fmt.Fprintln(os.Stderr, err)
	os.Exit(1)
}

Values of an interface type only compare equal to nil if they have neither a type nor a value. In this case, the return value from foo() will have a nil value, but the type will be (*Errors), so err != nil is true.

func (*Errors) Error

func (e *Errors) Error() string

Error returns a string by joining the Error() value of each element with newlines.

type FlagLoader

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

FlagLoader implements a Loader type to parse settings from command line flags.

Command line flag names are generated by expanding the path for each setting to a list of optional prefixes and ending with the setting's name:

opts := struct {
	HTMLParser struct {
		ElementIDs []string
		Name       string
	}
}{}

results in paths

["HTMLParser", "ElementIDs"]
["HTMLParser", "Name"]

Each element is then replaced with the result of passing it to SplitName:

["HTML", "Parser", "Element", "IDs"]
["HTML", "Parser", "Name"]

Any dashes in each word are removed, the words lowercased, and finally joined with dashes to produce the final names:

-html-parser-element-ids
-html-parser-name

The zero value is ready to use.

func (*FlagLoader) Args

func (fl *FlagLoader) Args() []string

Args returns any command-line arguments that are left after parsing arguments.

It returns nil if Load() has not been called.

func (*FlagLoader) Init

func (fl *FlagLoader) Init(settings []Setting)

Init initializes the loader with the given settings.

Init must be called before Load.

func (*FlagLoader) Load

func (fl *FlagLoader) Load() error

Load attempts to parse the configured settings from command line flags.

The returned error, if non-nil, will be either ErrHelp or an error value returned by (*flag.FlagSet).Parse.

func (*FlagLoader) Name

func (*FlagLoader) Name() string

Name returns the name of the loader. It is always "flag".

func (*FlagLoader) Parse

func (fl *FlagLoader) Parse(args []string) error

Parse loads arguments from the provided slice.

It is similar to fl.Load except that arguments are provided instead of being loaded from os.Args[1:]. It is useful primarily for testing.

The returned error, if non-nil, will be either ErrHelp or an error value returned by (*flag.FlagSet).Parse.

func (*FlagLoader) SetUsageFn

func (fl *FlagLoader) SetUsageFn(fn func())

SetUsageFn sets a function to be executed to provide usage information.

If the -h flag is not overridden and is encountered on the command line when fl.Load is called, the function provided will be called.

This method is called by (*Config).Load to provide detailed usage information for all loaders.

func (*FlagLoader) Usage

func (fl *FlagLoader) Usage() string

Usage returns a string with a list of command line flags and their descriptions.

type Loader

type Loader interface {
	// Init is used to initialize a loader with a list of settings. Config
	// will always call it before Load. Implementations should support calling
	// it more than once.
	Init([]Setting)
	// Load will be called to parse and set variables. For each Setting passed
	// to Init, the implementation should look for an appropriate setting, and,
	// if found, call one of the 'Set*' methods on Setting.Setter.
	Load() error
	// Name should return a name for the loader. The name need not be unique.
	// However, the name will be used for matching against the `from:""` struct
	// tag.
	Name() string
	// Usage should return a string providing context-specific help for the
	// given loader. Config will always call Init before calling Usage, so
	// the implementation may use the Setting variables passed to Init to
	// provide setting-specific help.
	Usage() string
}

Loader is an interface for parsing and configuring settings using Config.

type Loaders

type Loaders []Loader

Loaders provides a slice type for managing multiple loaders.

func GetDefaultLoaders

func GetDefaultLoaders() Loaders

GetDefaultLoaders returns an ordered list of default loaders.

It currently returns {*EnvLoader, *FlagLoader}. This implies that command line flags can override environment variables.

The returned values are always new values without other references, so can be modified without affecting existing references.

func (*Loaders) Add

func (l *Loaders) Add(loader Loader)

Add appends a loader to the list of loaders.

func (Loaders) Copy

func (l Loaders) Copy() Loaders

Copy makes a copy of l.

This is primarily useful in order to modify the list of loaders based on an existing template without modifying the original. Note that Loader implementations may be pointer types, so while the slice is copied, individual elements may point to shared data.

type NodePath

type NodePath struct {
	Path
	// contains filtered or unexported fields
}

NodePath represents an intermediate node in a configuration path.

It is associated with one parent NodePath, or none if it is a root. It is also associated with 0 or more child NodePath or Path elements.

func NewRootPath

func NewRootPath(name string) *NodePath

NewRootPath returns a *NodePath that represents the root of a path hierarchy.

If name is the empty string, the root is unnamed. This is equivalent to the zero value, which is also ready to use.

func (*NodePath) AddNodePath

func (np *NodePath) AddNodePath(c *NodePath) *NodePath

AddNodePath registers a child NodePath to np.

This makes the child locatable using np.FindNodePath.

func (*NodePath) AddPath

func (np *NodePath) AddPath(c *Path) *Path

AddPath registers a child Path to np.

This makes the child locatable using np.FindPath.

func (*NodePath) FindNodePath

func (np *NodePath) FindNodePath(elements ...string) *NodePath

FindNodePath finds the given path.

The name of np is not considered, so the first parameter will be a child of np. For example, in the hierarchy

NodePath()->NodePath(usr)->NodePath(bin)->Path(python)

Calling FindPath("usr", "bin") on the root node will return NodePath(bin).

If the path is not found within np, or is not an intermediate node (*NodePath), FindNodePath returns nil.

func (*NodePath) FindPath

func (np *NodePath) FindPath(elements ...string) *Path

FindPath finds the given path.

The name of np is not considered, so the first parameter will be a child of np. For example, in the hierarchy

NodePath()->NodePath(usr)->NodePath(bin)->Path(python)

Calling FindPath("usr", "bin", "python") on the root node will return Path(python).

If the path is not found within np, or is not a leaf node (*Path), FindPath returns nil.

func (*NodePath) NewNodePath

func (np *NodePath) NewNodePath(name string) *NodePath

NewNodePath returns a new NodePath but without adding it as a child of np.

The returned *NodePath will have np as its parent, but will not be locatable using np.FindNodePath.

func (*NodePath) NewPath

func (np *NodePath) NewPath(name string) *Path

NewPath returns a new Path but without adding it as a child of np.

The returned *Path will have np as its parent, but will not be locatable using np.FindPath.

type Path

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

Path provides a leaf node in a hierarchy of configuration parameters.

When scanning nested structs, for example, there will be a hierarchy such as

TypeNameA +> TypeNameB -> TypeNameC
          |
          +-> TypeNameD -> TypeNameE

A Path can refer to the edge nodes, TypeNameC or TypeNameE in this case. Each will have an association with one parent node.

func (*Path) Elements

func (p *Path) Elements() []string

Elements returns a list of names from the root node to p.

If the root *NodePath is unnamed, it will not be included in the list. Otherwise, the first item will be the name of the root node, and the last will be the name of p. E.g., for

NodePath()->NodePath(usr)->NodePath(bin)->Path(python)

Elements returns

[]string{"usr", "bin", "python"}

func (*Path) Name

func (p *Path) Name() string

Name returns the name of node p.

func (*Path) String

func (p *Path) String() string

String returns a string for p by joining the result of p.Elements() with "->".

type Setter

type Setter interface {
	// String should return a descriptive string for the current value
	// associated with the Setter. Note that this method may be called on a
	// zero value of the implementation type and should not panic in that case.
	String() string
	// Set is called to parse, validate and set the associated value from a
	// string. The implementation must return an error (such as
	// *ConversionError) if the value cannot be parsed from the given string, or
	// if string is not a valid type to represent the parameter.
	Set(string) error
	// SetInt is called to interpret, validate and set the associated value from
	// an int64. The implementation must return an error (such as
	// *ConversionError) if the value cannot be interpreted from the given
	// int64, or if int64 is not a valid type to represent the parameter.
	SetInt(int64) error
	// SetUint is called to interpret, validate and set the associated value
	// from a uint64. The implementation must return an error (such as
	// *ConversionError) if the value cannot be interpreted from the given
	// uint64, or if uint64 is not a valid type to represent the parameter.
	SetUint(uint64) error
	// SetFloat is called to interpret, validate and set the associated value
	// from a float64. The implementation must return an error (such as
	// *ConversionError) if the value cannot be interpreted from the given
	// float64, or if float64 is not a valid type to represent the parameter.
	SetFloat(float64) error
	// SetBool is called to interpret, validate and set the associated value
	// from a bool. The implementation must return an error (such as
	// *ConversionError) if the value cannot be interpreted from the given
	// bool, or if bool is not a valid type to represent the parameter.
	SetBool(bool) error
	// Get is called to get the current value set on the Setter. The type of
	// the returned value should be the same as the value being set, even if
	// the value is currently unset or zero.
	Get() interface{}
}

Setter is an interface which is used to parse, validate and set values of a specific type.

Note that SetInt, SetUint, SetFloat and SetBool are not used for the default loaders, but may be used by custom Loader implementations or in future features.

type SetterCreator

type SetterCreator interface {
	// Type must return the reflect.Type that the Setter returned from Setter
	// will support.
	Type() reflect.Type
	// Setter must return an implementation of Setter to set a value of the
	// type returned by Type(). The value passed to Setter will always be of
	// the type returned by Type(), and the Setter must be able to accept
	// and set that type.
	Setter(reflect.Value, reflect.StructTag) Setter
}

SetterCreator is an interface type for creating a Setter for a given value.

type SetterRegistry

type SetterRegistry map[reflect.Type]SetterCreator

SetterRegistry is a map of reflect.Type to SetterCreator.

It provides methods that can be used to find or create a Setter for a given value.

func (*SetterRegistry) Add

func (sr *SetterRegistry) Add(sc SetterCreator)

Add adds a SetterCreator to the registry.

If there is already a SetterCreator registered for the same type returned by sc.Type(), it will be replaced.

func (*SetterRegistry) Copy

func (sr *SetterRegistry) Copy() *SetterRegistry

Copy creates a copy of the registry.

It is useful for modifying the existing registry without affecting other references to it.

func (*SetterRegistry) GetSetter

func (sr *SetterRegistry) GetSetter(val reflect.Value, tag reflect.StructTag) Setter

GetSetter returns a Setter that wraps/sets the given val.

If the value and type represented by val implements the Setter type, val.Interface() is simply returned.

If val.Type() has an existing entry in the registry, the registered SetterCreator will be used to create the Setter. Otherwise, if val.Type() is a slice or pointer type, it will be dereferenced until either a type is found in the registry, or a non-element type is found. If a Setter is returned for a pointer or slice type, it may be created using wrappers to handle the indirections, so may not be a value returned by one of the registered SetterCreators.

If no SetterCreator can be found or created, GetSetter returns nil.

func (*SetterRegistry) GetSetterCreator

func (sr *SetterRegistry) GetSetterCreator(t reflect.Type) SetterCreator

GetSetterCreator returns the registered SetterCreator for the given type, or nil if none is registered.

type Setting

type Setting struct {
	// Path is the given path within the configuration hierarchy. This should
	// be used by Loader implementations to create or identify the parameter.
	// it will never be nil when passed to Loader.Init().
	Path *Path
	// Tag is the struct tag parsed by Config.Scan or passed to Config.Var.
	Tag reflect.StructTag
	// Setter is an implementation of Setter. When passed to Loader.Init(), it
	// will never be nil.
	Setter
}

Setting represents one configuration value.

It represents a value parsed from either a struct field or passed to Config.Var.

type UnknownTypeError

type UnknownTypeError struct {
	Type reflect.Type
	Path *Path
}

UnknownTypeError represents an error when no Setter can be created for a type.

func (*UnknownTypeError) Error

func (ute *UnknownTypeError) Error() string

type ValidationError

type ValidationError struct {
	Value   interface{}
	Message string
	Path    *Path
}

ValidationError is returned by a Setter when values fail validation.

func (*ValidationError) Error

func (ve *ValidationError) Error() string

Jump to

Keyboard shortcuts

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