Add Symlink(Output) class

This commit is contained in:
2026-08-14 23:55:48 +02:00
parent 1a5f3bfc67
commit 5660ef2974
4 changed files with 48 additions and 3 deletions
+4 -1
View File
@@ -1,13 +1,15 @@
from omicron.ssg.output.output import Output from omicron.ssg.output.output import Output, OutputError
from omicron.ssg.output.content import Content, ContentError from omicron.ssg.output.content import Content, ContentError
from omicron.ssg.output.factory import create_content, is_content from omicron.ssg.output.factory import create_content, is_content
from omicron.ssg.output.file import File from omicron.ssg.output.file import File
from omicron.ssg.output.index import Index, discover_index from omicron.ssg.output.index import Index, discover_index
from omicron.ssg.output.memory import Memory from omicron.ssg.output.memory import Memory
from omicron.ssg.output.symlink import Symlink
from omicron.ssg.output.tags import Tags, discover_tags from omicron.ssg.output.tags import Tags, discover_tags
__all__ = [ __all__ = [
"Output", "Output",
"OutputError",
"Content", "Content",
"ContentError", "ContentError",
"create_content", "create_content",
@@ -16,6 +18,7 @@ __all__ = [
"Index", "Index",
"discover_index", "discover_index",
"Memory", "Memory",
"Symlink",
"Tags", "Tags",
"discover_tags", "discover_tags",
] ]
+2 -2
View File
@@ -1,6 +1,6 @@
import re import re
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
from omicron.ssg.output.output import Output from omicron.ssg.output.output import Output, OutputError
from pathlib import Path from pathlib import Path
from datetime import date from datetime import date
@@ -10,7 +10,7 @@ else:
Site = "omicron.ssg.site.Site" Site = "omicron.ssg.site.Site"
class ContentError(RuntimeError): class ContentError(OutputError):
pass pass
+4
View File
@@ -9,6 +9,10 @@ else:
Site = "omicron.ssg.site.Site" # for runtime checking with beartype Site = "omicron.ssg.site.Site" # for runtime checking with beartype
class OutputError(RuntimeError):
pass
class Output(ABC): class Output(ABC):
def __init__(self, site: Site, destination: Path): def __init__(self, site: Site, destination: Path):
self._site_ref = weakref.ref(site) self._site_ref = weakref.ref(site)
+38
View File
@@ -0,0 +1,38 @@
import logging
import os
from typing import TYPE_CHECKING
from omicron.ssg.output.output import Output, OutputError
from pathlib import Path
log = logging.getLogger(__name__)
if TYPE_CHECKING:
from omicron.ssg.site import Site # for static checking with mypy
else:
Site = "omicron.ssg.site.Site" # for runtime checking with beartype
class Symlink(Output):
def __init__(self, site: Site, link: Path, target: Path):
if target.is_absolute():
raise ValueError("Symlinks must be relative")
if (
not (site.output_path / target)
.resolve()
.is_relative_to(site.output_path.resolve())
):
raise ValueError("Symlink target escapes the output directory")
super().__init__(site, link)
self.target = target
def write(self) -> None:
site = self.site
if self.target not in site.by_path:
raise OutputError(f"Symlink target '{self.target}' is not a known output")
link = site.output_path / self.destination
link.parent.mkdir(parents=True, exist_ok=True)
if link.exists() or link.is_symlink():
link.unlink()
rel_target = os.path.relpath(site.output_path / self.target, link.parent)
link.symlink_to(rel_target)
log.debug("Symlinked %s -> %s", link, rel_target)