clif

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

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

Go to latest
Published: Sep 29, 2015 License: MIT Imports: 14 Imported by: 3

README

status GoDoc

CLIF - Command line interface framework

Go framework for rapid command line application development.

Example

demo

package main

import "gopkg.in/ukautz/clif.v0"

func main() {
	clif.New("My App", "1.0.0", "An example application").
		New("hello", "The obligatory hello world", func(out clif.Output) {
			out.Printf("Hello World\n")
		}).
		Run()
}


Install

$ go get gopkg.in/ukautz/clif.v0

Getting started

One the one side, CLIF's builder-like API can be easily used for rapid development of small, single purpose tools. On the other side, CLIF is designed with complex console applications in mind.

Commands

Commands must have a unique name and can have additional arguments and options.

cmd1 := clif.NewCommand("name", "A description", callBackFunction)
cmd2 := clif.NewCommand("other", "Another description", callBackFunction2)

The name is used from the command line to call the command:

$ ./app name
$ ./app other
Callback functions

Callback functions can have arbitrary parameters. CLIF uses a small, built-in (signatur) injection container which allows you to register any kind of object (struct or interface) beforehand.

So you can register any object (interface{}, struct{} .. and anything else, see below) in your bootstrap and then "require" those instances by simply putting them in the command callback signature:

// Some type definition
type MyFoo struct {
    X int
}

func main() {
    // init cli
    cli := clif.New("My App", "1.0.0", "An example application")

    // register object instance with container
    foo := &MyFoo{X: 123}
    cli.Register(foo)

    // Create command with callback using the peviously registered instance
    cli.NewCommand("foo", "Call foo", func (foo *MyFoo) {
        // do something with foo
    })

    cli.Run()
}

Using interfaces is possible as well, but a bit less elegant:

// Some interface
type MyBar interface {
    Bar() string
}

// Some type
type MyFoo struct {
}

// implement interface
func (m *MyFoo) Bar() string {
    return "bar"
}

func main() {
    // init cli
    cli := clif.New("My App", "1.0.0", "An example application")

    // create object, which implements MyBar:
    foo := &MyFoo{}
    t := reflect.TypeOf((*MyBar)(nil)).Elem()
    cli.RegisterAs(t.String(), foo)

    // Register command with callback using the type
    cli.NewCommand("bar", "Call bar", func (bar MyBar) {
        // do something with bar
    })

    cli.Run()
}
Named

Everything works great if you only have a single instance of any object of a specific type. However, if you need more than one instance (which might often be the case for primitive types, such as int or string) you can use named registering:

// Register abitrary objects under unique name
cli.RegisterNamed("foo", new(MyFoo)).
    RegisterNamed("bar", 123).
    RegisterNamed("baz", "bla")

// Register command with callback named container
cli.NewCommand("bar", "Call bar", func (named clif.NamedParameters) {
    asMap := map[string]interface{}(named)
    fmt.Println(asMap["baz"].(string))
})

Note: If you want to use the named feature, you cannot Register() any NamedParameters instance yourself, since "normally" registered objects are evaluated before named.

Default objects

CLIF pre-populates the dependency container with a couple of built-in objects:

  • The Output (formatted output helper, see below), eg func (out clif.Output) { .. }
  • The Input (input helper, see below), eg func (in clif.Input) { .. }
  • The *Cli instance itself, eg func (c *clif.Cli) { .. }
  • The current *Command instance, eg func (o *clif.Command) { .. }
Arguments and Options

CLIF can deal with arguments and options. The difference being:

  • Arguments come after the command name. They are identified by their position.
  • Options have no fixed position. They are identified by their --opt-name (or alias, eg -O)
  • Both Arguments and Options come after the comand (eg ./my-cli command foo --bar baz)

Of course you can use arguments and options at the same time..

Arguments

Arguments are additional command line parameters which come after the command name itself.

cmd := clif.NewCommand("hello", "A description", callBackFunction)
	.NewArgument("name", "Name for greeting", "", true, false)

arg := cmd.NewAgument("other", "Something ..", "default", false, true)
cmd.AddArgument(arg)

Arguments consist of a name, a description, an optional default value a required flag and a multiple flag.

$ ./my-app hello the-name other1 other2 other3
#            ^      ^       ^       ^     ^
#            |      |       |       |     |
#            |      |       |       | third "other" arg
#            |      |       |  second "other" arg
#            |      |  first "other" arg
#            |  the "name" arg
#        command name

Position of arguments matters. Make sure you add them in the right order. And: required arguments must come before optional arguments (makes sense, right?). There can be only one multiple argument at all and, of course, it must be the last (think: variadic).

You can access the arguments by injecting the command instance *clif.Command into the callback and calling the Argument() method. You can choose to interpret the argument as String(), Int(), Float(), Bool(), Time() or Json(). Multiple arguments can be accessed with Strings(), Ints() .. and so on. Count() gives the amount of (provided) multiple arguments and Provided() returns bool for optional arguments. Please see parameter.go for more.

func callbackFunctionI(c *clif.Command) {
	// a single
	name := c.Argument("name").String()

	// a multiple
	others := c.Argument("other").Strings()

	// .. do something ..
}
Options

Options have no fixed position. They are referenced by their name (eg --name) or alias (eg -n).

cmd := clif.NewCommand("hello", "A description", callBackFunction)
	.NewOption("name", "n", "Name for greeting", "", true, false)

