cli

package module
v1.1.0 Latest Latest
Warning

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

Go to latest
Published: Apr 4, 2026 License: MIT Imports: 13 Imported by: 0

README

Minimal Viable CLI

Implement a parser for CLI's like this:

  $ myapp prices sort=product
  $ myapp prices:add 3.14 "Best Product"

All flags are optional. All arguments are required.

Documentation

Overview

Package cli implements a minimal viable CLI library.

All flags are optional. All arguments are required.

Flags and argument functions follow the same patterns and support the same types as the standard library `flag`, with additions.

Example (BoolFlagExplicit)
package main

import (
	"fmt"

	cli "github.com/Minimal-Viable-Software/cli-go"
)

func main() {
	root := cli.NewApplication()
	var verbose bool
	root.BoolFlag(&verbose, "verbose", "Be verbose about it")

	root.Run(func() error {
		fmt.Println("verbose", verbose)
		return nil
	})

	root.Parse([]string{"verbose=false"})
}
Output:
verbose false
Example (CommandDispatch)
package main

import (
	"fmt"

	cli "github.com/Minimal-Viable-Software/cli-go"
)

type sortstr string

func (s *sortstr) Set(str string) error {
	*s = sortstr(str)
	return nil
}

func (s *sortstr) String() string {
	return string(*s)
}

func main() {
	root := cli.NewApplication()
	cmd := root.SubCommand("prices", "List prices")
	var sorting sortstr
	cmd.EnumFlag(&sorting, "sort", "Sort by (default: price)", "price", "product")
	var desc bool
	cmd.BoolFlag(&desc, "descending", "Sort descending instead of ascending")

	cmd.Run(func() error {
		fmt.Println("sort=" + sorting)
		fmt.Println("descending", desc)
		return nil
	})

	root.Parse([]string{"prices", "sort=product"})
}
Output:
sort=product
descending false
Example (DoubleHyphenTerminator)
package main

import (
	"fmt"

	cli "github.com/Minimal-Viable-Software/cli-go"
)

func main() {
	root := cli.NewApplication()
	var verbose bool
	root.BoolFlag(&verbose, "verbose", "Be verbose about it")
	var name string
	root.StringArg(&name, "name", "Your name")

	root.Run(func() error {
		fmt.Println("name=" + name)
		return nil
	})

	root.Parse([]string{"--", "verbose"})
}
Output:
name=verbose
Example (EnumArg)
package main

import (
	"fmt"
	"os"

	cli "github.com/Minimal-Viable-Software/cli-go"
)

type sortstr string

func (s *sortstr) Set(str string) error {
	*s = sortstr(str)
	return nil
}

func (s *sortstr) String() string {
	return string(*s)
}

func main() {
	root := cli.NewApplication()
	root.SetOutput(os.Stdout)

	cmd := root.SubCommand("query", "Run a query")
	var sort sortstr
	cmd.EnumArg(&sort, "sort", "Sort field", "price", "name")

	cmd.Run(func() error {
		fmt.Println("sort=" + sort)
		return nil
	})

	root.Parse([]string{"query", "price"})

	// Show help too
	root.Parse([]string{"help", "query"})
}
Output:
sort=price
query                Run a query
  <price|name:sort>  Sort field
Example (EnumValidation)
package main

import (
	"fmt"

	cli "github.com/Minimal-Viable-Software/cli-go"
)

type sortstr string

func (s *sortstr) Set(str string) error {
	*s = sortstr(str)
	return nil
}

func (s *sortstr) String() string {
	return string(*s)
}

func main() {
	root := cli.NewApplication()
	cmd := root.SubCommand("prices", "List prices")
	var sorting sortstr
	cmd.EnumFlag(&sorting, "sort", "Sort by (default: price)", "price", "product")

	err := root.Parse([]string{"prices", "sort=invalid"})
	fmt.Println(err)
}
Output:
invalid value "invalid" for flag "sort": enum must be one of: price, product
Example (ExtraArgs)
package main

import (
	"fmt"

	cli "github.com/Minimal-Viable-Software/cli-go"
)

func main() {
	root := cli.NewApplication()
	var name string
	root.StringArg(&name, "name", "Your name")

	err := root.Parse([]string{"Alice", "extra"})
	fmt.Println(err)
}
Output:
too many arguments: expected 1, got 2
Example (FlagsAnywhere)
package main

import (
	"fmt"

	cli "github.com/Minimal-Viable-Software/cli-go"
)

func main() {
	root := cli.NewApplication()
	var greeting string
	root.StringFlag(&greeting, "greeting", "A greeting")
	var a string
	root.StringArg(&a, "a", "First arg")
	var b string
	root.StringArg(&b, "b", "Second arg")

	root.Run(func() error {
		fmt.Println("a=" + a)
		fmt.Println("b=" + b)
		fmt.Println("greeting=" + greeting)
		return nil
	})

	root.Parse([]string{"hello", "greeting=hi", "world"})
}
Output:
a=hello
b=world
greeting=hi
Example (Help)
package main

