Go library to simplify CLI workflow

Documentation Go Report Card Coverage Status Build Status

This is a simple Go library to manage commands for your CLI tool. Easy to use and now you can focus on Business Logic instead of building the command routing.

What this library does for you?

Manage your separated commands. How? Generates a general help and command specific helps for your commands. If your command fails somewhere (panic for example), commander will display the error message and the command specific help to guide your user.

Install

$ go get github.com/yitsushi/go-commander

Sample output (from totp-cli)

$ totp-cli help

change-password                   Change password
update                            Check and update totp-cli itself
version                           Print current version of this application
generate <namespace>.<account>    Generate a specific OTP
add-token [namespace] [account]   Add new token
list [namespace]                  List all available namespaces or accounts under a namespace
delete <namespace>[.account]      Delete an account or a whole namespace
help [command]                    Display this help or a command specific help

Usage

Every single command has to implement CommandHandler. Check this project for examples.

package main

// Import the package
import "github.com/yitsushi/go-commander"

// Your Command
type YourCommand struct {
}

// Executed only on command call
func (c *YourCommand) Execute(opts *commander.CommandHelper) {
  // Command Action
}

func NewYourCommand(appName string) *commander.CommandWrapper {
  return &commander.CommandWrapper{
    Handler: &YourCommand{},
    Help: &commander.CommandDescriptor{
      Name:             "your-command",
      ShortDescription: "This is my own command",
      LongDescription:  `This is a very long
description about this command.`,
      Arguments:        "<filename> [optional-argument]",
      Examples:         []string {
        "test.txt",
        "test.txt copy",
        "test.txt move",
      },
    },
  }
}

// Main Section
func main() {
	registry := commander.NewCommandRegistry()

	registry.Register(NewYourCommand)

	registry.Execute()
}

Now you have a CLI tool with two commands: help and your-command.

❯ go build mytool.go

❯ ./mytool
your-command <filename> [optional-argument]   This is my own command
help [command]                                Display this help or a command specific help

❯ ./mytool help your-command
Usage: mytool your-command <filename> [optional-argument]

This is a very long
description about this command.

Examples:
  mytool your-command test.txt
  mytool your-command test.txt copy
  mytool your-command test.txt move

How to use subcommand pattern?

When you create your main command, just create a new CommandRegistry inside the Execute function like you did in your main() and change Depth.

import subcommand "github.com/yitsushi/mypackage/command/something"

func (c *Something) Execute(opts *commander.CommandHelper) {
	registry := commander.NewCommandRegistry()
	registry.Depth = 1
	registry.Register(subcommand.NewSomethingMySubCommand)
	registry.Execute()
}

PreValidation

If you want to write a general pre-validation for your command or just simply keep your validation logic separated:

// Or you can define inline if you want
func MyValidator(c *commander.CommandHelper) {
  if c.Arg(0) == "" {
    panic("File?")
  }

  info, err := os.Stat(c.Arg(0))
  if err != nil {
    panic("File not found")
  }

  if !info.Mode().IsRegular() {
    panic("It's not a regular file")
  }

  if c.Arg(1) != "" {
    if c.Arg(1) != "copy" && c.Arg(1) != "move" {
      panic("Invalid operation")
    }
  }
}

func NewYourCommand(appName string) *commander.CommandWrapper {
  return &commander.CommandWrapper{
    Handler: &YourCommand{},
    Validator: MyValidator
    Help: &commander.CommandDescriptor{
      Name:             "your-command",
      ShortDescription: "This is my own command",
      LongDescription:  `This is a very long
description about this command.`,
      Arguments:        "<filename> [optional-argument]",
      Examples:         []string {
        "test.txt",
        "test.txt copy",
        "test.txt move",
      },
    },
  }
}

Define arguments with type

&commander.CommandWrapper{
  Handler: &MyCommand{},
  Arguments: []*commander.Argument{
    &commander.Argument{
      Name: "list",
      Type: "StringArray[]",
    },
  },
  Help: &commander.CommandDescriptor{
    Name: "my-command",
  },
}

In your command:

if opts.HasValidTypedOpt("list") == nil {
  myList := opts.TypedOpt("list").([]string)
  if len(myList) > 0 {
    mockPrintf("My list: %v\n", myList)
  }
}

Define own type

Yes you can ;)

// Define your struct (optional)
type MyCustomType struct {
	ID   uint64
	Name string
}

// register your own type with parsing/validation
commander.RegisterArgumentType("MyType", func(value string) (interface{}, error) {
  values := strings.Split(value, ":")

  if len(values) < 2 {
    return &MyCustomType{}, errors.New("Invalid format! MyType => 'ID:Name'")
  }

  id, err := strconv.ParseUint(values[0], 10, 64)
  if err != nil {
    return &MyCustomType{}, errors.New("Invalid format! MyType => 'ID:Name'")
  }

  return &MyCustomType{
      ID:   id,
      Name: values[1],
    },
    nil
})

// Define your command
&commander.CommandWrapper{
  Handler: &MyCommand{},
  Arguments: []*commander.Argument{
    &commander.Argument{
      Name:        "owner",
      Type:        "MyType",
      FailOnError: true,          // Optional boolean
    },
  },
  Help: &commander.CommandDescriptor{
    Name: "my-command",
  },
}

