aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--http/main.go27
-rw-r--r--http/render.go62
-rw-r--r--local/index.go10
-rw-r--r--local/page.go88
-rw-r--r--local/time.go2
-rw-r--r--page/main.go1
6 files changed, 147 insertions, 43 deletions
diff --git a/http/main.go b/http/main.go
index e09f610..c4726d8 100644
--- a/http/main.go
+++ b/http/main.go
@@ -9,7 +9,6 @@ import (
"net/http"
"os"
"path/filepath"
- "strings"
"riedstra.dev/mitch/go-website/local"
"riedstra.dev/mitch/go-website/page"
@@ -21,7 +20,7 @@ import (
// since an interface is used, you can swap this out with a different
// library to load pages from different sources
var NewPage func(string) page.Page = func(u string) page.Page {
- return &local.Page{Path: u}
+ return local.NewPage(u)
}
// ReindexRedirectTo is the path that we'll redirect to when a call to rebuild
@@ -54,29 +53,7 @@ func PageHandler(w http.ResponseWriter, r *http.Request) {
}
u = filepath.Join(".", u)
- p := NewPage(u)
- err := p.Render(w)
- if err != nil {
- if strings.HasSuffix(err.Error(), "no such file or directory") {
- Logger.Printf("%s %s %d %s", r.RemoteAddr, r.Method, 404, u)
- p = NewPage("404")
- w.WriteHeader(404)
- err := p.Render(w)
- if err != nil {
- Logger.Printf("%s %s path: %s while trying 404: %s", r.RemoteAddr, r.Method, u, err)
- http.Error(w, "Internal server error", 500)
- return
- }
- return
- } else {
- Logger.Printf("%s %s path: %s encountered: %s", r.RemoteAddr, r.Method, u, err)
- http.Error(w, "Internal server error", 500)
- return
- }
- }
-
- Logger.Printf("%s %s %d %s", r.RemoteAddr, r.Method, 200, u)
-
+ RenderForPath(w, r, u)
}
func RebuildIndexHandler(w http.ResponseWriter, r *http.Request) {
diff --git a/http/render.go b/http/render.go
new file mode 100644
index 0000000..b73ae76
--- /dev/null
+++ b/http/render.go
@@ -0,0 +1,62 @@
+package http
+
+import (
+ "net/http"
+ "path/filepath"
+ "strings"
+)
+
+func Render(w http.ResponseWriter, r *http.Request,
+ path string, vars map[string]interface{}, statusCode int) {
+
+ u := r.URL.Path
+ if u == "/" {
+ u = "/index"
+ }
+ u = filepath.Join(".", u)
+
+ // Sepcifically use the specified path for the page
+ p := NewPage(path)
+
+ if vars != nil {
+ p.SetVars(vars)
+ }
+
+ err := p.Render(w)
+ if err != nil {
+ if strings.HasSuffix(err.Error(), "no such file or directory") {
+ Logger.Printf("%s %s %d %s", r.RemoteAddr, r.Method, 404, u)
+ p = NewPage("404")
+ w.WriteHeader(404)
+ err := p.Render(w)
+ if err != nil {
+ Logger.Printf("%s %s path: %s while trying 404: %s", r.RemoteAddr, r.Method, u, err)
+ http.Error(w, "Internal server error", 500)
+ return
+ }
+ return
+ } else {
+ Logger.Printf("%s %s path: %s encountered: %s", r.RemoteAddr, r.Method, u, err)
+ http.Error(w, "Internal server error", 500)
+ return
+ }
+ }
+
+ Logger.Printf("%s %s %d %s", r.RemoteAddr, r.Method, statusCode, u)
+
+}
+
+// RenderWithVars allows you to specify a specific page and whether or not
+// you wish to override vars. If left nil they will not be overridden.
+// Also see RenderForPath if you don't need to override them
+func RenderWithVars(w http.ResponseWriter, r *http.Request,
+ path string, vars map[string]interface{}) {
+
+ Render(w, r, path, vars, 200)
+}
+
+// RenderForPath takes the path to a page and finish up the rendering
+// Allowing you to place logic on what page is rendered by your handlers
+func RenderForPath(w http.ResponseWriter, r *http.Request, path string) {
+ RenderWithVars(w, r, path, nil)
+}
diff --git a/local/index.go b/local/index.go
index a90276e..7b821f6 100644
--- a/local/index.go
+++ b/local/index.go
@@ -10,6 +10,8 @@ import (
var pageIndex map[string]PageList
+// RebuildIndex can be called in order to rebuild the entire website
+// index
func (p *Page) RebuildIndex() error {
pageIndex = nil
_, err := p.Index()
@@ -18,7 +20,7 @@ func (p *Page) RebuildIndex() error {
// Index returns a map of all pages below the current Page's Path seperated
// into their respective tags If a Page has multiple tags it will be listed
-// under each
+// under each.
func (p *Page) Index() (map[string]PageList, error) {
if pageIndex != nil {
return pageIndex, nil
@@ -29,15 +31,15 @@ func (p *Page) Index() (map[string]PageList, error) {
var pageErr error
- filepath.Walk(filepath.Dir(p.Path),
+ filepath.Walk(filepath.Dir(p.path),
func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
- if !info.IsDir() && strings.HasSuffix(info.Name(), ".md") {
+ if !info.IsDir() && strings.HasSuffix(info.Name(), Suffix) {
- p2 := &Page{Path: strings.ReplaceAll(path, ".md", "")}
+ p2 := NewPage(strings.ReplaceAll(path, Suffix, ""))
err = p2.Read()
if err != nil {
diff --git a/local/page.go b/local/page.go
index f514b4a..0ccaf2e 100644
--- a/local/page.go
+++ b/local/page.go
@@ -1,3 +1,25 @@
+// local implements the website backed by a local filesystem.
+//
+// Reading the base template off the disk, then any markdown files which are
+// split into two sections by the DocumentSplit global variable. The first
+// section is parsed as yaml to populate the Page struct. The second portion is
+// markdown, first executed as part of the text/template then rendered by
+// blackfriday.
+//
+// Usage:
+//
+// import (
+// "fmt"
+// "os"
+// site "riedstra.dev/mitch/go-website/local"
+// )
+// // Where some/path.md exists
+// p := site.NewPage("/some/path")
+// // Dump the rendered HTML to stdout
+// err := p.Render(os.Stdout)
+// if err != nil {
+// fmt.Fprintln(os.Stderr, err)
+// }
package local
import (
@@ -12,27 +34,65 @@ import (
"gopkg.in/yaml.v3"
)
+// Page should not be created directly as it will not set the interal path
+// properly. Use NewPage instead.
+//
+// The exported fields can be filled in the yaml at the top of a page and
+// utilized within.
type Page struct {
- Path string
+ path string
Title string
Head string
Description string
- Tags map[string]interface{}
- Date *PageTime
- Published bool
- Vars map[string]interface{}
- Markdown []byte
+ // Tags to apply to the page in question. Useful for Index()
+ Tags map[string]interface{}
+ Date *PageTime
+ Published bool
+ Vars map[string]interface{}
+ markdown []byte
}
-// Can be adjusted to change the base template used in rendering
+// Global is meant to be supplied by external users of this package to populate
+// globally accessable information across all of the templates accessiable via
+// .Global care must be taken when utilizing this functionality
+var Global interface{}
+
+// BaseTemplate can be adjusted to change the base template used in rendering
var BaseTemplate = "inc/base.html"
-// Used to split the .md files into yaml and markdown
+// Suffix is applied to all pages for reading off of the disk
+var Suffix = ".md"
+
+// DocumentSplit is used to split the .md files into yaml and markdown
var DocumentSplit = "|---\n"
-// Allow for the creation of a new page from the page
+// NewPage returns a page struct with the path populated
+func NewPage(pth string) *Page {
+ return &Page{path: pth}
+}
+
+// NewPage Allow for the creation of a new page from the current page, does
+// not inlcude any information about the current page.
func (p Page) NewPage(pth string) *Page {
- return &Page{Path: pth}
+ return NewPage(pth)
+}
+
+// Path gets the current path set on the struct for the page in question
+// Useful if you're say iterating across tags to print out a list of
+// relevant posts on a blog or so by topic.
+func (p Page) Path() string {
+ return p.path
+}
+
+// Global is specifically for use inside of a page markdown file or
+// in a base template. This simply returns the package Global variable
+func (p *Page) Global() interface{} {
+ return Global
+}
+
+// SetVars Will set to `nil` if provided
+func (p *Page) SetVars(vars map[string]interface{}) {
+ p.Vars = vars
}
// Renders a page
@@ -79,7 +139,7 @@ func (p *Page) Read() error {
yamlBuf := bytes.NewBuffer(nil)
markdownBuf := bytes.NewBuffer(nil)
- fh, err := os.Open(p.Path + ".md")
+ fh, err := os.Open(p.path + Suffix)
if err != nil {
return err
}
@@ -115,13 +175,13 @@ func (p *Page) Read() error {
return err
}
- p.Markdown = markdownBuf.Bytes()
+ p.markdown = markdownBuf.Bytes()
return nil
}
func (p *Page) RenderBody() (string, error) {
buf := &bytes.Buffer{}
- t, err := template.New("Body").Parse(string(p.Markdown))
+ t, err := template.New("Body").Parse(string(p.markdown))
if err != nil {
return "", err
}
@@ -135,5 +195,5 @@ func (p *Page) RenderBody() (string, error) {
}
func (p Page) String() string {
- return fmt.Sprintf("Page: %s", p.Path)
+ return fmt.Sprintf("Page: %s", p.path)
}
diff --git a/local/time.go b/local/time.go
index 72ff3c6..27efc88 100644
--- a/local/time.go
+++ b/local/time.go
@@ -9,6 +9,8 @@ type PageTime struct {
time.Time
}
+// TimeFormat is the format string used when unmarshaling the time
+// from the yaml information.
var TimeFormat = "01.02.2006 15:04:05 MST"
func (pt *PageTime) UnmarshalYAML(n *yaml.Node) error {
diff --git a/page/main.go b/page/main.go
index ebcf33d..da7feec 100644
--- a/page/main.go
+++ b/page/main.go
@@ -9,4 +9,5 @@ import (
type Page interface {
Render(io.Writer) error
RebuildIndex() error
+ SetVars(map[string]interface{})
}