github.com/StackPointCloud/packer@v0.10.2-0.20180716202532-b28098e0f79b/template/interpolate/funcs.go (about)

     1  package interpolate
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"os"
     7  	"path/filepath"
     8  	"strconv"
     9  	"strings"
    10  	"text/template"
    11  	"time"
    12  
    13  	"github.com/hashicorp/packer/common/uuid"
    14  	"github.com/hashicorp/packer/version"
    15  )
    16  
    17  // InitTime is the UTC time when this package was initialized. It is
    18  // used as the timestamp for all configuration templates so that they
    19  // match for a single build.
    20  var InitTime time.Time
    21  
    22  func init() {
    23  	InitTime = time.Now().UTC()
    24  }
    25  
    26  // Funcs are the interpolation funcs that are available within interpolations.
    27  var FuncGens = map[string]FuncGenerator{
    28  	"build_name":     funcGenBuildName,
    29  	"build_type":     funcGenBuildType,
    30  	"env":            funcGenEnv,
    31  	"isotime":        funcGenIsotime,
    32  	"pwd":            funcGenPwd,
    33  	"template_dir":   funcGenTemplateDir,
    34  	"timestamp":      funcGenTimestamp,
    35  	"uuid":           funcGenUuid,
    36  	"user":           funcGenUser,
    37  	"packer_version": funcGenPackerVersion,
    38  
    39  	"upper": funcGenPrimitive(strings.ToUpper),
    40  	"lower": funcGenPrimitive(strings.ToLower),
    41  }
    42  
    43  // FuncGenerator is a function that given a context generates a template
    44  // function for the template.
    45  type FuncGenerator func(*Context) interface{}
    46  
    47  // Funcs returns the functions that can be used for interpolation given
    48  // a context.
    49  func Funcs(ctx *Context) template.FuncMap {
    50  	result := make(map[string]interface{})
    51  	for k, v := range FuncGens {
    52  		result[k] = v(ctx)
    53  	}
    54  	if ctx != nil {
    55  		for k, v := range ctx.Funcs {
    56  			result[k] = v
    57  		}
    58  	}
    59  
    60  	return template.FuncMap(result)
    61  }
    62  
    63  func funcGenBuildName(ctx *Context) interface{} {
    64  	return func() (string, error) {
    65  		if ctx == nil || ctx.BuildName == "" {
    66  			return "", errors.New("build_name not available")
    67  		}
    68  
    69  		return ctx.BuildName, nil
    70  	}
    71  }
    72  
    73  func funcGenBuildType(ctx *Context) interface{} {
    74  	return func() (string, error) {
    75  		if ctx == nil || ctx.BuildType == "" {
    76  			return "", errors.New("build_type not available")
    77  		}
    78  
    79  		return ctx.BuildType, nil
    80  	}
    81  }
    82  
    83  func funcGenEnv(ctx *Context) interface{} {
    84  	return func(k string) (string, error) {
    85  		if !ctx.EnableEnv {
    86  			// The error message doesn't have to be that detailed since
    87  			// semantic checks should catch this.
    88  			return "", errors.New("env vars are not allowed here")
    89  		}
    90  
    91  		return os.Getenv(k), nil
    92  	}
    93  }
    94  
    95  func funcGenIsotime(ctx *Context) interface{} {
    96  	return func(format ...string) (string, error) {
    97  		if len(format) == 0 {
    98  			return InitTime.Format(time.RFC3339), nil
    99  		}
   100  
   101  		if len(format) > 1 {
   102  			return "", fmt.Errorf("too many values, 1 needed: %v", format)
   103  		}
   104  
   105  		return InitTime.Format(format[0]), nil
   106  	}
   107  }
   108  
   109  func funcGenPrimitive(value interface{}) FuncGenerator {
   110  	return func(ctx *Context) interface{} {
   111  		return value
   112  	}
   113  }
   114  
   115  func funcGenPwd(ctx *Context) interface{} {
   116  	return func() (string, error) {
   117  		return os.Getwd()
   118  	}
   119  }
   120  
   121  func funcGenTemplateDir(ctx *Context) interface{} {
   122  	return func() (string, error) {
   123  		if ctx == nil || ctx.TemplatePath == "" {
   124  			return "", errors.New("template path not available")
   125  		}
   126  
   127  		path, err := filepath.Abs(filepath.Dir(ctx.TemplatePath))
   128  		if err != nil {
   129  			return "", err
   130  		}
   131  
   132  		return path, nil
   133  	}
   134  }
   135  
   136  func funcGenTimestamp(ctx *Context) interface{} {
   137  	return func() string {
   138  		return strconv.FormatInt(InitTime.Unix(), 10)
   139  	}
   140  }
   141  
   142  func funcGenUser(ctx *Context) interface{} {
   143  	return func(k string) (string, error) {
   144  		if ctx == nil || ctx.UserVariables == nil {
   145  			return "", errors.New("test")
   146  		}
   147  
   148  		return ctx.UserVariables[k], nil
   149  	}
   150  }
   151  
   152  func funcGenUuid(ctx *Context) interface{} {
   153  	return func() string {
   154  		return uuid.TimeOrderedUUID()
   155  	}
   156  }
   157  
   158  func funcGenPackerVersion(ctx *Context) interface{} {
   159  	return func() string {
   160  		return version.FormattedVersion()
   161  	}
   162  }