diff --git a/caddyhttp/markdown/markdown.go b/caddyhttp/markdown/markdown.go index 27e60b03c..12c2ec61b 100644 --- a/caddyhttp/markdown/markdown.go +++ b/caddyhttp/markdown/markdown.go @@ -53,6 +53,9 @@ type Config struct { // Template(s) to render with Template *template.Template + + // a pair of template's name and its underlying file path + TemplateFiles map[string]string } // ServeHTTP implements the http.Handler interface. diff --git a/caddyhttp/markdown/markdown_test.go b/caddyhttp/markdown/markdown_test.go index 658da51e9..94827d809 100644 --- a/caddyhttp/markdown/markdown_test.go +++ b/caddyhttp/markdown/markdown_test.go @@ -4,10 +4,12 @@ import ( "io/ioutil" "net/http" "net/http/httptest" + "os" "path/filepath" "testing" "text/template" + "github.com/mholt/caddy" "github.com/mholt/caddy/caddyhttp/httpserver" "github.com/russross/blackfriday" ) @@ -127,7 +129,7 @@ Doc.var_bool true Markdown test 2 - + @@ -178,3 +180,68 @@ func setDefaultTemplate(filename string) *template.Template { return template.Must(GetDefaultTemplate().Parse(string(buf))) } + +func TestTemplateReload(t *testing.T) { + const ( + templateFile = "testdata/test.html" + targetFile = "testdata/hello.md" + ) + c := caddy.NewTestController("http", `markdown { + template `+templateFile+` + }`) + + err := ioutil.WriteFile(templateFile, []byte("hello {{.Doc.body}}"), 0644) + if err != nil { + t.Fatal(err) + } + err = ioutil.WriteFile(targetFile, []byte("caddy"), 0644) + if err != nil { + t.Fatal(err) + } + defer func() { + os.Remove(templateFile) + os.Remove(targetFile) + }() + + config, err := markdownParse(c) + if err != nil { + t.Fatal(err) + } + md := Markdown{ + Root: "./testdata", + FileSys: http.Dir("./testdata"), + Configs: config, + Next: httpserver.HandlerFunc(func(w http.ResponseWriter, r *http.Request) (int, error) { + t.Fatalf("Next shouldn't be called") + return 0, nil + }), + } + + req := httptest.NewRequest("GET", "/hello.md", nil) + get := func() string { + rec := httptest.NewRecorder() + code, err := md.ServeHTTP(rec, req) + if err != nil { + t.Fatal(err) + } + if code != http.StatusOK { + t.Fatalf("Wrong status, expected: %d and got %d", http.StatusOK, code) + } + return rec.Body.String() + } + + if expect, got := "hello

caddy

\n", get(); expect != got { + t.Fatalf("Expected body:\n%q\nbut got:\n%q", expect, got) + } + + // update template + err = ioutil.WriteFile(templateFile, []byte("hi {{.Doc.body}}"), 0644) + if err != nil { + t.Fatal(err) + } + + if expect, got := "hi

caddy

\n", get(); expect != got { + t.Fatalf("Expected body:\n%q\nbut got:\n%q", expect, got) + } + +} diff --git a/caddyhttp/markdown/setup.go b/caddyhttp/markdown/setup.go index 3117062c1..8792f85bc 100644 --- a/caddyhttp/markdown/setup.go +++ b/caddyhttp/markdown/setup.go @@ -44,10 +44,11 @@ func markdownParse(c *caddy.Controller) ([]*Config, error) { for c.Next() { md := &Config{ - Renderer: blackfriday.HtmlRenderer(0, "", ""), - Extensions: make(map[string]struct{}), - Template: GetDefaultTemplate(), - IndexFiles: []string{}, + Renderer: blackfriday.HtmlRenderer(0, "", ""), + Extensions: make(map[string]struct{}), + Template: GetDefaultTemplate(), + IndexFiles: []string{}, + TemplateFiles: make(map[string]string), } // Get the path scope @@ -118,6 +119,7 @@ func loadParams(c *caddy.Controller, mdc *Config) error { return c.Errf("default template parse error: %v", err) } + mdc.TemplateFiles[""] = fpath return nil case 2: fpath := filepath.ToSlash(filepath.Clean(cfg.Root + string(filepath.Separator) + tArgs[1])) @@ -126,13 +128,16 @@ func loadParams(c *caddy.Controller, mdc *Config) error { return c.Errf("template parse error: %v", err) } + mdc.TemplateFiles[tArgs[0]] = fpath return nil } case "templatedir": if !c.NextArg() { return c.ArgErr() } - _, err := mdc.Template.ParseGlob(c.Val()) + + pattern := c.Val() + _, err := mdc.Template.ParseGlob(pattern) if err != nil { return c.Errf("template load error: %v", err) } @@ -140,6 +145,13 @@ func loadParams(c *caddy.Controller, mdc *Config) error { return c.ArgErr() } + paths, err := filepath.Glob(pattern) + if err != nil { + return c.Errf("glob %q failed: %v", pattern, err) + } + for _, path := range paths { + mdc.TemplateFiles[filepath.Base(path)] = path + } return nil default: return c.Err("Expected valid markdown configuration property") diff --git a/caddyhttp/markdown/setup_test.go b/caddyhttp/markdown/setup_test.go index 745337b63..596ad84d2 100644 --- a/caddyhttp/markdown/setup_test.go +++ b/caddyhttp/markdown/setup_test.go @@ -4,6 +4,7 @@ import ( "bytes" "fmt" "net/http" + "reflect" "testing" "text/template" @@ -59,9 +60,10 @@ func TestMarkdownParse(t *testing.T) { ".md": {}, ".txt": {}, }, - Styles: []string{"/resources/css/blog.css"}, - Scripts: []string{"/resources/js/blog.js"}, - Template: GetDefaultTemplate(), + Styles: []string{"/resources/css/blog.css"}, + Scripts: []string{"/resources/js/blog.js"}, + Template: GetDefaultTemplate(), + TemplateFiles: make(map[string]string), }}}, {`markdown /blog { ext .md @@ -72,6 +74,9 @@ func TestMarkdownParse(t *testing.T) { ".md": {}, }, Template: setDefaultTemplate("./testdata/tpl_with_include.html"), + TemplateFiles: map[string]string{ + "": "testdata/tpl_with_include.html", + }, }}}, } @@ -107,6 +112,10 @@ func TestMarkdownParse(t *testing.T) { if ok, tx, ty := equalTemplates(actualMarkdownConfig.Template, test.expectedMarkdownConfig[j].Template); !ok { t.Errorf("Test %d the %dth Markdown Config Templates did not match, expected %s to be %s", i, j, tx, ty) } + if expect, got := test.expectedMarkdownConfig[j].TemplateFiles, actualMarkdownConfig.TemplateFiles; !reflect.DeepEqual(expect, got) { + t.Errorf("Test %d the %d Markdown config TemplateFiles did not match, expect %v, but got %v", i, j, expect, got) + } + } } } diff --git a/caddyhttp/markdown/template.go b/caddyhttp/markdown/template.go index 639f06fed..b21e59849 100644 --- a/caddyhttp/markdown/template.go +++ b/caddyhttp/markdown/template.go @@ -38,8 +38,18 @@ func execTemplate(c *Config, mdata metadata.Metadata, meta map[string]string, fi Files: files, } + templateName := mdata.Template + // reload template on every request for now + // TODO: cache templates by a general plugin + if templateFile, ok := c.TemplateFiles[templateName]; ok { + err := SetTemplate(c.Template, templateName, templateFile) + if err != nil { + return nil, err + } + } + b := new(bytes.Buffer) - if err := c.Template.ExecuteTemplate(b, mdata.Template, mdData); err != nil { + if err := c.Template.ExecuteTemplate(b, templateName, mdData); err != nil { return nil, err }