configstruct

package module
v1.6.0 Latest Latest
Warning

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

Go to latest
Published: Apr 28, 2024 License: MIT Imports: 7 Imported by: 30

README

configstruct

Simple Go module to parse a configuration from environment values and CLI flags or arguments using struct tags. Starting with v1.3.0 there is also support for CLI commands and subcommands

Since v1.5.0 it is possible to define arguments that are also parsed into struct values.

Starting with v1.6.0 parsing a config file is supported (YAML only for now). Use WithYamlConfig(path) option to pass a path to a YAML file that should be parsed. Values passed by flag or env will override values from the config file.

Usage without commands

// define a struct with tags for env name, cli flag and usage
type Config struct {
	Filename string `arg:"1" name:"filename" required:"true"`
	Hostname string `env:"CONFIGSTRUCT_HOSTNAME" cli:"hostname" usage:"hostname value"`
	Port     int    `env:"CONFIGSTRUCT_PORT" cli:"port" usage:"listen port"`
	Debug    bool   `env:"CONFIGSTRUCT_DEBUG" cli:"debug" usage:"debug mode"`
}

// create a variable of the struct type and define defaults if needed
conf := Config{
    Hostname: "localhost",
    Port:     8000,
    Debug:    true,
}

// imagine the programm is called like this:
// ./myprogram -hostname=myhost -port=9000 testfile
// the flag values (hostname, port) and argument (filename) are parsed into the struct
// all pre-set defaults are overwritten if a value is provided otherwise it is left as is
err := configstruct.Parse(&conf)
if err != nil {...}

// if you prefer env with precedence over cli than use option
err := configstruct.Parse(&conf, configstruct.WithPrecedenceEnv())
if err != nil {...}

// you can also use a special option for the default first cli, then env
err := configstruct.Parse(&conf, configstruct.WithPrecedenceCli())
if err != nil {...}

// after parsing you can pass through you config struct and access values
port := conf.Port
host := conf.Hostname
filename := conf.Filename
if conf.Debug {...}

// cli arguments are also possible

Usage with commands

You can also define "commands" that can be used to execute callback functions. The program with global flags and a command count should be called like this:

mycmd -hostname=localhost count -number=2

This is the code to model this behaviour:

// define a struct with tags for env name, cli flag and usage
type RootConfig struct {
	Hostname string `env:"CONFIGSTRUCT_HOSTNAME" cli:"hostname" usage:"hostname value"`
	Debug    bool   `env:"CONFIGSTRUCT_DEBUG" cli:"debug" usage:"debug mode"`
}

type CountConfig struct {
    Number int `cli:"number" usage:"number to count"`
} 

// create a variable of the struct type and define defaults if needed
rootCfg := RootConfig{
    Hostname: "localhost",
    Debug:    true,
}

countCfg := CountConfig {
    Number: 1
}

countCmd := NewCommand("count", &subConfig, func(c *configstruct.Command, cfg interface{}) error {
    cfgValues := cfg.(*CountConfig)
    ...
    return nil
})

cmd := NewCommand("", &rootCfg, func(c *configstruct.Command, cfg interface{}) error {
    cfgValues := cfg.(*RootConfig)
    ...
    return nil
}, subCmd)

err := cmd.ParseAndRun(os.Args)

Share dependencies across commands

It is possible to share dependencies with the command functions c.SetDependency(name, dep) and dep, err := c.GetDependency(name). If you for instance initialize a logger in the root command and register it as dependency every sub-command has access to it. Keep in mind that dependencies are saved as interface{} so you have to take care of asserting the right type.

Taking the example from above further it could look like this:

type Logger struct {}

countCmd := NewCommand("count", &subConfig, func(c *configstruct.Command, cfg interface{}) error {
    cfgValues := cfg.(*CountConfig)
	loggerDep, err := c.GetDependency("logger")
	if err != nil {
	    return err	
	}
	
	logger := loggerDep.(*Logger)
	
    ...
    return nil
})

cmd := NewCommand("", &rootCfg, func(c *configstruct.Command, cfg interface{}) error {
    cfgValues := cfg.(*RootConfig)
    logger := &Logger{}
    c.SetDependency("logger", logger)
    ...
    return nil
}, subCmd)


Documentation

Overview

Package configstruct provides a parse function to fill a config struct with values from cli flags or environment

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func Parse

func Parse(c interface{}, opts ...Option) error

Parse uses a given struct c with tags and parses values from env or cli flags, it uses the default FlagSet and os.Args

Example

Example for using `configstruct` with default values.

// define a struct with tags
type Config struct {
	Hostname string `env:"CONFIGSTRUCT_HOSTNAME" cli:"hostname" usage:"hostname value"`
	Port     int    `env:"CONFIGSTRUCT_PORT" cli:"port" usage:"listen port"`
	Debug    bool   `env:"CONFIGSTRUCT_DEBUG" cli:"debug" usage:"debug mode"`
}

// create a variable of the struct type and define defaults if needed
conf := testConfig{
	Hostname: "localhost",
	Port:     8000,
	Debug:    true,
}

// now parse values from first cli flags and then env into this var
err := Parse(&conf)
if err != nil {
	fmt.Printf("can't parse config %s", err)
}
Output:

func ParseWithFlagSet added in v1.1.0

func ParseWithFlagSet(flagSet *flag.FlagSet, cliArgs []string, c interface{}, opts ...Option) error

ParseWithFlagSet can use a specific FlagSet and args slice to parse data from

Types

type Command added in v1.3.0

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

Command defines a command that consists of a name (empty for root command), a struct that models all flags, a function that is executed if the command matches and that gets the config struct as argument several sub-commands can be added

func NewCommand added in v1.3.0

func NewCommand(name string, description string, config interface{}, f CommandFunc, subCommands ...*Command) *Command

NewCommand creates a command that is triggered by the given name in the command line all flags are defined by a struct that is parsed and filled with real values this struct is then set as argument for the function that is executed if the name matches

func (*Command) GetDependency added in v1.4.0

func (c *Command) GetDependency(name string) (interface{}, error)

GetDependency gets a previous saved dependency in this command or any of the parent commands in the chain

func (*Command) ParseAndRun added in v1.3.0

func (c *Command) ParseAndRun(args []string, opts ...Option) error

ParseAndRun parses the given arguments and executes command functions

func (*Command) SetDependency added in v1.4.0

func (c *Command) SetDependency(name string, dep interface{})

SetDependency saves a dependency referenced by a name for subcommands

type CommandFunc added in v1.4.0

type CommandFunc func(c *Command, cfg interface{}) error

CommandFunc is a function that is executed when a command is referenced in a CLI call

type Option added in v1.2.0

type Option func(c *config)

Option is a config setting function

func WithPrecedenceCli added in v1.2.0

func WithPrecedenceCli() Option

WithPrecedenceCli enabled precedence of cli over ENV values (default)

func WithPrecedenceEnv added in v1.2.0

func WithPrecedenceEnv() Option

WithPrecedenceEnv enabled precedence of ENV values over cli

func WithYamlConfig added in v1.6.0

func WithYamlConfig(path string) Option

WithYamlConfig sets the path to a yaml config file

Jump to

Keyboard shortcuts

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