mirror of https://github.com/knative/func.git
213 lines
5.5 KiB
Go
213 lines
5.5 KiB
Go
// Copyright © 2020 The Knative 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"
|
|
"os"
|
|
"strings"
|
|
"text/template"
|
|
"unicode"
|
|
|
|
"github.com/spf13/cobra"
|
|
flag "github.com/spf13/pflag"
|
|
"golang.org/x/term"
|
|
)
|
|
|
|
type templateEngine struct {
|
|
RootCmd *cobra.Command
|
|
CommandGroups
|
|
functions template.FuncMap
|
|
}
|
|
|
|
// Create new template engine
|
|
func newTemplateEngine(rootCmd *cobra.Command, g CommandGroups, extraFunctions *template.FuncMap) templateEngine {
|
|
engine := templateEngine{
|
|
RootCmd: rootCmd,
|
|
CommandGroups: g,
|
|
}
|
|
engine.functions = engine.templateFunctions()
|
|
if extraFunctions != nil {
|
|
for name, function := range *extraFunctions {
|
|
engine.functions[name] = function
|
|
}
|
|
}
|
|
return engine
|
|
}
|
|
|
|
func (e templateEngine) usageFunc() func(*cobra.Command) error {
|
|
return func(c *cobra.Command) error {
|
|
return e.fillTemplate("usage", c, usageTemplate())
|
|
}
|
|
}
|
|
|
|
func (e templateEngine) helpFunc() func(*cobra.Command, []string) {
|
|
return func(c *cobra.Command, s []string) {
|
|
err := e.fillTemplate("help", c, helpTemplate(c.Long))
|
|
if err != nil {
|
|
c.Println(err)
|
|
}
|
|
}
|
|
}
|
|
|
|
func (e templateEngine) fillTemplate(name string, c *cobra.Command, templ string) error {
|
|
t := template.New(name)
|
|
t.Funcs(e.functions)
|
|
_, err := t.Parse(templ)
|
|
if err != nil {
|
|
fmt.Fprintf(c.ErrOrStderr(), "\nINTERNAL: >>>>> %v\n", err)
|
|
return err
|
|
}
|
|
return t.Execute(c.OutOrStdout(), c)
|
|
}
|
|
|
|
// ======================================================================================
|
|
// Template helper functions
|
|
|
|
func (e templateEngine) templateFunctions() template.FuncMap {
|
|
return template.FuncMap{
|
|
"cmdGroupsString": e.cmdGroupsString,
|
|
"subCommandsString": e.subCommandsString,
|
|
"useLine": useLine,
|
|
"visibleFlags": visibleFlags,
|
|
"rpad": rpad,
|
|
"rootCmdName": e.rootCmdName,
|
|
"rootCmdUse": e.rootCmdUse,
|
|
"isRootCmd": e.isRootCmd,
|
|
"flagsUsages": flagsUsagesCobra, // or use flagsUsagesKubectl for kubectl like flag styles
|
|
"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) },
|
|
"execTemplate": e.executeTemplate,
|
|
}
|
|
}
|
|
|
|
func (e templateEngine) executeTemplate(tbody string, data any) (string, error) {
|
|
t, err := template.New("").Funcs(e.templateFunctions()).Parse(tbody)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
buf := &strings.Builder{}
|
|
err = t.Execute(buf, data)
|
|
return buf.String(), err
|
|
}
|
|
|
|
func (e templateEngine) cmdGroupsString() string {
|
|
groups := make([]string, 0, len(e.CommandGroups))
|
|
for _, cmdGroup := range e.CommandGroups {
|
|
groups = append(groups, formatCommandGroup(cmdGroup))
|
|
}
|
|
return strings.Join(groups, "\n\n")
|
|
}
|
|
|
|
func (e templateEngine) subCommandsString(c *cobra.Command) string {
|
|
return formatCommandGroup(CommandGroup{
|
|
Header: "Available Commands:",
|
|
Commands: c.Commands(),
|
|
})
|
|
}
|
|
|
|
func (e templateEngine) rootCmdName() string {
|
|
return e.RootCmd.CommandPath()
|
|
}
|
|
|
|
func (e templateEngine) rootCmdUse() string {
|
|
return e.RootCmd.Use
|
|
}
|
|
|
|
func (e templateEngine) isRootCmd(c *cobra.Command) bool {
|
|
return e.RootCmd == c
|
|
}
|
|
|
|
func visibleFlags(c *cobra.Command) *flag.FlagSet {
|
|
ret := flag.NewFlagSet("filtered", flag.ContinueOnError)
|
|
local := c.LocalFlags()
|
|
persistent := c.PersistentFlags()
|
|
local.VisitAll(func(flag *flag.Flag) {
|
|
if flag.Name != "help" && persistent.Lookup(flag.Name) == nil {
|
|
ret.AddFlag(flag)
|
|
}
|
|
})
|
|
return ret
|
|
}
|
|
|
|
func useLine(c *cobra.Command) string {
|
|
var useLine string
|
|
var suffix string
|
|
if c.HasParent() {
|
|
useLine = c.Parent().CommandPath() + " " + c.Use
|
|
suffix = "[flags]"
|
|
} else {
|
|
useLine = c.Use
|
|
suffix = "[command]"
|
|
}
|
|
if c.HasFlags() && !strings.Contains(useLine, suffix) {
|
|
useLine += " " + suffix
|
|
}
|
|
return useLine
|
|
}
|
|
|
|
func formatCommandGroup(cmdGroup CommandGroup) string {
|
|
cmds := []string{cmdGroup.Header}
|
|
for _, cmd := range cmdGroup.Commands {
|
|
if cmd.IsAvailableCommand() {
|
|
cmds = append(cmds, " "+rpad(cmd.Name(), cmd.NamePadding())+" "+cmd.Short)
|
|
}
|
|
}
|
|
return strings.Join(cmds, "\n")
|
|
}
|
|
|
|
func rpad(s string, padding int) string {
|
|
t := fmt.Sprintf("%%-%ds", padding)
|
|
return fmt.Sprintf(t, s)
|
|
}
|
|
|
|
// flagsUsagesCobra formats flags in Cobra style
|
|
func flagsUsagesCobra(f *flag.FlagSet) string {
|
|
width, _, err := term.GetSize(int(os.Stdout.Fd()))
|
|
if err == nil {
|
|
return f.FlagUsagesWrapped(width)
|
|
} else {
|
|
return f.FlagUsages()
|
|
}
|
|
}
|
|
|
|
// flagsUsagesKubectl formats the flags like kubectl does
|
|
func flagsUsagesKubectl(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()
|
|
}
|