-
Notifications
You must be signed in to change notification settings - Fork 1
/
cmdns.go
157 lines (129 loc) · 4.43 KB
/
cmdns.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
package cmdns
import (
"errors"
"fmt"
"github.com/spf13/cobra"
)
var (
// DefaultNamespacer is the default namespacer for the package
DefaultNamespacer = New()
// DefaultNamespaceSeparator is the char that seperates commands
DefaultNamespaceSeparator = ":"
)
// SetOverrideUsageFunc when set to true will overide the command's usage function with the package's usage function that displays namespaces using the default namespacer
func SetOverrideUsageFunc(v bool) *CobraNamespacer {
return DefaultNamespacer.SetOverrideUsageFunc(v)
}
// Namespace enables namespacing for the command using the DefaultCmdNS
func Namespace(cmd *cobra.Command) error {
return DefaultNamespacer.Namespace(cmd)
}
// CobraNamespacer is the struct represting the component that namespaces cobra's sucommands
type CobraNamespacer struct {
// Namespaces is the collection of cobra namespaces
Namespaces []*CobraNamespace
OverrideUsageFunc bool
}
// New returns a new instance of the CobraNamespacer
func New() *CobraNamespacer {
return &CobraNamespacer{
Namespaces: make([]*CobraNamespace, 0),
OverrideUsageFunc: true,
}
}
// SetOverrideUsageFunc when set to true will overide the command's usage
// function with the package's usage function that displays namespaces
func (c *CobraNamespacer) SetOverrideUsageFunc(v bool) *CobraNamespacer {
c.OverrideUsageFunc = v
return c
}
// Namespace enables namespacing for the command's subcommands
func (c *CobraNamespacer) Namespace(cmd *cobra.Command) error {
if cmd == nil {
return errors.New("cmdns: cmd cannot be nil")
}
for _, child := range cmd.Commands() {
n := NewCobraNamespace()
n.OverrideUsageFunc = c.OverrideUsageFunc
c.Namespaces = append(c.Namespaces, n)
if err := n.Namespace(child); err != nil {
return err
}
}
return nil
}
// CobraNamespace represents a namespace for a command. This is usually then second level command.
type CobraNamespace struct {
OverrideUsageFunc bool
cmd *cobra.Command
commands []*cobra.Command
}
// NewCobraNamespace returns a new Namespace
func NewCobraNamespace() *CobraNamespace {
return &CobraNamespace{
OverrideUsageFunc: true,
commands: make([]*cobra.Command, 0),
}
}
// AvailableCommands returns the namespaced commands that are available
func (n *CobraNamespace) AvailableCommands() []*cobra.Command {
return n.commands
}
// Command returns the command for the namespace
func (n *CobraNamespace) Command() *cobra.Command {
return n.cmd
}
// Namespace enables namespacing for a sub-commmand and its immediated children. It returns an error if the command does not have a parent.
func (n *CobraNamespace) Namespace(cmd *cobra.Command) error {
if !cmd.HasParent() {
return errors.New("cmdns: command requires a parent")
}
// Do not bind if there are not available sub commands
if !cmd.HasAvailableSubCommands() {
return nil
}
if n.OverrideUsageFunc {
cmd.SetUsageFunc(n.UsageFunc())
}
for _, c := range cmd.Commands() {
if !c.IsAvailableCommand() {
continue
}
// copy the command add it to the root command with a prefix of its parent.
nc := *c
nc.Use = cmd.Name() + DefaultNamespaceSeparator + c.Use
// add this command to the root and hide it so it does not show in available commands list
c.Parent().Parent().AddCommand(&nc)
c.Hidden = true
n.commands = append(n.commands, &nc)
}
n.cmd = cmd
return nil
}
// UsageFunc returns the usage function for the command that renders namespaces
func (n *CobraNamespace) UsageFunc() (f func(*cobra.Command) error) {
return func(*cobra.Command) error {
err := tmpl(n.Command().OutOrStdout(), usageTemplate, n)
if err != nil {
fmt.Print(err)
}
return err
}
}
var usageTemplate = `{{$ns := .}}{{with .Command}}Usage: {{if .Runnable}}{{.UseLine}}{{if .HasFlags}} [flags]{{end}}{{end}}{{if gt .Aliases 0}}
Aliases:
{{.NameAndAliases}}
{{end}}{{if .HasExample}}
Examples:
{{ .Example }}{{end}}{{ if gt $ns.AvailableCommands 0 }}
Additional commands, use "{{.Parent.CommandPath}} COMMAND --help" for more information about a command.
{{range $ns.AvailableCommands}}
{{rpad .Name .NamePadding }} {{.Short}}{{end}}{{end}}{{ if .HasLocalFlags}}
Flags:
{{.LocalFlags.FlagUsages | trimRightSpace}}{{end}}{{ if .HasInheritedFlags}}
Global Flags:
{{.InheritedFlags.FlagUsages | trimRightSpace}}{{end}}{{if .HasHelpSubCommands}}
Additional help topics:{{range .Commands}}{{if .IsHelpCommand}}
{{rpad .CommandPath .CommandPathPadding}} {{.Short}}{{end}}{{end}}{{end}}
{{end}}
`