Migrate from urfave/cli to cobra (#1385)
This commit is contained in:
@@ -0,0 +1,286 @@
|
||||
/*
|
||||
Copyright 2019 The Fission 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 cobra
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/pflag"
|
||||
|
||||
wCli "github.com/fission/fission/pkg/fission-cli/cliwrapper/cli"
|
||||
"github.com/fission/fission/pkg/fission-cli/cliwrapper/driver/cobra/helptemplate"
|
||||
cmd "github.com/fission/fission/pkg/fission-cli/cmd"
|
||||
"github.com/fission/fission/pkg/fission-cli/flag"
|
||||
)
|
||||
|
||||
var _ wCli.Input = &Cli{}
|
||||
|
||||
type (
|
||||
Cli struct {
|
||||
c *cobra.Command
|
||||
args []string
|
||||
}
|
||||
)
|
||||
|
||||
// Parse is only for converting urfave *cli.Context to Input and will be removed in future.
|
||||
func Parse(cmd *cobra.Command, args []string) wCli.Input {
|
||||
return Cli{c: cmd, args: args}
|
||||
}
|
||||
|
||||
func Wrapper(action cmd.CommandAction) func(*cobra.Command, []string) error {
|
||||
return func(c *cobra.Command, args []string) error {
|
||||
return action(Cli{c: c, args: args})
|
||||
}
|
||||
}
|
||||
|
||||
func SetFlags(cmd *cobra.Command, flagSet flag.FlagSet) {
|
||||
aliases := make(map[string]string)
|
||||
|
||||
// set required flags
|
||||
for _, f := range flagSet.Required {
|
||||
requiredFlags(cmd, f)
|
||||
for _, alias := range f.Aliases {
|
||||
aliases[alias] = f.Name
|
||||
}
|
||||
}
|
||||
|
||||
// set optional flags
|
||||
for _, f := range flagSet.Optional {
|
||||
optionalFlags(cmd, f)
|
||||
for _, alias := range f.Aliases {
|
||||
aliases[alias] = f.Name
|
||||
}
|
||||
}
|
||||
|
||||
// set flag alias normalize function
|
||||
cmd.Flags().SetNormalizeFunc(
|
||||
func(f *pflag.FlagSet, name string) pflag.NormalizedName {
|
||||
n, ok := aliases[name]
|
||||
if ok {
|
||||
name = n
|
||||
}
|
||||
return pflag.NormalizedName(name)
|
||||
},
|
||||
)
|
||||
cmd.Flags().SortFlags = false
|
||||
}
|
||||
|
||||
func optionalFlags(cmd *cobra.Command, flags ...flag.Flag) {
|
||||
for _, f := range flags {
|
||||
toCobraFlag(cmd, f)
|
||||
if f.Deprecated {
|
||||
usage := fmt.Sprintf("Use --%v instead. The flag still works for now and will be removed in future", f.Substitute)
|
||||
cmd.Flags().MarkDeprecated(f.Name, usage)
|
||||
} else if f.Hidden {
|
||||
cmd.Flags().MarkHidden(f.Name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func requiredFlags(cmd *cobra.Command, flags ...flag.Flag) {
|
||||
for _, f := range flags {
|
||||
toCobraFlag(cmd, f)
|
||||
cmd.MarkFlagRequired(f.Name)
|
||||
}
|
||||
}
|
||||
|
||||
func toCobraFlag(cmd *cobra.Command, f flag.Flag) {
|
||||
// Workaround to pass aliases to templater for generating flag aliases.
|
||||
if len(f.Aliases) > 0 {
|
||||
var aliases []string
|
||||
for _, alias := range f.Aliases {
|
||||
dash := "--"
|
||||
if len(alias) == 1 {
|
||||
dash = "-"
|
||||
f.Short = alias
|
||||
}
|
||||
aliases = append(aliases, dash+alias)
|
||||
}
|
||||
// Use separator to separator aliases and usage text.
|
||||
f.Usage = fmt.Sprintf("%s%s%s",
|
||||
strings.Join(aliases, helptemplate.AliasSeparator),
|
||||
helptemplate.AliasSeparator, f.Usage)
|
||||
}
|
||||
|
||||
switch f.Type {
|
||||
case flag.Bool:
|
||||
val, ok := f.DefaultValue.(bool)
|
||||
if !ok {
|
||||
val = false
|
||||
}
|
||||
cmd.Flags().BoolP(f.Name, f.Short, val, f.Usage)
|
||||
case flag.String:
|
||||
val, ok := f.DefaultValue.(string)
|
||||
if !ok {
|
||||
val = ""
|
||||
}
|
||||
cmd.Flags().StringP(f.Name, f.Short, val, f.Usage)
|
||||
case flag.StringSlice:
|
||||
val, ok := f.DefaultValue.([]string)
|
||||
if !ok {
|
||||
val = []string{}
|
||||
}
|
||||
cmd.Flags().StringArrayP(f.Name, f.Short, val, f.Usage)
|
||||
case flag.Int:
|
||||
val, ok := f.DefaultValue.(int)
|
||||
if !ok {
|
||||
val = 0
|
||||
}
|
||||
cmd.Flags().IntP(f.Name, f.Short, val, f.Usage)
|
||||
case flag.IntSlice:
|
||||
val, ok := f.DefaultValue.([]int)
|
||||
if !ok {
|
||||
val = []int{}
|
||||
}
|
||||
cmd.Flags().IntSliceP(f.Name, f.Short, val, f.Usage)
|
||||
case flag.Int64:
|
||||
val, ok := f.DefaultValue.(int64)
|
||||
if !ok {
|
||||
val = 0
|
||||
}
|
||||
cmd.Flags().Int64P(f.Name, f.Short, val, f.Usage)
|
||||
case flag.Int64Slice:
|
||||
val, ok := f.DefaultValue.([]int64)
|
||||
if !ok {
|
||||
val = []int64{}
|
||||
}
|
||||
cmd.Flags().Int64SliceP(f.Name, f.Short, val, f.Usage)
|
||||
case flag.Float32:
|
||||
val, ok := f.DefaultValue.(float32)
|
||||
if !ok {
|
||||
val = 0
|
||||
}
|
||||
cmd.Flags().Float32P(f.Name, f.Short, val, f.Usage)
|
||||
case flag.Float64:
|
||||
val, ok := f.DefaultValue.(float64)
|
||||
if !ok {
|
||||
val = 0
|
||||
}
|
||||
cmd.Flags().Float64P(f.Name, f.Short, val, f.Usage)
|
||||
case flag.Duration:
|
||||
val, ok := f.DefaultValue.(time.Duration)
|
||||
if !ok {
|
||||
val = 0
|
||||
}
|
||||
cmd.Flags().DurationP(f.Name, f.Short, val, f.Usage)
|
||||
}
|
||||
}
|
||||
|
||||
func WrapperChain(actions ...cmd.CommandAction) func(*cobra.Command, []string) error {
|
||||
return func(c *cobra.Command, args []string) error {
|
||||
for _, action := range actions {
|
||||
err := action(Cli{c: c, args: args})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func (u Cli) IsSet(key string) bool {
|
||||
return u.c.Flags().Changed(key)
|
||||
}
|
||||
|
||||
func (u Cli) Bool(key string) bool {
|
||||
// TODO: ignore the error here, but we should handle it properly in some ways.
|
||||
v, _ := u.c.Flags().GetBool(key)
|
||||
return v
|
||||
}
|
||||
|
||||
func (u Cli) String(key string) string {
|
||||
v, _ := u.c.Flags().GetString(key)
|
||||
return v
|
||||
}
|
||||
|
||||
func (u Cli) StringSlice(key string) []string {
|
||||
// difference between StringSlice and StringArray
|
||||
// --ss="one" --ss="two,three"
|
||||
// StringSlice* - will result in []string{"one", "two", "three"}
|
||||
// StringArray* - will result in []s
|
||||
// https://github.com/spf13/cobra/issues/661#issuecomment-377684634
|
||||
// Use StringArray here to fit our use case.
|
||||
v, _ := u.c.Flags().GetStringArray(key)
|
||||
return v
|
||||
}
|
||||
|
||||
func (u Cli) Int(key string) int {
|
||||
v, _ := u.c.Flags().GetInt(key)
|
||||
return v
|
||||
}
|
||||
|
||||
func (u Cli) IntSlice(key string) []int {
|
||||
v, _ := u.c.Flags().GetIntSlice(key)
|
||||
return v
|
||||
}
|
||||
|
||||
func (u Cli) Int64(key string) int64 {
|
||||
v, _ := u.c.Flags().GetInt64(key)
|
||||
return v
|
||||
}
|
||||
|
||||
func (u Cli) Int64Slice(key string) []int64 {
|
||||
v, _ := u.c.Flags().GetIntSlice(key)
|
||||
vals := make([]int64, len(v))
|
||||
for _, i := range v {
|
||||
vals = append(vals, int64(i))
|
||||
}
|
||||
return vals
|
||||
}
|
||||
|
||||
func (u Cli) GlobalBool(key string) bool {
|
||||
v, _ := u.c.Flags().GetBool(key)
|
||||
return v
|
||||
}
|
||||
|
||||
func (u Cli) GlobalString(key string) string {
|
||||
v, _ := u.c.Flags().GetString(key)
|
||||
return v
|
||||
}
|
||||
|
||||
func (u Cli) GlobalStringSlice(key string) []string {
|
||||
v, _ := u.c.Flags().GetStringArray(key)
|
||||
return v
|
||||
}
|
||||
|
||||
func (u Cli) GlobalInt(key string) int {
|
||||
v, _ := u.c.Flags().GetInt(key)
|
||||
return v
|
||||
}
|
||||
|
||||
func (u Cli) GlobalIntSlice(key string) []int {
|
||||
v, _ := u.c.Flags().GetIntSlice(key)
|
||||
return v
|
||||
}
|
||||
|
||||
func (u Cli) GlobalInt64(key string) int64 {
|
||||
v, _ := u.c.Flags().GetInt64(key)
|
||||
return v
|
||||
}
|
||||
|
||||
func (u Cli) GlobalInt64Slice(key string) []int64 {
|
||||
v, _ := u.c.Flags().GetInt64Slice(key)
|
||||
return v
|
||||
}
|
||||
|
||||
func (u Cli) Duration(key string) time.Duration {
|
||||
v, _ := u.c.Flags().GetDuration(key)
|
||||
return v
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
// Original file location: https://github.com/kubernetes/kubectl/tree/master/pkg/util/templates
|
||||
|
||||
package helptemplate
|
||||
|
||||
import (
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
type CommandGroup struct {
|
||||
Message string
|
||||
Commands []*cobra.Command
|
||||
}
|
||||
|
||||
type CommandGroups []CommandGroup
|
||||
|
||||
func (g CommandGroups) Add(c *cobra.Command) {
|
||||
for _, group := range g {
|
||||
c.AddCommand(group.Commands...)
|
||||
}
|
||||
}
|
||||
|
||||
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 have 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)
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
Copyright 2019 The Fission 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 helptemplate
|
||||
|
||||
import (
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func CreateCmdGroup(msg string, cmds ...*cobra.Command) CommandGroup {
|
||||
return CommandGroup{
|
||||
Message: msg,
|
||||
Commands: cmds,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,347 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
// Original file location: https://github.com/kubernetes/kubectl/tree/master/pkg/util/templates
|
||||
|
||||
package helptemplate
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
"text/template"
|
||||
"unicode"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
flag "github.com/spf13/pflag"
|
||||
)
|
||||
|
||||
const AliasSeparator = " |:|: "
|
||||
|
||||
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.SetFlagErrorFunc(templater.FlagErrorFunc())
|
||||
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) FlagErrorFunc(exposedFlags ...string) func(*cobra.Command, error) error {
|
||||
return func(c *cobra.Command, err error) error {
|
||||
c.SilenceUsage = true
|
||||
switch c.CalledAs() {
|
||||
case "options":
|
||||
return fmt.Errorf("%s\nRun '%s' without flags", err, c.CommandPath())
|
||||
default:
|
||||
return fmt.Errorf("%s\nSee '%s --help' for usage", err, c.CommandPath())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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))
|
||||
err := t.Execute(os.Stdout, 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))
|
||||
return t.Execute(os.Stdout, 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)
|
||||
exposed.SortFlags = false
|
||||
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)
|
||||
|
||||
var flags [][]string
|
||||
var maxPadLength int
|
||||
|
||||
f.VisitAll(func(flag *flag.Flag) {
|
||||
if flag.Hidden {
|
||||
return
|
||||
}
|
||||
|
||||
format := "--%s=%s"
|
||||
if flag.Value.Type() == "string" {
|
||||
format = "--%s='%s'"
|
||||
}
|
||||
|
||||
var usage string
|
||||
var aliases []string
|
||||
|
||||
// extract aliases from usage text
|
||||
u := strings.Split(flag.Usage, AliasSeparator)
|
||||
|
||||
if len(u) == 1 {
|
||||
// means the flag has no aliases
|
||||
usage = u[0]
|
||||
format = format + " %s"
|
||||
} else {
|
||||
usage = u[len(u)-1]
|
||||
aliases = u[0 : len(u)-1]
|
||||
format = format + " (%s)"
|
||||
}
|
||||
|
||||
aliasesStr := strings.Join(aliases, ", ")
|
||||
flagName := fmt.Sprintf(format, flag.Name, flag.DefValue, aliasesStr)
|
||||
flags = append(flags, []string{flagName, usage})
|
||||
|
||||
if len(flagName) > maxPadLength {
|
||||
maxPadLength = len(flagName)
|
||||
}
|
||||
})
|
||||
|
||||
for _, v := range flags {
|
||||
name := rpad(v[0], maxPadLength)
|
||||
fmt.Fprintf(x, " %s %s\n", name, toFitUsagePadding(v[1], maxPadLength))
|
||||
}
|
||||
|
||||
return x.String()
|
||||
}
|
||||
|
||||
func toFitUsagePadding(u string, pad int) (usage string) {
|
||||
us := strings.Split(u, " ")
|
||||
length := pad
|
||||
|
||||
for _, chunk := range us {
|
||||
if length+len(chunk) > 100 {
|
||||
usage = usage + "\n" + lpad(chunk, pad+len(chunk)+4) // 4 for whitespace in format
|
||||
length = pad
|
||||
continue
|
||||
}
|
||||
usage = usage + " " + chunk
|
||||
length += len(chunk) + 1 // 1 is for whitespace
|
||||
}
|
||||
|
||||
return usage
|
||||
}
|
||||
|
||||
func rpad(s string, padding int) string {
|
||||
template := fmt.Sprintf("%%-%ds", padding)
|
||||
return fmt.Sprintf(template, s)
|
||||
}
|
||||
|
||||
func lpad(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)
|
||||
f.SortFlags = false // disable sorting flags
|
||||
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)
|
||||
f.SortFlags = false // disable sorting flags
|
||||
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
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
// Original file location: https://github.com/kubernetes/kubectl/tree/master/pkg/util/templates
|
||||
|
||||
package helptemplate
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"unicode"
|
||||
)
|
||||
|
||||
const (
|
||||
// SectionVars is the help template section that declares variables to be used in the template.
|
||||
SectionVars = `{{$isRootCmd := isRootCmd .}}` +
|
||||
`{{$rootCmd := rootCmd .}}` +
|
||||
`{{$visibleFlags := visibleFlags (flagsNotIntersected .LocalFlags .PersistentFlags)}}` +
|
||||
`{{$explicitlyExposedFlags := exposed .}}` +
|
||||
`{{$optionsCmdFor := optionsCmdFor .}}` +
|
||||
`{{$usageLine := usageLine .}}`
|
||||
|
||||
// SectionAliases is the help template section that displays command aliases.
|
||||
SectionAliases = `{{if gt .Aliases 0}}Aliases:
|
||||
{{.NameAndAliases}}
|
||||
|
||||
{{end}}`
|
||||
|
||||
// SectionExamples is the help template section that displays command examples.
|
||||
SectionExamples = `{{if .HasExample}}Examples:
|
||||
{{trimRight .Example}}
|
||||
|
||||
{{end}}`
|
||||
|
||||
// SectionSubcommands is the help template section that displays the command's subcommands.
|
||||
SectionSubcommands = `{{if .HasAvailableSubCommands}}{{cmdGroupsString .}}
|
||||
|
||||
{{end}}`
|
||||
|
||||
// SectionFlags is the help template section that displays the command's flags.
|
||||
SectionFlags = `{{ if or $visibleFlags.HasFlags $explicitlyExposedFlags.HasFlags}}Options:
|
||||
{{ if $visibleFlags.HasFlags}}{{trimRight (flagsUsages $visibleFlags)}}{{end}}{{ if $explicitlyExposedFlags.HasFlags}}{{ if $visibleFlags.HasFlags}}
|
||||
{{end}}{{trimRight (flagsUsages $explicitlyExposedFlags)}}{{end}}
|
||||
|
||||
{{end}}`
|
||||
|
||||
// SectionUsage is the help template section that displays the command's usage.
|
||||
SectionUsage = `{{if and .Runnable (ne .UseLine "") (ne .UseLine $rootCmd)}}Usage:
|
||||
{{$usageLine}}
|
||||
|
||||
{{end}}`
|
||||
|
||||
// SectionTipsHelp is the help template section that displays the '--help' hint.
|
||||
SectionTipsHelp = `{{if .HasSubCommands}}Use "{{$rootCmd}} <command> --help" for more information about a given command.{{end}}`
|
||||
|
||||
// SectionTipsGlobalOptions is the help template section that displays the 'options' hint for displaying global flags.
|
||||
SectionTipsGlobalOptions = `{{if $optionsCmdFor}}Use "{{$optionsCmdFor}}" for a list of global command-line options (applies to all commands).{{end}}`
|
||||
)
|
||||
|
||||
// MainHelpTemplate if the template for 'help' used by most commands.
|
||||
func MainHelpTemplate() string {
|
||||
return `{{with or .Long .Short }}{{. | trimRight}}
|
||||
{{end}}{{if or .Runnable .HasSubCommands}}{{.UsageString}}{{end}}`
|
||||
}
|
||||
|
||||
// MainUsageTemplate if the template for 'usage' used by most commands.
|
||||
func MainUsageTemplate() string {
|
||||
sections := []string{
|
||||
"\n",
|
||||
SectionVars,
|
||||
SectionAliases,
|
||||
SectionExamples,
|
||||
SectionSubcommands,
|
||||
SectionFlags,
|
||||
SectionUsage,
|
||||
SectionTipsHelp,
|
||||
SectionTipsGlobalOptions,
|
||||
}
|
||||
return strings.TrimRightFunc(strings.Join(sections, ""), unicode.IsSpace)
|
||||
}
|
||||
|
||||
// OptionsHelpTemplate if the template for 'help' used by the 'options' command.
|
||||
func OptionsHelpTemplate() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
// OptionsUsageTemplate if the template for 'usage' used by the 'options' command.
|
||||
func OptionsUsageTemplate() string {
|
||||
return `{{ if .HasInheritedFlags}}The following options can be passed to any command:
|
||||
|
||||
{{flagsUsages .InheritedFlags}}{{end}}`
|
||||
}
|
||||
@@ -1,107 +0,0 @@
|
||||
/*
|
||||
Copyright 2019 The Fission 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 urfavecli
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/urfave/cli"
|
||||
|
||||
fCli "github.com/fission/fission/pkg/fission-cli/cliwrapper/cli"
|
||||
"github.com/fission/fission/pkg/fission-cli/cmd"
|
||||
)
|
||||
|
||||
var _ fCli.Input = &Cli{}
|
||||
|
||||
type Cli struct {
|
||||
c *cli.Context
|
||||
}
|
||||
|
||||
// Parse is only for converting urfave *cli.Context to Input and will be removed in future.
|
||||
func Parse(c *cli.Context) fCli.Input {
|
||||
return Cli{c: c}
|
||||
}
|
||||
|
||||
func Wrapper(action cmd.CommandAction) func(*cli.Context) error {
|
||||
return func(c *cli.Context) error {
|
||||
return action(Cli{c: c})
|
||||
}
|
||||
}
|
||||
|
||||
func (u Cli) IsSet(key string) bool {
|
||||
return u.c.IsSet(key)
|
||||
}
|
||||
|
||||
func (u Cli) Bool(key string) bool {
|
||||
return u.c.Bool(key)
|
||||
}
|
||||
|
||||
func (u Cli) String(key string) string {
|
||||
return u.c.String(key)
|
||||
}
|
||||
|
||||
func (u Cli) StringSlice(key string) []string {
|
||||
return u.c.StringSlice(key)
|
||||
}
|
||||
|
||||
func (u Cli) Int(key string) int {
|
||||
return u.c.Int(key)
|
||||
}
|
||||
|
||||
func (u Cli) IntSlice(key string) []int {
|
||||
return u.c.IntSlice(key)
|
||||
}
|
||||
|
||||
func (u Cli) Int64(key string) int64 {
|
||||
return u.c.Int64(key)
|
||||
}
|
||||
|
||||
func (u Cli) Int64Slice(key string) []int64 {
|
||||
return u.c.Int64Slice(key)
|
||||
}
|
||||
|
||||
func (u Cli) GlobalBool(key string) bool {
|
||||
return u.c.GlobalBool(key)
|
||||
}
|
||||
|
||||
func (u Cli) GlobalString(key string) string {
|
||||
return u.c.GlobalString(key)
|
||||
}
|
||||
|
||||
func (u Cli) GlobalStringSlice(key string) []string {
|
||||
return u.c.GlobalStringSlice(key)
|
||||
}
|
||||
|
||||
func (u Cli) GlobalInt(key string) int {
|
||||
return u.c.GlobalInt(key)
|
||||
}
|
||||
|
||||
func (u Cli) GlobalIntSlice(key string) []int {
|
||||
return u.c.GlobalIntSlice(key)
|
||||
}
|
||||
|
||||
func (u Cli) GlobalInt64(key string) int64 {
|
||||
return u.c.GlobalInt64(key)
|
||||
}
|
||||
|
||||
func (u Cli) GlobalInt64Slice(key string) []int64 {
|
||||
return u.c.GlobalInt64Slice(key)
|
||||
}
|
||||
|
||||
func (u Cli) Duration(key string) time.Duration {
|
||||
return u.c.Duration(key)
|
||||
}
|
||||
Reference in New Issue
Block a user