blob: c87598040790cb91e3050a3b9fcb861cb9afccee [file] [log] [blame] [edit]
def _mdbook_html_impl(ctx):
# We will be generating our own book.toml based on this rule's configuration.
#
# We do this because:
# - The book.toml must contain a reference to the source files of the
# generated book. This only works as long as the source files are not
# generated by Bazel.
# - The book.toml file effectively describes a build, so it makes sense to
# port that over to be fully managed by the Bazel rule for mdbook. This
# makes things more consistent with the rest of our Bazel usage, at the
# expense of slightly deviating from how upstream does things.
#
# We emit the toml into `book.toml` because that's what mdbook needs.
# However, instead of emitting it in a subdirectory named after this
# target, we do that in `${target}_`. This is so that we can use the target
# name as a directory containing the actual generated HTML files, making
# the life of developers using this rule a bit easier.
out_book_toml = ctx.actions.declare_file(ctx.attr.name + "_/book.toml")
# Find root of given handbook from srcs - there must be exactly one
# SUMMARY.md and the parent directory of that is the root.
summary = None
for f in ctx.files.srcs:
if not f.path.endswith('/SUMMARY.md'):
continue
if summary != None:
fail("More then one SUMMARY.md provided.")
summary = f
if summary == None:
fail("No SUMMARY.md provided in srcs.")
# We now have the SUMMARY.md file from which we can figure out the source
# directory of the book. However, mdbook takes a source root path relative
# to the book.toml file, not one relative to the current working
# directory... Thus, we need to prepend a list of '../' elements that bring
# mdbook down from the book.toml location back into the workspace execution
# root, which is where our SUMMARY.md path is itself rooted.
#
# For example, if book.toml lives in:
# execroot/dev_source_monogon/bazel-out/k8-fastbuild/bin/metropolis/handbook/handbook_/book.toml
# Then we will need to prepend:
# ../../../../../../../
# To get back to execroot/.
prepend = len(out_book_toml.path.split('/')) - 1
src_dir_path = ('../' * prepend) + summary.dirname
# Generate book.toml.
# Bazel does not have a toml library. We abuse JSON encoding to get
# serialized list/string data as an acceptable substitute to building a
# fully self-standing toml serializer for Bazel.
book_toml_contents = [
"[book]",
"title = {}".format(json.encode(ctx.attr.title)),
"authors = {}".format(json.encode(ctx.attr.authors)),
"language = {}".format(json.encode(ctx.attr.language)),
"multilingual = false",
"src = {}".format(json.encode(src_dir_path)),
]
ctx.actions.write(
output = out_book_toml,
content = "\n".join(book_toml_contents)
)
out_dir = ctx.actions.declare_directory(ctx.attr.name)
# We also have to prepend the out dir path, for the same reasons for which
# we prepend src_dir_path above.
out_dir_path = ('../' * prepend) + out_dir.path
ctx.actions.run(
executable = ctx.executable._mdbook,
arguments = [
"build",
"-d", out_dir_path,
out_book_toml.dirname,
],
inputs = ctx.files.srcs + [ out_book_toml ],
outputs = [ out_dir ],
)
return [
DefaultInfo(
files = depset([out_dir]),
)
]
mdbook_html = rule(
doc = "Build an mdbook source root into HTML files.",
implementation = _mdbook_html_impl,
attrs = {
"title": attr.string(
doc = "The title of the generated book.",
),
"authors": attr.string_list(
default = ["Monogon Project Authors"],
doc = "The authors of the generated book.",
),
"language": attr.string(
default = "en",
doc = "The language of the generated book.",
),
"srcs": attr.label_list(
allow_files = True,
doc = "The sources of the generated book. Exaclty one file must be named SUMMARY.md, and that file's location will be used to determine the root of the book sources.",
),
"_mdbook": attr.label(
doc = "The mdbook tool.",
executable = True,
cfg = "host",
default = "@dev_source_monogon//third_party/rust:cargo_bin_mdbook",
),
},
)