-
Notifications
You must be signed in to change notification settings - Fork 16
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
refactor watcher, generator, tpldata into their own file
- Loading branch information
Showing
4 changed files
with
235 additions
and
218 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,133 @@ | ||
package main | ||
|
||
import ( | ||
"html/template" | ||
"io" | ||
"io/ioutil" | ||
"log" | ||
"os" | ||
"path/filepath" | ||
"sort" | ||
|
||
"github.com/eknkc/amber" | ||
) | ||
|
||
const ( | ||
maxRecentPosts = 2 | ||
) | ||
|
||
var ( | ||
postTpl *template.Template | ||
postTplNm = "post.amber" | ||
) | ||
|
||
type sortableFileInfo []os.FileInfo | ||
|
||
func (s sortableFileInfo) Len() int { return len(s) } | ||
func (s sortableFileInfo) Less(i, j int) bool { return s[i].ModTime().Before(s[j].ModTime()) } | ||
func (s sortableFileInfo) Swap(i, j int) { s[i], s[j] = s[j], s[i] } | ||
|
||
func FilterDir(s sortableFileInfo) sortableFileInfo { | ||
for i := 0; i < len(s); { | ||
if s[i].IsDir() { | ||
s[i], s = s[len(s)-1], s[:len(s)-1] | ||
} else { | ||
i++ | ||
} | ||
} | ||
return s | ||
} | ||
|
||
func compileTemplate() { | ||
ap := filepath.Join(TemplatesDir, postTplNm) | ||
if _, err := os.Stat(ap); os.IsNotExist(err) { | ||
// Amber post template does not exist, compile the native Go templates | ||
postTpl, err = template.ParseGlob(filepath.Join(TemplatesDir, "*.html")) | ||
if err != nil { | ||
log.Fatal("FATAL ", err) | ||
} | ||
postTplNm = "post" // TODO : Validate this... | ||
} else { | ||
c := amber.New() | ||
if err := c.ParseFile(ap); err != nil { | ||
log.Fatal("FATAL ", err) | ||
} | ||
if postTpl, err = c.Compile(); err != nil { | ||
log.Fatal("FATAL ", err) | ||
} | ||
} | ||
} | ||
|
||
func generateSite() { | ||
// First compile the template(s) | ||
compileTemplate() | ||
// Clear the public directory, except subdirs | ||
fis, err := ioutil.ReadDir(PublicDir) | ||
if err != nil { | ||
log.Fatal("FATAL ", err) | ||
} | ||
for _, fi := range fis { | ||
if !fi.IsDir() { | ||
err = os.Remove(filepath.Join(PublicDir, fi.Name())) | ||
if err != nil { | ||
log.Println("DELETE ERROR ", err) | ||
} | ||
} | ||
} | ||
// Now read the posts | ||
fis, err = ioutil.ReadDir(PostsDir) | ||
if err != nil { | ||
log.Fatal("FATAL ", err) | ||
} | ||
sfi := sortableFileInfo(fis) | ||
sfi = FilterDir(sfi) | ||
sort.Reverse(sfi) | ||
|
||
recent := make([]*ShortPost, maxRecentPosts) | ||
all := make([]*LongPost, len(sfi)) | ||
// First pass to get the recent posts (and others) so that | ||
// they can be passed to all posts. | ||
for i, fi := range sfi { | ||
all[i] = newLongPost(fi) | ||
if i < maxRecentPosts { | ||
recent[i] = all[i].Short() | ||
} | ||
} | ||
|
||
for i, p := range all { | ||
td := newTemplateData(p, i, recent, all) | ||
generateFile(td, i == 0) | ||
} | ||
} | ||
|
||
// TODO : Should pass to the template: | ||
// Title : The first heading in the file, or the file name, or front matter? | ||
// Description : ? | ||
// ModTime | ||
// Parsed : The html-parsed markdown | ||
// Recent : A slice of n recent posts | ||
// Next : The next (more recent) post | ||
// Previous : The previous (older) post | ||
|
||
func generateFile(td *TemplateData, idx bool) { | ||
var w io.Writer | ||
|
||
fw, err := os.Create(filepath.Join(PublicDir, td.Post.Slug)) | ||
if err != nil { | ||
log.Fatal("FATAL ", err) | ||
} | ||
defer fw.Close() | ||
w = fw | ||
if idx { | ||
idxw, err := os.Create(filepath.Join(PublicDir, "index.html")) | ||
if err != nil { | ||
log.Fatal("FATAL ", err) | ||
} | ||
defer idxw.Close() | ||
w = io.MultiWriter(fw, idxw) | ||
} | ||
err = postTpl.ExecuteTemplate(w, postTplNm, td) | ||
if err != nil { | ||
log.Fatal("FATAL ", err) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,61 +1,17 @@ | ||
package main | ||
|
||
import ( | ||
"html/template" | ||
"log" | ||
"os" | ||
"path/filepath" | ||
|
||
"github.com/eknkc/amber" | ||
"github.com/howeyc/fsnotify" | ||
"github.com/jessevdk/go-flags" | ||
) | ||
|
||
var ( | ||
postTpl *template.Template | ||
postTplNm = "post.amber" | ||
) | ||
|
||
func main() { | ||
_, err := flags.Parse(&Options) | ||
if err == nil { // err prints the usage automatically | ||
// Compile the template(s) | ||
compileTemplate() | ||
if err == nil { // err != nil prints the usage automatically | ||
// Generate the site | ||
regeneratePosts() | ||
|
||
generateSite() | ||
// Start the watcher | ||
w, err := fsnotify.NewWatcher() | ||
if err != nil { | ||
log.Fatal("FATAL ", err) | ||
} | ||
defer w.Close() | ||
go watch(w) | ||
if err = w.Watch(PostsDir); err != nil { | ||
log.Fatal("FATAL ", err) | ||
} | ||
|
||
defer startWatcher().Close() | ||
// Start the web server | ||
run() | ||
} | ||
} | ||
|
||
func compileTemplate() { | ||
ap := filepath.Join(TemplatesDir, postTplNm) | ||
if _, err := os.Stat(ap); os.IsNotExist(err) { | ||
// Amber post template does not exist, compile the native Go templates | ||
postTpl, err = template.ParseGlob(filepath.Join(TemplatesDir, "*.html")) | ||
if err != nil { | ||
log.Fatal("FATAL ", err) | ||
} | ||
postTplNm = "post" // TODO : Validate this... | ||
} else { | ||
c := amber.New() | ||
if err := c.ParseFile(ap); err != nil { | ||
log.Fatal("FATAL ", err) | ||
} | ||
if postTpl, err = c.Compile(); err != nil { | ||
log.Fatal("FATAL ", err) | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
package main | ||
|
||
import ( | ||
"io/ioutil" | ||
"log" | ||
"os" | ||
"path/filepath" | ||
"regexp" | ||
"strings" | ||
"time" | ||
|
||
"github.com/russross/blackfriday" | ||
) | ||
|
||
type TemplateData struct { | ||
SiteName string | ||
Post *LongPost | ||
Recent []*ShortPost | ||
Prev *ShortPost | ||
Next *ShortPost | ||
} | ||
|
||
func newTemplateData(p *LongPost, i int, r []*ShortPost, all []*LongPost) *TemplateData { | ||
td := &TemplateData{SiteName: SiteName, Post: p, Recent: r} | ||
|
||
if i > 0 { | ||
td.Prev = all[i-1].Short() | ||
} | ||
if i < len(all)-2 { | ||
td.Next = all[i+1].Short() | ||
} | ||
return td | ||
} | ||
|
||
type ShortPost struct { | ||
Slug string | ||
Author string | ||
Title string | ||
Description string | ||
PubTime time.Time | ||
ModTime time.Time | ||
} | ||
|
||
type LongPost struct { | ||
*ShortPost | ||
Content string | ||
} | ||
|
||
var rxSlug = regexp.MustCompile(`[^a-zA-Z\-_0-9]`) | ||
|
||
func getSlug(fnm string) string { | ||
return rxSlug.ReplaceAllString(strings.Replace(fnm, filepath.Ext(fnm), "", 1), "-") | ||
} | ||
|
||
func newLongPost(fi os.FileInfo) *LongPost { | ||
slug := getSlug(fi.Name()) | ||
sp := &ShortPost{ | ||
slug, | ||
"author", // TODO : Complete... | ||
slug, // TODO : Read first heading, or front matter | ||
"description", // TODO : Read front matter | ||
fi.ModTime(), // TODO : This is NOT the pub time... | ||
fi.ModTime(), | ||
} | ||
|
||
f, err := os.Open(filepath.Join(PostsDir, fi.Name())) | ||
if err != nil { | ||
log.Fatal("FATAL ", err) | ||
} | ||
defer f.Close() | ||
b, err := ioutil.ReadAll(f) | ||
if err != nil { | ||
log.Fatal("FATAL ", err) | ||
} | ||
res := blackfriday.MarkdownCommon(b) | ||
lp := &LongPost{ | ||
sp, | ||
string(res), | ||
} | ||
return lp | ||
} | ||
|
||
func (lp *LongPost) Short() *ShortPost { | ||
return lp.ShortPost | ||
} |
Oops, something went wrong.