gofigure

package module
v0.1.2 Latest Latest
Warning

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

Go to latest
Published: Apr 4, 2023 License: MIT Imports: 14 Imported by: 3

README

Go figure!

Build Issues Pull Requests Go Doc License

A configuration tool that will allow configuration from the command line, environment variable, local config file, or a remote configure file. You give it the details and just say "Go figure!".

Usage

go get -u bitbucket.org/idomdavis/gofigure

See gofigure_test.go for example usage.

Documentation

Overview

Package gofigure allows for configuration of an application using command line flags, environment variables and configuration files.

Example
package main

import (
	"fmt"
	"os"
	"time"

	"bitbucket.org/idomdavis/gofigure"
)

func main() {
	var configFile gofigure.External

	var settings struct {
		Mode    int
		Name    string
		Address string
		Timeout time.Duration
		TLS     bool
	}

	config := gofigure.NewConfiguration("EXAMPLE")
	config.AddHelp(gofigure.CommandLine)

	group := config.Group("settings")

	group.Add(gofigure.Required("Config File", "config", &configFile,
		gofigure.CommandLine, gofigure.ReportValue, "Path to config file"))
	group.Add(gofigure.Required("App Name", "name", &settings.Name,
		gofigure.AllSources, gofigure.ReportValue, "Application name"))
	group.Add(gofigure.Required("Mode", "mode", &settings.Mode, gofigure.Flag,
		gofigure.ReportValue, "Mode indicator"))
	group.Add(gofigure.Optional("IP Address", "address", &settings.Address,
		"", gofigure.AllSources, gofigure.MaskUnset, "Remote server address"))
	group.Add(gofigure.Optional("Timeout", "timeout", &settings.Timeout,
		time.Minute, gofigure.AllSources, gofigure.ReportValue,
		"Remote server address"))
	group.Add(gofigure.Optional("TLS", "tls", &settings.TLS, false,
		gofigure.NamedSources, gofigure.ReportValue, "Use TLS"))

	// Ordinarily this would be config.Parse().
	err := config.ParseUsing([]string{
		"-c", "testdata/config.json",
		"--mode", "3",
		"--name", "example",
		"-h",
	})

	if err != nil {
		fmt.Println(config.Format(err))
		fmt.Println(config.Usage())
		os.Exit(-1)
	}

	fmt.Printf("%v\n\n", settings)

	if config.Help {
		fmt.Println(config.Usage())
	}

}
Output:

{3 example localhost:8000 1m0s false}

usage:
  Help [-h, --help]
    Display usage information

  Config File [-c, --config]
    Path to config file

  App Name [JSON key: "name", env EXAMPLE_NAME, -n, --name]
    Application name

  Mode [--mode]
    Mode indicator

  IP Address [JSON key: "address", env EXAMPLE_ADDRESS, -a, --address]
    Remote server address

  Timeout [JSON key: "timeout", env EXAMPLE_TIMEOUT, -t, --timeout]
    Remote server address

  TLS [JSON key: "tls", env EXAMPLE_TLS, --tls]
    Use TLS

Index

Examples

Constants

View Source
const (
	// HideSet will not report the value if it's set.
	HideSet = Mask(1 << iota)

	// HideUnset will not report anything if the value is not set.
	HideUnset = Mask(1 << iota)

	// MaskSet will report Set rather than the definition value.
	MaskSet = Mask(1 << iota)

	// MaskUnset will report Unset rather than the definition value.
	MaskUnset = Mask(1 << iota)

	// DefaultIsSet sets the behaviour of Mask to treat a default value as
	// Set rather than NotSet.
	DefaultIsSet = Mask(1 << iota)

	// ReportValue will report the definition value.
	ReportValue = 0

	// HideValue will not report anything for the definition.
	HideValue = HideSet | HideUnset

	// MaskValue will report Set or Unset rather than the definition value.
	MaskValue = MaskSet | MaskUnset
)
View Source
const (
	// Set is used when MaskSet is specified.
	Set = "SET"

	// NotSet is used when MaskNotSet is specified.
	NotSet = "UNSET"

	// Invalid is used when a Value is invalid.
	Invalid = "INVALID"
)
View Source
const (
	// None indicates no source has set the Value.
	None = Source(1 << iota)

	// A Default Value has been used. No other sources have overwritten this.
	Default = Source(1 << iota)

	// A Key in a JSON file. Can be used either to indicate the Value can be set
	// via this Key, or has been set via this Key.
	Key = Source(1 << iota)

	// An EnvVar or environment variable. Can be used either to indicate the
	// Value can be set via this environment variable, or that it has been set
	// via this environment variable.
	EnvVar = Source(1 << iota)

	// A ShortFlag on the command line. Can be used either to indicate the
	// Value can be set via this flag, or that it has been set via this flag.
	ShortFlag = Source(1 << iota)

	// A Flag on the command line. Can be used either to indicate the
	// Value can be set via this flag, or that it has been set via this flag.
	Flag = Source(1 << iota)
)
View Source
const AllSources = NamedSources | ShortFlag

AllSources indicates an option should be set from a short flag, flag, environment variable, or JSON key.

View Source
const CommandLine = Flag | ShortFlag

CommandLine indicates an option can come from a short or long flag.

View Source
const Dev = "dev"

Dev identifier, used as a default when the Identifier is unset and cannot be inferred.

View Source
const NamedSources = Flag | EnvVar | Key

NamedSources indicates an option should be set from a flag, environment variable, or JSON key.

View Source
const Unset = "<unset>"

Unset is used when version data is unset and cannot be inferred.

Variables

View Source
var (
	Identifier = Dev
	BuildTime  = Unset
	CommitHash = Unset
)

Build identifiers. These are given sensible defaults, but can be overridden when an application is compiled using -ldflags. Within a Makefile this may look like:

 PACKAGE = bitbucket.org/idomdavis/gofigure
 BUILD_TIME = $(shell date +"%Y/%m/%d-%H:%M:%S")
 HASH = $(shell git rev-parse HEAD)

 ifdef BITBUCKET_TAG
 TAG = $(BITBUCKET_TAG)
 else ifdef BITBUCKET_BRANCH
 TAG = $(BITBUCKET_BRANCH)
 else
 TAG = $(shell git rev-parse --abbrev-ref HEAD)
 endif

 ifeq (, $(TAG))
 TAG = dev
 endif

 LDFLAGS = -X $(PACKAGE).BuildTime=$(BUILD_TIME) \
	-X $(PACKAGE).CommitHash=$(HASH) \
	-X $(PACKAGE).Identifier=$(TAG)

 build:
 	go build -ldflags "$(LDFLAGS)"

The identifiers are used for reference only and have no impact on the operation of gofigure.

View Source
var (
	ErrMissingName        = errors.New("value for Value.Name is empty")
	ErrMissingDescription = errors.New("value for Value.Description is empty")
	ErrNilPointer         = errors.New("value for Value.Ptr is nil")
	ErrInvalidType        = errors.New("invalid type")
)

Value validation errors.

View Source
var ErrInvalidValue = errors.New("invalid value")

ErrInvalidValue is used when an option can't be mapped.

View Source
var ErrLoadingConfig = errors.New("error loading config")

ErrLoadingConfig is returned if a config file cannot be read from the path or URL given.

View Source
var ErrMissingRequiredOption = errors.New("missing required option")

ErrMissingRequiredOption is returned if a required option has not been set after parsing.

View Source
var ErrParsingConfig = errors.New("error parsing config")

ErrParsingConfig is returned if the config file is not valid JSON.

View Source
var ErrUnexpectedArgument = errors.New("unexpected argument")

ErrUnexpectedArgument is returned if an unexpected argument is passed.

Functions

func Assign

func Assign[T Type](target *T, value any) (err error)

Assign the value to the target, returning an error if assignment fails. Assign will attempt to coerce string values to the correct type.

func Build added in v0.1.1

func Build() string

Build returns a build string for the application. This relies on the correct ldflags being set.

Example
package main

import (
	"fmt"

	"bitbucket.org/idomdavis/gofigure"
)

func main() {
	fmt.Println(gofigure.Build())

}
Output:

dev [<unset>] (built: <unset>)

func Coerce

func Coerce(value, typeOf any) (r any, err error)

Coerce will coerce string values to the correct type. All other value types are simply returned as is. If the string value cannot be coerced to the type an error is returned.

Example
package main

import (
	"fmt"
	"time"

	"bitbucket.org/idomdavis/gofigure"
)

func main() {
	fmt.Println(gofigure.Coerce(1, 0))
	fmt.Println(gofigure.Coerce("1m0s", time.Nanosecond))
	fmt.Println(gofigure.Coerce("true", false))
	fmt.Println(gofigure.Coerce("1", 0))
	fmt.Println(gofigure.Coerce("1", int64(0)))
	fmt.Println(gofigure.Coerce("1", uint(0)))
	fmt.Println(gofigure.Coerce("1", uint64(0)))
	fmt.Println(gofigure.Coerce("1.1", float64(0)))
	fmt.Println(gofigure.Coerce("1", int8(0)))

}
Output:

1 <nil>
1m0s <nil>
true <nil>
1 <nil>
1 <nil>
1 <nil>
1 <nil>
1.1 <nil>
1 cannot coerce "1": invalid type: int8

func Dereference

func Dereference(in any) any

Dereference a value. If the value isn't a pointer then it is returned as is.

Example
package main

import (
	"fmt"

	"bitbucket.org/idomdavis/gofigure"
)

func main() {
	i := 1

	fmt.Println(gofigure.Dereference(i))
	fmt.Println(gofigure.Dereference(&i))

}
Output:

1
1

Types

type ConfigError

type ConfigError struct {
	Cause    error
	Internal error

	Parameters Parameters
	Value      any
}

ConfigError holds data about what specifically caused configuration to fail. This can e used to generate a user-friendly report.

func NewConfigError

func NewConfigError(cause, internal error, parameters ...Parameter) ConfigError

NewConfigError will return a new ConfigError for the given errors and Parameters.

func (ConfigError) Error

func (c ConfigError) Error() string

func (ConfigError) Format

func (c ConfigError) Format(prefix string) string

Format the error in a user-centric way.

func (ConfigError) Unwrap

func (c ConfigError) Unwrap() error

type Configuration

type Configuration struct {
	Help   bool
	Prefix string
	Groups []*Group
	// contains filtered or unexported fields
}

Configuration for a program.

func NewConfiguration

func NewConfiguration(envPrefix string) *Configuration

NewConfiguration returns a new Configuration set to use the given prefix for environment variables.

func (*Configuration) AddHelp

func (c *Configuration) AddHelp(sources Source)

AddHelp will add a "help" flag to the set of Options. If ShortFlag is set on the sources then a short flag of 'h' is also added. All other sources are ignored.

func (*Configuration) Format

func (c *Configuration) Format(err error) string

Format an error for user consumption. This will remove most of the technical details and leave a simple message as to why the configuration failed. Format should be used to report any errors to the user.

func (*Configuration) Group

func (c *Configuration) Group(name string) *Group

Group of Definitions for this Configuration.

func (*Configuration) Log

func (c *Configuration) Log(logger *logrus.Logger)

Log the configuration using the given logger. Masks will be respected.

func (*Configuration) Parse

func (c *Configuration) Parse() error

Parse the Options.

func (*Configuration) ParseUsing

func (c *Configuration) ParseUsing(args []string) error

ParseUsing uses the given arguments as the set of command line arguments.

func (*Configuration) Usage

func (c *Configuration) Usage() string

Usage string for this set of Options.

type External

type External string

External types hold a path to an external configuration file.

type Group

type Group struct {
	Name     string
	Settings []*Setting
}

Group of Settings.

func (*Group) Add

func (g *Group) Add(setting *Setting)

Add a Setting to the Group.

func (*Group) Values

func (g *Group) Values() map[string]any

Values set on this group. Values will strip any Setting with a Mask that indicates it should be hidden.

Example
package main

import (
	"fmt"

	"bitbucket.org/idomdavis/gofigure"
)

func main() {
	var a, b string

	g := gofigure.Group{}

	g.Add(gofigure.Required("a", "a", &a, gofigure.Flag, gofigure.HideUnset, "a"))
	g.Add(gofigure.Required("b", "b", &b, gofigure.Flag, gofigure.MaskValue, "b"))

	fmt.Println(g.Values())

}
Output:

map[b:UNSET]

type Mask

type Mask uint8

Mask definition values when they are logged.

func (Mask) Contains

func (m Mask) Contains(mask Mask) bool

Contains returns true if the Mask contains the given Mask.

func (Mask) String

func (m Mask) String() string
Example
package main

import (
	"fmt"

	"bitbucket.org/idomdavis/gofigure"
)

func main() {
	fmt.Println(gofigure.HideValue)
	fmt.Println(gofigure.MaskValue)
	fmt.Println(gofigure.DefaultIsSet)

}
Output:

Hide value
Mask value
Mask value: 16

type Options

type Options map[Parameter]any

Options use to configure an application.

func Environment

func Environment(prefix string, settings Settings) Options

Environment Options defined by the Settings.

func Flags

func Flags(args []string) (Options, error)

Flags will build a set of Options from the given argument list.

Example
package main

import (
	"fmt"

	"bitbucket.org/idomdavis/gofigure"
)

func main() {
	flags, err := gofigure.Flags([]string{"-v", "--name", "example"})

	if err != nil {
		fmt.Println(err)
	}

	fmt.Println(flags)

}
Output:

[name:example, v:true]

func Load

func Load(uri string) (Options, error)

Load external Options from a URI. The external file can be any JSON object.

Example
package main

import (
	"fmt"

	"bitbucket.org/idomdavis/gofigure"
)

func main() {
	d, err := gofigure.Load("testdata/config.json")

	if err != nil {
		fmt.Println(err)
	}

	fmt.Println(d)

}
Output:

[address:localhost:8000, name:overridden]

func (Options) String

func (o Options) String() string

type Parameter

type Parameter struct {
	Name   string
	Source Source

	Stub string
}

Parameter used to set a Value.

func (Parameter) FullName

func (p Parameter) FullName() string

FullName returns the fully formatted name for the parameter.

func (Parameter) Matches

func (p Parameter) Matches(parameter Parameter) bool

Matches returns true if the Argument matches the Parameter.

Example
package main

import (
	"fmt"

	"bitbucket.org/idomdavis/gofigure"
)

func main() {
	a := gofigure.Parameter{Name: "param", Source: gofigure.AllSources}
	b := gofigure.Parameter{Name: "param", Source: gofigure.Flag}
	c := gofigure.Parameter{Name: "param", Source: gofigure.ShortFlag}

	fmt.Println(a.Matches(b))
	fmt.Println(b.Matches(c))
	fmt.Println(b.Matches(a))
	fmt.Println(c.Matches(b))

}
Output:

true
false
true
false

func (Parameter) String

func (p Parameter) String() string

type Parameters

type Parameters []Parameter

Parameters that can be used to set a Value.

func NewParameters

func NewParameters(name string, sources Source) Parameters

NewParameters returns a set of named parameters for the given sources. Combine multiple sources with | (e.g. Flag | EnvVar). The given name is used for each source with Flag and Key using the name as is, EnvSuffix set to the uppercase version of the name, and ShortFlag set to the first character of name.

Example
package main

import (
	"fmt"

	"bitbucket.org/idomdavis/gofigure"
)

func main() {
	fmt.Println(gofigure.NewParameters("param", gofigure.AllSources))

}
Output:

[JSON key: "param" env PARAM -p --param]

func (Parameters) Format

func (p Parameters) Format(prefix string) string

Format the given Parameters into a human-readable string.

Example
package main

import (
	"fmt"

	"bitbucket.org/idomdavis/gofigure"
)

func main() {
	p := gofigure.NewParameters("param", gofigure.AllSources)

	fmt.Println(p.Format("STUB"))

}
Output:

[JSON key: "param", env STUB_PARAM, -p, --param]

type Setting

type Setting struct {
	Value      *Value
	Parameters Parameters
	Mask       Mask
}

