Files
STSG/stsg/build.py

213 lines
5.7 KiB
Python

from __future__ import annotations
import logging
import shutil
from pathlib import Path
import os
import markdown
from typing import Optional, Union, Dict, Generator
from .config import SOURCE_DIRECTORY, DIST_DIRECTORY, LANGUAGE_INFORMATION
logger = logging.getLogger("stsg.build")
class CustomPath:
def __init__(self, path: Path):
self.path = path
def __repr__(self) -> str:
return str(self.path)
@property
def source_path(self) -> Path:
return Path(SOURCE_DIRECTORY, self.path)
@property
def dist_path(self) -> Path:
return Path(DIST_DIRECTORY, self.path)
@property
def name(self) -> str:
return Path(self.path).name
@property
def parent(self) -> CustomPath:
return CustomPath(Path(self.path).parent)
@property
def stem(self) -> str:
return Path(self.path).stem
def iterdir(self) -> Generator[CustomPath, None, None]:
for p in self.source_path.iterdir():
yield CustomPath(Path(self.path, p.name))
def get_child(self, name: str, force_directory: bool = False, force_file: bool = False) -> Optional[CustomPath]:
child = Path(self.source_path, name)
if not child.exists():
return None
if force_directory and not child.is_dir():
return None
if force_file and not child.is_file():
return None
return CustomPath(Path(self.path, name))
def read_text(self) -> str:
return self.source_path.read_text()
def copy_static(path: CustomPath):
src = path.source_path
dst = path.dist_path
if not src.exists():
logger.warning("The static folder '%s' wasn't defined.", src)
return
logger.info("Copying static files from '%s' to '%s'", src, dst)
dst.mkdir(parents=True, exist_ok=True)
for root, dirs, files in os.walk(src):
root_path = Path(root)
if any(part.startswith(".") for part in root_path.parts):
continue
rel_path = root_path.relative_to(src)
dest_dir = dst / rel_path
dest_dir.mkdir(parents=True, exist_ok=True)
for file in files:
if file.startswith("."):
continue
src_file = root_path / file
dest_file = dest_dir / file
shutil.copy2(src_file, dest_file)
class Article(CustomPath):
def __init__(self, path: CustomPath):
super().__init__(path.path)
def get_content(self) -> str:
if self.name.endswith(".md"):
return markdown.markdown(self.read_text())
return self.read_text()
@property
def article_directory(self) -> Path:
return self.dist_path.parent / self.stem
class CustomLanguageCode:
def __init__(self, file: CustomPath):
self.file = file
@property
def language_code(self) -> str:
return self.file.stem
@property
def relative_url(self) -> str:
return "/" + str(self)
def __repr__(self) -> str:
return f"{self.language_code}"
def _get_additional_data(self) -> dict:
parsed_language_code = self.language_code.lower().replace("-", "_")
if parsed_language_code in LANGUAGE_INFORMATION:
return LANGUAGE_INFORMATION[parsed_language_code]
parsed_language_code = parsed_language_code.split("_")[0]
if parsed_language_code in LANGUAGE_INFORMATION:
return LANGUAGE_INFORMATION[parsed_language_code]
return {}
@property
def flag(self) -> str:
return self._get_additional_data()["flag"]
@property
def native_name(self) -> str:
return self._get_additional_data()["native_name"]
@property
def html_code(self) -> str:
return f'<ul><a href="{self.relative_url}"><bold>{self.flag} {self.native_name}</bold></a></ul>'
class Template:
def __init__(self, root: CustomPath):
self.root = root
self.articles = []
def copy(self):
return Template(root=self.root)
def _replace_keywords(self, text: str, **placeholder_values: str) -> str:
for key, value in placeholder_values.items():
text = text.replace(f"<{key}/>", value)
text = text.replace(f"<{key} />", value)
return text
@property
def article_template(self) -> str:
article = self.root.get_child("article.html", force_file=True)
return article.source_path.read_text() if article else "<content/>"
def convert_article(self, path: Article):
logger.info("converting %s", path)
article_text = self._replace_keywords(
self.article_template,
content = path.get_content(),
)
path.article_directory.mkdir(parents=True, exist_ok=True)
with Path(path.article_directory, "index.html").open("w") as f:
f.write(article_text)
def walk_directory(root: CustomPath, template: Optional[Template] = None):
template_dir = root.get_child("_templates", force_directory=True)
if template_dir is not None:
template = Template(template_dir)
if template is None:
logger.error("Didn't find template for %d", root)
return
for current_path in root.iterdir():
if current_path.name.startswith("_") or current_path.name == "static":
continue
if current_path.source_path.is_file():
template.convert_article(Article(current_path))
continue
if current_path.source_path.is_dir():
walk_directory(current_path, template=template.copy())
static_dir = root.get_child("static", force_directory=True)
if static_dir:
copy_static(static_dir)
def build():
logger.info("building static page")
walk_directory(CustomPath(Path()))