mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-08-22 10:06:15 +00:00
Use responsive writer in help
This commit is contained in:
parent
f6d1ac72a0
commit
4d641c4911
@ -195,33 +195,6 @@ __custom_func() {
|
||||
* serviceaccounts (aka 'sa')
|
||||
* services (aka 'svc')
|
||||
`
|
||||
usage_template = `{{if gt .Aliases 0}}
|
||||
|
||||
Aliases:
|
||||
{{.NameAndAliases}}{{end}}{{if .HasExample}}
|
||||
|
||||
Examples:
|
||||
{{ .Example }}{{end}}{{ if .HasAvailableSubCommands}}
|
||||
|
||||
Available Sub-commands:{{range .Commands}}{{if .IsAvailableCommand}}
|
||||
{{rpad .Name .NamePadding }} {{.Short}}{{end}}{{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}}
|
||||
|
||||
Usage:{{if .Runnable}}
|
||||
{{if .HasFlags}}{{appendIfNotPresent .UseLine "[flags]"}}{{else}}{{.UseLine}}{{end}}{{end}}{{ if .HasSubCommands }}
|
||||
{{ .CommandPath}} [command]
|
||||
|
||||
Use "{{.CommandPath}} [command] --help" for more information about a command.{{end}}
|
||||
`
|
||||
help_template = `{{with or .Long .Short }}{{. | trim}}{{end}}{{if or .Runnable .HasSubCommands}}{{.UsageString}}{{end}}`
|
||||
)
|
||||
|
||||
// NewKubectlCommand creates the `kubectl` command and its nested children.
|
||||
|
61
pkg/kubectl/cmd/templates/command_groups.go
Normal file
61
pkg/kubectl/cmd/templates/command_groups.go
Normal file
@ -0,0 +1,61 @@
|
||||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package templates
|
||||
|
||||
import (
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
type CommandGroup struct {
|
||||
Message string
|
||||
Commands []*cobra.Command
|
||||
}
|
||||
|
||||
type CommandGroups []CommandGroup
|
||||
|
||||
func (g CommandGroups) Add(c *cobra.Command) {
|
||||
for _, group := range g {
|
||||
for _, command := range group.Commands {
|
||||
c.AddCommand(command)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (g CommandGroups) Has(c *cobra.Command) bool {
|
||||
for _, group := range g {
|
||||
for _, command := range group.Commands {
|
||||
if command == c {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func AddAdditionalCommands(g CommandGroups, message string, cmds []*cobra.Command) CommandGroups {
|
||||
group := CommandGroup{Message: message}
|
||||
for _, c := range cmds {
|
||||
// Don't show commands that have no short description
|
||||
if !g.Has(c) && len(c.Short) != 0 {
|
||||
group.Commands = append(group.Commands, c)
|
||||
}
|
||||
}
|
||||
if len(group.Commands) == 0 {
|
||||
return g
|
||||
}
|
||||
return append(g, group)
|
||||
}
|
@ -23,73 +23,12 @@ import (
|
||||
"text/template"
|
||||
"unicode"
|
||||
|
||||
"k8s.io/kubernetes/pkg/util/term"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
flag "github.com/spf13/pflag"
|
||||
)
|
||||
|
||||
// Content of this package was borrowed from openshift/origin.
|
||||
|
||||
type CommandGroup struct {
|
||||
Message string
|
||||
Commands []*cobra.Command
|
||||
}
|
||||
|
||||
type CommandGroups []CommandGroup
|
||||
|
||||
func (g CommandGroups) Add(c *cobra.Command) {
|
||||
for _, group := range g {
|
||||
for _, command := range group.Commands {
|
||||
c.AddCommand(command)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (g CommandGroups) Has(c *cobra.Command) bool {
|
||||
for _, group := range g {
|
||||
for _, command := range group.Commands {
|
||||
if command == c {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func AddAdditionalCommands(g CommandGroups, message string, cmds []*cobra.Command) CommandGroups {
|
||||
group := CommandGroup{Message: message}
|
||||
for _, c := range cmds {
|
||||
// Don't show commands that has no short description
|
||||
if !g.Has(c) && len(c.Short) != 0 {
|
||||
group.Commands = append(group.Commands, c)
|
||||
}
|
||||
}
|
||||
if len(group.Commands) == 0 {
|
||||
return g
|
||||
}
|
||||
return append(g, group)
|
||||
}
|
||||
|
||||
func filter(cmds []*cobra.Command, names ...string) []*cobra.Command {
|
||||
out := []*cobra.Command{}
|
||||
for _, c := range cmds {
|
||||
if c.Hidden {
|
||||
continue
|
||||
}
|
||||
skip := false
|
||||
for _, name := range names {
|
||||
if name == c.Name() {
|
||||
skip = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if skip {
|
||||
continue
|
||||
}
|
||||
out = append(out, c)
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
type FlagExposer interface {
|
||||
ExposeFlags(cmd *cobra.Command, flags ...string) FlagExposer
|
||||
}
|
||||
@ -98,27 +37,30 @@ func ActsAsRootCommand(cmd *cobra.Command, filters []string, groups ...CommandGr
|
||||
if cmd == nil {
|
||||
panic("nil root command")
|
||||
}
|
||||
cmd.SetHelpTemplate(MainHelpTemplate())
|
||||
templater := &templater{
|
||||
RootCmd: cmd,
|
||||
UsageTemplate: MainUsageTemplate(),
|
||||
HelpTemplate: MainHelpTemplate(),
|
||||
CommandGroups: groups,
|
||||
Filtered: filters,
|
||||
}
|
||||
cmd.SetUsageFunc(templater.UsageFunc())
|
||||
cmd.SetHelpFunc(templater.HelpFunc())
|
||||
return templater
|
||||
}
|
||||
|
||||
func UseOptionsTemplates(cmd *cobra.Command) {
|
||||
cmd.SetHelpTemplate(OptionsHelpTemplate())
|
||||
templater := &templater{
|
||||
UsageTemplate: OptionsUsageTemplate(),
|
||||
HelpTemplate: OptionsHelpTemplate(),
|
||||
}
|
||||
cmd.SetUsageFunc(templater.UsageFunc())
|
||||
cmd.SetHelpFunc(templater.HelpFunc())
|
||||
}
|
||||
|
||||
type templater struct {
|
||||
UsageTemplate string
|
||||
HelpTemplate string
|
||||
RootCmd *cobra.Command
|
||||
CommandGroups
|
||||
Filtered []string
|
||||
@ -129,42 +71,58 @@ func (templater *templater) ExposeFlags(cmd *cobra.Command, flags ...string) Fla
|
||||
return templater
|
||||
}
|
||||
|
||||
func (templater *templater) HelpFunc() func(*cobra.Command, []string) {
|
||||
return func(c *cobra.Command, s []string) {
|
||||
t := template.New("help")
|
||||
t.Funcs(templater.templateFuncs())
|
||||
template.Must(t.Parse(templater.HelpTemplate))
|
||||
out := term.NewResponsiveWriter(c.OutOrStdout())
|
||||
err := t.Execute(out, c)
|
||||
if err != nil {
|
||||
c.Println(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (templater *templater) UsageFunc(exposedFlags ...string) func(*cobra.Command) error {
|
||||
return func(c *cobra.Command) error {
|
||||
t := template.New("custom")
|
||||
t := template.New("usage")
|
||||
t.Funcs(templater.templateFuncs(exposedFlags...))
|
||||
template.Must(t.Parse(templater.UsageTemplate))
|
||||
out := term.NewResponsiveWriter(c.OutOrStderr())
|
||||
return t.Execute(out, c)
|
||||
}
|
||||
}
|
||||
|
||||
t.Funcs(template.FuncMap{
|
||||
"trim": strings.TrimSpace,
|
||||
"trimRight": func(s string) string { return strings.TrimRightFunc(s, unicode.IsSpace) },
|
||||
"trimLeft": func(s string) string { return strings.TrimLeftFunc(s, unicode.IsSpace) },
|
||||
"gt": cobra.Gt,
|
||||
"eq": cobra.Eq,
|
||||
"rpad": rpad,
|
||||
"appendIfNotPresent": appendIfNotPresent,
|
||||
"flagsNotIntersected": flagsNotIntersected,
|
||||
"visibleFlags": visibleFlags,
|
||||
"flagsUsages": flagsUsages,
|
||||
"indentLines": indentLines,
|
||||
"cmdGroups": templater.cmdGroups,
|
||||
"rootCmd": templater.rootCmdName,
|
||||
"isRootCmd": templater.isRootCmd,
|
||||
"optionsCmdFor": templater.optionsCmdFor,
|
||||
"usageLine": templater.usageLine,
|
||||
"exposed": func(c *cobra.Command) *flag.FlagSet {
|
||||
exposed := flag.NewFlagSet("exposed", flag.ContinueOnError)
|
||||
if len(exposedFlags) > 0 {
|
||||
for _, name := range exposedFlags {
|
||||
if flag := c.Flags().Lookup(name); flag != nil {
|
||||
exposed.AddFlag(flag)
|
||||
}
|
||||
func (templater *templater) templateFuncs(exposedFlags ...string) template.FuncMap {
|
||||
return template.FuncMap{
|
||||
"trim": strings.TrimSpace,
|
||||
"trimRight": func(s string) string { return strings.TrimRightFunc(s, unicode.IsSpace) },
|
||||
"trimLeft": func(s string) string { return strings.TrimLeftFunc(s, unicode.IsSpace) },
|
||||
"gt": cobra.Gt,
|
||||
"eq": cobra.Eq,
|
||||
"rpad": rpad,
|
||||
"appendIfNotPresent": appendIfNotPresent,
|
||||
"flagsNotIntersected": flagsNotIntersected,
|
||||
"visibleFlags": visibleFlags,
|
||||
"flagsUsages": flagsUsages,
|
||||
"cmdGroups": templater.cmdGroups,
|
||||
"cmdGroupsString": templater.cmdGroupsString,
|
||||
"rootCmd": templater.rootCmdName,
|
||||
"isRootCmd": templater.isRootCmd,
|
||||
"optionsCmdFor": templater.optionsCmdFor,
|
||||
"usageLine": templater.usageLine,
|
||||
"exposed": func(c *cobra.Command) *flag.FlagSet {
|
||||
exposed := flag.NewFlagSet("exposed", flag.ContinueOnError)
|
||||
if len(exposedFlags) > 0 {
|
||||
for _, name := range exposedFlags {
|
||||
if flag := c.Flags().Lookup(name); flag != nil {
|
||||
exposed.AddFlag(flag)
|
||||
}
|
||||
}
|
||||
return exposed
|
||||
},
|
||||
})
|
||||
|
||||
template.Must(t.Parse(templater.UsageTemplate))
|
||||
return t.Execute(c.OutOrStdout(), c)
|
||||
}
|
||||
return exposed
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@ -182,6 +140,20 @@ func (templater *templater) cmdGroups(c *cobra.Command, all []*cobra.Command) []
|
||||
}
|
||||
}
|
||||
|
||||
func (t *templater) cmdGroupsString(c *cobra.Command) string {
|
||||
groups := []string{}
|
||||
for _, cmdGroup := range t.cmdGroups(c, c.Commands()) {
|
||||
cmds := []string{cmdGroup.Message}
|
||||
for _, cmd := range cmdGroup.Commands {
|
||||
if cmd.Runnable() {
|
||||
cmds = append(cmds, " "+rpad(cmd.Name(), cmd.NamePadding())+" "+cmd.Short)
|
||||
}
|
||||
}
|
||||
groups = append(groups, strings.Join(cmds, "\n"))
|
||||
}
|
||||
return strings.Join(groups, "\n\n")
|
||||
}
|
||||
|
||||
func (t *templater) rootCmdName(c *cobra.Command) string {
|
||||
return t.rootCmd(c).CommandPath()
|
||||
}
|
||||
@ -298,3 +270,24 @@ func visibleFlags(l *flag.FlagSet) *flag.FlagSet {
|
||||
})
|
||||
return f
|
||||
}
|
||||
|
||||
func filter(cmds []*cobra.Command, names ...string) []*cobra.Command {
|
||||
out := []*cobra.Command{}
|
||||
for _, c := range cmds {
|
||||
if c.Hidden {
|
||||
continue
|
||||
}
|
||||
skip := false
|
||||
for _, name := range names {
|
||||
if name == c.Name() {
|
||||
skip = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if skip {
|
||||
continue
|
||||
}
|
||||
out = append(out, c)
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
@ -16,84 +16,87 @@ limitations under the License.
|
||||
|
||||
package templates
|
||||
|
||||
import "strings"
|
||||
|
||||
func MainHelpTemplate() string {
|
||||
return decorate(mainHelpTemplate, false)
|
||||
}
|
||||
|
||||
func MainUsageTemplate() string {
|
||||
return decorate(mainUsageTemplate, true) + "\n"
|
||||
}
|
||||
|
||||
func OptionsHelpTemplate() string {
|
||||
return decorate(optionsHelpTemplate, false)
|
||||
}
|
||||
|
||||
func OptionsUsageTemplate() string {
|
||||
return decorate(optionsUsageTemplate, false)
|
||||
}
|
||||
|
||||
func decorate(template string, trim bool) string {
|
||||
if trim && len(strings.Trim(template, " ")) > 0 {
|
||||
template = strings.Trim(template, "\n")
|
||||
}
|
||||
return template
|
||||
}
|
||||
import (
|
||||
"strings"
|
||||
"unicode"
|
||||
)
|
||||
|
||||
const (
|
||||
vars = `{{$isRootCmd := isRootCmd .}}` +
|
||||
// SectionVars is the help template section that declares variables to be used in the template.
|
||||
SectionVars = `{{$isRootCmd := isRootCmd .}}` +
|
||||
`{{$rootCmd := rootCmd .}}` +
|
||||
`{{$visibleFlags := visibleFlags (flagsNotIntersected .LocalFlags .PersistentFlags)}}` +
|
||||
`{{$explicitlyExposedFlags := exposed .}}` +
|
||||
`{{$optionsCmdFor := optionsCmdFor .}}` +
|
||||
`{{$usageLine := usageLine .}}`
|
||||
|
||||
mainHelpTemplate = `{{with or .Long .Short }}{{. | trim}}{{end}}{{if or .Runnable .HasSubCommands}}{{.UsageString}}{{end}}`
|
||||
// SectionAliases is the help template section that displays command aliases.
|
||||
SectionAliases = `{{if gt .Aliases 0}}Aliases:
|
||||
{{.NameAndAliases}}
|
||||
|
||||
mainUsageTemplate = vars +
|
||||
// ALIASES
|
||||
`{{if gt .Aliases 0}}
|
||||
{{end}}`
|
||||
|
||||
Aliases:
|
||||
{{.NameAndAliases}}{{end}}` +
|
||||
// SectionExamples is the help template section that displays command examples.
|
||||
SectionExamples = `{{if .HasExample}}Examples:
|
||||
{{trimRight .Example}}
|
||||
|
||||
// EXAMPLES
|
||||
`{{if .HasExample}}
|
||||
{{end}}`
|
||||
|
||||
Examples:
|
||||
{{ .Example}}{{end}}` +
|
||||
// SectionSubcommands is the help template section that displays the command's subcommands.
|
||||
SectionSubcommands = `{{if .HasAvailableSubCommands}}{{cmdGroupsString .}}
|
||||
|
||||
// SUBCOMMANDS
|
||||
`{{ if .HasAvailableSubCommands}}
|
||||
{{range cmdGroups . .Commands}}
|
||||
{{.Message}}
|
||||
{{range .Commands}}{{if .Runnable}} {{rpad .Name .NamePadding }} {{.Short}}
|
||||
{{end}}{{end}}{{end}}{{end}}` +
|
||||
{{end}}`
|
||||
|
||||
// VISIBLE FLAGS
|
||||
`{{ if or $visibleFlags.HasFlags $explicitlyExposedFlags.HasFlags}}
|
||||
// SectionFlags is the help template section that displays the command's flags.
|
||||
SectionFlags = `{{ if or $visibleFlags.HasFlags $explicitlyExposedFlags.HasFlags}}Options:
|
||||
{{ if $visibleFlags.HasFlags}}{{trimRight (flagsUsages $visibleFlags)}}{{end}}{{ if $explicitlyExposedFlags.HasFlags}}{{trimRight (flagsUsages $explicitlyExposedFlags)}}{{end}}
|
||||
|
||||
Options:
|
||||
{{ if $visibleFlags.HasFlags}}{{flagsUsages $visibleFlags}}{{end}}{{ if $explicitlyExposedFlags.HasFlags}}{{flagsUsages $explicitlyExposedFlags}}{{end}}{{end}}` +
|
||||
{{end}}`
|
||||
|
||||
// USAGE LINE
|
||||
`{{if and .Runnable (ne .UseLine "") (ne .UseLine $rootCmd)}}
|
||||
Usage:
|
||||
// SectionUsage is the help template section that displays the command's usage.
|
||||
SectionUsage = `{{if and .Runnable (ne .UseLine "") (ne .UseLine $rootCmd)}}Usage:
|
||||
{{$usageLine}}
|
||||
{{end}}` +
|
||||
|
||||
// TIPS: --help
|
||||
`{{ if .HasSubCommands }}
|
||||
Use "{{$rootCmd}} <command> --help" for more information about a given command.{{end}}` +
|
||||
{{end}}`
|
||||
|
||||
// TIPS: global options
|
||||
`{{ if $optionsCmdFor}}
|
||||
Use "{{$optionsCmdFor}}" for a list of global command-line options (applies to all commands).{{end}}`
|
||||
// SectionTipsHelp is the help template section that displays the '--help' hint.
|
||||
SectionTipsHelp = `{{if .HasSubCommands}}Use "{{$rootCmd}} <command> --help" for more information about a given command.
|
||||
{{end}}`
|
||||
|
||||
optionsHelpTemplate = ``
|
||||
// SectionTipsGlobalOptions is the help template section that displays the 'options' hint for displaying global flags.
|
||||
SectionTipsGlobalOptions = `{{if $optionsCmdFor}}Use "{{$optionsCmdFor}}" for a list of global command-line options (applies to all commands).
|
||||
{{end}}`
|
||||
)
|
||||
|
||||
optionsUsageTemplate = `{{ if .HasInheritedFlags}}The following options can be passed to any command:
|
||||
// MainHelpTemplate if the template for 'help' used by most commands.
|
||||
func MainHelpTemplate() string {
|
||||
return `{{with or .Long .Short }}{{. | trim}}{{end}}{{if or .Runnable .HasSubCommands}}{{.UsageString}}{{end}}`
|
||||
}
|
||||
|
||||
// MainUsageTemplate if the template for 'usage' used by most commands.
|
||||
func MainUsageTemplate() string {
|
||||
sections := []string{
|
||||
"\n\n",
|
||||
SectionVars,
|
||||
SectionAliases,
|
||||
SectionExamples,
|
||||
SectionSubcommands,
|
||||
SectionFlags,
|
||||
SectionUsage,
|
||||
SectionTipsHelp,
|
||||
SectionTipsGlobalOptions,
|
||||
}
|
||||
return strings.TrimRightFunc(strings.Join(sections, ""), unicode.IsSpace)
|
||||
}
|
||||
|
||||
// OptionsHelpTemplate if the template for 'help' used by the 'options' command.
|
||||
func OptionsHelpTemplate() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
// OptionsUsageTemplate if the template for 'usage' used by the 'options' command.
|
||||
func OptionsUsageTemplate() string {
|
||||
return `{{ if .HasInheritedFlags}}The following options can be passed to any command:
|
||||
|
||||
{{flagsUsages .InheritedFlags}}{{end}}`
|
||||
)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user