1
0
Fork 0
mirror of https://github.com/Luzifer/go_helpers.git synced 2024-12-25 13:31:21 +00:00
go_helpers/cli/cli.go
Knut Ahlers 2c3bf95990
Add simple CLI helper
Signed-off-by: Knut Ahlers <knut@ahlers.me>
2023-05-19 14:09:20 +02:00

89 lines
1.8 KiB
Go

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...), " ")
}