Skip to content

Commit cd59e9b

Browse files
authored
purge cache on delete (#119)
1 parent a794078 commit cd59e9b

File tree

5 files changed

+85
-5
lines changed

5 files changed

+85
-5
lines changed

Cargo.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/kiorg/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "kiorg"
3-
version = "1.5.0"
3+
version = "1.5.1"
44
edition = "2024"
55
rust-version = "1.87"
66
authors = ["houqp"]

crates/kiorg/src/ui/popup/delete.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -440,6 +440,8 @@ fn delete_async(app: &mut crate::app::Kiorg, entries_to_delete: Vec<PathBuf>) {
440440
let mut current_file = 0;
441441

442442
for path in entries_to_delete {
443+
crate::utils::preview_cache::delete_previews_for_path(&path);
444+
443445
let result = if path.is_dir() {
444446
delete_dir_with_progress(&path, &tx, &mut current_file, total_files)
445447
} else {

crates/kiorg/src/ui/popup/rename.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,9 @@ pub fn handle_rename_confirmation(app: &mut Kiorg, ctx: &Context) {
3737
{
3838
app.notify_error(format!("Failed to rename: {e}"));
3939
} else {
40+
// Delete preview cache for the old path (all associated versions)
41+
crate::utils::preview_cache::delete_previews_for_path(&entry.meta.path);
42+
4043
// Record rename action in history
4144
let old_path = entry.meta.path.clone();
4245
tab.action_history.add_action(ActionType::Rename {

crates/kiorg/src/utils/preview_cache.rs

Lines changed: 78 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,10 +57,14 @@ mod imp {
5757

5858
pub use imp::{get_cache_dir, purge_cache_dir};
5959

60-
pub fn calculate_cache_key(entry: &DirEntryMeta) -> String {
61-
let path_str = entry.path.to_string_lossy();
60+
pub fn calculate_path_hash(path: &std::path::Path) -> u64 {
61+
let path_str = path.to_string_lossy();
6262
let hasher = RandomState::with_seeds(0, 0, 0, 0);
63-
let path_hash = hasher.hash_one(path_str.as_bytes());
63+
hasher.hash_one(path_str.as_bytes())
64+
}
65+
66+
pub fn calculate_cache_key(entry: &DirEntryMeta) -> String {
67+
let path_hash = calculate_path_hash(&entry.path);
6468

6569
let mtime = entry
6670
.modified
@@ -71,6 +75,29 @@ pub fn calculate_cache_key(entry: &DirEntryMeta) -> String {
7175
format!("{path_hash:x}.{mtime}")
7276
}
7377

78+
pub fn delete_previews_for_path(path: &std::path::Path) {
79+
let path_hash = calculate_path_hash(path);
80+
let hash_hex = format!("{path_hash:x}");
81+
let prefix = format!("{hash_hex}.");
82+
83+
if let Some(mut d) = get_cache_dir() {
84+
if hash_hex.len() >= 2 {
85+
d.push(&hash_hex[0..2]);
86+
}
87+
if d.exists() && d.is_dir() {
88+
if let Ok(entries) = fs::read_dir(d) {
89+
for entry in entries.flatten() {
90+
if let Some(file_name) = entry.file_name().to_str() {
91+
if file_name.starts_with(&prefix) {
92+
let _ = fs::remove_file(entry.path());
93+
}
94+
}
95+
}
96+
}
97+
}
98+
}
99+
}
100+
74101
pub fn get_cache_path(key: &str) -> Option<PathBuf> {
75102
get_cache_dir().map(|mut d| {
76103
if key.len() >= 2 {
@@ -170,4 +197,52 @@ mod tests {
170197
let _ = fs::remove_file(path);
171198
}
172199
}
200+
201+
#[test]
202+
fn test_delete_previews_for_path() {
203+
let path = PathBuf::from("/tmp/test_delete.txt");
204+
let cached = CachedPreviewContent::Zip(vec![]);
205+
206+
// Create multiple cache entries for the same path with different mtimes
207+
let mut keys = Vec::new();
208+
for i in 0..3 {
209+
let entry = DirEntryMeta {
210+
path: path.clone(),
211+
modified: std::time::SystemTime::UNIX_EPOCH + std::time::Duration::from_secs(i),
212+
};
213+
let key = calculate_cache_key(&entry);
214+
save_preview(&key, &cached).expect("Failed to save");
215+
assert!(get_cache_path(&key).unwrap().exists());
216+
keys.push(key);
217+
}
218+
219+
// Verify another path's cache is NOT deleted
220+
let other_path = PathBuf::from("/tmp/other_file.txt");
221+
let other_entry = DirEntryMeta {
222+
path: other_path.clone(),
223+
modified: std::time::SystemTime::now(),
224+
};
225+
let other_key = calculate_cache_key(&other_entry);
226+
save_preview(&other_key, &cached).expect("Failed to save");
227+
assert!(get_cache_path(&other_key).unwrap().exists());
228+
229+
delete_previews_for_path(&path);
230+
231+
// All keys for the target path should be gone
232+
for key in keys {
233+
assert!(
234+
!get_cache_path(&key).unwrap().exists(),
235+
"Cache key {key} should have been deleted"
236+
);
237+
}
238+
239+
// The other path's cache should still exist
240+
assert!(
241+
get_cache_path(&other_key).unwrap().exists(),
242+
"Other path's cache should not have been deleted"
243+
);
244+
245+
// Clean up other path's cache
246+
let _ = fs::remove_file(get_cache_path(&other_key).unwrap());
247+
}
173248
}

0 commit comments

Comments
 (0)