Documentation ¶
Overview ¶
Pakckage flagr is a thin wrapper over the standard flag package creating a generalized API for defining flags of any type.
Example (Builtins) ¶
package main import ( "errors" "fmt" "net/netip" "os" "github.com/flga/flagr" ) func main() { var set flagr.Set // Builtin types like int, float, etc. a := flagr.Add(&set, "a", flagr.Int(42), "usage") // Slices of things, every flag provided by flagr has a slice counterpart. b := flagr.Add(&set, "b", flagr.Ints(1, 2, 3), "usage") // A bool flag has the same semantics as std/flag bools. c := flagr.Add(&set, "c", flagr.Bool(false), "usage") // One of the extra types flagr provides, along with urls, times, etc. d := flagr.Add(&set, "d", flagr.IPAddrPort(netip.MustParseAddrPort("127.0.0.1:8080")), "usage") // Same as above but allows defaults to be provided as strings, delegating parsing to flagr. e := flagr.Add(&set, "e", flagr.MustIPAddrPort("127.0.0.1:8080"), "usage") args := []string{ "-b", "5", "-b", "6", "-c", "-d", "0.0.0.0:80", } if err := set.Parse(args); err != nil { if errors.Is(err, flagr.ErrHelp) { os.Exit(0) } os.Exit(2) } fmt.Printf("a = %v and is a %T\n", *a, a) fmt.Printf("b = %v and is a %T\n", *b, b) fmt.Printf("c = %v and is a %T\n", *c, c) fmt.Printf("d = %v and is a %T\n", *d, d) fmt.Printf("e = %v and is a %T\n", *e, e) }
Output: a = 42 and is a *int b = [5 6] and is a *[]int c = true and is a *bool d = 0.0.0.0:80 and is a *netip.AddrPort e = 127.0.0.1:8080 and is a *netip.AddrPort
Example (CustomTypes) ¶
package main import ( "errors" "fmt" "os" "github.com/flga/flagr" ) func main() { var set flagr.Set // A fully custom flagr.Getter implementation. a := flagr.Add(&set, "a", NewFileMode(0), "usage") // Another fully custom implementation. // Notice that while the flag type is Counter, f is a *int. b := flagr.Add(&set, "b", NewCounter(2), "usage") args := []string{ "-a", "rw", "-b", "-b", "-b", } if err := set.Parse(args); err != nil { if errors.Is(err, flagr.ErrHelp) { os.Exit(0) } os.Exit(2) } fmt.Printf("a = %s and is a %T\n", a.String(), a) fmt.Printf("b = %v and is a %T\n", *b, b) } var _ flagr.Getter[FileMode] = new(FileMode) // a fully custom implementation of flagr.Getter type FileMode byte const ( Read FileMode = 1 << iota Write ) func NewFileMode(defaultValue FileMode) flagr.Getter[FileMode] { return &defaultValue } func (f *FileMode) Get() any { return f } func (f *FileMode) Set(s string) error { for _, rune := range s { switch rune { case 'r': *f |= Read case 'w': *f |= Write default: return fmt.Errorf("invalid file mode %q", s) } } return nil } func (f *FileMode) String() string { if f == nil { return "" } var ret string if *f&Read > 0 { ret += "r" } if *f&Write > 0 { ret += "w" } return ret } func (f *FileMode) IsBoolFlag() bool { return false } func (f *FileMode) Val() *FileMode { return f } // a fully custom implementation of flagr.Getter type Counter struct { value *int set bool } func NewCounter(defaultValue int) flagr.Getter[int] { return &Counter{value: &defaultValue} } func (f *Counter) Get() any { return f.value } func (f *Counter) Set(s string) error { if !f.set { *f.value = 0 f.set = true } *f.value++ return nil } func (f *Counter) String() string { if f == nil || f.value == nil { return "" } return fmt.Sprint(f.value) } func (f Counter) Val() *int { return f.value // this is what we care about, the wrapper struct is just an implementation constraint } func (f Counter) IsBoolFlag() bool { return true }
Output: a = rw and is a *flagr_test.FileMode b = 3 and is a *int
Example (Slices) ¶
package main import ( "errors" "fmt" "net/url" "os" "strconv" "github.com/flga/flagr" ) func main() { var set flagr.Set // We can use flagr.Slice to create repeatable flags. Custom slice types are supported. type bools []bool a := flagr.Add[bools](&set, "a", flagr.Slice(bools{true, false, true}, strconv.ParseBool), "usage") // Making use of MustSlice so that we can pass default values as strings and delegate the parsing to flagr. // Makes it much more comfortable to use things that have to be parsed, like urls. b := flagr.Add[[]*url.URL](&set, "b", flagr.MustSlice([]string{"https://a.com", "https://b.com"}, url.Parse), "usage") // Using helper functions allows us to have cleaner signatures (type inference is still a little wonky) c := flagr.Add(&set, "c", Urls("https://a.com", "https://b.com"), "usage") args := []string{ "-a", "-a", // std/flag bool semantics apply "-b", "https://c.com", "-b", "https://d.com", } if err := set.Parse(args); err != nil { if errors.Is(err, flagr.ErrHelp) { os.Exit(0) } os.Exit(2) } fmt.Printf("a = %v and is a %T\n", *a, a) fmt.Printf("b = %v and is a %T\n", *b, b) fmt.Printf("c = %v and is a %T\n", *c, c) } func Urls(defaults ...string) flagr.Getter[[]*url.URL] { return flagr.MustSlice(defaults, url.Parse) }
Output: a = [true true] and is a *flagr_test.bools b = [https://c.com https://d.com] and is a *[]*url.URL c = [https://a.com https://b.com] and is a *[]*url.URL
Example (Var) ¶
package main import ( "errors" "fmt" "net/url" "os" "strconv" "github.com/flga/flagr" ) func main() { var set flagr.Set // Using flagr.Var to reimplement flagr.Int64. a := flagr.Add(&set, "a", flagr.Var(42, func(value *int64, s string) error { v, err := strconv.ParseInt(s, 0, 64) if err != nil { return err } *value = v return nil }), "usage") // Using helper functions allows us to have cleaner signatures b := flagr.Add(&set, "b", CustomInt64(42), "usage") // Making use of flagr.SetterFrom when setting a value is just a simple assignment (like above). // Also, if the underlying type is a ~bool std/flag bool semantics apply. c := flagr.Add(&set, "c", flagr.Var(false, flagr.SetterFrom(strconv.ParseBool)), "usage") // Making use of MustVar so that we can pass default values as strings and delegate the parsing to flagr. // Makes it much more comfortable to use things that have to be parsed, like urls. d := flagr.Add[*url.URL](&set, "d", flagr.MustVar("http://a.com", flagr.SetterFrom(url.Parse)), "usage") args := []string{ "-a", "1", "-c", // std/flag bool semantics apply "-d", "http://b.com", } if err := set.Parse(args); err != nil { if errors.Is(err, flagr.ErrHelp) { os.Exit(0) } os.Exit(2) } fmt.Printf("a = %v and is a %T\n", *a, a) fmt.Printf("b = %v and is a %T\n", *b, b) fmt.Printf("c = %v and is a %T\n", *c, c) fmt.Printf("d = %v and is a %T\n", *d, d) } // an implementation equivalent to flagr.Int64 func CustomInt64(defaultValue int64) flagr.Getter[int64] { return flagr.Var(defaultValue, func(value *int64, s string) error { v, err := strconv.ParseInt(s, 0, 64) if err != nil { return err } *value = v return nil }) }
Output: a = 1 and is a *int64 b = 42 and is a *int64 c = true and is a *bool d = http://b.com and is a **url.URL
Index ¶
- Constants
- Variables
- func Add[T any](set *Set, name string, value Getter[T], usage string) *T
- func MustSlice[T any](defaults []string, parse ValParser[T]) *slice[T, []T]
- func MustVar[T any](defaultValue string, setter ValSetter[T]) value[T]
- func Slice[T any, S ~[]T](defaultValue S, parse ValParser[T]) *slice[T, S]
- func UnquoteUsage(flag *Flag) (name string, usage string)
- type ErrorHandling
- type Flag
- type Getter
- func Bool(defaultValue bool) Getter[bool]
- func Bools(defaults ...bool) Getter[[]bool]
- func Complex128(defaultValue complex128) Getter[complex128]
- func Complex128s(defaults ...complex128) Getter[[]complex128]
- func Complex64(defaultValue complex64) Getter[complex64]
- func Complex64s(defaults ...complex64) Getter[[]complex64]
- func Duration(defaultValue time.Duration) Getter[time.Duration]
- func Durations(defaults ...time.Duration) Getter[[]time.Duration]
- func Float32(defaultValue float32) Getter[float32]
- func Float32s(defaults ...float32) Getter[[]float32]
- func Float64(defaultValue float64) Getter[float64]
- func Float64s(defaults ...float64) Getter[[]float64]
- func IPAddr(defaultValue netip.Addr) Getter[netip.Addr]
- func IPAddrPort(defaultValue netip.AddrPort) Getter[netip.AddrPort]
- func IPAddrPorts(defaults ...netip.AddrPort) Getter[[]netip.AddrPort]
- func IPAddrs(defaults ...netip.Addr) Getter[[]netip.Addr]
- func Int(defaultValue int) Getter[int]
- func Int16(defaultValue int16) Getter[int16]
- func Int16s(defaults ...int16) Getter[[]int16]
- func Int32(defaultValue int32) Getter[int32]
- func Int32s(defaults ...int32) Getter[[]int32]
- func Int64(defaultValue int64) Getter[int64]
- func Int64s(defaults ...int64) Getter[[]int64]
- func Int8(defaultValue int8) Getter[int8]
- func Int8s(defaults ...int8) Getter[[]int8]
- func Ints(defaults ...int) Getter[[]int]
- func MustIPAddr(defaultValue string) Getter[netip.Addr]
- func MustIPAddrPort(defaultValue string) Getter[netip.AddrPort]
- func MustIPAddrPorts(defaults ...string) Getter[[]netip.AddrPort]
- func MustIPAddrs(defaults ...string) Getter[[]netip.Addr]
- func MustTime(layout string, defaultValue string) Getter[time.Time]
- func MustTimes(layout string, defaults ...string) Getter[[]time.Time]
- func MustURL(defaultValue string) Getter[*url.URL]
- func MustURLs(defaults ...string) Getter[[]*url.URL]
- func String(defaultValue string) Getter[string]
- func Strings(defaults ...string) Getter[[]string]
- func Time(layout string, defaultValue time.Time) Getter[time.Time]
- func Times(layout string, defaults ...time.Time) Getter[[]time.Time]
- func URL(defaultValue *url.URL) Getter[*url.URL]
- func URLs(defaults ...*url.URL) Getter[[]*url.URL]
- func Uint(defaultValue uint) Getter[uint]
- func Uint16(defaultValue uint16) Getter[uint16]
- func Uint16s(defaults ...uint16) Getter[[]uint16]
- func Uint32(defaultValue uint32) Getter[uint32]
- func Uint32s(defaults ...uint32) Getter[[]uint32]
- func Uint64(defaultValue uint64) Getter[uint64]
- func Uint64s(defaults ...uint64) Getter[[]uint64]
- func Uint8(defaultValue uint8) Getter[uint8]
- func Uint8s(defaults ...uint8) Getter[[]uint8]
- func Uints(defaults ...uint) Getter[[]uint]
- func Var[T any](val T, setter ValSetter[T]) Getter[T]
- type Parser
- type Set
- func (set *Set) Arg(i int) string
- func (set *Set) Args() []string
- func (set *Set) ErrorHandling() ErrorHandling
- func (set *Set) Init(name string, errorHandling ErrorHandling)
- func (set *Set) Lookup(name string) *Flag
- func (set *Set) NArg() int
- func (set *Set) NFlag() int
- func (set *Set) Name() string
- func (set *Set) Output() io.Writer
- func (set *Set) Parse(arguments []string, extraParsers ...Parser) error
- func (set *Set) Parsed() bool
- func (set *Set) PrintDefaults()
- func (set *Set) PrintValues()
- func (set *Set) Set(src Source, name, value string) error
- func (set *Set) SetOutput(output io.Writer)
- func (set *Set) SetUsage(usage func())
- func (set *Set) Usage()
- func (set *Set) Visit(fn func(*Flag) error) error
- func (set *Set) VisitAll(fn func(*Flag) error) error
- func (set *Set) VisitRemaining(fn func(*Flag) error) error
- type Source
- type ValParser
- type ValSetter
Examples ¶
Constants ¶
const ( ContinueOnError = stdflag.ContinueOnError // Return a descriptive error. ExitOnError = stdflag.ExitOnError // Call os.Exit(2) or for -h/-help Exit(0). PanicOnError = stdflag.PanicOnError // Call panic with a descriptive error. )
These constants cause Set.Parse to behave as described if the parse fails.
Variables ¶
var ErrHelp = stdflag.ErrHelp
ErrHelp is the error returned if the -help or -h flag is invoked but no such flag is defined.
Functions ¶
func Add ¶
Add creates a new flag on the given Set, returning the underlying value of the provided Getter.
func MustSlice ¶
MustSlice, returns a Getter[[]T] with the given default value, but allows the default values to be provided as a strings. Unlike Slice custom slice implementations are not supported. This could change in the future.
When calling MustSlice each value will be parsed with the given Parser, any error will cause MustSlice to panic.
If the same flag is provided multiple times, the result will be accumulated in a []T.
func MustVar ¶
MustVar, like Var, returns a Getter[T] with the given default value and Setter, but allows the default value to be provided as a string.
When calling MustVar the given setter will be used to convert the default value, into T. If it returns an error, MustVar panics.
Setter is called to parse the provided value and assign it to the underlying value.
func Slice ¶
Slice returns a Getter[S] with the given default value.
If the same flag is provided multiple times, the result will be accumulated in S.
The value will be initialized with a shallow copy of defaultValue.
func UnquoteUsage ¶ added in v0.2.0
UnquoteUsage extracts a back-quoted name from the usage string for a flag and returns it and the un-quoted usage. Given "a `name` to show" it returns ("name", "a name to show"). If there are no back quotes, the name is an educated guess of the type of the flag's value, or the empty string if the flag is boolean.
Types ¶
type ErrorHandling ¶
type ErrorHandling = stdflag.ErrorHandling
ErrorHandling defines how Set.Parse behaves if the parse fails.
type Getter ¶
Getter is any type that satisfies flag.Getter and provides a new method Val() that returns a pointer to the actual value of type.
This allows constructing a flag.Getter such that its type and the type of its value can (but don't need too) be diferent.
In scenarios where the implementation is simple both types should be the same, such as custom builtin type, for example.
In scenarios where the implementation is complex, we might want to use different types.
Let's consider a Getter implementation that counts the times a flag has been provided.
It could be described as a simple integer, but this is insufficient for a correct implementation given that we would need to know, somehow, if the current value is the default value and we should reset it, or if we can just increment the count.
Since we need to keep track of that extra state, we'd need to use a struct to implement Getter, but because the type that implements a Getter and the type that a Getter returns as its value need not be the same, we can define a struct MyCounter that implements a Getter[int], which is the actual value the caller is interested in. The fact that we had to use a struct is an implementation detail.
You can look at the CustomTypes example for a concrete implementation.
func Complex128 ¶
func Complex128(defaultValue complex128) Getter[complex128]
Complex128 returns a Getter that can parse values of type complex128.
func Complex128s ¶
func Complex128s(defaults ...complex128) Getter[[]complex128]
Complex128s returns a Getter that can parse and accumulate values of type complex128.
func Complex64s ¶
Complex64s returns a Getter that can parse and accumulate values of type complex64.
func Durations ¶
Durations returns a Getter that can parse and accumulate values of type time.Duration.
func IPAddrPort ¶
IPAddrPort returns a Getter that can parse values of type netip.AddrPort.
func IPAddrPorts ¶
IPAddrPorts returns a Getter that can parse and accumulate values of type netip.AddrPort.
func MustIPAddr ¶
MustIPAddr, like IPAddr, returns a Getter that can parse values of type netip.Addr, but allowing the default value to be provided as a string. It panics if the given string cannot be parsed as netip.Addr.
func MustIPAddrPort ¶
MustIPAddrPort, like IPAddrPort, returns a Getter that can parse values of type netip.AddrPort, but allowing the default value to be provided as a string. It panics if the given string cannot be parsed as netip.AddrPort.
func MustIPAddrPorts ¶
MustIPAddrPorts, like IPAddrPorts, returns a Getter that can parse values of type netip.AddrPort and accumulate them, but allowing the default values to be provided as strings. It panics if any given string cannot be parsed as netip.AddrPort.
func MustIPAddrs ¶
MustIPAddrs, like IPAddrs, returns a Getter that can parse values of type netip.Addr and accumulate them, but allowing the default values to be provided as strings. It panics if any given string cannot be parsed as netip.Addr.
func MustTime ¶
MustTime, like Time, returns a Getter that can parse values of type time.Time, but allowing the default value to be provided as a string. It panics if the given string cannot be parsed as time.Time.
func MustTimes ¶
MustTimes, like Times, returns a Getter that can parse values of type time.Time and accumulate them, but allowing the default values to be provided as strings. It panics if any given string cannot be parsed as time.Time.
func MustURL ¶
MustURL, like URL, returns a Getter that can parse values of type *url.URL, but allowing the default value to be provided as a string. It panics if the given string cannot be parsed as *url.URL.
func MustURLs ¶
MustURLs, like URLs, returns a Getter that can parse values of type *url.URL and accumulate them, but allowing the default values to be provided as strings. It panics if any given string cannot be parsed as *url.URL.
type Parser ¶
Parser is any function that can set flag values, these are optionally used in Parse to populate values from different sources (such as environment values).
type Set ¶
type Set struct {
// contains filtered or unexported fields
}
A Set represents a set of defined flags. The zero value of a Set has no name and has ContinueOnError error handling.
Flag names must be unique within a Set. An attempt to define a flag whose name is already in use will cause a panic.
func NewSet ¶
func NewSet(name string, errorHandling ErrorHandling) *Set
NewSet returns a new, empty flag set with the specified name and error handling property. If the name is not empty, it will be printed in the default usage message and in error messages.
func (*Set) Arg ¶
Arg returns the i'th argument. Arg(0) is the first remaining argument after flags have been processed. Arg returns an empty string if the requested element does not exist.
func (*Set) ErrorHandling ¶
func (set *Set) ErrorHandling() ErrorHandling
ErrorHandling returns the error handling behavior of the flag set.
func (*Set) Init ¶
func (set *Set) Init(name string, errorHandling ErrorHandling)
Init sets the name and error handling property for a flag set. By default, the zero Set uses an empty name and the ContinueOnError error handling policy.
func (*Set) Lookup ¶
Lookup returns the Flag structure of the named flag, returning nil if none exists.
func (*Set) Output ¶
Output returns the destination for usage and error messages. os.Stderr is returned if output was not set or was set to nil.
func (*Set) Parse ¶
Parse parses flag definitions from the argument list, which should not include the command name. Must be called after all flags in the Set are defined and before flags are accessed by the program. The return value will be ErrHelp if -help or -h were set but not defined.
After parsing the program arguments, it will call each extraParser, in the order they were provided. If any parser fails Parse will return an error. Extra parsers are only allowed to set flags that have not been set previously, either by the program arguments or any other parser that was called before.
This enables you to create a cascade of configuration sources with the precedence you want.
In this example, we call Parse in such way that flags have priority over everything, any flag that was not set explicitly may be set by the env parser, any flag that was not set either by the program arguments or the env parser may be set by the config file parser. If you switch the order of env.Parser() and file.Parser() precedence will change accordingly.
set.Parse( args, // has precedence over env and cfg file env.Parser(), // has precedence over cfg file file.Parser(), // can only set flags that were not set previously )
func (*Set) PrintDefaults ¶
func (set *Set) PrintDefaults()
PrintDefaults prints, to standard error unless configured otherwise, the default values of all defined command-line flags in the set. See the documentation for the global function PrintDefaults for more information.
func (*Set) PrintValues ¶ added in v0.3.0
func (set *Set) PrintValues()
PrintValues works like PrintDefaults, but it prints the current value for every flag, annotated with the source of the value.
It is meant as a debugging utility to troubleshoot value propagation when using multiple sources for flag values (such as environment and config files).
func (*Set) SetOutput ¶
SetOutput sets the destination for usage and error messages. If output is nil, os.Stderr is used.
func (*Set) SetUsage ¶ added in v0.2.0
func (set *Set) SetUsage(usage func())
SetUsage overrides the Set's usage func.
func (*Set) Usage ¶ added in v0.2.0
func (set *Set) Usage()
Usage invokes the usage function provided with SetUsage.
func (*Set) Visit ¶
Visit visits the flags in lexicographical order, calling fn for each. It visits only those flags that have been set. It will stop walking if the fn returns an error.
type Source ¶ added in v0.3.0
type Source string
Source identifies who set the value for a given flag. Used for dumping the current config with source information.
type ValSetter ¶ added in v0.3.0
ValSetter is a function that can, given a string, construct a meaningful value and assign it to *T.
func SetterFrom ¶
Setter from returns a Setter that assigns into *T the result of Parser[T].
Directories ¶
Path | Synopsis |
---|---|
Package env provides a flagr.Parser that is able to read environment variables (and .env files) and set the appropriate flags.
|
Package env provides a flagr.Parser that is able to read environment variables (and .env files) and set the appropriate flags. |
Package file provides a flagr.Parser that is able to read config files and set the appropriate flags.
|
Package file provides a flagr.Parser that is able to read config files and set the appropriate flags. |
internal
|
|