Skip to content

Commit 5316331

Browse files
jdxclaude
andcommitted
fix(prune): over-protect for sub-N:latest in offline mode
Per cursor review: applying version_sub to latest_installed_version shifts the result one step too low, missing the actually-installed sub-N target. resolve_sub now returns the raw `sub-N:latest` spec in offline mode, and get_versions_needed_by_tracked_configs detects this case and protects every installed version of the backend. Over-protecting (some old versions stay) is the safe failure mode vs. deleting the active version. Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
1 parent 1e335ae commit 5316331

2 files changed

Lines changed: 19 additions & 11 deletions

File tree

src/toolset/mod.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -643,6 +643,20 @@ pub async fn get_versions_needed_by_tracked_configs(
643643
ts.resolve_with_opts(config, &opts).await?;
644644
for (_, tv) in ts.list_current_versions() {
645645
needed.insert((tv.ba().short.to_string(), tv.tv_pathname()));
646+
// Offline can't resolve `sub-N:latest` to a concrete version
647+
// (no remote latest available). Conservatively protect every
648+
// installed version of this backend so we don't delete the
649+
// active one.
650+
if offline
651+
&& let crate::toolset::ToolRequest::Sub { orig_version, .. } = &tv.request
652+
&& orig_version == "latest"
653+
&& let Ok(backend) = tv.backend()
654+
{
655+
let short = tv.ba().short.to_string();
656+
for v in backend.list_installed_versions() {
657+
needed.insert((short.clone(), v));
658+
}
659+
}
646660
}
647661
}
648662
Ok(needed)

src/toolset/tool_version.rs

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -458,17 +458,11 @@ impl ToolVersion {
458458
) -> Result<Self> {
459459
let backend = request.backend()?;
460460
if v == "latest" && opts.offline {
461-
// Use the latest installed version as the basis for the sub
462-
// computation so the resolved concrete version still matches an
463-
// installed pathname (and gets protected from prune). Falling
464-
// straight to the raw "sub-N:latest" string would never match
465-
// anything in `to_delete`.
466-
if !opts.latest_versions
467-
&& let Some(latest) = backend.latest_installed_version(None)?
468-
{
469-
let v = tool_request::version_sub(&latest, sub);
470-
return Box::pin(Self::resolve_version(config, request, &v, opts)).await;
471-
}
461+
// Can't resolve sub-N:latest offline (no remote latest, and
462+
// applying version_sub to latest_installed_version would shift
463+
// one step too low). Return the raw spec; callers that care
464+
// (`get_versions_needed_by_tracked_configs`) over-protect by
465+
// keeping all installed versions of this backend.
472466
let version = request.version();
473467
return Ok(Self::new(request, version));
474468
}

0 commit comments

Comments
 (0)