Skip to content

Commit

Permalink
generalize documentation rendering
Browse files Browse the repository at this point in the history
render documentation for original workspace based on separate modules,
only using `stardoc` templates.

this lets us get rid of additional template files and a lot of noisy
helper code.

add rule aliases for backwards compatibility.
  • Loading branch information
fricklerhandwerk committed Mar 24, 2022
1 parent 8ba45e5 commit 4f9af6f
Show file tree
Hide file tree
Showing 13 changed files with 207 additions and 328 deletions.
40 changes: 4 additions & 36 deletions core/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
load("@bazel_skylib//:bzl_library.bzl", "bzl_library")
load("//docs:stardoc.bzl", "generate")

package(default_visibility = ["//visibility:public"])
Expand All @@ -9,47 +8,16 @@ filegroup(
visibility = ["//visibility:public"],
)

# boilerplate for `bazel_tools`
bzl_library(
name = "bazel_tools",
srcs = [
"@bazel_tools//tools:bzl_srcs",
],
)

# define Bazel library and its dependencies for generating documentation. considered
# in isolation we could immediately use
#
# generate(deps = [":srcs", <foreign dependencies> ], ...)
#
# but toolchain modules that import definitions from here require a target to
# declare as their dependency for their own documentation rendering. same for
# legacy documentation. one could possibly extract this highly repetitive
# pattern into `generate()` itself, and capture its `deps=` attribute to
# automatically create these Bazel library targets. this approach may become
# meaningful once we want to generate legacy documentation for all the toolchains
# at once, as those toolchains will also have to export their Bazel libraries
# to make that convenient.
bzl_library(
name = "nixpkgs",
srcs = [
generate(
name = "README.md",
inputs = [
"nixpkgs.bzl",
"util.bzl",
],
visibility = ["//visibility:public"],
deps = [
":bazel_tools",
"@bazel_skylib//lib:paths",
],
)

generate(
name = "README.md",
input = "//:nixpkgs.bzl",
symbol_names = [
"nixpkgs_git_repository",
"nixpkgs_local_repository",
"nixpkgs_package",
],
deps = ["//:nixpkgs"],
deps = ["@bazel_skylib//lib:paths"],
)
79 changes: 68 additions & 11 deletions core/docs/stardoc.bzl
Original file line number Diff line number Diff line change
@@ -1,15 +1,64 @@
load("@bazel_skylib//:bzl_library.bzl", "bzl_library")
load("@io_bazel_stardoc//stardoc:stardoc.bzl", _stardoc = "stardoc")

def generate(
name,
input,
inputs,
error_message = None,
deps = [],
**kwargs):
"""
create rules for generating documentation, copying a file into the source
tree containing it, and testing that the copying has actually happened
(since the copy rule must be run manually).
full-service documentation rendering
- make a Bazel library from `inputs`
- create rules for
- generating library documentation
- copying a file into the source tree containing it
- testing that the copying has actually happened
(since the copy rule must be run manually)
NOTE: library name is derived from first file in `inputs`, without extensions.
Args:
name: target file name for rendered documentation.
inputs: file names for Bazel library and documentation
error_message: custom error message to print if rendered documentation is not up to date.
deps: library dependencies of the `inputs` provided.
**kwargs: arguments for `stardoc`, most notably `symbol_names` to generate documentation for.
"""

# necessary boilerplate: to build a Bazel library, we always need to include
# `bazel_tools` as a dependency.
# since we will combine toolchain libraries with the core library, but only
# need `bazel_tools` dependency once, only create if not already there.
if not native.existing_rule("bazel_tools"):
bzl_library(
name = "bazel_tools",
srcs = [
"@bazel_tools//tools:bzl_srcs",
],
)

# massage first input file name into nice rule name
lib = Label(absolute_label(inputs[0])).name.split(".")[0]
bzl_library(
name = lib,
srcs = inputs,
visibility = ["//visibility:public"],
deps = [":bazel_tools"] + deps,
)

# generate documentation into transient file
out = "_{}".format(name)
stardoc("__{}".format(name), out, inputs[0], deps = [lib], **kwargs)

# create rule to copy documentation into source tree
# has to be run manually! set up a commit hook for convenience?
copy_files(
name = "update-{}".format(name),
data = [(out, name)],
)

if not error_message:
error_message = [
"{} is not up to date.",
Expand All @@ -18,15 +67,12 @@ def generate(
"bazel run //{}:update-{}",
]
error_message = "\n".join(error_message).format(name, native.package_name(), name)
out = "_{}".format(name)
stardoc("__{}".format(name), out, input, **kwargs)
copy_files(
name = "update-{}".format(name),
data = [(out, name)],
)

# create test that source tree is up to date with rendered documentation
compare_files(
name = "check-{}".format(name),
data = [(out, name)],
# expect target file at top level of current workspace, see `copy_files`
data = [(out, to_root(name))],
error_message = error_message,
)

Expand Down Expand Up @@ -77,3 +123,14 @@ def compare_files(name, data, error_message = ""):
data = data,
env = {"errormsg": error_message},
)

def to_root(label):
return "//:" + Label(absolute_label(label)).name

def absolute_label(label):
# adapted from https://stackoverflow.com/a/66705640/18406610
if label.startswith("@") or label.startswith("/"):
return label
if label.startswith(":"):
return native.repository_name() + "//" + native.package_name() + label
return native.repository_name() + "//" + native.package_name() + ":" + label
118 changes: 23 additions & 95 deletions docs/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
load("@rules_nixpkgs_core//docs:stardoc.bzl", "compare_files", "copy_files", "stardoc")
load("@rules_nixpkgs_core//docs:stardoc.bzl", "generate")

stardoc(
name = "nixpkgs",
out = "nixpkgs.md",
input = "//nixpkgs:nixpkgs.bzl",
generate(
name = "README.md",
inputs = ["//nixpkgs:nixpkgs.bzl"],
symbol_names = [
"nixpkgs_git_repository",
"nixpkgs_local_repository",
Expand All @@ -12,102 +11,31 @@ stardoc(
"nixpkgs_cc_configure_deprecated",
"nixpkgs_java_configure",
"nixpkgs_python_configure",
"nixpkgs_sh_posix_configure",
],
deps = ["//nixpkgs"],
)

stardoc(
name = "core",
out = "core.md",
input = "@rules_nixpkgs_core//:nixpkgs.bzl",
symbol_names = [
"nixpkgs_git_repository",
"nixpkgs_local_repository",
"nixpkgs_package",
],
deps = ["@rules_nixpkgs_core//:nixpkgs"],
)

stardoc(
name = "go",
out = "toolchains/go.md",
input = "//nixpkgs:toolchains/go.bzl",
symbol_names = [
"nixpkgs_rust_configure",
"nixpkgs_go_configure",
"nixpkgs_sh_posix_configure",
],
deps = ["//nixpkgs:toolchains_go"],
)

genrule(
name = "readme",
srcs = [
"README.md.tpl",
"nixpkgs.md",
"toolchains/go.md",
deps = [
"@bazel_skylib//lib:new_sets",
"@bazel_skylib//lib:paths",
"@bazel_skylib//lib:sets",
"@bazel_skylib//lib:versions",
"@rules_nixpkgs_cc//:cc",
"@rules_nixpkgs_core//:nixpkgs",
"@rules_nixpkgs_go//:go",
"@rules_nixpkgs_java//:java",
"@rules_nixpkgs_posix//:posix",
"@rules_nixpkgs_python//:python",
"@rules_nixpkgs_rust//:rust",
],
outs = ["README.md"],
cmd = """$(POSIX_AWK) \\
<$(execpath README.md.tpl) \\
>$(OUTS) \\
'{
if (/{{nixpkgs}}/) {
RS="\\0";
getline content <"$(execpath nixpkgs.md)";
print content;
RS="\\n";
} else if (/{{toolchains_go}}/) {
RS="\\0";
getline content <"$(execpath toolchains/go.md)";
print content;
RS="\\n";
} else {
print
}
}'
""",
toolchains = ["@rules_sh//sh/posix:make_variables"],
)

genrule(
name = "readme_core",
srcs = [
"README_core.md.tpl",
"core.md",
],
outs = ["core/README.md"],
cmd = """$(POSIX_AWK) \\
<$(execpath README_core.md.tpl) \\
>$(OUTS) \\
'{
if (/{{core}}/) {
RS="\\0";
getline content <"$(execpath core.md)";
print content;
RS="\\n";
} else {
print
}
}'
""",
toolchains = ["@rules_sh//sh/posix:make_variables"],
alias(
name = "update-readme",
actual = "update-README.md",
)

compare_files(
alias(
name = "check-readme",
data = [
("README.md", "//:README.md"),
("core/README.md", "@rules_nixpkgs_core//:README.md"),
],
error_message = """
The project README is not up-to-date.
Please update it using the following command.
bazel run //docs:update-readme
""",
)

copy_files(
name = "update-readme",
data = [("README.md", "core/README.md")],
actual = "check-README.md",
)
Loading

0 comments on commit 4f9af6f

Please sign in to comment.