claptrap

package module
v4.2.4 Latest Latest
Warning

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

Go to latest
Published: Oct 18, 2023 License: BSD-3-Clause Imports: 9 Imported by: 7

README

claptrap

logo

Claptrap is a small but feature-rich Go flags library. Claptrap features: getopt-ish flags; sub-commands; long and short flags; --flag=<value> syntax; invertable boolean flags; short-flag combination; variadic arguments; typed arguments/flags (int, bool, string, float, Duration); global flags; mandatory arguments; positional arguments; Levenshtein(ish) command matching; Usage text; and no external dependencies. Claptrap is a single, stand-alone Go source file.

Build statusAPI DocumentationGo Report Card

The project home is here. File bugs here. Send patches, or any other comments or questions, to ~ser/claptrap@lists.sr.ht. For help, join #claptrap:matrix.org with a (Matrix client).

Why? You'd consider this if you want POSIX getopt flags in a small (ca 500 LOC, among the smallest) and yet feature-rich library.

There are a growing number of external, optional expansions for Claptrap:

  • claphelp adds color to usage and error text
  • Claphelp also provides a command-line tool that will generate manpages from your program.
  • clapconf provides TOML config file read/write syncing to a claptrap.CommandConfig with 1 line of code.
  • clapenv adds environment variable support to claptrap

Note: Claptrap is unrelated to the args library go-clap. The first public release of Claptrap was March 29, 2020; go-clap's first commit was Apr 27, 2023. go-clap has a significantly different design, and I believe the naming is sheer coincidence. The two projects share a couple of features: like Claptrap, go-clap also has no dependencies; and go-clap also prefers double-dash long format arguments. go-clap is of the style that parses args into a struct, so if that design is your cup of tea, check it out!

Installation

claptrap is a library, and is added to your Go modules like any other:

$ go get ser1.net/claptrap/v4@latest

Usage

module ser1.net/claptest
require ser1.net/claptrap/v4 v4.1.7
go 1.16
package main

import (
  "fmt"
  "os"
  "ser1.net/claptrap/v4"
  "time"
)

func main() {

  reg := claptrap.Command("claptest", "This is the claptest")

  // Flags start with a -- for long flags, and a - for short flags. The long name must preceed the short name.
  // Boolean flags may default to true or false.
  reg.Add("--fuzzy", "-f", true, "fuzzy match flag") // A flag with a default true value
  // If no default value is provided, the argument has a boolean false default. 
  reg.Add("-v", "verbosity flag")
  // Either the long or short name may be omitted.
  reg.Add("--name", "Mr. Biggles", "your name")
  // Mandatory arguments start with a `!`. Commands may not be mandatory.
  // If the default value is an array, only the values in the array are legal values.
  reg.Add("!--count", "-c", []int{1, 2, 3}, "count flag")
  // Variadic arguments end in `...`. Variadic flags may appear anywhere, any number of times (minimum 1 if they are also mandatory).
  reg.Add("--prob...", "-p", 0.5, "probability flag")
  // time.Durations are parsed by the `time` package rules: "10s", "20m", "1h"
  reg.Add("--delay...", []time.Duration{10 * time.Second, 20 * time.Minute, time.Hour}, "duration flag")
  // Named, positional arguments consume any non-flag values. They may also be mandatory or variadic (or both), have types, and choices.
  reg.Add("commestibles...", []string{"carrots", "cabbage", "ceyanne"}, "food to eat")
  // Sub-commands are added with `AddCommand`, and may have flags, arguments, and sub-sub-commands.
  // Ad-nauseum. You're free to make as hellish a UI as you like
  reg.AddCommand("make-man", "make a manpage")
  // Any arguments added to the root command are global, and may be combined with sub-commands -- *before* the subcommand appears
  // in the arguments.

  info := reg.AddCommand("info", "the info command about information")
  info.Add("first", "the first argument")                                    // default: false
  info.Add("second", 99, "the second argument")                              // an int argument
  info.Add("third...", []string{"a", "b", "c", "d"}, "the third argument")   // any combination of these values may appear
  info.Add("--verbose", "-v", 0, "info verbosity flag")                      // this does not conflict with the root "-v" flag -- different type
  info.Add("--fuzzy", "-f", true, "fuzzilischiousity!")                      // A completely different "fuzzy", defaulting to true

  subinfo := info.AddCommand("subcommand", "a subcommand for the info command")   // Sub-commands may be nested indefinitely, guaranteeing chaos
  subinfo.Add("--verbose", "-V", []string{"quiet", "loud"}, "how verbose the subcommand is") // yet another verbosity with a different short flag and values

  help := reg.AddCommand("help", "print the help")
  help.Add("subcommand...", []string{"help", "info"}, "Get help about a subcommand")

  reg.Parse(os.Args[1:]) // exclude the command when parsing, or pass nil

  // Looping like this is probably only good if the commands are unique
  for c := reg; c != nil; c = c.Command {
    switch c.Name {
    case "make-man":
      claptrap.HelpTemplate = claptrap.ManTempl
      claptrap.Usage()
      os.Exit(0)
    case "claptest":
      fmt.Printf("%s %v\n", "commestibles", c.Strings("commestibles"))
      fmt.Printf("%s %t\n", "verbose", c.Bool("verbose"))
      fmt.Printf("%s %t\n", "fuzzy", c.Bool("fuzzy"))
      fmt.Printf("%s %+v\n", "count", c.Ints("count"))
      fmt.Printf("%s %+v\n", "prob", c.Floats("prob"))
      fmt.Printf("%s %+v\n", "delay", c.Durations("delay"))
    case "info":
      fmt.Printf("info: %s %t\n", "first", c.Bool("first"))
      fmt.Printf("info: %s %+v\n", "second", c.Int("second"))
      fmt.Printf("info: %s %+v\n", "third", c.Strings("third"))
      fmt.Printf("info: %s %d\n", "verbose", c.Int("verbose"))
      fmt.Printf("info: %s %t\n", "fuzzy", c.Bool("fuzzy"))
    case "subcommand":
      fmt.Printf("Heeeyaw, subcommand, with verbose %q\n", c.String("verbose"))
    case "help":
	    claptrap.Usage()
	    os.Exit(0)
    }
  }
}

Flags and arguments are added with Add(). The format of the command is:

   Add( <name>           // string, mandatory argument.
        <shortname>,     // string, optional.
        <default value>, // optional. If not provided, defaults to boolean false
        <description>    // textual description of command, mandatory
      )

The format of <name> determines characteristics of the argument. If <name>

  • starts with !, then the argument is mandatory. The parser will error out if the argument is missing,
  • ends with ..., then the argument is variadic, and may occur many times,
  • starts with -- (after !), then the argument is a long flag,
  • starts with - (after !), then the argument is a short flag (single character)
  • has no dashes, then it is a positional argument

The default value, if provided, may be a string, int, float64, bool, or time.Duration. The default type of arguments are strings, and the default types of flags are bools; this is validated by the Parse() function. The default value may also be an array of any of these types, in which case the argument is a choice -- users may provide any of the arguments in the array, and no others. The default value for choices is the first choice.

Rules

There are commands, flags, and args. A parse scope is created with claptrap.Command().

Commands

Commands are specified without dashes, and are like flag sets: each command can have its own set of flags and args. The top-level command is registered with the claptrap.Command() function; subcommands with the CommandConfig.AddCommand() method. Commands usually have a name, but there is a special root command specified by the empty string; args and flags created on this root command don't require a command.

The parser will match abbreviated strings to commands, so "lis", "ls", and "l" will match "list", as long as it is a unique match. If both "less" and "list" are registered, the user could supply "lss", "le", or "lt" for example; "ls" is ambiguous and would be a parse error.

Args

Args are placeholders for non-flagged arguments, and are created with CommandConfig.Add(); they consume variables in the order they're created. The very last Arg created (on a command) can be variadic, which means it consumes all of the remaining arguments.

Arg names are just that: references to use in your program. They do not appear in the command line. If a varargs argument is not provided, then input is restricted to no more than the number of positional arguments.

See the example code for more info.

If a varargs argument appears (an argument with "..." at the end of the name), then it gets any other input; note there can be at most one vararg argument, while there can be many vararg flags.

Arguments are optional by default, but can be made mandatory by prefixing the name with !.

Note that this has the effect of also making any previous arguments also mandatory, because claptrap fills arguments in order.

claptrap supports strong typing; types are derived from the default value.

Choices are also supported. Choices limit the allowed arguments, and are set by passing an array of the choices to default value parameter of Add(). Choices with all types except bools: booleans are always only ever true or false, and boolean arguments can not be variadic. With the exception of booleans, all of these features can be combined.

See the documentation examples for a complete list of the rules in action.

