Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/yitsushi/go-commander
Go library to simplify CLI workflow
https://github.com/yitsushi/go-commander
Last synced: 14 days ago
JSON representation
Go library to simplify CLI workflow
- Host: GitHub
- URL: https://github.com/yitsushi/go-commander
- Owner: yitsushi
- License: mit
- Archived: true
- Created: 2016-10-10T10:09:41.000Z (about 8 years ago)
- Default Branch: master
- Last Pushed: 2020-05-24T20:27:55.000Z (over 4 years ago)
- Last Synced: 2024-07-31T20:42:48.163Z (3 months ago)
- Language: Go
- Homepage: http://yitsushi.github.io/go-commander/
- Size: 70.3 KB
- Stars: 35
- Watchers: 3
- Forks: 5
- Open Issues: 1
-
Metadata Files:
- Readme: README.md
- License: LICENSE
- Code of conduct: CODE_OF_CONDUCT.md
Awesome Lists containing this project
- awesome-go - go-commander - Go library to simplify CLI workflow. (Command Line / Standard CLI)
- fucking-awesome-go - go-commander - Go library to simplify CLI workflow. (Command Line / Standard CLI)
- awesome-go - go-commander - Go library to simplify CLI workflow. (Command Line / Standard CLI)
- awesome-go - go-commander - Go library to simplify CLI workflow. (Command Line / Standard CLI)
- awesome-go - go-commander - Go library to simplify CLI workflow - ★ 7 (Command Line)
- awesome-go-extra - go-commander - 10-10T10:09:41Z|2020-05-24T20:27:55Z| (Build Automation / Standard CLI)
- awesome-go-with-stars - go-commander - Go library to simplify CLI workflow. (Command Line / Standard CLI)
- awesome-go-plus - go-commander - Go library to simplify CLI workflow. ![stars](https://img.shields.io/badge/stars-35-blue) ![forks](https://img.shields.io/badge/forks-5-blue) (Command Line / Standard CLI)
- awesome-go-plus - go-commander - Go library to simplify CLI workflow. (Command Line / Standard CLI)
README
[![Documentation](https://godoc.org/github.com/yitsushi/go-commander?status.svg)](http://godoc.org/github.com/yitsushi/go-commander)
[![Go Report Card](https://goreportcard.com/badge/github.com/yitsushi/go-commander)](https://goreportcard.com/report/github.com/yitsushi/go-commander)
[![Coverage Status](https://coveralls.io/repos/github/yitsushi/go-commander/badge.svg)](https://coveralls.io/github/yitsushi/go-commander)
[![Build Status](https://travis-ci.org/yitsushi/go-commander.svg?branch=master)](https://travis-ci.org/yitsushi/go-commander)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
```shell
$ go get github.com/yitsushi/go-commander
```### Sample output _(from [totp-cli](https://github.com/yitsushi/totp-cli))_
```shell
$ totp-cli helpchange-password Change password
update Check and update totp-cli itself
version Print current version of this application
generate . Generate a specific OTP
add-token [namespace] [account] Add new token
list [namespace] List all available namespaces or accounts under a namespace
delete [.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](https://github.com/yitsushi/totp-cli) for examples.```go
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: " [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`.
```bash
❯ go build mytool.go❯ ./mytool
your-command [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 [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`.```go
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:```go
// 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: " [optional-argument]",
Examples: []string {
"test.txt",
"test.txt copy",
"test.txt move",
},
},
}
}
```### Define arguments with type
```go
&commander.CommandWrapper{
Handler: &MyCommand{},
Arguments: []*commander.Argument{
&commander.Argument{
Name: "list",
Type: "StringArray[]",
},
},
Help: &commander.CommandDescriptor{
Name: "my-command",
},
}
```In your command:
```go
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 ;)
```go
// 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:
```go
if opts.HasValidTypedOpt("owner") == nil {
owner := opts.TypedOpt("owner").(*MyCustomType)
mockPrintf("OwnerID: %d, Name: %s\n", owner.ID, owner.Name)
}
```