147 lines
4.4 KiB
Go
147 lines
4.4 KiB
Go
package templatelib
|
|
|
|
import (
|
|
"crypto/sha256"
|
|
"encoding/hex"
|
|
"encoding/json"
|
|
"fmt"
|
|
"os"
|
|
"reflect"
|
|
"strings"
|
|
"text/template"
|
|
)
|
|
|
|
func swapStringsFuncBoolArgsOrder(a func(string, string) bool) func(string, string) bool {
|
|
return func(str1 string, str2 string) bool {
|
|
return a(str2, str1)
|
|
}
|
|
}
|
|
|
|
func thingsActionFactory(name string, actOnFirst bool, action func([]interface{}, interface{}) interface{}) func(args ...interface{}) interface{} {
|
|
return func(args ...interface{}) interface{} {
|
|
if len(args) < 1 {
|
|
panic(fmt.Sprintf(`%q requires at least one argument`, name))
|
|
}
|
|
|
|
actArgs := []interface{}{}
|
|
for _, val := range args {
|
|
v := reflect.ValueOf(val)
|
|
|
|
switch v.Kind() {
|
|
case reflect.Slice, reflect.Array:
|
|
for i := 0; i < v.Len(); i++ {
|
|
actArgs = append(actArgs, v.Index(i).Interface())
|
|
}
|
|
default:
|
|
actArgs = append(actArgs, v.Interface())
|
|
}
|
|
}
|
|
|
|
var arg interface{}
|
|
if actOnFirst {
|
|
arg = actArgs[0]
|
|
actArgs = actArgs[1:]
|
|
} else {
|
|
arg = actArgs[len(actArgs)-1]
|
|
actArgs = actArgs[:len(actArgs)-1]
|
|
}
|
|
|
|
return action(actArgs, arg)
|
|
}
|
|
}
|
|
|
|
func stringsActionFactory(name string, actOnFirst bool, action func([]string, string) string) func(args ...interface{}) interface{} {
|
|
return thingsActionFactory(name, actOnFirst, func(args []interface{}, arg interface{}) interface{} {
|
|
str := arg.(string)
|
|
strs := []string{}
|
|
for _, val := range args {
|
|
strs = append(strs, val.(string))
|
|
}
|
|
return action(strs, str)
|
|
})
|
|
}
|
|
|
|
func stringsModifierActionFactory(a func(string, string) string) func([]string, string) string {
|
|
return func(strs []string, str string) string {
|
|
for _, mod := range strs {
|
|
str = a(str, mod)
|
|
}
|
|
return str
|
|
}
|
|
}
|
|
|
|
var FuncMap = template.FuncMap{
|
|
// {{- $isGitHub := hasPrefix "https://github.com/" $url -}}
|
|
// {{- $isHtml := hasSuffix ".html" $url -}}
|
|
"hasPrefix": swapStringsFuncBoolArgsOrder(strings.HasPrefix),
|
|
"hasSuffix": swapStringsFuncBoolArgsOrder(strings.HasSuffix),
|
|
|
|
// {{- $hugeIfTrue := .SomeValue | ternary "HUGE" "not so huge" -}}
|
|
// if .SomeValue is truthy, $hugeIfTrue will be "HUGE"
|
|
// (otherwise, "not so huge")
|
|
"ternary": func(truthy interface{}, falsey interface{}, val interface{}) interface{} {
|
|
if t, ok := template.IsTrue(val); !ok {
|
|
panic(fmt.Sprintf(`template.IsTrue(%+v) says things are NOT OK`, val))
|
|
} else if t {
|
|
return truthy
|
|
} else {
|
|
return falsey
|
|
}
|
|
},
|
|
|
|
// First Tag: {{- .Tags | first -}}
|
|
// Last Tag: {{- .Tags | last -}}
|
|
"first": thingsActionFactory("first", true, func(args []interface{}, arg interface{}) interface{} { return arg }),
|
|
"last": thingsActionFactory("last", false, func(args []interface{}, arg interface{}) interface{} { return arg }),
|
|
|
|
// JSON data dump: {{ json . }}
|
|
// (especially nice for taking data and piping it to "jq")
|
|
// (ie "some-tool inspect --format '{{ json . }}' some-things | jq .")
|
|
"json": func(v interface{}) (string, error) {
|
|
j, err := json.Marshal(v)
|
|
return string(j), err
|
|
},
|
|
|
|
// Everybody: {{- join ", " .Names -}}
|
|
// Concat: {{- join "/" "https://github.com" "jsmith" "some-repo" -}}
|
|
"join": stringsActionFactory("join", true, strings.Join),
|
|
|
|
// {{- $mungedUrl := $url | replace "git://" "https://" | trimSuffixes ".git" -}}
|
|
// turns: git://github.com/jsmith/some-repo.git
|
|
// into: https://github.com/jsmith/some-repo
|
|
"trimPrefixes": stringsActionFactory("trimPrefixes", false, stringsModifierActionFactory(strings.TrimPrefix)),
|
|
"trimSuffixes": stringsActionFactory("trimSuffixes", false, stringsModifierActionFactory(strings.TrimSuffix)),
|
|
"replace": stringsActionFactory("replace", false, func(strs []string, str string) string {
|
|
return strings.NewReplacer(strs...).Replace(str)
|
|
}),
|
|
|
|
// {{- getenv "PATH" -}}
|
|
// {{- getenv "HOME" "no HOME set" -}}
|
|
// {{- getenv "HOME" "is set" "is NOT set (or is empty)" -}}
|
|
"getenv": thingsActionFactory("getenv", true, func(args []interface{}, arg interface{}) interface{} {
|
|
var (
|
|
val = os.Getenv(arg.(string))
|
|
setVal interface{} = val
|
|
unsetVal interface{} = ""
|
|
)
|
|
if len(args) == 2 {
|
|
setVal, unsetVal = args[0], args[1]
|
|
} else if len(args) == 1 {
|
|
unsetVal = args[0]
|
|
} else if len(args) != 0 {
|
|
panic(fmt.Sprintf(`expected between 1 and 3 arguments to "getenv", got %d`, len(args)+1))
|
|
}
|
|
if val != "" {
|
|
return setVal
|
|
} else {
|
|
return unsetVal
|
|
}
|
|
}),
|
|
|
|
// {{- sha256sum "hello world" -}}
|
|
"sha256sum": func(input string) string {
|
|
hash := sha256.Sum256([]byte(input))
|
|
return hex.EncodeToString(hash[:])
|
|
},
|
|
}
|