mirror of
https://github.com/Luzifer/go_helpers.git
synced 2024-12-24 13:01:21 +00:00
Add simple CLI helper
Signed-off-by: Knut Ahlers <knut@ahlers.me>
This commit is contained in:
parent
233ea21df6
commit
2c3bf95990
1 changed files with 89 additions and 0 deletions
89
cli/cli.go
Normal file
89
cli/cli.go
Normal file
|
@ -0,0 +1,89 @@
|
||||||
|
package cli
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"sort"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
type (
|
||||||
|
// Registry contains a collection of commands to be executed
|
||||||
|
Registry struct {
|
||||||
|
cmds map[string]RegistryEntry
|
||||||
|
sync.Mutex
|
||||||
|
}
|
||||||
|
|
||||||
|
// Entry defines a sub-command with its parameters, description and
|
||||||
|
// run function to be called when this command is executed
|
||||||
|
RegistryEntry struct {
|
||||||
|
Description string
|
||||||
|
Name string
|
||||||
|
Params []string
|
||||||
|
Run func([]string) error
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
// ErrHelpCalled is returned from the Call function if the given
|
||||||
|
// command is not found and the help function was executed
|
||||||
|
var ErrHelpCalled = errors.New("help called")
|
||||||
|
|
||||||
|
// New creates a new Registry
|
||||||
|
func New() *Registry {
|
||||||
|
return &Registry{
|
||||||
|
cmds: make(map[string]RegistryEntry),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add adds a new command to the Registry
|
||||||
|
func (c *Registry) Add(e RegistryEntry) {
|
||||||
|
c.Lock()
|
||||||
|
defer c.Unlock()
|
||||||
|
|
||||||
|
c.cmds[e.Name] = e
|
||||||
|
}
|
||||||
|
|
||||||
|
// Call executes the matchign command from the given arguments
|
||||||
|
func (c *Registry) Call(args []string) error {
|
||||||
|
c.Lock()
|
||||||
|
defer c.Unlock()
|
||||||
|
|
||||||
|
cmdEntry := c.cmds[args[0]]
|
||||||
|
if cmdEntry.Name != args[0] {
|
||||||
|
c.help()
|
||||||
|
return ErrHelpCalled
|
||||||
|
}
|
||||||
|
|
||||||
|
return cmdEntry.Run(args)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Registry) help() {
|
||||||
|
// Called from Call, does not need lock
|
||||||
|
|
||||||
|
var (
|
||||||
|
maxCmdLen int
|
||||||
|
cmds []RegistryEntry
|
||||||
|
)
|
||||||
|
|
||||||
|
for name := range c.cmds {
|
||||||
|
entry := c.cmds[name]
|
||||||
|
if l := len(entry.commandDisplay()); l > maxCmdLen {
|
||||||
|
maxCmdLen = l
|
||||||
|
}
|
||||||
|
cmds = append(cmds, entry)
|
||||||
|
}
|
||||||
|
|
||||||
|
sort.Slice(cmds, func(i, j int) bool { return cmds[i].Name < cmds[j].Name })
|
||||||
|
|
||||||
|
tpl := fmt.Sprintf(" %%-%ds %%s\n", maxCmdLen)
|
||||||
|
fmt.Fprintln(os.Stdout, "Supported sub-commands are:")
|
||||||
|
for _, cmd := range cmds {
|
||||||
|
fmt.Fprintf(os.Stdout, tpl, cmd.commandDisplay(), cmd.Description)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c RegistryEntry) commandDisplay() string {
|
||||||
|
return strings.Join(append([]string{c.Name}, c.Params...), " ")
|
||||||
|
}
|
Loading…
Reference in a new issue