123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285 |
- /*
- 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"
- "k8s.io/kubernetes/pkg/kubectl/util/term"
- "github.com/spf13/cobra"
- flag "github.com/spf13/pflag"
- )
- 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")
- }
- 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) {
- 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
- }
- func (templater *templater) ExposeFlags(cmd *cobra.Command, flags ...string) FlagExposer {
- cmd.SetUsageFunc(templater.UsageFunc(flags...))
- 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("usage")
- t.Funcs(templater.templateFuncs(exposedFlags...))
- template.Must(t.Parse(templater.UsageTemplate))
- out := term.NewResponsiveWriter(c.OutOrStderr())
- return t.Execute(out, c)
- }
- }
- 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
- },
- }
- }
- 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) 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.IsAvailableCommand() {
- 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()
- }
- 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 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
- }
- 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
- }
|