/
tools.go
131 lines (116 loc) · 3.07 KB
/
tools.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
package common
import (
"fmt"
"os"
"regexp"
"strconv"
"strings"
"time"
)
const stringWordSeparators = "[ \t\n,.;:\\(\\)\\[\\]{}'\"/\\\\!\\?<>@#|*+-=]"
// TrueStr is the true truth.
const TrueStr = "true"
const FalseStr = "false"
// PathExist returns true if a file or directory exists
func PathExist(path string) bool {
_, err := os.Stat(path)
if os.IsNotExist(err) {
return false
}
// I know Stat() may fail for a lot of reasons, but
// os.IsNotExist is not enough, see ENOTDIR for
// things like /etc/passwd/test
if err != nil {
return false
}
return true
}
// InterfaceValueToString converts most interface types to string
func InterfaceValueToString(iv interface{}) string {
switch civ := iv.(type) {
case int:
return fmt.Sprintf("%d", civ)
case int16:
return fmt.Sprintf("%d", civ)
case uint16:
return fmt.Sprintf("%d", civ)
case int32:
return fmt.Sprintf("%d", civ)
case int64:
return strconv.FormatInt(civ, 10)
case uint64:
return strconv.FormatUint(civ, 10)
case float32:
return fmt.Sprintf("%f", civ)
case float64:
return strconv.FormatFloat(civ, 'f', -1, 64)
case string:
return civ
case []byte:
return string(civ)
case bool:
return strconv.FormatBool(civ)
case time.Time:
return civ.String()
case time.Duration:
return civ.String()
case []string:
return strings.Join(civ, ", ")
}
return "INVALID_TYPE"
}
// MapStringToInterface convert a map[string]string to a map[string]interface{}
func MapStringToInterface(ms map[string]string) map[string]interface{} {
mi := make(map[string]interface{}, len(ms))
for k, v := range ms {
mi[k] = v
}
return mi
}
// StringFindVariables returns a deduplicated slice of all "variables" ($test)
// in the string
func StringFindVariables(str string) []string {
re := regexp.MustCompile("\\$([a-zA-Z0-9_]+)(" + stringWordSeparators + "|$)")
all := re.FindAllStringSubmatch(str, -1)
// deduplicate using a map
varMap := make(map[string]bool)
for _, v := range all {
varMap[v[1]] = true
}
// map to slice
res := []string{}
for name := range varMap {
res = append(res, name)
}
return res
}
// StringExpandVariables expands "variables" ($test, for instance) in str
// and returns a new string
func StringExpandVariables(str string, variables map[string]interface{}) string {
vars := StringFindVariables(str)
for _, v := range vars {
if val, exists := variables[v]; exists {
re := regexp.MustCompile("\\$" + v + "(" + stringWordSeparators + "|$)")
str = re.ReplaceAllString(str, InterfaceValueToString(val)+"${1}")
}
}
return str
}
// FileContains returns true if file contain text
func FileContains(filepath string, text string) (bool, error) {
data, err := os.ReadFile(filepath)
if err != nil {
return false, err
}
contains := strings.Contains(string(data), text)
return contains, nil
}
// StringIsVariable returns true and the value if the string's like:
// FOOBAR=dummy
// (returns true and "dummy" if varName is "FOOBAR")
func StringIsVariable(s string, varName string) (bool, string) {
if !strings.HasPrefix(s, varName+"=") {
return false, ""
}
return true, s[len(varName)+1:]
}