Commit 345b312e authored by Toby Allen's avatar Toby Allen Committed by GitHub

Merge branch 'master' into macros

parents 9ebc11d7 5cca9cc1
...@@ -68,8 +68,13 @@ type Config struct { ...@@ -68,8 +68,13 @@ type Config struct {
// Template(s) to render with // Template(s) to render with
Template *template.Template Template *template.Template
// a pair of template's name and its underlying file path // a pair of template's name and its underlying file information
TemplateFiles map[string]string TemplateFiles map[string]*cachedFileInfo
}
type cachedFileInfo struct {
path string
fi os.FileInfo
} }
// ServeHTTP implements the http.Handler interface. // ServeHTTP implements the http.Handler interface.
......
...@@ -62,7 +62,7 @@ func markdownParse(c *caddy.Controller) ([]*Config, error) { ...@@ -62,7 +62,7 @@ func markdownParse(c *caddy.Controller) ([]*Config, error) {
Extensions: make(map[string]struct{}), Extensions: make(map[string]struct{}),
Template: GetDefaultTemplate(), Template: GetDefaultTemplate(),
IndexFiles: []string{}, IndexFiles: []string{},
TemplateFiles: make(map[string]string), TemplateFiles: make(map[string]*cachedFileInfo),
} }
// Get the path scope // Get the path scope
...@@ -133,7 +133,9 @@ func loadParams(c *caddy.Controller, mdc *Config) error { ...@@ -133,7 +133,9 @@ func loadParams(c *caddy.Controller, mdc *Config) error {
return c.Errf("default template parse error: %v", err) return c.Errf("default template parse error: %v", err)
} }
mdc.TemplateFiles[""] = fpath mdc.TemplateFiles[""] = &cachedFileInfo{
path: fpath,
}
return nil return nil
case 2: case 2:
fpath := filepath.ToSlash(filepath.Clean(cfg.Root + string(filepath.Separator) + tArgs[1])) fpath := filepath.ToSlash(filepath.Clean(cfg.Root + string(filepath.Separator) + tArgs[1]))
...@@ -142,7 +144,9 @@ func loadParams(c *caddy.Controller, mdc *Config) error { ...@@ -142,7 +144,9 @@ func loadParams(c *caddy.Controller, mdc *Config) error {
return c.Errf("template parse error: %v", err) return c.Errf("template parse error: %v", err)
} }
mdc.TemplateFiles[tArgs[0]] = fpath mdc.TemplateFiles[tArgs[0]] = &cachedFileInfo{
path: fpath,
}
return nil return nil
} }
case "templatedir": case "templatedir":
...@@ -164,7 +168,9 @@ func loadParams(c *caddy.Controller, mdc *Config) error { ...@@ -164,7 +168,9 @@ func loadParams(c *caddy.Controller, mdc *Config) error {
return c.Errf("glob %q failed: %v", pattern, err) return c.Errf("glob %q failed: %v", pattern, err)
} }
for _, path := range paths { for _, path := range paths {
mdc.TemplateFiles[filepath.Base(path)] = path mdc.TemplateFiles[filepath.Base(path)] = &cachedFileInfo{
path: path,
}
} }
return nil return nil
default: default:
......
...@@ -77,7 +77,7 @@ func TestMarkdownParse(t *testing.T) { ...@@ -77,7 +77,7 @@ func TestMarkdownParse(t *testing.T) {
Styles: []string{"/resources/css/blog.css"}, Styles: []string{"/resources/css/blog.css"},
Scripts: []string{"/resources/js/blog.js"}, Scripts: []string{"/resources/js/blog.js"},
Template: GetDefaultTemplate(), Template: GetDefaultTemplate(),
TemplateFiles: make(map[string]string), TemplateFiles: make(map[string]*cachedFileInfo),
}}}, }}},
{`markdown /blog { {`markdown /blog {
ext .md ext .md
...@@ -88,8 +88,8 @@ func TestMarkdownParse(t *testing.T) { ...@@ -88,8 +88,8 @@ func TestMarkdownParse(t *testing.T) {
".md": {}, ".md": {},
}, },
Template: setDefaultTemplate("./testdata/tpl_with_include.html"), Template: setDefaultTemplate("./testdata/tpl_with_include.html"),
TemplateFiles: map[string]string{ TemplateFiles: map[string]*cachedFileInfo{
"": "testdata/tpl_with_include.html", "": {path: "testdata/tpl_with_include.html"},
}, },
}}}, }}},
} }
......
...@@ -17,6 +17,8 @@ package markdown ...@@ -17,6 +17,8 @@ package markdown
import ( import (
"bytes" "bytes"
"io/ioutil" "io/ioutil"
"os"
"sync"
"text/template" "text/template"
"github.com/mholt/caddy/caddyhttp/httpserver" "github.com/mholt/caddy/caddyhttp/httpserver"
...@@ -41,6 +43,8 @@ func (d Data) Include(filename string, args ...interface{}) (string, error) { ...@@ -41,6 +43,8 @@ func (d Data) Include(filename string, args ...interface{}) (string, error) {
return httpserver.ContextInclude(filename, d, d.Root) return httpserver.ContextInclude(filename, d, d.Root)
} }
var templateUpdateMu sync.RWMutex
// execTemplate executes a template given a requestPath, template, and metadata // execTemplate executes a template given a requestPath, template, and metadata
func execTemplate(c *Config, mdata metadata.Metadata, meta map[string]string, files []FileInfo, ctx httpserver.Context) ([]byte, error) { func execTemplate(c *Config, mdata metadata.Metadata, meta map[string]string, files []FileInfo, ctx httpserver.Context) ([]byte, error) {
mdData := Data{ mdData := Data{
...@@ -51,18 +55,43 @@ func execTemplate(c *Config, mdata metadata.Metadata, meta map[string]string, fi ...@@ -51,18 +55,43 @@ func execTemplate(c *Config, mdata metadata.Metadata, meta map[string]string, fi
Meta: meta, Meta: meta,
Files: files, Files: files,
} }
templateName := mdata.Template templateName := mdata.Template
// reload template on every request for now
// TODO: cache templates by a general plugin updateTemplate := func() error {
if templateFile, ok := c.TemplateFiles[templateName]; ok { templateUpdateMu.Lock()
err := SetTemplate(c.Template, templateName, templateFile) defer templateUpdateMu.Unlock()
templateFile, ok := c.TemplateFiles[templateName]
if !ok {
return nil
}
currentFileInfo, err := os.Lstat(templateFile.path)
if err != nil {
return err
}
if !fileChanged(currentFileInfo, templateFile.fi) {
return nil
}
// update template due to file changes
err = SetTemplate(c.Template, templateName, templateFile.path)
if err != nil { if err != nil {
return nil, err return err
} }
templateFile.fi = currentFileInfo
return nil
}
if err := updateTemplate(); err != nil {
return nil, err
} }
b := new(bytes.Buffer) b := new(bytes.Buffer)
templateUpdateMu.RLock()
defer templateUpdateMu.RUnlock()
if err := c.Template.ExecuteTemplate(b, templateName, mdData); err != nil { if err := c.Template.ExecuteTemplate(b, templateName, mdData); err != nil {
return nil, err return nil, err
} }
...@@ -70,6 +99,21 @@ func execTemplate(c *Config, mdata metadata.Metadata, meta map[string]string, fi ...@@ -70,6 +99,21 @@ func execTemplate(c *Config, mdata metadata.Metadata, meta map[string]string, fi
return b.Bytes(), nil return b.Bytes(), nil
} }
func fileChanged(new, old os.FileInfo) bool {
// never checked before
if old == nil {
return true
}
if new.Size() != old.Size() ||
new.Mode() != old.Mode() ||
new.ModTime() != old.ModTime() {
return true
}
return false
}
// SetTemplate reads in the template with the filename provided. If the file does not exist or is not parsable, it will return an error. // SetTemplate reads in the template with the filename provided. If the file does not exist or is not parsable, it will return an error.
func SetTemplate(t *template.Template, name, filename string) error { func SetTemplate(t *template.Template, name, filename string) error {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment