From 97b6bc511170f1eb5b01ab742e7c06934068beb5 Mon Sep 17 00:00:00 2001 From: facundoolano Date: Mon, 12 Feb 2024 15:59:18 -0300 Subject: [PATCH] extract site to its own mod --- commands/commands.go | 84 +++------------------------- commands/site.go | 51 ----------------- go.mod | 9 ++- go.sum | 7 +++ site/site.go | 128 +++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 150 insertions(+), 129 deletions(-) delete mode 100644 commands/site.go create mode 100644 site/site.go diff --git a/commands/commands.go b/commands/commands.go index 3fa8e06..382a1e1 100644 --- a/commands/commands.go +++ b/commands/commands.go @@ -2,7 +2,7 @@ package commands import ( "fmt" - "github.com/facundoolano/blorg/templates" + "github.com/facundoolano/blorg/site" "io" "io/fs" "os" @@ -34,82 +34,15 @@ func Build() error { return fmt.Errorf("couldn't read %s", SRC_DIR) } - site := Site{ - layouts: make(map[string]templates.Template), - templateIndex: make(map[string]*templates.Template), - } - - // FIXME these sound like they should be site methods too - PHASES := []func(*Site) error{ - loadConfig, - loadLayouts, - loadTemplates, - writeTarget, - } - for _, phaseFun := range PHASES { - if err := phaseFun(&site); err != nil { - return err - } - } - - return err -} - -func loadConfig(site *Site) error { - // context["config"] - return nil -} - -func loadLayouts(site *Site) error { - files, err := os.ReadDir(LAYOUT_DIR) - if os.IsNotExist(err) { - return nil - } else if err != nil { + // TODO add dir override support + site, err := site.Load(".") + if err != nil { return err } - - for _, entry := range files { - if !entry.IsDir() { - filename := entry.Name() - path := filepath.Join(LAYOUT_DIR, filename) - templ, err := templates.Parse(path) - if err != nil { - return err - } - - layout_name := strings.TrimSuffix(filename, filepath.Ext(filename)) - site.layouts[layout_name] = *templ - } - } - - return nil + return writeTarget(site) } -func loadTemplates(site *Site) error { - return filepath.WalkDir(SRC_DIR, func(path string, entry fs.DirEntry, err error) error { - if !entry.IsDir() { - templ, err := templates.Parse(path) - // if sometime fails or this is not a template, skip - if err != nil || templ == nil { - return err - } - - // posts are templates that can be chronologically sorted --that have a date. - // the rest are pages. - if _, ok := templ.Metadata["date"]; ok { - site.posts = append(site.posts, *templ) - } else { - site.pages = append(site.pages, *templ) - } - site.templateIndex[path] = templ - - // TODO load tags - } - return nil - }) -} - -func writeTarget(site *Site) error { +func writeTarget(site *site.Site) error { // clear previous target contents os.RemoveAll(TARGET_DIR) os.Mkdir(TARGET_DIR, FILE_RW_MODE) @@ -123,9 +56,10 @@ func writeTarget(site *Site) error { os.MkdirAll(targetPath, FILE_RW_MODE) } else { - if templ, ok := site.templateIndex[path]; ok { + // FIXME replace with method + if templ, ok := site.TemplateIndex[path]; ok { // if a template was found at source, render it - content, err := site.render(templ) + content, err := site.Render(templ) if err != nil { return err } diff --git a/commands/site.go b/commands/site.go deleted file mode 100644 index f4e0542..0000000 --- a/commands/site.go +++ /dev/null @@ -1,51 +0,0 @@ -package commands - -import ( - "fmt" - - "github.com/facundoolano/blorg/templates" -) - -// TODO review build and other commands and think what can be brought over here. -// e.g. SRC and TARGET dir knowledge -type Site struct { - config map[string]string // may need to make this interface{} if config gets sophisticated - layouts map[string]templates.Template - posts []templates.Template - pages []templates.Template - tags map[string]*templates.Template - - templateIndex map[string]*templates.Template -} - -func (site Site) render(templ *templates.Template) (string, error) { - ctx := site.baseContext() - ctx["page"] = templ.Metadata - content, err := templ.Render(ctx) - if err != nil { - return "", err - } - - // recursively render parent layouts - layout := templ.Metadata["layout"] - for layout != nil && err == nil { - if layout_templ, ok := site.layouts[layout.(string)]; ok { - ctx["layout"] = layout_templ.Metadata - ctx["content"] = content - content, err = layout_templ.Render(ctx) - layout = layout_templ.Metadata["layout"] - } else { - return "", fmt.Errorf("layout '%s' not found", layout) - } - } - - return content, err -} - -func (site Site) baseContext() map[string]interface{} { - return map[string]interface{}{ - "config": site.config, - "posts": site.posts, - "tags": site.tags, - } -} diff --git a/go.mod b/go.mod index 2d63eb8..ecbd94c 100644 --- a/go.mod +++ b/go.mod @@ -3,11 +3,14 @@ module github.com/facundoolano/blorg go 1.22.0 require ( - github.com/niklasfasching/go-org v1.7.0 // indirect + github.com/niklasfasching/go-org v1.7.0 + gopkg.in/osteele/liquid.v1 v1.2.4 + gopkg.in/yaml.v3 v3.0.1 +) + +require ( github.com/osteele/liquid v1.3.2 // indirect github.com/osteele/tuesday v1.0.3 // indirect golang.org/x/net v0.0.0-20201224014010-6772e930b67b // indirect - gopkg.in/osteele/liquid.v1 v1.2.4 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect - gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index cb642ae..0af66db 100644 --- a/go.sum +++ b/go.sum @@ -1,15 +1,22 @@ +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/niklasfasching/go-org v1.7.0 h1:vyMdcMWWTe/XmANk19F4k8XGBYg0GQ/gJGMimOjGMek= github.com/niklasfasching/go-org v1.7.0/go.mod h1:WuVm4d45oePiE0eX25GqTDQIt/qPW1T9DGkRscqLW5o= github.com/osteele/liquid v1.3.2 h1:G+MvVYt1HX2xuv99JgdrhV7zRVdlvFnNi8M5rN8gQmI= github.com/osteele/liquid v1.3.2/go.mod h1:VmzQQHa5v4E0GvGzqccfAfLgMwRk2V+s1QbxYx9dGak= github.com/osteele/tuesday v1.0.3 h1:SrCmo6sWwSgnvs1bivmXLvD7Ko9+aJvvkmDjB5G4FTU= github.com/osteele/tuesday v1.0.3/go.mod h1:pREKpE+L03UFuR+hiznj3q7j3qB1rUZ4XfKejwWFF2M= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= golang.org/x/net v0.0.0-20201224014010-6772e930b67b h1:iFwSg7t5GZmB/Q5TjiEAsdoLDrdJRC1RiF2WhuV29Qw= golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/osteele/liquid.v1 v1.2.4 h1:OioNeCaVyWL1jRXzRqQ2vr4ISBbTgtnYsJeVlToLhBw= gopkg.in/osteele/liquid.v1 v1.2.4/go.mod h1:9Bx5f04tf9SVwv3Tcx93dx3WH0EKWmE0Gjd6Dyoc5cs= diff --git a/site/site.go b/site/site.go new file mode 100644 index 0000000..b51a46f --- /dev/null +++ b/site/site.go @@ -0,0 +1,128 @@ +package site + +import ( + "fmt" + "github.com/facundoolano/blorg/templates" + "io/fs" + "os" + "path/filepath" + "strings" +) + +// TODO review build and other commands and think what can be brought over here. +// e.g. SRC and TARGET dir knowledge +type Site struct { + config map[string]string // may need to make this interface{} if config gets sophisticated + layouts map[string]templates.Template + posts []templates.Template + pages []templates.Template + tags map[string]*templates.Template + + TemplateIndex map[string]*templates.Template +} + +func Load(rootDir string) (*Site, error) { + site := Site{ + layouts: make(map[string]templates.Template), + TemplateIndex: make(map[string]*templates.Template), + } + + // TODO merge with contents of local config.yml file + site.config = map[string]string{ + "src_dir": filepath.Join(rootDir, "src"), + "target_dir": filepath.Join(rootDir, "target"), + "layouts_dir": filepath.Join(rootDir, "layouts"), + } + + if err := site.loadLayouts(); err != nil { + return nil, err + } + + if err := site.loadTemplates(); err != nil { + return nil, err + } + + return &site, nil +} + +func (site *Site) loadLayouts() error { + files, err := os.ReadDir(site.config["layouts_dir"]) + + if os.IsNotExist(err) { + return nil + } else if err != nil { + return err + } + + for _, entry := range files { + if !entry.IsDir() { + filename := entry.Name() + path := filepath.Join(site.config["layouts_dir"], filename) + templ, err := templates.Parse(path) + if err != nil { + return err + } + + layout_name := strings.TrimSuffix(filename, filepath.Ext(filename)) + site.layouts[layout_name] = *templ + } + } + + return nil +} + +func (site *Site) loadTemplates() error { + return filepath.WalkDir(site.config["src_dir"], func(path string, entry fs.DirEntry, err error) error { + if !entry.IsDir() { + templ, err := templates.Parse(path) + // if sometime fails or this is not a template, skip + if err != nil || templ == nil { + return err + } + + // posts are templates that can be chronologically sorted --that have a date. + // the rest are pages. + if _, ok := templ.Metadata["date"]; ok { + site.posts = append(site.posts, *templ) + } else { + site.pages = append(site.pages, *templ) + } + site.TemplateIndex[path] = templ + + // TODO load tags + } + return nil + }) +} + +func (site Site) Render(templ *templates.Template) (string, error) { + ctx := site.baseContext() + ctx["page"] = templ.Metadata + content, err := templ.Render(ctx) + if err != nil { + return "", err + } + + // recursively render parent layouts + layout := templ.Metadata["layout"] + for layout != nil && err == nil { + if layout_templ, ok := site.layouts[layout.(string)]; ok { + ctx["layout"] = layout_templ.Metadata + ctx["content"] = content + content, err = layout_templ.Render(ctx) + layout = layout_templ.Metadata["layout"] + } else { + return "", fmt.Errorf("layout '%s' not found", layout) + } + } + + return content, err +} + +func (site Site) baseContext() map[string]interface{} { + return map[string]interface{}{ + "config": site.config, + "posts": site.posts, + "tags": site.tags, + } +}