arg := cmd.NewOption("other", "O", "Something ..", "default", false, true)
cmd.AddOption(arg)

Now:

$ ./my-app hello --other bar -n Me -O foo
#                       ^       ^    ^
#                       |       |    |
#                       |       |  second other opt
#                       |   name opt
#                  first other opt

You can access options the same way as arguments, just use Option() instead.

func callbackFunctionI(c *clif.Command) {
	name := c.Option("name").String()
	others := c.Option("other").Strings()
	// .. do something ..
}
Flags

There is a special kind of option, which does not expect a parameter: the flag.

flag := clif.NewOption("my-flag", "f", "Something ..", "", false, false).IsFlag()
cmd := clif.NewCommand("hello", "A description", callBackFunction).AddOption(flag)

When using the option, you dont need to (nor can you) provide an argument:

$ ./my-app hello --my-flag

You want to use Bool() to check if a flag is provided:

func callbackFunctionI(c *clif.Command) {
	if c.Option("my-flag").Bool() {
		// ..
	}
}
Validation & (Parsing | Transformation)

You can validate/parse/transform the input using the Parse attribute of options or arguments. It can be (later on) set using the SetParse() method:

// Validation example
arg := clif.NewArgument("my-int", "An integer", "", true, false).
    SetParse(func(name, value string) (string, error) {
        if _, err := strconv.Atoi(value); err != nil {
            return "", fmt.Errorf("Oops: %s is not an integer: %s", name, err)
        } else {
            return value, nil
        }
    })

// Transformation example
opt := clif.NewOption("client-id", "c", "The client ID", "", true, false).
    SetParse(func(name, value string) (string, error) {
        if strings.Index(value, "#") != 0 {
            return fmt.Sprintf("#%s", value), nil
        } else {
            return value, nil
        }
    })

There are a few built-in validators you can use out of the box:

  • clif.IsInt - Checks for integer, eg clif.NewOption(..).SetParse(clif.IsInt)
  • clif.IsFloat - Checks for float, eg clif.NewOption(..).SetParse(clif.IsFloat)

See validators.go.

Environment variables & default

The argument and option constructors (NewArgument, NewOption) already allow you to set a default. In addition you can set the name of an environment variable, which will be used, if the parameter is not provided.

opt := clif.NewOption("client-id", "c", "The client ID", "", true, false).SetEnv("CLIENT_ID")

The order is:

  1. Provided, eg --config /path/to/config
  2. Environment variable, eg CONFIG_FILE
  3. Default value, as provided in constructor or set via SetDefault()

Note: A required parameter must have a value, but it does not care whether it came from input, via environment variable or as a default value.

Default options

