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 }