Skip to main content

Module walk

Module walk 

Source
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:

  1. Escape hatch: Walk::allow. Un-prunes specific directory names for one Walk — the one legal way to widen past the by-construction policy (every other builder, Walk::prune_also, can only narrow further). brink-driver’s RealFs wires this to a new brink.toml key, [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.

  2. Gitignore-awareness: deliberately NOT implemented. .gitignore is 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):

    • .gitignore resolution 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 global core.excludesFile can all change what it matches, so two checkouts of byte-identical tracked source could discover a different file set and silently compile differently. unprune-dirs avoids exactly this: it lives in brink.toml, which is itself tracked, versioned source — the same input on every clone.
    • Correctly implementing gitignore’s matching semantics (nested .gitignore files, !-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.

  3. Diagnostic: Walk::warn_on_pruned_sources / Walk::pruned_with_sources. A caller opts a Walk into watching for source-shaped files (by extension) sitting inside a pruned directory; after the walk is drained, Walk::pruned_with_sources names 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 huge target/ never turns a cheap prune into an expensive walk of the very tree being skipped. The depth cap is chosen to cover node_modules/<package>/lib.brink (two levels below the pruned directory), the shape an npm-style dependency tree actually uses — a same-directory drop like node_modules/vendor.brink was 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).
WalkEntry
One entry yielded by a Walk: a path plus the file type the directory listing reported for it.