| 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", | 
 |         ), | 
 |     }, | 
 | ) |