mcfg

package
v0.0.0-...-c20f884 Latest Latest
Warning

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

Go to latest
Published: Jul 30, 2019 License: MIT Imports: 13 Imported by: 1

Documentation

Overview

Package mcfg implements the creation of different types of configuration parameters and various methods of filling those parameters from external configuration sources (e.g. the command line and environment variables).

Parameters are registered onto a Component, and that same Component (or one of its ancestors) is used later to collect and fill those parameters.

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func AddParam

func AddParam(cmp *mcmp.Component, param Param, opts ...ParamOption)

AddParam adds the given Param to the given Component. It will panic if a Param with the same Name already exists in the Component.

func Bool

func Bool(cmp *mcmp.Component, name string, opts ...ParamOption) *bool

Bool returns a *bool which will be populated once Populate is run on the Component, and which defaults to false if unconfigured.

The default behavior of all Sources is that a boolean parameter will be set to true unless the value is "", 0, or false. In the case of the CLI Source the value will also be true when the parameter is used with no value at all, as would be expected.

func CLISubCommand

func CLISubCommand(cmp *mcmp.Component, name, descr string, callback func(*mcmp.Component)) *bool

CLISubCommand establishes a sub-command which can be activated on the command-line. When a sub-command is given on the command-line, the bool returned for that sub-command will be set to true.

Additionally, the Component which was passed into Parse (i.e. the one passed into Populate) will be passed into the given callback, and can be modified for subsequent parsing. This allows for setting sub-command specific Params, sub-command specific runtime behavior (via mrun.WithStartHook), support for sub-sub-commands, and more. The callback may be nil.

If any sub-commands have been defined on a Component which is passed into Parse, it is assumed that a sub-command is required on the command-line.

When parsing the command-line options, it is assumed that sub-commands will be found before any other options.

This function panics if not called on a root Component (i.e. a Component which has no parents).

Example
var (
	cmp           *mcmp.Component
	foo, bar, baz *int
	aFlag, bFlag  *bool
)

// resetExample re-initializes all variables used in this example. We'll
// call it multiple times to show different behaviors depending on what
// arguments are passed in.
resetExample := func() {
	// Create a new Component with a parameter "foo", which can be used across
	// all sub-commands.
	cmp = new(mcmp.Component)
	foo = Int(cmp, "foo")

	// Create a sub-command "a", which has a parameter "bar" specific to it.
	aFlag = CLISubCommand(cmp, "a", "Description of a.",
		func(cmp *mcmp.Component) {
			bar = Int(cmp, "bar")
		})

	// Create a sub-command "b", which has a parameter "baz" specific to it.
	bFlag = CLISubCommand(cmp, "b", "Description of b.",
		func(cmp *mcmp.Component) {
			baz = Int(cmp, "baz")
		})
}

// Use Populate with manually generated CLI arguments, calling the "a"
// sub-command.
resetExample()
args := []string{"a", "--foo=1", "--bar=2"}
if err := Populate(cmp, &SourceCLI{Args: args}); err != nil {
	panic(err)
}
fmt.Printf("foo:%d bar:%d aFlag:%v bFlag:%v\n", *foo, *bar, *aFlag, *bFlag)

// reset for another Populate, this time calling the "b" sub-command.
resetExample()
args = []string{"b", "--foo=1", "--baz=3"}
if err := Populate(cmp, &SourceCLI{Args: args}); err != nil {
	panic(err)
}
fmt.Printf("foo:%d baz:%d aFlag:%v bFlag:%v\n", *foo, *baz, *aFlag, *bFlag)
Output:

foo:1 bar:2 aFlag:true bFlag:false
foo:1 baz:3 aFlag:false bFlag:true

func CLITail

func CLITail(cmp *mcmp.Component, descr string) *[]string

CLITail modifies the behavior of SourceCLI's Parse. Normally when SourceCLI encounters an unexpected Arg it will immediately return an error. This function modifies the Component to indicate to Parse that the unexpected Arg, and all subsequent Args (i.e. the tail), should be set to the returned []string value.

The descr (optional) will be appended to the "Usage" line which is printed with the help document when "-h" is passed in.

This function panics if not called on a root Component (i.e. a Component which has no parents).

