| # Copyright 2023 The Bazel Authors. All rights reserved. |
| # |
| # Licensed under the Apache License, Version 2.0 (the "License"); |
| # you may not use this file except in compliance with the License. |
| # You may obtain a copy of the License at |
| # |
| # http://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, software |
| # distributed under the License is distributed on an "AS IS" BASIS, |
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| # See the License for the specific language governing permissions and |
| # limitations under the License. |
| |
| """Rules to generate Sphinx-compatible documentation for bzl files.""" |
| |
| load("@bazel_skylib//lib:types.bzl", "types") |
| load("@bazel_skylib//rules:build_test.bzl", "build_test") |
| load("@io_bazel_stardoc//stardoc:stardoc.bzl", "stardoc") |
| load("//python/private:util.bzl", "add_tag", "copy_propagating_kwargs") # buildifier: disable=bzl-visibility |
| |
| def sphinx_stardocs(name, docs, footer = None, **kwargs): |
| """Generate Sphinx-friendly Markdown docs using Stardoc for bzl libraries. |
| |
| A `build_test` for the docs is also generated to ensure Stardoc is able |
| to process the files. |
| |
| NOTE: This generates MyST-flavored Markdown. |
| |
| Args: |
| name: `str`, the name of the resulting file group with the generated docs. |
| docs: `dict[str output, source]` of the bzl files to generate documentation |
| for. The `output` key is the path of the output filename, e.g., |
| `foo/bar.md`. The `source` values can be either of: |
| * A `str` label that points to a `bzl_library` target. The target |
| name will replace `_bzl` with `.bzl` and use that as the input |
| bzl file to generate docs for. The target itself provides the |
| necessary dependencies. |
| * A `dict` with keys `input` and `dep`. The `input` key is a string |
| label to the bzl file to generate docs for. The `dep` key is a |
| string label to a `bzl_library` providing the necessary dependencies. |
| footer: optional [`label`] File to append to generated docs. |
| **kwargs: Additional kwargs to pass onto each `sphinx_stardoc` target |
| """ |
| add_tag(kwargs, "@rules_python//sphinxdocs:sphinx_stardocs") |
| common_kwargs = copy_propagating_kwargs(kwargs) |
| |
| stardocs = [] |
| for out_name, entry in docs.items(): |
| stardoc_kwargs = {} |
| stardoc_kwargs.update(kwargs) |
| |
| if types.is_string(entry): |
| stardoc_kwargs["deps"] = [entry] |
| stardoc_kwargs["input"] = entry.replace("_bzl", ".bzl") |
| else: |
| stardoc_kwargs.update(entry) |
| stardoc_kwargs["deps"] = [stardoc_kwargs.pop("dep")] |
| |
| doc_name = "_{}_{}".format(name.lstrip("_"), out_name.replace("/", "_")) |
| _sphinx_stardoc( |
| name = doc_name, |
| footer = footer, |
| out = out_name, |
| **stardoc_kwargs |
| ) |
| stardocs.append(doc_name) |
| |
| native.filegroup( |
| name = name, |
| srcs = stardocs, |
| **common_kwargs |
| ) |
| build_test( |
| name = name + "_build_test", |
| targets = stardocs, |
| **common_kwargs |
| ) |
| |
| def _sphinx_stardoc(*, name, out, footer = None, public_load_path = None, **kwargs): |
| stardoc_name = "_{}_stardoc".format(name.lstrip("_")) |
| stardoc_pb = stardoc_name + ".binaryproto" |
| |
| if not public_load_path: |
| public_load_path = str(kwargs["input"]) |
| |
| stardoc( |
| name = stardoc_name, |
| out = stardoc_pb, |
| format = "proto", |
| **kwargs |
| ) |
| |
| _stardoc_proto_to_markdown( |
| name = name, |
| src = stardoc_pb, |
| output = out, |
| footer = footer, |
| public_load_path = public_load_path, |
| ) |
| |
| def _stardoc_proto_to_markdown_impl(ctx): |
| args = ctx.actions.args() |
| args.use_param_file("@%s") |
| args.set_param_file_format("multiline") |
| |
| inputs = [ctx.file.src] |
| args.add("--proto", ctx.file.src) |
| args.add("--output", ctx.outputs.output) |
| |
| if ctx.file.footer: |
| args.add("--footer", ctx.file.footer) |
| inputs.append(ctx.file.footer) |
| if ctx.attr.public_load_path: |
| args.add("--public-load-path={}".format(ctx.attr.public_load_path)) |
| |
| ctx.actions.run( |
| executable = ctx.executable._proto_to_markdown, |
| arguments = [args], |
| inputs = inputs, |
| outputs = [ctx.outputs.output], |
| mnemonic = "SphinxStardocProtoToMd", |
| progress_message = "SphinxStardoc: converting proto to markdown: %{input} -> %{output}", |
| ) |
| |
| _stardoc_proto_to_markdown = rule( |
| implementation = _stardoc_proto_to_markdown_impl, |
| attrs = { |
| "footer": attr.label(allow_single_file = True), |
| "output": attr.output(mandatory = True), |
| "public_load_path": attr.string(), |
| "src": attr.label(allow_single_file = True, mandatory = True), |
| "_proto_to_markdown": attr.label( |
| default = "//sphinxdocs/private:proto_to_markdown", |
| executable = True, |
| cfg = "exec", |
| ), |
| }, |
| ) |