Values are retrieved using one of the type getters. If the wrong type is retrieved, an empty array is provided. If the argument was not provided by the user, the default is provided. An argument can be tested whether it is a default, or was provided by the user, with the Arg.IsSet() function. Getters are available for both single values and vararg arrays. The convenience functions get the first value of any argument; if the argument type is different than what is asked for, then the zero-value for that type is returned.

Durations can be any string parsable by Go time.ParseDuration().

Flags

Flags are prefixed with dashes. Flags can have long and short forms; like getopt, long forms are specified with a double-dash -- and short forms with a single dash -. With a couple of exceptions, Flags follow all the rules and features of arguments: mandatory, variadic, defaults, choices, and types.

  • All flags may be variadic, not only the last.
  • Mandatory and variadic syntax is specified on the long form (the first argument to Add()).
  • Boolean flags take no arguments. If they're supplied, they're true; if they are not supplied, they get the default.
  • Boolean long Flags automatically get a no- version that returns false if supplied.
package main
import "ser1.net/claptrap/v4"
import "fmt"
func main() {
  rt := claptrap.Command("flags", "demonstrating arguments (vs args)")
	rt.Add("!--required", "-r", "this is a very silly flag")
	rt.Add("--choice", []string{"connor", "kurgen"}, "there can be only one")
	rt.Add("--poke...", "", "there can be many")
	rt.Add("--semi...", "-s", "", "there can be many more")
	rt.Add("--true", "-t", true, "boolean defaults only matter if they're not provided")
	sc := rt.AddCommand("sub", "this is a sub-command")
	sc.Add("--choice", []string{"go", "rust", "c"}, "ha ha! No way this could be confusing!")
	rt.Parse(nil) // If you pass nil to Parse, os.Args[1:] are used
	for _, k := range []string{"choice", "poke", "semi", "true"} {
	  fmt.Printf("%s: %v\n", k, rt.Args[k].Value)
	}
	if rt.Command != nil && rt.Command.Name == "sub" {
		fmt.Printf("sub choice: %s\n", rt.Command.String("choice"))
	}
}

Important


Root arguments and flags are global: they can be provided on the command line before other arguments. However, if the root command has any arguments, they will consume commands before the commands are identified.

If args and flags are created with the same name, the one that's added last is the one that wins.

Shell completion

There is an autocompletion function in assets/clapcomplete.sh. Currently, as my autocomplete-fu is rather basic, it only completes the first word. It depends on jq, as well. To use it:

$ source assets/clapcomplete.sh
$ complete -F _clapcomplete_ <yourprogram>

I will happily accept patches to improve the autocompletion.

Best practices

UIs that have subcommands should limit themselves to using Flags and not Args in the parent command. It'll work, but it's easy to get unexpected results. For example, what would you expect to happen here?

	root := Command("","")
	root.Add("arg1", []string{"info", "man"}, "first argument")
	info := root.AddCommand("info", "more information")

What should happen? I can tell you what will happen, but it's confusing for everyone and could change in the future, so it's best avoided. It gets worse with command matching; consider:

	root := Command("","")
	root.Add("arg1", "first argument")
	info := root.AddCommand("category", "the category of the thing")
	root.Parse([]string{"cat"})

There isn't much logic trying to make this work a particular way, because no matter what, it's going to be unexpected for somebody. It is far more clear to simply avoid mixing Arguments and Commands, except in commands which do not have subcommands.

Args and flags should not have the same names; this is merely because of an implementation decision to simplify the code, rather than adding extra code to separate things out.

For shorthand commands ("ls" for "list"), the first letter must match, and the match must be unique. For example:

  • list, less -- ls bad, it matches both
  • config, configs -- config good, it matches both, but one is an exact match
  • list, config, help -- l, c, h good, completely unambiguous

But -- again -- if you have arguments defined claptrap will choose commands over arguments. Keep this in mind when creating your UI.

Convenience Rules

The convenience functions return a single argument of the requested type; what gets returned is based on these rules:

  1. If an argument(/flag) is not found found; or if the found item is not the correct type; or the default is a choice; then the default value of the type requested is returned.
  2. If the value is variadic, the first element of the user values is returned. It's best to not use the convenience functions with variadic args, because you throw away user input.

If you need to inspect the argument, acces them by name with CommandConfig.Args[]; with the result, you can check Arg.IsSet() to see if the user provided a value, or if you're getting a default (among other things, but this is probably the most useful).

Help Text

claptrap generates help text output; it looks like this:

