-
Notifications
You must be signed in to change notification settings - Fork 26
/
asset.go
78 lines (75 loc) · 1.72 KB
/
asset.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
package template
import (
"bytes"
"encoding/hex"
"fmt"
"hash/fnv"
"io"
"io/ioutil"
"path"
"gnd.la/log"
"gnd.la/template/assets"
)
func executeAsset(t *Template, p *Template, vars VarMap, m *assets.Manager, asset *assets.Asset) (string, error) {
name := asset.TemplateName()
log.Debugf("executing asset template %s (from %s)", name, t.name)
tmpl := New(m.VFS(), nil)
tmpl.addFuncMap(t.funcMap, true)
if p != nil {
tmpl.addFuncMap(p.funcMap, true)
}
if err := tmpl.Parse(name); err != nil {
return "", err
}
if err := tmpl.Compile(); err != nil {
return "", err
}
if p != nil && p != t {
ns := t.namespaceIn(p)
if ns != "" {
vars = vars.unpack(ns)
}
}
var buf bytes.Buffer
if err := tmpl.ExecuteContext(&buf, nil, nil, vars); err != nil {
return "", err
}
f, err := m.Load(name)
if err != nil {
return "", err
}
h := fnv.New32a()
// Writing to a hash.Hash never fails
// Include the initial and the final
// asset in the hash.
io.Copy(h, f)
f.Close()
h.Write(buf.Bytes())
hash := hex.EncodeToString(h.Sum(nil))
ext := path.Ext(name)
nonExt := name[:len(name)-len(ext)]
out := fmt.Sprintf("%s.gen.%s%s", nonExt, hash, ext)
// Check if the file already exists and has the same
// contents. This prevents failures when runnin on
// App Engine, since writes are not allowed.
if prev, err := m.Load(out); err == nil {
defer prev.Close()
if data, err := ioutil.ReadAll(prev); err == nil {
if bytes.Equal(data, buf.Bytes()) {
// File already up to date
return out, nil
}
}
}
w, err := m.Create(out, true)
if err != nil {
return "", err
}
if _, err := w.Write(buf.Bytes()); err != nil {
return "", err
}
if err := w.Close(); err != nil {
return "", err
}
return out, nil
}