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