USAGE: claptest [args] [commands]
 This is the claptest
 Commands:
   help                              print the help
   info                              the info command about information
   make-man                          make a manpage

 Arguments:
   commestibles     <string>...      food to eat  ([carrots cabbage ceyanne])

 Flags:
   --count / -c     <int>            count flag  (![1 2 3])
   --delay / -      <Duration>...    duration flag  ([10s 20m0s 1h0m0s])
   --fuzzy / -f                      fuzzy match flag  (true)
   --name / -       <string>         your name  (Mr. Biggles)
   --prob / -p      <float64>...     probability flag  (0.5)
   -- / -v                           verbosity flag  (false)

help [args]
 print the help
 Commands:

 Arguments:
   subcommand       <string>...      Get help about a subcommand  ([help info])

 Flags:

You can replace the Usage function with your own. The default usage function uses templates, so you can also write your own templates and use the default function. Again, see the API documentation example.

claptrap responds to a super-secret environment variable, CLAPTRAP_USAGE_JSON. If set (to any value), claptrap's Usage function will dump the configuration as a JSON document. This document can be fed to the other tools (such as claphelp) to, e.g., generate man pages.

Credits

This library was based initially on clapper; it adds several features missing from clapper, but the main reason for the fork was that the several behaviors were changed in ways that differ fundamentally with how clapper treats arguments.

Features

Briefly:

  • Positional (named) arguments: myprog server.com server.net could be parsed into from and to args
  • Subcommands: myprog tcp connect myhost.net, myprog tcp list, myprog tcp scan bing.com
  • getopt-like long and short flag names, and = syntax: --count 5, -c 5, --count=5
  • Automatic boolean flag inversion: --clean gives you also --no-clean
  • Short-flag combination: -c -v -p == -cvp
  • Variadic arguments: -a 1 -a 2 -a 3
  • Typed arguments/flags, supporting int, bool, string, float, & Duration
  • Global flags: myprog -v tcp list -a, -v would be global, -a is a flag on the list command
  • Mandatory arguments: flags and arguments can be made mandatory
  • Command matching: list will be matched by ls and lt, if they the match is unique
  • Easy Usage templating and overriding
  • No external dependencies
  • Ca 500 LOC in a single, stand-alone claptrap.go file. You could vendor it by copying the file into your project, change the package name, and go, change the package name, and go.

Tools built with the Claptrap have an opts interface that is familiar to largest population of command-line users in the world: POSIX getop. Claptrap provides a fair amount of user input validation: variadics, mandatory, and argument types.

Claptrap strives to remain light, while providing these features. The most popular Go flags libraries are large, either themselves or through their dependencies; Claptrap has 0 non-stdlib dependencies.

lib short long combined inverted env vars types choices commands varargs mand/opt files usage
claptrap Y Y Y Y N Y Y Y Y Y N Y
go-clap Y Y Y N N Y ? N Y Y N Y
clapper Y Y N Y N N N Y Y N N
droundy Y Y Y N Y Y N Y
sircmpwn Y N Y N N N N N Y Y N Y
opflag Y Y Y N N Y N N Y N N Y
namsral Y Y Y Y Y Y Y
integrii Y Y y Y Y Y Y
jessevdk Y Y Y N N Y Y Y Y Y N Y
  • short means getopt short-form syntax, e.g. "-x"
  • long means getopt long-form syntax, e.g. "--long"
  • combined means that arguments may have both long and short forms
  • inverted means automatic support for inverted boolean arguments, e.g. "--true" gives you "--no-true"
  • env vars is support for parsing environment variables into parameters, e.g. "--var" gets the value of "$PROG_VAR" (or similar)
  • types is support for typed arguments, beyond boolean and strings
  • choices is whether the library supports limited values, e.g. a paramenter "--type=" allowing only "file" and "dir" as legal arguments
  • commands are dash-less subsets, such as "backup" in the command "restic backup". Implicit here is that the tool allows flags to have distinct settings per command
  • varargs is when users can provide flags multiple times, e.g. "command --val one --val two" provides ["one", "two"]
  • mand/opt is whether the library allows setting flags as mandatory (the user must provide it) or optional (the user may provide it)
  • files is whether flags can be loaded from a configuration file
  • usage is library-generated help-text

claptrap supports the following data types:

  • bool
  • string
  • int
  • float64
  • time.Duration

Some features are provided through external add-ons; for example, clapenv adds environment variable support to claptrap, for 12-factor apps; and clapconf provides TOML config file parsing into flags.

The following size table is sorted by ABC[^1].

