continue working on config and default parsing

This commit is contained in:
Daniel Fichtinger 2024-11-25 16:05:35 -05:00
parent 4d1b18fd12
commit c6c801e248
8 changed files with 183 additions and 109 deletions

View file

@ -74,7 +74,7 @@ func buildPageData(m Metadata, path string, settings *Settings) *PageData {
}
func ConvertFile(in string, out string, settings *Settings) error {
mdPre, err := ReadFile(in)
mdPre, err := util.ReadFile(in)
if err != nil {
return err
}
@ -86,10 +86,7 @@ func ConvertFile(in string, out string, settings *Settings) error {
fmt.Println("Title: ", pd.Title)
// build according to template here
html, err := MdToHTML(md)
if err != nil {
return err
}
html := MdToHTML(md)
pd.Content = template.HTML(html)
tmpl, err := template.New("webpage").Parse(settings.DefaultTemplate)
@ -102,6 +99,6 @@ func ConvertFile(in string, out string, settings *Settings) error {
return err
}
err = WriteFile(output.Bytes(), out)
err = util.WriteFile(output.Bytes(), out)
return err
}

View file

@ -2,68 +2,124 @@ package builder
import (
"embed"
"html/template"
"log"
"path/filepath"
"github.com/ficcdaf/zona/internal/util"
"gopkg.in/yaml.v3"
)
const (
DefaultHeader = ""
DefaultFooter = ""
DefaultStylesheet = "/style/zonaDefault.css"
DefaultIcon = ""
DefaultTemplate = `<!doctype html>
<html>
<head>
<title>{{ .Title }}</title>
<link rel="icon" href="{{ .Icon }}" type="image/x-icon" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta charset="UTF-8" />
<link
href="{{ .Stylesheet }}"
rel="stylesheet"
type="text/css"
media="all"
/>
</head>
<body>
<div id="container">
<header id="header">{{ .Header }}</header>
<article id="content">
{{ .Content }}
<nav id="nextprev">
{{ .NextPost }}<br />
{{ .PrevPost }}
</nav>
</article>
<footer id="footer">{{ .Footer }}</footer>
</div>
</body>
</html>`
DefConfigName = "config.yml"
DefHeaderName = "header.md"
DefFooterName = "footer.md"
DefStylesheetName = "style.css"
DefIconName = "icon.png"
DefTemplateName = "default.html"
)
//go:embed embed
var embedDir embed.FS
type Settings struct {
Header string
Footer string
Stylesheet string
Icon string
DefaultTemplate string
Header template.HTML
HeaderName string
Footer template.HTML
FooterName string
Stylesheet []byte
StylesheetName string
Icon []byte
IconName string
DefaultTemplate template.HTML
DefaultTemplateName string
}
func NewSettings(header string, footer string, style string, icon string, temp string) *Settings {
return &Settings{
header,
footer,
style,
icon,
temp,
func buildSettings(f []byte) (*Settings, error) {
s := &Settings{}
var c map[string]interface{}
// Parse YAML
if err := yaml.Unmarshal(f, &c); err != nil {
return nil, err
}
if headerName, ok := c["header"].(string); ok {
header, err := util.ReadFile(headerName)
s.HeaderName = headerName
if err != nil {
return nil, util.ErrorPrepend("Could not read header specified in config: ", err)
}
s.Header = template.HTML(MdToHTML(header))
} else {
header := readEmbed(DefHeaderName)
s.Header = template.HTML(MdToHTML(header))
s.HeaderName = DefHeaderName
}
if footerName, ok := c["footer"].(string); ok {
footer, err := util.ReadFile(footerName)
s.FooterName = footerName
if err != nil {
return nil, util.ErrorPrepend("Could not read footer specified in config: ", err)
}
s.Footer = template.HTML(MdToHTML(footer))
} else {
footer := readEmbed(DefFooterName)
s.Footer = template.HTML(MdToHTML(footer))
s.FooterName = DefFooterName
}
if stylesheetName, ok := c["stylesheet"].(string); ok {
stylesheet, err := util.ReadFile(stylesheetName)
if err != nil {
return nil, util.ErrorPrepend("Could not read stylesheet specified in config: ", err)
}
s.StylesheetName = stylesheetName
s.Stylesheet = stylesheet
} else {
stylesheet := readEmbed(DefStylesheetName)
s.Stylesheet = stylesheet
s.StylesheetName = DefStylesheetName
}
if iconName, ok := c["icon"].(string); ok {
icon, err := util.ReadFile(iconName)
if err != nil {
return nil, util.ErrorPrepend("Could not read icon specified in config: ", err)
}
s.Icon = icon
s.IconName = iconName
} else {
icon := readEmbed(DefIconName)
s.Icon = icon
s.IconName = DefIconName
}
if
return s, nil
}
func GetSettings() *Settings {
// readEmbed reads a file inside the embedded dir
func readEmbed(name string) []byte {
f, err := embedDir.ReadFile(name)
if err != nil {
log.Fatalln("Fatal internal error: Could not read embedded default config!")
}
return f
}
func GetSettings(root string) *Settings {
// TODO: Read a config file to override defaults
// "Defaults" should be a default config file via embed package,
// so the settings func should need to handle one case:
// check if config file exists, if not, use embedded one
return NewSettings(DefaultHeader, DefaultFooter, DefaultStylesheet, DefaultIcon, DefaultTemplate)
var config []byte
configPath := filepath.Join(root, DefConfigName)
if !util.FileExists(configPath) {
// Config file does not exist, we used embedded default
config = readEmbed(configPath)
} else {
config, err := util.ReadFile(configPath)
if err != nil {
log.Fatalln("Fatal internal error: Config file exists but could not be read!")
}
}
// return NewSettings(DefaultHeader, DefaultFooter, DefaultStylesheet, DefaultIcon, DefaultTemplate)
}

View file

@ -14,7 +14,7 @@ import (
)
// This function takes a Markdown document and returns an HTML document.
func MdToHTML(md []byte) ([]byte, error) {
func MdToHTML(md []byte) []byte {
// create parser with extensions
extensions := parser.CommonExtensions | parser.AutoHeadingIDs | parser.NoEmptyLineBeforeBlock
p := parser.NewWithExtensions(extensions)
@ -25,7 +25,7 @@ func MdToHTML(md []byte) ([]byte, error) {
opts := html.RendererOptions{Flags: htmlFlags}
renderer := newZonaRenderer(opts)
return markdown.Render(doc, renderer), nil
return markdown.Render(doc, renderer)
}
// PathIsValid checks if a path is valid.
@ -78,55 +78,3 @@ func newZonaRenderer(opts html.RendererOptions) *html.Renderer {
opts.RenderNodeHook = htmlRenderHook
return html.NewRenderer(opts)
}
// WriteFile writes a given byte array to the given path.
func WriteFile(b []byte, p string) error {
f, err := os.Create(p)
if err != nil {
return err
}
_, err = f.Write(b)
defer f.Close()
if err != nil {
return err
}
return nil
}
// ReadFile reads a byte array from a given path.
func ReadFile(p string) ([]byte, error) {
f, err := os.Open(p)
if err != nil {
return nil, err
}
var result []byte
buf := make([]byte, 1024)
for {
n, err := f.Read(buf)
// check for a non EOF error
if err != nil && err != io.EOF {
return nil, err
}
// n==0 when there are no chunks left to read
if n == 0 {
defer f.Close()
break
}
result = append(result, buf[:n]...)
}
return result, nil
}
// CopyFile reads the file at the input path, and write
// it to the output path.
func CopyFile(inPath string, outPath string) error {
inB, err := ReadFile(inPath)
if err != nil {
return err
}
if err := WriteFile(inB, outPath); err != nil {
return err
} else {
return nil
}
}

View file

@ -33,7 +33,7 @@ func processFile(inPath string, entry fs.DirEntry, err error, outRoot string, se
if err := util.CreateParents(outPath); err != nil {
return err
}
if err := CopyFile(inPath, outPath); err != nil {
if err := util.CopyFile(inPath, outPath); err != nil {
return errors.Join(errors.New("Error processing file "+inPath), err)
} else {
return nil

58
internal/util/file.go Normal file
View file

@ -0,0 +1,58 @@
package util
import (
"io"
"os"
)
// WriteFile writes a given byte array to the given path.
func WriteFile(b []byte, p string) error {
f, err := os.Create(p)
if err != nil {
return err
}
_, err = f.Write(b)
defer f.Close()
if err != nil {
return err
}
return nil
}
// ReadFile reads a byte array from a given path.
func ReadFile(p string) ([]byte, error) {
f, err := os.Open(p)
if err != nil {
return nil, err
}
var result []byte
buf := make([]byte, 1024)
for {
n, err := f.Read(buf)
// check for a non EOF error
if err != nil && err != io.EOF {
return nil, err
}
// n==0 when there are no chunks left to read
if n == 0 {
defer f.Close()
break
}
result = append(result, buf[:n]...)
}
return result, nil
}
// CopyFile reads the file at the input path, and write
// it to the output path.
func CopyFile(inPath string, outPath string) error {
inB, err := ReadFile(inPath)
if err != nil {
return err
}
if err := WriteFile(inB, outPath); err != nil {
return err
} else {
return nil
}
}

View file

@ -40,6 +40,13 @@ func ReplaceRoot(inPath, outRoot string) string {
return outPath
}
// FileExists returns a boolean indicating
// whether something exists at the path.
func FileExists(path string) bool {
_, err := os.Stat(path)
return !os.IsNotExist(err)
}
func CreateParents(path string) error {
dir := filepath.Dir(path)
// Check if the parent directory already exists

View file

@ -1,6 +1,9 @@
package util
import "strings"
import (
"errors"
"strings"
)
func NormalizeContent(content string) string {
var normalized []string
@ -13,3 +16,8 @@ func NormalizeContent(content string) string {
}
return strings.Join(normalized, "\n")
}
// ErrorPrepend returns a new error with a message prepended to the given error.
func ErrorPrepend(m string, err error) error {
return errors.Join(errors.New(m), err)
}