Merge pull request #104736 from lauchokyip/improveFlags
Beautify kubectl help flag commands Kubernetes-commit: 750cb93e62bad7bc798b75c96eb4ff0f6f1883b9
This commit is contained in:
commit
ef04426c7b
4
go.mod
4
go.mod
|
@ -33,7 +33,7 @@ require (
|
||||||
gopkg.in/yaml.v2 v2.4.0
|
gopkg.in/yaml.v2 v2.4.0
|
||||||
k8s.io/api v0.0.0-20220324210930-df53a95c65aa
|
k8s.io/api v0.0.0-20220324210930-df53a95c65aa
|
||||||
k8s.io/apimachinery v0.0.0-20220324210734-b68ae5efb0e8
|
k8s.io/apimachinery v0.0.0-20220324210734-b68ae5efb0e8
|
||||||
k8s.io/cli-runtime v0.0.0-20220324213237-c15667ffec05
|
k8s.io/cli-runtime v0.0.0-20220325012647-524d19e1c796
|
||||||
k8s.io/client-go v0.0.0-20220324211221-af0252eed9c0
|
k8s.io/client-go v0.0.0-20220324211221-af0252eed9c0
|
||||||
k8s.io/component-base v0.0.0-20220324211736-57e5b231b63e
|
k8s.io/component-base v0.0.0-20220324211736-57e5b231b63e
|
||||||
k8s.io/component-helpers v0.0.0-20220324211837-3d0aa6c934c2
|
k8s.io/component-helpers v0.0.0-20220324211837-3d0aa6c934c2
|
||||||
|
@ -50,7 +50,7 @@ require (
|
||||||
replace (
|
replace (
|
||||||
k8s.io/api => k8s.io/api v0.0.0-20220324210930-df53a95c65aa
|
k8s.io/api => k8s.io/api v0.0.0-20220324210930-df53a95c65aa
|
||||||
k8s.io/apimachinery => k8s.io/apimachinery v0.0.0-20220324210734-b68ae5efb0e8
|
k8s.io/apimachinery => k8s.io/apimachinery v0.0.0-20220324210734-b68ae5efb0e8
|
||||||
k8s.io/cli-runtime => k8s.io/cli-runtime v0.0.0-20220324213237-c15667ffec05
|
k8s.io/cli-runtime => k8s.io/cli-runtime v0.0.0-20220325012647-524d19e1c796
|
||||||
k8s.io/client-go => k8s.io/client-go v0.0.0-20220324211221-af0252eed9c0
|
k8s.io/client-go => k8s.io/client-go v0.0.0-20220324211221-af0252eed9c0
|
||||||
k8s.io/code-generator => k8s.io/code-generator v0.0.0-20220324210542-671bd3e7b101
|
k8s.io/code-generator => k8s.io/code-generator v0.0.0-20220324210542-671bd3e7b101
|
||||||
k8s.io/component-base => k8s.io/component-base v0.0.0-20220324211736-57e5b231b63e
|
k8s.io/component-base => k8s.io/component-base v0.0.0-20220324211736-57e5b231b63e
|
||||||
|
|
4
go.sum
4
go.sum
|
@ -852,8 +852,8 @@ k8s.io/api v0.0.0-20220324210930-df53a95c65aa h1:NzCktMsy22Y/ddoBN/kf96kFaklITIH
|
||||||
k8s.io/api v0.0.0-20220324210930-df53a95c65aa/go.mod h1:Ea6ReZGsqdWOZc66t7sHO58lTcUGyQcMJ3UfsqOnKfM=
|
k8s.io/api v0.0.0-20220324210930-df53a95c65aa/go.mod h1:Ea6ReZGsqdWOZc66t7sHO58lTcUGyQcMJ3UfsqOnKfM=
|
||||||
k8s.io/apimachinery v0.0.0-20220324210734-b68ae5efb0e8 h1:LULUz36bFy2WqAjJVZAbn4yVJ92Xn7oBaUCF6BR8HDk=
|
k8s.io/apimachinery v0.0.0-20220324210734-b68ae5efb0e8 h1:LULUz36bFy2WqAjJVZAbn4yVJ92Xn7oBaUCF6BR8HDk=
|
||||||
k8s.io/apimachinery v0.0.0-20220324210734-b68ae5efb0e8/go.mod h1:V4ECjDypP1xQpnL3N9yFzlbGZgd8tLKouJnRyAn/Zyw=
|
k8s.io/apimachinery v0.0.0-20220324210734-b68ae5efb0e8/go.mod h1:V4ECjDypP1xQpnL3N9yFzlbGZgd8tLKouJnRyAn/Zyw=
|
||||||
k8s.io/cli-runtime v0.0.0-20220324213237-c15667ffec05 h1:XElf3z4AiZ6ZBDGs+hR/xTWH+4QRXbIMzL2dwaTmV54=
|
k8s.io/cli-runtime v0.0.0-20220325012647-524d19e1c796 h1:Y7FlIv0av0nqBIfnCIPkqqRw4absoKoxg0rFQlC4k2w=
|
||||||
k8s.io/cli-runtime v0.0.0-20220324213237-c15667ffec05/go.mod h1:O2DkSiS1T4zJvcVaGWoTeMtiuEeAuKgE0vJ5yNMJJRo=
|
k8s.io/cli-runtime v0.0.0-20220325012647-524d19e1c796/go.mod h1:O2DkSiS1T4zJvcVaGWoTeMtiuEeAuKgE0vJ5yNMJJRo=
|
||||||
k8s.io/client-go v0.0.0-20220324211221-af0252eed9c0 h1:1CEitsCQXwuKQ22HYRYCgZPi0+3RXCQsiQlOAkkGAAI=
|
k8s.io/client-go v0.0.0-20220324211221-af0252eed9c0 h1:1CEitsCQXwuKQ22HYRYCgZPi0+3RXCQsiQlOAkkGAAI=
|
||||||
k8s.io/client-go v0.0.0-20220324211221-af0252eed9c0/go.mod h1:sVLZTMIBHUCD7MFbyyUPejZNIlOLYZ2aZcZuP0z1aI0=
|
k8s.io/client-go v0.0.0-20220324211221-af0252eed9c0/go.mod h1:sVLZTMIBHUCD7MFbyyUPejZNIlOLYZ2aZcZuP0z1aI0=
|
||||||
k8s.io/code-generator v0.0.0-20220324210542-671bd3e7b101/go.mod h1:PF9AME2o5S390iHxUI2/febDrY7GRb+AECnBzIWxIO0=
|
k8s.io/code-generator v0.0.0-20220324210542-671bd3e7b101/go.mod h1:PF9AME2o5S390iHxUI2/febDrY7GRb+AECnBzIWxIO0=
|
||||||
|
|
|
@ -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