github.com/docker-library/go-dockerlibrary@v0.0.0-20200821205225-669fbe5c1d52/pkg/templatelib/lib.go (about) 1 package templatelib 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "os" 7 "reflect" 8 "strings" 9 "text/template" 10 ) 11 12 func swapStringsFuncBoolArgsOrder(a func(string, string) bool) func(string, string) bool { 13 return func(str1 string, str2 string) bool { 14 return a(str2, str1) 15 } 16 } 17 18 func thingsActionFactory(name string, actOnFirst bool, action func([]interface{}, interface{}) interface{}) func(args ...interface{}) interface{} { 19 return func(args ...interface{}) interface{} { 20 if len(args) < 1 { 21 panic(fmt.Sprintf(`%q requires at least one argument`, name)) 22 } 23 24 actArgs := []interface{}{} 25 for _, val := range args { 26 v := reflect.ValueOf(val) 27 28 switch v.Kind() { 29 case reflect.Slice, reflect.Array: 30 for i := 0; i < v.Len(); i++ { 31 actArgs = append(actArgs, v.Index(i).Interface()) 32 } 33 default: 34 actArgs = append(actArgs, v.Interface()) 35 } 36 } 37 38 var arg interface{} 39 if actOnFirst { 40 arg = actArgs[0] 41 actArgs = actArgs[1:] 42 } else { 43 arg = actArgs[len(actArgs)-1] 44 actArgs = actArgs[:len(actArgs)-1] 45 } 46 47 return action(actArgs, arg) 48 } 49 } 50 51 func stringsActionFactory(name string, actOnFirst bool, action func([]string, string) string) func(args ...interface{}) interface{} { 52 return thingsActionFactory(name, actOnFirst, func(args []interface{}, arg interface{}) interface{} { 53 str := arg.(string) 54 strs := []string{} 55 for _, val := range args { 56 strs = append(strs, val.(string)) 57 } 58 return action(strs, str) 59 }) 60 } 61 62 func stringsModifierActionFactory(a func(string, string) string) func([]string, string) string { 63 return func(strs []string, str string) string { 64 for _, mod := range strs { 65 str = a(str, mod) 66 } 67 return str 68 } 69 } 70 71 var FuncMap = template.FuncMap{ 72 // {{- $isGitHub := hasPrefix "https://github.com/" $url -}} 73 // {{- $isHtml := hasSuffix ".html" $url -}} 74 "hasPrefix": swapStringsFuncBoolArgsOrder(strings.HasPrefix), 75 "hasSuffix": swapStringsFuncBoolArgsOrder(strings.HasSuffix), 76 77 // {{- $hugeIfTrue := .SomeValue | ternary "HUGE" "not so huge" -}} 78 // if .SomeValue is truthy, $hugeIfTrue will be "HUGE" 79 // (otherwise, "not so huge") 80 "ternary": func(truthy interface{}, falsey interface{}, val interface{}) interface{} { 81 if t, ok := template.IsTrue(val); !ok { 82 panic(fmt.Sprintf(`template.IsTrue(%+v) says things are NOT OK`, val)) 83 } else if t { 84 return truthy 85 } else { 86 return falsey 87 } 88 }, 89 90 // First Tag: {{- .Tags | first -}} 91 // Last Tag: {{- .Tags | last -}} 92 "first": thingsActionFactory("first", true, func(args []interface{}, arg interface{}) interface{} { return arg }), 93 "last": thingsActionFactory("last", false, func(args []interface{}, arg interface{}) interface{} { return arg }), 94 95 // JSON data dump: {{ json . }} 96 // (especially nice for taking data and piping it to "jq") 97 // (ie "some-tool inspect --format '{{ json . }}' some-things | jq .") 98 "json": func(v interface{}) (string, error) { 99 j, err := json.Marshal(v) 100 return string(j), err 101 }, 102 103 // Everybody: {{- join ", " .Names -}} 104 // Concat: {{- join "/" "https://github.com" "jsmith" "some-repo" -}} 105 "join": stringsActionFactory("join", true, strings.Join), 106 107 // {{- $mungedUrl := $url | replace "git://" "https://" | trimSuffixes ".git" -}} 108 // turns: git://github.com/jsmith/some-repo.git 109 // into: https://github.com/jsmith/some-repo 110 "trimPrefixes": stringsActionFactory("trimPrefixes", false, stringsModifierActionFactory(strings.TrimPrefix)), 111 "trimSuffixes": stringsActionFactory("trimSuffixes", false, stringsModifierActionFactory(strings.TrimSuffix)), 112 "replace": stringsActionFactory("replace", false, func(strs []string, str string) string { 113 return strings.NewReplacer(strs...).Replace(str) 114 }), 115 116 // {{- getenv "PATH" -}} 117 // {{- getenv "HOME" "no HOME set" -}} 118 // {{- getenv "HOME" "is set" "is NOT set (or is empty)" -}} 119 "getenv": thingsActionFactory("getenv", true, func(args []interface{}, arg interface{}) interface{} { 120 var ( 121 val = os.Getenv(arg.(string)) 122 setVal interface{} = val 123 unsetVal interface{} = "" 124 ) 125 if len(args) == 2 { 126 setVal, unsetVal = args[0], args[1] 127 } else if len(args) == 1 { 128 unsetVal = args[0] 129 } else if len(args) != 0 { 130 panic(fmt.Sprintf(`expected between 1 and 3 arguments to "getenv", got %d`, len(args)+1)) 131 } 132 if val != "" { 133 return setVal 134 } else { 135 return unsetVal 136 } 137 }), 138 }