@@ -57,10 +57,14 @@ mod imp {
5757
5858pub 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+
74101pub 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