Library LOC Deps ABC Score Complexity
clapper 303 0 119 76
cosiner-argv 462 0 155 94
go-clap 326 0 176 104
droundy-goopt 596 0 243 162
claptrap 487 0 251 176
namsral-flag 764 0 299 162
ogier-pflag 1112 0 438 97
opflag 1161 0 461 118
integrii-flaggy 1732 0 659 303
spf13-pflag 3856 0 1464 583
jessevdk-go-flags 3529 0 1604 1045
dmulholland-args 437 1 199 97
thatisuday-commando 640 1 213 110
mwitkow-go-flagz 1461 1 487 265
cosiner-flag 1821 1 713 463
sircmpwn-getopt 501 2 154 60
moogar0880-venom 2029 2 604 303
stevenroose-gonfig 1169 4 540 375
peterbourgon-ff 1060 5 308 231
cobra 4529 5 1507 808
dc0d-argify 348 12 139 96

LOC -- no tests, no comments scc -i go -M _test --no-cocomo
ABC Score -- ABC complexity for the project (excluding dependencies) abcgo -format summary -path . -no-test

  • Man page generation, but as a separate program Man pages can be generated by a tool in the claphelp project.

Inspiration for some parts of the Claptrap ecosystem came from working with several of the other flags libraries, as well as:

As I mention above, if you prefer the parse-into-struct model, at the moment I'd recommend looking at go-clap, which is lightweight, also has no dependencies, and supports sane flag syntax.

Elevator Pitch (toot-sized)

claptrap opts lib: very small, much features, getoptish https://sr.ht/~ser/claptrap/

  • getopt long & short flags (--bool, -b)
  • combined short (-b -e == -be)
  • inverted bools (--bool => --no-bool)
  • typed params (int, bool, Duration, string, float)
  • mandatory flags and arguments
  • positional arguments
  • global flags
  • subcommands
  • variadic flags (-a 1 -a 2 -a 3)
  • partial command matching (list =~ ls)
  • usage()

And it's under 500 lines of code, and 0 dependencies.

[^1] ABC is a better prediction of the amount of binary size a library will add to any give program using it, so I'm no longer sorting by LOC; striving for low LOC is a perverse incentive, when what we really should be striving for is simplicity and weight. Claptrap code isn't simple; it uses introspection quite a bit, and introspection is almost never easy to reason about. It does keep the end user API more simple, and Go's (new-ish) Generic system wouldn't help here because of the restriction on type parameters. Claptrap cheats on the LOC metric, as there's a fair bit of logic in the text and manpage Usage templates, and code in text/template isn't counted by LOC tools. With that code, it's closer to 560 LOC with the help text.

Documentation

Overview

Package claptrap processes the command-line arguments of getopt(3) syntax. claptrap has built-in support for sub-commands; long and short flag name combination (`--version`, `-v`); `--flag=<value>` syntax; automatic invertable boolean flags (`--clean` => `--no-clean`); short-flag combination (`-c -v -p` = `-cvp`); variadic arguments; typed arguments/flags (int, bool, string, float, Duration); global flags; mandatory arguments; positional arguments; command matching (`ls` = `list`); subcommands (`cmd help topic`); `Usage` *and* manpage generation; -- and **no external dependencies**. Vendoring is as easy as copying this file into your project and changing the package name.

Index

Examples

Constants

This section is empty.

Variables

View Source
var HandleErrors func(int, []error) = func(exitCode int, errors []error) {
	for _, e := range errors {
		fmt.Fprintf(os.Stderr, "%s\n", e)
	}
	os.Exit(exitCode)
}

Override this if you want to handle parse errors on your own.