In your command:

if opts.HasValidTypedOpt("owner") == nil {
  owner := opts.TypedOpt("owner").(*MyCustomType)
  mockPrintf("OwnerID: %d, Name: %s\n", owner.ID, owner.Name)
}
Similar Resources

Cli-algorithm - A cli program with A&DS in go!

cli-algorithm Objectives The objective of this cli is to implement 4 basic algorithms to sort arrays been Merge Sort Insertion Sort Bubble Sort Quick

Jan 2, 2022

Nebulant-cli - Nebulant's CLI

Nebulant-cli - Nebulant's CLI

Nebulant CLI Website: https://nebulant.io Documentation: https://nebulant.io/docs.html The Nebulant CLI tool is a single binary that can be used as a

Jan 11, 2022

News-parser-cli - Simple CLI which allows you to receive news depending on the parameters passed to it

News-parser-cli - Simple CLI which allows you to receive news depending on the parameters passed to it

news-parser-cli Simple CLI which allows you to receive news depending on the par

Jan 4, 2022

Go-api-cli - Small CLI to fetch data from an API sync and async

Async API Cli CLI to fetch data on "todos" from a given API in a number of ways.

Jan 13, 2022

Nebula Diagnosis CLI Tool is an information diagnosis cli tool for the nebula service and the node to which the service belongs.

Nebula Diagnosis CLI Tool is an information diagnosis cli tool for the nebula service and the node to which the service belongs.

Jan 12, 2022

bcrypt-cli is the CLI tool for hashing passwords with bcrypt.

bcrypt-cli bcrypt-cli is the CLI tool for hashing passwords with bcrypt. Install go install github.com/ryicoh/bcrypt-cli Usage It can be used like bas

Jan 9, 2023

Gobby-cli - CLI application to debug gobby applications

go(bby) Interactive debugging tool for gobby applications Usage Coming soon™ Ins

Feb 8, 2022

GTDF-CLI - The official CLI tool to operate with Getting Things Done Framework

GTDF-CLI - The official CLI tool to operate with Getting Things Done Framework

This is the official CLI tool to operate with Getting Things Done Framework. How

Feb 14, 2022

A Simple and Clear CLI library. Dependency free.

A Simple and Clear CLI library. Dependency free.

A Simple and Clear CLI library. Dependency free. Features Nested Subcommands Uses the standard library flag package Auto-generated help Custom banners

Jan 1, 2023
Comments
  • Remove protocol from go get url

    Remove protocol from go get url

    Removing https from the go get command, to avoid the error: package https:/github.com/Yitsushi/go-commander: "https://" not allowed in import path.

  • Refactor README

    Refactor README

    Now it's a bit chaotic because I updated the README file as I added features. For example, Type-checked Arguments are placed at the bottom of the documentation, but it can be part of the original example as well.

Yikes is a cli-application to simplify the process to maintaining a list of tasks to complete.

yikes Yikes is a cli-application to simplify the process to maintaining a list of tasks to complete. It also has commands to help store random notes a

Oct 7, 2021
An Alfred Workflow for the Johnny.Decimal filing system
An Alfred Workflow for the Johnny.Decimal filing system

alfred-jd An Alfred Workflow for the Johnny.Decimal filing system This workflow provides tools for working with the brilliant Johnny.Decimal filing sy

Dec 26, 2022
Pack a Go workflow/function as a Unix-style pipeline command
Pack a Go workflow/function as a Unix-style pipeline command

tpack Pack a Go workflow/function as a Unix-style pipeline command. Wiki In Unix-like computer operating systems, a pipeline is a mechanism for inter-

Nov 9, 2022
CLI to run a docker image with R. CLI built using cobra library in go.
CLI  to run a docker image with R. CLI built using cobra library in go.

BlueBeak Installation Guide Task 1: Building the CLI The directory structure looks like Fastest process: 1)cd into bbtools 2)cd into bbtools/bin 3)I h

Dec 20, 2021
Syno-cli - Synology unofficial API CLI and library

Synology CLI Unofficial wrapper over Synology API in Go. Focus on administrative

Jan 6, 2023
Elegant CLI wrapper for kubeseal CLI

Overview This is a wrapper CLI ofkubeseal CLI, specifically the raw mode. If you just need to encrypt your secret on RAW mode, this CLI will be the ea

Jan 8, 2022
A wrapper of aliyun-cli subcommand alidns, run aliyun-cli in Declarative mode.

aliyun-dns A wrapper of aliyun-cli subcommand alidns, run aliyun-cli in Declarative mode. Installation Install aliyun-cli. Usage $ aliyun-dns -h A wra

Dec 21, 2021
Symfony-cli - The Symfony CLI tool For Golang

Symfony CLI Install To install Symfony CLI, please download the appropriate vers

Dec 28, 2022
Go-file-downloader-ftctl - A file downloader cli built using golang. Makes use of cobra for building the cli and go concurrent feature to download files.

ftctl This is a file downloader cli written in Golang which uses the concurrent feature of go to download files. The cli is built using cobra. How to

Jan 2, 2022