Skip to main content

Module fallback

Module fallback 

Source
Expand description

Tier two: the gitignore fallback, for the ecosystems nobody wrote a rule for.

This is the differentiator from kondo, whose coverage is exactly its ruleset and which is therefore blind to anything outside it. Inside a git work tree a directory is reclaimable by inference when all four of these hold:

  1. it is ignored, per the whole gitignore stack — nested files, negations, info/exclude, global excludes — and not merely per the root .gitignore;
  2. it contains no tracked file at any depth;
  3. it clears a size floor, 10 MiB by default;
  4. no tier-one rule already claimed it.

Condition two is the safety property, it is exactly the guarantee git clean enforces, and it is the reason this tier can be on by default without being reckless. Condition four falls out of evaluation order in crate::walk: tier one is asked first, and it prunes.

§A candidate may be a FILE, and then only conditions one, two and four apply

Conditions one, two and four are statements about a path and hold unchanged. Condition three does not, and leaving it out is the design rather than an exemption: the floor is about rows, not about safety. A gitignored directory under 10 MiB is not worth a row because the list is sorted by size and it would be at the bottom of it. A 40-byte .env IS worth a row, and the reason has nothing to do with its size.

A file is also always priced, where a tier-one directory lives in crate::size::Size::Unmeasured until somebody asks for a breakdown. One lstat — which the walk has already done — is the exact and complete answer in constant time, so the unpriced machinery never has to grow a file branch. That is a simplification rather than a special case.

Because this is a different job from the one the tier does for directories — clearing fifty env files reclaims kilobytes, and the value is hygiene rather than space — it is asked for separately: see crate::walk::Walker::ignored_files, which is off unless a caller says otherwise.

§The fifth condition, which git clean also enforces

A directory holding a git checkout at any depth is not claimed either. This is not in the four above and it is not optional: git clean -ndX in a repository whose ignored .sandboxes/ holds live work trees prints Would skip repository … and then lists the siblings one by one, rather than collapsing the directory into a single removal. Anything that collapses it is offering to delete somebody’s uncommitted work, and that shape — checkouts parked under an ignored directory — is common rather than exotic. So a candidate holding a checkout is refused and descended into, which is exactly what git does with it, and its subdirectories that hold no checkout are claimed on their own.

For the same reason a candidate with an unreadable corner is refused. “Holds no checkout” is a claim about the whole subtree, and a traversal that could not see all of it has not made that claim. Tier one survives an unreadable corner with a size that is a lower bound, because a rule vouched for the directory; here the traversal is the evidence.

§Outside a work tree this tier is inert

Deliberately, and it is reported rather than left to look like an empty result. With no repository there is no ignore file that means anything, and the only signal left would be the directory’s name — which is precisely how a cleaner deletes somebody’s source. build/ is a CMake project’s hand-written source as often as it is output, and no amount of wanting a broader tier makes a name into evidence.

§Why a query matcher rather than a filtering walk

Tier one switches every ignore file off, because node_modules, target and .venv are gitignored in every repository that has a .gitignore and a filtering walk would find almost nothing. So tier two cannot ride on the walk’s own filtering and instead asks IncrementalIgnore, which answers the same question for one path at a time and caches per directory. One matcher per work tree per walker thread: the matchers hold mutable caches, so sharing one would mean a lock on the hottest path in the scan.

Structs§

FallbackReport
What tier two was able to do, reported alongside what it found.

Constants§

DEFAULT_MIN_SIZE
The default size floor: below this a directory is not worth a row, and tier two would otherwise report every scrap of ignored cache on the disk.