Setting in a Configuration. A Setting takes values from a set of Parameters and applies them to a Value. The Mask is used when generating a Display value.

func Optional

func Optional[T Type](name, param string, ptr *T, value T, sources Source,
	mask Mask, description string) *Setting

Optional Setting uses the given default value if no value is provided via its parameters. The parameters are constructed using the param value and the defined sources. Combine multiple sources with | (e.g. Flag | EnvVar). The given name is used for each source with Flag and Key using the name as is, EnvSuffix set to the uppercase version of the name, and ShortFlag set to the first character of name.

func Required

func Required[T Type](name, param string, ptr *T, sources Source, mask Mask,
	description string) *Setting

Required Setting must be set via one of its Parameters. The parameters are constructed using the param value and the defined sources. Combine multiple sources with | (e.g. Flag | EnvVar). The given name is used for each source with Flag and Key using the name as is, EnvSuffix set to the uppercase version of the name, and ShortFlag set to the first character of name.

func (Setting) Accepts

func (s Setting) Accepts(parameter Parameter) bool

Accepts returns true if this Setting accepts the given Parameter.

func (Setting) Display

func (s Setting) Display() (string, bool)

Display string for the Setting. The string should only be displayed if Display returns true, otherwise it should be hidden.

type Settings

type Settings []*Setting

func (Settings) Apply

func (s Settings) Apply(parameter Parameter, value any) error

Apply the Parameter to the correct Setting in the set. Apply will return an error if the relevant Setting cannot be set, or if no Settings have been set.

func (Settings) External

func (s Settings) External() []string

External configuration file paths defined by these settings.

func (Settings) Map

func (s Settings) Map(options map[Parameter]any, ignore ...error) error

Map the options to the settings, ignoring any errors provided.

type Source

type Source uint8

Source of a Value, either accepted sources (i.e. what sources set a Value), or defining Source that set the Value. Combine multiple sources with | when defining accepted sources (e.g. Flag | EnvVar).

func (Source) Contains

func (s Source) Contains(source Source) bool

Contains returns true if the Source contains the given Source.

Example
package main

import (
	"fmt"

	"bitbucket.org/idomdavis/gofigure"
)

func main() {
	sources := gofigure.Flag | gofigure.ShortFlag

	fmt.Println(sources.Contains(gofigure.Flag))
	fmt.Println(sources.Contains(gofigure.Key))

	sources = gofigure.AllSources

	fmt.Println(sources.Contains(gofigure.Key))

}
Output:

true
false
true

func (Source) String

func (s Source) String() string
Example
package main

import (
	"fmt"
	"math"

	"bitbucket.org/idomdavis/gofigure"
)

func main() {
	fmt.Println(gofigure.Default)
	fmt.Println(gofigure.Key)
	fmt.Println(gofigure.EnvVar)
	fmt.Println(gofigure.ShortFlag)
	fmt.Println(gofigure.Flag)
	fmt.Println(gofigure.Source(math.MaxUint8))
	fmt.Println(gofigure.None)

}
Output:

default value
config file key
environment value
short flag
flag
config file
source

type Type

type Type interface {
	~bool | ~int | ~int64 | ~uint | ~uint64 | ~float64 | ~string
}

Type accepted by gofigure.

type Value

type Value struct {
	Name        string
	Description string
	Ptr         any

	Source Source
	// contains filtered or unexported fields
}

A Value is used to hold a configured value. The Value must be a pointer to the variable being set, and must satisfy Type. Once set the Value will contain the Source that provided the value.

func NewValue

func NewValue[T Type](name string, ptr *T, value T, source Source, description string) *Value

NewValue returns a new, valid value. An empty name, description, or an invalid ptr will result in a panic.

func (*Value) Assign

func (v *Value) Assign(value any, source Source) error

Assign a value to the Value.Ptr, returning an error if the assignment cannot be made.

func (*Value) Validate

func (v *Value) Validate() error

Validate the setting returning an error if the Value lacks a name or description, if the Ptr is nil, or if the Ptr is of the incorrect type.

Jump to

Keyboard shortcuts

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