pub trait PackageManager: Send + Sync {
// Required methods
fn name(&self) -> &'static str;
fn detect(&self, project_path: &Path) -> bool;
fn bloat_dirs(&self, project_path: &Path) -> Vec<BloatDir>;
fn enforce_lockfile(
&self,
project_path: &Path,
policy: EnforcePolicy,
) -> Result<()>;
fn restore(&self, project_path: &Path, timeout: Duration) -> Result<()>;
// Provided methods
fn restore_named(
&self,
project_path: &Path,
dir_name: &str,
timeout: Duration,
) -> Result<()> { ... }
fn lockfiles(&self) -> &'static [&'static str] { ... }
fn drift(&self, project_path: &Path) -> Vec<DriftReport> { ... }
}Expand description
The core trait that every package manager adapter must implement.
Each adapter is responsible for:
- Detecting whether it applies to a given project directory
- Listing the bloat directories it manages
- Enforcing lockfile consistency before deletion
- Restoring dependencies from lockfiles
Required Methods§
Sourcefn name(&self) -> &'static str
fn name(&self) -> &'static str
Human-readable name for this adapter (e.g., “npm”, “pnpm”, “uv”).
Sourcefn detect(&self, project_path: &Path) -> bool
fn detect(&self, project_path: &Path) -> bool
Check if this adapter applies to the given project directory.
Typically checks for the presence of a specific lockfile or config file.
Sourcefn bloat_dirs(&self, project_path: &Path) -> Vec<BloatDir>
fn bloat_dirs(&self, project_path: &Path) -> Vec<BloatDir>
List all bloat directories this adapter manages in the given project.
Only returns directories that actually exist on disk.
Sourcefn enforce_lockfile(
&self,
project_path: &Path,
policy: EnforcePolicy,
) -> Result<()>
fn enforce_lockfile( &self, project_path: &Path, policy: EnforcePolicy, ) -> Result<()>
Prove the lockfile can rebuild what is about to be deleted.
This is a safety-critical method. It MUST succeed before any bloat directory is deleted. If this fails, deletion for this adapter is aborted.
See EnforcePolicy for the one rule every adapter follows.
Sourcefn restore(&self, project_path: &Path, timeout: Duration) -> Result<()>
fn restore(&self, project_path: &Path, timeout: Duration) -> Result<()>
Restore dependencies from the lockfile (for dev-prune restore).
timeout is threaded explicitly for the same reason EnforcePolicy is: the
restore path used to burn the compiled-in default regardless of
command_timeout_secs, and a full npm ci on a large tree needs the raised
timeout far more often than a verify does.
Provided Methods§
Sourcefn restore_named(
&self,
project_path: &Path,
dir_name: &str,
timeout: Duration,
) -> Result<()>
fn restore_named( &self, project_path: &Path, dir_name: &str, timeout: Duration, ) -> Result<()>
PackageManager::restore, told the name the pruned directory had.
Most managers have exactly one possible directory name and ignore this. venv does
not: it prunes any folder carrying a pyvenv.cfg — venv, env, my_env — and
without the recorded name it would rebuild the environment as .venv, leaving
every activate script, IDE interpreter path and Makefile pointing at nothing.
Sourcefn lockfiles(&self) -> &'static [&'static str]
fn lockfiles(&self) -> &'static [&'static str]
The file this manager rebuilds its bloat directory from.
Two callers. Conflict resolution breaks ties between managers that share a bloat
directory — npm, pnpm, yarn and bun all own the same node_modules — by comparing
these files’ timestamps. devp doctor names them, because a missing one is the
most common reason a project is not pruneable.
More than one entry means the manager accepts any of them (bun’s binary and text lockfiles). An empty slice means the manager has no single file to point at.
Sourcefn drift(&self, project_path: &Path) -> Vec<DriftReport>
fn drift(&self, project_path: &Path) -> Vec<DriftReport>
Installed-but-unrecorded packages, as data instead of a refusal.
The same comparison PackageManager::enforce_lockfile refuses a prune on,
surfaced early so devp status --drift can point at the problem before a prune
is ever attempted. Runs nothing and writes nothing. An empty answer means
“nothing detected”, not “proven clean” — most managers have no cheap way to
compare and say nothing here.
Dyn Compatibility§
This trait is dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety".