Skip to content

Commit c5cf350

Browse files
committed
Add pre/post render hooks to ModPlugin
1 parent 4de4631 commit c5cf350

File tree

5 files changed

+85
-2
lines changed

5 files changed

+85
-2
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,12 @@ All notable changes to this project will be documented in this file.
44

55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and [Pydantic's HISTORY.md](https://github.com/pydantic/pydantic/blob/main/HISTORY.md), and this project *mostly* adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
66

7+
## `1!0.1.0a34`
8+
9+
### Added
10+
11+
* Added several new hooks to `ModPlugin` for running code before/after the web book is generated.
12+
713
## `1!0.1.0a33`
814

915
### Fixed

src/hexdoc/cli/app.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,10 @@ def build(
254254
env = create_jinja_env(pm, props.template.include, props_file)
255255

256256
logger.info(f"Rendering book for {len(books)} language(s).")
257+
258+
site_dir.mkdir(parents=True, exist_ok=True)
259+
pm.pre_render_site(books, env, site_dir, props.template.include)
260+
257261
for book_info in books:
258262
try:
259263
templates = get_templates(
@@ -312,6 +316,8 @@ def build(
312316
raise
313317
logger.exception(f"Failed to render book for {book_info.language}")
314318

319+
pm.post_render_site(books, env, site_dir, props.template.include)
320+
315321
logger.info("Done.")
316322
return site_dir
317323

src/hexdoc/jinja/render.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ def create_jinja_env(pm: PluginManager, include: Sequence[str], props_file: Path
8888
)
8989
)
9090

91-
return pm.update_jinja_env(env, include)
91+
return pm.update_jinja_env(include, env)
9292

9393

9494
def create_jinja_env_with_loader(loader: BaseLoader):
@@ -235,6 +235,8 @@ def render_book(
235235
}
236236
pm.update_template_args(template_args)
237237

238+
pm.pre_render_book(template_args, output_dir, props.template.include)
239+
238240
for filename, (template, extra_args) in templates.items():
239241
file = template.render(template_args | dict(extra_args))
240242
stripped_file = strip_empty_lines(file)
@@ -286,6 +288,8 @@ def render_book(
286288

287289
(output_dir / MARKER_NAME).write_text(marker.model_dump_json(), "utf-8")
288290

291+
pm.post_render_book(template_args, output_dir, props.template.include)
292+
289293

290294
def strip_empty_lines(text: str) -> str:
291295
return "\n".join(s for s in text.splitlines() if s.strip())

src/hexdoc/plugin/manager.py

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
from hexdoc.utils import ContextSource, ValidationContext
2929

3030
if TYPE_CHECKING:
31+
from hexdoc.cli.app import LoadedBookInfo
3132
from hexdoc.core import Properties, ResourceLocation
3233
from hexdoc.minecraft import I18n
3334
from hexdoc.patchouli import FormatTree
@@ -212,17 +213,55 @@ def update_context(self, context: dict[str, Any]) -> Iterator[ValidationContext]
212213
if returns := caller.try_call(context=context):
213214
yield from flatten(returns)
214215

215-
def update_jinja_env(self, env: SandboxedEnvironment, modids: Sequence[str]):
216+
def update_jinja_env(self, modids: Sequence[str], env: SandboxedEnvironment):
216217
for modid in modids:
217218
plugin = self.mod_plugin(modid)
218219
plugin.update_jinja_env(env)
219220
return env
220221

222+
def pre_render_site(
223+
self,
224+
books: list[LoadedBookInfo],
225+
env: SandboxedEnvironment,
226+
output_dir: Path,
227+
modids: Sequence[str],
228+
):
229+
for modid in modids:
230+
self.mod_plugin(modid).pre_render_site(self.props, books, env, output_dir)
231+
232+
def post_render_site(
233+
self,
234+
books: list[LoadedBookInfo],
235+
env: SandboxedEnvironment,
236+
output_dir: Path,
237+
modids: Sequence[str],
238+
):
239+
for modid in modids:
240+
self.mod_plugin(modid).post_render_site(self.props, books, env, output_dir)
241+
221242
def update_template_args(self, template_args: dict[str, Any]):
222243
caller = self._hook_caller(PluginSpec.hexdoc_update_template_args)
223244
caller.try_call(template_args=template_args)
224245
return template_args
225246

247+
def pre_render_book(
248+
self,
249+
template_args: dict[str, Any],
250+
output_dir: Path,
251+
modids: Sequence[str],
252+
):
253+
for modid in modids:
254+
self.mod_plugin(modid).pre_render_book(template_args, output_dir)
255+
256+
def post_render_book(
257+
self,
258+
template_args: dict[str, Any],
259+
output_dir: Path,
260+
modids: Sequence[str],
261+
):
262+
for modid in modids:
263+
self.mod_plugin(modid).post_render_book(template_args, output_dir)
264+
226265
def load_resources(self, modid: str) -> Iterator[ModuleType]:
227266
plugin = self.mod_plugin(modid)
228267
for package in flatten([plugin.resource_dirs()]):

src/hexdoc/plugin/mod_plugin.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
from .types import HookReturn
1616

1717
if TYPE_CHECKING:
18+
from hexdoc.cli.app import LoadedBookInfo
1819
from hexdoc.core import ModResourceLoader, Properties
1920
from hexdoc.minecraft.assets import HexdocAssetLoader
2021

@@ -140,6 +141,33 @@ def update_jinja_env(self, env: SandboxedEnvironment) -> None:
140141
rendering the book.
141142
"""
142143

144+
def pre_render_site(
145+
self,
146+
props: Properties,
147+
books: list[LoadedBookInfo],
148+
env: SandboxedEnvironment,
149+
output_dir: Path,
150+
) -> None:
151+
"""Called once, after hexdoc is done setting up the Jinja environment but before
152+
rendering the book."""
153+
154+
def post_render_site(
155+
self,
156+
props: Properties,
157+
books: list[LoadedBookInfo],
158+
env: SandboxedEnvironment,
159+
output_dir: Path,
160+
) -> None:
161+
"""Called once, at the end of `hexdoc build`."""
162+
163+
def pre_render_book(self, template_args: dict[str, Any], output_dir: Path) -> None:
164+
"""Called once per language, just before rendering the book for that
165+
language."""
166+
167+
def post_render_book(self, template_args: dict[str, Any], output_dir: Path) -> None:
168+
"""Called once per language, after all book files for that language are
169+
rendered."""
170+
143171
# utils
144172

145173
def site_path(self, versioned: bool):

0 commit comments

Comments
 (0)