ff

package module
v4.0.0-alpha.1 Latest Latest
Warning

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

Go to latest
Published: Aug 31, 2023 License: Apache-2.0 Imports: 15 Imported by: 117

README

ff go.dev reference Latest Release Build Status

ff is a flags-first approach to configuration.

The basic rationale is that that myprogram -h should reliably describe the complete configuration "surface area" of a program. Therefore, every config parameter should be defined as a flag. This module provides a simple and robust way to define those flags, and to parse them from command-line arguments, environment variables, and/or a config file.

Building a command-line application in the style of kubectl or docker? Command provides a declarative approach that's simpler to write, and easier to maintain, than many common alternatives.

Usage

This module provides a getopts(3)-inspired flag set, used as follows.

fs := ff.NewFlags("myprogram")
var (
	listenAddr = fs.StringLong("listen", "localhost:8080", "listen address")
	refresh    = fs.Duration('r', "refresh", 15*time.Second, "refresh interval")
	debug      = fs.Bool('d', "debug", false, "log debug information")
	_          = fs.StringLong("config", "", "config file (optional)")
)

It's also possible to adapt a standard library flag set. In this case, be sure to use the ContinueOnError error handling strategy. Other options either panic or terminate the program on parse errors. Rude!

fs := flag.NewFlagSet("myprogram", flag.ContinueOnError)
var (
	listenAddr = fs.String("listen", "localhost:8080", "listen address")
	refresh    = fs.Duration("refresh", 15*time.Second, "refresh interval")
	debug      = fs.Bool("debug", "log debug information")
	_          = fs.String("config", "", "config file (optional)")
)

Once you have a set of flags, you can parse them as follows, using options to control parse behavior.

err := ff.Parse(fs, os.Args[1:],
	ff.WithEnvVarPrefix("MY_PROGRAM"),
	ff.WithConfigFileFlag("config"),
	ff.WithConfigFileParser(ff.PlainParser),
)

Here, flags are first set from the provided command-line arguments, then from env vars beginning with MY_PROGRAM, and, finally, if the user specifies a config file, from values in that file, as parsed by PlainParser.

Unlike other flag packages, help/usage text is not automatically printed as a side effect of parse. Instead, when a user requests help via e.g. -h or --help, it's reported as a parse error. Callers are always responsible for checking parse errors, and printing help/usage text as appropriate.

if errors.Is(err, ff.ErrHelp) {
	fmt.Fprint(os.Stderr, ffhelp.Flags(fs))
	os.Exit(0)
} else if err != nil {
	fmt.Fprintf(os.Stderr, "error: %v\n", )
	os.Exit(1)
}

Environment variables

It's possible to take runtime configuration from the environment. The options WithEnvVars and WithEnvVarPrefix enable this feature, and determine how flag names are mapped to environment variable names.

fs := ff.NewFlags("myservice")
var (
	port  = fs.Int('p', "port", 8080, "listen port for server (also via PORT)")
	debug = fs.Bool('d', "debug", false, "log debug information (also via DEBUG)")
)
ff.Parse(fs, os.Args[1:], ff.WithEnvVars())
fmt.Printf("port %d, debug %v\n", *port, *debug)
$ env PORT=9090 myservice
port 9090, debug false
$ env PORT=9090 DEBUG=1 myservice --port=1234
port 1234, debug true

Config files

It's possible to take runtime configuration from config files. The options WithConfigFile, WithConfigFileFlag, and WithConfigFileParser control how config files are specified and parsed. This module includes support for JSON, YAML, TOML, and .env config files, as well as the simple PlainParser format.

fs := ff.NewFlags("myservice")
var (
	port  = fs.IntLong("port", 8080, "listen port for server")
	debug = fs.BoolLong("debug", false, "log debug information")
	_     = fs.StringLong("config", "", "config file")
)
ff.Parse(fs, os.Args[1:], ff.WithConfigFileFlag("config"), ff.WithConfigFileParser(ff.PlainParser))
fmt.Printf("port %d, debug %v\n", *port, *debug)
$ printf "port 9090\n" >1.conf ; myservice --config=1.conf
port 9090, debug false
$ printf "port 9090\ndebug\n" >2.conf ; myservice --config=2.conf --port=1234
port 1234, debug true

Priority

Command-line args have the highest priority, because they're explicitly given to each running instance of a program by the user. Think of command-line args as the "user" configuration.

Environment variables have the next-highest priority, because they reflect configuration set in the runtime context. Think of env vars as the "session" configuration.

Config files have the lowest priority, because they represent config that's static to the host. Think of config files as the "host" configuration.

Commands

Command is a declarative and lightweight alternative to common CLI frameworks like spf13/cobra, urfave/cli, or alecthomas/kingpin.

