diff --git a/src/extensions/score_mounts/__init__.py b/src/extensions/score_mounts/__init__.py index 55157f475..03c537815 100644 --- a/src/extensions/score_mounts/__init__.py +++ b/src/extensions/score_mounts/__init__.py @@ -123,6 +123,16 @@ def _canonical_mount_dir(walk_dir: Path, spec: MountSpec) -> Path: generated files below it can resolve to the action execroot spelling, for example ``~/.cache/bazel/.../execroot/_main/bazel-out/.../docs/generated/index.rst``. + - for in-tree (same-workspace) source bundles, the mount root directory + exists in the sandbox but the individual source files are symlinks back + to the original workspace, for example + ``.../sandbox/.../execroot/_main/score/socom/docs/index.rst`` + ``→ /home/user/workspace/score/socom/docs/index.rst``. + + This applies to all bundle types: external repositories, generated data + bundles, and in-tree (same-workspace) source bundles. Resolve one mounted + source file first and walk back by its bundle-relative suffix to get the + canonical root. Resolving only ``walk_dir`` therefore keeps the sandbox spelling, while resolving a referenced image/include from Sphinx follows the file symlink. @@ -143,19 +153,6 @@ def _canonical_mount_dir(walk_dir: Path, spec: MountSpec) -> Path: the canonical mount root. For ``subdir/page.rst`` we walk back two components, yielding the same canonical root. """ - if not spec.external and not spec.data: - return walk_dir.resolve() - - # Bazel materializes the mount directory structure in the sandbox but may - # symlink the individual files either to the external repository cache or to - # the action execroot's bazel-out tree. A mounted documentation source gives - # us the same canonical spelling that Sphinx will later see for dependency - # files. Walking back by the source file's path relative to the mount - # reconstructs the canonical mount root: - # - # source_file = walk_dir / "subdir/page.rst" - # relative_path.parts = ("subdir", "page.rst") - # source_file.resolve().parents[1] == canonical walk_dir for source_file in walk_dir.rglob("*"): if not source_file.is_file() or source_file.suffix not in {".md", ".rst"}: continue diff --git a/src/extensions/score_mounts/tests/test_data_mounts.py b/src/extensions/score_mounts/tests/test_data_mounts.py index 87e2d5c5f..a8144e343 100644 --- a/src/extensions/score_mounts/tests/test_data_mounts.py +++ b/src/extensions/score_mounts/tests/test_data_mounts.py @@ -85,6 +85,46 @@ def test_mount_entry_uses_canonical_directory_for_symlinked_bundle( assert entry["dir"] == str(canonical_dir) +def test_canonical_mount_dir_in_tree_sandbox_bundle(tmp_path: Path) -> None: + """In-tree bundles with symlinked files must resolve to the workspace root.""" + workspace_docs = tmp_path / "workspace" / "module" / "docs" + workspace_docs.mkdir(parents=True) + (workspace_docs / "index.rst").write_text("Index", encoding="utf-8") + (workspace_docs / "guide").mkdir() + (workspace_docs / "guide" / "overview.rst").write_text("Overview", encoding="utf-8") + + sandbox_docs = tmp_path / "sandbox" / "module" / "docs" + sandbox_docs.mkdir(parents=True) + sandbox_docs.joinpath("index.rst").symlink_to(workspace_docs / "index.rst") + (sandbox_docs / "guide").mkdir() + sandbox_docs.joinpath("guide", "overview.rst").symlink_to( + workspace_docs / "guide" / "overview.rst" + ) + + spec = MountSpec( + src_root="module/docs", runtime_path="module/docs", mount_at="module" + ) + + entry = _make_mount_entry(sandbox_docs, spec) + + assert entry["dir"] == str(workspace_docs) + + +def test_canonical_mount_dir_empty_bundle_fallback(tmp_path: Path) -> None: + """A bundle with no .rst/.md files falls back to walk_dir.resolve().""" + bundle_dir = tmp_path / "bundle" + bundle_dir.mkdir() + (bundle_dir / "diagram.puml").write_text("@startuml\n@enduml", encoding="utf-8") + + spec = MountSpec( + src_root="module/docs", runtime_path="module/docs", mount_at="module" + ) + + entry = _make_mount_entry(bundle_dir, spec) + + assert entry["dir"] == str(bundle_dir.resolve()) + + def test_mount_entry_uses_canonical_directory_for_generated_data_bundle( tmp_path: Path, ) -> None: