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