yacl

package module
v0.3.0 Latest Latest
Warning

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

Go to latest
Published: Jun 1, 2025 License: MIT Imports: 8 Imported by: 5

README

Go codecov Go Report Card Go Reference

go-yacl

Yet another configuration library for Go.

This library parses command line flags, environment variables, and configuration files (yaml) into a struct.

With the go's default flag package there is only the possibility to define "flat" flags: there is no possibility to define dynamic structures.

This library tackle that issue. They can parse arguments like this:

$> myApp --map[key]=value --entry[0].key=key1 --entry[0].value=val1

The "key-mechanic" is converting command line arguments to yaml-content and then use yaml parser to parse the content into a struct. Therefore, you have to use the yaml-tags for defining the key names.

How to use it

Basic usage

package main

import (
	"github.com/rainu/go-yacl"
)

type MyConfig struct {
	Help bool               `yaml:"help" short:"h" usage:"Show help"`
	Map  map[string]string  `yaml:"map"`
	Entries []struct{
		Key   string `yaml:"key"`
		Value string `yaml:"value"`
	} `yaml:"entry"`
}

func main() {
	c := MyConfig{}

	config := yacl.NewConfig(&c)
	err := config.ParseArguments("--help")
	if err != nil {
		panic(err)
	}
	if c.Help {
		println(config.HelpFlags())
		return
	}
}

Parse environment

package main

import (
	"github.com/rainu/go-yacl"
)

type MyConfig struct {
	Help bool `yaml:"help" short:"h" usage:"Show help"`
}

func main() {
	c := MyConfig{}

	config := yacl.NewConfig(&c)
	err := config.ParseEnvironment("CFG_0=--help")
	if err != nil {
		panic(err)
	}
	if c.Help {
		println(config.HelpFlags())
		return
	}
}

Parse yaml file

package main

import (
	"github.com/rainu/go-yacl"
	"os"
)

type MyConfig struct {
	Help bool `yaml:"help" short:"h" usage:"Show help"`
}

func main() {
	c := MyConfig{}

	config := yacl.NewConfig(&c)

	yamlFile, err := os.Open("/path/to/config.yaml")
	if err != nil {
		panic(err)
	}
	defer yamlFile.Close()

	err = config.ParseYaml(yamlFile)
	if err != nil {
		panic(err)
	}
	if c.Help {
		println(config.HelpFlags())
		return
	}
}

Define default values

For applying default values you have to define a function which is responsible for setting those values. Attention: This function will be called after the unmarshalling! So you have to check if a field is already filled before setting a default value. Otherwise, you will override the provided value! Because of that it is recommended to use pointers for primitive types. Otherwise, you cannot really be sure if the field is intended to be empty.

To define suche a function there are two ways to do this:

Register a function
package main

import (
	"github.com/rainu/go-yacl"
)

type MyConfig struct {
	String *string `yaml:"string"`
}

func Default(m *MyConfig) {
	// check if the field is already set
	if m.String == nil {
        m.String = yacl.P("default")
    }
}

func main() {
	c := MyConfig{}

	config := yacl.NewConfig(&c, yacl.WithDefaults(Default))
	err := config.ParseArguments()
	if err != nil {
		panic(err)
	}
	println(c.String) // should be "default"
}
Define a pointer receiver function
package main

import (
	"github.com/rainu/go-yacl"
)

type MyConfig struct {
	String *string `yaml:"string"`
}

// implements the interface >yacl.DefaultSetter<
func (m *MyConfig) SetDefaults() {
	// check if the field is already set
	if m.String == nil {
		m.String = yacl.P("default")
	}
}

func main() {
	c := MyConfig{}

	config := yacl.NewConfig(&c)
	err := config.ParseArguments()
	if err != nil {
		panic(err)
	}
	println(c.String) // should be "default"
}

Define usage

There are three ways to define the usage

Usage tag
type MyConfig struct {
	String string `yaml:"string" usage:"Put a string here"`
}
Register a function
package main

import (
	"github.com/rainu/go-yacl"
)

type MyConfig struct {
	String string `yaml:"string"`
}

func main() {
	c := MyConfig{}

	config := yacl.NewConfig(&c, yacl.WithUsage(func(t *MyConfig, f string) string {
        if f == "String" {
            return "Put a string here"
        }
		return ""
	}))
	println(config.HelpFlags())
}
Define a pointer receiver function
package main

import (
	"github.com/rainu/go-yacl"
)

type MyConfig struct {
	String string `yaml:"string"`
}

// implements the interface >yacl.UsageProvider<
func (m *MyConfig) GetUsage(field string) string {
    if field == "String" {
        return "Put a string here"
    }
    return ""
}

func main() {
	c := MyConfig{}

	config := yacl.NewConfig(&c)
	println(config.HelpFlags())
}

Nested structs

package main

import (
	"github.com/rainu/go-yacl"
)

type MyConfig struct {
	Inner struct {
		Bool bool `yaml:"bool" usage:"bool"`
	} `yaml:"inner" usage:"Inner: "`
}

func main() {
	c := MyConfig{}

	config := yacl.NewConfig(&c)
	err := config.ParseArguments("--inner.bool=true")
	if err != nil {
		panic(err)
	}
	println(config.HelpFlags())
}

Shadow structs

package main

import (
	"github.com/rainu/go-yacl"
)

type MyConfig struct {
	Inner struct {
		Bool bool `yaml:"bool" usage:"bool"`
	} `yaml:",inline"`
}

func main() {
	c := MyConfig{}

	config := yacl.NewConfig(&c)
	err := config.ParseArguments("--inner.bool=true")
	if err != nil {
		panic(err)
	}
	println(config.HelpFlags())
}

More options

For more options, have a look into the option.go file.

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func D added in v0.2.0

func D[T any](t *T) T

D is a helper function that dereferences a pointer of type T. If the pointer is nil, it returns the zero value of type T.

func P added in v0.2.0

func P[T any](t T) *T

P is a helper function that returns a pointer to the value of type T.

func PathSorter

func PathSorter(a, b FieldInfo) int

Types

type Config

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

func NewConfig

func NewConfig[T any](destination *T, opts ...Option) *Config

NewConfig creates a new Config instance where all parse-results will be reflected in the given destination.

func (*Config) ApplyDefaults

func (c *Config) ApplyDefaults()

ApplyDefaults applies default values (execute all DefaultSetters) to the fields of the destination struct.

func (*Config) ArgumentReader

func (c *Config) ArgumentReader(args ...string) io.ReadCloser

ArgumentReader creates a new reader that reads the given arguments and transform them into yaml-format.

func (*Config) CollectInfos

func (c *Config) CollectInfos() FieldInfos

CollectInfos returns a list of all fields which are defined in the destination struct.

func (*Config) EnvironmentReader

func (c *Config) EnvironmentReader(env ...string) io.ReadCloser

EnvironmentReader creates a new reader that reads the given environment variables and transform them into yaml-format.

func (*Config) HelpFlags

func (c *Config) HelpFlags(opts ...HelpOption) string

HelpFlags returns the help text for the flags in a table format. Sorted by the order in struct.

func (*Config) HelpYaml

func (c *Config) HelpYaml(opts ...HelpOption) string

HelpYaml returns the help text for the flags in a YAML format. Sorted by the order in struct.

func (*Config) ParseArguments

func (c *Config) ParseArguments(args ...string) error

ParseArguments parses the given arguments and sets the values in the destination struct.

func (*Config) ParseEnvironment

func (c *Config) ParseEnvironment(env ...string) error

ParseEnvironment parses the given environment variables and sets the values in the destination struct.

func (*Config) ParseOsArguments

func (c *Config) ParseOsArguments() error

ParseOsArguments parses the command line arguments (os.Args[1:]) and sets the values in the destination struct.

func (*Config) ParseOsEnvironment

func (c *Config) ParseOsEnvironment() error

ParseOsEnvironment parses the environment variables (os.Environ()) and sets the values in the destination struct.

func (*Config) ParseYaml

func (c *Config) ParseYaml(reader io.Reader) error

ParseYaml parses the given YAML reader and sets the values in the destination struct.

type DefaultSetter

type DefaultSetter interface {
	SetDefaults()
}

type FieldInfo

type FieldInfo interface {
	// Path returns the path to the field in the destination struct.
	Path() string

	// Field returns the corresponding field in the destination struct.
	Field() reflect.StructField
}

type FieldInfos

type FieldInfos interface {
	// Infos returns a list of all relevant fields which are defined in the destination struct.
	Infos() []FieldInfo
}

type Filter

type Filter func(a FieldInfo) bool

type FlagDecorator added in v0.3.0

type FlagDecorator func(string) string

type FlagDecorators added in v0.3.0

type FlagDecorators struct {
	Short        FlagDecorator
	LongKey      FlagDecorator
	LongValue    FlagDecorator
	Usage        FlagDecorator
	DefaultValue FlagDecorator
}

type HelpOption

type HelpOption func(*HelpOptions)

func WithFilter

func WithFilter(filter Filter) HelpOption

WithFilter sets the filter for the help output.

func WithFlagDecorators added in v0.3.0

func WithFlagDecorators(decorators FlagDecorators) HelpOption

WithFlagDecorators sets the decorators for the flags in the help output.

func WithSorter

func WithSorter(sorter Sorter) HelpOption

WithSorter sets the sorter for the help output.

type HelpOptions

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

type Option

type Option func(*Options)

func WithAssignSign

func WithAssignSign(sign rune) Option

WithAssignSign sets the sign for assignment. Default is '='.

func WithAutoApplyDefaults

func WithAutoApplyDefaults(b bool) Option

WithAutoApplyDefaults define if the default values should be applied automatically before first parsing. Default is true.

func WithDecoderOptions

func WithDecoderOptions(options ...yaml.DecodeOption) Option

WithDecoderOptions sets the decoder options for the parser.

func WithDefaults

func WithDefaults[T any](defaultSetter func(*T)) Option

WithDefaults register a function which is responsible for setting default values for the given type.

func WithKeyDelimiter

func WithKeyDelimiter(delimiter rune) Option

WithKeyDelimiter sets the delimiter for keys. Default is '.'.

func WithPrefixEnv

func WithPrefixEnv(prefix string) Option

WithPrefixEnv sets the prefix for environment variables. Default is "CFG_".

func WithPrefixLong

func WithPrefixLong(prefix string) Option

WithPrefixLong sets the prefix for the keys (long variant). Default is "--".

func WithPrefixShort

func WithPrefixShort(prefix string) Option

WithPrefixShort sets the prefix for the keys (short variant). Default is "-".

func WithShortTag

func WithShortTag(tag string) Option

WithShortTag sets the tag for short usage. Default is "short".

func WithUsage

func WithUsage[T any](getUsage func(*T, string) string) Option

WithUsage register a function which is responsible for getting the usage for the given type and field.

func WithUsageTag

func WithUsageTag(tag string) Option

WithUsageTag sets the tag for usage. Default is "usage".

type Options

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

type Reader

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

func (*Reader) Close

func (r *Reader) Close() error

func (*Reader) Read

func (r *Reader) Read(p []byte) (n int, err error)

type Sorter

type Sorter func(a, b FieldInfo) int

type UsageProvider

type UsageProvider interface {
	GetUsage(field string) string
}

Jump to

Keyboard shortcuts

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