bashbrew/pkg/templatelib/lib.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[:])
},
}