cli

package module
v0.0.0-...-bdeb6c6 Latest Latest
Warning

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

Go to latest
Published: Jun 26, 2017 License: MIT Imports: 9 Imported by: 116

README

mow.cli

Build Status GoDoc

A framework to build command line applications in Go with most of the burden of arguments parsing and validation placed on the framework instead of the developer.

Motivation

mow.cli codegangsta/cli flag
Contextual help
Commands
Option folding -xyz
Option Value folding -fValue
Option exclusion: --start ❘ --stop
Option dependency : [-a -b] or [-a [-b]]
Arguments validation : SRC DST
Argument optionality : SRC [DST]
Argument repetition : SRC... DST
Option/Argument dependency : SRC [-f DST]
Any combination of the above: [-d ❘ --rm] IMAGE [COMMAND [ARG...]]

In the goland, docopt is another library with rich flags and arguments validation. However, it falls short for many use cases:

mow.cli docopt
Contextual help
Backtracking: SRC... DST
Backtracking: [SRC] DST
Branching: (SRC ❘ -f DST)

Installation

To install this library, simply run:

$ go get github.com/jawher/mow.cli

First app

Here's a sample showcasing many features of mow.cli: flags, arguments, and spec string:

package main

import (
    "fmt"
    "os"

    "github.com/jawher/mow.cli"
)

func main() {
    app := cli.App("cp", "Copy files around")

    app.Spec = "[-r] SRC... DST"

    var (
        recursive = app.BoolOpt("r recursive", false, "Copy files recursively")
        src       = app.StringsArg("SRC", nil, "Source files to copy")
        dst       = app.StringArg("DST", "", "Destination where to copy files to")
    )

    app.Action = func() {
        fmt.Printf("Copying %v to %s [recursively: %v]\n", *src, *dst, *recursive)
    }

    app.Run(os.Args)
}

Basics

You start by creating an application by passing a name and a description:

cp := cli.App("cp", "Copy files around")

To attach the code to execute when the app is launched, assign a function to the Action field:

cp.Action = func() {
    fmt.Printf("Hello world\n")
}

If you want you can add support for printing the app version (invoked by -v, --version) like so:

cp.Version("v version", "cp 1.2.3")

Finally, in your main func, call Run on the app:

cp.Run(os.Args)

Options

To add a (global) option, call one of the (String[s]|Int[s]|Bool)Opt methods on the app:

recursive := cp.BoolOpt("R recursive", false, "recursively copy the src to dst")
  • The first argument is a space separated list of names for the option without the dashes
  • The second parameter is the default value for the option
  • The third and last parameter is the option description, as will be shown in the help messages

There is also a second set of methods Bool, String, Int, Strings and Ints, which accepts structs describing the option:

recursive = cp.Bool(BoolOpt{
    Name:  "R recursive",
    Value: false,
    Desc:  "copy src files recursively",
    EnvVar: "VAR1 VAR2",
    SetByUser: &srcSetByUser,
})

The field names are self-describing.

EnvVar accepts a space separated list of environment variables names to be used to initialize the option.

If SetByUser is specified (by passing a pointer to a bool variable), it will be set to true if the user explicitly set the option.

The result is a pointer to a value that will be populated after parsing the command line arguments. You can access the values in the Action func.

In the command line, mow.cli accepts the following syntaxes

For boolean options:
  • -f : a single dash for the one letter names
  • -f=false : a single dash for the one letter names, equal sign followed by true or false
  • --force : double dash for longer option names
  • -it : mow.cli supports option folding, this is equivalent to: -i -t
For string, int options:
  • -e=value : single dash for one letter names, equal sign followed by the value
  • -e value : single dash for one letter names, space followed by the value
  • -Ivalue : single dash for one letter names immediately followed by the value
  • --extra=value : double dash for longer option names, equal sign followed by the value
  • --extra value : double dash for longer option names, space followed by the value
For slice options (StringsOpt, IntsOpt):

repeat the option to accumulate the values in the resulting slice:

  • -e PATH:/bin -e PATH:/usr/bin : resulting slice contains ["/bin", "/usr/bin"]
  • -ePATH:/bin -ePATH:/usr/bin : resulting slice contains ["/bin", "/usr/bin"]
  • -e=PATH:/bin -e=PATH:/usr/bin : resulting slice contains ["/bin", "/usr/bin"]
  • --env PATH:/bin --env PATH:/usr/bin : resulting slice contains ["/bin", "/usr/bin"]
  • --env=PATH:/bin --env=PATH:/usr/bin : resulting slice contains ["/bin", "/usr/bin"]

Arguments

To accept arguments, you need to explicitly declare them by calling one of the (String[s]|Int[s]|Bool)Arg methods on the app:

src := cp.StringArg("SRC", "", "the file to copy")
dst := cp.StringArg("DST", "", "the destination")
  • The first argument is the argument name as will be shown in the help messages
  • The second parameter is the default value for the argument
  • The third parameter is the argument description, as will be shown in the help messages

There is also a second set of methods Bool, String, Int, Strings and Ints, which accepts structs describing the argument:

src = cp.Strings(StringsArg{
    Name:  "SRC",
    Desc:  "The source files to copy",
    Value: "default value",
    EnvVar: "VAR1 VAR2",
    SetByUser: &srcSetByUser,
})

The field names are self-describing. The Value field is where you can set the initial value for the argument.

EnvVar accepts a space separated list of environment variables names to be used to initialize the argument.

If SetByUser is specified (by passing a pointer to a bool variable), it will be set to true if the user explicitly set the argument.

The result is a pointer to a value that will be populated after parsing the command line arguments. You can access the values in the Action func.

You can also

Operators

The -- operator marks the end of options. Everything that follow will be treated as an argument, even if starts with a dash.

For example, given the touch command which takes a filename as an argument (and possibly other options):

file := cp.StringArg("FILE", "", "the file to create")

If we try to create a file named -f this way:

touch -f

Would fail, because -f will be parsed as an option not as an argument. The fix is to prefix the filename with the -- operator:

touch -- -f

Commands

mow.cli supports nesting commands and sub commands. Declare a top level command by calling the Command func on the app struct, and a sub command by calling the Command func on the command struct:

docker := cli.App("docker", "A self-sufficient runtime for linux containers")

docker.Command("run", "Run a command in a new container", func(cmd *cli.Cmd) {
    // initialize the run command here
})
  • The first argument is the command name, as will be shown in the help messages and as will need to be input by the user in the command line to call the command
  • The second argument is the command description as will be shown in the help messages
  • The third argument is a CmdInitializer, a function that receives a pointer to a Cmd struct representing the command. In this function, you can add options and arguments by calling the same methods as you would with an app struct (BoolOpt, StringArg, ...). You would also assign a function to the Action field of the Cmd struct for it to be executed when the command is invoked.
docker.Command("run", "Run a command in a new container", func(cmd *cli.Cmd) {
    detached := cmd.BoolOpt("d detach", false, "Detached mode: run the container in the background and print the new container ID", nil)
    memory := cmd.StringOpt("m memory", "", "Memory limit (format: <number><optional unit>, where unit = b, k, m or g)", nil)

    image := cmd.StringArg("IMAGE", "", "", nil)

    cmd.Action = func() {
        if *detached {
            //do something
        }
        runContainer(*image, *detached, *memory)
    }
})

