From eff29672cff6a292f881bb73180dd624aa5a7014 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kat=20March=C3=A1n?= Date: Sat, 7 Oct 2023 12:40:19 -0700 Subject: [PATCH] fix(remove_fully): Remove the key content when set `remove_fully` to `true` Closes #61 --- Cargo.toml | 2 +- src/index.rs | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index b38f51b..4c2481f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cacache" -version = "11.7.1" +version = "12.0.0" authors = ["Kat Marchán "] edition = "2021" description = "Content-addressable, key-value, high-performance, on-disk cache." diff --git a/src/index.rs b/src/index.rs index 8852107..24c06d6 100644 --- a/src/index.rs +++ b/src/index.rs @@ -20,6 +20,7 @@ use walkdir::WalkDir; #[cfg(any(feature = "async-std", feature = "tokio"))] use crate::async_lib::{AsyncBufReadExt, AsyncWriteExt}; +use crate::content::path::content_path; use crate::errors::{IoErrorExt, Result}; use crate::put::WriteOpts; @@ -407,6 +408,11 @@ impl RemoveOpts { if !self.remove_fully { delete(cache.as_ref(), key.as_ref()) } else { + if let Some(meta) = crate::metadata_sync(cache.as_ref(), key.as_ref())? { + let content = content_path(cache.as_ref(), &meta.integrity); + fs::remove_file(&content) + .with_context(|| format!("Failed to remove content at {content:?}"))?; + } let bucket = bucket_path(cache.as_ref(), key.as_ref()); fs::remove_file(&bucket) .with_context(|| format!("Failed to remove bucket at {bucket:?}")) @@ -422,6 +428,12 @@ impl RemoveOpts { if !self.remove_fully { delete_async(cache.as_ref(), key.as_ref()).await } else { + if let Some(meta) = crate::metadata(cache.as_ref(), key.as_ref()).await? { + let content = content_path(cache.as_ref(), &meta.integrity); + crate::async_lib::remove_file(&content) + .await + .with_context(|| format!("Failed to remove content at {content:?}"))?; + } let bucket = bucket_path(cache.as_ref(), key.as_ref()); crate::async_lib::remove_file(&bucket) .await @@ -535,6 +547,44 @@ mod tests { assert_eq!(find(&dir, "hello").unwrap(), None); } + #[test] + fn delete_fully() { + let tmp = tempfile::tempdir().unwrap(); + let dir = tmp.path().to_owned(); + let content = content_path(&dir, &"sha1-deadbeef".parse().unwrap()); + fs::create_dir_all(content.parent().unwrap()).unwrap(); + fs::write(content.as_path(), "hello").unwrap(); + let sri: Integrity = "sha1-deadbeef".parse().unwrap(); + let time = 1_234_567; + insert(&dir, "hello", WriteOpts::new().integrity(sri).time(time)).unwrap(); + RemoveOpts::new() + .remove_fully(true) + .remove_sync(&dir, "hello") + .unwrap(); + assert_eq!(find(&dir, "hello").unwrap(), None); + assert!(!content.exists()); + } + + #[cfg(any(feature = "async-std", feature = "tokio"))] + #[async_test] + async fn delete_fully_async() { + let tmp = tempfile::tempdir().unwrap(); + let dir = tmp.path().to_owned(); + let content = content_path(&dir, &"sha1-deadbeef".parse().unwrap()); + fs::create_dir_all(content.parent().unwrap()).unwrap(); + fs::write(content.as_path(), "hello").unwrap(); + let sri: Integrity = "sha1-deadbeef".parse().unwrap(); + let time = 1_234_567; + insert(&dir, "hello", WriteOpts::new().integrity(sri).time(time)).unwrap(); + RemoveOpts::new() + .remove_fully(true) + .remove(&dir, "hello") + .await + .unwrap(); + assert_eq!(find(&dir, "hello").unwrap(), None); + assert!(!content.exists()); + } + #[test] fn round_trip() { let tmp = tempfile::tempdir().unwrap();