pulith_fs/primitives/
replace_dir.rs1use crate::{Error, Result};
2use std::path::Path;
3
4pub struct Options {
5 pub retry_count: u32,
6 pub retry_delay: std::time::Duration,
7}
8
9impl Default for Options {
10 fn default() -> Self {
11 Self {
12 retry_count: 5,
13 retry_delay: std::time::Duration::from_millis(100),
14 }
15 }
16}
17
18impl Options {
19 pub fn new() -> Self {
20 Self::default()
21 }
22 pub fn retry_count(mut self, count: u32) -> Self {
23 self.retry_count = count;
24 self
25 }
26 pub fn retry_delay(mut self, delay: std::time::Duration) -> Self {
27 self.retry_delay = delay;
28 self
29 }
30}
31
32pub fn replace_dir(src: impl AsRef<Path>, dest: impl AsRef<Path>, _options: Options) -> Result<()> {
33 let src = src.as_ref();
34 let dest = dest.as_ref();
35
36 #[cfg(unix)]
37 {
38 std::fs::rename(src, dest).map_err(|e| Error::ReplaceDir {
39 path: dest.to_path_buf(),
40 source: e,
41 })
42 }
43
44 #[cfg(windows)]
45 {
46 use std::thread;
47 let options = _options;
48 let mut attempts = 0;
49 loop {
50 if dest.exists()
51 && let Err(e) = std::fs::remove_dir_all(dest)
52 {
53 attempts += 1;
54 if attempts >= options.retry_count {
55 return Err(Error::ReplaceDir {
56 path: dest.to_path_buf(),
57 source: e,
58 });
59 }
60 thread::sleep(options.retry_delay * attempts);
61 continue;
62 }
63
64 match std::fs::rename(src, dest) {
65 Ok(_) => return Ok(()),
66 Err(e) => {
67 attempts += 1;
68 if attempts >= options.retry_count {
69 return Err(Error::ReplaceDir {
70 path: dest.to_path_buf(),
71 source: e,
72 });
73 }
74 thread::sleep(options.retry_delay * attempts);
75 }
76 }
77 }
78 }
79}
80
81#[cfg(test)]
82mod tests {
83 use super::*;
84 use tempfile::tempdir;
85
86 #[test]
87 fn test_replace_dir() {
88 let dir = tempdir().unwrap();
89 let src = dir.path().join("src");
90 let dest = dir.path().join("dest");
91 std::fs::create_dir_all(&src).unwrap();
92 std::fs::write(src.join("file.txt"), "data").unwrap();
93
94 replace_dir(&src, &dest, Options::new()).unwrap();
95 assert!(dest.exists());
96 assert!(dest.join("file.txt").exists());
97 }
98}