github.com/kbehouse/nsc@v0.0.6/cmd/test.go (about)

     1  /*
     2   * Copyright 2018 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  	"path/filepath"
    21  	"sort"
    22  	"strings"
    23  
    24  	"github.com/spf13/cobra"
    25  	"github.com/spf13/cobra/doc"
    26  	flag "github.com/spf13/pflag"
    27  )
    28  
    29  // addCmd represents the add command
    30  var testCmd = &cobra.Command{
    31  	Hidden: true,
    32  	Use:    "test",
    33  	Short:  "Test commands",
    34  }
    35  
    36  func createFlagTable() *cobra.Command {
    37  	var cmds flagTable
    38  	cmd := &cobra.Command{
    39  		Use:           "flags",
    40  		Short:         "prints a table with all the flags",
    41  		SilenceErrors: true,
    42  		SilenceUsage:  true,
    43  		RunE: func(cmd *cobra.Command, args []string) error {
    44  
    45  			var buf Stack
    46  			buf.Push(rootCmd)
    47  
    48  			for {
    49  				v := buf.Pop()
    50  				if v == nil {
    51  					break
    52  				}
    53  				if v.HasSubCommands() {
    54  					for _, vv := range v.Commands() {
    55  						buf.Push(vv)
    56  					}
    57  					continue
    58  				} else {
    59  					cmds.addCmd(v)
    60  				}
    61  			}
    62  			return Write("--", []byte(cmds.render()))
    63  		},
    64  	}
    65  	return cmd
    66  }
    67  
    68  func generateDoc() *cobra.Command {
    69  	cmd := &cobra.Command{
    70  		Use:   "doc",
    71  		Short: "generate markdown documentation in the specified directory",
    72  		Args:  cobra.ExactArgs(1),
    73  		RunE: func(cmd *cobra.Command, args []string) error {
    74  			dir, err := filepath.Abs(args[0])
    75  			if err != nil {
    76  				return err
    77  			}
    78  			if err = MaybeMakeDir(dir); err != nil {
    79  				return err
    80  			}
    81  			return doc.GenMarkdownTree(rootCmd, dir)
    82  		},
    83  	}
    84  	return cmd
    85  }
    86  
    87  type Stack struct {
    88  	data []*cobra.Command
    89  }
    90  
    91  func (s *Stack) Push(v *cobra.Command) {
    92  	s.data = append([]*cobra.Command{v}, s.data...)
    93  }
    94  
    95  func (s *Stack) Pop() *cobra.Command {
    96  	var v *cobra.Command
    97  	if len(s.data) == 0 {
    98  		return nil
    99  	}
   100  	v = s.data[0]
   101  	s.data = s.data[1:]
   102  	return v
   103  }
   104  
   105  func reverse(a []string) {
   106  	for i := len(a)/2 - 1; i >= 0; i-- {
   107  		opp := len(a) - 1 - i
   108  		a[i], a[opp] = a[opp], a[i]
   109  	}
   110  }
   111  
   112  type parsedCommand struct {
   113  	name    string
   114  	flagMap map[string]string
   115  }
   116  
   117  type flagTable struct {
   118  	commands []parsedCommand
   119  }
   120  
   121  func (t *flagTable) addCmd(cmd *cobra.Command) {
   122  	var c parsedCommand
   123  	c.flagMap = make(map[string]string)
   124  	names := []string{cmd.Name()}
   125  	v := cmd
   126  	for {
   127  		p := v.Parent()
   128  		if p == nil {
   129  			break
   130  		}
   131  		names = append(names, p.Name())
   132  		v = p
   133  	}
   134  	reverse(names)
   135  	c.name = strings.Join(names, " ")
   136  
   137  	flags := cmd.Flags()
   138  	flags.VisitAll(func(f *flag.Flag) {
   139  		c.flagMap[f.Name] = f.Shorthand
   140  	})
   141  
   142  	t.commands = append(t.commands, c)
   143  }
   144  
   145  func (t *flagTable) render() string {
   146  	var buf bytes.Buffer
   147  
   148  	allFlags := make(map[string]bool)
   149  	for _, c := range t.commands {
   150  		for n := range c.flagMap {
   151  			allFlags[n] = true
   152  		}
   153  	}
   154  	var cols []string
   155  	for k := range allFlags {
   156  		cols = append(cols, k)
   157  	}
   158  	sort.Strings(cols)
   159  	cols = append([]string{"cmd"}, cols...)
   160  
   161  	buf.WriteString(strings.Join(cols, ","))
   162  	buf.WriteString("\n")
   163  
   164  	for _, c := range t.commands {
   165  		sf := []string{c.name}
   166  		for i := 1; i < len(cols); i++ {
   167  			v, ok := c.flagMap[cols[i]]
   168  			if v != "" {
   169  				sf = append(sf, v)
   170  			} else if ok {
   171  				sf = append(sf, "-")
   172  			} else {
   173  				sf = append(sf, "")
   174  			}
   175  		}
   176  		buf.WriteString(strings.Join(sf, ","))
   177  		buf.WriteString("\n")
   178  	}
   179  
   180  	return buf.String()
   181  }
   182  
   183  func init() {
   184  	GetRootCmd().AddCommand(testCmd)
   185  	testCmd.AddCommand(createGenerateNKeyCmd())
   186  	testCmd.AddCommand(createFlagTable())
   187  	testCmd.AddCommand(generateDoc())
   188  }