You can also add sub commands by calling Command on the Cmd struct:

bzk.Command("job", "actions on jobs", func(cmd *cli.Cmd) {
    cmd.Command("list", "list jobs", listJobs)
    cmd.Command("start", "start a new job", startJob)
    cmd.Command("log", "show a job log", nil)
})

When you just want to set Action to cmd, you can use ActionCommand function for this

app.Command("list", "list all configs", cli.ActionCommand(func() { list() }))

is the same as

app.Command("list", "list all configs", func(cmd *cli.Cmd)) {
    cmd.Action = func() {
      list()
    }
}

This could go on to any depth if need be.

As a side-note: it may seem a bit weird the way mow.cli uses a function to initialize a command instead of just returning the command struct.

The motivation behind this choice is scoping: as with the standard flag package, adding an option or an argument returns a pointer to a value which will be populated when the app is run.

Since you'll want to store these pointers in variables, and to avoid having dozens of them in the same scope (the main func for example or as global variables), mow.cli's API was specifically tailored to take a func parameter (called CmdInitializer) which accepts the command struct.

This way, the command specific variables scope is limited to this function.

Custom types

Out of the box, mow.cli supports the following types for options and arguments:

  • bool
  • string
  • int
  • strings (slice of strings)
  • ints (slice of ints)

You can however extend mow.cli to handle other types, e.g. time.Duration, float64, or even your own struct types for example.

To do so, you'll need to:

  • implement the flag.Value interface for the custom type
  • declare the option or the flag using VarOpt, VarArg for the short hands, and Var for the full form.

Here's an example:

// Declare your type
type Duration time.Duration

// Make it implement flag.Value
func (d *Duration) Set(v string) error {
	parsed, err := time.ParseDuration(v)
	if err != nil {
		return err
	}
	*d = Duration(parsed)
	return nil
}

func (d *Duration) String() string {
	duration := time.Duration(*d)
	return duration.String()
}

func main() {
    duration := Duration(0)

	app := App("var", "")

	app.VarArg("DURATION", &duration, "")

	app.Run([]string{"cp", "1h31m42s"})
}
Boolean custom types

To make your custom type behave as a boolean option, i.e. doesn't take a value, it has to implement a IsBoolFlag method that returns true:

type BoolLike int


func (d *BoolLike) IsBoolFlag() bool {
	return true
}
Multi-valued custom type

To make your custom type behave as a multi-valued option or argument, i.e. takes multiple values, it has to implement a Clear method which will be called whenever the value list needs to be cleared, e.g. when the value was initially populated from an environment variable, and then explicitly set from the CLI:

type Durations []time.Duration

// Make it implement flag.Value
func (d *Durations) Set(v string) error {
	parsed, err := time.ParseDuration(v)
	if err != nil {
		return err
	}
	*d = append(*d, Duration(parsed))
	return nil
}

func (d *Durations) String() string {
	return fmt.Sprintf("%v", *d)
}


// Make it multi-valued
func (d *Durations) Clear() {
	*d = []Duration{}
}

Interceptors

It is possible to define snippets of code to be executed before and after a command or any of its sub commands is executed.

For example, given an app with multiple commands but with a global flag which toggles a verbose mode:

app := cli.App("app", "bla bla")

verbose := app.Bool(cli.BoolOpt{
	Name:  "verbose",
	Value: false,
	Desc:  "Enable debug logs",
})

app.Command("command1", "...", func(cmd *cli.Cmd) {

})

app.Command("command2", "...", func(cmd *cli.Cmd) {

})

Instead of repeating yourself by checking if the verbose flag is set or not, and setting the debug level in every command (and its sub-commands), a before interceptor can be set on the app instead:

app.Before = func() {
	if (*verbose) {
		logrus.SetLevel(logrus.DebugLevel)
	}
}

Whenever a valid command is called by the user, all the before interceptors defined on the app and the intermediate commands will be called, in order from the root to the leaf.

Similarly, if you need to execute a code snippet after a command has been called, e.g. to cleanup resources allocated in before interceptors, simply set the After field of the app struct or any other command. After interceptors will be called, in order from the leaf up to the root (the opposite order of the Before interceptors).

Here's a diagram which shows in when and in which order multiple Before and After interceptors get executed:

flow

Spec

An app or command's call syntax can be customized using spec strings. This can be useful to indicate that an argument is optional for example, or that 2 options are mutually exclusive.

You can set a spec string on:

  • The app: to configure the syntax for global options and arguments
  • A command: to configure the syntax for that command's options and arguments

In both cases, a spec string is assigned to the Spec field:

cp := cli.App("cp", "Copy files around")
cp.Spec = "[-R [-H | -L | -P]]"

And:

docker := cli.App("docker", "A self-sufficient runtime for linux containers")
docker.Command("run", "Run a command in a new container", func(cmd *cli.Cmd) {
    cmd.Spec = "[-d|--rm] IMAGE [COMMAND [ARG...]]"
    :
    :
}

The spec syntax is mostly based on the conventions used in POSIX command line apps help messages and man pages:

Options

You can use both short and long option names in spec strings:

x.Spec="-f"

And:

x.Spec="--force"

In both cases, we required that the f or force flag be set

Any option you reference in a spec string MUST be explicitly declared, otherwise mow.cli will panic:

x.BoolOpt("f force", ...)
Arguments

Arguments are all-uppercased words:

x.Spec="SRC DST"

This spec string will force the user to pass exactly 2 arguments, SRC and DST

Any argument you reference in a spec string MUST be explicitly declared, otherwise mow.cli will panic:

x.StringArg("SRC", ...)
x.StringArg("DST", ...)
Ordering

Except for options, The order of the elements in a spec string is respected and enforced when parsing the command line arguments:

x.Spec = "-f -g SRC -h DST"

Consecutive options (-f and -g for example) get parsed regardless of the order they are specified in (both -f=5 -g=6 and -g=6 -f=5 are valid).

Order between options and arguments is significant (-f and -g must appear before the SRC argument).

Same goes for arguments, where SRC must appear before DST.

Optionality

You can mark items as optional in a spec string by enclosing them in square brackets :[...]

x.Spec = "[-x]"
Choice

You can use the | operator to indicate a choice between two or more items

x.Spec = "--rm | --daemon"
x.Spec = "-H | -L | -P"
x.Spec = "-t | DST"
Repetition

You can use the ... postfix operator to mark an element as repeatable:

x.Spec="SRC..."
x.Spec="-e..."
Grouping

You can group items using parenthesis. This is useful in combination with the choice and repetition operators (| and ...):

x.Spec = "(-e COMMAND)... | (-x|-y)"

The parenthesis in the example above serve to mark that it is the sequence of a -e flag followed by an argument that is repeatable, and that all that is mutually exclusive to a choice between -x and -y options.

Option group

This is a shortcut to declare a choice between multiple options:

x.Spec = "-abcd"

Is equivalent to:

x.Spec = "(-a | -b | -c | -d)..."

I.e. any combination of the listed options in any order, with at least one option.

All options

Another shortcut:

x.Spec = "[OPTIONS]"

This is a special syntax (the square brackets are not for marking an optional item, and the uppercased word is not for an argument).
This is equivalent to a repeatable choice between all the available options. For example, if an app or a command declares 4 options a, b, c and d, [OPTIONS] is equivalent to

x.Spec = "[-a | -b | -c | -d]..."
Inline option values

You can use the =<some-text> notation right after an option (long or short form) to give an inline description or value.

An example:

x.Spec = "[ -a=<absolute-path> | --timeout=<in seconds> ] ARG"

The inline values are ignored by the spec parser and are just there for the final user as a contextual hint.

Operators

The -- operator can be used in a spec string to automatically treat everything following it as an options.

In other words, placing a -- in the spec string automatically inserts a -- in the same position in the program call arguments.

This lets you write programs like the time utility for example:

x.Spec = "time -lp [-- CMD [ARG...]]"

Grammar

Here's the (simplified) EBNF grammar for the Specs language:

spec         -> sequence
sequence     -> choice*
req_sequence -> choice+
choice       -> atom ('|' atom)*
atom         -> (shortOpt | longOpt | optSeq | allOpts | group | optional) rep? | optEnd
shortOp      -> '-' [A-Za-z]
longOpt      -> '--' [A-Za-z][A-Za-z0-9]*
optSeq       -> '-' [A-Za-z]+
allOpts      -> '[OPTIONS]'
group        -> '(' req_sequence ')'
optional     -> '[' req_sequence ']'
rep          -> '...'
optEnd       -> '--'

And that's it for the spec language. You can combine these few building blocks in any way you want (while respecting the grammar above) to construct sophisticated validation constraints (don't go too wild though).

Behind the scenes, mow.cli parses the spec string and constructs a finite state machine to be used to parse the command line arguments. mow.cli also handles backtracking, and so it can handle tricky cases, or what I like to call "the cp test"

cp SRC... DST

Without backtracking, this deceptively simple spec string cannot be parsed correctly. For instance, docopt can't handle this case, whereas mow.cli does.

Default spec

By default, and unless a spec string is set by the user, mow.cli auto-generates one for the app and every command using this logic:

  • Start with an empty spec string
  • If at least one option was declared, append [OPTIONS] to the spec string
  • For every declared argument, append it, in the order of declaration, to the spec string

For example, given this command declaration:

docker.Command("run", "Run a command in a new container", func(cmd *cli.Cmd) {
    detached := cmd.BoolOpt("d detach", false, "Detached mode: run the container in the background and print the new container ID", nil)
    memory := cmd.StringOpt("m memory", "", "Memory limit (format: <number><optional unit>, where unit = b, k, m or g)", nil)

    image := cmd.StringArg("IMAGE", "", "", nil)
    args := cmd.StringsArg("ARG", "", "", nil)
})

The auto-generated spec string would be:

[OPTIONS] IMAGE ARG

Which should suffice for simple cases. If not, the spec string has to be set explicitly.

Exiting

mow.cli provides the Exit function which accepts an exit code and exits the app with the provided code.

You are highly encouraged to call cli.Exit instead of os.Exit for the After interceptors to be executed.

License

This work is published under the MIT license.

Please see the LICENSE file for details.

Documentation

Overview

Package cli provides a framework to build command line applications in Go with most of the burden of arguments parsing and validation placed on the framework instead of the user.

Basics

You start by creating an application by passing a name and a description:

cp = cli.App("cp", "Copy files around")

To attach the code to execute when the app is launched, assign a function to the Action field:

cp.Action = func() {
	fmt.Printf("Hello world\n")
}

Finally, in your main func, call Run on the app:

cp.Run(os.Args)

Options

To add a (global) option, call one of the (String[s]|Int[s]|Bool)Opt methods on the app:

recursive := cp.BoolOpt("R recursive", false, "recursively copy the src to dst")

* The first argument is a space separated list of names for the option without the dashes

* The second parameter is the default value for the option

* The third parameter is the option description, as will be shown in the help messages

There is also a second set of methods Bool, String, Int, Strings and Ints, which accepts structs describing the option:

recursive = cp.Bool(BoolOpt{
	Name:  "R",
	Value: false,
	Desc:  "copy src files recursively",
	EnvVar: "",
})

The field names are self-describing. There EnvVar field is a space separated list of environment variables names to be used to initialize the option.

The result is a pointer to a value that will be populated after parsing the command line arguments. You can access the values in the Action func.

In the command line, mow.cli accepts the following syntaxes

* For boolean options:

-f : a single dash for the one letter names
-f=false : a single dash for the one letter names, equal sign followed by true or false
--force :  double dash for longer option names
-it : mow.cli supports option folding, this is equivalent to: -i -t

* For string, int options:

-e=value : single dash for one letter names, equal sign followed by the value
-e value : single dash for one letter names, space followed by the value
-Ivalue : single dash for one letter names immediately followed by the value
--extra=value : double dash for longer option names, equal sign followed by the value
--extra value : double dash for longer option names, space followed by the value

* For slice options (StringsOpt, IntsOpt): repeat the option to accumulate the values in the resulting slice:

-e PATH:/bin -e PATH:/usr/bin : resulting slice contains ["/bin", "/usr/bin"]

Arguments

To accept arguments, you need to explicitly declare them by calling one of the (String[s]|Int[s]|Bool)Arg methods on the app:

src := cp.StringArg("SRC", "", "the file to copy")
dst := cp.StringArg("DST", "", "the destination")

* The first argument is the argument name as will be shown in the help messages

* The second parameter is the default value for the argument

* The third parameter is the argument description, as will be shown in the help messages

There is also a second set of methods Bool, String, Int, Strings and Ints, which accepts structs describing the argument:

src = cp.Strings(StringsArg{
	Name:  "SRC",
	Desc:  "The source files to copy",
	Value: "",
	EnvVar: "",
})

The field names are self-describing. The Value field is where you can set the initial value for the argument.

EnvVar accepts a space separated list of environment variables names to be used to initialize the argument.

The result is a pointer to a value that will be populated after parsing the command line arguments. You can access the values in the Action func.

Operators

The -- operator marks the end of options. Everything that follow will be treated as an argument, even if starts with a dash.

For example, given the touch command which takes a filename as an argument (and possibly other options):

file := cp.StringArg("FILE", "", "the file to create")

If we try to create a file named -f this way:

touch -f

Would fail, because -f will be parsed as an option not as an argument. The fix is to prefix the filename with the -- operator:

touch -- -f

Commands

mow.cli supports nesting commands and sub commands. Declare a top level command by calling the Command func on the app struct, and a sub command by calling the Command func on the command struct:

docker := cli.App("docker", "A self-sufficient runtime for linux containers")

docker.Command("run", "Run a command in a new container", func(cmd *cli.Cmd) {
	// initialize the run command here
})

* The first argument is the command name, as will be shown in the help messages and as will need to be input by the user in the command line to call the command

* The second argument is the command description as will be shown in the help messages

* The third argument is a CmdInitializer, a function that receives a pointer to a Cmd struct representing the command. In this function, you can add options and arguments by calling the same methods as you would with an app struct (BoolOpt, StringArg, ...). You would also assign a function to the Action field of the Cmd struct for it to be executed when the command is invoked.

