Skip to content
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
151 changes: 131 additions & 20 deletions docs.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,71 @@ load("@aspect_rules_py//py:defs.bzl", "py_binary", "py_venv")
load("@docs_as_code_hub_env//:requirements.bzl", "all_requirements")
load("@rules_python//sphinxdocs:sphinx.bzl", "sphinx_build_binary", "sphinx_docs")

# -- Host-platform transition for host-only documentation tooling --------------
#
# The runnable doc targets (docs, ide_support, live_preview, ...) are pure host tools that run
# Python/Sphinx locally. Under a cross `--platforms` (e.g. QNX) they would be configured for the
# target platform and fail Python toolchain resolution. Instead of `target_compatible_with` (which
# would only make `bazel build //...` skip them), each is wrapped in a rule whose incoming transition
# pins `//command_line_option:platforms` to `--host_platform`, so they always build and run in the
# host config regardless of the top-level `--platforms`.

def _to_host_platform_impl(settings, _attr):
return {
"//command_line_option:platforms": [
settings["//command_line_option:host_platform"],
],
}

_to_host_platform = transition(
implementation = _to_host_platform_impl,
inputs = ["//command_line_option:host_platform"],
outputs = ["//command_line_option:platforms"],
)

def _host_binary_impl(ctx):
# `actual` is a singleton list because of the outgoing transition.
target = ctx.attr.actual[0]
default_info = target[DefaultInfo]

# Re-expose the wrapped binary under this target's name by symlinking its executable and
# forwarding its runfiles, so `bazel run` keeps working.
executable = ctx.actions.declare_file(ctx.label.name)
ctx.actions.symlink(
output = executable,
target_file = default_info.files_to_run.executable,
is_executable = True,
)
runfiles = ctx.runfiles([executable]).merge(default_info.default_runfiles)

providers = [DefaultInfo(
executable = executable,
files = depset([executable]),
runfiles = runfiles,
)]

# Forward the wrapped binary's run environment (its `env` attr) so `bazel run`
# of the wrapper still applies it.
if RunEnvironmentInfo in target:
providers.append(target[RunEnvironmentInfo])
return providers

# Wrapper for runnable host tools (py_binary / py_venv / sphinx_build_binary).
_host_binary = rule(
implementation = _host_binary_impl,
executable = True,
attrs = {
"actual": attr.label(
mandatory = True,
doc = "The host-only target to build in the host configuration.",
cfg = _to_host_platform,
),
"_allowlist_function_transition": attr.label(
default = "@bazel_tools//tools/allowlists/function_transition_allowlist",
),
},
)

def _rewrite_needs_json_to_docs_sources(labels):
"""Replace '@repo//:needs_json' -> '@repo//:docs_sources' for every item."""
out = []
Expand All @@ -63,8 +128,10 @@ def _rewrite_needs_json_to_sourcelinks(labels):
s = str(x)
if s.endswith("//:needs_json"):
out.append(s.replace("//:needs_json", "//:sourcelinks_json"))

#Items which do not end up with '//:needs_json' shall not be appended to 'out'.
#They are treated separately and are not related to source code linking.

return out

def _merge_sourcelinks(name, sourcelinks, known_good = None):
Expand Down Expand Up @@ -100,15 +167,19 @@ def _missing_requirements(deps):
"""Add Python hub dependencies if they are missing."""
found = []
missing = []

def _target_to_packagename(target):
return str(target).split("/")[-1].split(":")[0]

all_packages = [_target_to_packagename(pkg) for pkg in all_requirements]

def _find(pkg):
for dep in deps:
dep_pkg = _target_to_packagename(dep)
if dep_pkg == pkg:
return True
return False

