rift-ssg 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- rift_ssg-0.1.0/PKG-INFO +15 -0
- rift_ssg-0.1.0/README.md +0 -0
- rift_ssg-0.1.0/pyproject.toml +28 -0
- rift_ssg-0.1.0/pyproject.toml.orig +29 -0
- rift_ssg-0.1.0/src/rift_ssg/__init__.py +17 -0
- rift_ssg-0.1.0/src/rift_ssg/cli/__init__.py +27 -0
- rift_ssg-0.1.0/src/rift_ssg/cli/server.py +15 -0
- rift_ssg-0.1.0/src/rift_ssg/cli/watcher.py +9 -0
- rift_ssg-0.1.0/src/rift_ssg/content.py +24 -0
- rift_ssg-0.1.0/src/rift_ssg/page.py +21 -0
- rift_ssg-0.1.0/src/rift_ssg/router.py +10 -0
- rift_ssg-0.1.0/src/rift_ssg/template.py +29 -0
rift_ssg-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
Metadata-Version: 2.3
|
|
2
|
+
Name: rift-ssg
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: A simple static site generator
|
|
5
|
+
Author: Aleks Rutins
|
|
6
|
+
Author-email: Aleks Rutins <keeper@farthergate.com>
|
|
7
|
+
Requires-Dist: aiohttp>=3.14.5
|
|
8
|
+
Requires-Dist: cyclopts>=5.4.0
|
|
9
|
+
Requires-Dist: frontmatter>=3.0.8
|
|
10
|
+
Requires-Dist: jinja2>=3.1.6
|
|
11
|
+
Requires-Dist: markdown>=3.11.3
|
|
12
|
+
Requires-Dist: watchfiles>=1.3.0
|
|
13
|
+
Requires-Python: >=3.14
|
|
14
|
+
Description-Content-Type: text/markdown
|
|
15
|
+
|
rift_ssg-0.1.0/README.md
ADDED
|
File without changes
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "rift-ssg"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "A simple static site generator"
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
requires-python = ">=3.14"
|
|
7
|
+
dependencies = [
|
|
8
|
+
"aiohttp>=3.14.5",
|
|
9
|
+
"cyclopts>=5.4.0",
|
|
10
|
+
"frontmatter>=3.0.8",
|
|
11
|
+
"jinja2>=3.1.6",
|
|
12
|
+
"markdown>=3.11.3",
|
|
13
|
+
"watchfiles>=1.3.0",
|
|
14
|
+
]
|
|
15
|
+
|
|
16
|
+
[[project.authors]]
|
|
17
|
+
name = "Aleks Rutins"
|
|
18
|
+
email = "keeper@farthergate.com"
|
|
19
|
+
|
|
20
|
+
[project.scripts]
|
|
21
|
+
rift = "rift_ssg.cli:main"
|
|
22
|
+
|
|
23
|
+
[build-system]
|
|
24
|
+
requires = ["uv_build>=0.13.7,<0.14.0"]
|
|
25
|
+
build-backend = "uv_build"
|
|
26
|
+
|
|
27
|
+
[dependency-groups]
|
|
28
|
+
dev = ["jinja2-time>=0.2.0"]
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "rift-ssg"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "A simple static site generator"
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
authors = [
|
|
7
|
+
{ name = "Aleks Rutins", email = "keeper@farthergate.com" }
|
|
8
|
+
]
|
|
9
|
+
requires-python = ">=3.14"
|
|
10
|
+
dependencies = [
|
|
11
|
+
"aiohttp>=3.14.5",
|
|
12
|
+
"cyclopts>=5.4.0",
|
|
13
|
+
"frontmatter>=3.0.8",
|
|
14
|
+
"jinja2>=3.1.6",
|
|
15
|
+
"markdown>=3.11.3",
|
|
16
|
+
"watchfiles>=1.3.0",
|
|
17
|
+
]
|
|
18
|
+
|
|
19
|
+
[project.scripts]
|
|
20
|
+
rift = "rift_ssg.cli:main"
|
|
21
|
+
|
|
22
|
+
[build-system]
|
|
23
|
+
requires = ["uv_build>=0.13.7,<0.14.0"]
|
|
24
|
+
build-backend = "uv_build"
|
|
25
|
+
|
|
26
|
+
[dependency-groups]
|
|
27
|
+
dev = [
|
|
28
|
+
"jinja2-time>=0.2.0",
|
|
29
|
+
]
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
from os import write, path
|
|
3
|
+
from rift_ssg.page import Page
|
|
4
|
+
|
|
5
|
+
def build(*pages: Page, out='_build'):
|
|
6
|
+
for p in pages:
|
|
7
|
+
path_to_clean = Path(p.path)
|
|
8
|
+
out_path = Path(out, path_to_clean.relative_to(path_to_clean.anchor))
|
|
9
|
+
if p.path != '/sitemap.xml' and not p.path.endswith('.html'):
|
|
10
|
+
out_path /= 'index.html'
|
|
11
|
+
|
|
12
|
+
out_path.parent.mkdir(parents = True, exist_ok=True)
|
|
13
|
+
|
|
14
|
+
with open(out_path, 'w') as f:
|
|
15
|
+
f.write(p.content(**p.meta))
|
|
16
|
+
|
|
17
|
+
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import runpy
|
|
2
|
+
import asyncio
|
|
3
|
+
from cyclopts import App
|
|
4
|
+
|
|
5
|
+
from . import server, watcher
|
|
6
|
+
|
|
7
|
+
app = App()
|
|
8
|
+
|
|
9
|
+
@app.command
|
|
10
|
+
def build(script="build.py"):
|
|
11
|
+
"""Build the site."""
|
|
12
|
+
runpy.run_path(script)
|
|
13
|
+
|
|
14
|
+
@app.command
|
|
15
|
+
async def dev(script="build.py", dir="_build", port=3000):
|
|
16
|
+
build(script)
|
|
17
|
+
|
|
18
|
+
httpd = await server.run(port, dir)
|
|
19
|
+
watch = asyncio.create_task(watcher.run(script))
|
|
20
|
+
|
|
21
|
+
try:
|
|
22
|
+
await watch
|
|
23
|
+
finally:
|
|
24
|
+
httpd.cleanup()
|
|
25
|
+
|
|
26
|
+
def main():
|
|
27
|
+
asyncio.run(app.run_async())
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
from aiohttp import web
|
|
3
|
+
|
|
4
|
+
async def run(port=3000, dir="_build"):
|
|
5
|
+
app = web.Application()
|
|
6
|
+
async def index(_, /):
|
|
7
|
+
return web.FileResponse(Path(dir) / 'index.html')
|
|
8
|
+
app.add_routes([
|
|
9
|
+
web.get('/', index),
|
|
10
|
+
web.static('/', dir)
|
|
11
|
+
])
|
|
12
|
+
runner = web.AppRunner(app)
|
|
13
|
+
await runner.setup()
|
|
14
|
+
await web.TCPSite(runner, "127.0.0.1", port).start()
|
|
15
|
+
return runner
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
import runpy
|
|
3
|
+
from watchfiles import PythonFilter, awatch
|
|
4
|
+
|
|
5
|
+
async def run(build_script="_build.py"):
|
|
6
|
+
async for _ in awatch('.',
|
|
7
|
+
watch_filter=PythonFilter(extra_extensions=(".md", ".html", ".xl", ".j2"))):
|
|
8
|
+
runpy.run_path(build_script)
|
|
9
|
+
await asyncio.sleep(0)
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
from markdown.extensions.abbr import makeExtension
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
import markupsafe
|
|
4
|
+
import markdown
|
|
5
|
+
from glob import glob
|
|
6
|
+
from frontmatter import Frontmatter
|
|
7
|
+
from rift_ssg.template import TemplateContext
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def template_for(path: str, template: TemplateContext, prefix: str):
|
|
11
|
+
data = Frontmatter.read_file(path)
|
|
12
|
+
content = markupsafe.Markup(
|
|
13
|
+
markdown.markdown(data["body"]) if path.endswith(".md") else data["body"]
|
|
14
|
+
)
|
|
15
|
+
return (
|
|
16
|
+
template.set_all(data["attributes"])
|
|
17
|
+
.set("body", content)
|
|
18
|
+
.at(Path(path.removeprefix(prefix)).with_suffix(".html").__str__())
|
|
19
|
+
.set_all(data["attributes"])
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def collection(pattern: str, template: TemplateContext, prefix=""):
|
|
24
|
+
return tuple(template_for(path, template, prefix) for path in glob(pattern))
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
from typing import Any
|
|
2
|
+
from collections import defaultdict
|
|
3
|
+
from collections.abc import Callable
|
|
4
|
+
from dataclasses import dataclass, field
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
@dataclass
|
|
8
|
+
class Page:
|
|
9
|
+
path: str
|
|
10
|
+
content: Callable[..., str]
|
|
11
|
+
meta: defaultdict[str, Any] = field(default_factory=lambda: defaultdict(dict))
|
|
12
|
+
|
|
13
|
+
def set_all(self, params: dict):
|
|
14
|
+
self.meta.update(params)
|
|
15
|
+
return self
|
|
16
|
+
|
|
17
|
+
def set(self, param: str, value: Any):
|
|
18
|
+
self.meta[param] = value
|
|
19
|
+
return self
|
|
20
|
+
|
|
21
|
+
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
from rift_ssg.page import Page
|
|
3
|
+
|
|
4
|
+
def router(base: str, *pages: Page):
|
|
5
|
+
def page_path(p):
|
|
6
|
+
path = Path(p.path)
|
|
7
|
+
path = path.relative_to(path.anchor)
|
|
8
|
+
return str(base / path)
|
|
9
|
+
|
|
10
|
+
return tuple(Page(page_path(p), p.content) for p in pages)
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
from rift_ssg.page import Page
|
|
2
|
+
from jinja2 import Environment
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
@dataclass
|
|
7
|
+
class TemplateContext:
|
|
8
|
+
name: str
|
|
9
|
+
env: Environment
|
|
10
|
+
args: tuple
|
|
11
|
+
kwargs: dict
|
|
12
|
+
|
|
13
|
+
def at(self, path: str):
|
|
14
|
+
return Page(path, self)
|
|
15
|
+
|
|
16
|
+
def set(self, key, value):
|
|
17
|
+
self.kwargs[key] = value
|
|
18
|
+
return self
|
|
19
|
+
|
|
20
|
+
def set_all(self, params: dict):
|
|
21
|
+
self.kwargs.update(params)
|
|
22
|
+
return self
|
|
23
|
+
|
|
24
|
+
def __call__(self, *args, **kwargs):
|
|
25
|
+
return self.env.get_template(self.name).render(*self.args, *args, **self.kwargs, **kwargs)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def templates(env: Environment):
|
|
29
|
+
return lambda name, *args, **kwargs: TemplateContext(name, env, args, kwargs)
|