podman
382 строки · 10.8 Кб
1package sprig
2
3import (
4"errors"
5"html/template"
6"math/rand"
7"os"
8"path"
9"path/filepath"
10"reflect"
11"strconv"
12"strings"
13ttemplate "text/template"
14"time"
15
16util "github.com/Masterminds/goutils"
17"github.com/huandu/xstrings"
18"github.com/shopspring/decimal"
19)
20
21// FuncMap produces the function map.
22//
23// Use this to pass the functions into the template engine:
24//
25// tpl := template.New("foo").Funcs(sprig.FuncMap()))
26//
27func FuncMap() template.FuncMap {
28return HtmlFuncMap()
29}
30
31// HermeticTxtFuncMap returns a 'text/template'.FuncMap with only repeatable functions.
32func HermeticTxtFuncMap() ttemplate.FuncMap {
33r := TxtFuncMap()
34for _, name := range nonhermeticFunctions {
35delete(r, name)
36}
37return r
38}
39
40// HermeticHtmlFuncMap returns an 'html/template'.Funcmap with only repeatable functions.
41func HermeticHtmlFuncMap() template.FuncMap {
42r := HtmlFuncMap()
43for _, name := range nonhermeticFunctions {
44delete(r, name)
45}
46return r
47}
48
49// TxtFuncMap returns a 'text/template'.FuncMap
50func TxtFuncMap() ttemplate.FuncMap {
51return ttemplate.FuncMap(GenericFuncMap())
52}
53
54// HtmlFuncMap returns an 'html/template'.Funcmap
55func HtmlFuncMap() template.FuncMap {
56return template.FuncMap(GenericFuncMap())
57}
58
59// GenericFuncMap returns a copy of the basic function map as a map[string]interface{}.
60func GenericFuncMap() map[string]interface{} {
61gfm := make(map[string]interface{}, len(genericMap))
62for k, v := range genericMap {
63gfm[k] = v
64}
65return gfm
66}
67
68// These functions are not guaranteed to evaluate to the same result for given input, because they
69// refer to the environment or global state.
70var nonhermeticFunctions = []string{
71// Date functions
72"date",
73"date_in_zone",
74"date_modify",
75"now",
76"htmlDate",
77"htmlDateInZone",
78"dateInZone",
79"dateModify",
80
81// Strings
82"randAlphaNum",
83"randAlpha",
84"randAscii",
85"randNumeric",
86"randBytes",
87"uuidv4",
88
89// OS
90"env",
91"expandenv",
92
93// Network
94"getHostByName",
95}
96
97var genericMap = map[string]interface{}{
98"hello": func() string { return "Hello!" },
99
100// Date functions
101"ago": dateAgo,
102"date": date,
103"date_in_zone": dateInZone,
104"date_modify": dateModify,
105"dateInZone": dateInZone,
106"dateModify": dateModify,
107"duration": duration,
108"durationRound": durationRound,
109"htmlDate": htmlDate,
110"htmlDateInZone": htmlDateInZone,
111"must_date_modify": mustDateModify,
112"mustDateModify": mustDateModify,
113"mustToDate": mustToDate,
114"now": time.Now,
115"toDate": toDate,
116"unixEpoch": unixEpoch,
117
118// Strings
119"abbrev": abbrev,
120"abbrevboth": abbrevboth,
121"trunc": trunc,
122"trim": strings.TrimSpace,
123"upper": strings.ToUpper,
124"lower": strings.ToLower,
125"title": strings.Title,
126"untitle": untitle,
127"substr": substring,
128// Switch order so that "foo" | repeat 5
129"repeat": func(count int, str string) string { return strings.Repeat(str, count) },
130// Deprecated: Use trimAll.
131"trimall": func(a, b string) string { return strings.Trim(b, a) },
132// Switch order so that "$foo" | trimall "$"
133"trimAll": func(a, b string) string { return strings.Trim(b, a) },
134"trimSuffix": func(a, b string) string { return strings.TrimSuffix(b, a) },
135"trimPrefix": func(a, b string) string { return strings.TrimPrefix(b, a) },
136"nospace": util.DeleteWhiteSpace,
137"initials": initials,
138"randAlphaNum": randAlphaNumeric,
139"randAlpha": randAlpha,
140"randAscii": randAscii,
141"randNumeric": randNumeric,
142"swapcase": util.SwapCase,
143"shuffle": xstrings.Shuffle,
144"snakecase": xstrings.ToSnakeCase,
145"camelcase": xstrings.ToCamelCase,
146"kebabcase": xstrings.ToKebabCase,
147"wrap": func(l int, s string) string { return util.Wrap(s, l) },
148"wrapWith": func(l int, sep, str string) string { return util.WrapCustom(str, l, sep, true) },
149// Switch order so that "foobar" | contains "foo"
150"contains": func(substr string, str string) bool { return strings.Contains(str, substr) },
151"hasPrefix": func(substr string, str string) bool { return strings.HasPrefix(str, substr) },
152"hasSuffix": func(substr string, str string) bool { return strings.HasSuffix(str, substr) },
153"quote": quote,
154"squote": squote,
155"cat": cat,
156"indent": indent,
157"nindent": nindent,
158"replace": replace,
159"plural": plural,
160"sha1sum": sha1sum,
161"sha256sum": sha256sum,
162"adler32sum": adler32sum,
163"toString": strval,
164
165// Wrap Atoi to stop errors.
166"atoi": func(a string) int { i, _ := strconv.Atoi(a); return i },
167"int64": toInt64,
168"int": toInt,
169"float64": toFloat64,
170"seq": seq,
171"toDecimal": toDecimal,
172
173//"gt": func(a, b int) bool {return a > b},
174//"gte": func(a, b int) bool {return a >= b},
175//"lt": func(a, b int) bool {return a < b},
176//"lte": func(a, b int) bool {return a <= b},
177
178// split "/" foo/bar returns map[int]string{0: foo, 1: bar}
179"split": split,
180"splitList": func(sep, orig string) []string { return strings.Split(orig, sep) },
181// splitn "/" foo/bar/fuu returns map[int]string{0: foo, 1: bar/fuu}
182"splitn": splitn,
183"toStrings": strslice,
184
185"until": until,
186"untilStep": untilStep,
187
188// VERY basic arithmetic.
189"add1": func(i interface{}) int64 { return toInt64(i) + 1 },
190"add": func(i ...interface{}) int64 {
191var a int64 = 0
192for _, b := range i {
193a += toInt64(b)
194}
195return a
196},
197"sub": func(a, b interface{}) int64 { return toInt64(a) - toInt64(b) },
198"div": func(a, b interface{}) int64 { return toInt64(a) / toInt64(b) },
199"mod": func(a, b interface{}) int64 { return toInt64(a) % toInt64(b) },
200"mul": func(a interface{}, v ...interface{}) int64 {
201val := toInt64(a)
202for _, b := range v {
203val = val * toInt64(b)
204}
205return val
206},
207"randInt": func(min, max int) int { return rand.Intn(max-min) + min },
208"add1f": func(i interface{}) float64 {
209return execDecimalOp(i, []interface{}{1}, func(d1, d2 decimal.Decimal) decimal.Decimal { return d1.Add(d2) })
210},
211"addf": func(i ...interface{}) float64 {
212a := interface{}(float64(0))
213return execDecimalOp(a, i, func(d1, d2 decimal.Decimal) decimal.Decimal { return d1.Add(d2) })
214},
215"subf": func(a interface{}, v ...interface{}) float64 {
216return execDecimalOp(a, v, func(d1, d2 decimal.Decimal) decimal.Decimal { return d1.Sub(d2) })
217},
218"divf": func(a interface{}, v ...interface{}) float64 {
219return execDecimalOp(a, v, func(d1, d2 decimal.Decimal) decimal.Decimal { return d1.Div(d2) })
220},
221"mulf": func(a interface{}, v ...interface{}) float64 {
222return execDecimalOp(a, v, func(d1, d2 decimal.Decimal) decimal.Decimal { return d1.Mul(d2) })
223},
224"biggest": max,
225"max": max,
226"min": min,
227"maxf": maxf,
228"minf": minf,
229"ceil": ceil,
230"floor": floor,
231"round": round,
232
233// string slices. Note that we reverse the order b/c that's better
234// for template processing.
235"join": join,
236"sortAlpha": sortAlpha,
237
238// Defaults
239"default": dfault,
240"empty": empty,
241"coalesce": coalesce,
242"all": all,
243"any": any,
244"compact": compact,
245"mustCompact": mustCompact,
246"fromJson": fromJson,
247"toJson": toJson,
248"toPrettyJson": toPrettyJson,
249"toRawJson": toRawJson,
250"mustFromJson": mustFromJson,
251"mustToJson": mustToJson,
252"mustToPrettyJson": mustToPrettyJson,
253"mustToRawJson": mustToRawJson,
254"ternary": ternary,
255"deepCopy": deepCopy,
256"mustDeepCopy": mustDeepCopy,
257
258// Reflection
259"typeOf": typeOf,
260"typeIs": typeIs,
261"typeIsLike": typeIsLike,
262"kindOf": kindOf,
263"kindIs": kindIs,
264"deepEqual": reflect.DeepEqual,
265
266// OS:
267"env": os.Getenv,
268"expandenv": os.ExpandEnv,
269
270// Network:
271"getHostByName": getHostByName,
272
273// Paths:
274"base": path.Base,
275"dir": path.Dir,
276"clean": path.Clean,
277"ext": path.Ext,
278"isAbs": path.IsAbs,
279
280// Filepaths:
281"osBase": filepath.Base,
282"osClean": filepath.Clean,
283"osDir": filepath.Dir,
284"osExt": filepath.Ext,
285"osIsAbs": filepath.IsAbs,
286
287// Encoding:
288"b64enc": base64encode,
289"b64dec": base64decode,
290"b32enc": base32encode,
291"b32dec": base32decode,
292
293// Data Structures:
294"tuple": list, // FIXME: with the addition of append/prepend these are no longer immutable.
295"list": list,
296"dict": dict,
297"get": get,
298"set": set,
299"unset": unset,
300"hasKey": hasKey,
301"pluck": pluck,
302"keys": keys,
303"pick": pick,
304"omit": omit,
305"merge": merge,
306"mergeOverwrite": mergeOverwrite,
307"mustMerge": mustMerge,
308"mustMergeOverwrite": mustMergeOverwrite,
309"values": values,
310
311"append": push, "push": push,
312"mustAppend": mustPush, "mustPush": mustPush,
313"prepend": prepend,
314"mustPrepend": mustPrepend,
315"first": first,
316"mustFirst": mustFirst,
317"rest": rest,
318"mustRest": mustRest,
319"last": last,
320"mustLast": mustLast,
321"initial": initial,
322"mustInitial": mustInitial,
323"reverse": reverse,
324"mustReverse": mustReverse,
325"uniq": uniq,
326"mustUniq": mustUniq,
327"without": without,
328"mustWithout": mustWithout,
329"has": has,
330"mustHas": mustHas,
331"slice": slice,
332"mustSlice": mustSlice,
333"concat": concat,
334"dig": dig,
335"chunk": chunk,
336"mustChunk": mustChunk,
337
338// Crypto:
339"bcrypt": bcrypt,
340"htpasswd": htpasswd,
341"genPrivateKey": generatePrivateKey,
342"derivePassword": derivePassword,
343"buildCustomCert": buildCustomCertificate,
344"genCA": generateCertificateAuthority,
345"genCAWithKey": generateCertificateAuthorityWithPEMKey,
346"genSelfSignedCert": generateSelfSignedCertificate,
347"genSelfSignedCertWithKey": generateSelfSignedCertificateWithPEMKey,
348"genSignedCert": generateSignedCertificate,
349"genSignedCertWithKey": generateSignedCertificateWithPEMKey,
350"encryptAES": encryptAES,
351"decryptAES": decryptAES,
352"randBytes": randBytes,
353
354// UUIDs:
355"uuidv4": uuidv4,
356
357// SemVer:
358"semver": semver,
359"semverCompare": semverCompare,
360
361// Flow Control:
362"fail": func(msg string) (string, error) { return "", errors.New(msg) },
363
364// Regex
365"regexMatch": regexMatch,
366"mustRegexMatch": mustRegexMatch,
367"regexFindAll": regexFindAll,
368"mustRegexFindAll": mustRegexFindAll,
369"regexFind": regexFind,
370"mustRegexFind": mustRegexFind,
371"regexReplaceAll": regexReplaceAll,
372"mustRegexReplaceAll": mustRegexReplaceAll,
373"regexReplaceAllLiteral": regexReplaceAllLiteral,
374"mustRegexReplaceAllLiteral": mustRegexReplaceAllLiteral,
375"regexSplit": regexSplit,
376"mustRegexSplit": mustRegexSplit,
377"regexQuoteMeta": regexQuoteMeta,
378
379// URLs:
380"urlParse": urlParse,
381"urlJoin": urlJoin,
382}
383