1package sprig
2
3import (
4	"encoding/base32"
5	"encoding/base64"
6	"fmt"
7	"reflect"
8	"strconv"
9	"strings"
10
11	util "github.com/Masterminds/goutils"
12)
13
14func base64encode(v string) string {
15	return base64.StdEncoding.EncodeToString([]byte(v))
16}
17
18func base64decode(v string) string {
19	data, err := base64.StdEncoding.DecodeString(v)
20	if err != nil {
21		return err.Error()
22	}
23	return string(data)
24}
25
26func base32encode(v string) string {
27	return base32.StdEncoding.EncodeToString([]byte(v))
28}
29
30func base32decode(v string) string {
31	data, err := base32.StdEncoding.DecodeString(v)
32	if err != nil {
33		return err.Error()
34	}
35	return string(data)
36}
37
38func abbrev(width int, s string) string {
39	if width < 4 {
40		return s
41	}
42	r, _ := util.Abbreviate(s, width)
43	return r
44}
45
46func abbrevboth(left, right int, s string) string {
47	if right < 4 || left > 0 && right < 7 {
48		return s
49	}
50	r, _ := util.AbbreviateFull(s, left, right)
51	return r
52}
53func initials(s string) string {
54	// Wrap this just to eliminate the var args, which templates don't do well.
55	return util.Initials(s)
56}
57
58func randAlphaNumeric(count int) string {
59	// It is not possible, it appears, to actually generate an error here.
60	r, _ := util.CryptoRandomAlphaNumeric(count)
61	return r
62}
63
64func randAlpha(count int) string {
65	r, _ := util.CryptoRandomAlphabetic(count)
66	return r
67}
68
69func randAscii(count int) string {
70	r, _ := util.CryptoRandomAscii(count)
71	return r
72}
73
74func randNumeric(count int) string {
75	r, _ := util.CryptoRandomNumeric(count)
76	return r
77}
78
79func untitle(str string) string {
80	return util.Uncapitalize(str)
81}
82
83func quote(str ...interface{}) string {
84	out := make([]string, 0, len(str))
85	for _, s := range str {
86		if s != nil {
87			out = append(out, fmt.Sprintf("%q", strval(s)))
88		}
89	}
90	return strings.Join(out, " ")
91}
92
93func squote(str ...interface{}) string {
94	out := make([]string, 0, len(str))
95	for _, s := range str {
96		if s != nil {
97			out = append(out, fmt.Sprintf("'%v'", s))
98		}
99	}
100	return strings.Join(out, " ")
101}
102
103func cat(v ...interface{}) string {
104	v = removeNilElements(v)
105	r := strings.TrimSpace(strings.Repeat("%v ", len(v)))
106	return fmt.Sprintf(r, v...)
107}
108
109func indent(spaces int, v string) string {
110	pad := strings.Repeat(" ", spaces)
111	return pad + strings.Replace(v, "\n", "\n"+pad, -1)
112}
113
114func nindent(spaces int, v string) string {
115	return "\n" + indent(spaces, v)
116}
117
118func replace(old, new, src string) string {
119	return strings.Replace(src, old, new, -1)
120}
121
122func plural(one, many string, count int) string {
123	if count == 1 {
124		return one
125	}
126	return many
127}
128
129func strslice(v interface{}) []string {
130	switch v := v.(type) {
131	case []string:
132		return v
133	case []interface{}:
134		b := make([]string, 0, len(v))
135		for _, s := range v {
136			if s != nil {
137				b = append(b, strval(s))
138			}
139		}
140		return b
141	default:
142		val := reflect.ValueOf(v)
143		switch val.Kind() {
144		case reflect.Array, reflect.Slice:
145			l := val.Len()
146			b := make([]string, 0, l)
147			for i := 0; i < l; i++ {
148				value := val.Index(i).Interface()
149				if value != nil {
150					b = append(b, strval(value))
151				}
152			}
153			return b
154		default:
155			if v == nil {
156				return []string{}
157			}
158
159			return []string{strval(v)}
160		}
161	}
162}
163
164func removeNilElements(v []interface{}) []interface{} {
165	newSlice := make([]interface{}, 0, len(v))
166	for _, i := range v {
167		if i != nil {
168			newSlice = append(newSlice, i)
169		}
170	}
171	return newSlice
172}
173
174func strval(v interface{}) string {
175	switch v := v.(type) {
176	case string:
177		return v
178	case []byte:
179		return string(v)
180	case error:
181		return v.Error()
182	case fmt.Stringer:
183		return v.String()
184	default:
185		return fmt.Sprintf("%v", v)
186	}
187}
188
189func trunc(c int, s string) string {
190	if c < 0 && len(s)+c > 0 {
191		return s[len(s)+c:]
192	}
193	if c >= 0 && len(s) > c {
194		return s[:c]
195	}
196	return s
197}
198
199func join(sep string, v interface{}) string {
200	return strings.Join(strslice(v), sep)
201}
202
203func split(sep, orig string) map[string]string {
204	parts := strings.Split(orig, sep)
205	res := make(map[string]string, len(parts))
206	for i, v := range parts {
207		res["_"+strconv.Itoa(i)] = v
208	}
209	return res
210}
211
212func splitn(sep string, n int, orig string) map[string]string {
213	parts := strings.SplitN(orig, sep, n)
214	res := make(map[string]string, len(parts))
215	for i, v := range parts {
216		res["_"+strconv.Itoa(i)] = v
217	}
218	return res
219}
220
221// substring creates a substring of the given string.
222//
223// If start is < 0, this calls string[:end].
224//
225// If start is >= 0 and end < 0 or end bigger than s length, this calls string[start:]
226//
227// Otherwise, this calls string[start, end].
228func substring(start, end int, s string) string {
229	if start < 0 {
230		return s[:end]
231	}
232	if end < 0 || end > len(s) {
233		return s[start:]
234	}
235	return s[start:end]
236}
237