Those frameworks have relatively large APIs, in order to support a large number of "table stakes" features. In contrast, the command API is quite small, with the immediate goal of being intuitive and productive, and the long-term goal of producing CLI applications that are substantially easier to understand and maintain.

Commands are concerned only with the core mechanics of defining a command tree, parsing flags, and selecting a command to run. They're not intended to be a one-stop-shop for everything a command-line application may need. Features like tab completion, colorized output, etc. are orthogonal to command tree parsing, and can be easily provided by the consumer.

See the examples directory for some CLI tools built with commands.

Documentation

Overview

Package ff provides a flags-first approach to runtime configuration.

Parse is the central function. It mirrors flag.FlagSet.Parse and populates a set of Flags from commandline arguments, environment variables, and/or a config file. Option values control parse behavior.

CoreFlags is a standard, getopts(3)-inspired implementation of the Flags interface. Consumers can create a CoreFlags via NewFlags, or adapt an existing flag.FlagSet to a CoreFlags via NewStdFlags, or provide their own implementation altogether.

Command is provided as a way to build hierarchical CLI tools, like docker or kubectl, in a simple and declarative style. It's intended to be easier to understand and maintain than more common alternatives.

Index

Examples

Constants

This section is empty.

Variables

View Source
var (
	// ErrHelp should be returned by flag sets during parse, when the provided
	// args indicate the user has requested help.
	ErrHelp = flag.ErrHelp

	// ErrDuplicateFlag should be returned by flag sets when the user tries to
	// add a flag with the same name as a pre-existing flag.
	ErrDuplicateFlag = errors.New("duplicate flag")

	// ErrNotParsed may be returned by flag set methods which require the flag
	// set to have been successfully parsed, and that condition isn't satisfied.
	ErrNotParsed = errors.New("not parsed")

	// ErrAlreadyParsed may be returned by the parse method of flag sets, if the
	// flag set has already been successfully parsed, and cannot be parsed
	// again.
	ErrAlreadyParsed = errors.New("already parsed")

	// ErrUnknownFlag should be returned by flag sets methods to indicate that a
	// specific or user-requested flag was provided but could not be found.
	ErrUnknownFlag = errors.New("unknown flag")

	// ErrNoExec is returned when a command without an exec function is run.
	ErrNoExec = errors.New("no exec function")
)

Functions

func Parse

func Parse(fs any, args []string, options ...Option) error

Parse the flag set with the provided args. Option values can be used to influence parse behavior. For example, options exist to read flags from environment variables, config files, etc.

The fs parameter must be of type Flags or *flag.FlagSet. Any other type will result in an error.

Example (Args)
fs := ff.NewFlags("myprogram")
var (
	listen  = fs.StringLong("listen", "localhost:8080", "listen address")
	refresh = fs.Duration('r', "refresh", 15*time.Second, "refresh interval")
	debug   = fs.Bool('d', "debug", false, "log debug information")
)

err := ff.Parse(fs, []string{"--refresh=1s", "-d"})

fmt.Printf("err=%v\n", err)
fmt.Printf("listen=%v\n", *listen)
fmt.Printf("refresh=%v\n", *refresh)
fmt.Printf("debug=%v\n", *debug)
Output:

err=<nil>
listen=localhost:8080
refresh=1s
debug=true
Example (Config)
fs := ff.NewFlags("myprogram")
var (
	listen  = fs.StringLong("listen", "localhost:8080", "listen address")
	refresh = fs.Duration('r', "refresh", 15*time.Second, "refresh interval")
	debug   = fs.Bool('d', "debug", false, "log debug information")
	_       = fs.String('c', "config", "", "path to config file")
)

f, _ := os.CreateTemp("", "ExampleParse_config")
defer func() { f.Close(); os.Remove(f.Name()) }()
fmt.Fprint(f, `
		debug
		listen localhost:9999
	`)

err := ff.Parse(fs, []string{"-c", f.Name()},
	ff.WithConfigFileFlag("config"),
	ff.WithConfigFileParser(ff.PlainParser),
)

fmt.Printf("err=%v\n", err)
fmt.Printf("listen=%v\n", *listen)
fmt.Printf("refresh=%v\n", *refresh)
fmt.Printf("debug=%v\n", *debug)
Output:

err=<nil>
listen=localhost:9999
refresh=15s
debug=true
Example (Env)
fs := ff.NewFlags("myprogram")
var (
	listen  = fs.StringLong("listen", "localhost:8080", "listen address")
	refresh = fs.Duration('r', "refresh", 15*time.Second, "refresh interval")
	debug   = fs.Bool('d', "debug", false, "log debug information")
)

os.Setenv("MY_PROGRAM_REFRESH", "3s")

