cli

package module
v0.1.0 Latest Latest
Warning

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

Go to latest
Published: Mar 17, 2020 License: Apache-2.0 Imports: 11 Imported by: 19

README

go-clix

Cli-X is a command line library for Go, inspired by spf13/cobra.

  • 📦 struct based API: Similar to cobra, clix features a struct based API for easy composition and discovery of available options.
  • 🚸 Subcommands: clix.Command can be nested for a git like experience.
  • 📌 Flags: Every command has it's own set of flags. POSIX compliant using spf13/pflag.
  • 👥 Aliases: Commands can have multiple names, so breaking changes can easily be mitigated.
  • 🎯 Go based completion: <TAB> completion is supported for bash, zsh and fish. But you can generate suggestions using Go code!

Getting started

Add the library to your project:

$ go get github.com/go-clix/cli

Then set up your root command:

package main

import (
    "fmt"
    "github.com/go-clix/cli"
)

func main() {
    // create the root command
    rootCmd := clix.Command{
        Use: "greet",
        Short: "print a message",
        Run: func(cmd *clix.Command, args []string) error {
            fmt.Println("Hello from Cli-X!")
        }
    }

    // run and check for errors
    if err := rootCmd.Execute(); err != nil {
        fmt.Println(err)
        os.Exit(1)
    }
}

Subcommands

Every command may have children:

// use a func to return a Command instead of
// a global variable and `init()`
func applyCmd() *clix.Command {
    cmd := &clix.Command{
        Use: "apply",
        Short: "apply the changes"
    }

    cmd.Run = func(cmd *clix.Command, args []string) error {
        fmt.Println("applied", args[0])
    }
}

func main() {
    rootCmd := &clix.Comand{
        Use: "kubectl",
        Short: "Kubernetes management tool",
    }

    // add the child command
    rootCmd.AddChildren(
       applyCmd(),
    )

    // run and check for errors
    if err := rootCmd.Execute(); err != nil {
        fmt.Println(err)
        os.Exit(1)
    }
}

Note: Do not use the init() function for setting up your commands. Create constructors as shown above!

Flags

A pflag.FlagSet can be accessed per command using *Command.Flags():

func applyCmd() *clix.Command {
    cmd := &clix.Command{
        Use: "apply",
        Short: "apply the changes"
    }

    force := cmd.Flags().BoolP("force", "f", false, "skip checks")

    cmd.Run = func(cmd *clix.Command, args []string) error {
        fmt.Println("applied", args[0])
        if *force {
            fmt.Println("The force was with us.")
        }
    }
}

Aliases

To make the apply subcommand also available as make and do:

func applyCmd() *clix.Command {
    cmd := &clix.Command{
        Use: "apply",
        Aliases: []string{"make", "do"},
        Short: "apply the changes"
    }
}

Keep in mind that in --help outputs the command will still be called apply.

Completion

Cli-X has a very powerful cli completion system, based on posener/complete.

It is powerful, because suggestions come directly from the Go application, not from a bash script or similar.

Command and Flag names are automatically suggested, custom suggestions can be implemented for positional arguments and flag values:

Flag Values

Custom suggestions for flag values can be set up using Command.Predictors.

To do so, you need to add a complete.Predictor for that flag. Cli-X has a number of predefined ones:

  • PredictAny(): Predicts available files and directories, like bash does when having no better idea
  • PredictNone(): Predicts literally nothing. No suggestions will be shown.
  • PredictSet(...string): Suggests from a predefined slice of options

If that's not sufficient, use PredictFunc(func(complete.Args) []string) to create your own.

import (
    "github.com/posener/complete"
    "github.com/go-clix/cli"
)

func logsCmd() *clix.Command {
    cmd := &clix.Command{
        Use: "logs",
        Short: "show logs of a pod",
        Predictors: map[string]complete.Predictor{
            "output": clix.PredictSet("lines", "json", "logfmt"),
        },
    }

    output := cmd.Flags().StringP("output", "o", "lines", "one of [lines, json, logfmt]")
}
Positional Arguments

For positional arguments, Cli-X uses a slightly different interface, to allow validation as well:

interface {
    Validate(args []string) error
    Predict(Args) []string
}

Predefined options are also available:

  • ArgsAny(): accepts any number args, predicts files and directories
  • ArgsExact(n): accepts exactly n arguments. Predicts files and directories.
  • ArgsNone(): accepts no args and predicts nothing.
  • ArgsSet(...string): Accepts one argument, which MUST be included in the given set. Predicts the values from the set.