docker.Command("run", "Run a command in a new container", func(cmd *cli.Cmd) {
	detached := cmd.BoolOpt("d detach", false, "Detached mode: run the container in the background and print the new container ID")
	memory := cmd.StringOpt("m memory", "", "Memory limit (format: <number><optional unit>, where unit = b, k, m or g)")

	image := cmd.StringArg("IMAGE", "", "The image to run")

	cmd.Action = func() {
		if *detached {
			//do something
		}
		runContainer(*image, *detached, *memory)
	}
})

You can also add sub commands by calling Command on the Cmd struct:

bzk.Command("job", "actions on jobs", func(cmd *cli.Cmd) {
	cmd.Command("list", "list jobs", listJobs)
	cmd.Command("start", "start a new job", startJob)
	cmd.Command("log", "show a job log", nil)
})

This could go on to any depth if need be.

As a side-note: it may seem a bit weird the way mow.cli uses a function to initialize a command instead of just returning the command struct.

The motivation behind this choice is scoping: as with the standard flag package, adding an option or an argument returns a pointer to a value which will be populated when the app is run.

Since you'll want to store these pointers in variables, and to avoid having dozens of them in the same scope (the main func for example or as global variables), mow.cli's API was specifically tailored to take a func parameter (called CmdInitializer) which accepts the command struct.

This way, the command specific variables scope is limited to this function.

Custom types

Out of the box, mow.cli supports the following types for options and arguments: bool, string, int, strings (slice of strings) and ints (slice of ints)

You can however extend mow.cli to handle other types, e.g. `time.Duration`, `float64`, or even your own struct types for example.

To do so, you'll need to:

* implement the `flag.Value` interface for the custom type

* declare the option or the flag using `VarOpt`, `VarArg` for the short hands, and `Var` for the full form.

Here's an example:

// Declare your type
type Duration time.Duration

// Make it implement flag.Value
func (d *Duration) Set(v string) error {
	parsed, err := time.ParseDuration(v)
	if err != nil {
		return err
	}
	*d = Duration(parsed)
	return nil
}

func (d *Duration) String() string {
	duration := time.Duration(*d)
	return duration.String()
}

func main() {
	duration := Duration(0)

	app := App("var", "")

	app.VarArg("DURATION", &duration, "")

	app.Run([]string{"cp", "1h31m42s"})
}

Boolean custom types

To make your custom type behave as a boolean option, i.e. doesn't take a value, it has to implement a IsBoolFlag method that returns true:

type BoolLike int

func (d *BoolLike) IsBoolFlag() bool {
	return true
}

Multi-valued custom type

To make your custom type behave as a multi-valued option or argument, i.e. takes multiple values, it has to implement a `Clear` method which will be called whenever the values list needs to be cleared, e.g. when the value was initially populated from an environment variable, and then explicitly set from the CLI:

type Durations []time.Duration

// Make it implement flag.Value
func (d *Durations) Set(v string) error {
	parsed, err := time.ParseDuration(v)
	if err != nil {
		return err
	}
	*d = append(*d, Duration(parsed))
	return nil
}

func (d *Durations) String() string {
	return fmt.Sprintf("%v", *d)
}

// Make it multi-valued
func (d *Durations) Clear() {
	*d = []Duration{}
}

Interceptors

It is possible to define snippets of code to be executed before and after a command or any of its sub commands is executed.

For example, given an app with multiple commands but with a global flag which toggles a verbose mode:

app := cli.App("app", "bla bla")
verbose := app.Bool(cli.BoolOpt{
	Name:  "verbose",
	Value: false,
	Desc:  "Enable debug logs",
})

app.Command("command1", "...", func(cmd *cli.Cmd) {

})

app.Command("command2", "...", func(cmd *cli.Cmd) {

})

Instead of repeating yourself by checking if the verbose flag is set or not, and setting the debug level in every command (and its sub-commands), a before interceptor can be set on the `app` instead:

app.Before = func() {
	if (*verbose) {
		logrus.SetLevel(logrus.DebugLevel)
	}
}

Whenever a valid command is called by the user, all the before interceptors defined on the app and the intermediate commands will be called, in order from the root to the leaf.

Similarly, if you need to execute a code snippet after a command has been called, e.g. to cleanup resources allocated in before interceptors, simply set the After field of the app struct or any other command.

After interceptors will be called, in order from the leaf up to the root (the opposite order of the Before interceptors).

Here's a diagram which shows in when and in which order multiple Before and After interceptors get executed:

+------------+    success    +------------+   success   +----------------+     success
| app.Before +---------------> cmd.Before +-------------> sub_cmd.Before +---------+
+------------+               +-+----------+             +--+-------------+         |
                               |                           |                     +-v-------+
                 error         |           error           |                     | sub_cmd |
       +-----------------------+   +-----------------------+                     | Action  |
       |                           |                                             +-+-------+
+------v-----+               +-----v------+             +----------------+         |
| app.After  <---------------+ cmd.After  <-------------+  sub_cmd.After <---------+
+------------+    always     +------------+    always   +----------------+      always

Spec

An app or command's call syntax can be customized using spec strings. This can be useful to indicate that an argument is optional for example, or that 2 options are mutually exclusive.

You can set a spec string on:

* The app: to configure the syntax for global options and arguments

* A command: to configure the syntax for that command's options and arguments

In both cases, a spec string is assigned to the Spec field:

cp := cli.App("cp", "Copy files around")
cp.Spec = "[-R [-H | -L | -P]]"

And:

