summaryrefslogtreecommitdiff
path: root/build.py
blob: 2dd85048b2c7685252a935d69202d9cdd47ff626 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
#!/usr/bin/env python3

import json
import os
import shutil
from argparse import ArgumentParser
from dataclasses import dataclass
from datetime import datetime
from pathlib import Path

import jinja2
from loguru import logger
from typst import Compiler
from watchfiles import watch


@dataclass
class CompiledPage:
    url: str
    title: str
    date: datetime


class Builder:
    def __init__(self, site_dir: Path, static_dir: Path, public_dir: Path) -> None:
        self.site_dir = site_dir
        self.content_dir = site_dir / 'content'
        self.static_dir = static_dir
        self.public_dir = public_dir
        self.compiler = Compiler(root=site_dir)

    def _compile_typst_page(self, path: Path) -> CompiledPage:
        relative_path = path.relative_to(self.content_dir)
        logger.info(f'Typst: {relative_path}')

        output_path = self.public_dir / relative_path.with_suffix('.html')
        output_path.parent.mkdir(parents=True, exist_ok=True)

        self.compiler.compile(input=path, output=output_path)

        metadata = json.loads(
            self.compiler.query(
                selector='<post-meta>',
                field='value',
                one=True,
            )
        )

        return CompiledPage(
            url=str(relative_path.with_suffix('.html')),
            title=metadata['title'],
            date=datetime(
                year=metadata['date_year'],
                month=metadata['date_month'],
                day=metadata['date_day'],
            ),
        )

    def _compile_typst_pages(self) -> list[CompiledPage]:
        return [self._compile_typst_page(path) for path in self.content_dir.rglob('*.typ')]

    def _compile_index_page(self, pages: list[CompiledPage]) -> None:
        pages.sort(key=lambda page: page.date)
        template = jinja2.Template((self.site_dir / 'index.html').read_text())
        (self.public_dir / 'index.html').write_text(template.render(pages=pages))

    def build(self) -> None:
        logger.info(f'Removing {str(self.public_dir)!r}...')
        shutil.rmtree(self.public_dir, ignore_errors=True)
        self.public_dir.mkdir(parents=True, exist_ok=True)

        logger.info('Linking static directory...')
        (self.public_dir / 'static').symlink_to(self.static_dir)

        pages = self._compile_typst_pages()

        logger.info('Building index page...')
        self._compile_index_page(pages)


def main() -> None:
    parser = ArgumentParser()
    parser.add_argument('-w', '--watch', action='store_true', help='watch for changes and rebuild')
    args = parser.parse_args()

    repo_dir = Path(__file__).parent
    site_dir = repo_dir / 'site'
    public_dir = repo_dir / 'public'
    static_dir = repo_dir / 'static'

    os.environ['TYPST_FEATURES'] = 'html'

    builder = Builder(site_dir=site_dir, static_dir=static_dir, public_dir=public_dir)
    builder.build()

    if args.watch:
        logger.info('Watching for changes...')

        for changes in watch(site_dir):
            print(changes)
            builder.build()


if __name__ == '__main__':
    main()