oct
Loading...
Searching...
No Matches
oct.docs.workspace_docs Namespace Reference

Functions

bool is_workspace_root (Path path)
str|None _doxygen_withheld (Subproject sp)
int _build_subproject (Subproject sp, *, WorkspaceDocsMode mode)
None _copytree_replace (Path src, Path dst)
Path _aggregate (Path ws_root, Workspace workspace, *, WorkspaceDocsMode mode)
int _clean_workspace (Path ws_root, Workspace workspace, *, bool dry_run)
int run_workspace_docs (Path ws_root, *, WorkspaceDocsMode mode, bool dry_run=False)

Variables

 WorkspaceDocsMode = Literal["sphinx", "doxygen", "typedoc", "all", "clean"]
str SITE_DIRNAME = "_site"
Path _SPHINX_BUILD_REL = Path("docs") / "html"
Path _DOXYGEN_BUILD_REL = Path("docs") / "doxygen_output" / "html"

Detailed Description

Purpose
-------
Workspace-mode orchestrator for ``oct docs``. When the docs command is
invoked from a workspace root (a directory containing
``.option_c_workspace.json``), this module fans out the build across
each subproject, builds the workspace-tier "Option C" Sphinx tree from
the spec markdown, and aggregates everything under
``<workspace>/_site/`` with a Jinja-rendered front page.

Single-project invocations (from inside ``oct/`` or ``oc_diagnostics/``,
or from any non-workspace directory) bypass this module entirely - the
existing single-project pipelines in :mod:`oct.docs.oct_docs` handle
those unchanged.

Responsibilities
----------------
- Detect workspace mode at the dispatcher boundary and refuse to run
  outside a real workspace root.
- Walk ``workspace.subprojects`` from the manifest and invoke the
  single-project Sphinx / Doxygen pipelines for each, suppressing
  recursion via ``no_workspace=True``. A subproject whose manifest entry
  sets ``html_docs: false`` is skipped and its aggregated output
  withdrawn; ``--clean`` still sweeps it, because opting out of building
  is not opting out of tidying up.
- Keep a subproject's Doxygen off the site when its manifest entry sets
  ``html_docs: {"doxygen": false}`` (2026-09-28) or it has no Doxyfile:
  the fan-out neither builds nor aggregates it, and any
  ``_site/<sp>/doxygen/`` an earlier run left is withdrawn in every build
  mode. A direct ``oct docs --doxygen`` inside the subproject is not
  routed through here and still builds.
- Build the Option C tier Sphinx tree from
  ``<workspace>/docs/option_c_specs/*.md`` plus the workspace
  ``README.md`` as the toctree root (Phase D).
- Aggregate every per-subproject ``docs/_build/html/`` into
  ``_site/<sp>/sphinx/html/``; same for Doxygen output.
- Render the front page via :mod:`oct.docs.front_page` (Phase B).
- Implement ``--clean`` semantics that strip ``_site/`` and every
  subproject's ``docs/_build/`` (Phase F).

Diagnostics
-----------
Domain: OCT-DOCS
Levels:
    L2 - orchestrator entry / exit, mode dispatch
    L3 - per-subproject build dispatch, aggregation steps
    L4 - per-file copy decisions

Contracts
---------
- ``run_workspace_docs`` is the single entry point. It must never be
  called from inside a subproject root - the dispatcher in
  :mod:`oct.docs.oct_docs` is responsible for that gate.
- The function returns a non-zero exit code on any sub-build failure;
  failures in one subproject do not abort the others, so the user sees
  every problem in one run.
- Aggregation uses :func:`shutil.copytree` not symlinks (Windows-safe).

Dependencies
------------
- oct.core.workspace (manifest loader, find_workspace_root)
- oct.core.diagnostics (_dbg structured logger)
- oct.tools.fs_remove (remove_tree_or_warn - clears aggregated and generated output, warning on a tree that will not go)
- oct.docs.front_page (lazy; render_front_page, FrontPageError - the hub front page)
- oct.docs.oct_docs (lazy; run_docs_sphinx, run_docs_doxygen, _find_doxyfile - the single-project pipelines)
- oct.docs.option_c_tier (lazy; build_option_c_tier - the workspace-tier Option C Sphinx tree)
- oct.docs.typedoc (lazy; has_typedoc, run_docs_typedoc, typedoc_output_dir - the TypeDoc tier)

Function Documentation

◆ _aggregate()

Path oct.docs.workspace_docs._aggregate ( Path ws_root,
Workspace workspace,
* ,
WorkspaceDocsMode mode )
protected
Copy each subproject's HTML into ``<ws_root>/_site/<sp>/<tool>/html/``,
plus the workspace-tier Option C Sphinx output into ``_site/option_c/``.

A subproject with ``html_docs=false`` loses its whole ``_site/<sp>/``
tree; one whose Doxygen is withheld (see :func:`_doxygen_withheld`)
loses only ``_site/<sp>/doxygen/``, plus ``_site/<sp>/`` itself when
that withdrawal leaves it empty. Both withdrawals run in every mode.

Returns the resolved site root.

Definition at line 240 of file workspace_docs.py.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ _build_subproject()

int oct.docs.workspace_docs._build_subproject ( Subproject sp,
* ,
WorkspaceDocsMode mode )
protected
Run the single-project pipeline for *sp* in ``no_workspace`` mode.

Returns the per-build exit code so the caller can aggregate. A subproject
with no ``docs/doxygen_work_dir/Doxyfile``, or whose manifest entry sets
``html_docs: {"doxygen": false}``, has its Doxygen step SKIPPED rather
than failed - see the comment at that branch.

Definition at line 139 of file workspace_docs.py.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ _clean_workspace()

int oct.docs.workspace_docs._clean_workspace ( Path ws_root,
Workspace workspace,
* ,
bool dry_run )
protected
Remove ``_site/`` and every subproject's ``docs/_build/`` + ``docs/html/``.

Returns 0 when every target is gone (or under *dry_run*), 1 when one or
more survived. Still best-effort in that one unremovable target never stops
the sweep - but a survivor is reported rather than counted as removed.

Definition at line 328 of file workspace_docs.py.

Here is the caller graph for this function:

◆ _copytree_replace()

None oct.docs.workspace_docs._copytree_replace ( Path src,
Path dst )
protected
Replace *dst* with a fresh copy of *src*.

No-op when *src* does not exist (allows partial builds - e.g. a
subproject that has only Sphinx, not Doxygen).

Definition at line 213 of file workspace_docs.py.

Here is the caller graph for this function:

◆ _doxygen_withheld()

str | None oct.docs.workspace_docs._doxygen_withheld ( Subproject sp)
protected
Return why *sp* has no Doxygen on the site, or ``None`` when it has.

Two causes share one consequence. The manifest switch
``html_docs: {"doxygen": false}`` keeps a declared Doxygen tier off the
site, and a subproject with no Doxyfile has no Doxygen tier to publish.
Either way the fan-out builds nothing and aggregates nothing, and any
tree an earlier run left under ``_site/<sp>/doxygen/`` is withdrawn, so
one answer serves the build step and the aggregation step alike. The
reason is worded to follow ``has`` in the printed line.

Definition at line 120 of file workspace_docs.py.

Here is the caller graph for this function:

◆ is_workspace_root()

bool oct.docs.workspace_docs.is_workspace_root ( Path path)
Return True iff *path* is the root of an Option C workspace.

A workspace root holds a ``.option_c_workspace.json`` manifest
*directly* (not inherited from a parent). This is the gate the
dispatcher uses to decide whether to route to
:func:`run_workspace_docs`.

Definition at line 105 of file workspace_docs.py.

◆ run_workspace_docs()

int oct.docs.workspace_docs.run_workspace_docs ( Path ws_root,
* ,
WorkspaceDocsMode mode,
bool dry_run = False )
Workspace-mode entry point.

Parameters
----------
ws_root:
    Resolved path to the workspace root. The caller (dispatcher)
    guarantees this is a real workspace root.
mode:
    Which subset of the pipeline to run. ``"sphinx"`` / ``"doxygen"``
    / ``"all"`` build subprojects + Option C tier + aggregate.
    ``"clean"`` removes ``_site/`` and every subproject's docs build
    outputs.
dry_run:
    Forwarded to ``--clean`` only. ``True`` reports planned removals
    without touching the filesystem.

Returns
-------
int
    ``0`` on success; non-zero when any sub-build or cleanup step
    fails. Failures in one subproject do not abort the others - every
    problem is reported in a single run.

Definition at line 384 of file workspace_docs.py.

Here is the call graph for this function:

Variable Documentation

◆ _DOXYGEN_BUILD_REL

Path oct.docs.workspace_docs._DOXYGEN_BUILD_REL = Path("docs") / "doxygen_output" / "html"
protected

Definition at line 102 of file workspace_docs.py.

◆ _SPHINX_BUILD_REL

Path oct.docs.workspace_docs._SPHINX_BUILD_REL = Path("docs") / "html"
protected

Definition at line 99 of file workspace_docs.py.

◆ SITE_DIRNAME

str oct.docs.workspace_docs.SITE_DIRNAME = "_site"

Definition at line 95 of file workspace_docs.py.

◆ WorkspaceDocsMode

oct.docs.workspace_docs.WorkspaceDocsMode = Literal["sphinx", "doxygen", "typedoc", "all", "clean"]

Definition at line 91 of file workspace_docs.py.