add builder

This commit is contained in:
Daniel Fichtinger 2025-06-21 16:11:45 -04:00
parent d558d1c5e1
commit b045739b45
4 changed files with 93 additions and 15 deletions

View file

@ -1,4 +1,6 @@
from zona.models import Item, Metadata
from zona.models import Item, Metadata, ItemType
from zona import markdown as zmd
from zona import util
from pathlib import Path
import frontmatter
from dacite import from_dict
@ -29,20 +31,35 @@ def discover(root: Path, out_dir: Path) -> list[Item]:
for path in base.rglob("*"):
if path.is_file():
print(f"{subdir}: {path.relative_to(root)}")
if path.name.endswith(".md") and not path.is_relative_to(
root / "content" / "static"
):
meta, content = split_metadata(path)
else:
meta = None
content = path.read_bytes()
# we only parse markdown files not in static/
destination = out_dir / path.relative_to(base)
item = Item(
source=path,
destination=destination,
url=str(destination.relative_to(out_dir)),
metadata=meta,
content=content,
)
if path.name.endswith(".md") and not path.is_relative_to(
root / "content" / "static"
):
item.metadata, item.content = split_metadata(path)
item.type = ItemType.MARKDOWN
item.copy = False
item.destination = destination.with_suffix(".html")
items.append(item)
return items
def build(items: list[Item]):
for item in items:
dst = item.destination
# create parent dirs if needed
if item.type == ItemType.MARKDOWN:
assert item.content is not None
# parse markdown and render as html
raw_html = zmd.md_to_html(item.content)
# TODO: apply to template here
util.ensure_parents(dst)
dst.write_text(raw_html, encoding="utf-8")
else:
if item.copy:
util.copy_static_file(item.source, dst)

View file

@ -1,6 +1,8 @@
from pathlib import Path
from enum import Enum
from datetime import date
from dataclasses import dataclass
from typing import Literal
@dataclass
@ -11,10 +13,18 @@ class Metadata:
# add more options later...
class ItemType(Enum):
MARKDOWN = "markdown"
HTML = "html"
IMAGE = "image"
@dataclass
class Item:
source: Path
destination: Path
url: str # relative to site root
metadata: Metadata | None # frontmatter
content: str | bytes
metadata: Metadata | None = None # frontmatter
content: str | None = None
type: ItemType | None = None
copy: bool = True

13
src/zona/util.py Normal file
View file

@ -0,0 +1,13 @@
from pathlib import Path
from shutil import copy2
def ensure_parents(target: Path):
"""Ensure the target's parent directories exist."""
target.parent.mkdir(parents=True, exist_ok=True)
def copy_static_file(src: Path, dst: Path):
"""Copy a static file from one location to another."""
ensure_parents(dst)
copy2(src, dst)

View file

@ -1,6 +1,6 @@
from datetime import date
from zona.models import Metadata
from zona.builder import split_metadata, discover
from zona.builder import split_metadata, discover, build
from pathlib import Path
@ -43,12 +43,13 @@ description: This is a test.
""")
style = staticd / "style.css"
style.write_text("""
style_content = """
p {
color: red;
text-align: center;
}
""")
"""
style.write_text(style_content)
items = discover(tmp_path, outd)
@ -61,6 +62,7 @@ p {
assert md_item.url == "post.md"
assert isinstance(md_item.metadata, Metadata)
assert md_item.metadata.title == "Test Post"
assert md_item.content is not None
assert md_item.content.strip() == "# Hello World"
st_item = items[1]
@ -69,3 +71,39 @@ p {
assert st_item.destination.is_relative_to(outd)
assert st_item.url == "static/style.css"
assert st_item.metadata is None
def test_build(tmp_path: Path):
contentd = tmp_path / "content"
staticd = contentd / "static"
templatesd = tmp_path / "templates"
outd = tmp_path / "out"
for d in [contentd, staticd, templatesd, outd]:
d.mkdir()
md_file = contentd / "post.md"
md_content = """---
title: Test Post
date: 2025-06-03
description: This is a test.
---
# Hello World
"""
md_file.write_text(md_content)
style = staticd / "style.css"
style_content = """
p {
color: red;
text-align: center;
}
"""
style.write_text(style_content)
items = discover(tmp_path, outd)
build(items)
html = (outd / "post.html").read_text()
assert html.strip() == "<h1>Hello World</h1>"
s = (outd / "static" / "style.css").read_text()
assert s.strip() == style_content.strip()