View Source
var HelpTemplate string = strings.Join([]string{`{{ define "defaults" }}  ({{ if .IsMandatory }}!{{ end }}{{ .DefaultValue }}){{ end }}`, `{{ define "command" }}{{ $command := . }}{{ .Name }}{{ if .Args }} [args]{{ end }}{{ if .Commands }} [commands]{{ end }}`, `  {{ .Description }}{{ $padname := 17 }}{{ $padtype := 17 }}{{ $longpad := 34 }}`, `  Commands:`, `{{ range .Commands }}    {{ PadOut $longpad .Name }}{{ .Description }}`, `{{ end }}`, `  Arguments:`, `{{ range .ArgNames }}{{ with (index $command.Args .) }}    {{ PadOut $padname .Name  }}{{ if .IsVariadic  }}{{ PadOut $padtype (printf "<%s>..." .Type)  }}{{ else  }}{{ PadOut $padtype (printf "<%s>   " .Type)  }}{{ .Description }}{{if .Options }} {{.Options}}{{end}}{{ template "defaults" . }}`, `{{ end }}{{ end }}{{ end }}`, `  Flags:`, `{{ range .Args }}{{ if .IsFlag }}    {{ $name := (printf "-%s" .ShortName) }}{{ if (and .Name (not .ShortName)) }}{{ $name = (printf "--%s" .Name) }}{{ else if .Name }}{{ $name = (printf "--%s / -%s" .Name .ShortName) }}{{ end }}{{ PadOut $padname $name }}{{ if (not (eq .Type "bool")) }}{{ if .IsVariadic }}{{ PadOut $padtype (printf "<%s>..." .Type) }}{{ else }}{{ PadOut $padtype (printf "<%s>   " .Type) }}{{ end }}{{ else }}{{ PadOut $padtype "" }}{{ end }}{{ .Description }}{{if .Options }} {{.Options}}{{end}}{{ template "defaults" . }}{{ if (and (eq .Type "bool") .Name)}}`, `    {{ PadOut $padname (printf "--no-%s" .Name)}}{{ PadOut $padtype ""}}{{ .Description}} (false){{ end}}`, `{{ end }}{{ end }}{{ end }}USAGE: {{ template "command" . }}`}, "\n")

Set this to ManTempl to generate man pages, or to your own template

View Source
var Usage func() = func() {

	t := template.New("help")
	t.Funcs(template.FuncMap{"PadOut": func(i int, v string) string {
		v = strings.ReplaceAll(strings.ReplaceAll(v, "[]", ""), "time.", "")
		if len(v) > i {
			i = len(v)
		}
		return v + strings.Repeat(" ", i-len(v))
	}})
	if mp, err := t.Parse(HelpTemplate); err != nil {
		panic(err)
	} else {
		if err := mp.Execute(os.Stdout, RootCommand); err != nil {
			panic(err)
		}
	}
}

Usage prints usage information for the flag set. To print usage for a subcommand, set the RootCommand to the command to be printed and call Usage.

Functions

This section is empty.

Types

type Arg

type Arg struct {
	// name of the argument
	Name        string
	ShortName   string
	IsVariadic  bool
	IsMandatory bool
	// Options is either nil, or a slice of type DefaultValue
	Options interface{}
	// DefaultValue is never nil, and it determines the type of Arg's value
	DefaultValue interface{}
	// Value is always either nil, or a slice of type DefaultValue
	Value       interface{}
	Description string
	IsFlag      bool
	// Type is the Go string representation of the type, minus the package. I.e., time.Duration is "Duration"
	Type string
}

Arg holds the structured information about an argument.

func (Arg) IsSet

func (a Arg) IsSet() bool

IsSet returns true if the Argument was provided with a value in the Parsed data.

func (*Arg) Set added in v4.1.7

func (arg *Arg) Set(unparsedValue string) (err error)

Set parses the supplied unparsedValue into the correct type and sets the value of the arg. If the unparsedValue is not convertable to the right type, then Set returns an error.

type CommandConfig

type CommandConfig struct {
	// name of the sub-command ("" for the root command)
	Name string
	// Defined subcommands
	Commands map[string]*CommandConfig
	// The parsed subcommand, if any
	Command *CommandConfig

	// registered command argument values
	Args map[string]*Arg
	// list of the argument names (for ordered iteration)
	ArgNames    []string
	Description string
	// contains filtered or unexported fields
}

CommandConfig type holds the structure and values of the command-line arguments of command.

var RootCommand *CommandConfig

RootCommand is the first command, if any. It will be nil if no command was parsed.

func Command

func Command(name, description string) *CommandConfig

Command creates the root command for the program. Usually, it will be called with os.Args[0] for the first argument.

func (*CommandConfig) Add

func (commandConfig *CommandConfig) Add(name string, params ...interface{}) *Arg

Add adds a named (positional) argument, or a flag. it requires a minimum of two arguments: a name and description. For flags, a second argument can be added for the short flag, and for all, the default value can be provided. If no default value is provided, then arguments are default strings and flags are default bools. Flags are specified with double dashes with long names; short flags are single dash and a single character.

The order of arguments must be:

If a flag, then <[LONGNAME] [SHORTNAME]> [DEFAULT-OR-CHOICE] <DESCRIPTION>

If an argument, then: <NAME> [DEFAULT] <DESCRIPTION>

Named (positional) arguments do not have short names. The `shortName` argument should be a single character after the dash.

Arguments can be made mandatory with a ! prefix in the name. Because named arguments (non-flags) are consumed in order, this has the effect of making _all_ arguments before the mandatory argument required. Mandatory flags can appear in any order.