import (
    "github.com/posener/complete"
    "github.com/go-clix/cli"
)

func applyCmd() *clix.Command {
    cmd := &clix.Command{
        Use: "logs",
        Short: "show logs of a pod",
        // we expect one argument which can be anything
        Args: clix.ArgsExact(1),
    }
}

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func PredictAny

func PredictAny() complete.Predictor

PredictAny predicts any files/directories

func PredictNone

func PredictNone() complete.Predictor

PredictNone predicts exactly nothing

func PredictSet

func PredictSet(set ...string) complete.Predictor

PredictSet predicts the values from the given set

Types

type Args

type Args struct {
	Validator
	complete.Predictor
}

Args bundles user-supplied implementations of the respective interfaces into an Arguments implementation.

type Arguments

type Arguments interface {
	Validator
	complete.Predictor
}

Arguments is used to validate and complete positional arguments. Use `Args()` to create an instance from functions.

func ArgsAny

func ArgsAny() Arguments

ArgsAny allows any number of arguments with any value

func ArgsExact

func ArgsExact(n int) Arguments

ArgsExact checks for exactly n arguments, predicting anything

func ArgsNone

func ArgsNone() Arguments

ArgsNone checks that no arguments were given, and disables predictions.

func ArgsSet

func ArgsSet(set ...string) Arguments

ArgsSet check the given argument is in the predefined set of options. Only these options are predicted. Only a single argument is assumed.

type Command

type Command struct {
	// Usage line. First word must be the command name, everything else is
	// displayed as-is.
	Use string
	// Aliases define alternative names for a command
	Aliases []string

	// Short help text, used for overviews
	Short string
	// Long help text, used for full help pages. `Short` is used as a fallback
	// if unset.
	Long string

	// Version of the application. Only used on the root command
	Version string

	// Run is the action that is run when this command is invoked.
	// The error is returned as-is from `Execute()`.
	Run func(cmd *Command, args []string) error

	// Validation + Completion
	//
	// Predict contains Predictors for flags. Defaults to
	// `complete.PredictSomething` if unset.
	// Use the flags name (not shorthand) as the key.
	Predictors map[string]complete.Predictor
	// Args is used to validate and complete positional arguments
	Args Arguments
	// contains filtered or unexported fields
}

Command represents a (sub)command of the application. Either `Run()` must be defined, or subcommands added using `AddCommand()`. These are also mutually exclusive.

func (*Command) AddCommand

func (c *Command) AddCommand(childs ...*Command)

AddCommand adds the supplied commands as subcommands. This command is set as the parent of the new children.

func (*Command) Execute

func (c *Command) Execute() error

Execute runs the application. It should be run on the most outer level command. The error return value is used for both, application errors but also help texts.

func (*Command) Flags

func (c *Command) Flags() *pflag.FlagSet

Flags returns the `*pflag.FlagSet` of this command

func (*Command) Name

func (c *Command) Name() string

Name of this command. The first segment of the `Use` field.

func (*Command) Usage

func (c *Command) Usage() string

Usage string

type ErrHelp

type ErrHelp struct {
	Reason error
	// contains filtered or unexported fields
}

ErrHelp wraps an actual error, showing the usage of the command afterwards

func (ErrHelp) Error

func (e ErrHelp) Error() string

type PredictFunc

type PredictFunc = complete.PredictFunc

PredictFunc allows to use an ordinary func as an Predictor

type ValidateFunc

type ValidateFunc func(args []string) error

ValidateFunc allows to use an ordinary func as an Validator

func ValidateAny

func ValidateAny() ValidateFunc

ValidateAny always approves

func ValidateExact

func ValidateExact(n int) ValidateFunc

ValidateExact checks that exactly n arguments were given

func ValidateNone

func ValidateNone() ValidateFunc

ValidateNone checks for no arguments at all

func ValidateSet

func ValidateSet(set ...string) ValidateFunc

ValidateSet checks that the given single argument is part of the set.

func (ValidateFunc) Validate

func (v ValidateFunc) Validate(args []string) error

Validate wrap the underlying function

type Validator

type Validator interface {
	// Validate receives the arguments of the command (without flags) and shall
	// return an error if they are unexpected.
	Validate(args []string) error
}

Validator checks that arguments have the expected form

Jump to

Keyboard shortcuts

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