Often you need one or multiple options on every or most commands. The usual --verbose or --config /path.. are common examples. CLIF provides two ways to deal with those.

  1. Modifying/extending clif.DefaultOptions (it's pre-filled with the --help option, which is clif.DefaultHelpOption)
  2. Calling AddDefaultOptions() or NewDefaultOption() on an instance of clif.Cli

The former is global (for any instance of clif.Cli) and assigned to any new command (created by the NewCommand constructor). The latter is applied when Run() is called and is in the scope of a single clif.Cli instance.

Note: A helpful patterns is combining default options and the injection container/registry. Following an example parsing a config file, which can be set on any command with --config /path.. or as an environment variable and has a default path.


type Conf struct {
    Foo string
    Bar string
}

func() main {

    // init new cli app
    cli := clif.New("my-app", "1.2.3", "My app that does something")

    // register default option, which fills injection container with config instance
    configOpt := clif.NewOption("config", "c", "Path to config file", "/default/config/path.json", true, false).
        SetEnv("MY_APP_CONFIG").
        SetParse(function(name, value string) (string, error) {
            conf := new(Conf)
            if raw, err := ioutil.ReadFile(value); err != nil {
                return "", fmt.Errorf("Could not read config file %s: %s", value, err)
            } else if err = json.Unmarshal(raw, conf); err != nil {
                return "", fmt.Errorf("Could not unmarshal config file %s: %s", value, err)
            } else if conf.Foo == "" {
                return "", fmt.Errorf("Config %s is missing \"foo\"", value)
            } else {
                // register *Conf
                cli.Register(conf)
                return value, nil
            }
        })
    cli.AddDefaultOptions(configOpt)

    // Since *Conf was registered it can be used in any callback
    cli.New("anything", "Does anything", func(conf *Conf) {
        // do something with conf
    })

    cli.Run()
}

Input & Output

Of course, you can just use fmt and os.Stdin, but for convenience (and fancy output) there are clif.Output and clif.Input.

Input

You can inject an instance of the clif.Input interface into your command callback. It provides small set of often used tools.

input

Ask & AskRegex

Just ask the user a question then read & check the input. The question will be asked until the check/requirement is satisfied (or the user exits out with ctrl+c):

func callbackFunctionI(in clif.Input) {
	// Any input is OK
	foo := in.Ask("What is a foo", nil)

	// Validate input
	name := in.Ask("Who are you? ", func(v string) error {
		if len(v) > 0 {
			return nil
		} else {
			return fmt.Errorf("Didn't catch that")
		}
	})

	// Shorthand for regex validation
	count := in.AskRegex("How many? ", regexp.MustCompile(`^[0-9]+$`))

	// ..
}

See clif.RenderAskQuestion for customization.

Confirm

Confirm() ask the user a question until it is answered with yes (or y) or no (or n) and returns the response as bool.

func callbackFunctionI(in clif.Input) {
	if in.Confirm("Let's do it?") {
		// ..
	}
}

See clif.ConfirmRejection, clif.ConfirmYesRegex and clif.ConfirmNoRegex for customization.

Choose

Choose() is like a select in HTML and provides a list of options with descriptions to the user. The user then must choose (type in) one of the options. The choices will be presented to the user until a valid choice (one of the options) is provided.

func callbackFunctionI(in clif.Input) {
	father := in.Choose("Who is your father?", map[string]string{
		"yoda":  "The small, green guy",
		"darth": "The one with the smoker voice and the dark cape!",
		"obi":   "The old man with the light thingy",
	})

	if father == "darth" {
		// ..
	}
}

See clif.RenderChooseQuestion, clif.RenderChooseOption and clif.RenderChooseQuery for customization.

Output & formatting

The clif.Output interface can be injected into any callback. It relies on a clif.Formatter, which does the actual formatting (eg colorizing) of the text.

Outputs

Per default, the clif.DefaultInput via clif.NewColorOutput() is used. It uses clif.DefaultStyles, which look like the screenshots you are seeing in this readme.

You can change the output like so:

cli := clif.New(..)
cli.SetOutput(clif.NewColorOutput().
    SetFormatter(clif.NewDefaultFormatter(clif.SunburnStyles))
Styles

Styles are applied by parsing (replacing) tokens like <error>, which would be substitude with \033[31;1m (using the default styles) resulting in a red coloring. Another example is <reset>, which is replaced with \033[0m leading to reset all colorings & styles.

There three built-in color styles (of course, you can extend them or add your own):

  1. DefaultStyles - as you can see on this page
  2. SunburnStyles - more yellow'ish
  3. WinterStyles - more blue'ish

Real-life example

To provide you a usful'ish example, I've written a small CLI application called repos.

See also

There are a lot of other approaches you should have a look at.

Documentation

Overview

Console Line Input Framework for rapid development of small or large scale CLI applications.

See the Github page for a full documentation with examples and patterns (https://github.com/ukautz/clif).

clif's design was influenced by Symfony Console (http://symfony.com/doc/current/components/console/introduction.html).

Index

Constants

This section is empty.

Variables

View Source
var ConfirmNoRegex = regexp.MustCompile(`^(?i)no?$`)

ConfirmNoRegex is the regular expression used to check if the user replied negative

View Source
var ConfirmRejection = "<warn>Please respond with \"yes\" or \"no\"<reset>\n\n"

ConfirmRejection is the message replied to the user if she does not answer with "yes", "y", "no" or "n" (case insensitive)

View Source
var ConfirmYesRegex = regexp.MustCompile(`^(?i)y(es)?$`)

ConfirmYesRegex is the regular expression used to check if the user replied positive

View Source
var DefaultFormatterEscape = func(msg string) string {
	return DefaultFormatterTokenRegex.ReplaceAllStringFunc(msg, func(token string) string {
		return `\` + token
	})
}

DefaultFormatterEscape is a callback to replace all tokens with escaped versions

View Source
var DefaultFormatterPost = func(msg string) string {
	return strings.Replace(msg, "~~~~#~~~~", "<", -1)
}

DefaultFormatterPost is a post-callback, after DefaultFormatterTokenRegex is used

View Source
var DefaultFormatterPre = func(msg string) string {
	return strings.Replace(msg, `\<`, "~~~~#~~~~", -1)
}

DefaultFormatterPre is a pre-callback, before DefaultFormatterTokenRegex is used

View Source
var DefaultFormatterTokenRegex = regexp.MustCompile(`(<[^>]+>)`)

DefaultFormatterTokenRegex is a regex to find all tokens, used by the DefaultFormatter

View Source
var DefaultHelpOption = &Option{
	parameter: parameter{
		Name:        "help",
		Usage:       "Display this help message",
		Description: "Display this help message",
	},
	Alias: "h",
	Flag:  true,
}

DefaultHelpOption is the "--help" option, which is (per default) added to any command.

View Source
var DefaultOptions = []*Option{DefaultHelpOption}

DefaultOptions are prepended to any newly created command. Will be added immediately in the `NewCommand` call. See also `cli.NewDefaultOption()` and `cli.AddDefaultOptions()`.

View Source
var DefaultStyles = map[string]string{
	"error":     "\033[31;1m",
	"warn":      "\033[33m",
	"info":      "\033[34m",
	"success":   "\033[32m",
	"debug":     "\033[30;1m",
	"headline":  "\033[4;1m",
	"subline":   "\033[4m",
	"important": "\033[47;30;1m",
	"query":     "\033[36m",
	"reset":     "\033[0m",
}
View Source
var DescribeCli = func(c *Cli) string {

	line := "<headline>" + c.Name + "<reset>"
	if c.Version != "" {
		line += " <debug>(" + c.Version + ")<reset>"
	}
	lines := []string{line}

	if c.Description != "" {
		lines = append(lines, "<info>"+c.Description+"<reset>\n")
	}

	prog := filepath.Base(os.Args[0])
	lines = append(lines, fmt.Sprintf("<subline>Usage:<reset>\n  %s command [arg ..] [--opt val ..]\n", prog))

	lines = append(lines, "<subline>Available commands:<reset>")
	max := 0
	ordered := make(map[string][]*Command)
	prefices := make([]string, 0)
	for _, cmd := range c.Commands {
		if l := len(cmd.Name); l > max {
			max = l
		}
		prefix := ""
		if i := strings.Index(cmd.Name, ":"); i > -1 {
			prefix = cmd.Name[0:i]
		}
		if ordered[prefix] == nil {
			prefices = append(prefices, prefix)
			ordered[prefix] = make([]*Command, 0)
		}
		ordered[prefix] = append(ordered[prefix], cmd)
	}
	sort.Strings(prefices)
	for _, prefix := range prefices {
		if prefix != "" {
			lines = append(lines, fmt.Sprintf(" <subline>%s<reset>", prefix))
		}
		sort.Sort(CommandsSort(ordered[prefix]))
		for _, cmd := range ordered[prefix] {
			lines = append(lines, fmt.Sprintf("  <info>%-"+fmt.Sprintf("%d", max)+"s<reset>  %s", cmd.Name, cmd.Usage))
		}
	}

	return strings.Join(lines, "\n") + "\n"
}

DescribeCli command implements the string rendering of a cli which help uses. Can be overwritten at users discretion.

View Source
var DescribeCommand = func(c *Command) string {
	lines := []string{"Command: <headline>" + c.Name + "<reset>"}

	if c.Description != "" {
		lines = append(lines, []string{"<info>" + c.Description + "<reset>", ""}...)
	} else if c.Usage != "" {
		lines = append(lines, []string{"<info>" + c.Usage + "<reset>", ""}...)
	}

	lines = append(lines, "<subline>Usage:<reset>")
	usage := []string{c.Name}
	args := make([][]string, 0)
	argMax := 0
	opts := make([][]string, 0)
	optMax := 0
	for _, p := range c.Arguments {
		var short string
		usg := p.Usage
		short = p.Name
		usgInfo := []string{}
		if p.Multiple {
			short = short + " ..."
			usgInfo = append(usgInfo, `<debug>mult<reset>`)
		}
		if p.Required {
			usgInfo = append(usgInfo, `<important>req<reset>`)
		} else {
			short = fmt.Sprintf("[%s]", short)
		}
		if p.Env != "" {
			usgInfo = append(usgInfo, fmt.Sprintf(`env: <debug>%s<reset>`, p.Env))
		}
		if p.Default != "" {
			usgInfo = append(usgInfo, fmt.Sprintf(`default: <debug>"%s"<reset>`, p.Default))
		}
		if l := len(p.Name); l > argMax {
			argMax = l
		}
		usage = append(usage, short)
		if len(usgInfo) > 0 {
			usg += " (" + strings.Join(usgInfo, ", ") + ")"
		}
		args = append(args, []string{p.Name, usg})
	}

	for _, p := range c.Options {
		short := fmt.Sprintf("--%s", p.Name)
		if p.Alias != "" {
			short += "|-" + p.Alias
		}
		if !p.Flag {
			short += " val"
		}
		long := short
		usg := p.Usage
		usgInfo := []string{}
		if p.Multiple {
			short = short + " ..."
			usgInfo = append(usgInfo, `<debug>mult<reset>`)
		}
		if !p.Required {
			short = "[" + short + "]"
		} else {
			usgInfo = append(usgInfo, `<important>req<reset>`)
		}
		if p.Env != "" {
			usgInfo = append(usgInfo, fmt.Sprintf(`env: <debug>%s<reset>`, p.Env))
		}
		if p.Default != "" {
			usgInfo = append(usgInfo, fmt.Sprintf(`default: <debug>"%s"<reset>`, p.Default))
		}
		if l := len(long); l > optMax {
			optMax = l
		}
		usage = append(usage, short)
		if len(usgInfo) > 0 {
			usg += " (" + strings.Join(usgInfo, ", ") + ")"
		}
		opts = append(opts, []string{long, usg})
	}
	lines = append(lines, "  "+strings.Join(usage, " "))
	lines = append(lines, "")

	if len(args) > 0 {
		lines = append(lines, "<subline>Arguments:<reset>")
		for _, l := range args {
			lines = append(lines, fmt.Sprintf("  <info>%-"+fmt.Sprintf("%d", argMax)+"s<reset>  %s", l[0], l[1]))
		}
		lines = append(lines, "")
	}

	if len(opts) > 0 {
		lines = append(lines, "<subline>Options:<reset>")
		for _, l := range opts {
			lines = append(lines, fmt.Sprintf("  <info>%-"+fmt.Sprintf("%d", optMax)+"s<reset>  %s", l[0], l[1]))
		}
		lines = append(lines, "")
	}

	return strings.Join(lines, "\n") + "\n"
}

DescribeCommand implements the string rendering of a command which help uses. Can be overwritten at users discretion.

View Source
var Die = func(msg string, args ...interface{}) {
	NewColorOutput(os.Stderr).Printf("<error>"+msg+"<reset>\n", args...)
	Exit(1)
}

Die is the default function executed on die. It can be used as a shorthand via `clif.Die("foo %s", "bar")` and can be overwritten to change the failure exit handling CLI-wide.

View Source
var Exit = func(s int) {
	os.Exit(s)
}

Exit is wrapper for os.Exit, so it can be overwritten for tests or edge use cases

View Source
var RenderAskQuestion = func(question string) string {
	return "<query>" + strings.TrimRight(question, " ") + "<reset> "
}
View Source
var RenderChooseOption = func(key, value string, size int) string {
	return fmt.Sprintf("  <query>%-"+fmt.Sprintf("%d", size+1)+"s<reset> %s\n", key+")", value)
}

RenderChooseOption is the method used by default input `Choose()` method to to render a singular choice into a string. Can be overwritten at users discretion.

View Source
var RenderChooseQuery = func() string {
	return "Choose: "
}

RenderChooseQuery is the method used by default input `Choose()` method to to render the query prompt choice (after the choices) into a string. Can be overwritten at users discretion.

View Source
var RenderChooseQuestion = func(question string) string {
	return question + "\n"
}

RenderChooseQuestion is the method used by default input `Choose()` method to to render the question (displayed before listing the choices) into a string. Can be overwritten at users discretion.

View Source
var SunburnStyles = map[string]string{
	"error":     "\033[97;48;5;196;1m",
	"warn":      "\033[30;48;5;208;2m",
	"info":      "\033[38;5;142;2m",
	"success":   "\033[38;5;2;2m",
	"debug":     "\033[38;5;242;2m",
	"headline":  "\033[38;5;226;1m",
	"subline":   "\033[38;5;228;1m",
	"important": "\033[38;5;15;2;4m",
	"query":     "\033[38;5;77m",
	"reset":     "\033[0m",
}

http://misc.flogisoft.com/bash/tip_colors_and_formatting#colors1

View Source
var WinterStyles = map[string]string{
	"error":     "\033[97;48;5;89;1m",
	"warn":      "\033[30;48;5;97;2m",
	"info":      "\033[38;5;69;2m",
	"success":   "\033[38;5;45;1m",
	"debug":     "\033[38;5;239;2m",
	"headline":  "\033[38;5;21;1m",
	"subline":   "\033[38;5;27;1m",
	"important": "\033[38;5;15;2;4m",
	"query":     "\033[38;5;111m",
	"reset":     "\033[0m",
}

http://misc.flogisoft.com/bash/tip_colors_and_formatting#colors1

Functions

func InputAny

func InputAny(s string) error

func InputEmptyOk

func InputEmptyOk(s string) error

func IsFloat

func IsFloat(name, value string) (string, error)

IsFloat checks if value is float

func IsInt

func IsInt(name, value string) (string, error)

IsInt checks if value is an integer

Types

type Argument

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

Arguments must be provided immediately after the command in the order they were added. Non required arguments must be ordered after required arguments. Only one argument is allowed to contain multiple values and it needs to be the last one.

func NewArgument

func NewArgument(name, usage, _default string, required, multiple bool) *Argument

NewArgument constructs a new argument

func (*Argument) Assign

func (this *Argument) Assign(val string) error

Assign tries to add value to parameter and returns error if it fails due to invalid format or invalid amount (single vs multiple parameters)

func (*Argument) Bool

func (this *Argument) Bool() bool

Bool representation of the value (will be false, if not given or not parsable)

func (*Argument) Bools

func (this *Argument) Bools() []bool

Bools returns values as bool array (values will be false, if not parsable to float64)

func (*Argument) Count

func (this *Argument) Count() int

Provided returns amount of values provided

func (*Argument) Float

func (this *Argument) Float() float64

Float representation of the value (will be 0.0, if not given or not parsable)

func (*Argument) Floats

func (this *Argument) Floats() []float64

Floats returns values as float64 array (values will be 0.0, if not parsable to float64)

func (*Argument) Int

func (this *Argument) Int() int

Int representation of the value (will be 0, if not given or not parsable)

func (*Argument) Ints

func (this *Argument) Ints() []int

Ints returns values as int array (values will be 0, if not parsable to int)

func (*Argument) Json

func (this *Argument) Json() (map[string]interface{}, error)

Json assumes the input is a JSON string and parses into a standard map[string]interface{} Returns error, if not parsable (or eg array JSON).

Helpful to allow complex inputs: `my-app do --foo '{"bar": "baz"}'`

func (*Argument) Jsons

func (this *Argument) Jsons() ([]map[string]interface{}, error)

Jsons returns values as individual JSON strings. See `Json()` above.

func (*Argument) Provided

func (this *Argument) Provided() bool

Provided returns bool whether argument was provided

func (*Argument) SetDefault

func (this *Argument) SetDefault(v string) *Argument

SetDefault is a builder method to set default value. Default value is used if the argument is not provided (after environment variable).

func (*Argument) SetDescription

func (this *Argument) SetDescription(v string) *Argument

SetDescription is a builder method to sets argument description. Description is an elaborate explanation which is used in help generation.

func (*Argument) SetEnv

func (this *Argument) SetEnv(v string) *Argument

SetEnv is a builder method to set environment variable name, from which to take the value, if not provided (before default).

func (*Argument) SetParse

func (this *Argument) SetParse(v ParseMethod) *Argument

SetParse is a builder method to set setup call on value. The setup call must return a replace value (can be unchanged) or an error, which stops evaluation and returns error to user.

func (*Argument) SetRegex

func (this *Argument) SetRegex(r *regexp.Regexp) *Argument

SetRegex is a builder method to set regular expression which is used to check the the argument input (in case of multiple: each will be checked)

func (*Argument) SetUsage

func (this *Argument) SetUsage(v string) *Argument

SetUsage is builder method to set the usage description. Usage is a short account of what the argument is used for, for help generaiton.

func (*Argument) String

func (this *Argument) String() string

String representation of the value (can be empty string)

func (*Argument) Strings

func (this *Argument) Strings() []string

Strings returns values as array of strings

func (*Argument) Time

func (this *Argument) Time(format ...string) (*time.Time, error)

Time is a date time representation of the value with a provided format. If no format is provided, then `2006-01-02 15:04:05` will be used

func (*Argument) Times

func (this *Argument) Times(format ...string) ([]time.Time, error)

Times returns array for `time.Time` values, parsed from provided format. See `Time()`.

type CallMethod

type CallMethod interface{}

CallMethod is the interface for functions used as command callbacks. `interface{}` is used so that those functions can have arbitrary input and output signatures. However, they still must be functions.

type Cli

type Cli struct {

	// Name is the name of the console application used in the generated help
	Name string

	// Version is used in the generated help
	Version string

	// Description is used in the generated help
	Description string

	// Commands contain all registered commands and can be manipulated directly
	Commands map[string]*Command

	// Heralds contain list of command-create-callbacks which will be executed on `Run()`
	Heralds []HeraldCallback

	// Registry is a container holding objects for injection
	Registry *Registry

	// DefaultOptions contains options which are added to all commands early in the `Run()` call.
	DefaultOptions []*Option

	// DefaultCommand contains name of the command which is executed if non is given. Defaults to "list"
	DefaultCommand string
	// contains filtered or unexported fields
}

Cli is a command line interface object

func New

func New(name, version, desc string) *Cli

New constructs new cli

func (*Cli) Add

func (this *Cli) Add(cmd ...*Command) *Cli

Add is a builder method for adding a new command

func (*Cli) AddDefaultOptions

func (this *Cli) AddDefaultOptions(opts ...*Option) *Cli

AddDefaultOptions adds a list of options to default options.

func (*Cli) Call

func (this *Cli) Call(c *Command) ([]reflect.Value, error)

Call executes command by building all input parameters based on objects registered in the container and running the callback.

func (*Cli) Herald

func (this *Cli) Herald(cmd ...HeraldCallback) *Cli

Herald registers command constructors, which will be executed in `Run()`.

func (*Cli) New

func (this *Cli) New(name, usage string, call CallMethod) *Cli

New creates and adds a new command

func (*Cli) NewDefaultOption

func (this *Cli) NewDefaultOption(name, alias, usage, _default string, required, multiple bool) *Cli

NewDefaultOption creates and adds a new option to default list.

func (*Cli) Output

func (this *Cli) Output() Output

Output is shorthand for currently registered output

func (*Cli) Register

func (this *Cli) Register(v interface{}) *Cli

RegisterAs is builder method and registers object in registry

func (*Cli) RegisterAs

func (this *Cli) RegisterAs(n string, v interface{}) *Cli

RegisterAs is builder method and registers object under alias in registry

func (*Cli) RegisterNamed

func (this *Cli) RegisterNamed(n string, v interface{}) *Cli

RegisterNamed registers a parameter for injecting in a named map[string]inteface{}

func (*Cli) Run

func (this *Cli) Run()

Run with OS command line arguments

func (*Cli) RunWith

func (this *Cli) RunWith(args []string)

RunWith runs the cli with custom list of arguments

func (*Cli) SetDefaultCommand

func (this *Cli) SetDefaultCommand(v string) *Cli

SetDefaultCommand is builder method and overwrites the default command ("list") with something else

func (*Cli) SetDescription

func (this *Cli) SetDescription(v string) *Cli

SetDescription is builder method and sets description

func (*Cli) SetInput

func (this *Cli) SetInput(in Input) *Cli

SetOutput is builder method and replaces current input

func (*Cli) SetOnInterrupt

func (this *Cli) SetOnInterrupt(cb func() error) *Cli

SetOnInterrupt sets callback for interrupt signal (ctrl+c)

func (*Cli) SetOutput

func (this *Cli) SetOutput(out Output) *Cli

SetOutput is builder method and replaces current output

type Command

type Command struct {

	// Cli back-references the Cli in which the command is registered
	Cli *Cli

	// Name is the unique (within Cli scope) call-name of the command
	Name string

	// Usage is a shorthand description of what the command does. Used in help output.
	Usage string

	// Description is a long elaboration on what the command does. Used in help output.
	Description string

	// Options contain all the registered options of the command.
	Options []*Option

	// Arguments contain all the registered arguments of the command.
	Arguments []*Argument

	// Call holds reflections of the callback.
	Call reflect.Value
}

Command represents a named callback with a set of arguments and options

func NewCommand

func NewCommand(name, usage string, call CallMethod) *Command

NewCommand constructs a new command

func NewHelpCommand

func NewHelpCommand() *Command

NewHelpCommand returns the default help command

func NewListCommand

func NewListCommand() *Command

NewListCommand returns the default help command

func (*Command) AddArgument

func (this *Command) AddArgument(v *Argument) *Command

AddArgument is builder method to add a new argument

func (*Command) AddOption

func (this *Command) AddOption(v *Option) *Command

AddOption is builder method to add a new option

func (*Command) Argument

func (this *Command) Argument(name string) *Argument

Argument provides access to registered, named arguments.

func (*Command) Input

func (this *Command) Input() map[string][]string

Input returns map containing whole input values (of all options, all arguments)

func (*Command) NewArgument

func (this *Command) NewArgument(name, usage, _default string, required, multiple bool) *Command

NewArgument is builder method to construct and add a new argument

func (*Command) NewOption

func (this *Command) NewOption(name, alias, usage, _default string, required, multiple bool) *Command

NewOption is builder method to construct and add a new option

func (*Command) Option

func (this *Command) Option(name string) *Option

Option provides access to registered, named options.

func (*Command) Parse

func (this *Command) Parse(args []string) error

Parse extracts options and arguments from command line arguments

func (*Command) SetCli

func (this *Command) SetCli(c *Cli) *Command

SetCli is builder method and sets the Cli back-reference

func (*Command) SetDescription

func (this *Command) SetDescription(desc string) *Command

SetDescription is builder method setting description

type CommandsSort

type CommandsSort []*Command

CommandSort implements the `sort.Sortable` interface for commands, based on the command `Name` attribute

func (CommandsSort) Len

func (this CommandsSort) Len() int

func (CommandsSort) Less

func (this CommandsSort) Less(i, j int) bool

func (CommandsSort) Swap

func (this CommandsSort) Swap(i, j int)

type DefaultFormatter

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

DefaultFormatter strips all formatting from the output message

func NewDefaultFormatter

func NewDefaultFormatter(styles map[string]string) *DefaultFormatter

NewDefaultFormatter constructs a new constructor with the given styles

func (*DefaultFormatter) Escape

func (this *DefaultFormatter) Escape(msg string) string

func (*DefaultFormatter) Format

func (this *DefaultFormatter) Format(msg string) string

type DefaultInput

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

DefaultInput is the default used input implementation

func NewDefaultInput

func NewDefaultInput(in io.Reader, out Output) *DefaultInput

NewDefaultInput constructs a new default input implementation on given io reader (if nil, fall back to `os.Stdin`). Requires Output for issuing questions to user.

func (*DefaultInput) Ask

func (this *DefaultInput) Ask(question string, check func(string) error) string

func (*DefaultInput) AskRegex

func (this *DefaultInput) AskRegex(question string, rx *regexp.Regexp) string

func (*DefaultInput) Choose

func (this *DefaultInput) Choose(question string, choices map[string]string) string

func (*DefaultInput) Confirm

func (this *DefaultInput) Confirm(question string) bool

type DefaultOutput

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

DefaultOutput is the default used output type

func NewColorOutput

func NewColorOutput(io io.Writer) *DefaultOutput

NewColoredOutput returns default output (on `os.Stdout`, if io is nil) using a formatter which applies the default color styles to style tokens on output.

func NewMonochromeOutput

func NewMonochromeOutput(io io.Writer) *DefaultOutput

NewMonochromeOutput returns default output (on `os.Stdout`, if io is nil) using a formatter which strips all style tokens (hence rendering non-colored, plain strings)

func NewOutput

func NewOutput(io io.Writer, f Formatter) *DefaultOutput

NewOutput generates a new (default) output with provided io writer (if nil then `os.Stdout` is used) and a formatter

func (*DefaultOutput) Escape

func (this *DefaultOutput) Escape(msg string) string

func (*DefaultOutput) Printf

func (this *DefaultOutput) Printf(msg string, args ...interface{})

func (*DefaultOutput) SetFormatter

func (this *DefaultOutput) SetFormatter(f Formatter) Output

func (*DefaultOutput) Sprintf

func (this *DefaultOutput) Sprintf(msg string, args ...interface{}) string

type Formatter

type Formatter interface {

	// Escape escapes a string, so that no formatter tokens will be interpolated (eg `<foo>` -> `\<foo>`)
	Escape(msg string) string

	// Format renders message for output by applying <style> tokens
	Format(msg string) string
}

Formatter is used by Output for rendering. It supports style directives in the form <info> or <end> or suchlike

type HeraldCallback

type HeraldCallback func(*Cli) *Command

HeraldCallback is type for creator method, which can be registered with the `Herald()` method.

type Input

type Input interface {

	// Ask prints question to user and then reads user input and returns as soon
	// as it's non empty or queries again until it is
	Ask(question string, check func(string) error) string

	// AskRegex prints question to user and then reads user input, compares it
	// against regex and return if matching or queries again until it does
	AskRegex(question string, rx *regexp.Regexp) string

	// Choose renders choices for user and returns what was choosen
	Choose(question string, choices map[string]string) string

	// Confirm prints question to user until she replies with "yes", "y", "no" or "n"
	Confirm(question string) bool
}

Input is an interface for input helping. It provides shorthand methods for often used CLI interactions.

type NamedParameters

type NamedParameters map[string]interface{}

NamedParameters ...

type Option

type Option struct {

	// Alias can be a shorter name
	Alias string

	// If is a flag, then no value can be assigned (if present, then bool true)
	Flag bool
	// contains filtered or unexported fields
}

Option is a user input which is initialized with a single or double dash (eg "--foo" or "-f"). It may not be followed by a value, in which case it is considered a flag (see `IsFlag`). Options can be multiple inputs (no restrictions as there are for Arguments). An option can be required or optional. Options do not need to have any particular order.

func NewOption

func NewOption(name, alias, usage, _default string, required, multiple bool) *Option

NewOption constructs new option

func (*Option) Assign

func (this *Option) Assign(val string) error

Assign tries to add value to parameter and returns error if it fails due to invalid format or invalid amount (single vs multiple parameters)

func (*Option) Bool

func (this *Option) Bool() bool

Bool representation of the value (will be false, if not given or not parsable)

func (*Option) Bools

func (this *Option) Bools() []bool

Bools returns values as bool array (values will be false, if not parsable to float64)

func (*Option) Count

func (this *Option) Count() int

Provided returns amount of values provided

func (*Option) Float

func (this *Option) Float() float64

Float representation of the value (will be 0.0, if not given or not parsable)

func (*Option) Floats

func (this *Option) Floats() []float64

Floats returns values as float64 array (values will be 0.0, if not parsable to float64)

func (*Option) Int

func (this *Option) Int() int

Int representation of the value (will be 0, if not given or not parsable)

func (*Option) Ints

func (this *Option) Ints() []int

Ints returns values as int array (values will be 0, if not parsable to int)

func (*Option) IsFlag

func (this *Option) IsFlag() *Option

IsFlag marks an option as a flag. A Flag does not have any values. If it exists (eg "--verbose"), then it is automatically initialized with the string "true", which then can be checked with the `Bool()` method for actual `bool`

func (*Option) Json

func (this *Option) Json() (map[string]interface{}, error)

Json assumes the input is a JSON string and parses into a standard map[string]interface{} Returns error, if not parsable (or eg array JSON).

Helpful to allow complex inputs: `my-app do --foo '{"bar": "baz"}'`

func (*Option) Jsons

func (this *Option) Jsons() ([]map[string]interface{}, error)

Jsons returns values as individual JSON strings. See `Json()` above.

func (*Option) Provided

func (this *Option) Provided() bool

Provided returns bool whether argument was provided

func (*Option) SetDefault

func (this *Option) SetDefault(v string) *Option

SetDefault is a builder method to set default value. Default value is used if the option is not provided (after environment variable).

func (*Option) SetDescription

func (this *Option) SetDescription(v string) *Option

SetDescription is a builder method to sets option description. Description is an elaborate explanation which is used in help generation.

func (*Option) SetEnv

func (this *Option) SetEnv(v string) *Option

SetEnv is a builder method to set environment variable name, from which to take the value, if not provided (before default).

func (*Option) SetParse

func (this *Option) SetParse(v ParseMethod) *Option

SetParse is a builder method to set setup call on value. The setup call must return a replace value (can be unchanged) or an error, which stops evaluation and returns error to user.

func (*Option) SetRegex

func (this *Option) SetRegex(r *regexp.Regexp) *Option

SetRegex is a builder method to set regular expression which is used to check the the option input (in case of multiple: each will be checked)

func (*Option) SetUsage

func (this *Option) SetUsage(v string) *Option

SetUsage is builder method to set the usage description. Usage is a short account of what the option is used for, for help generaiton.

func (*Option) String

func (this *Option) String() string

String representation of the value (can be empty string)

func (*Option) Strings

func (this *Option) Strings() []string

Strings returns values as array of strings

func (*Option) Time

func (this *Option) Time(format ...string) (*time.Time, error)

Time is a date time representation of the value with a provided format. If no format is provided, then `2006-01-02 15:04:05` will be used

func (*Option) Times

func (this *Option) Times(format ...string) ([]time.Time, error)

Times returns array for `time.Time` values, parsed from provided format. See `Time()`.

type Output

type Output interface {

	// Escape escapes a string, so that no formatter tokens will be interpolated (eg `<foo>` -> `\<foo>`)
	Escape(s string) string

	// Printf applies format (renders styles) and writes to output
	Printf(msg string, args ...interface{})

	// Sprintf applies format (renders styles) and returns as string
	Sprintf(msg string, args ...interface{}) string

	// SetFormatter is builder method and replaces current formatter
	SetFormatter(f Formatter) Output
}

Output is interface for

type ParseMethod

type ParseMethod func(name, value string) (string, error)

SetupMethod is type for callback on Setup of Argument or Option. The return string replaces the original input. Called on each value (in case of multiple).

func IsAll

func IsAll(v ...ParseMethod) ParseMethod

IsAll joins a set of validators methods and returns true if ALL of them match

func IsAny

func IsAny(v ...ParseMethod) ParseMethod

IsAny joins a set of validator methods and returns true if ANY of them matches

type ReduceMethod

type ReduceMethod func(name string, value interface{}) bool

ReduceMethod is type of the callback of the `Reduce` and `ReduceAsync` methods

type Registry

type Registry struct {
	Container map[string]reflect.Value
}

Registry is a small container holding objects which are injected into command calls.

func NewRegistry

func NewRegistry() *Registry

NewRegistry constructs new, empty registry

func (*Registry) Alias

func (this *Registry) Alias(alias string, v interface{})

Alias registers an object under a different name. Eg for interfaces.

func (*Registry) Get

func (this *Registry) Get(s string) reflect.Value

Get returns registered object by their type name (`reflect.TypeOf(..).String()`)

func (*Registry) Has

func (this *Registry) Has(s string) bool

Has checks whether a requested type is registered

func (*Registry) Names

func (this *Registry) Names() []string

Names returns sorted (asc) list of registered names

func (*Registry) Reduce

func (this *Registry) Reduce(cb ReduceMethod) []interface{}

Reduce calls a bool-returning function on all registered objects in alphanumerical order and returns all selected as a slice

func (*Registry) ReduceAsync

func (this *Registry) ReduceAsync(cb ReduceMethod) chan interface{}

ReduceAsync calls a bool-returning function on all registered objects concurrently and writes all selected objects in a return channel

func (*Registry) Register

func (this *Registry) Register(v interface{})

Register adds new object to registry. An existing object of same type would be replaced.

Jump to

Keyboard shortcuts

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