blob: 810dca352487730c0bba425372dd3ae4fc98c3bc [file] [log] [blame]
# 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",
),
},
)