Ensure overcommit_memory=0
[iec.git] / src / foundation / api / revel / template_engine.go
1 package revel
2
3 import (
4         "bufio"
5         "bytes"
6         "errors"
7         "fmt"
8         "path/filepath"
9         "strings"
10 )
11
12 type TemplateEngine interface {
13         // prase template string and add template to the set.
14         ParseAndAdd(basePath *TemplateView) error
15
16         // returns Template corresponding to the given templateName, or nil
17         Lookup(templateName string) Template
18
19         // Fired by the template loader when events occur
20         Event(event Event, arg interface{})
21
22         // returns true if this engine should be used to parse the file specified in baseTemplate
23         Handles(templateView *TemplateView) bool
24
25         // returns the name of the engine
26         Name() string
27 }
28
29 // The template view information
30 type TemplateView struct {
31         TemplateName string // The name of the view
32         FilePath     string // The file path (view relative)
33         BasePath     string // The file system base path
34         FileBytes    []byte // The file loaded
35         EngineType   string // The name of the engine used to render the view
36 }
37
38 var templateLoaderMap = map[string]func(loader *TemplateLoader) (TemplateEngine, error){}
39
40 // Allow for templates to be registered during init but not initialized until application has been started
41 func RegisterTemplateLoader(key string, loader func(loader *TemplateLoader) (TemplateEngine, error)) (err error) {
42         if _, found := templateLoaderMap[key]; found {
43                 err = fmt.Errorf("Template loader %s already exists", key)
44         }
45         templateLog.Debug("Registered template engine loaded", "name", key)
46         templateLoaderMap[key] = loader
47         return
48 }
49
50 // Sets the template name from Config
51 // Sets the template API methods for parsing and storing templates before rendering
52 func (loader *TemplateLoader) CreateTemplateEngine(templateEngineName string) (TemplateEngine, error) {
53         if "" == templateEngineName {
54                 templateEngineName = GO_TEMPLATE
55         }
56         factory := templateLoaderMap[templateEngineName]
57         if nil == factory {
58                 fmt.Printf("registered factories %#v\n %s \n", templateLoaderMap, templateEngineName)
59                 return nil, errors.New("Unknown template engine name - " + templateEngineName + ".")
60         }
61         templateEngine, err := factory(loader)
62         if nil != err {
63                 return nil, errors.New("Failed to init template engine (" + templateEngineName + "), " + err.Error())
64         }
65
66         templateLog.Debug("CreateTemplateEngine: init templates", "name", templateEngineName)
67         return templateEngine, nil
68 }
69
70 // Passing in a comma delimited list of engine names to be used with this loader to parse the template files
71 func (loader *TemplateLoader) initializeEngines(runtimeLoader *templateRuntime, templateEngineNameList string) (err *Error) {
72         // Walk through the template loader's paths and build up a template set.
73         if templateEngineNameList == "" {
74                 templateEngineNameList = GO_TEMPLATE
75
76         }
77         runtimeLoader.templatesAndEngineList = []TemplateEngine{}
78         for _, engine := range strings.Split(templateEngineNameList, ",") {
79                 engine := strings.TrimSpace(strings.ToLower(engine))
80
81                 if templateLoader, err := loader.CreateTemplateEngine(engine); err != nil {
82                         runtimeLoader.compileError = &Error{
83                                 Title:       "Panic (Template Loader)",
84                                 Description: err.Error(),
85                         }
86                         return runtimeLoader.compileError
87                 } else {
88                         // Always assign a default engine, switch it if it is specified in the config
89                         runtimeLoader.templatesAndEngineList = append(runtimeLoader.templatesAndEngineList, templateLoader)
90                 }
91         }
92         return
93 }
94
95 func EngineHandles(engine TemplateEngine, templateView *TemplateView) bool {
96         if line, _, e := bufio.NewReader(bytes.NewBuffer(templateView.FileBytes)).ReadLine(); e == nil && string(line[:3]) == "#! " {
97                 // Extract the shebang and look at the rest of the line
98                 // #! pong2
99                 // #! go
100                 templateType := strings.TrimSpace(string(line[2:]))
101                 if engine.Name() == templateType {
102                         // Advance the read file bytes so it does not include the shebang
103                         templateView.FileBytes = templateView.FileBytes[len(line)+1:]
104                         templateView.EngineType = templateType
105                         return true
106                 }
107         }
108         filename := filepath.Base(templateView.FilePath)
109         bits := strings.Split(filename, ".")
110         if len(bits) > 2 {
111                 templateType := strings.TrimSpace(bits[len(bits)-2])
112                 if engine.Name() == templateType {
113                         templateView.EngineType = templateType
114                         return true
115                 }
116         }
117         return false
118 }