Skip to content

Commit 4538bb5

Browse files
committed
Add ibazel support to mdbook_server
1 parent fabd0f9 commit 4538bb5

2 files changed

Lines changed: 225 additions & 74 deletions

File tree

extensions/mdbook/private/mdbook.bzl

Lines changed: 47 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -105,23 +105,39 @@ def _rlocationpath(file, workspace_name):
105105

106106
return "{}/{}".format(workspace_name, file.short_path)
107107

108+
def _src_dest_path(file):
109+
"""Returns the path of `file` inside the staged workdir, mirroring the build action's `_map_inputs`."""
110+
dest = file.short_path
111+
if dest.startswith("../"):
112+
dest = "external/" + dest.removeprefix("../")
113+
return dest
114+
108115
def _mdbook_server_impl(ctx):
109116
toolchain = ctx.toolchains["@rules_rust_mdbook//:toolchain_type"]
110117
book_info = ctx.attr.book[MdBookInfo]
111118

112119
args = ctx.actions.args()
113120

114-
args.add("--mdbook={}".format(_rlocationpath(toolchain.mdbook, ctx.workspace_name)))
115-
args.add("--config={}".format(_rlocationpath(book_info.config, ctx.workspace_name)))
121+
workspace_name = ctx.workspace_name
122+
123+
args.add("--mdbook={}".format(_rlocationpath(toolchain.mdbook, workspace_name)))
124+
args.add("--config={}".format(_src_dest_path(book_info.config)))
116125
args.add("--hostname={}".format(ctx.attr.hostname))
117126
args.add("--port={}".format(ctx.attr.port))
118127

119-
workspace_name = ctx.workspace_name
128+
def _src_map(file):
129+
return "--src={}={}".format(_rlocationpath(file, workspace_name), _src_dest_path(file))
120130

121-
def _runfile_map(file):
131+
# The set of files that must be staged into the workdir for `mdbook serve` to
132+
# see a consistent source tree. `book.toml` is included so that referencing it
133+
# by `--config` resolves to a real file rather than a runfiles symlink.
134+
book_inputs = depset([book_info.config], transitive = [book_info.srcs])
135+
args.add_all(book_inputs, map_each = _src_map, allow_closure = True)
136+
137+
def _plugin_map(file):
122138
return "--plugin={}".format(_rlocationpath(file, workspace_name))
123139

124-
args.add_all(depset(transitive = [book_info.plugins, toolchain.plugins]), map_each = _runfile_map, allow_closure = True)
140+
args.add_all(depset(transitive = [book_info.plugins, toolchain.plugins]), map_each = _plugin_map, allow_closure = True)
125141

126142
args_file = ctx.actions.declare_file("{}.mdbook_serve_args.txt".format(ctx.label.name))
127143
ctx.actions.write(
@@ -167,7 +183,32 @@ def _mdbook_server_impl(ctx):
167183

168184
mdbook_server = rule(
169185
implementation = _mdbook_server_impl,
170-
doc = "Spawn an mdbook server for a given `mdbook` target.",
186+
doc = """\
187+
Spawn an mdbook server for a given `mdbook` target.
188+
189+
The server stages every input (including generated sources) into an isolated \
190+
working directory before invoking `mdbook serve`, so the running book always \
191+
reflects the bazel-built sources rather than the workspace checkout.
192+
193+
For live-reload during development, add `tags = ["ibazel_notify_changes"]` and \
194+
invoke with [ibazel](https://github.com/bazelbuild/bazel-watcher):
195+
196+
```python
197+
mdbook_server(
198+
name = "book_server",
199+
book = ":book",
200+
tags = ["ibazel_notify_changes"],
201+
)
202+
```
203+
204+
```sh
205+
ibazel run //path/to:book_server
206+
```
207+
208+
ibazel will rebuild on source changes and signal the running server via stdin; \
209+
the server re-stages the freshly built inputs and `mdbook serve` reloads any \
210+
connected browsers.
211+
""",
171212
attrs = {
172213
"book": attr.label(
173214
doc = "The `mdbook` target to serve.",

0 commit comments

Comments
 (0)