-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathtpl.go
154 lines (124 loc) · 3.26 KB
/
tpl.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 tpl
import (
"fmt"
"html/template"
"io"
"io/ioutil"
"net/http"
"os"
"path/filepath"
"strings"
"github.com/oxtoacart/bpool"
)
// Templates is a map of all parsed templates.
type Templates map[string]*template.Template
// Must helper for Load()
func Must(t Templates, err error) Templates {
if err != nil {
panic(err)
}
return t
}
var bufPool = bpool.NewBufferPool(10)
// Render the template into a writer. Uses a buffer pool to not be inefficient.
func (t Templates) Render(w http.ResponseWriter, name string, data interface{}) error {
buf := bufPool.Get()
defer bufPool.Put(buf)
tmpl, ok := t[name]
if !ok {
return fmt.Errorf("Template named: %s does not exist", name)
}
err := tmpl.ExecuteTemplate(buf, "", data)
if err != nil {
return err
}
w.Header().Set("Content-Type", "text/html")
w.WriteHeader(http.StatusOK)
_, err = io.Copy(w, buf)
return err
}
// Load .tpl template files from dir, using layout as a base. Panics on
// failure to parse/load anything.
func Load(dir, partialDir, layout string, funcs template.FuncMap) (Templates, error) {
tpls := make(Templates)
b, err := ioutil.ReadFile(filepath.Join(dir, layout))
if err != nil {
return nil, fmt.Errorf("Could not load layout: %v", err)
}
layoutTpl, err := template.New("").Funcs(funcs).Parse(string(b))
if err != nil {
return nil, fmt.Errorf("Failed to parse layout: %v", err)
}
err = filepath.Walk(partialDir, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if info.IsDir() {
return nil
}
if !strings.HasPrefix(filepath.Base(path), "_") {
return nil
}
rel, err := filepath.Rel(dir, path)
if err != nil {
return fmt.Errorf("Could not create relative path: %v", err)
}
name := removeExtension(filepath.Base(rel))
b, err := ioutil.ReadFile(path)
if err != nil {
return fmt.Errorf("Failed to load partial (%s): %v", rel, err)
}
_, err = layoutTpl.New(name).Parse(string(b))
if err != nil {
return fmt.Errorf("Failed to parse partial: (%s): %v", rel, err)
}
return nil
})
if err != nil && !os.IsNotExist(err) {
return nil, fmt.Errorf("Failed to load partials: %v", err)
}
err = filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if info.IsDir() {
return nil
}
if path == filepath.Join(dir, layout) || strings.HasPrefix(filepath.Base(path), "_") {
return nil
}
if err != nil {
return fmt.Errorf("Could not walk directory: %v", err)
}
rel, err := filepath.Rel(dir, path)
if err != nil {
return fmt.Errorf("Could not create relative path: %v", err)
}
name := removeExtension(rel)
b, err := ioutil.ReadFile(path)
if err != nil {
return fmt.Errorf("Failed to load template (%s): %v", rel, err)
}
clone, err := layoutTpl.Clone()
if err != nil {
return fmt.Errorf("Failed to clone layout: %v", err)
}
t, err := clone.New("yield").Parse(string(b))
if err != nil {
return fmt.Errorf("Failed to parse template (%s): %v", rel, err)
}
tpls[name] = t
return nil
})
if err != nil {
return nil, fmt.Errorf("Failed to load templates: %v", err)
}
return tpls, nil
}
func removeExtension(path string) string {
dot := strings.Index(path, ".")
if dot >= 0 {
return path[:dot]
}
return path
}