import (
	"errors"
	"fmt"
	"os"

	cli "github.com/Minimal-Viable-Software/cli-go"
)

type sortstr string

func (s *sortstr) Set(str string) error {
	*s = sortstr(str)
	return nil
}

func (s *sortstr) String() string {
	return string(*s)
}

func main() {
	root := cli.NewApplication()
	root.SetOutput(os.Stdout)
	root.Help = "Tell me about your self!"

	age := -1
	root.IntFlag(&age, "age", "Your age.")
	var name string
	root.StringArg(&name, "name", "Your name")
	var verbose bool
	root.BoolFlag(&verbose, "verbose", "Be verbose about it")

	cmd := root.SubCommand("prices", "List prices")
	var sorting sortstr
	cmd.EnumFlag(&sorting, "sort", "Sort by (default: price)", "price", "product")
	var descending bool
	cmd.BoolFlag(&descending, "descending", "Sort descending instead of ascending")

	err := root.Parse([]string{"help"})
	if errors.Is(err, cli.ErrHelp) {
		fmt.Println("Help requested")
	}
}
Output:
Tell me about your self!

Options:
  age=<int>      Your age.
  verbose        Be verbose about it
  <string:name>  Your name

Commands:
  prices                List prices
    descending          Sort descending instead of ascending
    sort=price|product  Sort by (default: price)
Help requested
Example (HelpCommand)
package main

import (
	"errors"
	"fmt"
	"os"

	cli "github.com/Minimal-Viable-Software/cli-go"
)

type sortstr string

func (s *sortstr) Set(str string) error {
	*s = sortstr(str)
	return nil
}

func (s *sortstr) String() string {
	return string(*s)
}

func main() {
	root := cli.NewApplication()
	root.SetOutput(os.Stdout)

	cmd := root.SubCommand("prices", "List prices")
	var sorting sortstr
	cmd.EnumFlag(&sorting, "sort", "Sort by (default: price)", "price", "product")
	var descending bool
	cmd.BoolFlag(&descending, "descending", "Sort descending instead of ascending")

	err := root.Parse([]string{"help", "prices"})
	if errors.Is(err, cli.ErrHelp) {
		fmt.Println("Help requested")
	}
}
Output:
prices                List prices
  descending          Sort descending instead of ascending
  sort=price|product  Sort by (default: price)
Help requested
Example (MissingRequiredArg)
package main

import (
	"fmt"

	cli "github.com/Minimal-Viable-Software/cli-go"
)

func main() {
	root := cli.NewApplication()
	var name string
	root.StringArg(&name, "name", "Your name")

	err := root.Parse([]string{})
	fmt.Println(err)
}
Output:
missing required argument: name
Example (RootFlagsAndArgs)
package main

import (
	"fmt"

	cli "github.com/Minimal-Viable-Software/cli-go"
)

func main() {
	root := cli.NewApplication()

	age := -1
	root.IntFlag(&age, "age", "Your age.")
	var name string
	root.StringArg(&name, "name", "Your name")
	var verbose bool
	root.BoolFlag(&verbose, "verbose", "Be verbose about it")

	root.Run(func() error {
		fmt.Println("verbose", verbose)
		fmt.Println("name=" + name)
		fmt.Println("age=" + fmt.Sprint(age))
		return nil
	})

	root.Parse([]string{"verbose", "age=4", "Stewie"})
}
Output:
verbose true
name=Stewie
age=4
Example (RunFuncError)
package main

import (
	"errors"
	"fmt"

	cli "github.com/Minimal-Viable-Software/cli-go"
)

func main() {
	root := cli.NewApplication()
	var name string
	root.StringArg(&name, "name", "Your name")

	root.Run(func() error {
		return errors.New("app error")
	})

	err := root.Parse([]string{"Alice"})
	fmt.Println(err)
}
Output:
app error
Example (UnknownFlag)
package main

import (
	"fmt"

	cli "github.com/Minimal-Viable-Software/cli-go"
)

func main() {
	root := cli.NewApplication()
	var name string
	root.StringArg(&name, "name", "Your name")

	err := root.Parse([]string{"unknown=value"})
	fmt.Println(err)
}
Output:
unknown flag: unknown

Index

Examples

Constants

This section is empty.

Variables

View Source
var ErrHelp = errors.New("cli: help requested")

Sentinel errors.

Functions

This section is empty.

Types

type Application

type Application struct {
	Command

	Help string
	// contains filtered or unexported fields
}

