pub struct Registry {
pub version: String,
pub settings: Settings,
pub repositories: HashMap<PathBuf, RepoEntry>,
pub total_freed_bytes: u64,
pub total_pruned_count: u64,
pub last_added_repos: Vec<PathBuf>,
pub last_prune: Option<LastPrune>,
pub prune_history: Vec<PruneRunSummary>,
pub last_update_check: Option<DateTime<Utc>>,
pub latest_known_version: Option<String>,
pub restore_rates: BTreeMap<String, RestoreRate>,
}Expand description
The top-level registry structure persisted to disk.
Fields§
§version: StringSchema version for forward compatibility.
settings: SettingsGlobal settings.
repositories: HashMap<PathBuf, RepoEntry>Map of canonical repo paths to their metadata.
total_freed_bytes: u64Total cumulative bytes freed historically across all prune passes.
total_pruned_count: u64How many prune passes have deleted something, ever.
One per pass, not per repository and not per directory — a devp run that
cleared eleven directories across four repositories counts once. Incremented in
exactly one place, Registry::record_prune, which is also where the pass is
recorded for devp restore --last-run; keeping the two together is what stops
them meaning different things depending on which command did the pruning.
last_added_repos: Vec<PathBuf>List of repository paths added in the most recent init/link action (for devp undo).
last_prune: Option<LastPrune>What the most recent prune pass deleted (for devp restore --last-run).
prune_history: Vec<PruneRunSummary>Summaries of recent prune passes, oldest first, for devp stats.
Capped at constants::PRUNE_HISTORY_LIMIT. Recorded from 1.1.0 onward.
last_update_check: Option<DateTime<Utc>>When the release check last ran, so it runs at most once every
UPDATE_CHECK_INTERVAL_DAYS instead of on every command.
latest_known_version: Option<String>The newest release seen by the last check, so the reminder survives until the user actually upgrades without needing the network again.
restore_rates: BTreeMap<String, RestoreRate>How fast each adapter has actually restored on this machine.
Measured by devp restore --last-run, which is the one command that knows both
how long a restore took and how many bytes it put back. Local only: nothing here
is uploaded, compared against anyone else’s machine, or used for anything except
the estimate devp status prints. See docs/PRIVACY.md.
Implementations§
Source§impl Registry
impl Registry
Sourcepub fn config_dir() -> Result<PathBuf>
pub fn config_dir() -> Result<PathBuf>
Returns the path to the config directory (~/.config/dev-prune/).
Uses the dirs crate to resolve the platform-specific config location:
- Linux/macOS:
~/.config/dev-prune/ - Windows:
C:\Users\<user>\AppData\Roaming\dev-prune\(or~/.config/dev-prune/)
Sourcepub fn registry_path() -> Result<PathBuf>
pub fn registry_path() -> Result<PathBuf>
Returns the full path to the registry file.
Sourcepub fn load() -> Result<Self>
pub fn load() -> Result<Self>
Loads the registry from disk, or the defaults when there is nothing to load.
Reading does not write. This used to persist the default registry on the way
out, which made devp --dry-run init create the very file it had just promised
not to write and gave devp status --json — documented as a pure read — a side
effect on first use. Every command that actually changes something calls
Registry::save, and that creates the directory as needed.
Sourcepub fn load_from(path: &Path) -> Result<Self>
pub fn load_from(path: &Path) -> Result<Self>
Loads the registry from a specific path (for testing or custom locations).
Non-persisting, exactly like Registry::load, which is implemented on top of
it. The two used to disagree — this one wrote the defaults out when the file was
missing — which is the sort of difference that makes a test pass while the
behaviour it stands in for is broken.
Sourcepub fn save(&self) -> Result<()>
pub fn save(&self) -> Result<()>
Saves the registry to disk atomically (write to temp, then rename).
Sourcepub fn save_to(&self, path: &Path) -> Result<()>
pub fn save_to(&self, path: &Path) -> Result<()>
Saves the registry to a specific path (for testing or custom locations).
Sourcepub fn add_repo(&mut self, path: PathBuf) -> bool
pub fn add_repo(&mut self, path: PathBuf) -> bool
Adds a repository to the registry. Returns true if newly added, false if already present.
Sourcepub fn adopt_moved_entry(
&mut self,
path: &Path,
identity: Option<String>,
) -> Adoption
pub fn adopt_moved_entry( &mut self, path: &Path, identity: Option<String>, ) -> Adoption
Record identity against a registered repository, and hand it the history of the
entry it moved away from.
Called after add_repo from both link and init. When exactly one registered
path no longer exists on disk and carries the same root commit, that entry is the
same repository at its old location: its added_at, prune history and settings
move across and the dead row is removed. Two dead entries claiming one identity
is a clone, not a move, so nothing is guessed — the caller says so instead.
Also the backfill path. Entries registered before 1.4.0 have no identity, so
nothing they do can be recognised as a move; re-registering them records one, and
a single devp init ~/code backfills the whole registry.
Sourcepub fn needs_identity(&self, path: &Path) -> bool
pub fn needs_identity(&self, path: &Path) -> bool
Whether a registered repository still has no recorded identity.
The global Git hook runs devp link --quiet on every commit, and backfilling
unconditionally would shell out to git and rewrite the registry once per commit
forever. This makes it once per repository.
Sourcepub fn remove_repo(&mut self, path: &Path) -> bool
pub fn remove_repo(&mut self, path: &Path) -> bool
Removes a repository from the registry. Returns true if it was present.
A repository that has been deleted from disk cannot be canonicalised any more,
so canonical_key falls back to the path as typed — which never equals the
canonical key it was registered under (on Windows those carry the \\?\
prefix). Unlinking a deleted repository is the most ordinary reason to unlink
at all, so a direct miss falls back to a lexical comparison.
Sourcepub fn mark_pruned(&mut self, path: &Path, bytes_freed: u64)
pub fn mark_pruned(&mut self, path: &Path, bytes_freed: u64)
Credit bytes_freed to one repository, and to the machine-wide total.
Safe to call once per repository or once per directory — every figure it touches
is either a sum or a timestamp, so the two styles agree. Counting passes is
deliberately not done here for exactly that reason; that lives in
Registry::record_prune, which is called once per pass.
Sourcepub fn record_restore(&mut self, adapter: &str, bytes: u64, millis: u64)
pub fn record_restore(&mut self, adapter: &str, bytes: u64, millis: u64)
Record what a prune pass deleted, replacing any earlier record.
A pass that deleted nothing is not a pass worth remembering, so an empty list is
ignored rather than stored — otherwise devp run on an already-clean machine
would quietly throw away the record of the run the user actually wants back.
This is the one place a prune pass is counted. It sets Registry::last_prune,
appends a PruneRunSummary to Registry::prune_history and bumps
Registry::total_pruned_count, because “a pass happened and it deleted things”
is exactly the condition all three describe. Splitting them across call sites is
how the counter previously came to mean repositories in devp run and directories
in the devp status dashboard.
Fold one measured restore into an adapter’s running average.
Ignores anything too quick to have been real work — see
constants::RESTORE_RATE_MIN_MILLIS — because a manager that found everything
still in its cache returns in a moment and would teach a throughput no cold
restore can reach. That is the difference between an estimate that is optimistic
and one that is wrong.
Sourcepub fn estimate_restore(
&self,
by_adapter: &[(String, u64)],
) -> Option<(f64, u64)>
pub fn estimate_restore( &self, by_adapter: &[(String, u64)], ) -> Option<(f64, u64)>
How long putting back by_adapter would take, from what this machine has
measured.
Returns the seconds and the bytes those seconds account for. Anything from an
adapter that has never been timed here is left out of both, so a caller can say
how much of the estimate is actually covered rather than quietly quoting a
number for half the work. None when nothing is covered at all — an estimate
with no measurement behind it is a guess, and this command does not print
guesses.
pub fn record_prune(&mut self, dirs: Vec<PrunedDir>)
Sourcepub fn record_prune_progress(&mut self, at: DateTime<Utc>, dirs: Vec<PrunedDir>)
pub fn record_prune_progress(&mut self, at: DateTime<Utc>, dirs: Vec<PrunedDir>)
Record a pass’s progress mid-flight, superseding this same pass’s earlier record.
at identifies the pass: a repeated call with the same timestamp replaces the
history entry and last_prune it wrote before, rather than counting a second
pass. This exists so a long pass can persist after every repository — a crash
half-way through used to leave devp restore --last-run pointing at the
previous pass, offering to reinstall directories that were never deleted while
saying nothing about the ones that were.
Sourcepub fn repo_count(&self) -> usize
pub fn repo_count(&self) -> usize
Returns the number of registered repositories.
Trait Implementations§
Source§impl<'de> Deserialize<'de> for Registry
impl<'de> Deserialize<'de> for Registry
Source§fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
impl StructuralPartialEq for Registry
Auto Trait Implementations§
impl Freeze for Registry
impl RefUnwindSafe for Registry
impl Send for Registry
impl Sync for Registry
impl Unpin for Registry
impl UnsafeUnpin for Registry
impl UnwindSafe for Registry
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> DeserializeOwned for Twhere
T: for<'de> Deserialize<'de>,
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more