diff --git a/config/setup/markdown.go b/config/setup/markdown.go
index 8e296ef4f..bfe96300b 100644
--- a/config/setup/markdown.go
+++ b/config/setup/markdown.go
@@ -2,11 +2,12 @@ package setup
import (
"net/http"
+ "path"
+ "path/filepath"
"github.com/mholt/caddy/middleware"
"github.com/mholt/caddy/middleware/markdown"
"github.com/russross/blackfriday"
- "path/filepath"
)
// Markdown configures a new Markdown middleware instance.
@@ -37,6 +38,7 @@ func markdownParse(c *Controller) ([]markdown.Config, error) {
Renderer: blackfriday.HtmlRenderer(0, "", ""),
Templates: make(map[string]string),
StaticFiles: make(map[string]string),
+ StaticDir: path.Join(c.Root, markdown.StaticDir),
}
// Get the path scope
diff --git a/middleware/markdown/markdown.go b/middleware/markdown/markdown.go
index f4eab69e5..d7bdcc399 100644
--- a/middleware/markdown/markdown.go
+++ b/middleware/markdown/markdown.go
@@ -31,6 +31,16 @@ type Markdown struct {
IndexFiles []string
}
+// Helper function to check if a file is an index file
+func (m Markdown) IsIndexFile(file string) bool {
+ for _, f := range m.IndexFiles {
+ if f == file {
+ return true
+ }
+ }
+ return false
+}
+
// Config stores markdown middleware configurations.
type Config struct {
// Markdown renderer
@@ -53,6 +63,9 @@ type Config struct {
// Static files
StaticFiles map[string]string
+
+ // Static files directory
+ StaticDir string
}
// ServeHTTP implements the http.Handler interface.
@@ -77,18 +90,37 @@ func (md Markdown) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, error
return http.StatusNotFound, nil
}
+ fs, err := f.Stat()
+ if err != nil {
+ return http.StatusNotFound, nil
+ }
+
+ // if static site is generated, attempt to use it
+ if filepath, ok := m.StaticFiles[fpath]; ok {
+ if fs1, err := os.Stat(filepath); err == nil {
+ // if markdown has not been modified
+ // since static page generation,
+ // serve the static page
+ if fs.ModTime().UnixNano() < fs1.ModTime().UnixNano() {
+ if html, err := ioutil.ReadFile(filepath); err == nil {
+ w.Write(html)
+ return http.StatusOK, nil
+ }
+ }
+ }
+ }
+
body, err := ioutil.ReadAll(f)
if err != nil {
return http.StatusInternalServerError, err
}
- html, err := Process(md, fpath, body)
+ html, err := md.process(m, fpath, body)
if err != nil {
return http.StatusInternalServerError, err
}
- w.Write([]byte(html))
-
+ w.Write(html)
return http.StatusOK, nil
}
}
diff --git a/middleware/markdown/process.go b/middleware/markdown/process.go
index 207b87337..a9fa702a2 100644
--- a/middleware/markdown/process.go
+++ b/middleware/markdown/process.go
@@ -9,12 +9,19 @@ import (
"text/template"
"github.com/russross/blackfriday"
+ "log"
+ "os"
"strings"
)
-// Process the contents of a page.
+const (
+ DefaultTemplate = "defaultTemplate"
+ StaticDir = ".caddy_static"
+)
+
+// process the contents of a page.
// It parses the metadata if any and uses the template if found
-func Process(c Config, fpath string, b []byte) ([]byte, error) {
+func (md Markdown) process(c Config, fpath string, b []byte) ([]byte, error) {
metadata, markdown, err := extractMetadata(b)
if err != nil {
return nil, err
@@ -42,7 +49,7 @@ func Process(c Config, fpath string, b []byte) ([]byte, error) {
// set it as body for template
metadata.Variables["body"] = string(markdown)
- return processTemplate(c, fpath, tmpl, metadata)
+ return md.processTemplate(c, fpath, tmpl, metadata)
}
// extractMetadata extracts metadata content from a page.
@@ -104,7 +111,7 @@ func findParser(line []byte) MetadataParser {
return nil
}
-func processTemplate(c Config, fpath string, tmpl []byte, metadata Metadata) ([]byte, error) {
+func (md Markdown) processTemplate(c Config, fpath string, tmpl []byte, metadata Metadata) ([]byte, error) {
// if template is specified
// replace parse the template
if tmpl != nil {
@@ -119,6 +126,14 @@ func processTemplate(c Config, fpath string, tmpl []byte, metadata Metadata) ([]
if err = t.Execute(b, metadata.Variables); err != nil {
return nil, err
}
+
+ // generate static page
+ if err = md.generatePage(c, fpath, b.Bytes()); err != nil {
+ // if static page generation fails,
+ // nothing fatal, only log the error.
+ log.Println(err)
+ }
+
return b.Bytes(), nil
}
@@ -154,6 +169,42 @@ func defaultTemplate(c Config, metadata Metadata, fpath string) []byte {
return html
}
+func (md Markdown) generatePage(c Config, fpath string, content []byte) error {
+ // should not happen
+ // must be set on init
+ if c.StaticDir == "" {
+ return fmt.Errorf("Static directory not set")
+ }
+
+ // if static directory is not existing, create it
+ if _, err := os.Stat(c.StaticDir); err != nil {
+ err := os.MkdirAll(c.StaticDir, os.FileMode(0755))
+ if err != nil {
+ return err
+ }
+ }
+
+ filePath := filepath.Join(c.StaticDir, fpath)
+
+ // If it is index file, use the directory instead
+ if md.IsIndexFile(filepath.Base(fpath)) {
+ filePath, _ = filepath.Split(filePath)
+ }
+ if err := os.MkdirAll(filePath, os.FileMode(0755)); err != nil {
+ return err
+ }
+
+ // generate index.html file in the directory
+ filePath = filepath.Join(filePath, "index.html")
+ err := ioutil.WriteFile(filePath, content, os.FileMode(0755))
+ if err != nil {
+ return err
+ }
+
+ c.StaticFiles[fpath] = filePath
+ return nil
+}
+
const (
htmlTemplate = `
@@ -169,6 +220,4 @@ const (
`
cssTemplate = ``
jsTemplate = ``
-
- DefaultTemplate = "defaultTemplate"
)