landing/src/build.py

93 lines
2.5 KiB
Python

import json
import os
from dataclasses import asdict, dataclass, fields
from os import environ as env
from pathlib import Path
from shutil import copytree
from moody import render
from watchdog.events import FileSystemEventHandler
from watchdog.observers import Observer
def dataclass_from_dict(klass, dikt):
try:
fieldtypes = {f.name: f.type for f in fields(klass)}
return klass(**{f: dataclass_from_dict(fieldtypes[f], dikt[f]) for f in dikt})
except:
if isinstance(dikt, (tuple, list)):
return [dataclass_from_dict(klass.__args__[0], f) for f in dikt]
return dikt # Not a dataclass field
@dataclass
class Link:
href: str
text: str
icon: str
cls: str
@dataclass
class Data:
links: list[Link]
description: str | None = None
def write_files(rendered: str, src_dir: Path, out_dir: Path):
# Copy the static files
copytree(src_dir / "www", out_dir, dirs_exist_ok=True)
# Write out the index file
with open(out_dir / "index.html", "w") as fp:
fp.write(rendered)
def build_project(src_dir: Path, build_dir: Path):
if not os.path.exists(build_dir):
os.mkdir(build_dir)
data_path = env.get("DATA_FILE", src_dir / "data.json")
# Load the data
with open(data_path) as fp:
data: Data = dataclass_from_dict(Data, json.load(fp)) # pyright: ignore
# Render the template with the correct data
with open(src_dir / "index.html") as fp:
rendered = render(fp.read(), links=data.links, description=data.description)
write_files(rendered, src_dir, build_dir)
class CatchAllHandler(FileSystemEventHandler):
def __init__(self, src_dir: Path, build_dir: Path):
self.src_dir = src_dir
self.build_dir = build_dir
self.count = 0
def on_modified(self, event):
print(f"Files changed, rebuilding project [{self.count}]")
build_project(self.src_dir, self.build_dir)
self.count += 1
if __name__ == "__main__":
src_dir = Path(__file__).parent.resolve()
build_dir = Path(env.get("BUILD_DIR", src_dir.parent.resolve() / "build"))
watch_files = bool(env.get("WATCH_SRC"))
build_project(src_dir, build_dir)
if watch_files:
# Create the structure to watch for changes
observer = Observer()
observer.schedule(CatchAllHandler(src_dir, build_dir), src_dir, recursive=True)
observer.start()
try:
while observer.is_alive():
observer.join()
finally:
observer.stop()
observer.join()