Expand description
The shared recursive directory walk (issue #1433).
crate::is_ignored_dir has existed since #1402, but only as a
predicate: every recursive traversal in the workspace still wrote its
own read_dir recursion and had to remember to call the predicate at the
right moment. It didn’t — five separate issues (#1370, #1381, #1402,
#1415, #1424) each fixed one traversal that had skipped the check,
because nothing structural made pruning the default. The predicate was
never the hard part; remembering to call it was.
Walk closes that by applying the policy by construction: it is
the only recursive read_dir loop in the workspace’s library code, so a
new traversal is pruned the moment it is written, with nothing to
remember.
This is host-side code (it touches the real filesystem), sitting here
rather than in brink-driver because it is the enforcement half of a
policy this crate already owns. Like RealFs/GitRev, it is never
constructed on a wasm-reachable path — the crate link is not the
constraint (see the module docs).
§Issue #1407: escape hatch, gitignore-awareness, diagnostic
Before #1407, Walk deliberately offered no unpruned mode at all —
a project legitimately keeping sources under a directory named target/,
.git/, or node_modules/ had no way to opt out, got no error, and got
no file. #1407 closes that gap with three decisions:
-
Escape hatch:
Walk::allow. Un-prunes specific directory names for oneWalk— the one legal way to widen past the by-construction policy (every other builder,Walk::prune_also, can only narrow further).brink-driver’sRealFswires this to a newbrink.tomlkey,[project] unprune-dirs(brink_project_config::ProjectConfig::unprune_dirs) — an explicit, checked-in, per-project override, not an environment variable or CLI flag, so the escape hatch itself stays a deterministic-compilation input (#1306): the same tree, compiled by anyone, unprunes the same directories. -
Gitignore-awareness: deliberately NOT implemented.
.gitignoreis not consulted anywhere in this crate, and that is a decision, not an oversight. Two reasons, both rooted in #1306 (discovery is a deterministic-compilation input):.gitignoreresolution is not fully determined by the tracked contents of a repository — a local uncommitted edit to.gitignore, a per-clone.git/info/exclude, and a user’s globalcore.excludesFilecan all change what it matches, so two checkouts of byte-identical tracked source could discover a different file set and silently compile differently.unprune-dirsavoids exactly this: it lives inbrink.toml, which is itself tracked, versioned source — the same input on every clone.- Correctly implementing gitignore’s matching semantics (nested
.gitignorefiles,!-negation, anchoring,.git/info/exclude, global excludes) is a substantial, easy-to-get-subtly-wrong reimplementation of git’s own resolution logic; a divergence would itself become a silent, hard-to-diagnose “files came and went” determinism bug — the same failure class #1306 exists to prevent, not a fix for it.
The actual pain point the issue names — a legitimately-authored source file going silently missing — is closed by items 1 and 3 instead, without taking on either cost.
-
Diagnostic:
Walk::warn_on_pruned_sources/Walk::pruned_with_sources. A caller opts aWalkinto watching for source-shaped files (by extension) sitting inside a pruned directory; after the walk is drained,Walk::pruned_with_sourcesnames every pruned directory that plausibly held something the author wanted. The check is bounded, not exhaustive — a depth cap ([PRUNED_SCAN_MAX_DEPTH]) and a total-entry budget ([PRUNED_SCAN_MAX_ENTRIES]), whichever is hit first — deliberately short of a full recursive descent, so noticing a stray source file inside a hugetarget/never turns a cheap prune into an expensive walk of the very tree being skipped. The depth cap is chosen to covernode_modules/<package>/lib.brink(two levels below the pruned directory), the shape an npm-style dependency tree actually uses — a same-directory drop likenode_modules/vendor.brinkwas always covered, but that’s a less faithful stand-in for how vendored source trees are actually laid out.
Every pruned directory is still skipped exactly as before unless
Walk::allow names it — items 1 and 3 change what the walk reports,
never what it silently does by default.
Structs§
- Walk
- Recursive directory walk that prunes
crate::IGNORED_DIR_NAMES(target/,.git/,node_modules/) by construction — there is no way to construct one that descends into them (issue #1433; see the module docs). - Walk
Entry - One entry yielded by a
Walk: a path plus the file type the directory listing reported for it.