Skip to content

Commit

Permalink
Avoid cache prune failure due to removed interpreter (#5286)
Browse files Browse the repository at this point in the history
## Summary

`uv cache prune` can fail if an ephemeral environment includes a
non-existent interpreter, since we then fail to read the symlink.
  • Loading branch information
charliermarsh committed Jul 22, 2024
1 parent 5a23f05 commit 4797259
Show file tree
Hide file tree
Showing 2 changed files with 22 additions and 20 deletions.
38 changes: 20 additions & 18 deletions crates/uv-cache/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -371,7 +371,22 @@ impl Cache {
}
}

// Second, remove any unused archives (by searching for archives that are not symlinked).
// Second, remove any cached environments. These are never referenced by symlinks, so we can
// remove them directly.
match fs::read_dir(self.bucket(CacheBucket::Environments)) {
Ok(entries) => {
for entry in entries {
let entry = entry?;
let path = fs_err::canonicalize(entry.path())?;
debug!("Removing dangling cache entry: {}", path.display());
summary += rm_rf(path)?;
}
}
Err(err) if err.kind() == io::ErrorKind::NotFound => (),
Err(err) => return Err(err),
}

// Third, remove any unused archives (by searching for archives that are not symlinked).
// TODO(charlie): Remove any unused source distributions. This requires introspecting the
// cache contents, e.g., reading and deserializing the manifests.
let mut references = FxHashSet::default();
Expand All @@ -382,7 +397,9 @@ impl Cache {
for entry in walkdir::WalkDir::new(bucket) {
let entry = entry?;
if entry.file_type().is_symlink() {
references.insert(entry.path().canonicalize()?);
if let Ok(target) = fs_err::canonicalize(entry.path()) {
references.insert(target);
}
}
}
}
Expand All @@ -392,7 +409,7 @@ impl Cache {
Ok(entries) => {
for entry in entries {
let entry = entry?;
let path = entry.path().canonicalize()?;
let path = fs_err::canonicalize(entry.path())?;
if !references.contains(&path) {
debug!("Removing dangling cache entry: {}", path.display());
summary += rm_rf(path)?;
Expand All @@ -403,21 +420,6 @@ impl Cache {
Err(err) => return Err(err),
}

// Third, remove any cached environments. These are never referenced by symlinks, so we can
// remove them directly.
match fs::read_dir(self.bucket(CacheBucket::Environments)) {
Ok(entries) => {
for entry in entries {
let entry = entry?;
let path = entry.path().canonicalize()?;
debug!("Removing dangling cache entry: {}", path.display());
summary += rm_rf(path)?;
}
}
Err(err) if err.kind() == io::ErrorKind::NotFound => (),
Err(err) => return Err(err),
}

Ok(summary)
}
}
Expand Down
4 changes: 2 additions & 2 deletions crates/uv-cache/src/removal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ fn set_readable(path: &Path) -> io::Result<bool> {
#[cfg(unix)]
{
use std::os::unix::fs::PermissionsExt;
let mut perms = path.metadata()?.permissions();
let mut perms = fs_err::metadata(path)?.permissions();
if perms.mode() & 0o500 == 0 {
perms.set_mode(perms.mode() | 0o500);
fs_err::set_permissions(path, perms)?;
Expand All @@ -115,7 +115,7 @@ fn set_readable(path: &Path) -> io::Result<bool> {

/// If the file is readonly, change the permissions to make it _not_ readonly.
fn set_not_readonly(path: &Path) -> io::Result<bool> {
let mut perms = path.metadata()?.permissions();
let mut perms = fs_err::metadata(path)?.permissions();
if !perms.readonly() {
return Ok(false);
}
Expand Down

0 comments on commit 4797259

Please sign in to comment.