mirror of https://github.com/dexidp/dex.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
175 lines
4.8 KiB
175 lines
4.8 KiB
// 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, |
|
"appendIfNotPresent": appendIfNotPresent, |
|
"rpad": rpad, |
|
"gt": Gt, |
|
"eq": Eq, |
|
} |
|
|
|
var initializers []func() |
|
|
|
// 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 |
|
|
|
//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 availalble 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()) { |
|
for _, x := range y { |
|
initializers = append(initializers, x) |
|
} |
|
} |
|
|
|
//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 |
|
} |
|
|
|
//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) |
|
} |
|
|
|
// 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)] |
|
}
|
|
|