update kubectl help output for better organization

pull/6/head
AdoHe 2016-08-20 08:03:39 +08:00
parent 6faa91dfb1
commit b411fe217f
8 changed files with 573 additions and 46 deletions

View File

@ -51,6 +51,7 @@ docs/man/man1/kubectl-get.1
docs/man/man1/kubectl-label.1
docs/man/man1/kubectl-logs.1
docs/man/man1/kubectl-namespace.1
docs/man/man1/kubectl-options.1
docs/man/man1/kubectl-patch.1
docs/man/man1/kubectl-port-forward.1
docs/man/man1/kubectl-proxy.1
@ -120,6 +121,7 @@ docs/user-guide/kubectl/kubectl_get.md
docs/user-guide/kubectl/kubectl_label.md
docs/user-guide/kubectl/kubectl_logs.md
docs/user-guide/kubectl/kubectl_namespace.md
docs/user-guide/kubectl/kubectl_options.md
docs/user-guide/kubectl/kubectl_patch.md
docs/user-guide/kubectl/kubectl_port-forward.md
docs/user-guide/kubectl/kubectl_proxy.md
@ -164,6 +166,7 @@ docs/yaml/kubectl/kubectl_get.yaml
docs/yaml/kubectl/kubectl_label.yaml
docs/yaml/kubectl/kubectl_logs.yaml
docs/yaml/kubectl/kubectl_namespace.yaml
docs/yaml/kubectl/kubectl_options.yaml
docs/yaml/kubectl/kubectl_patch.yaml
docs/yaml/kubectl/kubectl_port-forward.yaml
docs/yaml/kubectl/kubectl_proxy.yaml

View File

@ -0,0 +1,3 @@
This file is autogenerated, but we've stopped checking such files into the
repository to reduce the need for rebases. Please run hack/generate-docs.sh to
populate this file.

View File

@ -0,0 +1,36 @@
<!-- BEGIN MUNGE: UNVERSIONED_WARNING -->
<!-- BEGIN STRIP_FOR_RELEASE -->
<img src="http://kubernetes.io/kubernetes/img/warning.png" alt="WARNING"
width="25" height="25">
<img src="http://kubernetes.io/kubernetes/img/warning.png" alt="WARNING"
width="25" height="25">
<img src="http://kubernetes.io/kubernetes/img/warning.png" alt="WARNING"
width="25" height="25">
<img src="http://kubernetes.io/kubernetes/img/warning.png" alt="WARNING"
width="25" height="25">
<img src="http://kubernetes.io/kubernetes/img/warning.png" alt="WARNING"
width="25" height="25">
<h2>PLEASE NOTE: This document applies to the HEAD of the source tree</h2>
If you are using a released version of Kubernetes, you should
refer to the docs that go with that version.
Documentation for other releases can be found at
[releases.k8s.io](http://releases.k8s.io).
</strong>
--
<!-- END STRIP_FOR_RELEASE -->
<!-- END MUNGE: UNVERSIONED_WARNING -->
This file is autogenerated, but we've stopped checking such files into the
repository to reduce the need for rebases. Please run hack/generate-docs.sh to
populate this file.
<!-- BEGIN MUNGE: GENERATED_ANALYTICS -->
[![Analytics](https://kubernetes-site.appspot.com/UA-36037335-10/GitHub/docs/user-guide/kubectl/kubectl_options.md?pixel)]()
<!-- END MUNGE: GENERATED_ANALYTICS -->

View File

@ -0,0 +1,3 @@
This file is autogenerated, but we've stopped checking such files into the
repository to reduce the need for rebases. Please run hack/generate-docs.sh to
populate this file.

View File

@ -17,16 +17,18 @@ limitations under the License.
package cmd
import (
"fmt"
"io"
"github.com/golang/glog"
"k8s.io/kubernetes/pkg/client/unversioned/clientcmd"
cmdconfig "k8s.io/kubernetes/pkg/kubectl/cmd/config"
"k8s.io/kubernetes/pkg/kubectl/cmd/rollout"
"k8s.io/kubernetes/pkg/kubectl/cmd/set"
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
"k8s.io/kubernetes/pkg/util/flag"
"github.com/golang/glog"
"github.com/spf13/cobra"
)
@ -222,59 +224,89 @@ Find more information at https://github.com/kubernetes/kubernetes.`,
Run: runHelp,
BashCompletionFunction: bash_completion_func,
}
cmds.SetHelpTemplate(help_template)
cmds.SetUsageTemplate(usage_template)
f.BindFlags(cmds.PersistentFlags())
f.BindExternalFlags(cmds.PersistentFlags())
cmds.SetHelpCommand(NewCmdHelp(f, out))
// From this point and forward we get warnings on flags that contain "_" separators
cmds.SetGlobalNormalizationFunc(flag.WarnWordSepNormalizeFunc)
cmds.AddCommand(NewCmdGet(f, out, err))
cmds.AddCommand(set.NewCmdSet(f, out))
cmds.AddCommand(NewCmdDescribe(f, out))
cmds.AddCommand(NewCmdCreate(f, out))
cmds.AddCommand(NewCmdReplace(f, out))
cmds.AddCommand(NewCmdPatch(f, out))
cmds.AddCommand(NewCmdDelete(f, out))
cmds.AddCommand(NewCmdEdit(f, out, err))
cmds.AddCommand(NewCmdApply(f, out))
groups := templates.CommandGroups{
{
Message: "Basic Commands (Beginner):",
Commands: []*cobra.Command{
NewCmdCreate(f, out),
NewCmdExposeService(f, out),
NewCmdRun(f, in, out, err),
set.NewCmdSet(f, out),
},
},
{
Message: "Basic Commands (Intermediate):",
Commands: []*cobra.Command{
NewCmdGet(f, out, err),
NewCmdExplain(f, out),
NewCmdEdit(f, out, err),
NewCmdDelete(f, out),
},
},
{
Message: "Deploy Commands:",
Commands: []*cobra.Command{
rollout.NewCmdRollout(f, out),
NewCmdRollingUpdate(f, out),
NewCmdScale(f, out),
NewCmdAutoscale(f, out),
},
},
{
Message: "Cluster Management Commands:",
Commands: []*cobra.Command{
NewCmdClusterInfo(f, out),
NewCmdTop(f, out),
NewCmdCordon(f, out),
NewCmdUncordon(f, out),
NewCmdDrain(f, out),
NewCmdTaint(f, out),
},
},
{
Message: "Troubleshooting and Debugging Commands:",
Commands: []*cobra.Command{
NewCmdDescribe(f, out),
NewCmdLogs(f, out),
NewCmdAttach(f, in, out, err),
NewCmdExec(f, in, out, err),
NewCmdPortForward(f, out, err),
NewCmdProxy(f, out),
},
},
{
Message: "Advanced Commands:",
Commands: []*cobra.Command{
NewCmdApply(f, out),
NewCmdPatch(f, out),
NewCmdReplace(f, out),
NewCmdConvert(f, out),
},
},
{
Message: "Settings Commands:",
Commands: []*cobra.Command{
NewCmdLabel(f, out),
NewCmdAnnotate(f, out),
NewCmdCompletion(f, out),
},
},
}
groups.Add(cmds)
cmds.AddCommand(NewCmdNamespace(out))
cmds.AddCommand(NewCmdLogs(f, out))
cmds.AddCommand(NewCmdRollingUpdate(f, out))
cmds.AddCommand(NewCmdScale(f, out))
cmds.AddCommand(NewCmdCordon(f, out))
cmds.AddCommand(NewCmdDrain(f, out))
cmds.AddCommand(NewCmdUncordon(f, out))
cmds.AddCommand(NewCmdAttach(f, in, out, err))
cmds.AddCommand(NewCmdExec(f, in, out, err))
cmds.AddCommand(NewCmdPortForward(f, out, err))
cmds.AddCommand(NewCmdProxy(f, out))
cmds.AddCommand(NewCmdRun(f, in, out, err))
cmds.AddCommand(NewCmdStop(f, out))
cmds.AddCommand(NewCmdExposeService(f, out))
cmds.AddCommand(NewCmdAutoscale(f, out))
cmds.AddCommand(rollout.NewCmdRollout(f, out))
cmds.AddCommand(NewCmdLabel(f, out))
cmds.AddCommand(NewCmdAnnotate(f, out))
cmds.AddCommand(NewCmdTaint(f, out))
cmds.AddCommand(cmdconfig.NewCmdConfig(clientcmd.NewDefaultPathOptions(), out))
cmds.AddCommand(NewCmdClusterInfo(f, out))
cmds.AddCommand(NewCmdApiVersions(f, out))
cmds.AddCommand(NewCmdVersion(f, out))
cmds.AddCommand(NewCmdExplain(f, out))
cmds.AddCommand(NewCmdConvert(f, out))
cmds.AddCommand(NewCmdCompletion(f, out))
cmds.AddCommand(NewCmdTop(f, out))
filters := []string{
"options",
Deprecated("kubectl", "delete", cmds, NewCmdStop(f, out)),
Deprecated("kubectl", "config set-context", cmds, NewCmdNamespace(out)),
}
templates.ActsAsRootCommand(cmds, filters, groups...)
if cmds.Flag("namespace") != nil {
if cmds.Flag("namespace").Annotations == nil {
@ -286,6 +318,11 @@ Find more information at https://github.com/kubernetes/kubernetes.`,
)
}
cmds.AddCommand(cmdconfig.NewCmdConfig(clientcmd.NewDefaultPathOptions(), out))
cmds.AddCommand(NewCmdVersion(f, out))
cmds.AddCommand(NewCmdApiVersions(f, out))
cmds.AddCommand(NewCmdOptions(out))
return cmds
}
@ -296,3 +333,10 @@ func runHelp(cmd *cobra.Command, args []string) {
func printDeprecationWarning(command, alias string) {
glog.Warningf("%s is DEPRECATED and will be removed in a future version. Use %s instead.", alias, command)
}
func Deprecated(baseName, to string, parent, cmd *cobra.Command) string {
cmd.Long = fmt.Sprintf("Deprecated: This command is deprecated, all its functionalities are covered by \"%s %s\"", baseName, to)
cmd.Short = fmt.Sprintf("Deprecated: %s", to)
parent.AddCommand(cmd)
return cmd.Name()
}

View File

@ -0,0 +1,39 @@
/*
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 cmd
import (
"io"
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
"github.com/spf13/cobra"
)
// NewCmdOptions implements the options command
func NewCmdOptions(out io.Writer) *cobra.Command {
cmd := &cobra.Command{
Use: "options",
Run: func(cmd *cobra.Command, args []string) {
cmd.Usage()
},
}
templates.UseOptionsTemplates(cmd)
return cmd
}

View File

@ -0,0 +1,300 @@
/*
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 (
"bytes"
"fmt"
"strings"
"text/template"
"unicode"
"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
}
func ActsAsRootCommand(cmd *cobra.Command, filters []string, groups ...CommandGroup) FlagExposer {
if cmd == nil {
panic("nil root command")
}
cmd.SetHelpTemplate(MainHelpTemplate())
templater := &templater{
RootCmd: cmd,
UsageTemplate: MainUsageTemplate(),
CommandGroups: groups,
Filtered: filters,
}
cmd.SetUsageFunc(templater.UsageFunc())
return templater
}
func UseOptionsTemplates(cmd *cobra.Command) {
cmd.SetHelpTemplate(OptionsHelpTemplate())
templater := &templater{
UsageTemplate: OptionsUsageTemplate(),
}
cmd.SetUsageFunc(templater.UsageFunc())
}
type templater struct {
UsageTemplate string
RootCmd *cobra.Command
CommandGroups
Filtered []string
}
func (templater *templater) ExposeFlags(cmd *cobra.Command, flags ...string) FlagExposer {
cmd.SetUsageFunc(templater.UsageFunc(flags...))
return templater
}
func (templater *templater) UsageFunc(exposedFlags ...string) func(*cobra.Command) error {
return func(c *cobra.Command) error {
t := template.New("custom")
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)
}
}
}
return exposed
},
})
template.Must(t.Parse(templater.UsageTemplate))
return t.Execute(c.OutOrStdout(), c)
}
}
func (templater *templater) cmdGroups(c *cobra.Command, all []*cobra.Command) []CommandGroup {
if len(templater.CommandGroups) > 0 && c == templater.RootCmd {
all = filter(all, templater.Filtered...)
return AddAdditionalCommands(templater.CommandGroups, "Other Commands:", all)
}
all = filter(all, "options")
return []CommandGroup{
{
Message: "Available Commands:",
Commands: all,
},
}
}
func (t *templater) rootCmdName(c *cobra.Command) string {
return t.rootCmd(c).CommandPath()
}
func (t *templater) isRootCmd(c *cobra.Command) bool {
return t.rootCmd(c) == c
}
func (t *templater) parents(c *cobra.Command) []*cobra.Command {
parents := []*cobra.Command{c}
for current := c; !t.isRootCmd(current) && current.HasParent(); {
current = current.Parent()
parents = append(parents, current)
}
return parents
}
func (t *templater) rootCmd(c *cobra.Command) *cobra.Command {
if c != nil && !c.HasParent() {
return c
}
if t.RootCmd == nil {
panic("nil root cmd")
}
return t.RootCmd
}
func (t *templater) optionsCmdFor(c *cobra.Command) string {
if !c.Runnable() {
return ""
}
rootCmdStructure := t.parents(c)
for i := len(rootCmdStructure) - 1; i >= 0; i-- {
cmd := rootCmdStructure[i]
if _, _, err := cmd.Find([]string{"options"}); err == nil {
return cmd.CommandPath() + " options"
}
}
return ""
}
func (t *templater) usageLine(c *cobra.Command) string {
usage := c.UseLine()
suffix := "[options]"
if c.HasFlags() && !strings.Contains(usage, suffix) {
usage += " " + suffix
}
return usage
}
func flagsUsages(f *flag.FlagSet) string {
x := new(bytes.Buffer)
f.VisitAll(func(flag *flag.Flag) {
if flag.Hidden {
return
}
format := "--%s=%s: %s\n"
if flag.Value.Type() == "string" {
format = "--%s='%s': %s\n"
}
if len(flag.Shorthand) > 0 {
format = " -%s, " + format
} else {
format = " %s " + format
}
fmt.Fprintf(x, format, flag.Shorthand, flag.Name, flag.DefValue, flag.Usage)
})
return x.String()
}
func rpad(s string, padding int) string {
template := fmt.Sprintf("%%-%ds", padding)
return fmt.Sprintf(template, s)
}
func indentLines(s string, indentation int) string {
r := []string{}
for _, line := range strings.Split(s, "\n") {
indented := strings.Repeat(" ", indentation) + line
r = append(r, indented)
}
return strings.Join(r, "\n")
}
func appendIfNotPresent(s, stringToAppend string) string {
if strings.Contains(s, stringToAppend) {
return s
}
return s + " " + stringToAppend
}
func flagsNotIntersected(l *flag.FlagSet, r *flag.FlagSet) *flag.FlagSet {
f := flag.NewFlagSet("notIntersected", flag.ContinueOnError)
l.VisitAll(func(flag *flag.Flag) {
if r.Lookup(flag.Name) == nil {
f.AddFlag(flag)
}
})
return f
}
func visibleFlags(l *flag.FlagSet) *flag.FlagSet {
hidden := "help"
f := flag.NewFlagSet("visible", flag.ContinueOnError)
l.VisitAll(func(flag *flag.Flag) {
if flag.Name != hidden {
f.AddFlag(flag)
}
})
return f
}

View File

@ -0,0 +1,99 @@
/*
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 "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
}
const (
vars = `{{$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}}`
mainUsageTemplate = vars +
// ALIASES
`{{if gt .Aliases 0}}
Aliases:
{{.NameAndAliases}}{{end}}` +
// EXAMPLES
`{{if .HasExample}}
Examples:
{{ indentLines (.Example | trimLeft) 2 }}{{end}}` +
// SUBCOMMANDS
`{{ if .HasAvailableSubCommands}}
{{range cmdGroups . .Commands}}
{{.Message}}
{{range .Commands}}{{if .Runnable}} {{rpad .Name .NamePadding }} {{.Short}}
{{end}}{{end}}{{end}}{{end}}` +
// VISIBLE FLAGS
`{{ if or $visibleFlags.HasFlags $explicitlyExposedFlags.HasFlags}}
Options:
{{ if $visibleFlags.HasFlags}}{{flagsUsages $visibleFlags}}{{end}}{{ if $explicitlyExposedFlags.HasFlags}}{{flagsUsages $explicitlyExposedFlags}}{{end}}{{end}}` +
// USAGE LINE
`{{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}}` +
// TIPS: global options
`{{ if $optionsCmdFor}}
Use "{{$optionsCmdFor}}" for a list of global command-line options (applies to all commands).{{end}}`
optionsHelpTemplate = ``
optionsUsageTemplate = `{{ if .HasInheritedFlags}}The following options can be passed to any command:
{{flagsUsages .InheritedFlags}}{{end}}`
)