extract site to its own mod

This commit is contained in:
facundoolano 2024-02-12 15:59:18 -03:00
parent 03da3b3770
commit 97b6bc5111
5 changed files with 150 additions and 129 deletions

View file

@ -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 {
return err
}
for _, entry := range files {
if !entry.IsDir() {
filename := entry.Name()
path := filepath.Join(LAYOUT_DIR, filename)
templ, err := templates.Parse(path)
// TODO add dir override support
site, err := site.Load(".")
if err != nil {
return err
}
layout_name := strings.TrimSuffix(filename, filepath.Ext(filename))
site.layouts[layout_name] = *templ
}
return writeTarget(site)
}
return nil
}
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
}

View file

@ -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,
}
}

9
go.mod
View file

@ -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
)

7
go.sum
View file

@ -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=

128
site/site.go Normal file
View file

@ -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,
}
}