err := ff.Parse(fs, []string{},
	ff.WithEnvVarPrefix("MY_PROGRAM"),
)

fmt.Printf("err=%v\n", err)
fmt.Printf("listen=%v\n", *listen)
fmt.Printf("refresh=%v\n", *refresh)
fmt.Printf("debug=%v\n", *debug)
Output:

err=<nil>
listen=localhost:8080
refresh=3s
debug=false
Example (Help)
fs := ff.NewFlags("myprogram")
var (
	listen  = fs.StringLong("listen", "localhost:8080", "listen address")
	refresh = fs.DurationLong("refresh", 15*time.Second, "refresh interval")
	debug   = fs.BoolLong("debug", false, "log debug information")
)

err := ff.Parse(fs, []string{"-h"})

fmt.Printf("err=%v\n", err)
fmt.Printf("listen=%v\n", *listen)
fmt.Printf("refresh=%v\n", *refresh)
fmt.Printf("debug=%v\n", *debug)
Output:

err=parse args: flag: help requested
listen=localhost:8080
refresh=15s
debug=false
Example (Stdlib)
fs := flag.NewFlagSet("myprogram", flag.ContinueOnError)
var (
	listen  = fs.String("listen", "localhost:8080", "listen address")
	refresh = fs.Duration("refresh", 15*time.Second, "refresh interval")
	debug   = fs.Bool("debug", false, "log debug information")
)

err := ff.Parse(fs, []string{"--debug", "-refresh=2s", "-listen", "localhost:9999"})

fmt.Printf("err=%v\n", err)
fmt.Printf("listen=%v\n", *listen)
fmt.Printf("refresh=%v\n", *refresh)
fmt.Printf("debug=%v\n", *debug)
Output:

err=<nil>
listen=localhost:9999
refresh=2s
debug=true

func PlainParser

func PlainParser(r io.Reader, set func(name, value string) error) error

PlainParser is a parser for config files in an extremely simple format. Each line is tokenized as a single key/value pair. The first space-delimited token in the line is interpreted as the flag name, and the rest of the line is interpreted as the flag value.

Any leading hyphens on the flag name are ignored. Lines with a flag name but no value are interpreted as booleans, and the value is set to true.

Flag values are trimmed of leading and trailing whitespace, but are otherwise unmodified. In particular, values are not quote-unescaped, and control characters like \n are not evaluated and instead passed through as literals.

Comments are supported via "#". End-of-line comments require a space between the end of the line and the "#" character.

An example config file follows.

# this is a full-line comment
timeout 250ms     # this is an end-of-line comment
foo     abc def   # set foo to `abc def`
foo     12345678  # repeated flags result in repeated calls to Set
bar     "abc def" # set bar to `"abc def"`, including quotes
baz     x\ny      # set baz to `x\ny`, passing \n literally
verbose           # equivalent to `verbose true`

Types

type Command

type Command struct {
	// Name of the command, which is used when producing the help output for the
	// command, as well as for subcommand matching.
	//
	// Required.
	Name string

	// Usage is a single line string which should describe the syntax of the
	// command, including flags and arguments. It's typically printed at the top
	// of the help output for the command. For example,
	//
	//    USAGE
	//      cmd [FLAGS] subcmd [FLAGS] <ARG> [<ARG>...]
	//
	// Here, the usage string begins with "cmd [FLAGS] ...".
	//
	// Recommended. If not provided, the help output for the command should not
	// include a usage section.
	Usage string

	// ShortHelp is a single line which should very briefly describe the purpose
	// of the command in prose. It's typically printed next to the command name
	// when it appears as a subcommand in help output. For example,
	//
	//    SUBCOMMANDS
	//      commandname   this is the short help string
	//
	// Recommended.
	ShortHelp string

	// LongHelp is a multi-line string, usually one or more paragraphs of prose,
	// which explain the command in detail. It's typically included in the help
	// output for the command, separate from other sections.
	//
	// Long help should be formatted for user readability. For example, if help
	// output is written to a terminal, long help should include newlines which
	// hard-wrap the string at an appropriate column width for that terminal.
	//
	// Optional.
	LongHelp string

	// Flags is the set of flags associated with, and parsed by, this command.
	//
	// When building a command tree, it's often useful to allow flags defined by
	// parent commands to be specified by any subcommand. The core flag set
	// supports this behavior via SetParent, see the documentation of that
	// method for details.
	//
	// Optional. If not provided, an empty flag set will be constructed and used
	// so that the -h, --help flag works as expected.
	Flags Flags

	// Subcommands which are available underneath (i.e. after) this command.
	// Selecting a subcommand is done via a case-insensitive comparison of the
	// first post-parse argument to this command, against the name of each
	// subcommand.
	//
	// Optional.
	Subcommands []*Command

	// Exec is invoked by Run (or ParseAndRun) if this command was selected as
	// the terminal command during the parse phase. The args passed to Exec are
	// the args left over after parsing.
	//
	// Optional. If not provided, running this command will result in ErrNoExec.
	Exec func(ctx context.Context, args []string) error
	// contains filtered or unexported fields
}

