treewide: replace custom mdbook rules with rules_rust extension

Change-Id: I342080f27cf3b41d0522aec7142b35ab53f1e24e
Reviewed-on: https://review.monogon.dev/c/monogon/+/4256
Tested-by: Jenkins CI
Reviewed-by: Lorenz Brun <lorenz@monogon.tech>
diff --git a/metropolis/handbook/BUILD.bazel b/metropolis/handbook/BUILD.bazel
index 72c3490..103748b 100644
--- a/metropolis/handbook/BUILD.bazel
+++ b/metropolis/handbook/BUILD.bazel
@@ -1,7 +1,7 @@
-load("//metropolis/handbook:defs.bzl", "mdbook_html")
+load("@rules_rust_mdbook//:defs.bzl", "mdbook")
 
-mdbook_html(
+mdbook(
     name = "handbook",
     srcs = glob(["src/**/*.md"]),
-    title = "Metropolis Handbook",
+    book = ":book.toml",
 )
diff --git a/metropolis/handbook/book.toml b/metropolis/handbook/book.toml
new file mode 100644
index 0000000..5a36569
--- /dev/null
+++ b/metropolis/handbook/book.toml
@@ -0,0 +1,5 @@
+[book]
+title = "Metropolis Handbook"
+authors = ["Monogon Project Authors"]
+language = "en"
+multilingual = false
diff --git a/metropolis/handbook/defs.bzl b/metropolis/handbook/defs.bzl
deleted file mode 100644
index 2ad44f3..0000000
--- a/metropolis/handbook/defs.bzl
+++ /dev/null
@@ -1,112 +0,0 @@
-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/_main/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 = "exec",
-            default = "@crate_index//:mdbook__mdbook",
-        ),
-    },
-)