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
|
||||
k8s.io/api v0.0.0-20220324210930-df53a95c65aa
|
||||
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/component-base v0.0.0-20220324211736-57e5b231b63e
|
||||
k8s.io/component-helpers v0.0.0-20220324211837-3d0aa6c934c2
|
||||
|
@ -50,7 +50,7 @@ require (
|
|||
replace (
|
||||
k8s.io/api => k8s.io/api v0.0.0-20220324210930-df53a95c65aa
|
||||
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/code-generator => k8s.io/code-generator v0.0.0-20220324210542-671bd3e7b101
|
||||
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/apimachinery v0.0.0-20220324210734-b68ae5efb0e8 h1:LULUz36bFy2WqAjJVZAbn4yVJ92Xn7oBaUCF6BR8HDk=
|
||||
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-20220324213237-c15667ffec05/go.mod h1:O2DkSiS1T4zJvcVaGWoTeMtiuEeAuKgE0vJ5yNMJJRo=
|
||||
k8s.io/cli-runtime v0.0.0-20220325012647-524d19e1c796 h1:Y7FlIv0av0nqBIfnCIPkqqRw4absoKoxg0rFQlC4k2w=
|
||||
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/go.mod h1:sVLZTMIBHUCD7MFbyyUPejZNIlOLYZ2aZcZuP0z1aI0=
|
||||
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().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().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")
|
||||
usage := "that contains the last-applied-configuration annotations"
|
||||
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().StringP("output", "o", "", "Output format. One of: name")
|
||||
cmd.Flags().StringP("output", "o", "", `Output format. One of: (name).`)
|
||||
return cmd
|
||||
}
|
||||
|
||||
|
|
|
@ -162,7 +162,7 @@ func (f *PrintFlags) AddFlags(cmd *cobra.Command) {
|
|||
f.CustomColumnsFlags.AddFlags(cmd)
|
||||
|
||||
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(
|
||||
"output",
|
||||
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"
|
||||
"unicode"
|
||||
|
||||
"k8s.io/kubectl/pkg/util/term"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
flag "github.com/spf13/pflag"
|
||||
|
||||
"k8s.io/kubectl/pkg/util/term"
|
||||
)
|
||||
|
||||
type FlagExposer interface {
|
||||
|
@ -160,7 +160,7 @@ func (t *templater) cmdGroupsString(c *cobra.Command) string {
|
|||
cmds := []string{cmdGroup.Message}
|
||||
for _, cmd := range cmdGroup.Commands {
|
||||
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"))
|
||||
|
@ -218,34 +218,40 @@ func (t *templater) usageLine(c *cobra.Command) string {
|
|||
return usage
|
||||
}
|
||||
|
||||
func flagsUsages(f *flag.FlagSet) string {
|
||||
x := new(bytes.Buffer)
|
||||
// flagsUsages will print out the kubectl help flags
|
||||
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) {
|
||||
if flag.Hidden {
|
||||
return
|
||||
}
|
||||
format := "--%s=%s: %s%s\n"
|
||||
|
||||
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)
|
||||
printer.PrintHelpFlag(flag)
|
||||
})
|
||||
|
||||
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 {
|
||||
|
|
|
@ -17,11 +17,14 @@ limitations under the License.
|
|||
package term
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io"
|
||||
"os"
|
||||
|
||||
wordwrap "github.com/mitchellh/go-wordwrap"
|
||||
"github.com/moby/term"
|
||||
|
||||
"k8s.io/client-go/tools/remotecommand"
|
||||
)
|
||||
|
||||
type wordWrapWriter struct {
|
||||
|
@ -51,16 +54,7 @@ func NewResponsiveWriter(w io.Writer) io.Writer {
|
|||
if terminalSize == nil {
|
||||
return w
|
||||
}
|
||||
|
||||
var limit uint
|
||||
switch {
|
||||
case terminalSize.Width >= 120:
|
||||
limit = 120
|
||||
case terminalSize.Width >= 100:
|
||||
limit = 100
|
||||
case terminalSize.Width >= 80:
|
||||
limit = 80
|
||||
}
|
||||
limit := getTerminalLimitWidth(terminalSize)
|
||||
|
||||
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) {
|
||||
if w.limit == 0 {
|
||||
return w.writer.Write(p)
|
||||
|
|
Loading…
Reference in New Issue