podman
244 строки · 7.3 Кб
1// Copyright 2013-2023 The Cobra Authors
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15// Commands similar to git, go tools and other modern CLI tools
16// inspired by go, go-Commander, gh and subcommand
17
18package cobra19
20import (21"fmt"22"io"23"os"24"reflect"25"strconv"26"strings"27"text/template"28"time"29"unicode"30)
31
32var templateFuncs = template.FuncMap{33"trim": strings.TrimSpace,34"trimRightSpace": trimRightSpace,35"trimTrailingWhitespaces": trimRightSpace,36"appendIfNotPresent": appendIfNotPresent,37"rpad": rpad,38"gt": Gt,39"eq": Eq,40}
41
42var initializers []func()43var finalizers []func()44
45const (46defaultPrefixMatching = false47defaultCommandSorting = true48defaultCaseInsensitive = false49defaultTraverseRunHooks = false50)
51
52// EnablePrefixMatching allows setting automatic prefix matching. Automatic prefix matching can be a dangerous thing
53// to automatically enable in CLI tools.
54// Set this to true to enable it.
55var EnablePrefixMatching = defaultPrefixMatching56
57// EnableCommandSorting controls sorting of the slice of commands, which is turned on by default.
58// To disable sorting, set it to false.
59var EnableCommandSorting = defaultCommandSorting60
61// EnableCaseInsensitive allows case-insensitive commands names. (case sensitive by default)
62var EnableCaseInsensitive = defaultCaseInsensitive63
64// EnableTraverseRunHooks executes persistent pre-run and post-run hooks from all parents.
65// By default this is disabled, which means only the first run hook to be found is executed.
66var EnableTraverseRunHooks = defaultTraverseRunHooks67
68// MousetrapHelpText enables an information splash screen on Windows
69// if the CLI is started from explorer.exe.
70// To disable the mousetrap, just set this variable to blank string ("").
71// Works only on Microsoft Windows.
72var MousetrapHelpText = `This is a command line tool.73
74You need to open cmd.exe and run it from there.
75`
76
77// MousetrapDisplayDuration controls how long the MousetrapHelpText message is displayed on Windows
78// if the CLI is started from explorer.exe. Set to 0 to wait for the return key to be pressed.
79// To disable the mousetrap, just set MousetrapHelpText to blank string ("").
80// Works only on Microsoft Windows.
81var MousetrapDisplayDuration = 5 * time.Second82
83// AddTemplateFunc adds a template function that's available to Usage and Help
84// template generation.
85func AddTemplateFunc(name string, tmplFunc interface{}) {86templateFuncs[name] = tmplFunc87}
88
89// AddTemplateFuncs adds multiple template functions that are available to Usage and
90// Help template generation.
91func AddTemplateFuncs(tmplFuncs template.FuncMap) {92for k, v := range tmplFuncs {93templateFuncs[k] = v94}95}
96
97// OnInitialize sets the passed functions to be run when each command's
98// Execute method is called.
99func OnInitialize(y ...func()) {100initializers = append(initializers, y...)101}
102
103// OnFinalize sets the passed functions to be run when each command's
104// Execute method is terminated.
105func OnFinalize(y ...func()) {106finalizers = append(finalizers, y...)107}
108
109// FIXME Gt is unused by cobra and should be removed in a version 2. It exists only for compatibility with users of cobra.
110
111// Gt takes two types and checks whether the first type is greater than the second. In case of types Arrays, Chans,
112// Maps and Slices, Gt will compare their lengths. Ints are compared directly while strings are first parsed as
113// ints and then compared.
114func Gt(a interface{}, b interface{}) bool {115var left, right int64116av := reflect.ValueOf(a)117
118switch av.Kind() {119case reflect.Array, reflect.Chan, reflect.Map, reflect.Slice:120left = int64(av.Len())121case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:122left = av.Int()123case reflect.String:124left, _ = strconv.ParseInt(av.String(), 10, 64)125}126
127bv := reflect.ValueOf(b)128
129switch bv.Kind() {130case reflect.Array, reflect.Chan, reflect.Map, reflect.Slice:131right = int64(bv.Len())132case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:133right = bv.Int()134case reflect.String:135right, _ = strconv.ParseInt(bv.String(), 10, 64)136}137
138return left > right139}
140
141// FIXME Eq is unused by cobra and should be removed in a version 2. It exists only for compatibility with users of cobra.
142
143// Eq takes two types and checks whether they are equal. Supported types are int and string. Unsupported types will panic.
144func Eq(a interface{}, b interface{}) bool {145av := reflect.ValueOf(a)146bv := reflect.ValueOf(b)147
148switch av.Kind() {149case reflect.Array, reflect.Chan, reflect.Map, reflect.Slice:150panic("Eq called on unsupported type")151case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:152return av.Int() == bv.Int()153case reflect.String:154return av.String() == bv.String()155}156return false157}
158
159func trimRightSpace(s string) string {160return strings.TrimRightFunc(s, unicode.IsSpace)161}
162
163// FIXME appendIfNotPresent is unused by cobra and should be removed in a version 2. It exists only for compatibility with users of cobra.
164
165// appendIfNotPresent will append stringToAppend to the end of s, but only if it's not yet present in s.
166func appendIfNotPresent(s, stringToAppend string) string {167if strings.Contains(s, stringToAppend) {168return s169}170return s + " " + stringToAppend171}
172
173// rpad adds padding to the right of a string.
174func rpad(s string, padding int) string {175formattedString := fmt.Sprintf("%%-%ds", padding)176return fmt.Sprintf(formattedString, s)177}
178
179// tmpl executes the given template text on data, writing the result to w.
180func tmpl(w io.Writer, text string, data interface{}) error {181t := template.New("top")182t.Funcs(templateFuncs)183template.Must(t.Parse(text))184return t.Execute(w, data)185}
186
187// ld compares two strings and returns the levenshtein distance between them.
188func ld(s, t string, ignoreCase bool) int {189if ignoreCase {190s = strings.ToLower(s)191t = strings.ToLower(t)192}193d := make([][]int, len(s)+1)194for i := range d {195d[i] = make([]int, len(t)+1)196}197for i := range d {198d[i][0] = i199}200for j := range d[0] {201d[0][j] = j202}203for j := 1; j <= len(t); j++ {204for i := 1; i <= len(s); i++ {205if s[i-1] == t[j-1] {206d[i][j] = d[i-1][j-1]207} else {208min := d[i-1][j]209if d[i][j-1] < min {210min = d[i][j-1]211}212if d[i-1][j-1] < min {213min = d[i-1][j-1]214}215d[i][j] = min + 1216}217}218
219}220return d[len(s)][len(t)]221}
222
223func stringInSlice(a string, list []string) bool {224for _, b := range list {225if b == a {226return true227}228}229return false230}
231
232// CheckErr prints the msg with the prefix 'Error:' and exits with error code 1. If the msg is nil, it does nothing.
233func CheckErr(msg interface{}) {234if msg != nil {235fmt.Fprintln(os.Stderr, "Error:", msg)236os.Exit(1)237}238}
239
240// WriteStringAndCheck writes a string into a buffer, and checks if the error is not nil.
241func WriteStringAndCheck(b io.StringWriter, s string) {242_, err := b.WriteString(s)243CheckErr(err)244}
245