mirror of
https://github.com/caddyserver/caddy.git
synced 2024-12-23 22:27:38 -05:00
Fix more tests, and fix template parsing.
This commit is contained in:
parent
027f697fdf
commit
42b7d57421
6 changed files with 160 additions and 102 deletions
|
@ -36,7 +36,7 @@ func markdownParse(c *Controller) ([]*markdown.Config, error) {
|
||||||
md := &markdown.Config{
|
md := &markdown.Config{
|
||||||
Renderer: blackfriday.HtmlRenderer(0, "", ""),
|
Renderer: blackfriday.HtmlRenderer(0, "", ""),
|
||||||
Extensions: make(map[string]struct{}),
|
Extensions: make(map[string]struct{}),
|
||||||
Templates: make(map[string]string),
|
Template: markdown.GetDefaultTemplate(),
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the path scope
|
// Get the path scope
|
||||||
|
@ -95,17 +95,32 @@ func loadParams(c *Controller, mdc *markdown.Config) error {
|
||||||
default:
|
default:
|
||||||
return c.ArgErr()
|
return c.ArgErr()
|
||||||
case 1:
|
case 1:
|
||||||
if _, ok := mdc.Templates[markdown.DefaultTemplate]; ok {
|
|
||||||
return c.Err("only one default template is allowed, use alias.")
|
|
||||||
}
|
|
||||||
fpath := filepath.ToSlash(filepath.Clean(c.Root + string(filepath.Separator) + tArgs[0]))
|
fpath := filepath.ToSlash(filepath.Clean(c.Root + string(filepath.Separator) + tArgs[0]))
|
||||||
mdc.Templates[markdown.DefaultTemplate] = fpath
|
|
||||||
|
if err := markdown.SetTemplate(mdc.Template, "", fpath); err != nil {
|
||||||
|
c.Errf("default template parse error: %v", err)
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
case 2:
|
case 2:
|
||||||
fpath := filepath.ToSlash(filepath.Clean(c.Root + string(filepath.Separator) + tArgs[1]))
|
fpath := filepath.ToSlash(filepath.Clean(c.Root + string(filepath.Separator) + tArgs[1]))
|
||||||
mdc.Templates[tArgs[0]] = fpath
|
|
||||||
|
if err := markdown.SetTemplate(mdc.Template, tArgs[0], fpath); err != nil {
|
||||||
|
c.Errf("template parse error: %v", err)
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
case "templatedir":
|
||||||
|
if !c.NextArg() {
|
||||||
|
return c.ArgErr()
|
||||||
|
}
|
||||||
|
_, err := mdc.Template.ParseGlob(c.Val())
|
||||||
|
if err != nil {
|
||||||
|
c.Errf("template load error: %v", err)
|
||||||
|
}
|
||||||
|
if c.NextArg() {
|
||||||
|
return c.ArgErr()
|
||||||
|
}
|
||||||
|
return nil
|
||||||
default:
|
default:
|
||||||
return c.Err("Expected valid markdown configuration property")
|
return c.Err("Expected valid markdown configuration property")
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,13 @@
|
||||||
package setup
|
package setup
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"net/http"
|
||||||
"testing"
|
"testing"
|
||||||
|
"text/template"
|
||||||
|
|
||||||
|
"github.com/mholt/caddy/middleware"
|
||||||
"github.com/mholt/caddy/middleware/markdown"
|
"github.com/mholt/caddy/middleware/markdown"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -58,8 +62,9 @@ func TestMarkdownParse(t *testing.T) {
|
||||||
".md": struct{}{},
|
".md": struct{}{},
|
||||||
".txt": struct{}{},
|
".txt": struct{}{},
|
||||||
},
|
},
|
||||||
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: markdown.GetDefaultTemplate(),
|
||||||
}}},
|
}}},
|
||||||
{`markdown /blog {
|
{`markdown /blog {
|
||||||
ext .md
|
ext .md
|
||||||
|
@ -69,9 +74,13 @@ func TestMarkdownParse(t *testing.T) {
|
||||||
Extensions: map[string]struct{}{
|
Extensions: map[string]struct{}{
|
||||||
".md": struct{}{},
|
".md": struct{}{},
|
||||||
},
|
},
|
||||||
Templates: map[string]string{markdown.DefaultTemplate: "testdata/tpl_with_include.html"},
|
Template: markdown.GetDefaultTemplate(),
|
||||||
}}},
|
}}},
|
||||||
}
|
}
|
||||||
|
// Setup the extra template
|
||||||
|
tmpl := tests[1].expectedMarkdownConfig[0].Template
|
||||||
|
markdown.SetTemplate(tmpl, "", "./testdata/tpl_with_include.html")
|
||||||
|
|
||||||
for i, test := range tests {
|
for i, test := range tests {
|
||||||
c := NewTestController(test.inputMarkdownConfig)
|
c := NewTestController(test.inputMarkdownConfig)
|
||||||
c.Root = "./testdata"
|
c.Root = "./testdata"
|
||||||
|
@ -101,11 +110,47 @@ func TestMarkdownParse(t *testing.T) {
|
||||||
t.Errorf("Test %d expected %dth Markdown Config Scripts to be %s , but got %s",
|
t.Errorf("Test %d expected %dth Markdown Config Scripts to be %s , but got %s",
|
||||||
i, j, fmt.Sprint(test.expectedMarkdownConfig[j].Scripts), fmt.Sprint(actualMarkdownConfig.Scripts))
|
i, j, fmt.Sprint(test.expectedMarkdownConfig[j].Scripts), fmt.Sprint(actualMarkdownConfig.Scripts))
|
||||||
}
|
}
|
||||||
if fmt.Sprint(actualMarkdownConfig.Templates) != fmt.Sprint(test.expectedMarkdownConfig[j].Templates) {
|
if ok, tx, ty := equalTemplates(actualMarkdownConfig.Template, test.expectedMarkdownConfig[j].Template); !ok {
|
||||||
t.Errorf("Test %d expected %dth Markdown Config Templates to be %s , but got %s",
|
t.Errorf("Test %d the %dth Markdown Config Templates did not match, expected %s to be %s", i, j, tx, ty)
|
||||||
i, j, fmt.Sprint(test.expectedMarkdownConfig[j].Templates), fmt.Sprint(actualMarkdownConfig.Templates))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func equalTemplates(i, j *template.Template) (bool, string, string) {
|
||||||
|
// Just in case :)
|
||||||
|
if i == j {
|
||||||
|
return true, "", ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// We can't do much here, templates can't really be compared. However,
|
||||||
|
// we can execute the templates and compare their outputs to be reasonably
|
||||||
|
// sure that they're the same.
|
||||||
|
|
||||||
|
// This is exceedingly ugly.
|
||||||
|
ctx := middleware.Context{
|
||||||
|
Root: http.Dir("./testdata"),
|
||||||
|
}
|
||||||
|
|
||||||
|
md := markdown.Data{
|
||||||
|
Context: ctx,
|
||||||
|
Doc: make(map[string]string),
|
||||||
|
DocFlags: make(map[string]bool),
|
||||||
|
Styles: []string{"style1"},
|
||||||
|
Scripts: []string{"js1"},
|
||||||
|
}
|
||||||
|
md.Doc["title"] = "some title"
|
||||||
|
md.Doc["body"] = "some body"
|
||||||
|
|
||||||
|
bufi := new(bytes.Buffer)
|
||||||
|
bufj := new(bytes.Buffer)
|
||||||
|
|
||||||
|
if err := i.Execute(bufi, md); err != nil {
|
||||||
|
return false, fmt.Sprintf("%v", err), ""
|
||||||
|
}
|
||||||
|
if err := j.Execute(bufj, md); err != nil {
|
||||||
|
return false, "", fmt.Sprintf("%v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return bytes.Equal(bufi.Bytes(), bufj.Bytes()), string(bufi.Bytes()), string(bufj.Bytes())
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,10 +4,10 @@ package markdown
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"log"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
|
"text/template"
|
||||||
|
|
||||||
"github.com/mholt/caddy/middleware"
|
"github.com/mholt/caddy/middleware"
|
||||||
"github.com/russross/blackfriday"
|
"github.com/russross/blackfriday"
|
||||||
|
@ -59,8 +59,8 @@ type Config struct {
|
||||||
// List of JavaScript files to load for each markdown file
|
// List of JavaScript files to load for each markdown file
|
||||||
Scripts []string
|
Scripts []string
|
||||||
|
|
||||||
// Map of registered templates
|
// Template(s) to render with
|
||||||
Templates map[string]string
|
Template *template.Template
|
||||||
}
|
}
|
||||||
|
|
||||||
// ServeHTTP implements the http.Handler interface.
|
// ServeHTTP implements the http.Handler interface.
|
||||||
|
|
|
@ -5,6 +5,7 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
"os"
|
"os"
|
||||||
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
@ -14,11 +15,15 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestMarkdown(t *testing.T) {
|
func TestMarkdown(t *testing.T) {
|
||||||
templates := make(map[string]string)
|
rootDir := "./testdata"
|
||||||
templates[DefaultTemplate] = "testdata/markdown_tpl.html"
|
|
||||||
|
f := func(filename string) string {
|
||||||
|
return filepath.ToSlash(rootDir + string(filepath.Separator) + filename)
|
||||||
|
}
|
||||||
|
|
||||||
md := Markdown{
|
md := Markdown{
|
||||||
Root: "./testdata",
|
Root: rootDir,
|
||||||
FileSys: http.Dir("./testdata"),
|
FileSys: http.Dir(rootDir),
|
||||||
Configs: []*Config{
|
Configs: []*Config{
|
||||||
{
|
{
|
||||||
Renderer: blackfriday.HtmlRenderer(0, "", ""),
|
Renderer: blackfriday.HtmlRenderer(0, "", ""),
|
||||||
|
@ -26,9 +31,9 @@ func TestMarkdown(t *testing.T) {
|
||||||
Extensions: map[string]struct{}{
|
Extensions: map[string]struct{}{
|
||||||
".md": struct{}{},
|
".md": struct{}{},
|
||||||
},
|
},
|
||||||
Styles: []string{},
|
Styles: []string{},
|
||||||
Scripts: []string{},
|
Scripts: []string{},
|
||||||
Templates: templates,
|
Template: setDefaultTemplate(f("markdown_tpl.html")),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Renderer: blackfriday.HtmlRenderer(0, "", ""),
|
Renderer: blackfriday.HtmlRenderer(0, "", ""),
|
||||||
|
@ -36,11 +41,9 @@ func TestMarkdown(t *testing.T) {
|
||||||
Extensions: map[string]struct{}{
|
Extensions: map[string]struct{}{
|
||||||
".md": struct{}{},
|
".md": struct{}{},
|
||||||
},
|
},
|
||||||
Styles: []string{},
|
Styles: []string{},
|
||||||
Scripts: []string{},
|
Scripts: []string{},
|
||||||
Templates: map[string]string{
|
Template: setDefaultTemplate(f("docflags/template.txt")),
|
||||||
DefaultTemplate: "testdata/docflags/template.txt",
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Renderer: blackfriday.HtmlRenderer(0, "", ""),
|
Renderer: blackfriday.HtmlRenderer(0, "", ""),
|
||||||
|
@ -48,9 +51,9 @@ func TestMarkdown(t *testing.T) {
|
||||||
Extensions: map[string]struct{}{
|
Extensions: map[string]struct{}{
|
||||||
".md": struct{}{},
|
".md": struct{}{},
|
||||||
},
|
},
|
||||||
Styles: []string{"/resources/css/log.css", "/resources/css/default.css"},
|
Styles: []string{"/resources/css/log.css", "/resources/css/default.css"},
|
||||||
Scripts: []string{"/resources/js/log.js", "/resources/js/default.js"},
|
Scripts: []string{"/resources/js/log.js", "/resources/js/default.js"},
|
||||||
Templates: make(map[string]string),
|
Template: GetDefaultTemplate(),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Renderer: blackfriday.HtmlRenderer(0, "", ""),
|
Renderer: blackfriday.HtmlRenderer(0, "", ""),
|
||||||
|
@ -58,9 +61,9 @@ func TestMarkdown(t *testing.T) {
|
||||||
Extensions: map[string]struct{}{
|
Extensions: map[string]struct{}{
|
||||||
".md": struct{}{},
|
".md": struct{}{},
|
||||||
},
|
},
|
||||||
Styles: []string{},
|
Styles: []string{},
|
||||||
Scripts: []string{},
|
Scripts: []string{},
|
||||||
Templates: templates,
|
Template: setDefaultTemplate(f("markdown_tpl.html")),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
IndexFiles: []string{"index.html"},
|
IndexFiles: []string{"index.html"},
|
||||||
|
@ -145,12 +148,10 @@ DocFlags.var_bool true`
|
||||||
<title>Markdown test 2</title>
|
<title>Markdown test 2</title>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<link rel="stylesheet" href="/resources/css/log.css">
|
<link rel="stylesheet" href="/resources/css/log.css">
|
||||||
<link rel="stylesheet" href="/resources/css/default.css">
|
<link rel="stylesheet" href="/resources/css/default.css">
|
||||||
|
|
||||||
<script src="/resources/js/log.js"></script>
|
<script src="/resources/js/log.js"></script>
|
||||||
<script src="/resources/js/default.js"></script>
|
<script src="/resources/js/default.js"></script>
|
||||||
|
</head>
|
||||||
</head>
|
|
||||||
<body>
|
<body>
|
||||||
<h2>Welcome on the blog</h2>
|
<h2>Welcome on the blog</h2>
|
||||||
|
|
||||||
|
|
|
@ -2,19 +2,12 @@ package markdown
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"io/ioutil"
|
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"text/template"
|
|
||||||
|
|
||||||
"github.com/mholt/caddy/middleware"
|
"github.com/mholt/caddy/middleware"
|
||||||
"github.com/russross/blackfriday"
|
"github.com/russross/blackfriday"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
|
||||||
// DefaultTemplate is the default template.
|
|
||||||
DefaultTemplate = "defaultTemplate"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Data represents a markdown document.
|
// Data represents a markdown document.
|
||||||
type Data struct {
|
type Data struct {
|
||||||
middleware.Context
|
middleware.Context
|
||||||
|
@ -52,24 +45,6 @@ func (md Markdown) Process(c *Config, requestPath string, b []byte, ctx middlewa
|
||||||
metadata = parser.Metadata()
|
metadata = parser.Metadata()
|
||||||
}
|
}
|
||||||
|
|
||||||
// if template is not specified, check if Default template is set
|
|
||||||
if metadata.Template == "" {
|
|
||||||
if _, ok := c.Templates[DefaultTemplate]; ok {
|
|
||||||
metadata.Template = DefaultTemplate
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// if template is set, load it
|
|
||||||
var tmpl []byte
|
|
||||||
if metadata.Template != "" {
|
|
||||||
if t, ok := c.Templates[metadata.Template]; ok {
|
|
||||||
tmpl, err = ioutil.ReadFile(t)
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// process markdown
|
// process markdown
|
||||||
extns := 0
|
extns := 0
|
||||||
extns |= blackfriday.EXTENSION_TABLES
|
extns |= blackfriday.EXTENSION_TABLES
|
||||||
|
@ -88,27 +63,12 @@ func (md Markdown) Process(c *Config, requestPath string, b []byte, ctx middlewa
|
||||||
}
|
}
|
||||||
metadata.Variables["title"] = title
|
metadata.Variables["title"] = title
|
||||||
|
|
||||||
return md.processTemplate(c, requestPath, tmpl, metadata, ctx)
|
// return md.processTemplate(c, requestPath, metadata, ctx)
|
||||||
|
return md.doTemplate(c, requestPath, metadata, ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
// processTemplate processes a template given a requestPath,
|
// doTemplate executes a template given a requestPath, template, and metadata
|
||||||
// template (tmpl) and metadata
|
func (md Markdown) doTemplate(c *Config, reqPath string, metadata Metadata, ctx middleware.Context) ([]byte, error) {
|
||||||
func (md Markdown) processTemplate(c *Config, requestPath string, tmpl []byte, metadata Metadata, ctx middleware.Context) ([]byte, error) {
|
|
||||||
var t *template.Template
|
|
||||||
var err error
|
|
||||||
|
|
||||||
// if template is not specified,
|
|
||||||
// use the default template
|
|
||||||
if tmpl == nil {
|
|
||||||
t = template.Must(template.New("").Parse(htmlTemplate))
|
|
||||||
} else {
|
|
||||||
t, err = template.New("").Parse(string(tmpl))
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// process the template
|
|
||||||
mdData := Data{
|
mdData := Data{
|
||||||
Context: ctx,
|
Context: ctx,
|
||||||
Doc: metadata.Variables,
|
Doc: metadata.Variables,
|
||||||
|
@ -118,27 +78,9 @@ func (md Markdown) processTemplate(c *Config, requestPath string, tmpl []byte, m
|
||||||
}
|
}
|
||||||
|
|
||||||
b := new(bytes.Buffer)
|
b := new(bytes.Buffer)
|
||||||
err = t.Execute(b, mdData)
|
if err := c.Template.ExecuteTemplate(b, metadata.Template, mdData); err != nil {
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return b.Bytes(), nil
|
return b.Bytes(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
|
||||||
htmlTemplate = `<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<title>{{.Doc.title}}</title>
|
|
||||||
<meta charset="utf-8">
|
|
||||||
{{range .Styles}}<link rel="stylesheet" href="{{.}}">
|
|
||||||
{{end -}}
|
|
||||||
{{range .Scripts}}<script src="{{.}}"></script>
|
|
||||||
{{end -}}
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
{{.Doc.body}}
|
|
||||||
</body>
|
|
||||||
</html>`
|
|
||||||
)
|
|
||||||
|
|
55
middleware/markdown/template.go
Normal file
55
middleware/markdown/template.go
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
package markdown
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io/ioutil"
|
||||||
|
"text/template"
|
||||||
|
)
|
||||||
|
|
||||||
|
func setDefaultTemplate(filename string) *template.Template {
|
||||||
|
buf, err := ioutil.ReadFile(filename)
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return template.Must(GetDefaultTemplate().Parse(string(buf)))
|
||||||
|
}
|
||||||
|
|
||||||
|
func SetTemplate(t *template.Template, name, filename string) error {
|
||||||
|
|
||||||
|
// Read template
|
||||||
|
buf, err := ioutil.ReadFile(filename)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update if exists
|
||||||
|
if tt := t.Lookup(name); tt != nil {
|
||||||
|
_, err = tt.Parse(string(buf))
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allocate new name if not
|
||||||
|
_, err = t.New(name).Parse(string(buf))
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetDefaultTemplate() *template.Template {
|
||||||
|
return template.Must(template.New("").Parse(defaultTemplate))
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
defaultTemplate = `<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>{{.Doc.title}}</title>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
{{range .Styles}}<link rel="stylesheet" href="{{.}}">
|
||||||
|
{{end -}}
|
||||||
|
{{range .Scripts}}<script src="{{.}}"></script>
|
||||||
|
{{end -}}
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
{{.Doc.body}}
|
||||||
|
</body>
|
||||||
|
</html>`
|
||||||
|
)
|
Loading…
Reference in a new issue