Documentation
¶
Overview ¶
Declaratively create heirarchical command line apps.
Index ¶
- func ColorFlagMap() flag.FlagMap
- func GoldenTest(t *testing.T, args GoldenTestArgs, parseOpts ...ParseOpt)
- func VersionCommandMap() command.CommandMap
- type App
- type AppOpt
- func ConfigFlag(configFlagName flag.Name, scalarOpts []scalar.ScalarOpt[path.Path], ...) AppOpt
- func GlobalFlag(name flag.Name, value flag.Flag) AppOpt
- func GlobalFlagMap(flagMap flag.FlagMap) AppOpt
- func NewGlobalFlag(name flag.Name, helpShort flag.HelpShort, empty value.EmptyConstructor, ...) AppOpt
- func OverrideHelpFlag(mappings []help.HelpFlagMapping, defaultChoice string, flagName flag.Name, ...) AppOpt
- func SkipValidation() AppOpt
- type FlagValue
- type FlagValueMap
- type GoldenTestArgs
- type LookupFunc
- type ParseOpt
- type ParseOptHolder
- type ParseResult
- type ParseResult2
- type ParseState
- type UnsetFlagNameSet
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func ColorFlagMap ¶ added in v0.0.28
ColorFlagMap returns a map with a single "--color" flag that can be used to control color output.
Example:
warg.GlobalFlagMap(warg.ColorFlagMap())
func GoldenTest ¶ added in v0.0.18
func GoldenTest( t *testing.T, args GoldenTestArgs, parseOpts ...ParseOpt)
GoldenTest runs the app and and captures stdout and stderr into files. If those differ than previously captured stdout/stderr, t.Fatalf will be called.
Passed `parseOpts` should not include OverrideStderr/OverrideStdout as GoldenTest overwrites those
func VersionCommandMap ¶ added in v0.0.28
func VersionCommandMap() command.CommandMap
VersioncommandMap returns a map with a single "version" command that prints the app version.
Example:
warg.GlobalFlagMap(warg.ColorFlagMap())
Types ¶
type App ¶
type App struct {
// contains filtered or unexported fields
}
An App contains your defined sections, commands, and flags Create a new App with New()
func New ¶
New creates a warg app. name is used for help output only (though generally it should match the name of the compiled binary). version is the app version - if empty, warg will attempt to set it to the go module version, or "unknown" if that fails.
Example ¶
package main import ( "fmt" "os" "go.bbkane.com/warg" "go.bbkane.com/warg/command" "go.bbkane.com/warg/flag" "go.bbkane.com/warg/section" "go.bbkane.com/warg/value/scalar" ) func login(ctx command.Context) error { url := ctx.Flags["--url"].(string) // timeout doesn't have a default value, // so we can't rely on it being passed. timeout, exists := ctx.Flags["--timeout"] if exists { timeout := timeout.(int) fmt.Printf("Logging into %s with timeout %d\n", url, timeout) return nil } fmt.Printf("Logging into %s\n", url) return nil } func main() { commonFlags := flag.FlagMap{ "--timeout": flag.New( "Optional timeout. Defaults to no timeout", scalar.Int(), ), "--url": flag.New( "URL of the blog", scalar.String( scalar.Default("https://www.myblog.com"), ), flag.EnvVars("BLOG_URL"), ), } app := warg.New( "newAppName", "v1.0.0", section.New( "work with a fictional blog platform", section.NewCommand( "login", "Login to the platform", login, command.FlagMap(commonFlags), ), section.NewSection( "comments", "Deal with comments", section.NewCommand( "list", "List all comments", // still prototyping how we want this // command to look, // so use a provided stub action command.DoNothing, command.FlagMap(commonFlags), ), ), ), ) // normally we would rely on the user to set the environment variable, // bu this is an example err := os.Setenv("BLOG_URL", "https://envvar.com") if err != nil { fmt.Fprintln(os.Stderr, err) os.Exit(1) } app.MustRun(warg.OverrideArgs([]string{"blog.exe", "login"})) }
Output: Logging into https://envvar.com
func (*App) MustRun ¶
MustRun runs the app. Any flag parsing errors will be printed to stderr and os.Exit(64) (EX_USAGE) will be called. Any errors on an Action will be printed to stderr and os.Exit(1) will be called.
func (*App) Parse ¶
func (app *App) Parse(opts ...ParseOpt) (*ParseResult, error)
Parse parses the args, but does not execute anything.
Example (Flag_value_options) ¶
ExampleApp_Parse_flag_value_options shows a couple combinations of flag/value options. It's also possible to use '--help detailed' to see the current value of a flag and what set it.
package main import ( "fmt" "log" "os" "go.bbkane.com/warg" "go.bbkane.com/warg/command" "go.bbkane.com/warg/config/yamlreader" "go.bbkane.com/warg/flag" "go.bbkane.com/warg/path" "go.bbkane.com/warg/section" "go.bbkane.com/warg/value/scalar" "go.bbkane.com/warg/value/slice" ) func main() { action := func(ctx command.Context) error { // flag marked as Required(), so no need to check for existance scalarVal := ctx.Flags["--scalar-flag"].(string) // flag might not exist in config, so check for existance // TODO: does this panic on nil? sliceVal, sliceValExists := ctx.Flags["--slice-flag"].([]int) fmt.Printf("--scalar-flag: %#v\n", scalarVal) if sliceValExists { fmt.Printf("--slice-flag: %#v\n", sliceVal) } else { fmt.Printf("--slice-flag value not filled!\n") } return nil } app := warg.New( "flag-overrides", "v1.0.0", section.New( "demo flag overrides", section.NewCommand( command.Name("show"), "Show final flag values", action, command.NewFlag( "--scalar-flag", "Demo scalar flag", scalar.String( scalar.Choices("a", "b"), scalar.Default("a"), ), flag.ConfigPath("args.scalar-flag"), flag.Required(), ), command.NewFlag( "--slice-flag", "Demo slice flag", slice.Int( slice.Choices(1, 2, 3), ), flag.Alias("-slice"), flag.ConfigPath("args.slice-flag"), flag.EnvVars("SLICE", "SLICE_ARG"), ), ), ), warg.ConfigFlag( "--config", []scalar.ScalarOpt[path.Path]{ scalar.Default(path.New("~/.config/flag-overrides.yaml")), }, yamlreader.New, "path to YAML config file", flag.Alias("-c"), ), ) err := os.WriteFile( "testdata/ExampleFlagValueOptions/config.yaml", []byte(`args: slice-flag: - 1 - 2 - 3 `), 0644, ) if err != nil { log.Fatalf("write error: %e", err) } app.MustRun( warg.OverrideArgs([]string{"calc", "show", "-c", "testdata/ExampleFlagValueOptions/config.yaml", "--scalar-flag", "b"}), ) }
Output: --scalar-flag: "b" --slice-flag: []int{1, 2, 3}
func (*App) Parse2 ¶ added in v0.0.26
func (a *App) Parse2(args []string, lookupEnv LookupFunc) (*ParseResult2, error)
type AppOpt ¶
type AppOpt func(*App)
AppOpt let's you customize the app. Most AppOpts panic if incorrectly called
func ConfigFlag ¶
func ConfigFlag( configFlagName flag.Name, scalarOpts []scalar.ScalarOpt[path.Path], newConfigReader config.NewReader, helpShort flag.HelpShort, flagOpts ...flag.FlagOpt, ) AppOpt
Use ConfigFlag in conjunction with flag.ConfigPath to allow users to override flag defaults with values from a config. This flag will be parsed and any resulting config will be read before other flag value sources.
Example ¶
package main import ( "fmt" "log" "os" "go.bbkane.com/warg" "go.bbkane.com/warg/command" "go.bbkane.com/warg/config/yamlreader" "go.bbkane.com/warg/flag" "go.bbkane.com/warg/path" "go.bbkane.com/warg/section" "go.bbkane.com/warg/value/scalar" "go.bbkane.com/warg/value/slice" ) func exampleConfigFlagTextAdd(ctx command.Context) error { addends := ctx.Flags["--addend"].([]int) sum := 0 for _, a := range addends { sum += a } fmt.Printf("Sum: %d\n", sum) return nil } func main() { app := warg.New( "newAppName", "v1.0.0", section.New( "do math", section.NewCommand( command.Name("add"), "add integers", exampleConfigFlagTextAdd, command.NewFlag( flag.Name("--addend"), "Integer to add. Flag is repeatible", slice.Int(), flag.ConfigPath("add.addends"), flag.Required(), ), ), ), warg.ConfigFlag( "--config", []scalar.ScalarOpt[path.Path]{ scalar.Default(path.New("~/.config/calc.yaml")), }, yamlreader.New, "path to YAML config file", flag.Alias("-c"), ), ) err := os.WriteFile( "testdata/ExampleConfigFlag/calc.yaml", []byte(`add: addends: - 1 - 2 - 3 `), 0644, ) if err != nil { log.Fatalf("write error: %e", err) } app.MustRun( warg.OverrideArgs([]string{"calc", "add", "-c", "testdata/ExampleConfigFlag/calc.yaml"}), ) }
Output: Sum: 6
func GlobalFlag ¶ added in v0.0.24
GlobalFlag adds an existing flag to a Command. It panics if a flag with the same name exists
func GlobalFlagMap ¶ added in v0.0.28
GlobalFlagMap adds existing flags to a Command. It panics if a flag with the same name exists
func NewGlobalFlag ¶ added in v0.0.28
func NewGlobalFlag(name flag.Name, helpShort flag.HelpShort, empty value.EmptyConstructor, opts ...flag.FlagOpt) AppOpt
NewGlobalFlag adds a flag to the app. It panics if a flag with the same name exists
func OverrideHelpFlag ¶
func OverrideHelpFlag( mappings []help.HelpFlagMapping, defaultChoice string, flagName flag.Name, flagHelp flag.HelpShort, flagOpts ...flag.FlagOpt, ) AppOpt
OverrideHelpFlag customizes your --help. If you write a custom --help function, you'll want to add it to your app here!
Example ¶
package main import ( "fmt" "go.bbkane.com/warg" "go.bbkane.com/warg/command" "go.bbkane.com/warg/flag" "go.bbkane.com/warg/help" "go.bbkane.com/warg/help/common" "go.bbkane.com/warg/help/detailed" "go.bbkane.com/warg/section" ) func exampleOverrideHelpFlaglogin(_ command.Context) error { fmt.Println("Logging in") return nil } func exampleOverrideHelpFlagCustomCommandHelp(_ *command.Command, _ common.HelpInfo) command.Action { return func(ctx command.Context) error { file := ctx.Stdout fmt.Fprintln(file, "Custom command help") return nil } } func exampleOverrideHelpFlagCustomSectionHelp(_ *section.SectionT, _ common.HelpInfo) command.Action { return func(ctx command.Context) error { file := ctx.Stdout fmt.Fprintln(file, "Custom section help") return nil } } func main() { app := warg.New( "newAppName", "v1.0.0", section.New( "work with a fictional blog platform", section.NewCommand( "login", "Login to the platform", exampleOverrideHelpFlaglogin, ), ), warg.OverrideHelpFlag( []help.HelpFlagMapping{ { Name: "default", CommandHelp: detailed.DetailedCommandHelp, SectionHelp: detailed.DetailedSectionHelp, }, { Name: "custom", CommandHelp: exampleOverrideHelpFlagCustomCommandHelp, SectionHelp: exampleOverrideHelpFlagCustomSectionHelp, }, }, "default", "--help", "Print help", flag.Alias("-h"), // the flag default should match a name in the HelpFlagMapping ), ) app.MustRun(warg.OverrideArgs([]string{"blog.exe", "-h", "custom"})) }
Output: Custom section help
func SkipValidation ¶ added in v0.0.13
func SkipValidation() AppOpt
SkipValidation skips (most of) the app's internal consistency checks when the app is created. If used, make sure to call app.Validate() in a test!
type FlagValueMap ¶ added in v0.0.26
func (FlagValueMap) ToPassedFlags ¶ added in v0.0.26
func (m FlagValueMap) ToPassedFlags() command.PassedFlags
type GoldenTestArgs ¶ added in v0.0.23
type LookupFunc ¶
Look up keys (meant for environment variable parsing) - fulfillable with os.LookupEnv or warg.LookupMap(map)
func LookupMap ¶
func LookupMap(m map[string]string) LookupFunc
LookupMap loooks up keys from a provided map. Useful to mock os.LookupEnv when parsing
type ParseOpt ¶ added in v0.0.21
type ParseOpt func(*ParseOptHolder)
func AddContext ¶ added in v0.0.21
func OverrideArgs ¶ added in v0.0.21
func OverrideLookupFunc ¶ added in v0.0.21
func OverrideLookupFunc(lookup LookupFunc) ParseOpt
func OverrideStderr ¶ added in v0.0.18
func OverrideStdout ¶ added in v0.0.18
type ParseOptHolder ¶ added in v0.0.21
type ParseOptHolder struct { Args []string Context context.Context LookupFunc LookupFunc // Stderr will be passed to command.Context for user commands to print to. // This file is never closed by warg, so if setting to something other than stderr/stdout, // remember to close the file after running the command. // Useful for saving output for tests. Defaults to os.Stderr if not passed Stderr *os.File // Stdout will be passed to command.Context for user commands to print to. // This file is never closed by warg, so if setting to something other than stderr/stdout, // remember to close the file after running the command. // Useful for saving output for tests. Defaults to os.Stdout if not passed Stdout *os.File }
func NewParseOptHolder ¶ added in v0.0.21
func NewParseOptHolder(opts ...ParseOpt) ParseOptHolder
type ParseResult ¶
type ParseResult struct { Context command.Context // Action holds the passed command's action to execute. Action command.Action }
ParseResult holds the result of parsing the command line.
type ParseResult2 ¶ added in v0.0.26
type ParseResult2 struct { SectionPath []string CurrentSection *section.SectionT CurrentCommandName command.Name CurrentCommand *command.Command CurrentFlagName flag.Name CurrentFlag *flag.Flag FlagValues FlagValueMap UnsetFlagNames UnsetFlagNameSet HelpPassed bool State ParseState }
type ParseState ¶ added in v0.0.26
type ParseState string
const ( Parse_ExpectingSectionOrCommand ParseState = "Parse_ExpectingSectionOrCommand" Parse_ExpectingFlagNameOrEnd ParseState = "Parse_ExpectingFlagNameOrEnd" Parse_ExpectingFlagValue ParseState = "Parse_ExpectingFlagValue" )
type UnsetFlagNameSet ¶ added in v0.0.26
func (UnsetFlagNameSet) Add ¶ added in v0.0.26
func (u UnsetFlagNameSet) Add(name flag.Name)
func (UnsetFlagNameSet) Contains ¶ added in v0.0.26
func (u UnsetFlagNameSet) Contains(name flag.Name) bool
func (UnsetFlagNameSet) Delete ¶ added in v0.0.26
func (u UnsetFlagNameSet) Delete(name flag.Name)
Directories
¶
Path | Synopsis |
---|---|
examples
|
|
package path provides a simple wrapper around a string path that can expand the users home directory, a common CLI need.
|
package path provides a simple wrapper around a string path that can expand the users home directory, a common CLI need. |