diff --git a/docs/BUILD.bazel b/docs/BUILD.bazel index 0c815940ba..aa1345aa08 100644 --- a/docs/BUILD.bazel +++ b/docs/BUILD.bazel @@ -19,10 +19,13 @@ load("//python/private:util.bzl", "IS_BAZEL_7_OR_HIGHER") # buildifier: disable load("//python/uv/private:lock.bzl", "lock") # buildifier: disable=bzl-visibility load("//sphinxdocs:readthedocs.bzl", "readthedocs_install") load("//sphinxdocs:sphinx.bzl", "sphinx_build_binary", "sphinx_docs") +load("//sphinxdocs:sphinx_docs_library.bzl", "sphinx_docs_library") load("//sphinxdocs:sphinx_stardoc.bzl", "sphinx_stardoc", "sphinx_stardocs") package(default_visibility = ["//:__subpackages__"]) +licenses(["notice"]) # Apache 2.0 + # We only build for Linux and Mac because: # 1. The actual doc process only runs on Linux # 2. Mac is a common development platform, and is close enough to Linux @@ -68,6 +71,7 @@ sphinx_docs( target_compatible_with = _TARGET_COMPATIBLE_WITH, deps = [ ":bzl_api_docs", + ":py_api_srcs", "//sphinxdocs/docs:docs_lib", ], ) @@ -97,7 +101,7 @@ sphinx_stardocs( # This depends on @pythons_hub, which is only created under bzlmod, "//python/extensions:pip_bzl", ] if IS_BAZEL_7_OR_HIGHER and BZLMOD_ENABLED else []), - prefix = "api/", + prefix = "api/rules_python/", tags = ["docs"], target_compatible_with = _TARGET_COMPATIBLE_WITH, ) @@ -105,7 +109,7 @@ sphinx_stardocs( sphinx_stardoc( name = "py_cc_toolchain", src = "//python/private:py_cc_toolchain_rule.bzl", - prefix = "api/", + prefix = "api/rules_python/", public_load_path = "//python/cc:py_cc_toolchain.bzl", tags = ["docs"], target_compatible_with = _TARGET_COMPATIBLE_WITH, @@ -115,11 +119,20 @@ sphinx_stardoc( sphinx_stardoc( name = "py_runtime_pair", src = "//python/private:py_runtime_pair_rule_bzl", + prefix = "api/rules_python", public_load_path = "//python:py_runtime_pair.bzl", tags = ["docs"], target_compatible_with = _TARGET_COMPATIBLE_WITH, ) +sphinx_docs_library( + name = "py_api_srcs", + srcs = [ + "//python/runfiles", + ], + strip_prefix = "python/", +) + readthedocs_install( name = "readthedocs_install", docs = [":docs"], @@ -135,6 +148,8 @@ sphinx_build_binary( requirement("myst_parser"), requirement("readthedocs_sphinx_ext"), requirement("typing_extensions"), + requirement("sphinx_autodoc2"), + requirement("sphinx_reredirects"), "//sphinxdocs/src/sphinx_bzl", ], ) @@ -147,8 +162,6 @@ lock( upgrade = True, ) -licenses(["notice"]) # Apache 2.0 - # Temporary compatibility aliases for some other projects depending on the old # bzl_library targets. alias( diff --git a/docs/api/index.md b/docs/api/index.md index 028fab7f84..87e17e1a8f 100644 --- a/docs/api/index.md +++ b/docs/api/index.md @@ -2,5 +2,6 @@ ```{toctree} :glob: -** +* +*/index ``` diff --git a/docs/api/rules_python/index.md b/docs/api/rules_python/index.md new file mode 100644 index 0000000000..7e4d1ff336 --- /dev/null +++ b/docs/api/rules_python/index.md @@ -0,0 +1,8 @@ +# rules_python Bazel APIs + +API documentation for rules_python Bazel objects. + +```{toctree} +:glob: +** +``` diff --git a/docs/api/python/cc/index.md b/docs/api/rules_python/python/cc/index.md similarity index 100% rename from docs/api/python/cc/index.md rename to docs/api/rules_python/python/cc/index.md diff --git a/docs/api/python/config_settings/index.md b/docs/api/rules_python/python/config_settings/index.md similarity index 100% rename from docs/api/python/config_settings/index.md rename to docs/api/rules_python/python/config_settings/index.md diff --git a/docs/api/python/index.md b/docs/api/rules_python/python/index.md similarity index 100% rename from docs/api/python/index.md rename to docs/api/rules_python/python/index.md diff --git a/docs/api/python/runtime_env_toolchains/index.md b/docs/api/rules_python/python/runtime_env_toolchains/index.md similarity index 100% rename from docs/api/python/runtime_env_toolchains/index.md rename to docs/api/rules_python/python/runtime_env_toolchains/index.md diff --git a/docs/api/tools/precompiler/index.md b/docs/api/rules_python/tools/precompiler/index.md similarity index 100% rename from docs/api/tools/precompiler/index.md rename to docs/api/rules_python/tools/precompiler/index.md diff --git a/docs/conf.py b/docs/conf.py index be428a6eb8..ba628b6fc1 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -18,9 +18,8 @@ # Any extensions here not built into Sphinx must also be added to # the dependencies of //docs:sphinx-builder extensions = [ - "sphinx.ext.autodoc", + "autodoc2", "sphinx.ext.autosectionlabel", - "sphinx.ext.autosummary", "sphinx.ext.doctest", "sphinx.ext.duration", "sphinx.ext.extlinks", @@ -28,8 +27,72 @@ "myst_parser", "sphinx_rtd_theme", # Necessary to get jquery to make flyout work "sphinx_bzl.bzl", + "sphinx_reredirects", ] +autodoc2_packages = [ + "sphinx_bzl", + "runfiles", +] + +autodoc2_output_dir = "api/py" +autodoc2_sort_names = True +autodoc2_class_docstring = "both" +autodoc2_index_template = """ +Python APIs +==================== + +This page contains auto-generated API reference documentation [#f1]_. + +.. toctree:: + :titlesonly: + +{% for package in top_level %} + {{ package }} +{%- endfor %} + +.. [#f1] Created with `sphinx-autodoc2 `_ + +""" + + +autodoc2_docstring_parser_regexes = [ + (".*", "myst"), +] + +# NOTE: The redirects generation will clobber existing files. +redirects = { + "api/tools/precompiler/index": "/api/rules_python/tools/precompiler/index.html", + "api/python/py_library": "/api/rules_python/python/py_library.html", + "api/python/py_binary": "/api/rules_python/python/py_binary.html", + "api/python/py_test": "/api/rules_python/python/py_test.html", + "api/python/defs": "/api/rules_python/python/defs.html", + "api/python/index": "/api/rules_python/python/index.html", + "api/python/py_runtime_info": "/api/rules_python/python/py_runtime_info.html", + "api/python/private/common/py_library_rule_bazel": "/api/rules_python/python/private/common/py_library_rule_bazel.html", + "api/python/private/common/py_test_rule_bazel": "/api/rules_python/python/private/common/py_test_rule_bazel.html", + "api/python/private/common/py_binary_rule_bazel": "/api/rules_python/python/private/common/py_binary_rule_bazel.html", + "api/python/private/common/py_runtime_rule": "/api/rules_python/python/private/common/py_runtime_rule.html", + "api/python/extensions/pip": "/api/rules_python/python/extensions/pip.html", + "api/python/extensions/python": "/api/rules_python/python/extensions/python.html", + "api/python/entry_points/py_console_script_binary": "/api/rules_python/python/entry_points/py_console_script_binary.html", + "api/python/cc/py_cc_toolchain_info": "/api/rules_python/python/cc/py_cc_toolchain_info.html", + "api/python/cc/index": "/api/rules_python/python/cc/index.html", + "api/python/py_cc_link_params_info": "/api/rules_python/python/py_cc_link_params_info.html", + "api/python/runtime_env_toolchains/index": "/api/rules_python/python/runtime_env_toolchains/index.html", + "api/python/pip": "/api/rules_python/python/pip.html", + "api/python/config_settings/index": "/api/rules_python/python/config_settings/index.html", + "api/python/packaging": "/api/rules_python/python/packaging.html", + "api/python/py_runtime": "/api/rules_python/python/py_runtime.html", + "api/sphinxdocs/sphinx": "/api/sphinxdocs/sphinxdocs/sphinx.html", + "api/sphinxdocs/sphinx_stardoc": "/api/sphinxdocs/sphinxdocs/sphinx_stardoc.html", + "api/sphinxdocs/readthedocs": "/api/sphinxdocs/sphinxdocs/readthedocs.html", + "api/sphinxdocs/index": "/api/sphinxdocs/sphinxdocs/index.html", + "api/sphinxdocs/private/sphinx_docs_library": "/api/sphinxdocs/sphinxdocs/private/sphinx_docs_library.html", + "api/sphinxdocs/sphinx_docs_library": "/api/sphinxdocs/sphinxdocs/sphinx_docs_library.html", + "api/sphinxdocs/inventories/index": "/api/sphinxdocs/sphinxdocs/inventories/index.html", +} + # Adapted from the template code: # https://github.com/readthedocs/readthedocs.org/blob/main/readthedocs/doc_builder/templates/doc_builder/conf.py.tmpl if os.environ.get("READTHEDOCS") == "True": diff --git a/docs/pyproject.toml b/docs/pyproject.toml index 03279c56e3..2bcb31bfc2 100644 --- a/docs/pyproject.toml +++ b/docs/pyproject.toml @@ -5,10 +5,12 @@ version = "0.0.0" dependencies = [ # NOTE: This is only used as input to create the resolved requirements.txt # file, which is what builds, both Bazel and Readthedocs, both use. + "sphinx-autodoc2", "sphinx", "myst-parser", - "sphinx_rtd_theme", + "sphinx_rtd_theme >=2.0", # uv insists on downgrading for some reason "readthedocs-sphinx-ext", "absl-py", - "typing-extensions" + "typing-extensions", + "sphinx-reredirects" ] diff --git a/docs/requirements.txt b/docs/requirements.txt index 7cd03296fe..19affcb02a 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -10,9 +10,13 @@ alabaster==0.7.16 \ --hash=sha256:75a8b99c28a5dad50dd7f8ccdd447a121ddb3892da9e53d1ca5cca3106d58d65 \ --hash=sha256:b46733c07dce03ae4e150330b975c75737fa60f0a7c591b6c8bf4928a28e2c92 # via sphinx -babel==2.15.0 \ - --hash=sha256:08706bdad8d0a3413266ab61bd6c34d0c28d6e1e7badf40a2cebe67644e2e1fb \ - --hash=sha256:8daf0e265d05768bc6c7a314cf1321e9a123afc328cc635c18622a2f30a04413 +astroid==3.3.2 \ + --hash=sha256:99e9b5b602cbb005434084309213d6af32bf7a9b743c836749168b8e2b330cbd \ + --hash=sha256:9f8136ce9770e0f912401b25a0f15d5c2ec20b50e99b1b413ac0778fe53ff6f1 + # via sphinx-autodoc2 +babel==2.16.0 \ + --hash=sha256:368b5b98b37c06b7daf6696391c3240c938b37767d4584413e8438c5c435fa8b \ + --hash=sha256:d1f3554ca26605fe173f3de0c65f750f5a42f924499bf134de6423582298e316 # via sphinx certifi==2024.7.4 \ --hash=sha256:5a1e7645bc0ec61a09e26c36f6106dd4cf40c6db3a1fb6352b0244e7fb057c7b \ @@ -121,9 +125,9 @@ docutils==0.20.1 \ # myst-parser # sphinx # sphinx-rtd-theme -idna==3.7 \ - --hash=sha256:028ff3aadf0609c1fd278d8ea3089299412a7a8b9bd005dd08b9f8285bcb5cfc \ - --hash=sha256:82fee1fc78add43492d3a1898bfa6d8a904cc97d8427f683ed8e798d07761aa0 +idna==3.8 \ + --hash=sha256:050b4e5baadcd44d760cedbd2b8e639f2ff89bbc7a5730fcc662954303377aac \ + --hash=sha256:d838c2c0ed6fced7693d5e8ab8e734d5f8fda53a039c0164afb0b82e771e3603 # via requests imagesize==1.4.1 \ --hash=sha256:0d8d18d08f840c19d0ee7ca1fd82490fdc3729b7ac93f49870406ddde8ef8d8b \ @@ -226,58 +230,60 @@ pygments==2.18.0 \ --hash=sha256:786ff802f32e91311bff3889f6e9a86e81505fe99f2735bb6d60ae0c5004f199 \ --hash=sha256:b8e6aca0523f3ab76fee51799c488e38782ac06eafcf95e7ba832985c8e7b13a # via sphinx -pyyaml==6.0.1 \ - --hash=sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5 \ - --hash=sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc \ - --hash=sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df \ - --hash=sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741 \ - --hash=sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206 \ - --hash=sha256:18aeb1bf9a78867dc38b259769503436b7c72f7a1f1f4c93ff9a17de54319b27 \ - --hash=sha256:1d4c7e777c441b20e32f52bd377e0c409713e8bb1386e1099c2415f26e479595 \ - --hash=sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62 \ - --hash=sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98 \ - --hash=sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696 \ - --hash=sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290 \ - --hash=sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9 \ - --hash=sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d \ - --hash=sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6 \ - --hash=sha256:4fb147e7a67ef577a588a0e2c17b6db51dda102c71de36f8549b6816a96e1867 \ - --hash=sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47 \ - --hash=sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486 \ - --hash=sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6 \ - --hash=sha256:596106435fa6ad000c2991a98fa58eeb8656ef2325d7e158344fb33864ed87e3 \ - --hash=sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007 \ - --hash=sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938 \ - --hash=sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0 \ - --hash=sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c \ - --hash=sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735 \ - --hash=sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d \ - --hash=sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28 \ - --hash=sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4 \ - --hash=sha256:9046c58c4395dff28dd494285c82ba00b546adfc7ef001486fbf0324bc174fba \ - --hash=sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8 \ - --hash=sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef \ - --hash=sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5 \ - --hash=sha256:afd7e57eddb1a54f0f1a974bc4391af8bcce0b444685d936840f125cf046d5bd \ - --hash=sha256:b1275ad35a5d18c62a7220633c913e1b42d44b46ee12554e5fd39c70a243d6a3 \ - --hash=sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0 \ - --hash=sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515 \ - --hash=sha256:baa90d3f661d43131ca170712d903e6295d1f7a0f595074f151c0aed377c9b9c \ - --hash=sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c \ - --hash=sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924 \ - --hash=sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34 \ - --hash=sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43 \ - --hash=sha256:c8098ddcc2a85b61647b2590f825f3db38891662cfc2fc776415143f599bb859 \ - --hash=sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673 \ - --hash=sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54 \ - --hash=sha256:d858aa552c999bc8a8d57426ed01e40bef403cd8ccdd0fc5f6f04a00414cac2a \ - --hash=sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b \ - --hash=sha256:f003ed9ad21d6a4713f0a9b5a7a0a79e08dd0f221aff4525a2be4c346ee60aab \ - --hash=sha256:f22ac1c3cac4dbc50079e965eba2c1058622631e526bd9afd45fedd49ba781fa \ - --hash=sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c \ - --hash=sha256:fca0e3a251908a499833aa292323f32437106001d436eca0e6e7833256674585 \ - --hash=sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d \ - --hash=sha256:fd66fc5d0da6d9815ba2cebeb4205f95818ff4b79c3ebe268e75d961704af52f +pyyaml==6.0.2 \ + --hash=sha256:01179a4a8559ab5de078078f37e5c1a30d76bb88519906844fd7bdea1b7729ff \ + --hash=sha256:0833f8694549e586547b576dcfaba4a6b55b9e96098b36cdc7ebefe667dfed48 \ + --hash=sha256:0a9a2848a5b7feac301353437eb7d5957887edbf81d56e903999a75a3d743086 \ + --hash=sha256:0b69e4ce7a131fe56b7e4d770c67429700908fc0752af059838b1cfb41960e4e \ + --hash=sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133 \ + --hash=sha256:11d8f3dd2b9c1207dcaf2ee0bbbfd5991f571186ec9cc78427ba5bd32afae4b5 \ + --hash=sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484 \ + --hash=sha256:1e2120ef853f59c7419231f3bf4e7021f1b936f6ebd222406c3b60212205d2ee \ + --hash=sha256:1f71ea527786de97d1a0cc0eacd1defc0985dcf6b3f17bb77dcfc8c34bec4dc5 \ + --hash=sha256:23502f431948090f597378482b4812b0caae32c22213aecf3b55325e049a6c68 \ + --hash=sha256:24471b829b3bf607e04e88d79542a9d48bb037c2267d7927a874e6c205ca7e9a \ + --hash=sha256:29717114e51c84ddfba879543fb232a6ed60086602313ca38cce623c1d62cfbf \ + --hash=sha256:2e99c6826ffa974fe6e27cdb5ed0021786b03fc98e5ee3c5bfe1fd5015f42b99 \ + --hash=sha256:39693e1f8320ae4f43943590b49779ffb98acb81f788220ea932a6b6c51004d8 \ + --hash=sha256:3ad2a3decf9aaba3d29c8f537ac4b243e36bef957511b4766cb0057d32b0be85 \ + --hash=sha256:3b1fdb9dc17f5a7677423d508ab4f243a726dea51fa5e70992e59a7411c89d19 \ + --hash=sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc \ + --hash=sha256:43fa96a3ca0d6b1812e01ced1044a003533c47f6ee8aca31724f78e93ccc089a \ + --hash=sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1 \ + --hash=sha256:5ac9328ec4831237bec75defaf839f7d4564be1e6b25ac710bd1a96321cc8317 \ + --hash=sha256:5d225db5a45f21e78dd9358e58a98702a0302f2659a3c6cd320564b75b86f47c \ + --hash=sha256:6395c297d42274772abc367baaa79683958044e5d3835486c16da75d2a694631 \ + --hash=sha256:688ba32a1cffef67fd2e9398a2efebaea461578b0923624778664cc1c914db5d \ + --hash=sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652 \ + --hash=sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5 \ + --hash=sha256:797b4f722ffa07cc8d62053e4cff1486fa6dc094105d13fea7b1de7d8bf71c9e \ + --hash=sha256:7c36280e6fb8385e520936c3cb3b8042851904eba0e58d277dca80a5cfed590b \ + --hash=sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8 \ + --hash=sha256:80bab7bfc629882493af4aa31a4cfa43a4c57c83813253626916b8c7ada83476 \ + --hash=sha256:82d09873e40955485746739bcb8b4586983670466c23382c19cffecbf1fd8706 \ + --hash=sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563 \ + --hash=sha256:8824b5a04a04a047e72eea5cec3bc266db09e35de6bdfe34c9436ac5ee27d237 \ + --hash=sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b \ + --hash=sha256:9056c1ecd25795207ad294bcf39f2db3d845767be0ea6e6a34d856f006006083 \ + --hash=sha256:936d68689298c36b53b29f23c6dbb74de12b4ac12ca6cfe0e047bedceea56180 \ + --hash=sha256:9b22676e8097e9e22e36d6b7bda33190d0d400f345f23d4065d48f4ca7ae0425 \ + --hash=sha256:a4d3091415f010369ae4ed1fc6b79def9416358877534caf6a0fdd2146c87a3e \ + --hash=sha256:a8786accb172bd8afb8be14490a16625cbc387036876ab6ba70912730faf8e1f \ + --hash=sha256:a9f8c2e67970f13b16084e04f134610fd1d374bf477b17ec1599185cf611d725 \ + --hash=sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183 \ + --hash=sha256:c70c95198c015b85feafc136515252a261a84561b7b1d51e3384e0655ddf25ab \ + --hash=sha256:cc1c1159b3d456576af7a3e4d1ba7e6924cb39de8f67111c735f6fc832082774 \ + --hash=sha256:ce826d6ef20b1bc864f0a68340c8b3287705cae2f8b4b1d932177dcc76721725 \ + --hash=sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e \ + --hash=sha256:d7fded462629cfa4b685c5416b949ebad6cec74af5e2d42905d41e257e0869f5 \ + --hash=sha256:d84a1718ee396f54f3a086ea0a66d8e552b2ab2017ef8b420e92edbc841c352d \ + --hash=sha256:d8e03406cac8513435335dbab54c0d385e4a49e4945d2909a581c83647ca0290 \ + --hash=sha256:e10ce637b18caea04431ce14fabcf5c64a1c61ec9c56b071a4b7ca131ca52d44 \ + --hash=sha256:ec031d5d2feb36d1d1a24380e4db6d43695f3748343d99434e6f5f9156aaa2ed \ + --hash=sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4 \ + --hash=sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba \ + --hash=sha256:f753120cb8181e736c57ef7636e83f31b9c0d1722c516f7e86cf15b7aa57ff12 \ + --hash=sha256:ff3824dc5261f50c9b0dfb3be22b4567a6f938ccce4587b38952d85fd9e9afe4 # via myst-parser readthedocs-sphinx-ext==2.2.5 \ --hash=sha256:ee5fd5b99db9f0c180b2396cbce528aa36671951b9526bb0272dbfce5517bd27 \ @@ -299,8 +305,17 @@ sphinx==7.4.7 \ # via # rules-python-docs (docs/pyproject.toml) # myst-parser + # sphinx-reredirects # sphinx-rtd-theme # sphinxcontrib-jquery +sphinx-autodoc2==0.5.0 \ + --hash=sha256:7d76044aa81d6af74447080182b6868c7eb066874edc835e8ddf810735b6565a \ + --hash=sha256:e867013b1512f9d6d7e6f6799f8b537d6884462acd118ef361f3f619a60b5c9e + # via rules-python-docs (docs/pyproject.toml) +sphinx-reredirects==0.1.5 \ + --hash=sha256:444ae1438fba4418242ca76d6a6de3eaee82aaf0d8f2b0cac71a15d32ce6eba2 \ + --hash=sha256:cfa753b441020a22708ce8eb17d4fd553a28fc87a609330092917ada2a6da0d8 + # via rules-python-docs (docs/pyproject.toml) sphinx-rtd-theme==2.0.0 \ --hash=sha256:bd5d7b80622406762073a04ef8fadc5f9151261563d47027de09910ce03afe6b \ --hash=sha256:ec93d0856dc280cf3aee9a4c9807c60e027c7f7b461b77aeffed682e68f0e586 @@ -336,7 +351,9 @@ sphinxcontrib-serializinghtml==2.0.0 \ typing-extensions==4.12.2 \ --hash=sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d \ --hash=sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8 - # via rules-python-docs (docs/pyproject.toml) + # via + # rules-python-docs (docs/pyproject.toml) + # sphinx-autodoc2 urllib3==2.2.2 \ --hash=sha256:a448b2f64d686155468037e1ace9f2d2199776e17f0a46610480d311f73e3472 \ --hash=sha256:dd505485549a7a552833da5e6063639d0d177c04f23bc3864e41e5dc5f612168 diff --git a/sphinxdocs/docs/BUILD.bazel b/sphinxdocs/docs/BUILD.bazel index a85155b0ef..6af908dc4c 100644 --- a/sphinxdocs/docs/BUILD.bazel +++ b/sphinxdocs/docs/BUILD.bazel @@ -20,13 +20,14 @@ sphinx_docs_library( name = "docs_lib", deps = [ ":artisian_api_docs", - ":artisian_docs", ":bzl_docs", + ":py_api_srcs", + ":regular_docs", ], ) sphinx_docs_library( - name = "artisian_docs", + name = "regular_docs", srcs = glob( ["**/*.md"], exclude = ["api/**"], @@ -39,6 +40,8 @@ sphinx_docs_library( srcs = glob( ["api/**/*.md"], ), + prefix = "api/sphinxdocs/", + strip_prefix = "sphinxdocs/docs/api/", ) sphinx_stardocs( @@ -50,6 +53,12 @@ sphinx_stardocs( "//sphinxdocs:sphinx_stardoc_bzl", "//sphinxdocs/private:sphinx_docs_library_bzl", ], - prefix = "api/", + prefix = "api/sphinxdocs/", target_compatible_with = _TARGET_COMPATIBLE_WITH, ) + +sphinx_docs_library( + name = "py_api_srcs", + srcs = ["//sphinxdocs/src/sphinx_bzl"], + strip_prefix = "sphinxdocs/src/", +) diff --git a/sphinxdocs/docs/api/index.md b/sphinxdocs/docs/api/index.md new file mode 100644 index 0000000000..3420b9180d --- /dev/null +++ b/sphinxdocs/docs/api/index.md @@ -0,0 +1,8 @@ +# sphinxdocs Bazel APIs + +API documentation for sphinxdocs Bazel objects. + +```{toctree} +:glob: +** +``` diff --git a/sphinxdocs/docs/sphinx-bzl.md b/sphinxdocs/docs/sphinx-bzl.md index 331e04acd4..0edd3202b6 100644 --- a/sphinxdocs/docs/sphinx-bzl.md +++ b/sphinxdocs/docs/sphinx-bzl.md @@ -53,6 +53,11 @@ While MyST isn't required for the core `sphinx_bzl` plugin to work, this document uses MyST syntax because `sphinx_stardoc` bzl doc gen rule requires MyST. +The main difference in syntax is: +* MyST directives use `:::{name}` with closing `:::` instead of `.. name::` with + indented content. +* MyST roles use `{role:name}` instead of `:role:name:` + ## Type expressions Several roles or fields accept type expressions. Type expressions use @@ -78,7 +83,7 @@ will try to find something that matches. Additionally, in `.bzl` code, the {obj}`py_binary` ``` -The text that is displayed by be customized by putting the reference string in +The text that is displayed can be customized by putting the reference string in chevrons (`<>`): ``` @@ -102,23 +107,52 @@ syntaxes](https://myst-parser.readthedocs.io/en/latest/syntax/cross-referencing. ### Cross reference roles A cross reference role is the `obj` portion of `{bzl:obj}`. It affects what is -searched and matched. Supported cross reference roles are: +searched and matched. + +:::{note} +The documentation renders using RST notation (`:foo:role:`), not +MyST notation (`{foo:role}`. +::: + +:::{rst:role} bzl:arg +Refer to a function argument. +::: + +:::{rst:role} bzl:attr +Refer to a rule attribute. +::: + +:::{rst:role} bzl:flag +Refer to a flag. +::: + +:::{rst:role} bzl:obj +Refer to any type of Bazel object +::: + +:::{rst:role} bzl:rule +Refer to a rule. +::: + +:::{rst:role} bzl:target +Refer to a target. +::: -* `{bzl:arg}`: Refer to a function argument. -* `{bzl:attr}`: Refer to a rule attribute. -* `{bzl:flag}`: Refer to a flag. -* `{bzl:obj}`: Refer to any type of Bazel object -* `{bzl:rule}`: Refer to a rule. -* `{bzl:target}`: Refer to a target. -* `{bzl:type}`: Refer to a type or type expression; can also be used in argument - documentation. +:::{rst:role} bzl:type +Refer to a type or type expression; can also be used in argument documentation. +::: ## Special roles There are several special roles that can be used to annotate parts of objects, such as the type of arguments or their default values. -### Role bzl:default-value +:::{note} +The documentation renders using RST notation (`:foo:role:`), not +MyST notation (`{foo:role}`. +::: + +:::{rst:role} bzl:default-value Indicate the default value for a function argument or rule attribute. Use it in the Args doc of a function or the doc text of an attribute. @@ -135,8 +169,9 @@ my_rule = rule(attrs = { }) ``` +::: -### Role bzl:return-type +:::{rst:role} bzl:return-type Indicates the return type for a function. Use it in the Returns doc of a function. @@ -150,8 +185,9 @@ def func(): """ return 1 ``` +::: -### Role bzl:type +:::{rst:role} bzl:type Indicates the type of an argument for a function. Use it in the Args doc of a function. @@ -165,6 +201,7 @@ def func(arg): """ print(arg + 1) ``` +::: ## Directives @@ -182,15 +219,26 @@ Doc about target ::: ``` -### Directive bzl:currentfile +:::{note} +The documentation renders using RST notation (`.. directive::`), not +MyST notation. +::: + +:::{rst:directive} .. bzl:currentfile:: file This directive indicates the Bazel file that objects defined in the current documentation file are in. This is required for any page that defines Bazel -objects. +objects. The format of `file` is Bazel label syntax, e.g. `//foo:bar.bzl` for bzl +files, and `//foo:BUILD.bazel` for things in BUILD files. + +::: -### Directive bzl:target -Documents a target. It takes no directive options +:::{rst:directive} .. bzl:target:: target + +Documents a target. It takes no directive options. The format of `target` +can either be a fully qualified label (`//foo:bar`), or the base target name +relative to `{bzl:currentfile}`. ``` :::{bzl:target} //foo:target @@ -199,6 +247,8 @@ My docs ::: ``` -### Directive bzl:flag +:::{rst:directive} .. bzl:flag:: target + +Documents a flag. It has the same format as `{bzl:target}` +::: -Documents a flag. It has the same format as `bzl:target` diff --git a/sphinxdocs/private/BUILD.bazel b/sphinxdocs/private/BUILD.bazel index d91e048e8f..c4246ed0de 100644 --- a/sphinxdocs/private/BUILD.bazel +++ b/sphinxdocs/private/BUILD.bazel @@ -29,6 +29,7 @@ exports_files( "readthedocs_install.py", "sphinx_build.py", "sphinx_server.py", + "sphinx_run_template.sh", ], visibility = ["//visibility:public"], ) diff --git a/sphinxdocs/private/sphinx.bzl b/sphinxdocs/private/sphinx.bzl index a198291a88..5724be856d 100644 --- a/sphinxdocs/private/sphinx.bzl +++ b/sphinxdocs/private/sphinx.bzl @@ -4,7 +4,7 @@ # 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 +# 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, @@ -27,10 +27,43 @@ _SPHINX_SERVE_MAIN_SRC = Label("//sphinxdocs/private:sphinx_server.py") _SphinxSourceTreeInfo = provider( doc = "Information about source tree for Sphinx to build.", fields = { + "source_dir_runfiles_path": """ +:type: str + +Runfiles-root relative path of the root directory for the source files. +""", "source_root": """ :type: str -Path of the root directory for the source files (which are in DefaultInfo.files) +Exec-root relative path of the root directory for the source files (which are in DefaultInfo.files) +""", + }, +) + +_SphinxRunInfo = provider( + doc = "Information for running the underlying Sphinx command directly", + fields = { + "per_format_args": """ +:type: dict[str, struct] + +A dict keyed by output format name. The values are a struct with attributes: +* args: a `list[str]` of args to run this format's build +* env: a `dict[str, str]` of environment variables to set for this format's build +""", + "source_tree": """ +:type: Target + +Target with the source tree files +""", + "sphinx": """ +:type: Target + +The sphinx-build binary to run. +""", + "tools": """ +:type: list[Target] + +Additional tools Sphinx needs """, }, ) @@ -74,16 +107,15 @@ def sphinx_docs( **kwargs): """Generate docs using Sphinx. - This generates three public targets: + Generates targets: * ``: The output of this target is a directory for each format Sphinx creates. This target also has a separate output group for each format. e.g. `--output_group=html` will only build the "html" format files. - * `_define`: A multi-string flag to add additional `-D` - arguments to the Sphinx invocation. This is useful for overriding - the version information in the config file for builds. * `.serve`: A binary that locally serves the HTML output. This allows previewing docs during development. + * `.run`: A binary that directly runs the underlying Sphinx command + to build the docs. This is a debugging aid. Args: name: {type}`Name` name of the docs rule. @@ -116,8 +148,10 @@ def sphinx_docs( add_tag(kwargs, "@rules_python//sphinxdocs:sphinx_docs") common_kwargs = copy_propagating_kwargs(kwargs) + internal_name = "_{}".format(name.lstrip("_")) + _sphinx_source_tree( - name = name + "/_sources", + name = internal_name + "/_sources", srcs = srcs, deps = deps, renamed_srcs = renamed_srcs, @@ -129,13 +163,13 @@ def sphinx_docs( name = name, sphinx = sphinx, formats = formats, - source_tree = name + "/_sources", + source_tree = internal_name + "/_sources", extra_opts = extra_opts, tools = tools, **kwargs ) - html_name = "_{}_html".format(name.lstrip("_")) + html_name = internal_name + "_html" native.filegroup( name = html_name, srcs = [name], @@ -153,6 +187,10 @@ def sphinx_docs( ], **common_kwargs ) + sphinx_run( + name = name + ".run", + docs = name, + ) build_test( name = name + "_build_test", @@ -161,12 +199,14 @@ def sphinx_docs( ) def _sphinx_docs_impl(ctx): - source_dir_path = ctx.attr.source_tree[_SphinxSourceTreeInfo].source_root + source_tree_info = ctx.attr.source_tree[_SphinxSourceTreeInfo] + source_dir_path = source_tree_info.source_root inputs = ctx.attr.source_tree[DefaultInfo].files + per_format_args = {} outputs = {} for format in ctx.attr.formats: - output_dir = _run_sphinx( + output_dir, args_env = _run_sphinx( ctx = ctx, format = format, source_path = source_dir_path, @@ -174,12 +214,19 @@ def _sphinx_docs_impl(ctx): inputs = inputs, ) outputs[format] = output_dir + per_format_args[format] = args_env return [ DefaultInfo(files = depset(outputs.values())), OutputGroupInfo(**{ format: depset([output]) for format, output in outputs.items() }), + _SphinxRunInfo( + sphinx = ctx.attr.sphinx, + source_tree = ctx.attr.source_tree, + tools = ctx.attr.tools, + per_format_args = per_format_args, + ), ] _sphinx_docs = rule( @@ -213,18 +260,35 @@ _sphinx_docs = rule( def _run_sphinx(ctx, format, source_path, inputs, output_prefix): output_dir = ctx.actions.declare_directory(paths.join(output_prefix, format)) - args = ctx.actions.args() - args.add("-T") # Full tracebacks on error - args.add("-b", format) + run_args = [] # Copy of the args to forward along to debug runner + args = ctx.actions.args() # Args passed to the action + + args.add("--show-traceback") # Full tracebacks on error + run_args.append("--show-traceback") + args.add("--builder", format) + run_args.extend(("--builder", format)) if ctx.attr._quiet_flag[BuildSettingInfo].value: - args.add("-q") # Suppress stdout informational text - args.add("-j", "auto") # Build in parallel, if possible - args.add("-E") # Don't try to use cache files. Bazel can't make use of them. - args.add("-a") # Write all files; don't try to detect "changed" files + # Not added to run_args because run_args is for debugging + args.add("--quiet") # Suppress stdout informational text + + args.add("--jobs", "auto") # Build in parallel, if possible + run_args.extend(("--jobs", "auto")) + args.add("--fresh-env") # Don't try to use cache files. Bazel can't make use of them. + run_args.append("--fresh-env") + args.add("--write-all") # Write all files; don't try to detect "changed" files + run_args.append("--write-all") + for opt in ctx.attr.extra_opts: - args.add(ctx.expand_location(opt)) - args.add_all(ctx.attr._extra_defines_flag[_FlagInfo].value, before_each = "-D") + expanded = ctx.expand_location(opt) + args.add(expanded) + run_args.append(expanded) + + extra_defines = ctx.attr._extra_defines_flag[_FlagInfo].value + args.add_all(extra_defines, before_each = "--define") + for define in extra_defines: + run_args.extend(("--define", define)) + args.add(source_path) args.add(output_dir.path) @@ -247,7 +311,7 @@ def _run_sphinx(ctx, format, source_path, inputs, output_prefix): progress_message = "Sphinx building {} for %{{label}}".format(format), env = env, ) - return output_dir + return output_dir, struct(args = run_args, env = env) def _sphinx_source_tree_impl(ctx): # Sphinx only accepts a single directory to read its doc sources from. @@ -309,6 +373,7 @@ def _sphinx_source_tree_impl(ctx): ), _SphinxSourceTreeInfo( source_root = sphinx_source_dir_path, + source_dir_runfiles_path = paths.dirname(source_conf_file.short_path), ), ] @@ -414,3 +479,85 @@ _sphinx_inventory = rule( ), }, ) + +def _sphinx_run_impl(ctx): + run_info = ctx.attr.docs[_SphinxRunInfo] + + builder = ctx.attr.builder + + if builder not in run_info.per_format_args: + builder = run_info.per_format_args.keys()[0] + + args_info = run_info.per_format_args.get(builder) + if not args_info: + fail("Format {} not built by {}".format( + builder, + ctx.attr.docs.label, + )) + + args_str = [] + args_str.extend(args_info.args) + args_str = "\n".join(["args+=('{}')".format(value) for value in args_info.args]) + if not args_str: + args_str = "# empty custom args" + + env_str = "\n".join([ + "sphinx_env+=({}='{}')".format(*item) + for item in args_info.env.items() + ]) + if not env_str: + env_str = "# empty custom env" + + executable = ctx.actions.declare_file(ctx.label.name) + sphinx = run_info.sphinx + ctx.actions.expand_template( + template = ctx.file._template, + output = executable, + substitutions = { + "%SETUP_ARGS%": args_str, + "%SETUP_ENV%": env_str, + "%SOURCE_DIR_EXEC_PATH%": run_info.source_tree[_SphinxSourceTreeInfo].source_root, + "%SOURCE_DIR_RUNFILES_PATH%": run_info.source_tree[_SphinxSourceTreeInfo].source_dir_runfiles_path, + "%SPHINX_EXEC_PATH%": sphinx[DefaultInfo].files_to_run.executable.path, + "%SPHINX_RUNFILES_PATH%": sphinx[DefaultInfo].files_to_run.executable.short_path, + }, + is_executable = True, + ) + runfiles = ctx.runfiles( + transitive_files = run_info.source_tree[DefaultInfo].files, + ).merge(sphinx[DefaultInfo].default_runfiles).merge_all([ + tool[DefaultInfo].default_runfiles + for tool in run_info.tools + ]) + return [ + DefaultInfo( + executable = executable, + runfiles = runfiles, + ), + ] + +sphinx_run = rule( + implementation = _sphinx_run_impl, + doc = """ +Directly run the underlying Sphinx command `sphinx_docs` uses. + +This is primarily a debugging tool. It's useful for directly running the +Sphinx command so that debuggers can be attached or output more directly +inspected without Bazel interference. +""", + attrs = { + "builder": attr.string( + doc = "The output format to make runnable.", + default = "html", + ), + "docs": attr.label( + doc = "The {obj}`sphinx_docs` target to make directly runnable.", + providers = [_SphinxRunInfo], + ), + "_template": attr.label( + allow_single_file = True, + default = "//sphinxdocs/private:sphinx_run_template.sh", + ), + }, + executable = True, +) diff --git a/sphinxdocs/private/sphinx_run_template.sh b/sphinxdocs/private/sphinx_run_template.sh new file mode 100644 index 0000000000..4a1f1e4410 --- /dev/null +++ b/sphinxdocs/private/sphinx_run_template.sh @@ -0,0 +1,36 @@ +#!/bin/bash + +declare -a args +%SETUP_ARGS% + +declare -a sphinx_env +%SETUP_ENV% + +for path in "%SOURCE_DIR_RUNFILES_PATH%" "%SOURCE_DIR_EXEC_PATH%"; do + if [[ -e $path ]]; then + source_dir=$path + break + fi +done + +if [[ -z "$source_dir" ]]; then + echo "Could not find source dir" + exit 1 +fi + +for path in "%SPHINX_RUNFILES_PATH%" "%SPHINX_EXEC_PATH%"; do + if [[ -e $path ]]; then + sphinx=$path + break + fi +done + +if [[ -z $sphinx ]]; then + echo "Could not find sphinx" + exit 1 +fi + +output_dir=${SPHINX_OUT:-/tmp/sphinx-out} + +set -x +exec env "${sphinx_env[@]}" -- "$sphinx" "${args[@]}" "$@" "$source_dir" "$output_dir" diff --git a/sphinxdocs/sphinx.bzl b/sphinxdocs/sphinx.bzl index 3c9dc6b515..6cae80ed5c 100644 --- a/sphinxdocs/sphinx.bzl +++ b/sphinxdocs/sphinx.bzl @@ -32,8 +32,10 @@ load( _sphinx_build_binary = "sphinx_build_binary", _sphinx_docs = "sphinx_docs", _sphinx_inventory = "sphinx_inventory", + _sphinx_run = "sphinx_run", ) sphinx_build_binary = _sphinx_build_binary sphinx_docs = _sphinx_docs sphinx_inventory = _sphinx_inventory +sphinx_run = _sphinx_run