1
0
mirror of https://github.com/astaxie/beego.git synced 2024-07-01 00:24:12 +00:00

Merge pull request #1727 from JessonChan/templates_bug_fix

lock the templates map when goroutie update the map
This commit is contained in:
astaxie 2016-02-26 15:56:47 +08:00
commit f0a41f978f

View File

@ -23,6 +23,7 @@ import (
"path/filepath" "path/filepath"
"regexp" "regexp"
"strings" "strings"
"sync"
"github.com/astaxie/beego/utils" "github.com/astaxie/beego/utils"
) )
@ -30,7 +31,8 @@ import (
var ( var (
beegoTplFuncMap = make(template.FuncMap) beegoTplFuncMap = make(template.FuncMap)
// BeeTemplates caching map and supported template file extensions. // BeeTemplates caching map and supported template file extensions.
BeeTemplates = make(map[string]*template.Template) BeeTemplates = make(map[string]*template.Template)
templatesLock sync.Mutex
// BeeTemplateExt stores the template extension which will build // BeeTemplateExt stores the template extension which will build
BeeTemplateExt = []string{"tpl", "html"} BeeTemplateExt = []string{"tpl", "html"}
) )
@ -66,17 +68,21 @@ func init() {
} }
// AddFuncMap let user to register a func in the template. // AddFuncMap let user to register a func in the template.
func AddFuncMap(key string, funname interface{}) error { func AddFuncMap(key string, fn interface{}) error {
beegoTplFuncMap[key] = funname beegoTplFuncMap[key] = fn
return nil return nil
} }
type templatefile struct { type templateFile struct {
root string root string
files map[string][]string files map[string][]string
} }
func (tf *templatefile) visit(paths string, f os.FileInfo, err error) error { // visit will make the paths into two part,the first is subDir (without tf.root),the second is full path(without tf.root).
// if tf.root="views" and
// paths is "views/errors/404.html",the subDir will be "errors",the file will be "errors/404.html"
// paths is "views/admin/errors/404.html",the subDir will be "admin/errors",the file will be "admin/errors/404.html"
func (tf *templateFile) visit(paths string, f os.FileInfo, err error) error {
if f == nil { if f == nil {
return err return err
} }
@ -88,18 +94,10 @@ func (tf *templatefile) visit(paths string, f os.FileInfo, err error) error {
} }
replace := strings.NewReplacer("\\", "/") replace := strings.NewReplacer("\\", "/")
a := []byte(paths) file := strings.TrimLeft(replace.Replace(paths[len(tf.root):]), "/")
a = a[len([]byte(tf.root)):] subDir := filepath.Dir(file)
file := strings.TrimLeft(replace.Replace(string(a)), "/")
subdir := filepath.Dir(file)
if _, ok := tf.files[subdir]; ok {
tf.files[subdir] = append(tf.files[subdir], file)
} else {
m := make([]string, 1)
m[0] = file
tf.files[subdir] = m
}
tf.files[subDir] = append(tf.files[subDir], file)
return nil return nil
} }
@ -132,7 +130,7 @@ func BuildTemplate(dir string, files ...string) error {
} }
return errors.New("dir open err") return errors.New("dir open err")
} }
self := &templatefile{ self := &templateFile{
root: dir, root: dir,
files: make(map[string][]string), files: make(map[string][]string),
} }
@ -146,12 +144,14 @@ func BuildTemplate(dir string, files ...string) error {
for _, v := range self.files { for _, v := range self.files {
for _, file := range v { for _, file := range v {
if len(files) == 0 || utils.InSlice(file, files) { if len(files) == 0 || utils.InSlice(file, files) {
templatesLock.Lock()
t, err := getTemplate(self.root, file, v...) t, err := getTemplate(self.root, file, v...)
if err != nil { if err != nil {
Trace("parse template err:", file, err) Trace("parse template err:", file, err)
} else { } else {
BeeTemplates[file] = t BeeTemplates[file] = t
} }
templatesLock.Unlock()
} }
} }
} }
@ -159,16 +159,16 @@ func BuildTemplate(dir string, files ...string) error {
} }
func getTplDeep(root, file, parent string, t *template.Template) (*template.Template, [][]string, error) { func getTplDeep(root, file, parent string, t *template.Template) (*template.Template, [][]string, error) {
var fileabspath string var fileAbsPath string
if filepath.HasPrefix(file, "../") { if filepath.HasPrefix(file, "../") {
fileabspath = filepath.Join(root, filepath.Dir(parent), file) fileAbsPath = filepath.Join(root, filepath.Dir(parent), file)
} else { } else {
fileabspath = filepath.Join(root, file) fileAbsPath = filepath.Join(root, file)
} }
if e := utils.FileExists(fileabspath); !e { if e := utils.FileExists(fileAbsPath); !e {
panic("can't find template file:" + file) panic("can't find template file:" + file)
} }
data, err := ioutil.ReadFile(fileabspath) data, err := ioutil.ReadFile(fileAbsPath)
if err != nil { if err != nil {
return nil, [][]string{}, err return nil, [][]string{}, err
} }
@ -177,11 +177,11 @@ func getTplDeep(root, file, parent string, t *template.Template) (*template.Temp
return nil, [][]string{}, err return nil, [][]string{}, err
} }
reg := regexp.MustCompile(BConfig.WebConfig.TemplateLeft + "[ ]*template[ ]+\"([^\"]+)\"") reg := regexp.MustCompile(BConfig.WebConfig.TemplateLeft + "[ ]*template[ ]+\"([^\"]+)\"")
allsub := reg.FindAllStringSubmatch(string(data), -1) allSub := reg.FindAllStringSubmatch(string(data), -1)
for _, m := range allsub { for _, m := range allSub {
if len(m) == 2 { if len(m) == 2 {
tlook := t.Lookup(m[1]) tl := t.Lookup(m[1])
if tlook != nil { if tl != nil {
continue continue
} }
if !HasTemplateExt(m[1]) { if !HasTemplateExt(m[1]) {
@ -193,17 +193,17 @@ func getTplDeep(root, file, parent string, t *template.Template) (*template.Temp
} }
} }
} }
return t, allsub, nil return t, allSub, nil
} }
func getTemplate(root, file string, others ...string) (t *template.Template, err error) { func getTemplate(root, file string, others ...string) (t *template.Template, err error) {
t = template.New(file).Delims(BConfig.WebConfig.TemplateLeft, BConfig.WebConfig.TemplateRight).Funcs(beegoTplFuncMap) t = template.New(file).Delims(BConfig.WebConfig.TemplateLeft, BConfig.WebConfig.TemplateRight).Funcs(beegoTplFuncMap)
var submods [][]string var subMods [][]string
t, submods, err = getTplDeep(root, file, "", t) t, subMods, err = getTplDeep(root, file, "", t)
if err != nil { if err != nil {
return nil, err return nil, err
} }
t, err = _getTemplate(t, root, submods, others...) t, err = _getTemplate(t, root, subMods, others...)
if err != nil { if err != nil {
return nil, err return nil, err
@ -211,44 +211,44 @@ func getTemplate(root, file string, others ...string) (t *template.Template, err
return return
} }
func _getTemplate(t0 *template.Template, root string, submods [][]string, others ...string) (t *template.Template, err error) { func _getTemplate(t0 *template.Template, root string, subMods [][]string, others ...string) (t *template.Template, err error) {
t = t0 t = t0
for _, m := range submods { for _, m := range subMods {
if len(m) == 2 { if len(m) == 2 {
templ := t.Lookup(m[1]) tpl := t.Lookup(m[1])
if templ != nil { if tpl != nil {
continue continue
} }
//first check filename //first check filename
for _, otherfile := range others { for _, otherFile := range others {
if otherfile == m[1] { if otherFile == m[1] {
var submods1 [][]string var subMods1 [][]string
t, submods1, err = getTplDeep(root, otherfile, "", t) t, subMods1, err = getTplDeep(root, otherFile, "", t)
if err != nil { if err != nil {
Trace("template parse file err:", err) Trace("template parse file err:", err)
} else if submods1 != nil && len(submods1) > 0 { } else if subMods1 != nil && len(subMods1) > 0 {
t, err = _getTemplate(t, root, submods1, others...) t, err = _getTemplate(t, root, subMods1, others...)
} }
break break
} }
} }
//second check define //second check define
for _, otherfile := range others { for _, otherFile := range others {
fileabspath := filepath.Join(root, otherfile) fileAbsPath := filepath.Join(root, otherFile)
data, err := ioutil.ReadFile(fileabspath) data, err := ioutil.ReadFile(fileAbsPath)
if err != nil { if err != nil {
continue continue
} }
reg := regexp.MustCompile(BConfig.WebConfig.TemplateLeft + "[ ]*define[ ]+\"([^\"]+)\"") reg := regexp.MustCompile(BConfig.WebConfig.TemplateLeft + "[ ]*define[ ]+\"([^\"]+)\"")
allsub := reg.FindAllStringSubmatch(string(data), -1) allSub := reg.FindAllStringSubmatch(string(data), -1)
for _, sub := range allsub { for _, sub := range allSub {
if len(sub) == 2 && sub[1] == m[1] { if len(sub) == 2 && sub[1] == m[1] {
var submods1 [][]string var subMods1 [][]string
t, submods1, err = getTplDeep(root, otherfile, "", t) t, subMods1, err = getTplDeep(root, otherFile, "", t)
if err != nil { if err != nil {
Trace("template parse file err:", err) Trace("template parse file err:", err)
} else if submods1 != nil && len(submods1) > 0 { } else if subMods1 != nil && len(subMods1) > 0 {
t, err = _getTemplate(t, root, submods1, others...) t, err = _getTemplate(t, root, subMods1, others...)
} }
break break
} }