@@ -11,7 +11,6 @@ import (
11
11
"os"
12
12
"path"
13
13
"path/filepath"
14
- "reflect"
15
14
"sync"
16
15
"text/template"
17
16
"text/template/parse"
@@ -36,20 +35,18 @@ var escapeOK = fmt.Errorf("template escaped correctly")
36
35
37
36
// nameSpace is the data structure shared by all templates in an association.
38
37
type nameSpace struct {
39
- mu sync.RWMutex
38
+ mu sync.Mutex
40
39
set map [string ]* Template
41
40
escaped bool
42
41
esc escaper
43
- // The original functions, before wrapping.
44
- funcMap FuncMap
45
42
}
46
43
47
44
// Templates returns a slice of the templates associated with t, including t
48
45
// itself.
49
46
func (t * Template ) Templates () []* Template {
50
47
ns := t .nameSpace
51
- ns .mu .RLock ()
52
- defer ns .mu .RUnlock ()
48
+ ns .mu .Lock ()
49
+ defer ns .mu .Unlock ()
53
50
// Return a slice so we don't expose the map.
54
51
m := make ([]* Template , 0 , len (ns .set ))
55
52
for _ , v := range ns .set {
@@ -87,8 +84,8 @@ func (t *Template) checkCanParse() error {
87
84
if t == nil {
88
85
return nil
89
86
}
90
- t .nameSpace .mu .RLock ()
91
- defer t .nameSpace .mu .RUnlock ()
87
+ t .nameSpace .mu .Lock ()
88
+ defer t .nameSpace .mu .Unlock ()
92
89
if t .nameSpace .escaped {
93
90
return fmt .Errorf ("html/template: cannot Parse after Execute" )
94
91
}
@@ -97,16 +94,6 @@ func (t *Template) checkCanParse() error {
97
94
98
95
// escape escapes all associated templates.
99
96
func (t * Template ) escape () error {
100
- t .nameSpace .mu .RLock ()
101
- escapeErr := t .escapeErr
102
- t .nameSpace .mu .RUnlock ()
103
- if escapeErr != nil {
104
- if escapeErr == escapeOK {
105
- return nil
106
- }
107
- return escapeErr
108
- }
109
-
110
97
t .nameSpace .mu .Lock ()
111
98
defer t .nameSpace .mu .Unlock ()
112
99
t .nameSpace .escaped = true
@@ -134,8 +121,6 @@ func (t *Template) Execute(wr io.Writer, data interface{}) error {
134
121
if err := t .escape (); err != nil {
135
122
return err
136
123
}
137
- t .nameSpace .mu .RLock ()
138
- defer t .nameSpace .mu .RUnlock ()
139
124
return t .text .Execute (wr , data )
140
125
}
141
126
@@ -151,36 +136,20 @@ func (t *Template) ExecuteTemplate(wr io.Writer, name string, data interface{})
151
136
if err != nil {
152
137
return err
153
138
}
154
- t .nameSpace .mu .RLock ()
155
- defer t .nameSpace .mu .RUnlock ()
156
139
return tmpl .text .Execute (wr , data )
157
140
}
158
141
159
142
// lookupAndEscapeTemplate guarantees that the template with the given name
160
143
// is escaped, or returns an error if it cannot be. It returns the named
161
144
// template.
162
145
func (t * Template ) lookupAndEscapeTemplate (name string ) (tmpl * Template , err error ) {
163
- t .nameSpace .mu .RLock ()
146
+ t .nameSpace .mu .Lock ()
147
+ defer t .nameSpace .mu .Unlock ()
148
+ t .nameSpace .escaped = true
164
149
tmpl = t .set [name ]
165
- var escapeErr error
166
- if tmpl != nil {
167
- escapeErr = tmpl .escapeErr
168
- }
169
- t .nameSpace .mu .RUnlock ()
170
-
171
150
if tmpl == nil {
172
151
return nil , fmt .Errorf ("html/template: %q is undefined" , name )
173
152
}
174
- if escapeErr != nil {
175
- if escapeErr != escapeOK {
176
- return nil , escapeErr
177
- }
178
- return tmpl , nil
179
- }
180
-
181
- t .nameSpace .mu .Lock ()
182
- defer t .nameSpace .mu .Unlock ()
183
- t .nameSpace .escaped = true
184
153
if tmpl .escapeErr != nil && tmpl .escapeErr != escapeOK {
185
154
return nil , tmpl .escapeErr
186
155
}
@@ -286,13 +255,6 @@ func (t *Template) Clone() (*Template, error) {
286
255
}
287
256
ns := & nameSpace {set : make (map [string ]* Template )}
288
257
ns .esc = makeEscaper (ns )
289
- if t .nameSpace .funcMap != nil {
290
- ns .funcMap = make (FuncMap , len (t .nameSpace .funcMap ))
291
- for name , fn := range t .nameSpace .funcMap {
292
- ns .funcMap [name ] = fn
293
- }
294
- }
295
- wrapFuncs (ns , textClone , ns .funcMap )
296
258
ret := & Template {
297
259
nil ,
298
260
textClone ,
@@ -307,13 +269,12 @@ func (t *Template) Clone() (*Template, error) {
307
269
return nil , fmt .Errorf ("html/template: cannot Clone %q after it has executed" , t .Name ())
308
270
}
309
271
x .Tree = x .Tree .Copy ()
310
- tc : = & Template {
272
+ ret . set [ name ] = & Template {
311
273
nil ,
312
274
x ,
313
275
x .Tree ,
314
276
ret .nameSpace ,
315
277
}
316
- ret .set [name ] = tc
317
278
}
318
279
// Return the template associated with the name of this template.
319
280
return ret .set [ret .Name ()], nil
@@ -382,43 +343,10 @@ type FuncMap map[string]interface{}
382
343
// type. However, it is legal to overwrite elements of the map. The return
383
344
// value is the template, so calls can be chained.
384
345
func (t * Template ) Funcs (funcMap FuncMap ) * Template {
385
- t .nameSpace .mu .Lock ()
386
- if t .nameSpace .funcMap == nil {
387
- t .nameSpace .funcMap = make (FuncMap , len (funcMap ))
388
- }
389
- for name , fn := range funcMap {
390
- t .nameSpace .funcMap [name ] = fn
391
- }
392
- t .nameSpace .mu .Unlock ()
393
-
394
- wrapFuncs (t .nameSpace , t .text , funcMap )
346
+ t .text .Funcs (template .FuncMap (funcMap ))
395
347
return t
396
348
}
397
349
398
- // wrapFuncs records the functions with text/template. We wrap them to
399
- // unlock the nameSpace. See TestRecursiveExecute for a test case.
400
- func wrapFuncs (ns * nameSpace , textTemplate * template.Template , funcMap FuncMap ) {
401
- if len (funcMap ) == 0 {
402
- return
403
- }
404
- tfuncs := make (template.FuncMap , len (funcMap ))
405
- for name , fn := range funcMap {
406
- fnv := reflect .ValueOf (fn )
407
- wrapper := func (args []reflect.Value ) []reflect.Value {
408
- ns .mu .RUnlock ()
409
- defer ns .mu .RLock ()
410
- if fnv .Type ().IsVariadic () {
411
- return fnv .CallSlice (args )
412
- } else {
413
- return fnv .Call (args )
414
- }
415
- }
416
- wrapped := reflect .MakeFunc (fnv .Type (), wrapper )
417
- tfuncs [name ] = wrapped .Interface ()
418
- }
419
- textTemplate .Funcs (tfuncs )
420
- }
421
-
422
350
// Delims sets the action delimiters to the specified strings, to be used in
423
351
// subsequent calls to Parse, ParseFiles, or ParseGlob. Nested template
424
352
// definitions will inherit the settings. An empty delimiter stands for the
@@ -432,8 +360,8 @@ func (t *Template) Delims(left, right string) *Template {
432
360
// Lookup returns the template with the given name that is associated with t,
433
361
// or nil if there is no such template.
434
362
func (t * Template ) Lookup (name string ) * Template {
435
- t .nameSpace .mu .RLock ()
436
- defer t .nameSpace .mu .RUnlock ()
363
+ t .nameSpace .mu .Lock ()
364
+ defer t .nameSpace .mu .Unlock ()
437
365
return t .set [name ]
438
366
}
439
367
0 commit comments