mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-21 10:51:29 +00:00
Merge pull request #104736 from lauchokyip/improveFlags
Beautify kubectl help flag commands
This commit is contained in:
commit
750cb93e62
@ -136,7 +136,7 @@ func (f *PrintFlags) AddFlags(cmd *cobra.Command) {
|
|||||||
f.TemplatePrinterFlags.AddFlags(cmd)
|
f.TemplatePrinterFlags.AddFlags(cmd)
|
||||||
|
|
||||||
if f.OutputFormat != nil {
|
if f.OutputFormat != nil {
|
||||||
cmd.Flags().StringVarP(f.OutputFormat, "output", "o", *f.OutputFormat, fmt.Sprintf("Output format. One of: %s.", strings.Join(f.AllowedFormats(), "|")))
|
cmd.Flags().StringVarP(f.OutputFormat, "output", "o", *f.OutputFormat, fmt.Sprintf(`Output format. One of: (%s).`, strings.Join(f.AllowedFormats(), ", ")))
|
||||||
if f.OutputFlagSpecified == nil {
|
if f.OutputFlagSpecified == nil {
|
||||||
f.OutputFlagSpecified = func() bool {
|
f.OutputFlagSpecified = func() bool {
|
||||||
return cmd.Flag("output").Changed
|
return cmd.Flag("output").Changed
|
||||||
|
@ -105,7 +105,7 @@ func NewCmdAPIResources(f cmdutil.Factory, ioStreams genericclioptions.IOStreams
|
|||||||
}
|
}
|
||||||
|
|
||||||
cmd.Flags().BoolVar(&o.NoHeaders, "no-headers", o.NoHeaders, "When using the default or custom-column output format, don't print headers (default print headers).")
|
cmd.Flags().BoolVar(&o.NoHeaders, "no-headers", o.NoHeaders, "When using the default or custom-column output format, don't print headers (default print headers).")
|
||||||
cmd.Flags().StringVarP(&o.Output, "output", "o", o.Output, "Output format. One of: wide|name.")
|
cmd.Flags().StringVarP(&o.Output, "output", "o", o.Output, `Output format. One of: (wide, name).`)
|
||||||
|
|
||||||
cmd.Flags().StringVar(&o.APIGroup, "api-group", o.APIGroup, "Limit to resources in the specified API group.")
|
cmd.Flags().StringVar(&o.APIGroup, "api-group", o.APIGroup, "Limit to resources in the specified API group.")
|
||||||
cmd.Flags().BoolVar(&o.Namespaced, "namespaced", o.Namespaced, "If false, non-namespaced resources will be returned, otherwise returning namespaced resources by default.")
|
cmd.Flags().BoolVar(&o.Namespaced, "namespaced", o.Namespaced, "If false, non-namespaced resources will be returned, otherwise returning namespaced resources by default.")
|
||||||
|
@ -85,7 +85,7 @@ func NewCmdApplyViewLastApplied(f cmdutil.Factory, ioStreams genericclioptions.I
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd.Flags().StringVarP(&options.OutputFormat, "output", "o", options.OutputFormat, "Output format. Must be one of yaml|json")
|
cmd.Flags().StringVarP(&options.OutputFormat, "output", "o", options.OutputFormat, `Output format. Must be one of (yaml, json)`)
|
||||||
cmd.Flags().BoolVar(&options.All, "all", options.All, "Select all resources in the namespace of the specified resource types")
|
cmd.Flags().BoolVar(&options.All, "all", options.All, "Select all resources in the namespace of the specified resource types")
|
||||||
usage := "that contains the last-applied-configuration annotations"
|
usage := "that contains the last-applied-configuration annotations"
|
||||||
cmdutil.AddFilenameOptionFlags(cmd, &options.FilenameOptions, usage)
|
cmdutil.AddFilenameOptionFlags(cmd, &options.FilenameOptions, usage)
|
||||||
|
@ -80,7 +80,7 @@ func NewCmdConfigGetContexts(streams genericclioptions.IOStreams, configAccess c
|
|||||||
}
|
}
|
||||||
|
|
||||||
cmd.Flags().Bool("no-headers", false, "When using the default or custom-column output format, don't print headers (default print headers).")
|
cmd.Flags().Bool("no-headers", false, "When using the default or custom-column output format, don't print headers (default print headers).")
|
||||||
cmd.Flags().StringP("output", "o", "", "Output format. One of: name")
|
cmd.Flags().StringP("output", "o", "", `Output format. One of: (name).`)
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -162,7 +162,7 @@ func (f *PrintFlags) AddFlags(cmd *cobra.Command) {
|
|||||||
f.CustomColumnsFlags.AddFlags(cmd)
|
f.CustomColumnsFlags.AddFlags(cmd)
|
||||||
|
|
||||||
if f.OutputFormat != nil {
|
if f.OutputFormat != nil {
|
||||||
cmd.Flags().StringVarP(f.OutputFormat, "output", "o", *f.OutputFormat, fmt.Sprintf("Output format. One of: %s See custom columns [https://kubernetes.io/docs/reference/kubectl/overview/#custom-columns], golang template [http://golang.org/pkg/text/template/#pkg-overview] and jsonpath template [https://kubernetes.io/docs/reference/kubectl/jsonpath/].", strings.Join(f.AllowedFormats(), "|")))
|
cmd.Flags().StringVarP(f.OutputFormat, "output", "o", *f.OutputFormat, fmt.Sprintf(`Output format. One of: (%s). See custom columns [https://kubernetes.io/docs/reference/kubectl/overview/#custom-columns], golang template [http://golang.org/pkg/text/template/#pkg-overview] and jsonpath template [https://kubernetes.io/docs/reference/kubectl/jsonpath/].`, strings.Join(f.AllowedFormats(), ", ")))
|
||||||
util.CheckErr(cmd.RegisterFlagCompletionFunc(
|
util.CheckErr(cmd.RegisterFlagCompletionFunc(
|
||||||
"output",
|
"output",
|
||||||
func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
|
func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
|
||||||
|
@ -0,0 +1,76 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2022 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 (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/mitchellh/go-wordwrap"
|
||||||
|
flag "github.com/spf13/pflag"
|
||||||
|
)
|
||||||
|
|
||||||
|
const offset = 10
|
||||||
|
|
||||||
|
// HelpFlagPrinter is a printer that
|
||||||
|
// processes the help flag and print
|
||||||
|
// it to i/o writer
|
||||||
|
type HelpFlagPrinter struct {
|
||||||
|
wrapLimit uint
|
||||||
|
out io.Writer
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewHelpFlagPrinter will initialize a HelpFlagPrinter given the
|
||||||
|
// i/o writer
|
||||||
|
func NewHelpFlagPrinter(out io.Writer, wrapLimit uint) *HelpFlagPrinter {
|
||||||
|
return &HelpFlagPrinter{
|
||||||
|
wrapLimit: wrapLimit,
|
||||||
|
out: out,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// PrintHelpFlag will beautify the help flags and print it out to p.out
|
||||||
|
func (p *HelpFlagPrinter) PrintHelpFlag(flag *flag.Flag) {
|
||||||
|
formatBuf := new(bytes.Buffer)
|
||||||
|
writeFlag(formatBuf, flag)
|
||||||
|
|
||||||
|
wrappedStr := formatBuf.String()
|
||||||
|
flagAndUsage := strings.Split(formatBuf.String(), "\n")
|
||||||
|
flagStr := flagAndUsage[0]
|
||||||
|
|
||||||
|
// if the flag usage is longer than one line, wrap it again
|
||||||
|
if len(flagAndUsage) > 1 {
|
||||||
|
nextLines := strings.Join(flagAndUsage[1:], " ")
|
||||||
|
wrappedUsages := wordwrap.WrapString(nextLines, p.wrapLimit-offset)
|
||||||
|
wrappedStr = flagStr + "\n" + wrappedUsages
|
||||||
|
}
|
||||||
|
appendTabStr := strings.ReplaceAll(wrappedStr, "\n", "\n\t")
|
||||||
|
|
||||||
|
fmt.Fprintf(p.out, appendTabStr+"\n\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
// writeFlag will output the help flag based
|
||||||
|
// on the format provided by getFlagFormat to i/o writer
|
||||||
|
func writeFlag(out io.Writer, f *flag.Flag) {
|
||||||
|
deprecated := ""
|
||||||
|
if f.Deprecated != "" {
|
||||||
|
deprecated = fmt.Sprintf(" (DEPRECATED: %s)", f.Deprecated)
|
||||||
|
}
|
||||||
|
fmt.Fprintf(out, getFlagFormat(f), f.Shorthand, f.Name, f.DefValue, f.Usage, deprecated)
|
||||||
|
}
|
@ -23,10 +23,10 @@ import (
|
|||||||
"text/template"
|
"text/template"
|
||||||
"unicode"
|
"unicode"
|
||||||
|
|
||||||
"k8s.io/kubectl/pkg/util/term"
|
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
flag "github.com/spf13/pflag"
|
flag "github.com/spf13/pflag"
|
||||||
|
|
||||||
|
"k8s.io/kubectl/pkg/util/term"
|
||||||
)
|
)
|
||||||
|
|
||||||
type FlagExposer interface {
|
type FlagExposer interface {
|
||||||
@ -160,7 +160,7 @@ func (t *templater) cmdGroupsString(c *cobra.Command) string {
|
|||||||
cmds := []string{cmdGroup.Message}
|
cmds := []string{cmdGroup.Message}
|
||||||
for _, cmd := range cmdGroup.Commands {
|
for _, cmd := range cmdGroup.Commands {
|
||||||
if cmd.IsAvailableCommand() {
|
if cmd.IsAvailableCommand() {
|
||||||
cmds = append(cmds, " "+rpad(cmd.Name(), cmd.NamePadding())+" "+cmd.Short)
|
cmds = append(cmds, " "+rpad(cmd.Name(), cmd.NamePadding())+" "+cmd.Short)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
groups = append(groups, strings.Join(cmds, "\n"))
|
groups = append(groups, strings.Join(cmds, "\n"))
|
||||||
@ -218,34 +218,40 @@ func (t *templater) usageLine(c *cobra.Command) string {
|
|||||||
return usage
|
return usage
|
||||||
}
|
}
|
||||||
|
|
||||||
func flagsUsages(f *flag.FlagSet) string {
|
// flagsUsages will print out the kubectl help flags
|
||||||
x := new(bytes.Buffer)
|
func flagsUsages(f *flag.FlagSet) (string, error) {
|
||||||
|
flagBuf := new(bytes.Buffer)
|
||||||
|
wrapLimit, err := term.GetWordWrapperLimit()
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
printer := NewHelpFlagPrinter(flagBuf, wrapLimit)
|
||||||
|
|
||||||
f.VisitAll(func(flag *flag.Flag) {
|
f.VisitAll(func(flag *flag.Flag) {
|
||||||
if flag.Hidden {
|
if flag.Hidden {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
format := "--%s=%s: %s%s\n"
|
printer.PrintHelpFlag(flag)
|
||||||
|
|
||||||
if flag.Value.Type() == "string" {
|
|
||||||
format = "--%s='%s': %s%s\n"
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(flag.Shorthand) > 0 {
|
|
||||||
format = " -%s, " + format
|
|
||||||
} else {
|
|
||||||
format = " %s " + format
|
|
||||||
}
|
|
||||||
|
|
||||||
deprecated := ""
|
|
||||||
if flag.Deprecated != "" {
|
|
||||||
deprecated = fmt.Sprintf(" (DEPRECATED: %s)", flag.Deprecated)
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Fprintf(x, format, flag.Shorthand, flag.Name, flag.DefValue, flag.Usage, deprecated)
|
|
||||||
})
|
})
|
||||||
|
|
||||||
return x.String()
|
return flagBuf.String(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// getFlagFormat will output the flag format
|
||||||
|
func getFlagFormat(f *flag.Flag) string {
|
||||||
|
var format string
|
||||||
|
format = "--%s=%s:\n%s%s"
|
||||||
|
if f.Value.Type() == "string" {
|
||||||
|
format = "--%s='%s':\n%s%s"
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(f.Shorthand) > 0 {
|
||||||
|
format = " -%s, " + format
|
||||||
|
} else {
|
||||||
|
format = " %s" + format
|
||||||
|
}
|
||||||
|
|
||||||
|
return format
|
||||||
}
|
}
|
||||||
|
|
||||||
func rpad(s string, padding int) string {
|
func rpad(s string, padding int) string {
|
||||||
|
@ -17,11 +17,14 @@ limitations under the License.
|
|||||||
package term
|
package term
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
wordwrap "github.com/mitchellh/go-wordwrap"
|
wordwrap "github.com/mitchellh/go-wordwrap"
|
||||||
"github.com/moby/term"
|
"github.com/moby/term"
|
||||||
|
|
||||||
|
"k8s.io/client-go/tools/remotecommand"
|
||||||
)
|
)
|
||||||
|
|
||||||
type wordWrapWriter struct {
|
type wordWrapWriter struct {
|
||||||
@ -51,16 +54,7 @@ func NewResponsiveWriter(w io.Writer) io.Writer {
|
|||||||
if terminalSize == nil {
|
if terminalSize == nil {
|
||||||
return w
|
return w
|
||||||
}
|
}
|
||||||
|
limit := getTerminalLimitWidth(terminalSize)
|
||||||
var limit uint
|
|
||||||
switch {
|
|
||||||
case terminalSize.Width >= 120:
|
|
||||||
limit = 120
|
|
||||||
case terminalSize.Width >= 100:
|
|
||||||
limit = 100
|
|
||||||
case terminalSize.Width >= 80:
|
|
||||||
limit = 80
|
|
||||||
}
|
|
||||||
|
|
||||||
return NewWordWrapWriter(w, limit)
|
return NewWordWrapWriter(w, limit)
|
||||||
}
|
}
|
||||||
@ -74,6 +68,32 @@ func NewWordWrapWriter(w io.Writer, limit uint) io.Writer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getTerminalLimitWidth(terminalSize *remotecommand.TerminalSize) uint {
|
||||||
|
var limit uint
|
||||||
|
switch {
|
||||||
|
case terminalSize.Width >= 120:
|
||||||
|
limit = 120
|
||||||
|
case terminalSize.Width >= 100:
|
||||||
|
limit = 100
|
||||||
|
case terminalSize.Width >= 80:
|
||||||
|
limit = 80
|
||||||
|
}
|
||||||
|
return limit
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetWordWrapperLimit() (uint, error) {
|
||||||
|
stdout := os.Stdout
|
||||||
|
fd := stdout.Fd()
|
||||||
|
if !term.IsTerminal(fd) {
|
||||||
|
return 0, errors.New("file descriptor is not a terminal")
|
||||||
|
}
|
||||||
|
terminalSize := GetSize(fd)
|
||||||
|
if terminalSize == nil {
|
||||||
|
return 0, errors.New("terminal size is nil")
|
||||||
|
}
|
||||||
|
return getTerminalLimitWidth(terminalSize), nil
|
||||||
|
}
|
||||||
|
|
||||||
func (w wordWrapWriter) Write(p []byte) (nn int, err error) {
|
func (w wordWrapWriter) Write(p []byte) (nn int, err error) {
|
||||||
if w.limit == 0 {
|
if w.limit == 0 {
|
||||||
return w.writer.Write(p)
|
return w.writer.Write(p)
|
||||||
|
Loading…
Reference in New Issue
Block a user