-
Notifications
You must be signed in to change notification settings - Fork 16
/
Copy pathgen.go
133 lines (119 loc) · 2.89 KB
/
gen.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
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)
}
}