for pkg in all_packages:
if _find(pkg):
found.append(pkg)
Expand Down Expand Up @@ -166,6 +237,11 @@ def docs(source_dir = "docs", data = [], deps = [], scan_code = [], known_good =

sphinx_build_binary(
name = "sphinx_build",
# `sphinx_build` is only consumed as a tool (see `needs_json`'s `sphinx` attr below), so Bazel
# already builds it in the exec (host) config -- no host transition needed. It is tagged
# `manual` so a cross-platform `bazel build //...` doesn't configure it for the target platform
# (which would fail Python toolchain resolution).
tags = ["manual"],
visibility = ["//visibility:private"],
data = data + metamodel_data,
deps = deps,
Expand Down Expand Up @@ -225,22 +301,32 @@ def docs(source_dir = "docs", data = [], deps = [], scan_code = [], known_good =
docs_env["ACTION"] = "incremental"

py_binary(
name = "docs",
tags = ["cli_help=Build documentation:\nbazel run //:docs"],
name = "docs_impl",
tags = ["manual"],
srcs = [incremental_src],
data = docs_data,
deps = deps,
env = docs_env
env = docs_env,
)
_host_binary(
name = "docs",
actual = ":docs_impl",
tags = ["cli_help=Build documentation:\nbazel run //:docs"],
)

docs_sources_env["ACTION"] = "incremental"
py_binary(
name = "docs_combo",
tags = ["cli_help=Build full documentation with all dependencies:\nbazel run //:docs_combo"],
name = "docs_combo_impl",
tags = ["manual"],
srcs = [incremental_src],
data = combo_data,
deps = deps,
env = docs_sources_env
env = docs_sources_env,
)
_host_binary(
name = "docs_combo",
actual = ":docs_combo_impl",
tags = ["cli_help=Build full documentation with all dependencies:\nbazel run //:docs_combo"],
)

native.alias(
Expand All @@ -251,52 +337,77 @@ def docs(source_dir = "docs", data = [], deps = [], scan_code = [], known_good =

docs_env["ACTION"] = "linkcheck"
py_binary(
name = "docs_link_check",
tags = ["cli_help=Verify Links inside Documentation:\nbazel run //:link_check\n (Note: this could take a long time)"],
name = "docs_link_check_impl",
tags = ["manual"],
srcs = [incremental_src],
data = docs_data,
deps = deps,
env = docs_env
env = docs_env,
)
_host_binary(
name = "docs_link_check",
actual = ":docs_link_check_impl",
tags = ["cli_help=Verify Links inside Documentation:\nbazel run //:link_check\n (Note: this could take a long time)"],
)

docs_env["ACTION"] = "check"
py_binary(
name = "docs_check",
tags = ["cli_help=Verify documentation:\nbazel run //:docs_check"],
name = "docs_check_impl",
tags = ["manual"],
srcs = [incremental_src],
data = docs_data,
deps = deps,
env = docs_env
env = docs_env,
)
_host_binary(
name = "docs_check",
actual = ":docs_check_impl",
tags = ["cli_help=Verify documentation:\nbazel run //:docs_check"],
)

docs_env["ACTION"] = "live_preview"
py_binary(
name = "live_preview",
tags = ["cli_help=Live preview documentation in the browser:\nbazel run //:live_preview"],
name = "live_preview_impl",
tags = ["manual"],
srcs = [incremental_src],
data = docs_data,
deps = deps,
env = docs_env
env = docs_env,
)
_host_binary(
name = "live_preview",
actual = ":live_preview_impl",
tags = ["cli_help=Live preview documentation in the browser:\nbazel run //:live_preview"],
)

docs_sources_env["ACTION"] = "live_preview"
py_binary(
name = "live_preview_combo_experimental",
tags = ["cli_help=Live preview full documentation with all dependencies in the browser:\nbazel run //:live_preview_combo_experimental"],
name = "live_preview_combo_experimental_impl",
tags = ["manual"],
srcs = [incremental_src],
data = combo_data,
deps = deps,
env = docs_sources_env
env = docs_sources_env,
)
_host_binary(
name = "live_preview_combo_experimental",
actual = ":live_preview_combo_experimental_impl",
tags = ["cli_help=Live preview full documentation with all dependencies in the browser:\nbazel run //:live_preview_combo_experimental"],
)

py_venv(
name = "ide_support",
tags = ["cli_help=Create virtual environment (.venv_docs) for documentation support:\nbazel run //:ide_support"],
name = "ide_support_impl",
tags = ["manual"],
venv_name = ".venv_docs",
deps = deps,
data = data,
package_collisions = "warning",
)
_host_binary(
name = "ide_support",
actual = ":ide_support_impl",
tags = ["cli_help=Create virtual environment (.venv_docs) for documentation support:\nbazel run //:ide_support"],
)

sphinx_docs(
name = "needs_json",
Expand Down
Loading