This adds the following commands: - faas-cli - faas-cli help - faas-cli build - faas-cli deploy - faas-cli remove (alias: rm) - faas-cli version - faas-cli push Note that the following is also added but hidden from help pending a more robust bash completion solution, initially using the Cobra generated bash completion but needs spf13/cobra#520 to merge before it'll work on the OSX default Bash 3.x. - faas-cli bashcompletion This commit intercepts the command line args passed to `faas-cli` and attempts to translate them from the deprecated go flag based syntax (`faas-cli -action xxx`) to the new Cobra verb/noun based syntax (`faas-cli xxx`), it also translates a frozen set of legacy flags (with the go-style single-dash) into a GNU style double-dash. Note that some special cases are included: - changing the delete action to remove - passing the function name as a noun to remove rather than as an arg to `-name` - it also handles the legacy format where args are passed after = (`-name=fnname`). If the translation results in a new set of args then a message is displayed to the user (stderr) telling warning that they are using the deprecated cli syntax and also prints the new syntax command that is being executed and which they should use going forward. Any errors thrown during translation result in the command failing with it printing the error cause to stderr. This renames the `fetchTemplates.go` file to use snake case. The convention appears to be for snakecase - as observed in both the Go and Kubernetes source. For example heres a random selection of source files. - https://github.com/kubernetes/kubernetes/blob/master/pkg/kubeapiserver/default_storage_factory_builder.go - https://github.com/kubernetes/kubernetes/blob/master/pkg/kubectl/bash_comp_utils.go - https://github.com/golang/go/blob/master/src/compress/bzip2/move_to_front.go Note that the language spec does not set a hard rule for source file names, only for package names, but making this change for consistency. Note that this file was initially generated by Cobra, but has been tweaked to include some fixes. It it an experimental initial version. This commit adds some instructions on enabling the `faas-cli` bash auto-completion support. Instructions for Linux users are very light as it differs per-distro and the assumption is that Linux users should be capable of following their Distros instructions on enabling bash completion support. Signed-off-by: John McCabe <john@johnmccabe.net>
191 lines
5.7 KiB
Go
191 lines
5.7 KiB
Go
// Copyright © 2013 Steve Francia <spf@spf13.com>.
|
|
//
|
|
// 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.
|
|
|
|
// Commands similar to git, go tools and other modern CLI tools
|
|
// inspired by go, go-Commander, gh and subcommand
|
|
|
|
package cobra
|
|
|
|
import (
|
|
"fmt"
|
|
"io"
|
|
"reflect"
|
|
"strconv"
|
|
"strings"
|
|
"text/template"
|
|
"unicode"
|
|
)
|
|
|
|
var templateFuncs = template.FuncMap{
|
|
"trim": strings.TrimSpace,
|
|
"trimRightSpace": trimRightSpace,
|
|
"trimTrailingWhitespaces": trimRightSpace,
|
|
"appendIfNotPresent": appendIfNotPresent,
|
|
"rpad": rpad,
|
|
"gt": Gt,
|
|
"eq": Eq,
|
|
}
|
|
|
|
var initializers []func()
|
|
|
|
// EnablePrefixMatching allows to set automatic prefix matching. Automatic prefix matching can be a dangerous thing
|
|
// to automatically enable in CLI tools.
|
|
// Set this to true to enable it.
|
|
var EnablePrefixMatching = false
|
|
|
|
// EnableCommandSorting controls sorting of the slice of commands, which is turned on by default.
|
|
// To disable sorting, set it to false.
|
|
var EnableCommandSorting = true
|
|
|
|
// MousetrapHelpText enables an information splash screen on Windows
|
|
// if the CLI is started from explorer.exe.
|
|
// To disable the mousetrap, just set this variable to blank string ("").
|
|
// Works only on Microsoft Windows.
|
|
var MousetrapHelpText string = `This is a command line tool.
|
|
|
|
You need to open cmd.exe and run it from there.
|
|
`
|
|
|
|
// AddTemplateFunc adds a template function that's available to Usage and Help
|
|
// template generation.
|
|
func AddTemplateFunc(name string, tmplFunc interface{}) {
|
|
templateFuncs[name] = tmplFunc
|
|
}
|
|
|
|
// AddTemplateFuncs adds multiple template functions that are available to Usage and
|
|
// Help template generation.
|
|
func AddTemplateFuncs(tmplFuncs template.FuncMap) {
|
|
for k, v := range tmplFuncs {
|
|
templateFuncs[k] = v
|
|
}
|
|
}
|
|
|
|
// OnInitialize takes a series of func() arguments and appends them to a slice of func().
|
|
func OnInitialize(y ...func()) {
|
|
initializers = append(initializers, y...)
|
|
}
|
|
|
|
// FIXME Gt is unused by cobra and should be removed in a version 2. It exists only for compatibility with users of cobra.
|
|
|
|
// Gt takes two types and checks whether the first type is greater than the second. In case of types Arrays, Chans,
|
|
// Maps and Slices, Gt will compare their lengths. Ints are compared directly while strings are first parsed as
|
|
// ints and then compared.
|
|
func Gt(a interface{}, b interface{}) bool {
|
|
var left, right int64
|
|
av := reflect.ValueOf(a)
|
|
|
|
switch av.Kind() {
|
|
case reflect.Array, reflect.Chan, reflect.Map, reflect.Slice:
|
|
left = int64(av.Len())
|
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
|
left = av.Int()
|
|
case reflect.String:
|
|
left, _ = strconv.ParseInt(av.String(), 10, 64)
|
|
}
|
|
|
|
bv := reflect.ValueOf(b)
|
|
|
|
switch bv.Kind() {
|
|
case reflect.Array, reflect.Chan, reflect.Map, reflect.Slice:
|
|
right = int64(bv.Len())
|
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
|
right = bv.Int()
|
|
case reflect.String:
|
|
right, _ = strconv.ParseInt(bv.String(), 10, 64)
|
|
}
|
|
|
|
return left > right
|
|
}
|
|
|
|
// FIXME Eq is unused by cobra and should be removed in a version 2. It exists only for compatibility with users of cobra.
|
|
|
|
// Eq takes two types and checks whether they are equal. Supported types are int and string. Unsupported types will panic.
|
|
func Eq(a interface{}, b interface{}) bool {
|
|
av := reflect.ValueOf(a)
|
|
bv := reflect.ValueOf(b)
|
|
|
|
switch av.Kind() {
|
|
case reflect.Array, reflect.Chan, reflect.Map, reflect.Slice:
|
|
panic("Eq called on unsupported type")
|
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
|
return av.Int() == bv.Int()
|
|
case reflect.String:
|
|
return av.String() == bv.String()
|
|
}
|
|
return false
|
|
}
|
|
|
|
func trimRightSpace(s string) string {
|
|
return strings.TrimRightFunc(s, unicode.IsSpace)
|
|
}
|
|
|
|
// FIXME appendIfNotPresent is unused by cobra and should be removed in a version 2. It exists only for compatibility with users of cobra.
|
|
|
|
// appendIfNotPresent will append stringToAppend to the end of s, but only if it's not yet present in s.
|
|
func appendIfNotPresent(s, stringToAppend string) string {
|
|
if strings.Contains(s, stringToAppend) {
|
|
return s
|
|
}
|
|
return s + " " + stringToAppend
|
|
}
|
|
|
|
// rpad adds padding to the right of a string.
|
|
func rpad(s string, padding int) string {
|
|
template := fmt.Sprintf("%%-%ds", padding)
|
|
return fmt.Sprintf(template, s)
|
|
}
|
|
|
|
// tmpl executes the given template text on data, writing the result to w.
|
|
func tmpl(w io.Writer, text string, data interface{}) error {
|
|
t := template.New("top")
|
|
t.Funcs(templateFuncs)
|
|
template.Must(t.Parse(text))
|
|
return t.Execute(w, data)
|
|
}
|
|
|
|
// ld compares two strings and returns the levenshtein distance between them.
|
|
func ld(s, t string, ignoreCase bool) int {
|
|
if ignoreCase {
|
|
s = strings.ToLower(s)
|
|
t = strings.ToLower(t)
|
|
}
|
|
d := make([][]int, len(s)+1)
|
|
for i := range d {
|
|
d[i] = make([]int, len(t)+1)
|
|
}
|
|
for i := range d {
|
|
d[i][0] = i
|
|
}
|
|
for j := range d[0] {
|
|
d[0][j] = j
|
|
}
|
|
for j := 1; j <= len(t); j++ {
|
|
for i := 1; i <= len(s); i++ {
|
|
if s[i-1] == t[j-1] {
|
|
d[i][j] = d[i-1][j-1]
|
|
} else {
|
|
min := d[i-1][j]
|
|
if d[i][j-1] < min {
|
|
min = d[i][j-1]
|
|
}
|
|
if d[i-1][j-1] < min {
|
|
min = d[i-1][j-1]
|
|
}
|
|
d[i][j] = min + 1
|
|
}
|
|
}
|
|
|
|
}
|
|
return d[len(s)][len(t)]
|
|
}
|