blob: c87598040790cb91e3050a3b9fcb861cb9afccee [file] [log] [blame]
Serge Bazanskiaad79482021-07-02 17:40:36 +02001def _mdbook_html_impl(ctx):
2 # We will be generating our own book.toml based on this rule's configuration.
3 #
4 # We do this because:
5 # - The book.toml must contain a reference to the source files of the
6 # generated book. This only works as long as the source files are not
7 # generated by Bazel.
8 # - The book.toml file effectively describes a build, so it makes sense to
9 # port that over to be fully managed by the Bazel rule for mdbook. This
10 # makes things more consistent with the rest of our Bazel usage, at the
11 # expense of slightly deviating from how upstream does things.
12 #
13 # We emit the toml into `book.toml` because that's what mdbook needs.
14 # However, instead of emitting it in a subdirectory named after this
15 # target, we do that in `${target}_`. This is so that we can use the target
16 # name as a directory containing the actual generated HTML files, making
17 # the life of developers using this rule a bit easier.
18 out_book_toml = ctx.actions.declare_file(ctx.attr.name + "_/book.toml")
19
20 # Find root of given handbook from srcs - there must be exactly one
21 # SUMMARY.md and the parent directory of that is the root.
22 summary = None
23 for f in ctx.files.srcs:
24 if not f.path.endswith('/SUMMARY.md'):
25 continue
26 if summary != None:
27 fail("More then one SUMMARY.md provided.")
28 summary = f
29 if summary == None:
30 fail("No SUMMARY.md provided in srcs.")
31
32 # We now have the SUMMARY.md file from which we can figure out the source
33 # directory of the book. However, mdbook takes a source root path relative
34 # to the book.toml file, not one relative to the current working
35 # directory... Thus, we need to prepend a list of '../' elements that bring
36 # mdbook down from the book.toml location back into the workspace execution
37 # root, which is where our SUMMARY.md path is itself rooted.
38 #
39 # For example, if book.toml lives in:
40 # execroot/dev_source_monogon/bazel-out/k8-fastbuild/bin/metropolis/handbook/handbook_/book.toml
41 # Then we will need to prepend:
42 # ../../../../../../../
43 # To get back to execroot/.
44 prepend = len(out_book_toml.path.split('/')) - 1
45 src_dir_path = ('../' * prepend) + summary.dirname
46
47 # Generate book.toml.
48 # Bazel does not have a toml library. We abuse JSON encoding to get
49 # serialized list/string data as an acceptable substitute to building a
50 # fully self-standing toml serializer for Bazel.
51 book_toml_contents = [
52 "[book]",
53 "title = {}".format(json.encode(ctx.attr.title)),
54 "authors = {}".format(json.encode(ctx.attr.authors)),
55 "language = {}".format(json.encode(ctx.attr.language)),
56 "multilingual = false",
57 "src = {}".format(json.encode(src_dir_path)),
58 ]
59 ctx.actions.write(
60 output = out_book_toml,
61 content = "\n".join(book_toml_contents)
62 )
63
64 out_dir = ctx.actions.declare_directory(ctx.attr.name)
65 # We also have to prepend the out dir path, for the same reasons for which
66 # we prepend src_dir_path above.
67 out_dir_path = ('../' * prepend) + out_dir.path
68 ctx.actions.run(
69 executable = ctx.executable._mdbook,
70 arguments = [
71 "build",
72 "-d", out_dir_path,
73 out_book_toml.dirname,
74 ],
75 inputs = ctx.files.srcs + [ out_book_toml ],
76 outputs = [ out_dir ],
77 )
78 return [
79 DefaultInfo(
80 files = depset([out_dir]),
81 )
82 ]
83
84mdbook_html = rule(
85 doc = "Build an mdbook source root into HTML files.",
86 implementation = _mdbook_html_impl,
87 attrs = {
88 "title": attr.string(
89 doc = "The title of the generated book.",
90 ),
91 "authors": attr.string_list(
92 default = ["Monogon Project Authors"],
93 doc = "The authors of the generated book.",
94 ),
95 "language": attr.string(
96 default = "en",
97 doc = "The language of the generated book.",
98 ),
99 "srcs": attr.label_list(
100 allow_files = True,
101 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.",
102 ),
103
104 "_mdbook": attr.label(
105 doc = "The mdbook tool.",
106 executable = True,
107 cfg = "host",
108 default = "@dev_source_monogon//third_party/rust:cargo_bin_mdbook",
109 ),
110 },
111)