continue working on config and default parsing
This commit is contained in:
parent
4d1b18fd12
commit
c6c801e248
8 changed files with 183 additions and 109 deletions
|
@ -41,7 +41,7 @@ func main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
settings := builder.GetSettings()
|
settings := builder.GetSettings(*rootPath)
|
||||||
err := builder.Traverse(*rootPath, "foobar", settings)
|
err := builder.Traverse(*rootPath, "foobar", settings)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("Error: %s\n", err.Error())
|
fmt.Printf("Error: %s\n", err.Error())
|
||||||
|
|
|
@ -74,7 +74,7 @@ func buildPageData(m Metadata, path string, settings *Settings) *PageData {
|
||||||
}
|
}
|
||||||
|
|
||||||
func ConvertFile(in string, out string, settings *Settings) error {
|
func ConvertFile(in string, out string, settings *Settings) error {
|
||||||
mdPre, err := ReadFile(in)
|
mdPre, err := util.ReadFile(in)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -86,10 +86,7 @@ func ConvertFile(in string, out string, settings *Settings) error {
|
||||||
fmt.Println("Title: ", pd.Title)
|
fmt.Println("Title: ", pd.Title)
|
||||||
|
|
||||||
// build according to template here
|
// build according to template here
|
||||||
html, err := MdToHTML(md)
|
html := MdToHTML(md)
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
pd.Content = template.HTML(html)
|
pd.Content = template.HTML(html)
|
||||||
|
|
||||||
tmpl, err := template.New("webpage").Parse(settings.DefaultTemplate)
|
tmpl, err := template.New("webpage").Parse(settings.DefaultTemplate)
|
||||||
|
@ -102,6 +99,6 @@ func ConvertFile(in string, out string, settings *Settings) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = WriteFile(output.Bytes(), out)
|
err = util.WriteFile(output.Bytes(), out)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,68 +2,124 @@ package builder
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"embed"
|
"embed"
|
||||||
|
"html/template"
|
||||||
|
"log"
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
|
"github.com/ficcdaf/zona/internal/util"
|
||||||
|
"gopkg.in/yaml.v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
DefaultHeader = ""
|
DefConfigName = "config.yml"
|
||||||
DefaultFooter = ""
|
DefHeaderName = "header.md"
|
||||||
DefaultStylesheet = "/style/zonaDefault.css"
|
DefFooterName = "footer.md"
|
||||||
DefaultIcon = ""
|
DefStylesheetName = "style.css"
|
||||||
DefaultTemplate = `<!doctype html>
|
DefIconName = "icon.png"
|
||||||
<html>
|
DefTemplateName = "default.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>`
|
|
||||||
)
|
)
|
||||||
|
|
||||||
//go:embed embed
|
//go:embed embed
|
||||||
var embedDir embed.FS
|
var embedDir embed.FS
|
||||||
|
|
||||||
type Settings struct {
|
type Settings struct {
|
||||||
Header string
|
Header template.HTML
|
||||||
Footer string
|
HeaderName string
|
||||||
Stylesheet string
|
Footer template.HTML
|
||||||
Icon string
|
FooterName string
|
||||||
DefaultTemplate 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 {
|
func buildSettings(f []byte) (*Settings, error) {
|
||||||
return &Settings{
|
s := &Settings{}
|
||||||
header,
|
var c map[string]interface{}
|
||||||
footer,
|
// Parse YAML
|
||||||
style,
|
if err := yaml.Unmarshal(f, &c); err != nil {
|
||||||
icon,
|
return nil, err
|
||||||
temp,
|
|
||||||
}
|
}
|
||||||
|
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
|
// TODO: Read a config file to override defaults
|
||||||
// "Defaults" should be a default config file via embed package,
|
// "Defaults" should be a default config file via embed package,
|
||||||
// so the settings func should need to handle one case:
|
// so the settings func should need to handle one case:
|
||||||
// check if config file exists, if not, use embedded one
|
// 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)
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
// This function takes a Markdown document and returns an HTML document.
|
// 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
|
// create parser with extensions
|
||||||
extensions := parser.CommonExtensions | parser.AutoHeadingIDs | parser.NoEmptyLineBeforeBlock
|
extensions := parser.CommonExtensions | parser.AutoHeadingIDs | parser.NoEmptyLineBeforeBlock
|
||||||
p := parser.NewWithExtensions(extensions)
|
p := parser.NewWithExtensions(extensions)
|
||||||
|
@ -25,7 +25,7 @@ func MdToHTML(md []byte) ([]byte, error) {
|
||||||
opts := html.RendererOptions{Flags: htmlFlags}
|
opts := html.RendererOptions{Flags: htmlFlags}
|
||||||
renderer := newZonaRenderer(opts)
|
renderer := newZonaRenderer(opts)
|
||||||
|
|
||||||
return markdown.Render(doc, renderer), nil
|
return markdown.Render(doc, renderer)
|
||||||
}
|
}
|
||||||
|
|
||||||
// PathIsValid checks if a path is valid.
|
// PathIsValid checks if a path is valid.
|
||||||
|
@ -78,55 +78,3 @@ func newZonaRenderer(opts html.RendererOptions) *html.Renderer {
|
||||||
opts.RenderNodeHook = htmlRenderHook
|
opts.RenderNodeHook = htmlRenderHook
|
||||||
return html.NewRenderer(opts)
|
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -33,7 +33,7 @@ func processFile(inPath string, entry fs.DirEntry, err error, outRoot string, se
|
||||||
if err := util.CreateParents(outPath); err != nil {
|
if err := util.CreateParents(outPath); err != nil {
|
||||||
return err
|
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)
|
return errors.Join(errors.New("Error processing file "+inPath), err)
|
||||||
} else {
|
} else {
|
||||||
return nil
|
return nil
|
||||||
|
|
58
internal/util/file.go
Normal file
58
internal/util/file.go
Normal 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
|
||||||
|
}
|
||||||
|
}
|
|
@ -40,6 +40,13 @@ func ReplaceRoot(inPath, outRoot string) string {
|
||||||
return outPath
|
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 {
|
func CreateParents(path string) error {
|
||||||
dir := filepath.Dir(path)
|
dir := filepath.Dir(path)
|
||||||
// Check if the parent directory already exists
|
// Check if the parent directory already exists
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
package util
|
package util
|
||||||
|
|
||||||
import "strings"
|
import (
|
||||||
|
"errors"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
func NormalizeContent(content string) string {
|
func NormalizeContent(content string) string {
|
||||||
var normalized []string
|
var normalized []string
|
||||||
|
@ -13,3 +16,8 @@ func NormalizeContent(content string) string {
|
||||||
}
|
}
|
||||||
return strings.Join(normalized, "\n")
|
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)
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue