diff --git a/docs.bzl b/docs.bzl index 56eaa297a..5e2d66fbc 100644 --- a/docs.bzl +++ b/docs.bzl @@ -109,13 +109,10 @@ def docs_bundle(name, source_dir = None, data = [], entry_doc = "index", bundles source_dir: optional directory holding this bundle's own doc sources. It is globbed like `docs()` (same file kinds) and the contents are stored after stripping the `source_dir` prefix. Leave it unset for a pure aggregator. - data: - Files owned by this bundle that are not discovered as documentation - sources. Use this for generated RST or other generated files that are - part of the bundle payload and belong at the bundle's eventual mount - location. Use ``docs(data = [...])`` only for project-level inputs - outside a bundle. Both forms make their files available to a build; - only bundle data travels with a mounted bundle. + data: Files owned by this bundle that are not discovered as documentation + sources. This includes generated RST, literalinclude inputs, and assets + that belong at the bundle's eventual mount location. Omitting + ``source_dir`` creates a bundle containing only these files. entry_doc: bundle-relative docname attached when this bundle is mounted. Defaults to `index`. bundles: nested bundles to compose, each a dict @@ -221,12 +218,9 @@ def docs( source_dir: The source directory containing documentation files. Defaults to "docs". project: optional project name, prefer setting this here if you can avoid having a conf.py project_url: Optional project URL, prefer setting this here if you can avoid having a conf.py - data: Additional files needed by the project-level documentation build. - These files are outside any bundle and have no bundle mount path. If a - file should travel with rendered or composable documentation, declare - it in a `docs_bundle` and place that bundle through `bundles` instead. - Generated documentation and assets are not staged into the workspace - source tree for `bazel run`; use a data-only `docs_bundle` for those. + data: Additional files owned by this project's root ``:docs_bundle``. + This is shorthand for declaring the files in that root bundle; mounted + child content belongs in the child ``docs_bundle(data = [...])``. deps: Additional dependencies for the documentation build. external_needs: List of external needs targets to include in the documentation build. scan_code: Deprecated. Explicit source files or filegroups to scan for source @@ -249,11 +243,9 @@ def docs( Note: a bundle label may also point at another module's auto-exposed bundle, e.g. "@score_process_description//:docs_bundle". - The short rule is about ownership and placement, not build availability: - use a bundle for anything that should travel as one portable mount. A - bundle may be data-only when its deliverable is generated/supporting data - rather than source RST. Use ``docs(data = [...])`` only for project-level - inputs that do not belong to a bundle mount. + ``docs(data = [...])`` owns files in the root ``:docs_bundle``. A child + bundle uses the same ``data`` attribute and may omit ``source_dir`` when it + contains only generated or supporting files. """ # HINT: keep documentation sync docs/reference/bazel_macros.rst @@ -282,31 +274,23 @@ def docs( # list-valued attributes such as ``data`` and ``tools``. metamodel_label = [metamodel] if metamodel else [] - data_library_label_for_sphinx_docs = [] + root_bundle_data_for_sphinx = [] if data: - # ``docs_bundle`` can carry data, including as a pure-data bundle. That - # data belongs to the bundle payload and is resolved at its eventual - # mount. These ``docs(data = [...])`` inputs are intentionally - # project-level instead: they support the project build or its - # literalinclude examples and are not assigned to a bundle mount. Both - # kinds of data are build inputs; without the staging below, project- - # level inputs would - # remain only execution inputs for Sphinx's tools rather than files - # below Sphinx's source directory, where standard ``literalinclude`` - # looks for them. - # - # ``sphinx_docs_library`` is the generic rules_python/rules_sphinxdocs - # mechanism for adding such files to the sandboxed needs source tree. - # Preserve their workspace-relative paths so one ordinary - # literalinclude works in that Sphinx action. The interactive run - # target reads the workspace source tree directly; generated files - # belong in a data-only docs_bundle instead. + # TODO: Replace this adapter once the mounts manifest can preserve a + # data file's destination path below the root documentation tree. + # The bundle provider records ownership and propagation. Sphinx uses + # its standard library provider to map the same files into the + # sandboxed source tree while preserving workspace-relative paths for + # literalinclude. sphinx_docs_library( - name = "_docs_data", + name = "_root_bundle_data_for_sphinx", srcs = data, - strip_prefix = "", + # rules_sphinxdocs treats an empty strip_prefix as the package + # path. An unmatched prefix preserves the workspace-relative paths + # used by this macro's direct documentation sources. + strip_prefix = "__root_bundle_data__", ) - data_library_label_for_sphinx_docs = [":_docs_data"] + root_bundle_data_for_sphinx = [":_root_bundle_data_for_sphinx"] mounts_manifest_label = [] if bundles: @@ -346,6 +330,7 @@ def docs( docs_bundle( name = "docs_bundle", source_dir = source_dir, + data = data, entry_doc = "index", bundles = bundles, scan_code = scan_code, @@ -472,7 +457,7 @@ def docs( # complete bundle as srcs would also expose those files as raw Sphinx # sources and make every nested need appear twice. srcs = [sphinx_sources], - deps = data_library_label_for_sphinx_docs, + deps = root_bundle_data_for_sphinx, config = sphinx_config, extra_opts = [ "-W", @@ -490,7 +475,7 @@ def docs( ) + (["--define=score_metamodel_yaml=$(location " + str(metamodel) + ")"] if metamodel else []), formats = ["needs"], sphinx = ":sphinx_build", - tools = data + external_needs + metamodel_label + [":sourcelinks_json", ":docs_bundle"] + mounts_manifest_label, + tools = external_needs + metamodel_label + [":sourcelinks_json", ":docs_bundle"] + mounts_manifest_label, visibility = ["//visibility:public"], # Persistent workers cause stale symlinks after dependency version # changes, corrupting the Bazel cache. diff --git a/docs/how-to/bundles/examples.rst b/docs/how-to/bundles/examples.rst index 3c70beeeb..78d59e8d1 100644 --- a/docs/how-to/bundles/examples.rst +++ b/docs/how-to/bundles/examples.rst @@ -54,9 +54,9 @@ If the parent is mounted at ``guides/example``, its page is rendered at Mount generated documentation ----------------------------- -Use a data-only bundle when a build action produces the documentation rather -than a source-tree ``.rst`` file. It has no ``source_dir``; its generated files -are the bundle's complete payload. You can generate and mount a page like this: +When a build action produces documentation rather than a source-tree ``.rst`` +file, create a bundle without ``source_dir``. Its generated files are the +bundle's complete payload. You can generate and mount a page like this: .. code-block:: starlark @@ -89,9 +89,8 @@ See the `complete generated-data fixture on GitHub `_. The generated page is rendered at ``data_test/index.html`` and is added to the -consuming project's index page's toctree. Although this bundle is data-only, -it is mounted and navigated in exactly the same way as a bundle with source -files. +consuming project's index page's toctree. It is mounted and navigated in +exactly the same way as a bundle with source files. Mount documentation from another module ---------------------------------------- diff --git a/docs/how-to/generated_docs.rst b/docs/how-to/generated_docs.rst index 264189977..cfd2960a8 100644 --- a/docs/how-to/generated_docs.rst +++ b/docs/how-to/generated_docs.rst @@ -23,21 +23,16 @@ with a ``docs_bundle`` and mount the bundle into your documentation tree. You find a `complete working example `_ in the :ref:`metamodel-reference`. -Which ``data`` attribute? -------------------------- +Supporting files belong to bundles +---------------------------------- -For a mounted documentation bundle, put the generated files in -``docs_bundle(data = [...])``. Those files are part of the bundle payload: they -travel with the bundle and are resolved below its eventual ``mount_at`` path. +``docs(data = [...])`` adds files to the root ``:docs_bundle`` exposed by the +macro. A mounted documentation bundle declares its own files with +``docs_bundle(data = [...])``. In both cases the files are bundle payload and, +when mounted, are resolved below the bundle's ``mount_at`` path. -``docs(data = [...])`` is different. It adds files to the project-level -``docs()`` build, outside any bundle, and therefore gives those files no bundle -mount path. Use it only for inputs that belong to the project-level build. If -the file is documentation, an image, or a supporting asset for a bundle, put -it in that bundle instead. - -For this how-to, the rule is simple: generated documentation belongs in -``docs_bundle(data = [...])``. +For this how-to, generated documentation belongs in +``docs_bundle(data = [...])`` because it is mounted as a child bundle. Step 1: Generate the RST Files ------------------------------ @@ -81,11 +76,10 @@ Do not use ``srcs`` — that is for handwritten sources in the source tree. data = [":generate_design_rst"], ) -This is a **data-only bundle**: it has no ``source_dir`` because all of its -documentation is generated. It is still a normal mountable bundle. The -generated ``index.rst`` becomes the bundle's entry page and travels with the -bundle when it is mounted. A bundle with both handwritten sources and -generated files can use ``source_dir`` and ``data`` together. +This bundle has no ``source_dir`` because all of its documentation is +generated. The generated ``index.rst`` becomes the bundle's entry page and +travels with the bundle when it is mounted. A bundle with both handwritten +sources and generated files can use ``source_dir`` and ``data`` together. Verify: ``bazel build :design_bundle`` must succeed. diff --git a/docs/reference/bazel_macros.rst b/docs/reference/bazel_macros.rst index d6f2ffc43..275dcbbfc 100644 --- a/docs/reference/bazel_macros.rst +++ b/docs/reference/bazel_macros.rst @@ -25,25 +25,18 @@ See :doc:`commands ` for the targets/commands it creates. The macro must be called from the repository root package. -Supporting files: project inputs and bundle payloads ----------------------------------------------------- - -There are two ``data`` attributes, and they belong to different documentation -trees: - -* ``docs_bundle(data = [...])`` puts files in a bundle payload. The files - travel with that bundle and are resolved below the bundle's eventual - ``mount_at`` path. Use this for generated documentation, images, and other - assets needed by a mounted bundle. -* ``docs(data = [...])`` puts files in the project-level ``docs()`` build, - outside any bundle. These files have no bundle mount path. Use this only for - inputs needed by the project-level build itself. ``bazel run`` does not copy - generated data into the workspace source tree; generated documentation or - assets must use ``docs_bundle(data = [...])``. - -If a file belongs to a mounted bundle, use ``docs_bundle(data = [...])``. -Both attributes make files available to a build; they differ in which -documentation tree carries the files and where they are resolved. +Supporting files +---------------- + +Documentation supporting files always belong to a ``docs_bundle``. The +``data`` argument of ``docs()`` is shorthand for adding files to the root +``:docs_bundle`` that the macro exposes. A mounted module puts its files in +its own ``docs_bundle(data = [...])``; those files travel with that bundle and +are resolved below its eventual ``mount_at`` path. + +A bundle with ``data`` but no ``source_dir`` is simply a bundle whose content +is generated or supporting files. It uses the same ownership and placement +mechanism as every other bundle. Minimal example (root ``BUILD``) -------------------------------- @@ -83,11 +76,10 @@ Minimal example (root ``BUILD``) it remains authoritative and these values are not used. - ``data`` (list of bazel labels) - Extra runfiles / data targets that should be made available to the documentation targets. - The items in ``data`` are added to the py_binaries and to the Sphinx tooling so they are - available at build time. These are project-level inputs; they are not part of - a bundle and do not receive a bundle mount path. Use ``docs_bundle(data = [...])`` - for files that belong to mounted documentation. + Supporting files for this project's root ``:docs_bundle``. The files are + available to the documentation targets and travel when another project + mounts this project's public bundle. Put files belonging to a mounted child + in that child's ``docs_bundle(data = [...])`` instead. .. note:: @@ -185,9 +177,8 @@ Signature: ``docs_bundle(name, source_dir = None, data = [], entry_doc = "index" the bundle payload and are available at the bundle's eventual mount path; they are useful for generated documentation sources such as a generated ``index.rst``. If ``source_dir`` is omitted and ``data`` contains the - bundle's deliverable, the result is a data-only bundle. Use this attribute - for any file that belongs with the mounted bundle. Use - ``docs(data = [...])`` only for project-level inputs outside a bundle. + bundle's deliverable, the result is a bundle containing only supporting + files. Use this attribute for every file that belongs with a mounted bundle. - ``entry_doc`` (string, optional) Bundle-relative docname used as the canonical navigation entry. It defaults to diff --git a/src/tests/docs_bzl/scenarios/basic_docs/BUILD b/src/tests/docs_bzl/scenarios/basic_docs/BUILD index 7ef270b83..9a076f759 100644 --- a/src/tests/docs_bzl/scenarios/basic_docs/BUILD +++ b/src/tests/docs_bzl/scenarios/basic_docs/BUILD @@ -17,5 +17,6 @@ docs( source_dir = "docs", project = "Basic Test", project_url = "https://github.com/eclipse-score/docs-as-code", + data = ["supporting-example.txt"], test_sources = ["src/tests/docs_bzl/scenarios/basic_docs"], ) diff --git a/src/tests/docs_bzl/scenarios/basic_docs/docs/index.rst b/src/tests/docs_bzl/scenarios/basic_docs/docs/index.rst index cc8afd54b..8bc5f00f3 100644 --- a/src/tests/docs_bzl/scenarios/basic_docs/docs/index.rst +++ b/src/tests/docs_bzl/scenarios/basic_docs/docs/index.rst @@ -14,3 +14,5 @@ Basic Test ========== + +.. literalinclude:: ../supporting-example.txt diff --git a/src/tests/docs_bzl/scenarios/basic_docs/supporting-example.txt b/src/tests/docs_bzl/scenarios/basic_docs/supporting-example.txt new file mode 100644 index 000000000..fce941dc4 --- /dev/null +++ b/src/tests/docs_bzl/scenarios/basic_docs/supporting-example.txt @@ -0,0 +1 @@ +The root bundle owns this supporting file. diff --git a/src/tests/docs_bzl/test_basic_docs.py b/src/tests/docs_bzl/test_basic_docs.py index ff92ffb1e..199bafdd1 100644 --- a/src/tests/docs_bzl/test_basic_docs.py +++ b/src/tests/docs_bzl/test_basic_docs.py @@ -25,6 +25,7 @@ def test_basic_docs_builds_html(): def test_basic_docs_builds_needs_without_conf_py(): + """Root docs data supports literalinclude in the sandboxed Sphinx build.""" result = run_scenario("build", "basic_docs", ":needs_json") # With no docs/conf.py the generated config is used; it must set a non-empty