WIP Bindata stuff

bindata
Noah 2020-10-28 18:56:09 -07:00
parent 445fffdf2b
commit 6a36c0ed76
5 changed files with 141 additions and 37 deletions

View File

@ -18,6 +18,14 @@ build:
gofmt -w .
go build $(LDFLAGS) -i -o bin/blog cmd/blog/main.go
# `make bindata` to make the bindata module.
# `make bindata-dev` for debug mode module for editing files locally.
.PHONY: bindata bindata-dev
bindata:
go-bindata -pkg root -prefix root/ -o src/root/bundle.go root/...
bindata-dev:
go-bindata -debug -pkg root -prefix root/ -o src/root/bundle.go root/...
# `make run` to run it in debug mode.
.PHONY: run
run:

View File

@ -3,7 +3,9 @@ package blog
import (
"html/template"
"io/ioutil"
"mime"
"net/http"
"path/filepath"
"strings"
"github.com/kirsle/blog/src/controllers/posts"
@ -11,6 +13,7 @@ import (
"github.com/kirsle/blog/src/markdown"
"github.com/kirsle/blog/src/render"
"github.com/kirsle/blog/src/responses"
"github.com/kirsle/blog/src/root"
)
// PageHandler is the catch-all route handler, for serving static web pages.
@ -31,7 +34,7 @@ func (b *Blog) PageHandler(w http.ResponseWriter, r *http.Request) {
}
// Search for a file that matches their URL.
filepath, err := render.ResolvePath(path)
fp, err := render.ResolvePath(path)
if err != nil {
// See if it resolves as a blog entry.
err = postctl.ViewPost(w, r, strings.TrimLeft(path, "/"))
@ -43,17 +46,30 @@ func (b *Blog) PageHandler(w http.ResponseWriter, r *http.Request) {
}
// Is it a template file?
if strings.HasSuffix(filepath.URI, ".gohtml") {
render.Template(w, r, filepath.URI, nil)
if strings.HasSuffix(fp.URI, ".gohtml") {
render.Template(w, r, fp.URI, nil)
return
}
// Is it a Markdown file?
if strings.HasSuffix(filepath.URI, ".md") || strings.HasSuffix(filepath.URI, ".markdown") {
source, err := ioutil.ReadFile(filepath.Absolute)
if err != nil {
responses.Error(w, r, "Couldn't read Markdown source!")
return
if strings.HasSuffix(fp.URI, ".md") || strings.HasSuffix(fp.URI, ".markdown") {
var source []byte
if len(fp.BindataKey) > 0 {
data, err := root.Asset(fp.BindataKey)
if err != nil {
responses.Error(w, r, "Couldn't read bindata key: "+fp.BindataKey)
return
}
source = data
} else {
data, err := ioutil.ReadFile(fp.Absolute)
if err != nil {
responses.Error(w, r, "Couldn't read Markdown source!")
return
}
source = data
}
// Render it to HTML and find out its title.
@ -64,10 +80,22 @@ func (b *Blog) PageHandler(w http.ResponseWriter, r *http.Request) {
render.Template(w, r, ".markdown", map[string]interface{}{
"Title": title,
"HTML": template.HTML(html),
"MarkdownPath": filepath.URI,
"MarkdownPath": fp.URI,
})
return
}
http.ServeFile(w, r, filepath.Absolute)
// It's a regular static file we can serve directly.
{
// Check if we have bindata for it.
if fp.BindataKey != "" {
data, _ := root.Asset(fp.BindataKey)
w.Header().Set("Content-Type", mime.TypeByExtension(filepath.Ext(fp.URI)))
w.Write(data)
return
}
// Try the filesystem.
http.ServeFile(w, r, fp.Absolute)
}
}

View File

@ -8,11 +8,12 @@ import (
"net/url"
"strings"
"github.com/kirsle/blog/models/comments"
"github.com/kirsle/blog/models/settings"
"github.com/kirsle/blog/src/log"
"github.com/kirsle/blog/src/markdown"
"github.com/kirsle/blog/src/render"
"github.com/kirsle/blog/models/comments"
"github.com/kirsle/blog/models/settings"
"github.com/kirsle/blog/src/root"
"github.com/microcosm-cc/bluemonday"
gomail "gopkg.in/gomail.v2"
)
@ -51,10 +52,21 @@ func SendEmail(email Email) {
// Render the template to HTML.
var html bytes.Buffer
t := template.New(tmpl.Basename)
t, err = template.ParseFiles(tmpl.Absolute)
// Load it from bindata or filesystem.
if tmpl.BindataKey != "" {
log.Debug("Parse %s from bindata", tmpl.BindataKey)
asset, _ := root.Asset(tmpl.BindataKey)
t, err = t.Parse(string(asset))
} else {
log.Debug("Parse %s from file", tmpl.Absolute)
t, err = t.ParseFiles(tmpl.Absolute)
}
if err != nil {
log.Error("SendEmail: template parsing error: %s", err.Error())
}
err = t.ExecuteTemplate(&html, tmpl.Basename, email)
if err != nil {
log.Error("SendEmail: template execution error: %s", err.Error())

View File

@ -8,6 +8,7 @@ import (
"strings"
"github.com/kirsle/blog/src/log"
"github.com/kirsle/blog/src/root"
)
// Blog configuration bindings.
@ -37,6 +38,10 @@ type Filepath struct {
Basename string
Relative string // Relative path including document root (i.e. "root/about.html")
Absolute string // Absolute path on disk (i.e. "/opt/blog/root/about.html")
// If file was resolved to embedded bindata, this is the bindata key name.
// Zero value means it resolved to a file on filesystem.
BindataKey string
}
func (f Filepath) String() string {
@ -55,39 +60,78 @@ func ResolvePath(path string) (Filepath, error) {
// If you need to debug this function, edit this block.
debug := func(tmpl string, args ...interface{}) {
if false {
if true { // edit this to enable
log.Debug(tmpl, args...)
}
}
debug("Resolving filepath for URI: %s", path)
for _, root := range []string{*UserRoot, *DocumentRoot} {
if len(root) == 0 {
continue
}
debug("ResolvePath(%s) called", path)
if len(*UserRoot) > 0 {
debug("1. Resolving filepath for URI in user root: %s", path)
// Resolve the file path.
relPath := filepath.Join(root, path)
relPath := filepath.Join(*UserRoot, path)
absPath, err := filepath.Abs(relPath)
basename := filepath.Base(relPath)
if err != nil {
log.Error("%v", err)
}
debug("Expected filepath: %s", absPath)
debug(" Expected filepath: %s", absPath)
// Found an exact hit?
if stat, err := os.Stat(absPath); !os.IsNotExist(err) && !stat.IsDir() {
debug("Exact filepath found: %s", absPath)
return Filepath{path, basename, relPath, absPath}, nil
debug(" + Exact filepath found: %s", absPath)
return Filepath{
URI: path,
Basename: basename,
Relative: relPath,
Absolute: absPath,
}, nil
}
// Try some supported suffixes.
for _, suffix := range hiddenSuffixes {
test := absPath + suffix
if stat, err := os.Stat(test); !os.IsNotExist(err) && !stat.IsDir() {
debug("Filepath found via suffix %s: %s", suffix, test)
return Filepath{path + suffix, basename + suffix, relPath + suffix, test}, nil
debug(" + Filepath found via suffix %s: %s", suffix, test)
return Filepath{
URI: path + suffix,
Basename: basename + suffix,
Relative: relPath + suffix,
Absolute: test,
}, nil
}
}
}
debug("2. Not found in filesystem, checking bindata for: %s", path)
{
// Exact hit?
if _, err := root.Asset(path); err == nil {
debug(" Found in bindata as: %s", path)
return Filepath{
URI: path,
Basename: filepath.Base(path),
Relative: path,
Absolute: path,
BindataKey: path,
}, nil
}
// Try some supported suffixes.
for _, suffix := range hiddenSuffixes {
test := path + suffix
if _, err := root.Asset(test); err == nil {
debug(" Filepath found via suffix %s: %s", suffix, test)
return Filepath{
URI: test,
Basename: filepath.Base(test),
Relative: test,
Absolute: test,
BindataKey: test,
}, nil
}
}
}

View File

@ -8,13 +8,14 @@ import (
"time"
gorilla "github.com/gorilla/sessions"
"github.com/kirsle/blog/models/settings"
"github.com/kirsle/blog/models/users"
"github.com/kirsle/blog/src/log"
"github.com/kirsle/blog/src/middleware"
"github.com/kirsle/blog/src/middleware/auth"
"github.com/kirsle/blog/src/root"
"github.com/kirsle/blog/src/sessions"
"github.com/kirsle/blog/src/types"
"github.com/kirsle/blog/models/settings"
"github.com/kirsle/blog/models/users"
)
// Vars is an interface to implement by the templates to pass their own custom
@ -113,19 +114,19 @@ func Template(w io.Writer, r *http.Request, path string, data interface{}) error
// Get the layout template.
if !isPartial {
templateName = "layout"
layout, err = ResolvePath(".layout")
layout, err = ResolvePath(".layout.gohtml")
if err != nil {
log.Error("RenderTemplate(%s): layout template not found", path)
return err
}
} else {
templateName = filepath.Basename
templateName = filepath.Absolute
}
// The comment entry partial.
commentEntry, err := ResolvePath("comments/entry.partial")
commentEntry, err := ResolvePath("comments/entry.partial.gohtml")
if err != nil {
log.Error("RenderTemplate(%s): comments/entry.partial not found")
log.Error("RenderTemplate: comments/entry.partial not found")
return err
}
@ -135,17 +136,28 @@ func Template(w io.Writer, r *http.Request, path string, data interface{}) error
// and allows the filepath template to set the page title.
var templates []string
if !isPartial {
templates = append(templates, layout.Absolute)
templates = append(templates, layout.Absolute, commentEntry.Absolute, filepath.Absolute)
}
t, err = t.ParseFiles(append(templates, commentEntry.Absolute, filepath.Absolute)...)
if err != nil {
log.Error(err.Error())
return err
for _, filename := range templates {
if asset, err2 := root.Asset(filename); err2 == nil {
log.Debug("Parse %s from bindata", filename)
t, err = t.Parse(string(asset))
} else {
log.Debug("Parse %s from file", filename)
t, err = t.ParseFiles(filename)
}
if err != nil {
log.Error(err.Error())
return err
}
}
err = t.ExecuteTemplate(w, templateName, v)
if err != nil {
log.Error("Template parsing error: %s", err)
log.Error("Template parsing error(tmpl name: %s; ): %s", err)
return err
}