Application defines a root command of a CLI and is the entry point for everything in this package.

func NewApplication

func NewApplication() *Application

NewApplication is where everything starts.

func (*Application) Output

func (a *Application) Output() io.Writer

Output returns the writer used for writing help text.

Defaults to stderr.

func (*Application) Parse

func (a *Application) Parse(args []string) error

Parse the given arguments and execute the appropriate command.

func (*Application) SetOutput

func (a *Application) SetOutput(w io.Writer)

SetOutput sets the writer used for writing help text.

func (*Application) SubCommand

func (a *Application) SubCommand(name, usage string) *Command

SubCommand registers a sub Command under the root.

There is no programmatic nesting of subcommands. All subcommands is added using this function. Subcommands can be nested semantically using colons: `users` and `users:add` (the help message groups these together).

type Argument

type Argument struct {
	Name     string     // name as it appears on command line
	Usage    string     // help message
	Value    flag.Value // value as set
	Position int        // position index, assigned by declaration order
}

Argument defines a required argument.

type Command

type Command struct {
	Name  string
	Usage string
	// contains filtered or unexported fields
}

Command represents a named command with its own set of flags and arguments.

func (*Command) Arg

func (c *Command) Arg(value flag.Value, name, usage string)

Arg defines a required argument at the next position for a custom flag.Value.

func (*Command) BoolFlag

func (c *Command) BoolFlag(p *bool, name string, usage string)

BoolFlag defines a bool flag with specified name and usage string.

func (*Command) BoolFuncFlag

func (c *Command) BoolFuncFlag(name, usage string, fn func(string) error)

BoolFuncFlag defines a bool flag with specified name and usage string. The flag does not require a pointer; instead fn is called with "true" when the flag is set.

func (*Command) DurationFlag

func (c *Command) DurationFlag(p *time.Duration, name string, usage string)

DurationFlag defines a time.Duration flag with specified name and usage string.

func (*Command) EnumArg

func (c *Command) EnumArg(value flag.Value, name, usage string, values ...string)

EnumArg defines a required argument at the next position, restricted to a set of allowed values.

Example
package main

import (
	"fmt"

	"github.com/Minimal-Viable-Software/cli-go"
)

type name string

func (n *name) Set(s string) error {
	*n = name(s)
	return nil
}

func (n *name) String() string {
	return string(*n)
}

func main() {
	app := cli.NewApplication()

	var player name
	app.EnumArg(&player, "name", "Choose your name", "Jack", "Will", "Barbarossa")

	app.Run(func() error {
		fmt.Printf("Hello, %s\n", player)
		return nil
	})

	app.Parse([]string{"Jack"})

	err := app.Parse([]string{})
	fmt.Println(err)

	err = app.Parse([]string{"Elizabeth"})
	fmt.Println(err)

}
Output:
Hello, Jack
missing required argument: name
invalid value "Elizabeth" for argument name: enum must be one of: Jack, Will, Barbarossa

func (*Command) EnumFlag

func (c *Command) EnumFlag(value flag.Value, name string, usage string, values ...string)

EnumFlag defines a flag restricted to a set of allowed values.

func (*Command) Flag

func (c *Command) Flag(value flag.Value, name string, usage string)

Flag defines a flag with specified name and usage string for a custom flag.Value.

func (*Command) Float64Arg

func (c *Command) Float64Arg(p *float64, name, usage string)

Float64Arg defines a required float64 argument at the next position.

func (*Command) Float64Flag

func (c *Command) Float64Flag(p *float64, name string, usage string)

Float64Flag defines a float64 flag with specified name and usage string.

func (*Command) FuncArg

func (c *Command) FuncArg(name, usage string, fn func(string) error)

FuncArg defines a required argument at the next position. The argument does not require a pointer; instead fn is called with the argument's value.

func (*Command) FuncFlag

func (c *Command) FuncFlag(name, usage string, fn func(string) error)

FuncFlag defines a flag with specified name and usage string. The flag does not require a pointer; instead fn is called with the flag's value.

func (*Command) Int64Arg

func (c *Command) Int64Arg(p *int64, name, usage string)

Int64Arg defines a required int64 argument at the next position.

func (*Command) Int64Flag

func (c *Command) Int64Flag(p *int64, name string, usage string)

Int64Flag defines an int64 flag with specified name and usage string.

func (*Command) IntArg

func (c *Command) IntArg(p *int, name, usage string)

IntArg defines a required int argument at the next position.

func (*Command) IntFlag

func (c *Command) IntFlag(p *int, name string, usage string)

IntFlag defines an int flag with specified name and usage string.

func (*Command) Run

func (c *Command) Run(fn RunFunc)

Run sets the function to execute when this command is invoked.

func (*Command) StringArg

