[go: up one dir, main page]

cacache/
rm.rs

1//! Functions for removing things from the cache.
2use std::fs;
3use std::path::Path;
4
5use ssri::Integrity;
6
7use crate::content::rm;
8use crate::errors::{IoErrorExt, Result};
9use crate::index;
10
11/// Removes an individual index metadata entry. The associated content will be
12/// left in the cache.
13///
14/// ## Example
15/// ```no_run
16/// use async_std::prelude::*;
17/// use async_attributes;
18///
19/// #[async_attributes::main]
20/// async fn main() -> cacache::Result<()> {
21///     let sri = cacache::write("./my-cache", "my-key", b"hello").await?;
22///
23///     cacache::remove("./my-cache", "my-key").await?;
24///
25///     // This fails:
26///     cacache::read("./my-cache", "my-key").await?;
27///
28///     // But this succeeds:
29///     cacache::read_hash("./my-cache", &sri).await?;
30///
31///     Ok(())
32/// }
33/// ```
34#[cfg(any(feature = "async-std", feature = "tokio"))]
35pub async fn remove<P, K>(cache: P, key: K) -> Result<()>
36where
37    P: AsRef<Path>,
38    K: AsRef<str>,
39{
40    index::delete_async(cache.as_ref(), key.as_ref()).await
41}
42
43/// Removes an individual content entry. Any index entries pointing to this
44/// content will become invalidated.
45///
46/// ## Example
47/// ```no_run
48/// use async_std::prelude::*;
49/// use async_attributes;
50///
51/// #[async_attributes::main]
52/// async fn main() -> cacache::Result<()> {
53///     let sri = cacache::write("./my-cache", "my-key", b"hello").await?;
54///
55///     cacache::remove_hash("./my-cache", &sri).await?;
56///
57///     // These fail:
58///     cacache::read("./my-cache", "my-key").await?;
59///     cacache::read_hash("./my-cache", &sri).await?;
60///
61///     // But this succeeds:
62///     cacache::metadata("./my-cache", "my-key").await?;
63///
64///     Ok(())
65/// }
66/// ```
67#[cfg(any(feature = "async-std", feature = "tokio"))]
68pub async fn remove_hash<P: AsRef<Path>>(cache: P, sri: &Integrity) -> Result<()> {
69    rm::rm_async(cache.as_ref(), sri).await
70}
71
72/// Removes entire contents of the cache, including temporary files, the entry
73/// index, and all content data.
74///
75/// ## Example
76/// ```no_run
77/// use async_std::prelude::*;
78/// use async_attributes;
79///
80/// #[async_attributes::main]
81/// async fn main() -> cacache::Result<()> {
82///     let sri = cacache::write("./my-cache", "my-key", b"hello").await?;
83///
84///     cacache::clear("./my-cache").await?;
85///
86///     // These all fail:
87///     cacache::read("./my-cache", "my-key").await?;
88///     cacache::metadata("./my-cache", "my-key").await?;
89///     cacache::read_hash("./my-cache", &sri).await?;
90///
91///     Ok(())
92/// }
93/// ```
94#[cfg(any(feature = "async-std", feature = "tokio"))]
95pub async fn clear<P: AsRef<Path>>(cache: P) -> Result<()> {
96    async fn inner(cache: &Path) -> Result<()> {
97        for entry in cache
98            .read_dir()
99            .with_context(|| {
100                format!(
101                    "Failed to read directory contents while clearing cache, at {}",
102                    cache.display()
103                )
104            })?
105            .flatten()
106        {
107            crate::async_lib::remove_dir_all(entry.path())
108                .await
109                .with_context(|| format!("Failed to clear cache at {}", cache.display()))?;
110        }
111        Ok(())
112    }
113    inner(cache.as_ref()).await
114}
115
116/// Removes an individual index entry synchronously. The associated content
117/// will be left in the cache.
118///
119/// ## Example
120/// ```no_run
121/// use std::io::Read;
122///
123/// fn main() -> cacache::Result<()> {
124///     let sri = cacache::write_sync("./my-cache", "my-key", b"hello")?;
125///
126///     cacache::remove_sync("./my-cache", "my-key")?;
127///
128///     // This fails:
129///     cacache::read_sync("./my-cache", "my-key")?;
130///
131///     // But this succeeds:
132///     cacache::read_hash_sync("./my-cache", &sri)?;
133///
134///     Ok(())
135/// }
136/// ```
137pub fn remove_sync<P, K>(cache: P, key: K) -> Result<()>
138where
139    P: AsRef<Path>,
140    K: AsRef<str>,
141{
142    index::delete(cache.as_ref(), key.as_ref())
143}
144
145/// Removes an individual content entry synchronously. Any index entries
146/// pointing to this content will become invalidated.
147///
148/// ## Example
149/// ```no_run
150/// use std::io::Read;
151///
152/// fn main() -> cacache::Result<()> {
153///     let sri = cacache::write_sync("./my-cache", "my-key", b"hello")?;
154///
155///     cacache::remove_hash_sync("./my-cache", &sri)?;
156///
157///     // These fail:
158///     cacache::read_sync("./my-cache", "my-key")?;
159///     cacache::read_hash_sync("./my-cache", &sri)?;
160///
161///     // But this succeeds:
162///     cacache::metadata_sync("./my-cache", "my-key")?;
163///
164///     Ok(())
165/// }
166/// ```
167pub fn remove_hash_sync<P: AsRef<Path>>(cache: P, sri: &Integrity) -> Result<()> {
168    rm::rm(cache.as_ref(), sri)
169}
170
171/// Removes entire contents of the cache synchronously, including temporary
172/// files, the entry index, and all content data.
173///
174/// ## Example
175/// ```no_run
176/// use std::io::Read;
177///
178/// fn main() -> cacache::Result<()> {
179///     let sri = cacache::write_sync("./my-cache", "my-key", b"hello")?;
180///
181///     cacache::clear_sync("./my-cache")?;
182///
183///     // These all fail:
184///     cacache::read_sync("./my-cache", "my-key")?;
185///     cacache::read_hash_sync("./my-cache", &sri)?;
186///     cacache::metadata_sync("./my-cache", "my-key")?;
187///
188///     Ok(())
189/// }
190/// ```
191pub fn clear_sync<P: AsRef<Path>>(cache: P) -> Result<()> {
192    fn inner(cache: &Path) -> Result<()> {
193        for entry in cache
194            .read_dir()
195            .with_context(|| {
196                format!(
197                    "Failed to read directory contents while clearing cache, at {}",
198                    cache.display()
199                )
200            })?
201            .flatten()
202        {
203            fs::remove_dir_all(entry.path())
204                .with_context(|| format!("Failed to clear cache at {}", cache.display()))?;
205        }
206        Ok(())
207    }
208    inner(cache.as_ref())
209}
210
211#[cfg(test)]
212mod tests {
213
214    #[cfg(feature = "async-std")]
215    use async_attributes::test as async_test;
216    #[cfg(feature = "tokio")]
217    use tokio::test as async_test;
218
219    #[cfg(any(feature = "async-std", feature = "tokio"))]
220    #[async_test]
221    async fn test_remove() {
222        futures::executor::block_on(async {
223            let tmp = tempfile::tempdir().unwrap();
224            let dir = tmp.path().to_owned();
225            let sri = crate::write(&dir, "key", b"my-data").await.unwrap();
226
227            crate::remove(&dir, "key").await.unwrap();
228
229            let entry = crate::metadata(&dir, "key").await.unwrap();
230            assert_eq!(entry, None);
231
232            let data_exists = crate::exists(&dir, &sri).await;
233            assert!(data_exists);
234        });
235    }
236
237    #[cfg(any(feature = "async-std", feature = "tokio"))]
238    #[async_test]
239    async fn test_remove_data() {
240        futures::executor::block_on(async {
241            let tmp = tempfile::tempdir().unwrap();
242            let dir = tmp.path().to_owned();
243            let sri = crate::write(&dir, "key", b"my-data").await.unwrap();
244
245            crate::remove_hash(&dir, &sri).await.unwrap();
246
247            let entry = crate::metadata(&dir, "key").await.unwrap();
248            assert!(entry.is_some());
249
250            let data_exists = crate::exists(&dir, &sri).await;
251            assert!(!data_exists);
252        });
253    }
254
255    #[cfg(any(feature = "async-std", feature = "tokio"))]
256    #[async_test]
257    async fn test_clear() {
258        futures::executor::block_on(async {
259            let tmp = tempfile::tempdir().unwrap();
260            let dir = tmp.path().to_owned();
261            let sri = crate::write(&dir, "key", b"my-data").await.unwrap();
262
263            crate::clear(&dir).await.unwrap();
264
265            let entry = crate::metadata(&dir, "key").await.unwrap();
266            assert!(entry.is_none());
267
268            let data_exists = crate::exists(&dir, &sri).await;
269            assert!(!data_exists);
270        });
271    }
272
273    #[test]
274    fn test_remove_sync() {
275        let tmp = tempfile::tempdir().unwrap();
276        let dir = tmp.path().to_owned();
277        let sri = crate::write_sync(&dir, "key", b"my-data").unwrap();
278
279        crate::remove_sync(&dir, "key").unwrap();
280
281        let new_entry = crate::metadata_sync(&dir, "key").unwrap();
282        assert!(new_entry.is_none());
283
284        let data_exists = crate::exists_sync(&dir, &sri);
285        assert!(data_exists);
286    }
287
288    #[test]
289    fn test_remove_data_sync() {
290        let tmp = tempfile::tempdir().unwrap();
291        let dir = tmp.path().to_owned();
292        let sri = crate::write_sync(&dir, "key", b"my-data").unwrap();
293
294        crate::remove_hash_sync(&dir, &sri).unwrap();
295
296        let entry = crate::metadata_sync(&dir, "key").unwrap();
297        assert!(entry.is_some());
298
299        let data_exists = crate::exists_sync(&dir, &sri);
300        assert!(!data_exists);
301    }
302
303    #[test]
304    fn test_clear_sync() {
305        let tmp = tempfile::tempdir().unwrap();
306        let dir = tmp.path().to_owned();
307        let sri = crate::write_sync(&dir, "key", b"my-data").unwrap();
308
309        crate::clear_sync(&dir).unwrap();
310
311        let entry = crate::metadata_sync(&dir, "key").unwrap();
312        assert_eq!(entry, None);
313
314        let data_exists = crate::exists_sync(&dir, &sri);
315        assert!(!data_exists);
316    }
317}