github.com/zntrio/harp/v2@v2.0.9/pkg/template/engine/compiler.go (about) 1 // Licensed to Elasticsearch B.V. under one or more contributor 2 // license agreements. See the NOTICE file distributed with 3 // this work for additional information regarding copyright 4 // ownership. Elasticsearch B.V. licenses this file to you under 5 // the Apache License, Version 2.0 (the "License"); you may 6 // not use this file except in compliance with the License. 7 // You may obtain a copy of the License at 8 // 9 // http://www.apache.org/licenses/LICENSE-2.0 10 // 11 // Unless required by applicable law or agreed to in writing, 12 // software distributed under the License is distributed on an 13 // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 // KIND, either express or implied. See the License for the 15 // specific language governing permissions and limitations 16 // under the License. 17 18 package engine 19 20 import ( 21 "bytes" 22 "fmt" 23 "text/template" 24 ) 25 26 // ----------------------------------------------------------------------------- 27 28 // Render compile and assemble attribute template to merge with values. 29 func Render(input string, data interface{}) (content string, err error) { 30 // Check argument 31 defer func() { 32 if r := recover(); r != nil { 33 err = fmt.Errorf("template rendering failed: %v", r) 34 } 35 }() 36 37 // Prepare the template 38 t, err := template.New("root"). 39 Funcs(FuncMap(nil)). 40 Parse(input) 41 if err != nil { 42 return "", fmt.Errorf("unable to compile attribute template %q: %w", input, err) 43 } 44 45 // Fail on missing key 46 t.Option("missingkey=error") 47 48 // Merge with values 49 var out bytes.Buffer 50 if err := t.Execute(&out, data); err != nil { 51 return "", fmt.Errorf("unable to merge data with template %q: %w", input, err) 52 } 53 54 // No error 55 return out.String(), nil 56 } 57 58 // RenderContext compile and assemble attribute template to merge with values. 59 func RenderContext(templateContext Context, input string) (string, error) { 60 return RenderContextWithData(templateContext, input, nil) 61 } 62 63 // RenderContextWithData compile and assemble attribute template to merge with values. 64 func RenderContextWithData(templateContext Context, input string, data interface{}) (content string, err error) { 65 // Check argument 66 defer func() { 67 if r := recover(); r != nil { 68 err = fmt.Errorf("template rendering failed: %v", r) 69 } 70 }() 71 72 // Retrieve delimiters 73 leftDelim, rightDelim := templateContext.Delims() 74 75 // Prepare the template 76 t, err := template.New(templateContext.Name()). 77 Delims(leftDelim, rightDelim). 78 Funcs(FuncMap(templateContext.SecretReaders())). 79 Parse(input) 80 if err != nil { 81 return "", fmt.Errorf("unable to compile attribute template %q: %w", input, err) 82 } 83 84 // Check strict mode 85 if templateContext.StrictMode() { 86 // Fail on missing key 87 t.Option("missingkey=error") 88 } else { 89 // Not that zero will attempt to add default values for types it knows, 90 // but will still emit <no value> for others. We mitigate that later. 91 t.Option("missingkey=zero") 92 } 93 94 // Merge with values 95 var out bytes.Buffer 96 if err := t.Execute(&out, map[string]interface{}{ 97 "Data": data, 98 "Values": templateContext.Values(), 99 "Files": templateContext.Files(), 100 }); err != nil { 101 return "", fmt.Errorf("unable to merge values with template %q: %w", input, err) 102 } 103 104 // No error 105 return out.String(), nil 106 }