qubit_fs/temp/
managed_temp_dir.rs1use std::sync::Arc;
13
14use log::warn;
15
16use crate::{
17 CopyConflictPolicy,
18 CopyOptions,
19 DeleteOptions,
20 FileSystem,
21 FsErrorKind,
22 FsPath,
23 FsResult,
24 PersistOptions,
25 RenameOptions,
26 TempDir,
27 TempResource,
28};
29
30#[derive(Debug)]
32pub struct ManagedTempDir {
33 fs: Arc<dyn FileSystem>,
35 path: FsPath,
37 cleanup_on_drop: bool,
39}
40
41impl ManagedTempDir {
42 #[inline]
51 #[must_use]
52 pub fn new(fs: Arc<dyn FileSystem>, path: FsPath) -> Self {
53 Self {
54 fs,
55 path,
56 cleanup_on_drop: true,
57 }
58 }
59
60 #[inline]
65 fn detach(&mut self) -> FsPath {
66 self.cleanup_on_drop = false;
67 self.path.clone()
68 }
69}
70
71impl TempResource for ManagedTempDir {
72 #[inline]
73 fn fs(&self) -> Arc<dyn FileSystem> {
74 self.fs.clone()
75 }
76
77 #[inline]
78 fn path(&self) -> &FsPath {
79 &self.path
80 }
81
82 fn cleanup(mut self: Box<Self>) -> FsResult<()> {
83 let result = self.fs.delete(
84 &self.path,
85 &DeleteOptions {
86 recursive: true,
87 missing_ok: true,
88 if_match: None,
89 },
90 );
91 if result.is_ok() {
92 self.cleanup_on_drop = false;
93 }
94 result
95 }
96
97 fn keep(mut self: Box<Self>) -> FsResult<FsPath> {
98 Ok(self.detach())
99 }
100}
101
102impl TempDir for ManagedTempDir {
103 fn persist(mut self: Box<Self>, target: &FsPath, options: &PersistOptions) -> FsResult<()> {
104 let rename_options = RenameOptions {
105 overwrite: options.overwrite,
106 atomic: options.atomic,
107 };
108 match self.fs.rename(&self.path, target, &rename_options) {
109 Ok(()) => {
110 self.cleanup_on_drop = false;
111 Ok(())
112 }
113 Err(error) if error.kind() == FsErrorKind::UnsupportedOperation && options.allow_copy_delete => {
114 let mut copy_options = CopyOptions::tree();
115 copy_options.conflict = if options.overwrite {
116 CopyConflictPolicy::Overwrite
117 } else {
118 CopyConflictPolicy::Fail
119 };
120 copy_options.preserve_metadata = options.preserve_metadata;
121 self.fs.copy(&self.path, target, ©_options)?;
122 self.fs.delete(
123 &self.path,
124 &DeleteOptions {
125 recursive: true,
126 missing_ok: true,
127 if_match: None,
128 },
129 )?;
130 self.cleanup_on_drop = false;
131 Ok(())
132 }
133 Err(error) => Err(error),
134 }
135 }
136}
137
138impl Drop for ManagedTempDir {
139 fn drop(&mut self) {
140 if self.cleanup_on_drop {
141 let result = self.fs.delete(
142 &self.path,
143 &DeleteOptions {
144 recursive: true,
145 missing_ok: true,
146 if_match: None,
147 },
148 );
149 if let Err(error) = result {
150 warn!("failed to cleanup temporary directory '{}': {error}", self.path);
151 }
152 }
153 }
154}