Add referenced file handling to Content
This commit is contained in:
@@ -1,6 +1,8 @@
|
||||
import logging
|
||||
from urllib.parse import urlparse
|
||||
from typing import TYPE_CHECKING, Any
|
||||
from omicron.ssg.output.content import Content
|
||||
from omicron.ssg.output.file import File
|
||||
from pathlib import Path
|
||||
import omicron.ssg.markdown as md
|
||||
|
||||
@@ -28,8 +30,41 @@ class Article(Content):
|
||||
)
|
||||
self.title: str = meta["title"]
|
||||
|
||||
def handle_reference(self, path: Path) -> Content | File:
|
||||
site = self.site
|
||||
if path in site.by_source:
|
||||
return site.by_source[path]
|
||||
return self.copy_referenced_file(path)
|
||||
|
||||
def resolve_references(self, tokens: list[md.Token]) -> None:
|
||||
# MarkdownIt guarantees links are always in the second level
|
||||
for token in tokens:
|
||||
if token.type != "inline" or token.children is None:
|
||||
continue
|
||||
for child in token.children:
|
||||
if child.type == "link_open":
|
||||
attr = "href"
|
||||
elif child.type == "image":
|
||||
attr = "src"
|
||||
else:
|
||||
continue
|
||||
|
||||
href = child.attrs.get(attr)
|
||||
assert type(href) is str, "unexpected link/image href type"
|
||||
parsed = urlparse(href)
|
||||
|
||||
if parsed.scheme or parsed.netloc:
|
||||
continue
|
||||
if not parsed.path or parsed.path.startswith("/"):
|
||||
continue
|
||||
target = self.locate_reference(Path(parsed.path))
|
||||
|
||||
output = self.handle_reference(target)
|
||||
child.attrs[attr] = parsed._replace(path=output.url).geturl()
|
||||
|
||||
def write(self) -> None:
|
||||
tokens = md.parse(self.read_body())
|
||||
self.resolve_references(tokens)
|
||||
if self.summary is None:
|
||||
self.summary = md.render_summary(tokens)
|
||||
content = md.render(tokens)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import re
|
||||
from typing import TYPE_CHECKING
|
||||
from omicron.ssg.output.output import Output, OutputError, is_normalized
|
||||
from omicron.ssg.output.file import File
|
||||
from pathlib import Path
|
||||
from datetime import date
|
||||
|
||||
@@ -49,6 +50,29 @@ class Content(Output):
|
||||
path = Path(f"{section}/{slug}/index.html")
|
||||
return path
|
||||
|
||||
def locate_reference(self, path: Path) -> Path:
|
||||
if path.is_absolute():
|
||||
raise ContentError("Can't resolve absolute references")
|
||||
base = self.site.site_path / "content"
|
||||
file = (self.source.parent / path).resolve()
|
||||
if not file.is_relative_to(base):
|
||||
raise ContentError("Reference escapes content directory")
|
||||
return file
|
||||
|
||||
def copy_referenced_file(self, path: Path) -> File:
|
||||
if not path.is_file():
|
||||
raise ContentError(f"Referenced file '{path}' does not exist")
|
||||
|
||||
dest = self.destination.parent / path.name
|
||||
existing = self.site.by_path.get(dest)
|
||||
if isinstance(existing, File) and existing.source == path:
|
||||
return existing
|
||||
|
||||
file = File(self.site, dest, path)
|
||||
self.site.add_by_path(file)
|
||||
file.write()
|
||||
return file
|
||||
|
||||
def read_body(self) -> str:
|
||||
with self.source.open("r", encoding="utf-8") as f:
|
||||
f.readline() # opening ---
|
||||
|
||||
+1
-1
@@ -32,7 +32,7 @@ class ConfigError(RuntimeError):
|
||||
|
||||
class Site:
|
||||
def __init__(self, site: Path):
|
||||
self.site_path = site.absolute()
|
||||
self.site_path = site.resolve()
|
||||
self.content: list[Content] = []
|
||||
self.directories: list[Directory] = []
|
||||
self.other_outputs: list[Output] = []
|
||||
|
||||
Reference in New Issue
Block a user