Variadic arguments can be created by appending "..." to the end of the name (the first argument). Only one amed (positional) argument may be variadic; any number of variadic flags can be created.

Arguments are strongly typed. The type of an argument is derived from the default value. The supported type

  • int
  • string
  • float64
  • bool
  • time.Duration

If the provided defaultValue is an array of one of the above types, then that array defines a set of legal values; any provided parameter that doesn't match a value in the array will result in a parse error.

Boolean arguments differ from other types in that boolean Args may *not* be variadic, and will produce an error. Boolean Args may not have array defaults; the options are always `true` and `false`. Boolean flags also do not take arguments: they are merely provided, or not. Boolean flags with long names automatically get a `no-<longname>` option, which if provided, returns `false' for the flag. Regardless of the default, boolean flags are true if provided, and false if inverted.

On the command line, Flags are prefixed with dashes. With the exceptions above, Flags follow all the rules and features of arguments: mandatory, variadic, defaults, choices, and types.

Example (Arguments)
rt := Command("args", "demonstrating arguments (vs flags)")
rt.Add("first", "firstDefault", "the first argument")
rt.Add("second", "secondDefault", "the second argument")
rt.Add("rest...", "", "the rest of the arguments")
rt.Parse([]string{"alpha", "bravo", "charlie", "delta", "echo", "foxtrot", "gamma"})
fmt.Printf("%s, %s, %+v\n", rt.String("first"), rt.String("second"), rt.Strings("rest"))
Output:

alpha, bravo, [charlie delta echo foxtrot gamma]
Example (Autono)
rt := Command("args", "demonstrating arguments (vs flags)")
rt.Add("--flag", true, "a bool flag with a true default")
rt.Parse([]string{"--no-flag"})
fmt.Printf("%t\n", rt.Bool(""))
// Output false
Output:

Example (Variations)
rt := Command("args", "demonstrating arguments (vs flags)")
rt.Add("namedarg", "a string argument")
rt.Add("--longname", "a bool long-name flag")
rt.Add("-s", "a bool short-name flag")
rt.Add("boolarg", false, "a boolean argument")
rt.Add("--string", "default", "a string flag")
rt.Add("-i", 10, "an int short flag")
rt.Add("--time", "-t", 5*time.Minute, "a Duration flag with short and long names")
rt.Add("--options", "-o", []string{"one", "of", "these"}, "a string flag with limited legal values")
rt.Add("!--mandatory", 0.0, "a mandatory float flag")
rt.Add("-m...", "", "a variadic flag")
rt.Add("remainder...", "all of the rest of the arguments, if any")
rt.Parse([]string{"--mandatory", "6.2831853070"})
fmt.Printf("%f %s\n", rt.Float("mandatory"), rt.Duration("time"))
// Output 6.283185 5m0s
Output:

func (*CommandConfig) AddCommand

func (c *CommandConfig) AddCommand(name, description string) *CommandConfig

AddCommand creates a command. If the command name is an empty string, the command created is the root command. Commands may have zero or more subcommands. Commands have their own, distinct sets of flags, arguments, and commands.

Example
rt := Command("jabberwocky", "a poem")
rt.Add("-v", true, "a bool flag that defaults to true")
m := rt.AddCommand("mome", "word one")
m.Add("-v", -1, "an int flag")
r := m.AddCommand("raths", "word two")
r.Add("-v", "dflt", "a string flag")
o := r.AddCommand("outgrabe", "word three")
o.Add("-v", "another, different, bool flag")
m.Parse([]string{"mome", "rath", "-v", "6", "outgrabe"})
fmt.Printf("(%t), %s(%d), %s(%q), %s(%t)",
	rt.Command.Bool("v"),
	rt.Command.Name, rt.Command.Int("v"),
	rt.Command.Name, rt.Command.String("v"),
	rt.Command.Name, rt.Command.Bool("v"))
// Output true, mome(true), rath(6), outgrabe(false)
Output:

func (CommandConfig) Bool

func (c CommandConfig) Bool(n string) bool

Bool finds a set Arg or Flag by name and returns its first value, or the value of the default, as an bool. See documentation for Int() for the rules

Example
rt := Command("args", "demonstrating booleans")
rt.Add("--correct", "correct type")
rt.Add("--incorrect", 4, "correct type")
rt.Add("--default", true, "default values")
rt.Parse([]string{"--correct"})
fmt.Printf("%t %t %t", rt.Bool("correct"), rt.Bool("incorrect"), rt.Bool("default"))
Output:

true false true

func (CommandConfig) Duration

func (c CommandConfig) Duration(n string) time.Duration

Duration finds a set Arg or Flag by name and returns its first value, or the value of the default, as an duration. See documentation for Int() for the rules

Example
rt := Command("args", "demonstrating booleans")
rt.Add("--time", time.Second, "correct type")
rt.Parse([]string{"--time", "5h"})
fmt.Printf("%s\n", rt.Duration("time"))
Output:

5h0m0s

func (CommandConfig) Durations added in v4.1.0

func (c CommandConfig) Durations(n string) []time.Duration

Durations returns the Arg value as an array of type duration, or the defaults if no argument was given. It returns an empty array if the Arg was declared as a different type.

Example
rt := Command("args", "demonstrating booleans")
rt.Add("--time", time.Second, "correct type")
rt.Add("--times...", time.Second, "correct type")
rt.Parse([]string{"--time", "5h", "--times", "1s", "--times", "2m"})
fmt.Printf("%s %v\n", rt.Duration("time"), rt.Durations("times"))
Output:

5h0m0s [1s 2m0s]

func (CommandConfig) Float

func (c CommandConfig) Float(n string) float64

Float finds a set Arg or Flag by name and returns its first value, or the value of the default, as an float. See documentation for Int() for the rules

func (CommandConfig) Floats added in v4.1.0

func (c CommandConfig) Floats(n string) []float64

Floats returns the Arg value as an array of type float, or the defaults if no argument was given. It returns an empty array if the Arg was declared as a different type.

func (CommandConfig) Int

func (c CommandConfig) Int(n string) int

Ints finds a set Arg or Flag by name and returns its first value, or the value of the default, as an int.

func (CommandConfig) Ints added in v4.1.0

func (c CommandConfig) Ints(n string) []int

Ints returns the Arg value as an array of type int, or the defaults if no argument was given. It returns an empty array if the Arg was declared as a different type.

func (*CommandConfig) Parse

func (c *CommandConfig) Parse(values []string)

Parse parses an array of arguments and returns a command object, or an error if any of the parameter validations fail. If no root command is registered, the first array item must be a registered command.

See the rules for `AddArg()` and `AddFlag()` for specific parse rules.

Example (ExitWithError)
HandleErrors = func(i int, es []error) {
	for _, e := range es {
		fmt.Println(e)
	}
}
rt := Command("args", "demonstrating arguments (vs flags)")
rt.Add("first", "firstDefault", "the first argument")
rt.Add("!second", "secondDefault", "the second argument")
rt.Parse([]string{"alpha"})
Output:

args -- missing mandatory option: second /
Example (Mandatory)
HandleErrors = func(i int, es []error) {
	for _, e := range es {
		fmt.Println(e)
	}
}
rt := Command("args", "demonstrating arguments (vs flags)")
rt.Add("first", "firstDefault", "the first argument")
rt.Add("!second", "secondDefault", "the second argument")
rt.Parse([]string{"alpha", "beta"})
fmt.Printf("%s, %s\n", rt.String("first"), rt.String("second"))
Output:

alpha, beta
Example (Usage)
HelpTemplate = "I am {{.Name}}, and I have {{len .Commands}} subcommand and {{len .Args}} args"
rt := Command("args", "demonstrating booleans")
rt.Add("name", "your name")
rt.Add("age", 21, "your age")
rt.AddCommand("help", "show the usage")
Usage()
fmt.Println()
// Output I am args, and I have 1 subcommand and 2 args
Output:

Example (ValidateArgs)
HandleErrors = func(i int, es []error) {
	for _, e := range es {
		fmt.Println(e)
	}
}
rt := Command("args", "demonstrating arguments (vs flags)")
rt.Add("first", "firstDefault", "the first argument")
rt.Add("second", "secondDefault", "the second argument")
rt.Parse([]string{"alpha", "bravo", "charlie", "delta", "echo", "foxtrot", "gamma"})
Output:

got more parameters than defined arguments: charlie

func (CommandConfig) String

func (c CommandConfig) String(n string) string

String finds a set Arg or Flag by name and returns its first value, or the value of the default, as an string. See documentation for Int() for the rules

func (CommandConfig) Strings added in v4.1.0

func (c CommandConfig) Strings(n string) []string

Strings returns the Arg value as an array of type string, or the defaults if no argument was given. It returns an empty array if the Arg was declared as a different type.

Jump to

Keyboard shortcuts

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