|
1 |
| -use std::ffi::CString; |
| 1 | +use std::ffi::{CString, OsStr}; |
2 | 2 | use std::path::{Path, PathBuf, absolute};
|
3 |
| -use std::{fs, io}; |
| 3 | +use std::{env, fs, io}; |
| 4 | + |
| 5 | +use tempfile::TempDir; |
4 | 6 |
|
5 | 7 | // Unfortunately, on windows, it looks like msvcrt.dll is silently translating
|
6 | 8 | // verbatim paths under the hood to non-verbatim paths! This manifests itself as
|
@@ -102,3 +104,43 @@ pub fn path_to_c_string(p: &Path) -> CString {
|
102 | 104 | pub fn try_canonicalize<P: AsRef<Path>>(path: P) -> io::Result<PathBuf> {
|
103 | 105 | fs::canonicalize(&path).or_else(|_| absolute(&path))
|
104 | 106 | }
|
| 107 | + |
| 108 | +pub struct TempDirBuilder<'a, 'b> { |
| 109 | + builder: tempfile::Builder<'a, 'b>, |
| 110 | +} |
| 111 | + |
| 112 | +impl<'a, 'b> TempDirBuilder<'a, 'b> { |
| 113 | + pub fn new() -> Self { |
| 114 | + Self { builder: tempfile::Builder::new() } |
| 115 | + } |
| 116 | + |
| 117 | + pub fn prefix<S: AsRef<OsStr> + ?Sized>(&mut self, prefix: &'a S) -> &mut Self { |
| 118 | + self.builder.prefix(prefix); |
| 119 | + self |
| 120 | + } |
| 121 | + |
| 122 | + pub fn suffix<S: AsRef<OsStr> + ?Sized>(&mut self, suffix: &'b S) -> &mut Self { |
| 123 | + self.builder.suffix(suffix); |
| 124 | + self |
| 125 | + } |
| 126 | + |
| 127 | + pub fn tempdir_in<P: AsRef<Path>>(&self, dir: P) -> io::Result<TempDir> { |
| 128 | + let dir = dir.as_ref(); |
| 129 | + // On Windows in CI, we had been getting fairly frequent "Access is denied" |
| 130 | + // errors when creating temporary directories. |
| 131 | + // So this implements a simple retry with backoff loop. |
| 132 | + #[cfg(windows)] |
| 133 | + for wait in 1..11 { |
| 134 | + match self.builder.tempdir_in(dir) { |
| 135 | + Err(e) if e.kind() == io::ErrorKind::PermissionDenied => {} |
| 136 | + t => return t, |
| 137 | + } |
| 138 | + std::thread::sleep(std::time::Duration::from_millis(1 << wait)); |
| 139 | + } |
| 140 | + self.builder.tempdir_in(dir) |
| 141 | + } |
| 142 | + |
| 143 | + pub fn tempdir(&self) -> io::Result<TempDir> { |
| 144 | + self.tempdir_in(env::temp_dir()) |
| 145 | + } |
| 146 | +} |
0 commit comments