Expand description
pristine finds reclaimable build artifacts and vendored dependency directories across
every ecosystem on a machine, and names what each one is before you delete it.
The core is a single parallel walk that prunes at every directory it claims, driven by a ruleset that lives in TOML rather than in code:
use std::sync::Arc;
use pristine::{Ruleset, Walker};
let ruleset = Arc::new(Ruleset::load(None)?);
let (tree, outcome) = Walker::new("/Users/me/repos", ruleset).run_to_tree();
println!("{} directories, {} not yet priced", outcome.hits, tree.unmeasured());A scan does not measure what it claims. Pruning at node_modules and then walking it to
size it would give back the cost the pruning saved, so sizes arrive as
Size::Unmeasured until a caller asks for a breakdown with
SizeMode::Breakdown — which costs an order of magnitude more
than the scan it prices. SizeMode::BreakdownUnder buys
the same answer for one subtree at that subtree’s price.
When a breakdown is asked for, the prices do not hold the claims up. A claim is
published as Found::Claim the moment it is judged and a pool of threads prices it
afterwards, reporting Found::Priced for the same path; over one real ~/repos that
moves the last row of the listing from 60.1 s to 7.5 s while the totals take the same
minute either way. Walker::run explains the shape and carries the measurements.
Detection is marker-anchored and never name-anchored: a rule is “a directory named
target whose parent holds a Cargo.toml”, never “a directory named target”.
target is Rust’s and Maven’s, vendor is Go’s and Composer’s and Bundler’s, and build
is Gradle’s, Dart’s and — in a CMake project — hand-written source. See rules.
A curated ruleset only ever covers the ecosystems somebody wrote a rule for, so there is a
second tier underneath it: inside a git work tree, a directory that is gitignored, holds no
tracked file and no git checkout at any depth, and clears a size floor is reclaimable by
inference even when no rule names it. It reports honestly that it does not know what the
directory is, and outside a work tree it is inert rather than guessing from directory
names. See fallback.
Removing what either tier found is delete, and it is split in two on purpose. A
Planner resolves every path and applies every check in the safety model; a Deleter
executes the resulting Plan and decides nothing. That split is what makes a dry run
honest: the plan a preview prints is the same object the removal consumes.
What a person actually uses to steer all of this is tui: the filesystem tree with the
reclaimable bytes rolled up into every ancestor, collapsed by default, where marking one
closed row covers everything beneath it and the batch it commits goes through the same
Planner and Deleter.
All of the above is the sweep: point it at a tree of unrelated projects and ask what is
reclaimable across all of them. The second mode is repo, which points at one git
checkout and replaces git clean -fdx. It enumerates nothing itself — git clean -n -d
and git clean -n -d -X are the authority, so nested ignore files, negations,
info/exclude and global excludes are inherited exactly rather than reimplemented — and it
feeds the same Planner and Deleter as the sweep.
Re-exports§
pub use delete::Deleter;pub use delete::Failure;pub use delete::Freeing;pub use delete::Plan;pub use delete::PlanTarget;pub use delete::Planner;pub use delete::Refusal;pub use delete::Refused;pub use delete::Removal;pub use delete::Removed;pub use delete::Step;pub use delete::Target;pub use fallback::DEFAULT_MIN_SIZE;pub use fallback::FallbackReport;pub use git::GitError;pub use git::WorkTree;pub use repo::Class;pub use repo::Enumeration;pub use repo::Repo;pub use repo::RepoError;pub use repo::Reset;pub use repo::Selected;pub use repo::Selection;pub use rules::Anchor;pub use rules::Kind;pub use rules::MarkersRequired;pub use rules::Rule;pub use rules::RuleError;pub use rules::Ruleset;pub use size::Measurement;pub use size::Measurer;pub use size::Size;pub use size::SizeMode;pub use size::Survey;pub use tree::Node;pub use tree::NodeId;pub use tree::Order;pub use tree::Sort;pub use tree::Tree;pub use walk::Claim;pub use walk::Found;pub use walk::Hit;pub use walk::IgnoredClaim;pub use walk::Priced;pub use walk::RuleClaim;pub use walk::UNLABELLED;pub use walk::WalkError;pub use walk::WalkOutcome;pub use walk::Walker;
Modules§
- delete
- The deleter: the half that cannot be undone.
- fallback
- Tier two: the gitignore fallback, for the ecosystems nobody wrote a rule for.
- git
- What git knows about a directory: where its work tree is, and whether anything under it is tracked.
- repo
- Repo mode: one checkout, cleaned the way
git clean -fdxcleans it. - rules
- The tier-one ruleset: what a reclaimable directory looks like, as data.
- size
- How many bytes a claimed directory is worth, and why a normal scan does not ask.
- tree
- The rollup tree: the filesystem tree pruned to paths that lead to something reclaimable, with each node carrying the bytes recoverable beneath it.
- tui
- The rollup tree TUI: the front end the whole tool is for.
- walk
- The parallel walker: one pass over a tree, pruning at every directory it claims.