123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300 |
- /*
- 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
- }
|