Command is a declarative structure that combines a main function with a flag set and zero or more subcommands. It's intended to model CLI applications which can be represented as a tree of such commands.

func (*Command) GetParent

func (cmd *Command) GetParent() *Command

GetParent returns the parent command of this command, or nil if a parent hasn't been set. Parents are set during the parse phase, but only for commands which are traversed.

func (*Command) GetSelected

func (cmd *Command) GetSelected() *Command

GetSelected returns the terminal command selected during the parse phase, or nil if the command hasn't been successfully parsed.

func (*Command) Parse

func (cmd *Command) Parse(args []string, options ...Option) error

Parse the args and options against the defined command, which sets relevant flags, traverses the command hierarchy to select a terminal command, and captures the arguments that will be given to that command's exec function. The args should not include the program name: pass os.Args[1:], not os.Args.

func (*Command) ParseAndRun

func (cmd *Command) ParseAndRun(ctx context.Context, args []string, options ...Option) error

ParseAndRun calls Command.Parse and, upon success, Command.Run.

func (*Command) Reset

func (cmd *Command) Reset() error

Reset every command in the command tree to its initial state, including all flag sets. Every flag set must implement Resetter, or else reset will return an error.

func (*Command) Run

func (cmd *Command) Run(ctx context.Context) error

Run the Exec function of the terminal command selected during the parse phase, passing the args left over after parsing. Calling Command.Run without first calling Command.Parse will result in ErrNotParsed.

type ConfigFileParseFunc

type ConfigFileParseFunc func(r io.Reader, set func(name, value string) error) error

ConfigFileParseFunc is a function that consumes the provided reader as a config file, and calls the provided set function for every name=value pair it discovers.

type CoreFlagConfig

type CoreFlagConfig struct {
	// ShortName is the short form name of the flag, which can be provided as a
	// commandline argument with a single dash - prefix. A rune value of 0 or
	// utf8.RuneError is considered an invalid short name and is ignored.
	//
	// At least one of ShortName and/or LongName is required.
	ShortName rune

	// LongName is the long form name of the flag, which can be provided as a
	// commandline argument with a double-dash -- prefix. An empty string is
	// considered an invalid long name and is ignored.
	//
	// At least one of ShortName and/or LongName is required.
	LongName string

	// Placeholder is typically used to represent an example value in the help
	// text for the flag. For example, a placeholder of `BAR` might result in
	// help text like
	//
	//      -f, --foo BAR   set the foo parameter
	//
	// The placeholder is determined by the following logic.
	//
	//  - If EmptyPlaceholder is true, use the empty string
	//  - If Placeholder is non-empty, use that string
	//  - If Usage contains a `backtick-quoted` substring, use that substring
	//  - If Value is a boolean with default value false, use the empty string
	//  - Otherwise, use a simple transformation of the concrete Value type name
	//
	// Optional.
	Placeholder string

	// NoPlaceholder forces the placeholder of the flag to the empty string.
	// This can be useful if you want to elide the placeholder from help text.
	NoPlaceholder bool

	// Usage is a short help message for the flag, typically printed after the
	// flag name(s) on a single line in the help output. For example, a foo flag
	// might have the usage string "set the foo parameter", which might be
	// rendered as follows.
	//
	//      -f, --foo BAR   set the foo parameter
	//
	// If the usage string contains a `backtick` quoted substring, that
	// substring will be treated as a placeholder, if a placeholder was not
	// otherwise explicitly provided.
	//
	// Recommended.
	Usage string

	// Value is used to parse and store the actual flag value. The MakeFlagValue
	// helper can be used to construct values for common primitive types.
	//
	// As a special case, if the value has an IsBoolFlag() bool method returning
	// true, then it will be treated as a boolean flag. Boolean flags are parsed
	// slightly differently than normal flags: they can be provided without an
	// explicit value, in which case the value is assumed to be true.
	//
	// Required.
	Value flag.Value

	// NoDefault forces the default value of the flag to the empty string. This
	// can be useful if you want to elide the default value from help text.
	NoDefault bool
}

CoreFlagConfig collects the required config for a flag in a core flag set.

type CoreFlags

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

CoreFlags is the default implementation of a Flags. It's broadly similar to a flag.FlagSet, but with additional capabilities inspired by getopt(3).

CoreFlags is not safe for concurrent use by multiple goroutines.

func NewFlags

func NewFlags(name string) *CoreFlags

NewFlags returns a new core flag set with the given name.

func NewStdFlags

func NewStdFlags(stdfs *flag.FlagSet) *CoreFlags

NewStdFlags returns a core flag set which acts as an adapter for the provided flag.FlagSet, allowing it to implement the Flags interface.

The returned core flag set has slightly different behavior than normal. It's a fixed "snapshot" of the provided stdfs, which means it doesn't allow new flags to be defined, and won't reflect changes made to the stdfs in the future. Also, to approximate standard parsing behavior, it treats every flag name as a long name, and treats "-" and "--" equivalently when parsing arguments.

func (*CoreFlags) AddFlag

func (fs *CoreFlags) AddFlag(cfg CoreFlagConfig) (Flag, error)

AddFlag adds a flag to the flag set, as specified by the provided config. An error is returned if the config is invalid, or if a flag is already defined in the flag set with the same short or long name.

This is a fairly low level method. Consumers may prefer type-specific helpers like CoreFlags.Bool, CoreFlags.StringVar, etc.

func (*CoreFlags) Bool

func (fs *CoreFlags) Bool(short rune, long string, def bool, usage string) *bool

Bool defines a new flag in the flag set, and panics on any error.

func (*CoreFlags) BoolLong

func (fs *CoreFlags) BoolLong(long string, def bool, usage string) *bool

BoolLong defines a new flag in the flag set, and panics on any error.

func (*CoreFlags) BoolShort

func (fs *CoreFlags) BoolShort(short rune, def bool, usage string) *bool

BoolShort defines a new flag in the flag set, and panics on any error.

func (*CoreFlags) BoolVar

func (fs *CoreFlags) BoolVar(pointer *bool, short rune, long string, def bool, usage string) Flag

BoolVar defines a new flag in the flag set, and panics on any error.

func (*CoreFlags) Duration

func (fs *CoreFlags) Duration(short rune, long string, def time.Duration, usage string) *time.Duration

Duration defines a new flag in the flag set, and panics on any error.

func (*CoreFlags) DurationLong

func (fs *CoreFlags) DurationLong(long string, def time.Duration, usage string) *time.Duration

DurationLong defines a new flag in the flag set, and panics on any error.

func (*CoreFlags) DurationShort

func (fs *CoreFlags) DurationShort(short rune, def time.Duration, usage string) *time.Duration

DurationShort defines a new flag in the flag set, and panics on any error.

func (*CoreFlags) DurationVar

func (fs *CoreFlags) DurationVar(pointer *time.Duration, short rune, long string, def time.Duration, usage string) Flag

DurationVar defines a new flag in the flag set, and panics on any error.

func (*CoreFlags) Float64

func (fs *CoreFlags) Float64(short rune, long string, def float64, usage string) *float64

Float64 defines a new flag in the flag set, and panics on any error.

func (*CoreFlags) Float64Long

func (fs *CoreFlags) Float64Long(long string, def float64, usage string) *float64

Float64Long defines a new flag in the flag set, and panics on any error.

func (*CoreFlags) Float64Short

func (fs *CoreFlags) Float64Short(short rune, def float64, usage string) *float64

Float64Short defines a new flag in the flag set, and panics on any error.

func (*CoreFlags) Float64Var

func (fs *CoreFlags) Float64Var(pointer *float64, short rune, long string, def float64, usage string) Flag

Float64Var defines a new flag in the flag set, and panics on any error.

func (*CoreFlags) Func

func (fs *CoreFlags) Func(short rune, long string, fn func(string) error, usage string)

Func defines a new flag in the flag set, and panics on any error.

func (*CoreFlags) FuncLong

func (fs *CoreFlags) FuncLong(long string, fn func(string) error, usage string)

FuncLong defines a new flag in the flag set, and panics on any error.

func (*CoreFlags) FuncShort

func (fs *CoreFlags) FuncShort(short rune, fn func(string) error, usage string)

FuncShort defines a new flag in the flag set, and panics on any error.

func (*CoreFlags) GetArgs

func (fs *CoreFlags) GetArgs() []string

GetArgs returns the args left over after a successful parse.

func (*CoreFlags) GetFlag

func (fs *CoreFlags) GetFlag(name string) (Flag, bool)

GetFlag returns the first flag known to the flag set that matches the given name. This includes all parent flags, if a parent has been set. The name is compared against each flag's long name, and, if the name is a single rune, it's also compared against each flag's short name.

func (*CoreFlags) GetName

func (fs *CoreFlags) GetName() string

GetName returns the name of the flag set provided during construction.

func (*CoreFlags) Int

func (fs *CoreFlags) Int(short rune, long string, def int, usage string) *int

Int defines a new flag in the flag set, and panics on any error.

func (*CoreFlags) IntLong

func (fs *CoreFlags) IntLong(long string, def int, usage string) *int

IntLong defines a new flag in the flag set, and panics on any error.

func (*CoreFlags) IntShort

func (fs *CoreFlags) IntShort(short rune, def int, usage string) *int

IntShort defines a new flag in the flag set, and panics on any error.

func (*CoreFlags) IntVar

func (fs *CoreFlags) IntVar(pointer *int, short rune, long string, def int, usage string) Flag

IntVar defines a new flag in the flag set, and panics on any error.

func (*CoreFlags) IsParsed

func (fs *CoreFlags) IsParsed() bool

IsParsed returns true if the flag set has been successfully parsed.

func (*CoreFlags) Parse

func (fs *CoreFlags) Parse(args []string) error

Parse the provided args against the flag set, assigning flag values as appropriate. Args are matched to flags defined in this flag set, and, if a parent is set, all parent flag sets, recursively. If a specified flag can't be found, parse fails with ErrUnknownFlag. After a successful parse, subsequent calls to parse fail with ErrAlreadyParsed, until and unless the flag set is reset.

func (*CoreFlags) Reset

func (fs *CoreFlags) Reset() error

Reset the flag set, and all of the flags defined in the flag set, to their initial state. After a successful reset, the flag set may be parsed as if it were newly constructed.

func (*CoreFlags) SetParent

func (fs *CoreFlags) SetParent(parent *CoreFlags) *CoreFlags

SetParent assigns a parent flag set to this one. In this case, all of the flags in all parent flag sets are available, recursively, to the child. For example, Parse will match against any parent flag, WalkFlags will traverse all parent flags, etc.

This method returns its receiver to allow for builder-style initialization.

func (*CoreFlags) String

func (fs *CoreFlags) String(short rune, long string, def string, usage string) *string

String defines a new flag in the flag set, and panics on any error.

func (*CoreFlags) StringList

func (fs *CoreFlags) StringList(short rune, long string, usage string) *[]string

StringList defines a new flag in the flag set, and panics on any error. See [StringListVar] for more details.

func (*CoreFlags) StringListLong

func (fs *CoreFlags) StringListLong(long string, usage string) *[]string

StringListLong defines a new flag in the flag set, and panics on any error. See [StringListVar] for more details.

func (*CoreFlags) StringListShort

func (fs *CoreFlags) StringListShort(short rune, usage string) *[]string

StringListShort defines a new flag in the flag set, and panics on any error. See [StringListVar] for more details.

func (*CoreFlags) StringListVar

func (fs *CoreFlags) StringListVar(pointer *[]string, short rune, long string, usage string) Flag

StringListVar defines a new flag in the flag set, and panics on any error.

The flag represents a list of strings, where each call to Set adds a new value to the list. Duplicate values are permitted.

func (*CoreFlags) StringLong

func (fs *CoreFlags) StringLong(long string, def string, usage string) *string

StringLong defines a new flag in the flag set, and panics on any error.

func (*CoreFlags) StringSet

func (fs *CoreFlags) StringSet(short rune, long string, usage string) *[]string

StringSet defines a new flag in the flag set, and panics on any error. See [StringSetVar] for more details.

func (*CoreFlags) StringSetLong

func (fs *CoreFlags) StringSetLong(long string, usage string) *[]string

StringSetLong defines a new flag in the flag set, and panics on any error. See [StringSetVar] for more details.

func (*CoreFlags) StringSetShort

func (fs *CoreFlags) StringSetShort(short rune, usage string) *[]string

StringSetShort defines a new flag in the flag set, and panics on any error. See [StringSetVar] for more details.

func (*CoreFlags) StringSetVar

func (fs *CoreFlags) StringSetVar(pointer *[]string, short rune, long string, usage string) Flag

StringSetVar defines a new flag in the flag set, and panics on any error.

The flag represents a unique list of strings, where each call to Set adds a new value to the list. Duplicate values are silently dropped.

func (*CoreFlags) StringShort

func (fs *CoreFlags) StringShort(short rune, def string, usage string) *string

StringShort defines a new flag in the flag set, and panics on any error.

func (*CoreFlags) StringVar

func (fs *CoreFlags) StringVar(pointer *string, short rune, long string, def string, usage string) Flag

StringVar defines a new flag in the flag set, and panics on any error.

func (*CoreFlags) Uint

func (fs *CoreFlags) Uint(short rune, long string, def uint, usage string) *uint

Uint defines a new flag in the flag set, and panics on any error.

func (*CoreFlags) Uint64

func (fs *CoreFlags) Uint64(short rune, long string, def uint64, usage string) *uint64

Uint64 defines a new flag in the flag set, and panics on any error.

func (*CoreFlags) Uint64Long

func (fs *CoreFlags) Uint64Long(long string, def uint64, usage string) *uint64

Uint64Long defines a new flag in the flag set, and panics on any error.

func (*CoreFlags) Uint64Short

func (fs *CoreFlags) Uint64Short(short rune, def uint64, usage string) *uint64

Uint64Short defines a new flag in the flag set, and panics on any error.

func (*CoreFlags) Uint64Var

func (fs *CoreFlags) Uint64Var(pointer *uint64, short rune, long string, def uint64, usage string) Flag

Uint64Var defines a new flag in the flag set, and panics on any error.

func (*CoreFlags) UintLong

func (fs *CoreFlags) UintLong(long string, def uint, usage string) *uint

UintLong defines a new flag in the flag set, and panics on any error.

func (*CoreFlags) UintShort

func (fs *CoreFlags) UintShort(short rune, def uint, usage string) *uint

UintShort defines a new flag in the flag set, and panics on any error.

func (*CoreFlags) UintVar

func (fs *CoreFlags) UintVar(pointer *uint, short rune, long string, def uint, usage string) Flag

UintVar defines a new flag in the flag set, and panics on any error.

func (*CoreFlags) Value

func (fs *CoreFlags) Value(short rune, long string, value flag.Value, usage string) Flag

Value defines a new flag in the flag set, and panics on any error.

func (*CoreFlags) ValueLong

func (fs *CoreFlags) ValueLong(long string, value flag.Value, usage string) Flag

ValueLong defines a new flag in the flag set, and panics on any error.

func (*CoreFlags) ValueShort

func (fs *CoreFlags) ValueShort(short rune, value flag.Value, usage string) Flag

ValueShort defines a new flag in the flag set, and panics on any error.

func (*CoreFlags) WalkFlags

func (fs *CoreFlags) WalkFlags(fn func(Flag) error) error

WalkFlags calls fn for every flag known to the flag set. This includes all parent flags, if a parent has been set.

type Flag

type Flag interface {
	// GetFlags should return the set of flags in which this flag is defined.
	// It's primarily used for help output.
	GetFlags() Flags

	// GetShortName should return the short name for this flag, if one is
	// defined. A short name is always a single character (rune) which is
	// typically parsed with a single leading - hyphen.
	GetShortName() (rune, bool)

	// GetLongName should return the long name for this flag, if one is defined.
	// A long name is always a non-empty string which is typically parsed with
	// two leading -- hyphens.
	GetLongName() (string, bool)

	// GetPlaceholder should return a string that can be used as a placeholder
	// for the flag value in help output. For example, a placeholder for a
	// string flag might be STRING. An empty placeholder is valid.
	GetPlaceholder() string

	// GetUsage should return a short description of the flag, which can be
	// included in the help output on the same line as the flag name(s). For
	// example, the usage string for a timeout flag used in an HTTP client might
	// be "timeout for outgoing HTTP requests". An empty usage string is valid,
	// but not recommended.
	GetUsage() string

	// GetDefault should return the default value of the flag as a string.
	GetDefault() string

	// SetValue should parse the provided string into the appropriate type for
	// the flag, and set the flag to that parsed value.
	SetValue(string) error

	// GetValue should return the current value of the flag as a string. If no
	// value has been set, it should return the default value.
	GetValue() string

	// IsSet should return true if SetValue has been called successfully.
	IsSet() bool
}

Flag describes a single runtime configuration parameter, defined within a set of flags, and with a value that's parsed from a string.

Implementations are not expected to be safe for concurrent use by multiple goroutines.

type Flags

type Flags interface {
	// GetName should return the name of the flag set.
	GetName() string

	// Parse should parse the provided args against the flag set, setting flags
	// as appropriate, and saving leftover args to be returned by GetArgs. The
	// provided args shouldn't include the program name: callers should pass
	// os.Args[1:], not os.Args.
	Parse(args []string) error

	// IsParsed should return true if the flag set was successfully parsed.
	IsParsed() bool

	// WalkFlags should call the given fn for each flag known to the flag set.
	// Note that this may include flags that are actually defined in different
	// "parent" flag sets. If fn returns an error, WalkFlags should immediately
	// return that error.
	WalkFlags(fn func(Flag) error) error

	// GetFlag should find and return the first flag known to the flag set with
	// the given name. The name should always be compared against valid flag
	// long names. If name is a single valid rune, it should also be compared
	// against valid flag short names. Note that this may return a flag that is
	// actually defined in a different "parent" flag set.
	GetFlag(name string) (Flag, bool)

	// GetArgs should return the args left over after a successful call to
	// parse. If parse has not yet been called successfully, it should return an
	// empty (or nil) slice.
	GetArgs() []string
}

