...

Source file src/go.etcd.io/etcd/pkg/v3/cobrautl/help.go

Documentation: go.etcd.io/etcd/pkg/v3/cobrautl

     1  // Copyright 2015 The etcd Authors
     2  //
     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  // copied from https://github.com/rkt/rkt/blob/master/rkt/help.go
    16  
    17  package cobrautl
    18  
    19  import (
    20  	"bytes"
    21  	"fmt"
    22  	"io"
    23  	"os"
    24  	"strings"
    25  	"text/tabwriter"
    26  	"text/template"
    27  
    28  	"github.com/spf13/cobra"
    29  	"github.com/spf13/pflag"
    30  )
    31  
    32  var (
    33  	commandUsageTemplate *template.Template
    34  	templFuncs           = template.FuncMap{
    35  		"descToLines": func(s string) []string {
    36  			// trim leading/trailing whitespace and split into slice of lines
    37  			return strings.Split(strings.Trim(s, "\n\t "), "\n")
    38  		},
    39  		"cmdName": func(cmd *cobra.Command, startCmd *cobra.Command) string {
    40  			parts := []string{cmd.Name()}
    41  			for cmd.HasParent() && cmd.Parent().Name() != startCmd.Name() {
    42  				cmd = cmd.Parent()
    43  				parts = append([]string{cmd.Name()}, parts...)
    44  			}
    45  			return strings.Join(parts, " ")
    46  		},
    47  	}
    48  )
    49  
    50  func init() {
    51  	commandUsage := `
    52  {{ $cmd := .Cmd }}\
    53  {{ $cmdname := cmdName .Cmd .Cmd.Root }}\
    54  NAME:
    55  {{ if not .Cmd.HasParent }}\
    56  {{printf "\t%s - %s" .Cmd.Name .Cmd.Short}}
    57  {{else}}\
    58  {{printf "\t%s - %s" $cmdname .Cmd.Short}}
    59  {{end}}\
    60  
    61  USAGE:
    62  {{printf "\t%s" .Cmd.UseLine}}
    63  {{ if not .Cmd.HasParent }}\
    64  
    65  VERSION:
    66  {{printf "\t%s" .Version}}
    67  {{end}}\
    68  {{if .Cmd.HasSubCommands}}\
    69  
    70  API VERSION:
    71  {{printf "\t%s" .APIVersion}}
    72  {{end}}\
    73  {{if .Cmd.HasSubCommands}}\
    74  
    75  
    76  COMMANDS:
    77  {{range .SubCommands}}\
    78  {{ $cmdname := cmdName . $cmd }}\
    79  {{ if .Runnable }}\
    80  {{printf "\t%s\t%s" $cmdname .Short}}
    81  {{end}}\
    82  {{end}}\
    83  {{end}}\
    84  {{ if .Cmd.Long }}\
    85  
    86  DESCRIPTION:
    87  {{range $line := descToLines .Cmd.Long}}{{printf "\t%s" $line}}
    88  {{end}}\
    89  {{end}}\
    90  {{if .Cmd.HasLocalFlags}}\
    91  
    92  OPTIONS:
    93  {{.LocalFlags}}\
    94  {{end}}\
    95  {{if .Cmd.HasInheritedFlags}}\
    96  
    97  GLOBAL OPTIONS:
    98  {{.GlobalFlags}}\
    99  {{end}}
   100  `[1:]
   101  
   102  	commandUsageTemplate = template.Must(template.New("command_usage").Funcs(templFuncs).Parse(strings.Replace(commandUsage, "\\\n", "", -1)))
   103  }
   104  
   105  func etcdFlagUsages(flagSet *pflag.FlagSet) string {
   106  	x := new(bytes.Buffer)
   107  
   108  	flagSet.VisitAll(func(flag *pflag.Flag) {
   109  		if len(flag.Deprecated) > 0 {
   110  			return
   111  		}
   112  		var format string
   113  		if len(flag.Shorthand) > 0 {
   114  			format = "  -%s, --%s"
   115  		} else {
   116  			format = "   %s   --%s"
   117  		}
   118  		if len(flag.NoOptDefVal) > 0 {
   119  			format = format + "["
   120  		}
   121  		if flag.Value.Type() == "string" {
   122  			// put quotes on the value
   123  			format = format + "=%q"
   124  		} else {
   125  			format = format + "=%s"
   126  		}
   127  		if len(flag.NoOptDefVal) > 0 {
   128  			format = format + "]"
   129  		}
   130  		format = format + "\t%s\n"
   131  		shorthand := flag.Shorthand
   132  		fmt.Fprintf(x, format, shorthand, flag.Name, flag.DefValue, flag.Usage)
   133  	})
   134  
   135  	return x.String()
   136  }
   137  
   138  func getSubCommands(cmd *cobra.Command) []*cobra.Command {
   139  	var subCommands []*cobra.Command
   140  	for _, subCmd := range cmd.Commands() {
   141  		subCommands = append(subCommands, subCmd)
   142  		subCommands = append(subCommands, getSubCommands(subCmd)...)
   143  	}
   144  	return subCommands
   145  }
   146  
   147  func UsageFunc(cmd *cobra.Command, version, APIVersion string) error {
   148  	subCommands := getSubCommands(cmd)
   149  	tabOut := getTabOutWithWriter(os.Stdout)
   150  	commandUsageTemplate.Execute(tabOut, struct {
   151  		Cmd         *cobra.Command
   152  		LocalFlags  string
   153  		GlobalFlags string
   154  		SubCommands []*cobra.Command
   155  		Version     string
   156  		APIVersion  string
   157  	}{
   158  		cmd,
   159  		etcdFlagUsages(cmd.LocalFlags()),
   160  		etcdFlagUsages(cmd.InheritedFlags()),
   161  		subCommands,
   162  		version,
   163  		APIVersion,
   164  	})
   165  	tabOut.Flush()
   166  	return nil
   167  }
   168  
   169  func getTabOutWithWriter(writer io.Writer) *tabwriter.Writer {
   170  	aTabOut := new(tabwriter.Writer)
   171  	aTabOut.Init(writer, 0, 8, 1, '\t', 0)
   172  	return aTabOut
   173  }
   174  

View as plain text