Example
cmp := new(mcmp.Component)
foo := Int(cmp, "foo", ParamDefault(1), ParamUsage("Description of foo."))
tail := CLITail(cmp, "[arg...]")
bar := String(cmp, "bar", ParamDefault("defaultVal"), ParamUsage("Description of bar."))

err := Populate(cmp, &SourceCLI{
	Args: []string{"--foo=100", "arg1", "arg2", "arg3"},
})

fmt.Printf("err:%v foo:%v bar:%v tail:%#v\n", err, *foo, *bar, *tail)
Output:

err:<nil> foo:100 bar:defaultVal tail:[]string{"arg1", "arg2", "arg3"}

func Duration

func Duration(cmp *mcmp.Component, name string, opts ...ParamOption) *mtime.Duration

Duration returns an *mtime.Duration which will be populated once Populate is run on the Component.

func Float64

func Float64(cmp *mcmp.Component, name string, opts ...ParamOption) *float64

Float64 returns a *float64 which will be populated once Populate is run on the Component

func Int

func Int(cmp *mcmp.Component, name string, opts ...ParamOption) *int

Int returns an *int which will be populated once Populate is run on the Component.

func Int64

func Int64(cmp *mcmp.Component, name string, opts ...ParamOption) *int64

Int64 returns an *int64 which will be populated once Populate is run on the Component.

func JSON

func JSON(cmp *mcmp.Component, name string, into interface{}, opts ...ParamOption)

JSON reads the parameter value as a JSON value and unmarshals it into the given interface{} (which should be a pointer) once Populate is run on the Component.

The receiver (into) is also used to determine the default value. ParamDefault should not be used as one of the opts.

func Populate

func Populate(cmp *mcmp.Component, src Source) error

Populate uses the Source to populate the values of all Params which were added to the given Component, and all of its children. Populate may be called multiple times with the same Component, each time will only affect the values of the Params which were provided by the respective Source.

Source may be nil to indicate that no configuration is provided. Only default values will be used, and if any parameters are required this will error.

Populating Params can affect the Component itself, for example in the case of sub-commands.

func String

func String(cmp *mcmp.Component, name string, opts ...ParamOption) *string

String returns a *string which will be populated once Populate is run on the Component.

func TS

func TS(cmp *mcmp.Component, name string, opts ...ParamOption) *mtime.TS

TS returns an *mtime.TS which will be populated once Populate is run on the Component.

Types

type Param

type Param struct {
	// How the parameter will be identified within a Component.
	Name string

	// A helpful description of how a parameter is expected to be used.
	Usage string

	// If the parameter's value is expected to be read as a go string. This is
	// used for configuration sources like CLI which will automatically add
	// double-quotes around the value if they aren't already there.
	IsString bool

	// If the parameter's value is expected to be a boolean. This is used for
	// configuration sources like CLI which treat boolean parameters (aka flags)
	// differently.
	IsBool bool

	// If true then the parameter _must_ be set by at least one Source.
	Required bool

	// The pointer/interface into which the configuration value will be
	// json.Unmarshal'd. The value being pointed to also determines the default
	// value of the parameter.
	Into interface{}

	// The Component this Param was added to. NOTE that this will be
	// automatically filled in by AddParam when the Param is added to the
	// Component.
	Component *mcmp.Component
}

Param is a configuration parameter which can be populated by Populate. The Param will exist as part of a Component. For example, a Param with name "addr" under a Component with path of []string{"foo","bar"} will be setable on the CLI via "--foo-bar-addr". Other configuration Sources may treat the path/name differently, however.

Param values are always unmarshaled as JSON values into the Into field of the Param, regardless of the actual Source.

func CollectParams

func CollectParams(cmp *mcmp.Component) []Param

CollectParams gathers all Params by recursively retrieving them from the given Component and its children. Returned Params are sorted according to their Path and Name.

type ParamOption

type ParamOption func(*Param)

ParamOption is a modifier which can be passed into most Param-generating functions (e.g. String, Int, etc...)

func ParamDefault

func ParamDefault(value interface{}) ParamOption

ParamDefault returns a ParamOption which ensures the parameter uses the given default value when no Sources set a value for it. If not given then mcfg will use the zero value of the Param's type as the default value.

If ParamRequired is given then this does nothing.

func ParamDefaultOrRequired

func ParamDefaultOrRequired(value interface{}) ParamOption

ParamDefaultOrRequired returns a ParamOption whose behavior depends on the given value. If the given value is the zero value for its type, then this returns ParamRequired(), otherwise this returns ParamDefault(value).

func ParamRequired

func ParamRequired() ParamOption

ParamRequired returns a ParamOption which ensures the parameter is required to be set by some configuration source. The default value of the parameter will be ignored.

func ParamUsage

func ParamUsage(usage string) ParamOption

ParamUsage returns a ParamOption which sets the usage string on the Param. This is used in some Sources, like SourceCLI, when displaying information about available parameters.

type ParamValue

type ParamValue struct {
	Name  string
	Path  []string
	Value json.RawMessage
}

ParamValue describes a value for a parameter which has been parsed by a Source.

type ParamValues

type ParamValues []ParamValue

ParamValues is simply a slice of ParamValue elements, which implements Parse by always returning itself as-is.

func (ParamValues) Parse

func (pvs ParamValues) Parse(*mcmp.Component) ([]ParamValue, error)

Parse implements the method for the Source interface.

type Source

type Source interface {
	Parse(*mcmp.Component) ([]ParamValue, error)
}

Source parses ParamValues out of a particular configuration source, given the Component which the Params were added to (via WithInt, WithString, etc...). CollectParams can be used to retrieve these Params.

It's possible for Parsing to affect the Component itself, for example in the case of sub-commands.

Source should not return ParamValues which were not explicitly set to a value by the configuration source.

The returned []ParamValue may contain duplicates of the same Param's value. in which case the latter value takes precedence. It may also contain ParamValues which do not correspond to any of the passed in Params. These will be ignored in Populate.

type SourceCLI

type SourceCLI struct {
	Args []string // if nil then os.Args[1:] is used

	DisableHelpPage bool
}

SourceCLI is a Source which will parse configuration from the CLI.

Possible CLI options are generated by joining a Param's Path and Name with dashes. For example:

cmp := new(mcmp.Component)
cmpFoo = cmp.Child("foo")
cmpFooBar = foo.Child("bar")
addr := mcfg.String(cmpFooBar, "addr", "", "Some address")
// the CLI option to fill addr will be "--foo-bar-addr"

If the "-h" option is seen then a help page will be printed to stdout and the process will exit. Since all normally-defined parameters must being with double-dash ("--") they won't ever conflict with the help option.

SourceCLI behaves a little differently with boolean parameters. Setting the value of a boolean parameter directly _must_ be done with an equals, or with no value at all. For example: `--boolean-flag`, `--boolean-flag=1` or `--boolean-flag=false`. Using the space-separated format will not work. If a boolean has no equal-separated value it is assumed to be setting the value to `true`.

func (*SourceCLI) Parse

func (cli *SourceCLI) Parse(cmp *mcmp.Component) ([]ParamValue, error)

Parse implements the method for the Source interface.

type SourceEnv

type SourceEnv struct {
	// In the format key=value. Defaults to os.Environ() if nil.
	Env []string

	// If set then all expected Env options must be prefixed with this string,
	// which will be uppercased and have dashes replaced with underscores like
	// all the other parts of the option names.
	Prefix string
}

SourceEnv is a Source which will parse configuration from the process environment.

Possible Env options are generated by joining a Param's Path and Name with underscores and making all characters uppercase, as well as changing all dashes to underscores.

cmp := new(mcmp.Component)
cmpFoo := cmp.Child("foo")
cmpFooBar := cmp.Child("bar")
addr := mcfg.String(cmpFooBar, "srv-addr", "", "Some address")
// the Env option to fill addr will be "FOO_BAR_SRV_ADDR"

func (*SourceEnv) Parse

func (env *SourceEnv) Parse(cmp *mcmp.Component) ([]ParamValue, error)

Parse implements the method for the Source interface.

type Sources

type Sources []Source

Sources combines together multiple Source instances into one. It will call Parse on each element individually. Values from later Sources take precedence over previous ones.

func (Sources) Parse

func (ss Sources) Parse(cmp *mcmp.Component) ([]ParamValue, error)

Parse implements the method for the Source interface.

Jump to

Keyboard shortcuts

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