summaryrefslogtreecommitdiffstats
path: root/ssg.py
diff options
context:
space:
mode:
Diffstat (limited to 'ssg.py')
-rw-r--r--ssg.py71
1 files changed, 71 insertions, 0 deletions
diff --git a/ssg.py b/ssg.py
new file mode 100644
index 0000000..43cba2f
--- /dev/null
+++ b/ssg.py
@@ -0,0 +1,71 @@
+"""A basic static site generator"""
+
+__version__ = "0.4.0"
+
+import sys
+from argparse import ArgumentParser, BooleanOptionalAction, Namespace
+from collections.abc import Callable
+from pathlib import Path
+from typing import Any
+
+import jinja2
+import tomllib
+from jinja2 import Environment, FileSystemLoader
+
+
+def parse_args(p=ArgumentParser(), argv=sys.argv):
+ p.add_argument(
+ "-o", "--output", default=Path("output"), help="Output directory", type=Path
+ )
+ p.add_argument("-p", "--prefix", default="", help="href prefix")
+ p.add_argument(
+ "--minify", default=True, action=BooleanOptionalAction, help="minify output"
+ )
+ return p.parse_args(argv[1:])
+
+
+class Generator:
+ output: Path
+ minify: bool
+ minifiers: dict[str, Callable[[str | bytes], str | bytes]]
+ env: Environment
+
+ def __init__(self, args: Namespace) -> None:
+ self.output = args.output
+ self.minify = args.minify
+ self.minifiers = dict()
+ self.env = Environment(
+ loader=FileSystemLoader("."), autoescape=jinja2.select_autoescape()
+ )
+ self.env.globals["prefix"] = args.prefix
+
+ def write(self, dest: str, content: str | bytes) -> None:
+ dest_path: Path = self.output / Path(dest)
+ if self.minify and dest_path.suffix and dest_path.suffix in self.minifiers:
+ content = self.minifiers[dest_path.suffix](content)
+ dest_path.parent.mkdir(parents=True, exist_ok=True)
+ with open(dest_path, "wb") as f:
+ if isinstance(content, str):
+ content = content.encode()
+ f.write(content)
+
+ def copy(self, dest: str, source: str | None = None) -> None:
+ if source is None:
+ source = dest
+ with open(source, "rb") as f:
+ self.write(dest, f.read())
+
+ def generate(
+ self, dest: str, template: str | None = None, env: dict[str, Any] = dict()
+ ) -> None:
+ if template is None:
+ template = dest
+ self.write(dest, self.env.get_template(template).render(**env))
+
+
+def parse(source: str | Path) -> dict[str, Any]:
+ with open(source) as f:
+ toml, content = f.read().split("\n\n", maxsplit=1)
+ vars = tomllib.loads(toml)
+ vars["content"] = content
+ return vars