github.com/homburg/packer@v0.6.1-0.20140528012651-1dcaf1716848/packer/config_template.go (about)

     1  package packer
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"github.com/mitchellh/packer/common/uuid"
     7  	"os"
     8  	"strconv"
     9  	"text/template"
    10  	"time"
    11  )
    12  
    13  // InitTime is the UTC time when this package was initialized. It is
    14  // used as the timestamp for all configuration templates so that they
    15  // match for a single build.
    16  var InitTime time.Time
    17  
    18  func init() {
    19  	InitTime = time.Now().UTC()
    20  }
    21  
    22  // ConfigTemplate processes string data as a text/template with some common
    23  // elements and functions available. Plugin creators should process as
    24  // many fields as possible through this.
    25  type ConfigTemplate struct {
    26  	UserVars map[string]string
    27  
    28  	root *template.Template
    29  	i    int
    30  }
    31  
    32  // NewConfigTemplate creates a new configuration template processor.
    33  func NewConfigTemplate() (*ConfigTemplate, error) {
    34  	result := &ConfigTemplate{
    35  		UserVars: make(map[string]string),
    36  	}
    37  
    38  	result.root = template.New("configTemplateRoot")
    39  	result.root.Funcs(template.FuncMap{
    40  		"env":       templateDisableEnv,
    41  		"pwd":       templatePwd,
    42  		"isotime":   templateISOTime,
    43  		"timestamp": templateTimestamp,
    44  		"user":      result.templateUser,
    45  		"uuid":      templateUuid,
    46  	})
    47  
    48  	return result, nil
    49  }
    50  
    51  // Process processes a single string, compiling and executing the template.
    52  func (t *ConfigTemplate) Process(s string, data interface{}) (string, error) {
    53  	tpl, err := t.root.New(t.nextTemplateName()).Parse(s)
    54  	if err != nil {
    55  		return "", err
    56  	}
    57  
    58  	buf := new(bytes.Buffer)
    59  	if err := tpl.Execute(buf, data); err != nil {
    60  		return "", err
    61  	}
    62  
    63  	return buf.String(), nil
    64  }
    65  
    66  // Validate the template.
    67  func (t *ConfigTemplate) Validate(s string) error {
    68  	root, err := t.root.Clone()
    69  	if err != nil {
    70  		return err
    71  	}
    72  
    73  	_, err = root.New("template").Parse(s)
    74  	return err
    75  }
    76  
    77  // Add additional functions to the template
    78  func (t *ConfigTemplate) Funcs(funcs template.FuncMap) {
    79  	t.root.Funcs(funcs)
    80  }
    81  
    82  func (t *ConfigTemplate) nextTemplateName() string {
    83  	name := fmt.Sprintf("tpl%d", t.i)
    84  	t.i++
    85  	return name
    86  }
    87  
    88  // User is the function exposed as "user" within the templates and
    89  // looks up user variables.
    90  func (t *ConfigTemplate) templateUser(n string) (string, error) {
    91  	result, ok := t.UserVars[n]
    92  	if !ok {
    93  		return "", fmt.Errorf("uknown user var: %s", n)
    94  	}
    95  
    96  	return result, nil
    97  }
    98  
    99  func templateDisableEnv(n string) (string, error) {
   100  	return "", fmt.Errorf(
   101  		"Environmental variables can only be used as default values for user variables.")
   102  }
   103  
   104  func templateDisableUser(n string) (string, error) {
   105  	return "", fmt.Errorf(
   106  		"User variable can't be used within a default value for a user variable: %s", n)
   107  }
   108  
   109  func templateEnv(n string) string {
   110  	return os.Getenv(n)
   111  }
   112  
   113  func templateISOTime() string {
   114  	return InitTime.Format(time.RFC3339)
   115  }
   116  
   117  func templatePwd() (string, error) {
   118  	return os.Getwd()
   119  }
   120  
   121  func templateTimestamp() string {
   122  	return strconv.FormatInt(InitTime.Unix(), 10)
   123  }
   124  
   125  func templateUuid() string {
   126  	return uuid.TimeOrderedUUID()
   127  }