func (c *Command) StringArg(p *string, name, usage string)

StringArg defines a required string argument at the next position.

func (*Command) StringFlag

func (c *Command) StringFlag(p *string, name string, usage string)

StringFlag defines a string flag with specified name and usage string.

func (*Command) TextArg

func (c *Command) TextArg(p encoding.TextUnmarshaler, name, usage string)

TextArg defines a required argument at the next position for a value implementing encoding.TextUnmarshaler.

Example
app := cli.NewApplication()

var ip net.IP
app.TextArg(&ip, "ip", "Your IP address")

app.Parse([]string{"127.0.0.1"})
fmt.Printf("IP: %v\n", ip)
Output:
IP: 127.0.0.1

func (*Command) TextFlag

func (c *Command) TextFlag(p encoding.TextUnmarshaler, name string, usage string)

TextFlag defines a flag with specified name and usage string for a value implementing encoding.TextUnmarshaler.

func (*Command) Uint64Arg

func (c *Command) Uint64Arg(p *uint64, name, usage string)

Uint64Arg defines a required uint64 argument at the next position.

func (*Command) Uint64Flag

func (c *Command) Uint64Flag(p *uint64, name string, usage string)

Uint64Flag defines a uint64 flag with specified name and usage string.

func (*Command) UintArg

func (c *Command) UintArg(p *uint, name, usage string)

UintArg defines a required uint argument at the next position.

func (*Command) UintFlag

func (c *Command) UintFlag(p *uint, name string, usage string)

UintFlag defines a uint flag with specified name and usage string.

type Flag

type Flag struct {
	Name     string     // name as it appears on command line
	Usage    string     // help message
	Value    flag.Value // value as set
	DefValue string     // default value (as text); for usage message
}

Flag defines an optional flag.

type Path added in v1.1.0

type Path string

Path is a CLI helper value for working with files and directories.

Example (Arg)
package main

import (
	"fmt"

	cli "github.com/Minimal-Viable-Software/cli-go"
)

func main() {
	app := cli.NewApplication()

	cmd := app.SubCommand("read", "Read a file")
	var path cli.Path
	cmd.Arg(&path, "file", "the file path")

	cmd.Run(func() error {
		fmt.Printf("path=%s\n", path)
		return nil
	})

	app.Parse([]string{"read", "/tmp/data.txt"})

}
Output:
path=/tmp/data.txt
Example (Flag)
package main

import (
	"fmt"

	cli "github.com/Minimal-Viable-Software/cli-go"
)

func main() {
	app := cli.NewApplication()

	cmd := app.SubCommand("write", "Write output")
	var path cli.Path
	cmd.Flag(&path, "output", "output path")

	cmd.Run(func() error {
		fmt.Printf("output=%s\n", path)
		return nil
	})

	app.Parse([]string{"write", "output=/tmp/out.txt"})

}
Output:
output=/tmp/out.txt
Example (Help)
package main

import (
	"os"

	cli "github.com/Minimal-Viable-Software/cli-go"
)

func main() {
	app := cli.NewApplication()
	app.SetOutput(os.Stdout)

	cmd := app.SubCommand("read", "Read a file")
	var path cli.Path
	cmd.Arg(&path, "file", "the file path")

	app.Parse([]string{"help", "read"})

}
Output:
read           Read a file
  <path:file>  the file path

func (*Path) Abs added in v1.1.0

func (p *Path) Abs() string

Abs returns the absolute path, or panic on any error.

func (*Path) Exists added in v1.1.0

func (p *Path) Exists() bool

Exists returns `true` if the path exists.

This always returns `false` if os.Stat fails, for any reason.

func (*Path) Get added in v1.1.0

func (p *Path) Get() any

Get returns the raw path string.

func (*Path) IsDir added in v1.1.0

func (p *Path) IsDir() bool

IsDir returns `true` if the path exists and is a directory.

This always returns `false` if os.Stat fails, for any reason.

func (*Path) IsRegularFile added in v1.1.0

func (p *Path) IsRegularFile() bool

IsRegularFile returns `true` if the path exists and is a regular file. That is, it tests that no mode type bits are set.

This always returns `false` if os.Stat fails, for any reason.

func (*Path) Name added in v1.1.0

func (p *Path) Name() string

Name returns the base name of the path.

func (*Path) Rel added in v1.1.0

func (p *Path) Rel(basePath string) string

Rel returns the path relative to current work directory, or panic on any error.

func (*Path) Set added in v1.1.0

func (p *Path) Set(s string) error

Set implements the flag.Value interface.

func (*Path) String added in v1.1.0

func (p *Path) String() string

String implements the flag.Value interface.

type RunFunc

type RunFunc func() error

RunFunc is the functions used to run commands.

Jump to

Keyboard shortcuts

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