github.com/henvic/wedeploycli@v1.7.6-0.20200319005353-3630f582f284/templates/templates.go (about)

     1  // Licensed under Apache license 2.0
     2  // SPDX-License-Identifier: Apache-2.0
     3  // Copyright 2013-2016 Docker, Inc.
     4  
     5  // NOTICE: export from moby/utils/templates/templates.go (modified)
     6  // https://github.com/moby/moby/blob/da0ccf8e61e4d5d4005e19fcf0115372f09840bf/utils/templates/templates.go
     7  // https://github.com/moby/moby/blob/da0ccf8e61e4d5d4005e19fcf0115372f09840bf/LICENSE
     8  
     9  package templates
    10  
    11  import (
    12  	"bytes"
    13  	"encoding/json"
    14  	"io"
    15  	"strings"
    16  	"text/template"
    17  
    18  	"github.com/hashicorp/errwrap"
    19  )
    20  
    21  var funcs = template.FuncMap{
    22  	"json": func(v interface{}) string {
    23  		a, _ := json.Marshal(v)
    24  		return string(a)
    25  	},
    26  	"split": strings.Split,
    27  	"join":  strings.Join,
    28  	"title": strings.Title,
    29  	"lower": strings.ToLower,
    30  	"upper": strings.ToUpper,
    31  	"pad":   padWithSpace,
    32  }
    33  
    34  // Funcs adds the elements of the argument map to the template's function map.
    35  func Funcs(funcMap template.FuncMap) {
    36  	for k, v := range funcMap {
    37  		funcs[k] = v
    38  	}
    39  }
    40  
    41  type compiledTemplate struct {
    42  	template *template.Template
    43  	err      error
    44  }
    45  
    46  var cachedTmpl = map[string]compiledTemplate{}
    47  
    48  // ExecuteOrList executes the Execute function if format is not empty,
    49  // otherwise, it returns all as a JSON
    50  func ExecuteOrList(format string, data interface{}) (string, error) {
    51  	if format != "" {
    52  		return Execute(format, data)
    53  	}
    54  
    55  	bin, err := json.MarshalIndent(&data, "", "    ")
    56  
    57  	if err != nil {
    58  		return "", err
    59  	}
    60  
    61  	return string(bin), nil
    62  }
    63  
    64  // Execute template with format and data values
    65  func Execute(format string, data interface{}) (string, error) {
    66  	if _, ok := cachedTmpl[format]; !ok {
    67  		tmpl, tmplErr := parse(format)
    68  		cachedTmpl[format] = compiledTemplate{tmpl, tmplErr}
    69  	}
    70  
    71  	return execute(format, data)
    72  }
    73  
    74  func execute(format string, data interface{}) (string, error) {
    75  	var (
    76  		buf bytes.Buffer
    77  		wr  io.Writer = &buf
    78  
    79  		cached = cachedTmpl[format]
    80  		tmpl   = cached.template
    81  		err    = cached.err
    82  	)
    83  
    84  	if err != nil {
    85  		return "", errwrap.Wrapf("template parsing error: {{err}}", err)
    86  	}
    87  
    88  	if err := tmpl.Execute(wr, data); err != nil {
    89  		return "", errwrap.Wrapf("can't execute template: {{err}}", err)
    90  	}
    91  
    92  	return buf.String(), nil
    93  }
    94  
    95  // Parse creates a new annonymous template with the basic functions
    96  // and parses the given format.
    97  func parse(format string) (*template.Template, error) {
    98  	return newParse("", format)
    99  }
   100  
   101  // NewParse creates a new tagged template with the basic functions
   102  // and parses the given format.
   103  func newParse(tag, format string) (*template.Template, error) {
   104  	return template.New(tag).Funcs(funcs).Parse(format)
   105  }
   106  
   107  // padWithSpace adds whitespace to the input if the input is non-empty
   108  func padWithSpace(source string, prefix, suffix int) string {
   109  	if source == "" {
   110  		return source
   111  	}
   112  	return strings.Repeat(" ", prefix) + source + strings.Repeat(" ", suffix)
   113  }