forked from hashicorp/otto
/
data.go
175 lines (145 loc) · 4.07 KB
/
data.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
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
package bindata
import (
"bytes"
"fmt"
"io"
"io/ioutil"
"log"
"os"
"path/filepath"
"strings"
"gopkg.in/flosch/pongo2.v3"
// Template helpers
_ "github.com/hashicorp/otto/helper/pongo2"
)
//go:generate go-bindata -o=bindata_test.go -pkg=bindata -nomemcopy -nometadata ./test-data/...
// Data is the struct that wraps the assets go-bindata generates in your
// package to provide more helpers.
type Data struct {
// Asset, AssetDir are functions used to look up the assets.
// These match the function signatures used by go-bindata so you
// can just use method handles for these.
Asset func(string) ([]byte, error)
AssetDir func(string) ([]string, error)
// Context is the template context that is given when rendering
Context map[string]interface{}
}
// CopyDir copies all the assets from the given prefix to the destination
// directory. It will automatically set file permissions, create folders,
// etc.
func (d *Data) CopyDir(dst, prefix string) error {
log.Printf("[DEBUG] Copying all assets: %s => %s", prefix, dst)
// Get all the assets in the directory
assets, err := d.AssetDir(prefix)
if err != nil {
return err
}
// If the destination directory doesn't exist, make that
if err := os.MkdirAll(dst, 0755); err != nil {
return err
}
// Go through each asset, and copy it into place
for _, asset := range assets {
log.Printf("[DEBUG] Copying asset: %s", asset)
// Load the asset bytes
assetFull := prefix + "/" + asset
data, err := d.Asset(assetFull)
if err != nil {
// Asset not found... check if it is a directory. If it is
// a directory, we recursively call CopyDir.
if _, err := d.AssetDir(assetFull); err != nil {
return fmt.Errorf("error loading asset %s: %s", asset, err)
}
if err := d.CopyDir(filepath.Join(dst, asset), assetFull); err != nil {
return err
}
continue
}
err = d.renderLowLevel(filepath.Join(dst, asset), asset, bytes.NewReader(data))
if err != nil {
return err
}
}
return nil
}
// RenderAsset renders a single bindata asset. This file
// will be processed as a template if it ends in ".tpl".
func (d *Data) RenderAsset(dst, src string) error {
data, err := d.Asset(src)
if err != nil {
return err
}
return d.renderLowLevel(dst, src, bytes.NewReader(data))
}
// RenderReal renders a real file (not a bindata'd file). This file
// will be processed as a template if it ends in ".tpl".
func (d *Data) RenderReal(dst, src string) error {
f, err := os.Open(src)
if err != nil {
return err
}
defer f.Close()
return d.renderLowLevel(dst, src, f)
}
// RenderString renders a string.
func (d *Data) RenderString(tpl string) (string, error) {
// Make a temporary file for the contents. This is kind of silly we
// need to do this but we can make this render in-memory later.
tf, err := ioutil.TempFile("", "otto")
if err != nil {
return "", err
}
tf.Close()
defer os.Remove(tf.Name())
// Render
err = d.renderLowLevel(tf.Name(), "dummy.tpl", strings.NewReader(tpl))
if err != nil {
return "", err
}
// Copy the file contents back into memory
var result bytes.Buffer
f, err := os.Open(tf.Name())
if err != nil {
return "", err
}
_, err = io.Copy(&result, f)
f.Close()
if err != nil {
return "", err
}
return result.String(), nil
}
func (d *Data) renderLowLevel(dst string, src string, r io.Reader) error {
var err error
// Determine the filename and whether we're dealing with a template
var tpl *pongo2.Template = nil
filename := src
if strings.HasSuffix(filename, ".tpl") {
var buf bytes.Buffer
if _, err := io.Copy(&buf, r); err != nil {
return err
}
dst = strings.TrimSuffix(dst, ".tpl")
tpl, err = pongo2.FromString(buf.String())
if err != nil {
return err
}
}
// Make the directory containing the final path.
dir := filepath.Dir(dst)
if err := os.MkdirAll(dir, 0755); err != nil {
return err
}
// Create the file itself
f, err := os.Create(dst)
if err != nil {
return err
}
defer f.Close()
// If it isn't a template, do a direct byte copy
if tpl == nil {
_, err = io.Copy(f, r)
return err
}
return tpl.ExecuteWriter(d.Context, f)
}