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