Flags describes a collection of flags, typically associated with a specific command (or sub-command) executed by an end user.

Any valid Flags can be provided to Parse, or used as the Flags field in a Command. This allows custom flag set implementations to take advantage of the primary features of this module.

Implementations are not expected to be safe for concurrent use by multiple goroutines.

type IsBoolFlagger

type IsBoolFlagger interface{ IsBoolFlag() bool }

IsBoolFlagger is used to identify flag values representing booleans.

type Option

type Option func(*ParseContext)

Option controls some aspect of parsing behavior.

func WithConfigAllowMissingFile

func WithConfigAllowMissingFile() Option

WithConfigAllowMissingFile tells Parse to ignore config files that are specified but don't exist.

By default, missing config files result in a parse error.

func WithConfigFile

func WithConfigFile(filename string) Option

WithConfigFile tells Parse to read the provided filename as a config file. Requires WithConfigFileParser, and overrides WithConfigFileFlag.

Because config files should generally be user-specifiable, this option should rarely be used; prefer WithConfigFileFlag.

func WithConfigFileFlag

func WithConfigFileFlag(flagname string) Option

WithConfigFileFlag tells Parse to treat the flag with the given name as a config file. The flag name must be defined in the flag set consumed by parse. Requires WithConfigFileParser, and is overridden by WithConfigFile.

To specify a default config file, provide it as the default value of the corresponding flag.

func WithConfigFileParser

func WithConfigFileParser(pf ConfigFileParseFunc) Option

WithConfigFileParser tells Parse how to interpret a config file. This option must be explicitly provided in order to parse config files.

By default, no config file parser is defined, and config files are ignored.

func WithConfigIgnoreUndefinedFlags

func WithConfigIgnoreUndefinedFlags() Option

WithConfigIgnoreUndefinedFlags tells Parse to ignore flags in config files which are not defined in the parsed flag set. This option only applies to flags in config files.

By default, undefined flags in config files result in a parse error.

func WithEnvVarPrefix

func WithEnvVarPrefix(prefix string) Option

WithEnvVarPrefix is like WithEnvVars, but only considers environment variables beginning with the given prefix followed by an underscore. That prefix (and underscore) are removed before matching the env var key to a flag name. For example, the env var prefix `MYPROG` would mean that the env var `MYPROG_FOO` matches a flag named `foo`.

By default, flags are not parsed from environment variables at all.

func WithEnvVarSplit

func WithEnvVarSplit(delimiter string) Option

WithEnvVarSplit tells Parse to split environment variable values on the given delimiter, and to set the flag multiple times, once for each delimited token. Values produced in this way are not trimmed of whitespace.

For example, `FOO=a,b,c` might cause a flag named `foo` to receive a single call to Set with the value `a,b,c`. If WithEnvVarSplit is provided as an option, with a delimiter of `,`, then that flag would receive three separate calls to Set with the strings `a`, `b`, and `c`.

By default, no splitting of environment variable values occurs.

func WithEnvVars

func WithEnvVars() Option

WithEnvVars tells Parse to set flags from environment variables. Flags are matched to environment variables by capitalizing the flag name, and replacing separator characters like periods or hyphens with underscores.

By default, flags are not parsed from environment variables at all.

func WithFilesystem

func WithFilesystem(fs embed.FS) Option

WithFilesystem tells Parse to use the provided filesystem when accessing files on disk, typically when reading a config file.

By default, the host filesystem is used, via os.Open.

type ParseContext

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

ParseContext receives and maintains parse options.

type Resetter

type Resetter interface {
	// Reset should revert the flag set to its initial state, including all
	// flags defined in the flag set. If reset returns successfully, the flag
	// set should be as if it were newly constructed: IsParsed should return
	// false, GetArgs should return an empty slice, etc.
	Reset() error
}

Resetter may optionally be implemented by Flags.

Directories

Path Synopsis
examples
basicflags command
textctl command
Package ffenv provides an .env config file paser.
Package ffenv provides an .env config file paser.
Package ffhelp provides tools to produce help text for flags and commands.
Package ffhelp provides tools to produce help text for flags and commands.
Package ffjson provides a JSON config file paser.
Package ffjson provides a JSON config file paser.
Package fftest provides tools for testing flag sets.
Package fftest provides tools for testing flag sets.
Package fftoml provides a TOML config file paser.
Package fftoml provides a TOML config file paser.
Package ffval provides common flag value types and helpers.
Package ffval provides common flag value types and helpers.
Package ffyaml provides a YAML config file parser.
Package ffyaml provides a YAML config file parser.
internal
ffdata
Package ffdata provides data-related helpers for ff packages.
Package ffdata provides data-related helpers for ff packages.

Jump to

Keyboard shortcuts

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