Skip to content
Merged
Show file tree
Hide file tree
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
71 changes: 70 additions & 1 deletion bzl/bundle_rules.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,10 @@


load("@score_docs_as_code//:bzl/basics.bzl", "join_path")
load(
"@sphinxdocs//sphinxdocs/private:sphinx_docs_library_info.bzl",
"SphinxDocsLibraryInfo",
)

# Internal data passed between bundle targets and eventually consumed by an
# adapter such as the Sphinx mounts manifest. Users configure bundles through
Expand All @@ -63,6 +67,8 @@ DocsBundleInfo = provider(
fields = {
"entries": "Ordered entries, one per source directory, including its final documentation-tree location.",
"own_source_files": "This bundle's direct source files, excluding nested bundles.",
"own_source_root": "Runtime path of this bundle's direct source root.",
"own_source_is_explicit": "Whether the direct sources came from explicit source targets.",
"sourcelinks": "Source-code-link JSON files together with their owning repository.",
"external_runfiles": "Documentation source files not read from the workspace at runtime.",
# Bundle-owned supporting/runtime files. Unlike host-owned docs data,
Expand Down Expand Up @@ -300,6 +306,8 @@ def _docs_bundle_impl(ctx):
"""Compose source files and nested bundles into a reusable bundle."""
entries = []
own_source_files = []
own_source_root = ""
own_source_is_explicit = False
own_external_runfiles = []
own_data = depset(direct = ctx.files.data)

Expand All @@ -311,6 +319,7 @@ def _docs_bundle_impl(ctx):

if ctx.files.source_dir_globbed:
runtime_path = _bundle_runtime_path(ctx)
own_source_root = runtime_path
external = runtime_path.startswith("../")
entries.append(struct(
runtime_path = runtime_path,
Expand Down Expand Up @@ -339,6 +348,8 @@ def _docs_bundle_impl(ctx):
# the declared relative file list so runtime discovery cannot include
# undeclared siblings from the shared parent directory.
runtime_path = _source_targets_runtime_path(ctx.files.source_targets)
own_source_root = runtime_path
own_source_is_explicit = True
source_files = _source_targets_relative_paths(
ctx.files.source_targets,
runtime_path,
Expand Down Expand Up @@ -423,6 +434,8 @@ def _docs_bundle_impl(ctx):
DocsBundleInfo(
entries = entries,
own_source_files = depset(direct = own_source_files),
own_source_root = own_source_root,
own_source_is_explicit = own_source_is_explicit,
sourcelinks = sourcelinks,
external_runfiles = external_runfiles,
data = all_data,
Expand Down Expand Up @@ -490,12 +503,68 @@ _bundle_source_files = rule(
doc = "Exposes direct bundle sources without nested bundle sources.",
)

def bundle_source_files(name, bundle, visibility = None):
def bundle_source_files(name, bundle, visibility = None, tags = None):
"""Create a target containing only the direct sources of a bundle."""
_bundle_source_files(
name = name,
bundle = bundle,
visibility = visibility,
tags = tags,
)
return ":" + name

def _bundle_sphinx_source_files_impl(ctx):
"""Expose direct bundle sources with a Sphinx-specific path mapping."""
bundle = ctx.attr.bundle[DocsBundleInfo]
source_files = tuple(bundle.own_source_files.to_list())
if not source_files:
fail("bundle %s has no direct documentation sources" % ctx.attr.bundle)

# Directory-discovered sources already carry a stable bundle-relative root
# in the provider. Explicit source targets instead use the output path
# Bazel gives to Sphinx. Deriving that parent from ``short_path`` handles
# both workspace files and generated outputs (whose paths include
# ``bazel-out``) without making the macro guess a configuration-dependent
# output directory.
if bundle.own_source_is_explicit:
source_path = source_files[0].short_path
separator = source_path.rfind("/")
strip_prefix = source_path[:separator + 1] if separator >= 0 else ""
else:
strip_prefix = bundle.own_source_root
if strip_prefix and not strip_prefix.endswith("/"):
strip_prefix += "/"

entry = struct(
strip_prefix = strip_prefix,
prefix = "",
files = source_files,
)
return [
DefaultInfo(files = depset(source_files)),
SphinxDocsLibraryInfo(
strip_prefix = strip_prefix,
prefix = "",
files = source_files,
transitive = depset(direct = [entry]),
),
]

_bundle_sphinx_source_files = rule(
implementation = _bundle_sphinx_source_files_impl,
attrs = {
"bundle": attr.label(providers = [DocsBundleInfo]),
},
doc = "Exposes direct bundle sources with paths rooted for a Sphinx build.",
)

def bundle_sphinx_source_files(name, bundle, visibility = None, tags = None):
"""Create a Sphinx library containing only a bundle's direct sources."""
_bundle_sphinx_source_files(
name = name,
bundle = bundle,
visibility = visibility,
tags = tags,
)
return ":" + name

Expand Down
10 changes: 6 additions & 4 deletions default_conf.py.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,19 @@
#
# SPDX-License-Identifier: Apache-2.0
# *******************************************************************************
# Default Sphinx configuration emitted by the ``docs()`` macro.
# SCORE Docs-as-Code owns these baseline settings. Projects needing further
# Sphinx configuration can provide their own conf.py instead.
# Default Sphinx configuration emitted by the ``docs()`` macro and by
# standalone bundle-local Needs exports. SCORE Docs-as-Code owns these
# baseline settings. Project builds and the root bundle may provide their own
# conf.py; standalone bundle-local exports use this baseline.

project = {PROJECT}
project_url = {PROJECT_URL}
version = "0.0.0"

# Allow feature IDs that use the Bazel module name without its first
# underscore-separated prefix (for example, ``score_docs_as_code`` becomes
# ``docs_as_code``). A user-provided conf.py remains authoritative.
# ``docs_as_code``). A user-provided conf.py remains authoritative for the
# normal project build.
required_in_id = {REQUIRED_IN_ID}

extensions = ["score_sphinx_bundle"]
Loading
Loading