docker := cli.App("docker", "A self-sufficient runtime for linux containers")
docker.Command("run", "Run a command in a new container", func(cmd *cli.Cmd) {
	cmd.Spec = "[-d|--rm] IMAGE [COMMAND [ARG...]]"
	:
	:
}

The spec syntax is mostly based on the conventions used in POSIX command line apps help messages and man pages:

Options

You can use both short and long option names in spec strings:

x.Spec="-f"

And:

x.Spec="--force"

In both cases, we required that the f or force flag be set

Any option you reference in a spec string MUST be explicitly declared, otherwise mow.cli will panic:

x.BoolOpt("f force", ...)

Arguments

Arguments are all-uppercased words:

x.Spec="SRC DST"

This spec string will force the user to pass exactly 2 arguments, SRC and DST

Any argument you reference in a spec string MUST be explicitly declared, otherwise mow.cli will panic:

x.StringArg("SRC", ...)
x.StringArg("DST", ...)

Ordering

Except for options, The order of the elements in a spec string is respected and enforced when parsing the command line arguments:

x.Spec = "-f -g SRC -h DST"

Consecutive options (-f and -g for example) get parsed regardless of the order they are specified in (both "-f=5 -g=6" and "-g=6 -f=5" are valid).

Order between options and arguments is significant (-f and -g must appear before the SRC argument).

Same goes for arguments, where SRC must appear before DST.

Optionality

You can mark items as optional in a spec string by enclosing them in square brackets :[...]

x.Spec = "[-x]"

Choice

You can use the | operator to indicate a choice between two or more items

x.Spec = "--rm | --daemon"
x.Spec = "-H | -L | -P"
x.Spec = "-t | DST"

Repetition

You can use the ... postfix operator to mark an element as repeatable:

x.Spec="SRC..."
x.Spec="-e..."

Grouping

You can group items using parenthesis. This is useful in combination with the choice and repetition operators (| and ...):

x.Spec = "(-e COMMAND)... | (-x|-y)"

The parenthesis in the example above serve to mark that it is the sequence of a -e flag followed by an argument that is repeatable, and that all that is mutually exclusive to a choice between -x and -y options.

Option group

This is a shortcut to declare a choice between multiple options:

x.Spec = "-abcd"

Is equivalent to:

x.Spec = "(-a | -b | -c | -d)..."

I.e. any combination of the listed options in any order, with at least one option.

All options

Another shortcut:

x.Spec = "[OPTIONS]"

This is a special syntax (the square brackets are not for marking an optional item, and the uppercased word is not for an argument). This is equivalent to a repeatable choice between all the available options. For example, if an app or a command declares 4 options a, b, c and d, [OPTIONS] is equivalent to

x.Spec = "[-a | -b | -c | -d]..."

Inline option values

You can use the =<some-text> notation right after an option (long or short form) to give an inline description or value. An example:

x.Spec = "[ -a=<absolute-path> | --timeout=<in seconds> ] ARG"

The inline values are ignored by the spec parser and are just there for the final user as a contextual hint.

Operators

The `--` operator can be used in a spec string to automatically treat everything following it as an options.

In other words, placing a `--` in the spec string automatically inserts a `--` in the same position in the program call arguments.

This lets you write programs like the `time` utility for example:

x.Spec = "time -lp [-- CMD [ARG...]]"

Spec Grammar

Here's the EBNF grammar for the Specs language:

spec         -> sequence
sequence     -> choice*
req_sequence -> choice+
choice       -> atom ('|' atom)*
atom         -> (shortOpt | longOpt | optSeq | allOpts | group | optional) rep?
shortOp      -> '-' [A-Za-z]
longOpt      -> '--' [A-Za-z][A-Za-z0-9]*
optSeq       -> '-' [A-Za-z]+
allOpts      -> '[OPTIONS]'
group        -> '(' req_sequence ')'
optional     -> '[' req_sequence ']'
rep          -> '...'

And that's it for the spec language. You can combine these few building blocks in any way you want (while respecting the grammar above) to construct sophisticated validation constraints (don't go too wild though).

Behind the scenes, mow.cli parses the spec string and constructs a finite state machine to be used to parse the command line arguments. mow.cli also handles backtracking, and so it can handle tricky cases, or what I like to call "the cp test"

cp SRC... DST

Without backtracking, this deceptively simple spec string cannot be parsed correctly. For instance, docopt can't handle this case, whereas mow.cli does.

Default spec

By default, and unless a spec string is set by the user, mow.cli auto-generates one for the app and every command using this logic:

* Start with an empty spec string

* If at least one option was declared, append "[OPTIONS]" to the spec string

* For every declared argument, append it, in the order of declaration, to the spec string

For example, given this command declaration:

docker.Command("run", "Run a command in a new container", func(cmd *cli.Cmd) {
	detached := cmd.BoolOpt("d detach", false, "Detached mode: run the container in the background and print the new container ID")
	memory := cmd.StringOpt("m memory", "", "Memory limit (format: <number><optional unit>, where unit = b, k, m or g)")

	image := cmd.StringArg("IMAGE", "", "")
	args := cmd.StringsArg("ARG", "", "")
})

The auto-generated spec string would be:

[OPTIONS] IMAGE ARG

Which should suffice for simple cases. If not, the spec string has to be set explicitly.

Exiting

mow.cli provides the Exit function which accepts an exit code and exits the app with the provided code.

You are highly encouraged to call cli.Exit instead of os.Exit for the After interceptors to be executed.

Example (BeforeAfter)
app := App("app", "App")
bench := app.BoolOpt("b bench", false, "Measure execution time")

var t0 time.Time

app.Before = func() {
	if *bench {
		t0 = time.Now()
	}
}

app.After = func() {
	if *bench {
		d := time.Since(t0)
		fmt.Printf("Command execution took: %vs", d.Seconds())
	}
}

app.Command("cmd1", "first command", func(cmd *Cmd) {
	cmd.Action = func() {
		fmt.Print("Running command 1")
	}
})

app.Command("cmd2", "second command", func(cmd *Cmd) {
	cmd.Action = func() {
		fmt.Print("Running command 2")
	}
})

app.Run(os.Args)
Output:

Example (Cp)
cp := App("cp", "Copy files around")
cp.Spec = "[-R [-H | -L | -P]] [-fi | -n] SRC... DST"

var (
	recursive = cp.Bool(BoolOpt{
		Name:  "R",
		Value: false,
		Desc:  "copy src files recursively",
	})

	followSymbolicCL   = cp.Bool(BoolOpt{Name: "H", Value: false, Desc: "If the -R option is specified, symbolic links on the command line are followed.  (Symbolic links encountered in the tree traversal are not followed.)"})
	followSymbolicTree = cp.Bool(BoolOpt{Name: "L", Value: false, Desc: "If the -R option is specified, all symbolic links are followed."})
	followSymbolicNo   = cp.Bool(BoolOpt{Name: "P", Value: true, Desc: "If the -R option is specified, no symbolic links are followed.  This is the default."})

	force       = cp.Bool(BoolOpt{Name: "f", Value: false, Desc: "If the destination file cannot be opened, remove it and create a new file, without prompting for confirmation regardless of its permissions.  (The -f option overrides any previous -n option.)"})
	interactive = cp.Bool(BoolOpt{Name: "i", Value: false, Desc: "Cause cp to write a prompt to the standard error output before copying a file that would overwrite an existing file.  If the response from the standard input begins with the character `y' or `Y', the file copy is attempted.  (The -i option overrides any previous -n option.)"})
	noOverwrite = cp.Bool(BoolOpt{Name: "f", Value: false, Desc: "Do not overwrite an existing file.  (The -n option overrides any previous -f or -i options.)"})
)

var (
	src = cp.Strings(StringsArg{
		Name: "SRC",
		Desc: "The source files to copy",
	})
	dst = cp.Strings(StringsArg{Name: "DST", Value: nil, Desc: "The destination directory"})
)

cp.Action = func() {
	fmt.Printf(`copy:
	SRC: %v
	DST: %v
	recursive: %v
	follow links (CL, Tree, No): %v %v %v
	force: %v
	interactive: %v
	no overwrite: %v`,
		*src, *dst, *recursive,
		*followSymbolicCL, *followSymbolicTree, *followSymbolicNo,
		*force,
		*interactive,
		*noOverwrite)
}

cp.Run(os.Args)
Output:

Example (Docker)
docker := App("docker", "A self-sufficient runtime for linux containers")

docker.Command("run", "Run a command in a new container", func(cmd *Cmd) {
	cmd.Spec = "[-d|--rm] IMAGE [COMMAND [ARG...]]"

	var (
		detached = cmd.Bool(BoolOpt{Name: "d detach", Value: false, Desc: "Detached mode: run the container in the background and print the new container ID"})
		rm       = cmd.Bool(BoolOpt{Name: "rm", Value: false, Desc: "Automatically remove the container when it exits (incompatible with -d)"})
		memory   = cmd.String(StringOpt{Name: "m memory", Value: "", Desc: "Memory limit (format: <number><optional unit>, where unit = b, k, m or g)"})
	)

	var (
		image   = cmd.String(StringArg{Name: "IMAGE", Value: "", Desc: ""})
		command = cmd.String(StringArg{Name: "COMMAND", Value: "", Desc: "The command to run"})
		args    = cmd.Strings(StringsArg{Name: "ARG", Value: nil, Desc: "The command arguments"})
	)

	cmd.Action = func() {
		var how string
		switch {
		case *detached:
			how = "detached"
		case *rm:
			how = "rm after"
		default:
			how = "--"
		}
		fmt.Printf("Run image %s, command %s, args %v, how? %v, mem %s", *image, *command, *args, how, *memory)
	}
})

