Discover a Cargo.toml in a subdirectory when none sits at the scan root

introspect_cargo only ever looked at root divided by Cargo dot toml,
with no search, so any repository whose crate lives in a subdirectory
got no crate nodes or dependency edges at all, even though the AST
pass had already parsed every rs file there. The common case is a
Tauri app, whose default scaffold keeps its manifest under its own
frontend adjacent crate folder rather than the project root.

Add a bounded depth search that only runs when the root manifest is
missing, reusing the same noise directory pruning the AST scanner
already applies so a vendored or example manifest nested inside a
dependency folder never wins over the project's own. A workspace
manifest found this way now resolves its own members relative to its
own directory rather than the outer scan root, since those two can
now differ.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017qfdzgbA5KedGEjD1AayNh
(cherry picked from commit 577e51749a)
This commit is contained in:
ayushcodes10 authored and safishamsi committed 2026-09-22 14:58:22 +01:00
1 parent 137ead6d56
commit 165a7da4a1
1 file changed
+41 -1
+41 -1
View File
@@ -2,11 +2,13 @@
from __future__ import annotations
import os
from pathlib import Path
from typing import Any
_CONFIDENCE_EXTRACTED = "EXTRACTED"
_MAX_DISCOVERY_DEPTH = 2
def _load_toml(path: Path) -> dict[str, Any]:
@@ -24,6 +26,37 @@ def _load_toml(path: Path) -> dict[str, Any]:
return tomllib.load(manifest)
def _discover_root_manifest(root: Path) -> Path | None:
"""Find a Cargo.toml under *root* when none sits directly at the root.
A bounded-depth search rather than an unbounded walk: a Tauri app's
crate lives in src-tauri/, a polyglot repo's in rust/ or crates/, but
going arbitrarily deep risks matching a vendored or example manifest
nested well inside an unrelated dependency (#3678). Reuses the same
noise-directory pruning the AST scanner already applies (venvs, caches,
node_modules, build output) so those never get searched into. A
genuinely ambiguous layout with more than one candidate at the same
depth is resolved by sorted path order rather than guessed at; the
caller is free to point --cargo at a subdirectory directly for a repo
where that is not the right answer.
"""
from graphify.detect import _is_noise_dir
found: list[Path] = []
for dirpath, dirnames, filenames in os.walk(root):
current = Path(dirpath)
depth = len(current.relative_to(root).parts)
if depth > 0 and "Cargo.toml" in filenames:
found.append(current / "Cargo.toml")
if depth >= _MAX_DISCOVERY_DEPTH:
dirnames[:] = []
continue
dirnames[:] = [d for d in dirnames if not _is_noise_dir(d, current)]
if not found:
return None
return sorted(found)[0]
def _member_manifest_paths(root: Path, root_data: dict[str, Any]) -> list[Path]:
paths: list[Path] = []
if isinstance(root_data.get("package"), dict):
@@ -48,9 +81,16 @@ def introspect_cargo(root: str | Path) -> dict[str, Any]:
"""Return crate nodes and internal dependency edges from Cargo manifests."""
root_path = Path(root).resolve()
root_manifest = root_path / "Cargo.toml"
if not root_manifest.is_file():
discovered = _discover_root_manifest(root_path)
if discovered is not None:
root_manifest = discovered
root_data = _load_toml(root_manifest)
manifests = _member_manifest_paths(root_path, root_data)
# Workspace members are resolved relative to the manifest's OWN
# directory, not necessarily root_path (#3678: the manifest can live in
# a discovered subdirectory, e.g. src-tauri/).
manifests = _member_manifest_paths(root_manifest.parent, root_data)
crates: dict[str, tuple[str, Path, dict[str, Any]]] = {}
for manifest in manifests: