forked from donuts-are-good/bearclaw
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmain.go
266 lines (218 loc) · 6.62 KB
/
main.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
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
package main
import (
"encoding/json"
"flag"
"fmt"
"log"
"net/url"
"os"
"path/filepath"
"sort"
"strings"
"github.com/fsnotify/fsnotify"
)
// init runs before main()
func init() {
// we are making a list of folders here to check for the presence of
// if they don't exist, we create them
foldersToCreate := []string{inFolder, outFolder, templateFolder, pluginsFolder}
createFoldersErr := createFolders(foldersToCreate)
if createFoldersErr != nil {
log.Println(createFoldersErr)
}
FindZips(pluginsFolder)
}
func main() {
// check to see if the user ran with --watch
watchFlag := flag.Bool("watch", false, "watch the current directory for changes")
flag.Parse()
// if they did...
if *watchFlag {
// make a list of folders to keep an eye on
foldersToWatch := []string{templateFolder, inFolder}
// the process to watch it goes in a goroutine
go watchFoldersForChanges(foldersToWatch)
// give the user some type of confirmation
fmt.Println("Waiting for changes: ", foldersToWatch)
// select {} is a blocking operation that keeps
// the program from closing
select {}
}
// now, if nothing has gone wrong, we process the html
markdownToHTML(inFolder, outFolder, templateFolder)
createPostList(inFolder, outFolder, templateFolder)
createAboutPage(outFolder, templateFolder)
}
// recreateHeaderFooterFiles recreates the header and footer files
// if we're rebuilding the templates, we'll need these.
func recreateHeaderFooterFiles(templatesFolder string) error {
headerFile, err := os.Create(templatesFolder + "/header.html")
if err != nil {
return err
}
defer headerFile.Close()
_, err = headerFile.WriteString(headerHTML)
if err != nil {
return err
}
footerFile, err := os.Create(templatesFolder + "/footer.html")
if err != nil {
return err
}
defer footerFile.Close()
_, err = footerFile.WriteString(footerHTML)
if err != nil {
return err
}
return nil
}
func watchFoldersForChanges(folders []string) {
// range through the watched files
for _, folder := range folders {
// create a new watcher for each watched folder
watcher, err := fsnotify.NewWatcher()
if err != nil {
log.Fatal(err)
}
// don't forget to close it
defer watcher.Close()
// make a channel for goroutine messaging
done := make(chan bool)
go func() {
// for { ev ... ver }
for {
select {
case event := <-watcher.Events:
if event.Op&fsnotify.Write == fsnotify.Write {
// if there's an event, remark and rebuild
log.Println("modified:", event.Name, " - rebuilding files..")
markdownToHTML(inFolder, outFolder, templateFolder)
createPostList(inFolder, outFolder, templateFolder)
}
// if we get an error instead of event, announce it
case err := <-watcher.Errors:
log.Println("error:", err)
}
}
}()
err = watcher.Add(folder)
if err != nil {
log.Fatal(err)
}
<-done
}
}
// createFolders takes a list of folders and checks for them to exist, and creates them if they don't exist.
func createFolders(folders []string) error {
for _, folder := range folders {
if _, err := os.Stat(folder); os.IsNotExist(err) {
err = os.MkdirAll(folder, os.ModePerm)
if err != nil {
return err
}
if folder == "templates" {
err = recreateHeaderFooterFiles(folder)
if err != nil {
return err
}
}
}
}
return nil
}
// createPostList creates the page that has a list of all of your posts
func createPostList(inFolder, outFolder, templateFolder string) {
// read the files in the directory
files, _ := os.ReadDir(inFolder)
// sort them by mod time
sort.Slice(files, func(i, j int) bool {
fi, _ := os.Stat(inFolder + "/" + files[i].Name())
fj, _ := os.Stat(inFolder + "/" + files[j].Name())
return fi.ModTime().After(fj.ModTime())
})
// unordered list
postList := "<ul>"
// for all files...
for _, file := range files {
// if it is a markdown file...
if filepath.Ext(file.Name()) == ".md" {
// get the filename/title
title := strings.TrimSuffix(file.Name(), filepath.Ext(file.Name()))
// put it on the list with the html
// postList += "<li><a href='" + file.Name() + ".html'>" + title + "</a></li>"
postList += "<li><a href='" + url.PathEscape(file.Name()) + ".html'>" + title + "</a></li>"
}
}
// if there are more than 0 posts make an RSS feed
if len(files) > 0 {
// generate the rss feed
CreateXMLRSSFeed(inFolder, outFolder)
}
// end the list
postList += "</ul>"
// create the posts file
htmlFile, _ := os.Create(outFolder + "/posts.html")
// don't forget to close it
defer htmlFile.Close()
// read the header/footer templates
header, _ := os.ReadFile(templateFolder + "/header.html")
footer, _ := os.ReadFile(templateFolder + "/footer.html")
// combine them
fmt.Fprintln(htmlFile, string(header)+postList+string(footer))
}
func createAboutPage(outFolder, templateFolder string) error {
// create the about file
aboutFile, err := os.Create(outFolder + "/about.html")
if err != nil {
return err
}
defer aboutFile.Close()
// read the header/footer templates
header, err := os.ReadFile(templateFolder + "/header.html")
if err != nil {
return err
}
footer, err := os.ReadFile(templateFolder + "/footer.html")
if err != nil {
return err
}
// content vars
siteName := "<h1>" + site_name + "</h1>"
siteDesc := "<p>" + site_description + "</p>"
siteLink := "<p><a href='" + site_link + "'>" + site_link + "</a></p>"
siteLicense := "<p>" + site_license + "</p>"
// author vars
authorName := "<h2>" + author_name + "</h2>"
authorBio := "<p>" + author_bio + "</p>"
authorLinks := "<ul>"
for _, link := range author_links {
authorLinks += "<li><a href='" + link + "'>" + link + "</a></li>"
}
authorLinks += "</ul>"
// plugin vars
pluginsSection := ""
plugins, err := os.ReadDir(pluginsFolder)
if err != nil {
return err
}
if len(plugins) > 0 {
pluginsSection = "<h2>Plugins</h2><ul>"
for _, plugin := range plugins {
file, err := os.Open(pluginsFolder + "/" + plugin.Name() + "/plugin.json")
if err != nil {
return err
}
defer file.Close()
var pluginData map[string]string
err = json.NewDecoder(file).Decode(&pluginData)
if err != nil {
return err
}
pluginsSection += "<li>" + pluginData["plugin_name"] + " v" + pluginData["plugin_version"] + " by " + pluginData["plugin_author"] + " - " + pluginData["plugin_description"] + "<br>" + pluginData["plugin_license"] + "<br>" + pluginData["plugin_link"] + "</li>"
}
pluginsSection += "</ul>"
}
// combine the content and write to the about file
fmt.Fprintln(aboutFile, string(header)+siteName+siteDesc+siteLink+siteLicense+authorName+authorBio+authorLinks+pluginsSection+string(footer))
return nil
}