docker.Command("pull", "Pull an image or a repository from the registry", func(cmd *Cmd) {
	cmd.Spec = "[-a] NAME"

	all := cmd.Bool(BoolOpt{Name: "a all-tags", Value: false, Desc: "Download all tagged images in the repository"})

	name := cmd.String(StringArg{Name: "NAME", Value: "", Desc: "Image name (optionally NAME:TAG)"})

	cmd.Action = func() {
		if *all {
			fmt.Printf("Download all tags for image %s", *name)
			return
		}
		fmt.Printf("Download image %s", *name)
	}
})

docker.Run(os.Args)
Output:

Example (Greet)
app := App("greet", "Greet")
app.Spec = "[NAME]"
name := app.String(StringArg{Name: "NAME", Value: "stranger", Desc: "Your name", EnvVar: "USER"})
app.Action = func() {
	fmt.Printf("Hello %s\n", *name)
}
app.Run(os.Args)
Output:

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func Exit

func Exit(code int)

Exit causes the app the exit with the specified exit code while giving the After interceptors a chance to run. This should be used instead of os.Exit.

Types

type BoolArg

type BoolArg struct {
	// The argument name as will be shown in help messages
	Name string
	// The argument description as will be shown in help messages
	Desc string
	// A space separated list of environment variables names to be used to initialize this argument
	EnvVar string
	// The argument's inital value
	Value bool
	// A boolean to display or not the current value of the argument in the help message
	HideValue bool
	// Set to true if this arg was set by the user (as opposed to being set from env or not set at all)
	SetByUser *bool
}

BoolArg describes a boolean argument

type BoolOpt

type BoolOpt struct {
	// A space separated list of the option names *WITHOUT* the dashes, e.g. `f force` and *NOT* `-f --force`.
	// The one letter names will then be called with a single dash (short option), the others with two (long options).
	Name string
	// The option description as will be shown in help messages
	Desc string
	// A space separated list of environment variables names to be used to initialize this option
	EnvVar string
	// The option's initial value
	Value bool
	// A boolean to display or not the current value of the option in the help message
	HideValue bool
	// Set to true if this option was set by the user (as opposed to being set from env or not set at all)
	SetByUser *bool
}

BoolOpt describes a boolean option

type BoolParam

type BoolParam interface {
	// contains filtered or unexported methods
}

BoolParam represents a Bool option or argument

type Cli

type Cli struct {
	*Cmd
	// contains filtered or unexported fields
}

Cli represents the structure of a CLI app. It should be constructed using the App() function

func App

func App(name, desc string) *Cli

App creates a new and empty CLI app configured with the passed name and description.

name and description will be used to construct the help message for the app:

Usage: $name [OPTIONS] COMMAND [arg...]

$desc

func (*Cli) PrintVersion

func (cli *Cli) PrintVersion()

PrintVersion prints the CLI app's version. In most cases the library users won't need to call this method, unless a more complex validation is needed.

func (*Cli) Run

func (cli *Cli) Run(args []string) error

Run uses the app configuration (specs, commands, ...) to parse the args slice and to execute the matching command.

In case of an incorrect usage, and depending on the configured ErrorHandling policy, it may return an error, panic or exit

func (*Cli) Version

func (cli *Cli) Version(name, version string)

Version sets the version string of the CLI app together with the options that can be used to trigger printing the version string via the CLI.

Usage: appName --$name
$version

type Cmd

type Cmd struct {
	// The code to execute when this command is matched
	Action func()
	// The code to execute before this command or any of its children is matched
	Before func()
	// The code to execute after this command or any of its children is matched
	After func()
	// The command options and arguments
	Spec string
	// The command long description to be shown when help is requested
	LongDesc string
	// Location of the description text. 0 for the top or 1 for bottom of the full output
	DescLocation DescriptionLocation
	// The command error handling strategy
	ErrorHandling flag.ErrorHandling

	Name string

	Commands []*Cmd
	// contains filtered or unexported fields
}

Cmd represents a command (or sub command) in a CLI application. It should be constructed by calling Command() on an app to create a top level command or by calling Command() on another command to create a sub command

func (*Cmd) Bool

func (c *Cmd) Bool(p BoolParam) *bool

Bool can be used to add a bool option or argument to a command. It accepts either a BoolOpt or a BoolArg struct.

The result should be stored in a variable (a pointer to a bool) which will be populated when the app is run and the call arguments get parsed

func (*Cmd) BoolArg

func (c *Cmd) BoolArg(name string, value bool, desc string) *bool

BoolArg defines a boolean argument on the command c named `name`, with an initial value of `value` and a description of `desc` which will be used in help messages.

The result should be stored in a variable (a pointer to a bool) which will be populated when the app is run and the call arguments get parsed

func (*Cmd) BoolOpt

func (c *Cmd) BoolOpt(name string, value bool, desc string) *bool

BoolOpt defines a boolean option on the command c named `name`, with an initial value of `value` and a description of `desc` which will be used in help messages.

The name is a space separated list of the option names *WITHOUT* the dashes, e.g. `f force` and *NOT* `-f --force`. The one letter names will then be called with a single dash (short option), the others with two (long options).

The result should be stored in a variable (a pointer to a bool) which will be populated when the app is run and the call arguments get parsed

func (*Cmd) Command

func (c *Cmd) Command(name, desc string, init CmdInitializer)

Command adds a new (sub) command to c where name is the command name (what you type in the console), description is what would be shown in the help messages, e.g.:

Usage: git [OPTIONS] COMMAND [arg...]

Commands:
  $name	$desc

the last argument, init, is a function that will be called by mow.cli to further configure the created (sub) command, e.g. to add options, arguments and the code to execute

func (*Cmd) CommandLong

func (c *Cmd) CommandLong(name, desc, long string, init CmdInitializer)

func (*Cmd) DoInit

func (c *Cmd) DoInit() error

func (*Cmd) Int

func (c *Cmd) Int(p IntParam) *int

Int can be used to add an int option or argument to a command. It accepts either a IntOpt or a IntArg struct.

The result should be stored in a variable (a pointer to an int) which will be populated when the app is run and the call arguments get parsed

func (*Cmd) IntArg

func (c *Cmd) IntArg(name string, value int, desc string) *int

IntArg defines an int argument on the command c named `name`, with an initial value of `value` and a description of `desc` which will be used in help messages.

The result should be stored in a variable (a pointer to an int) which will be populated when the app is run and the call arguments get parsed

func (*Cmd) IntOpt

func (c *Cmd) IntOpt(name string, value int, desc string) *int

IntOpt defines an int option on the command c named `name`, with an initial value of `value` and a description of `desc` which will be used in help messages.

The name is a space separated list of the option names *WITHOUT* the dashes, e.g. `f force` and *NOT* `-f --force`. The one letter names will then be called with a single dash (short option), the others with two (long options).

The result should be stored in a variable (a pointer to an int) which will be populated when the app is run and the call arguments get parsed

func (*Cmd) Ints

func (c *Cmd) Ints(p IntsParam) *[]int

Ints can be used to add an int slice option or argument to a command. It accepts either a IntsOpt or a IntsArg struct.

The result should be stored in a variable (a pointer to an int slice) which will be populated when the app is run and the call arguments get parsed

func (*Cmd) IntsArg

func (c *Cmd) IntsArg(name string, value []int, desc string) *[]int

IntsArg defines an int slice argument on the command c named `name`, with an initial value of `value` and a description of `desc` which will be used in help messages.

The result should be stored in a variable (a pointer to an int slice) which will be populated when the app is run and the call arguments get parsed

func (*Cmd) IntsOpt

func (c *Cmd) IntsOpt(name string, value []int, desc string) *[]int

IntsOpt defines an int slice option on the command c named `name`, with an initial value of `value` and a description of `desc` which will be used in help messages.

The name is a space separated list of the option names *WITHOUT* the dashes, e.g. `f force` and *NOT* `-f --force`. The one letter names will then be called with a single dash (short option), the others with two (long options).

The result should be stored in a variable (a pointer to an int slice) which will be populated when the app is run and the call arguments get parsed

func (*Cmd) PrintHelp

func (c *Cmd) PrintHelp()

PrintHelp prints the command's help message. In most cases the library users won't need to call this method, unless a more complex validation is needed

func (*Cmd) PrintLongHelp

func (c *Cmd) PrintLongHelp()

PrintLongHelp prints the command's help message using the command long description if specified. In most cases the library users won't need to call this method, unless a more complex validation is needed

func (*Cmd) PrintLongHelpTo

func (c *Cmd) PrintLongHelpTo(longDesc bool, writer io.Writer)

func (*Cmd) String

func (c *Cmd) String(p StringParam) *string

String can be used to add a string option or argument to a command. It accepts either a StringOpt or a StringArg struct.

The result should be stored in a variable (a pointer to a string) which will be populated when the app is run and the call arguments get parsed

func (*Cmd) StringArg

func (c *Cmd) StringArg(name string, value string, desc string) *string

StringArg defines a string argument on the command c named `name`, with an initial value of `value` and a description of `desc` which will be used in help messages.

The result should be stored in a variable (a pointer to a string) which will be populated when the app is run and the call arguments get parsed

func (*Cmd) StringOpt

func (c *Cmd) StringOpt(name string, value string, desc string) *string

StringOpt defines a string option on the command c named `name`, with an initial value of `value` and a description of `desc` which will be used in help messages.

The name is a space separated list of the option names *WITHOUT* the dashes, e.g. `f force` and *NOT* `-f --force`. The one letter names will then be called with a single dash (short option), the others with two (long options).

The result should be stored in a variable (a pointer to a string) which will be populated when the app is run and the call arguments get parsed

func (*Cmd) Strings

func (c *Cmd) Strings(p StringsParam) *[]string

Strings can be used to add a string slice option or argument to a command. It accepts either a StringsOpt or a StringsArg struct.

The result should be stored in a variable (a pointer to a string slice) which will be populated when the app is run and the call arguments get parsed

func (*Cmd) StringsArg

func (c *Cmd) StringsArg(name string, value []string, desc string) *[]string

StringsArg defines a string slice argument on the command c named `name`, with an initial value of `value` and a description of `desc` which will be used in help messages.

The result should be stored in a variable (a pointer to a string slice) which will be populated when the app is run and the call arguments get parsed

func (*Cmd) StringsOpt

func (c *Cmd) StringsOpt(name string, value []string, desc string) *[]string

StringsOpt defines a string slice option on the command c named `name`, with an initial value of `value` and a description of `desc` which will be used in help messages.

The name is a space separated list of the option names *WITHOUT* the dashes, e.g. `f force` and *NOT* `-f --force`. The one letter names will then be called with a single dash (short option), the others with two (long options).

The result should be stored in a variable (a pointer to a string slice) which will be populated when the app is run and the call arguments get parsed

func (*Cmd) Var

func (c *Cmd) Var(p VarParam)

Var can be used to add a custom option or argument to a command. It accepts either a VarOpt or a VarArg struct.

As opposed to the other built-in types, this function does not return a pointer the the value. Instead, the VarOpt or VarOptArg structs hold the said value.

func (*Cmd) VarArg

func (c *Cmd) VarArg(name string, value flag.Value, desc string)

VarArg defines an argument where the type and format is controlled by the developer on the command c named `name` and a description of `desc` which will be used in help messages.

The result will be stored in the value parameter (a value implementing the flag.Value interface) which will be populated when the app is run and the call arguments get parsed

func (*Cmd) VarOpt

func (c *Cmd) VarOpt(name string, value flag.Value, desc string)

VarOpt defines an option where the type and format is controlled by the developer.

The name is a space separated list of the option names *WITHOUT* the dashes, e.g. `f force` and *NOT* `-f --force`. The one letter names will then be called with a single dash (short option), the others with two (long options).

The result will be stored in the value parameter (a value implementing the flag.Value interface) which will be populated when the app is run and the call arguments get parsed

type CmdInitializer

type CmdInitializer func(*Cmd)

CmdInitializer is a function that configures a command by adding options, arguments, a spec, sub commands and the code to execute when the command is called

func ActionCommand

func ActionCommand(action func()) CmdInitializer

ActionCommand(myFun) is syntactic sugar for func(cmd *cli.Cmd) { cmd.Action = myFun }

cmd.CommandAction(_, _, myFun } is syntactic sugar for cmd.Command(_, _, func(cmd *cli.Cmd) { cmd.Action = myFun })

type DescriptionLocation

type DescriptionLocation int

DescriptionLocation defines where to print out help text

const (
	// DescriptionLocationTop specifies printing out the help text at the top of the output
	DescriptionLocationTop DescriptionLocation = iota
	// DescriptionLocationBottom specifies printing out the help text at the bottom of the output
	DescriptionLocationBottom
)

type IntArg

type IntArg struct {
	// The argument name as will be shown in help messages
	Name string
	// The argument description as will be shown in help messages
	Desc string
	// A space separated list of environment variables names to be used to initialize this argument
	EnvVar string
	// The argument's initial value
	Value int
	// A boolean to display or not the current value of the argument in the help message
	HideValue bool
	// Set to true if this arg was set by the user (as opposed to being set from env or not set at all)
	SetByUser *bool
}

IntArg describes an int argument

type IntOpt

type IntOpt struct {
	// A space separated list of the option names *WITHOUT* the dashes, e.g. `f force` and *NOT* `-f --force`.
	// The one letter names will then be called with a single dash (short option), the others with two (long options).
	Name string
	// The option description as will be shown in help messages
	Desc string
	// A space separated list of environment variables names to be used to initialize this option
	EnvVar string
	// The option's initial value
	Value int
	// A boolean to display or not the current value of the option in the help message
	HideValue bool
	// Set to true if this option was set by the user (as opposed to being set from env or not set at all)
	SetByUser *bool
}

IntOpt describes an int option

type IntParam

