mirror of https://github.com/coder/coder.git
86 lines
2.1 KiB
Go
86 lines
2.1 KiB
Go
// Package clibase offers an all-in-one solution for a highly configurable CLI
|
|
// application. Within Coder, we use it for all of our subcommands, which
|
|
// demands more functionality than cobra/viber offers.
|
|
//
|
|
// The Command interface is loosely based on the chi middleware pattern and
|
|
// http.Handler/HandlerFunc.
|
|
package clibase
|
|
|
|
import (
|
|
"strings"
|
|
|
|
"golang.org/x/exp/maps"
|
|
)
|
|
|
|
// Group describes a hierarchy of groups that an option or command belongs to.
|
|
type Group struct {
|
|
Parent *Group `json:"parent,omitempty"`
|
|
Name string `json:"name,omitempty"`
|
|
Children []Group `json:"children,omitempty"`
|
|
Description string `json:"description,omitempty"`
|
|
}
|
|
|
|
func (g *Group) AddChild(child Group) {
|
|
child.Parent = g
|
|
g.Children = append(g.Children, child)
|
|
}
|
|
|
|
// Ancestry returns the group and all of its parents, in order.
|
|
func (g *Group) Ancestry() []Group {
|
|
if g == nil {
|
|
return nil
|
|
}
|
|
|
|
groups := []Group{*g}
|
|
for p := g.Parent; p != nil; p = p.Parent {
|
|
// Prepend to the slice so that the order is correct.
|
|
groups = append([]Group{*p}, groups...)
|
|
}
|
|
return groups
|
|
}
|
|
|
|
func (g *Group) FullName() string {
|
|
var names []string
|
|
for _, g := range g.Ancestry() {
|
|
names = append(names, g.Name)
|
|
}
|
|
return strings.Join(names, " / ")
|
|
}
|
|
|
|
// Annotations is an arbitrary key-mapping used to extend the Option and Command types.
|
|
// Its methods won't panic if the map is nil.
|
|
type Annotations map[string]string
|
|
|
|
// Mark sets a value on the annotations map, creating one
|
|
// if it doesn't exist. Mark does not mutate the original and
|
|
// returns a copy. It is suitable for chaining.
|
|
func (a Annotations) Mark(key string, value string) Annotations {
|
|
var aa Annotations
|
|
if a != nil {
|
|
aa = maps.Clone(a)
|
|
} else {
|
|
aa = make(Annotations)
|
|
}
|
|
aa[key] = value
|
|
return aa
|
|
}
|
|
|
|
// IsSet returns true if the key is set in the annotations map.
|
|
func (a Annotations) IsSet(key string) bool {
|
|
if a == nil {
|
|
return false
|
|
}
|
|
_, ok := a[key]
|
|
return ok
|
|
}
|
|
|
|
// Get retrieves a key from the map, returning false if the key is not found
|
|
// or the map is nil.
|
|
func (a Annotations) Get(key string) (string, bool) {
|
|
if a == nil {
|
|
return "", false
|
|
}
|
|
v, ok := a[key]
|
|
return v, ok
|
|
}
|