github.com/nats-io/nsc/v2@v2.8.7-0.20240307184528-efd7023c6896/cmd/test.go (about) 1 /* 2 * Copyright 2018-2023 The NATS Authors 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16 package cmd 17 18 import ( 19 "bytes" 20 "fmt" 21 "path/filepath" 22 "sort" 23 "strings" 24 25 "github.com/spf13/cobra" 26 "github.com/spf13/cobra/doc" 27 flag "github.com/spf13/pflag" 28 ) 29 30 // addCmd represents the add command 31 var testCmd = &cobra.Command{ 32 Hidden: true, 33 Use: "test", 34 Short: "Test commands", 35 } 36 37 func createFlagTable() *cobra.Command { 38 var cmds flagTable 39 cmd := &cobra.Command{ 40 Use: "flags", 41 Short: "prints a table with all the flags", 42 SilenceErrors: true, 43 SilenceUsage: true, 44 RunE: func(cmd *cobra.Command, args []string) error { 45 46 var buf Stack 47 buf.Push(rootCmd) 48 49 for { 50 v := buf.Pop() 51 if v == nil { 52 break 53 } 54 if v.HasSubCommands() { 55 for _, vv := range v.Commands() { 56 buf.Push(vv) 57 } 58 continue 59 } else { 60 cmds.addCmd(v) 61 } 62 } 63 return Write("--", []byte(cmds.render())) 64 }, 65 } 66 return cmd 67 } 68 69 func createWhatUsesFlag() *cobra.Command { 70 var cmds flagTable 71 cmd := &cobra.Command{ 72 Use: "whoflag", 73 Short: "prints a table with commands using the specified flag", 74 SilenceErrors: true, 75 SilenceUsage: true, 76 Args: cobra.ExactArgs(1), 77 RunE: func(cmd *cobra.Command, args []string) error { 78 var buf Stack 79 buf.Push(rootCmd) 80 81 for { 82 v := buf.Pop() 83 if v == nil { 84 break 85 } 86 if v.HasSubCommands() { 87 for _, vv := range v.Commands() { 88 buf.Push(vv) 89 } 90 continue 91 } else { 92 cmds.addCmd(v) 93 } 94 } 95 cmds.find(args[0]) 96 return nil 97 }, 98 } 99 return cmd 100 } 101 102 func generateDoc() *cobra.Command { 103 cmd := &cobra.Command{ 104 Use: "doc", 105 Short: "generate markdown documentation in the specified directory", 106 Args: cobra.ExactArgs(1), 107 RunE: func(cmd *cobra.Command, args []string) error { 108 dir, err := filepath.Abs(args[0]) 109 if err != nil { 110 return err 111 } 112 if err = MaybeMakeDir(dir); err != nil { 113 return err 114 } 115 return doc.GenMarkdownTree(rootCmd, dir) 116 }, 117 } 118 return cmd 119 } 120 121 type Stack struct { 122 data []*cobra.Command 123 } 124 125 func (s *Stack) Push(v *cobra.Command) { 126 s.data = append([]*cobra.Command{v}, s.data...) 127 } 128 129 func (s *Stack) Pop() *cobra.Command { 130 var v *cobra.Command 131 if len(s.data) == 0 { 132 return nil 133 } 134 v = s.data[0] 135 s.data = s.data[1:] 136 return v 137 } 138 139 func reverse(a []string) { 140 for i := len(a)/2 - 1; i >= 0; i-- { 141 opp := len(a) - 1 - i 142 a[i], a[opp] = a[opp], a[i] 143 } 144 } 145 146 type parsedCommand struct { 147 name string 148 flagMap map[string]string 149 } 150 151 type flagTable struct { 152 commands []parsedCommand 153 } 154 155 func (t *flagTable) addCmd(cmd *cobra.Command) { 156 var c parsedCommand 157 c.flagMap = make(map[string]string) 158 names := []string{cmd.Name()} 159 v := cmd 160 for { 161 p := v.Parent() 162 if p == nil { 163 break 164 } 165 names = append(names, p.Name()) 166 v = p 167 } 168 reverse(names) 169 c.name = strings.Join(names, " ") 170 171 flags := cmd.Flags() 172 flags.VisitAll(func(f *flag.Flag) { 173 c.flagMap[f.Name] = f.Shorthand 174 }) 175 176 t.commands = append(t.commands, c) 177 } 178 179 func (t *flagTable) find(flag string) { 180 for _, c := range t.commands { 181 m := c.flagMap 182 for n := range m { 183 if flag == m[n] || n == flag { 184 fmt.Println(c.name) 185 } 186 } 187 } 188 } 189 190 func (t *flagTable) render() string { 191 var buf bytes.Buffer 192 193 allFlags := make(map[string]bool) 194 for _, c := range t.commands { 195 for n := range c.flagMap { 196 allFlags[n] = true 197 } 198 } 199 var cols []string 200 for k := range allFlags { 201 cols = append(cols, k) 202 } 203 sort.Strings(cols) 204 cols = append([]string{"cmd"}, cols...) 205 206 buf.WriteString(strings.Join(cols, ",")) 207 buf.WriteString("\n") 208 209 for _, c := range t.commands { 210 sf := []string{c.name} 211 for i := 1; i < len(cols); i++ { 212 v, ok := c.flagMap[cols[i]] 213 if v != "" { 214 sf = append(sf, v) 215 } else if ok { 216 sf = append(sf, "-") 217 } else { 218 sf = append(sf, "") 219 } 220 } 221 buf.WriteString(strings.Join(sf, ",")) 222 buf.WriteString("\n") 223 } 224 225 return buf.String() 226 } 227 228 func (t *flagTable) ResetFlagDefaults() string { 229 var buf bytes.Buffer 230 231 allFlags := make(map[string]bool) 232 for _, c := range t.commands { 233 for n := range c.flagMap { 234 allFlags[n] = true 235 } 236 } 237 var cols []string 238 for k := range allFlags { 239 cols = append(cols, k) 240 } 241 sort.Strings(cols) 242 cols = append([]string{"cmd"}, cols...) 243 244 buf.WriteString(strings.Join(cols, ",")) 245 buf.WriteString("\n") 246 247 for _, c := range t.commands { 248 sf := []string{c.name} 249 for i := 1; i < len(cols); i++ { 250 v, ok := c.flagMap[cols[i]] 251 if v != "" { 252 sf = append(sf, v) 253 } else if ok { 254 sf = append(sf, "-") 255 } else { 256 sf = append(sf, "") 257 } 258 } 259 buf.WriteString(strings.Join(sf, ",")) 260 buf.WriteString("\n") 261 } 262 263 return buf.String() 264 } 265 266 func init() { 267 GetRootCmd().AddCommand(testCmd) 268 testCmd.AddCommand(createGenerateNKeyCmd()) 269 testCmd.AddCommand(createFlagTable()) 270 testCmd.AddCommand(generateDoc()) 271 testCmd.AddCommand(createWhatUsesFlag()) 272 }