type IntParam interface {
	// contains filtered or unexported methods
}

IntParam represents an Int option or argument

type IntsArg

type IntsArg struct {
	// The argument name as will be shown in help messages
	Name string
	// The argument description as will be shown in help messages
	Desc string
	// A space separated list of environment variables names to be used to initialize this argument.
	// The env variable should contain a comma separated list of values
	EnvVar string
	// The argument's initial value
	Value []int
	// A boolean to display or not the current value of the argument in the help message
	HideValue bool
	// Set to true if this arg was set by the user (as opposed to being set from env or not set at all)
	SetByUser *bool
}

IntsArg describes an int slice argument

type IntsOpt

type IntsOpt struct {
	// A space separated list of the option names *WITHOUT* the dashes, e.g. `f force` and *NOT* `-f --force`.
	// The one letter names will then be called with a single dash (short option), the others with two (long options).
	Name string
	// The option description as will be shown in help messages
	Desc string
	// A space separated list of environment variables names to be used to initialize this option.
	// The env variable should contain a comma separated list of values
	EnvVar string
	// The option's initial value
	Value []int
	// A boolean to display or not the current value of the option in the help message
	HideValue bool
	// Set to true if this option was set by the user (as opposed to being set from env or not set at all)
	SetByUser *bool
}

IntsOpt describes an int slice option

type IntsParam

type IntsParam interface {
	// contains filtered or unexported methods
}

IntsParam represents an int slice option or argument

type StringArg

type StringArg struct {
	// The argument name as will be shown in help messages
	Name string
	// The argument description as will be shown in help messages
	Desc string
	// A space separated list of environment variables names to be used to initialize this argument
	EnvVar string
	// The argument's initial value
	Value string
	// A boolean to display or not the current value of the argument in the help message
	HideValue bool
	// Set to true if this arg was set by the user (as opposed to being set from env or not set at all)
	SetByUser *bool
}

StringArg describes a string argument

type StringOpt

type StringOpt struct {
	// A space separated list of the option names *WITHOUT* the dashes, e.g. `f force` and *NOT* `-f --force`.
	// The one letter names will then be called with a single dash (short option), the others with two (long options).
	Name string
	// The option description as will be shown in help messages
	Desc string
	// A space separated list of environment variables names to be used to initialize this option
	EnvVar string
	// The option's initial value
	Value string
	// A boolean to display or not the current value of the option in the help message
	HideValue bool
	// Set to true if this option was set by the user (as opposed to being set from env or not set at all)
	SetByUser *bool
}

StringOpt describes a string option

type StringParam

type StringParam interface {
	// contains filtered or unexported methods
}

StringParam represents a String option or argument

type StringsArg

type StringsArg struct {
	// The argument name as will be shown in help messages
	Name string
	// The argument description as will be shown in help messages
	Desc string
	// A space separated list of environment variables names to be used to initialize this argument.
	// The env variable should contain a comma separated list of values
	EnvVar string
	// The argument's initial value
	Value []string
	// A boolean to display or not the current value of the argument in the help message
	HideValue bool
	// Set to true if this arg was set by the user (as opposed to being set from env or not set at all)
	SetByUser *bool
}

StringsArg describes a string slice argument

type StringsOpt

type StringsOpt struct {
	// A space separated list of the option names *WITHOUT* the dashes, e.g. `f force` and *NOT* `-f --force`.
	// The one letter names will then be called with a single dash (short option), the others with two (long options).
	Name string
	// The option description as will be shown in help messages
	Desc string
	// A space separated list of environment variables names to be used to initialize this option.
	// The env variable should contain a comma separated list of values
	EnvVar string
	// The option's initial value
	Value []string
	// A boolean to display or not the current value of the option in the help message
	HideValue bool
	// Set to true if this option was set by the user (as opposed to being set from env or not set at all)
	SetByUser *bool
}

StringsOpt describes a string slice option

type StringsParam

type StringsParam interface {
	// contains filtered or unexported methods
}

StringsParam represents a string slice option or argument

type VarArg

type VarArg struct {
	// A space separated list of the option names *WITHOUT* the dashes, e.g. `f force` and *NOT* `-f --force`.
	// The one letter names will then be called with a single dash (short option), the others with two (long options).
	Name string
	// The option description as will be shown in help messages
	Desc string
	// A space separated list of environment variables names to be used to initialize this option
	EnvVar string
	// A value implementing the flag.Value type (will hold the final value)
	Value flag.Value
	// A boolean to display or not the current value of the option in the help message
	HideValue bool
	// Set to true if this arg was set by the user (as opposed to being set from env or not set at all)
	SetByUser *bool
}

VarArg describes an argument where the type and format of the value is controlled by the developer

Example
package main

import (
	"fmt"
	"time"

	cli "github.com/jault3/mow.cli"
)

// Declare your type
type Duration time.Duration

// Make it implement flag.Value
func (d *Duration) Set(v string) error {
	parsed, err := time.ParseDuration(v)
	if err != nil {
		return err
	}
	*d = Duration(parsed)
	return nil
}

func (d *Duration) String() string {
	duration := time.Duration(*d)
	return duration.String()
}

func main() {

	app := cli.App("var", "Var arg example")

	// Declare a variable of your type
	duration := Duration(0)
	// Call one of the Var methods (arg, opt, ...) to declare your custom type
	app.VarArg("DURATION", &duration, "")

	app.Action = func() {
		// The variable will be populated after the app is ran
		fmt.Print(time.Duration(duration))
	}

	app.Run([]string{"cp", "1h31m42s"})
}
Output:

1h31m42s

type VarOpt

type VarOpt struct {
	// A space separated list of the option names *WITHOUT* the dashes, e.g. `f force` and *NOT* `-f --force`.
	// The one letter names will then be called with a single dash (short option), the others with two (long options).
	Name string
	// The option description as will be shown in help messages
	Desc string
	// A space separated list of environment variables names to be used to initialize this option
	EnvVar string
	// A value implementing the flag.Value type (will hold the final value)
	Value flag.Value
	// A boolean to display or not the current value of the option in the help message
	HideValue bool
	// Set to true if this option was set by the user (as opposed to being set from env or not set at all)
	SetByUser *bool
}

VarOpt describes an option where the type and format of the value is controlled by the developer

Example
package main

import (
	"fmt"

	cli "github.com/jault3/mow.cli"
)

// Declare your type
type Counter int

// Make it implement flag.Value
func (c *Counter) Set(v string) error {
	*c++
	return nil
}

func (c *Counter) String() string {
	return fmt.Sprintf("%d", *c)
}

// Make it a bool option
func (c *Counter) IsBoolFlag() bool {
	return true
}

func main() {

	app := cli.App("var", "Var opt example")

	// Declare a variable of your type
	verbosity := Counter(0)
	// Call one of the Var methods (arg, opt, ...) to declare your custom type
	app.VarOpt("v", &verbosity, "verbosity level")

	app.Action = func() {
		// The variable will be populated after the app is ran
		fmt.Print(verbosity)
	}

	app.Run([]string{"app", "-vvvvv"})
}
Output:

5

type VarParam

type VarParam interface {
	// contains filtered or unexported methods
}

VarParam represents an custom option or argument where the type and format are controlled by the developer

Jump to

Keyboard shortcuts

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