6
6
_ "embed"
7
7
"encoding/xml"
8
8
"errors"
9
+ "flag"
9
10
"fmt"
10
11
"github.com/yuin/goldmark"
11
12
"github.com/yuin/goldmark/renderer/html"
@@ -46,34 +47,9 @@ type Page struct {
46
47
Filepath string
47
48
}
48
49
49
- func NewPageFromFile (file string , baseUrl string ) (* Page , error ) {
50
- info , err := os .Stat (file )
51
- if err != nil {
52
- return nil , err
53
- }
54
-
55
- urlPath , datePublished := parseFilename (file )
56
-
57
- p := Page {
58
- Filepath : file ,
59
- UrlPath : urlPath ,
60
- DatePublished : datePublished ,
61
- DateModified : info .ModTime (),
62
- Template : "default.html" ,
63
- }
64
-
65
- p .Permalink = baseUrl + p .UrlPath
66
-
67
- if err := parseFrontMatter (& p ); err != nil {
68
- return nil , err
69
- }
70
-
71
- return & p , nil
72
- }
73
-
74
50
// parseFilename parses the URL path and optional date component from the given file path
75
- func parseFilename (path string ) (string , time.Time ) {
76
- path = strings .TrimPrefix (path , "content/" )
51
+ func parseFilename (path string , rootDir string ) (string , time.Time ) {
52
+ path = strings .TrimPrefix (path , rootDir + "content/" )
77
53
path = strings .TrimSuffix (path , ".md" )
78
54
path = strings .TrimSuffix (path , "index" )
79
55
@@ -172,7 +148,7 @@ func (s *Site) buildPage(p *Page) error {
172
148
}
173
149
174
150
dest := p .UrlPath + "index.html"
175
- if err := os .MkdirAll ("build/" + filepath .Dir (dest ), 0755 ); err != nil {
151
+ if err := os .MkdirAll ("build/" + filepath .Dir (dest ), 0655 ); err != nil {
176
152
return err
177
153
}
178
154
@@ -191,35 +167,55 @@ func (s *Site) buildPage(p *Page) error {
191
167
"Page" : p ,
192
168
"Posts" : s .posts ,
193
169
"Pages" : s .pages ,
194
- "SiteUrl" : s .config . SiteUrl ,
170
+ "SiteUrl" : s .SiteUrl ,
195
171
"Title" : p .Title ,
196
172
"Content" : template .HTML (content ),
197
173
})
198
174
}
199
175
200
176
type Site struct {
201
- pages []Page
202
- posts []Page
203
- config * Config
177
+ pages []Page
178
+ posts []Page
179
+
180
+ SiteUrl string
181
+ RootDir string
204
182
}
205
183
206
184
func (s * Site ) AddPageFromFile (file string ) error {
207
- p , err := NewPageFromFile (file , s . config . SiteUrl )
185
+ info , err := os . Stat (file )
208
186
if err != nil {
209
187
return err
210
188
}
211
189
212
- s .pages = append (s .pages , * p )
190
+ urlPath , datePublished := parseFilename (file , s .RootDir )
191
+
192
+ p := Page {
193
+ Filepath : file ,
194
+ UrlPath : urlPath ,
195
+ DatePublished : datePublished ,
196
+ DateModified : info .ModTime (),
197
+ Template : "default.html" ,
198
+ }
199
+
200
+ p .Permalink = s .SiteUrl + p .UrlPath
201
+
202
+ if err := parseFrontMatter (& p ); err != nil {
203
+ return err
204
+ }
205
+
206
+ s .pages = append (s .pages , p )
207
+
208
+ // every page with a date is assumed to be a blog post
213
209
if ! p .DatePublished .IsZero () {
214
- s .posts = append (s .posts , * p )
210
+ s .posts = append (s .posts , p )
215
211
}
216
212
217
213
return nil
218
214
}
219
215
220
- func (s * Site ) readContent () error {
216
+ func (s * Site ) readContent (dir string ) error {
221
217
// walk over files in "content" directory
222
- err := filepath .WalkDir ("content" , func (file string , d fs.DirEntry , err error ) error {
218
+ err := filepath .WalkDir (dir , func (file string , d fs.DirEntry , err error ) error {
223
219
if d .IsDir () {
224
220
return nil
225
221
}
@@ -253,7 +249,7 @@ func (s *Site) createSitemap() error {
253
249
urls := make ([]Url , 0 , len (s .pages ))
254
250
for _ , p := range s .pages {
255
251
urls = append (urls , Url {
256
- Loc : s .config . SiteUrl + p .UrlPath ,
252
+ Loc : s .SiteUrl + p .UrlPath ,
257
253
LastMod : p .DateModified .Format (time .RFC1123Z ),
258
254
})
259
255
}
@@ -325,10 +321,10 @@ func (s *Site) createRSSFeed() error {
325
321
326
322
items = append (items , Item {
327
323
Title : p .Title ,
328
- Link : s .config . SiteUrl + p .UrlPath ,
324
+ Link : s .SiteUrl + p .UrlPath ,
329
325
Description : pageContent ,
330
326
PubDate : p .DatePublished .Format (time .RFC1123Z ),
331
- GUID : s .config . SiteUrl + p .UrlPath ,
327
+ GUID : s .SiteUrl + p .UrlPath ,
332
328
})
333
329
}
334
330
@@ -337,7 +333,7 @@ func (s *Site) createRSSFeed() error {
337
333
Atom : "http://www.w3.org/2005/Atom" ,
338
334
Channel : Channel {
339
335
Title : "Site title" ,
340
- Link : s .config . SiteUrl ,
336
+ Link : s .SiteUrl ,
341
337
Generator : "Gosite" ,
342
338
LastBuildDate : time .Now ().Format (time .RFC1123Z ),
343
339
Items : items ,
@@ -361,8 +357,8 @@ func (s *Site) createRSSFeed() error {
361
357
return nil
362
358
}
363
359
364
- func parseConfig () (* Config , error ) {
365
- wr , err := os .Open ("config.xml" )
360
+ func parseConfig (file string ) (* Config , error ) {
361
+ wr , err := os .Open (file )
366
362
if err != nil {
367
363
return nil , err
368
364
}
@@ -378,24 +374,59 @@ func parseConfig() (*Config, error) {
378
374
}
379
375
380
376
func main () {
377
+ configFile := "config.xml"
378
+ rootPath := ""
379
+
380
+ // parse flags
381
+ flag .StringVar (& configFile , "config" , configFile , "" )
382
+ flag .StringVar (& configFile , "c" , configFile , "" )
383
+ flag .StringVar (& rootPath , "root" , rootPath , "" )
384
+ flag .StringVar (& rootPath , "r" , rootPath , "" )
385
+ flag .Parse ()
386
+
387
+ command := os .Args [len (os .Args )- 1 ]
388
+ if command != "build" && command != "serve" {
389
+ fmt .Printf (`Gozer - a fast & simple static site generator
390
+
391
+ Usage: gozer [OPTIONS] <COMMAND>
392
+
393
+ Commands:
394
+ build Deletes the output directory if there is one and builds the site
395
+ serve Builds the site and starts an HTTP server on http://localhost:8080
396
+
397
+ Options:
398
+ -r, --root <ROOT> Directory to use as root of project (default: .)
399
+ -c, --config <CONFIG> Path to confiruation file (default: config.xml)
400
+ ` )
401
+ return
402
+ }
403
+
404
+ if rootPath != "" {
405
+ rootPath = strings .TrimSuffix (rootPath , "/" ) + "/"
406
+ }
407
+
381
408
var err error
382
409
timeStart := time .Now ()
383
410
384
- templates , err = template .ParseFS (os .DirFS ("templates/" ), "*.html" )
411
+ templates , err = template .ParseFS (os .DirFS (rootPath + "templates/" ), "*.html" )
385
412
if err != nil {
386
413
log .Fatal ("Error reading templates/ directory: %s" , err )
387
414
}
388
415
389
- site := Site {}
390
-
391
416
// read config.xml
392
- site .config , err = parseConfig ()
417
+ var config * Config
418
+ config , err = parseConfig (rootPath + configFile )
393
419
if err != nil {
394
- log .Fatal ("Error reading config.xml: %w\n " , err )
420
+ log .Fatal ("Error reading configuration file at %s: %w\n " , rootPath + configFile , err )
421
+ }
422
+
423
+ site := Site {
424
+ SiteUrl : config .SiteUrl ,
425
+ RootDir : rootPath ,
395
426
}
396
427
397
428
// read content
398
- if err := site .readContent (); err != nil {
429
+ if err := site .readContent (rootPath + "content/" ); err != nil {
399
430
log .Fatal ("Error reading content/: %s" , err )
400
431
}
401
432
@@ -406,24 +437,24 @@ func main() {
406
437
}
407
438
}
408
439
409
- // create sitemap
440
+ // create XML sitemap
410
441
if err := site .createSitemap (); err != nil {
411
442
log .Warn ("Error creating sitemap: %s\n " , err )
412
443
}
413
444
414
- // create sitemap
445
+ // create RSS feed
415
446
if err := site .createRSSFeed (); err != nil {
416
447
log .Warn ("Error creating RSS feed: %s\n " , err )
417
448
}
418
449
419
450
// static files
420
- if err := copyDirRecursively ("public" , "build" ); err != nil {
451
+ if err := copyDirRecursively (rootPath + "public/ " , "build/ " ); err != nil {
421
452
log .Fatal ("Error copying public/ directory: %s" , err )
422
453
}
423
454
424
455
log .Info ("Built site containing %d pages in %d ms\n " , len (site .pages ), time .Since (timeStart ).Milliseconds ())
425
456
426
- if len ( os . Args ) > 1 && os . Args [ 1 ] == "serve" {
457
+ if command == "serve" {
427
458
log .Info ("Listening on http://localhost:8080\n " )
428
459
log .Fatal ("Hello" , http .ListenAndServe ("localhost:8080" , http .FileServer (http .Dir ("build/" ))))
429
460
}
0 commit comments