|
1 |
| -use std::ffi::CString; |
| 1 | +use std::ffi::{CString, OsStr}; |
2 | 2 | use std::path::{Path, PathBuf, absolute};
|
3 | 3 | use std::{fs, io};
|
4 | 4 |
|
| 5 | +use tempfile::TempDir; |
| 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
|
7 | 9 | // gcc looking like it cannot accept paths of the form `\\?\C:\...`, but the
|
@@ -102,3 +104,45 @@ 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 | + let mut builder = tempfile::Builder::new(); |
| 115 | + builder.rand_bytes(8); |
| 116 | + Self { builder } |
| 117 | + } |
| 118 | + |
| 119 | + pub fn prefix<S: AsRef<OsStr> + ?Sized>(&mut self, prefix: &'a S) -> &mut Self { |
| 120 | + self.builder.prefix(prefix); |
| 121 | + self |
| 122 | + } |
| 123 | + |
| 124 | + pub fn suffix<S: AsRef<OsStr> + ?Sized>(&mut self, suffix: &'b S) -> &mut Self { |
| 125 | + self.builder.suffix(suffix); |
| 126 | + self |
| 127 | + } |
| 128 | + |
| 129 | + pub fn tempdir_in<P: AsRef<Path>>(&self, dir: P) -> io::Result<TempDir> { |
| 130 | + let dir = dir.as_ref(); |
| 131 | + // On Windows in CI, we had been getting fairly frequent "Access is denied" |
| 132 | + // errors when creating temporary directories. |
| 133 | + // So this implements a simple retry with backoff loop. |
| 134 | + #[cfg(windows)] |
| 135 | + for wait in 1..11 { |
| 136 | + match self.builder.tempdir_in(dir) { |
| 137 | + Err(e) if e.kind() == std::io::ErrorKind::PermissionDenied => {} |
| 138 | + t => return t, |
| 139 | + } |
| 140 | + std::thread::sleep(std::time::Duration::from_millis(1 << wait)); |
| 141 | + } |
| 142 | + self.builder.tempdir_in(dir) |
| 143 | + } |
| 144 | + |
| 145 | + pub fn tempdir(&self) -> io::Result<TempDir> { |
| 146 | + self.builder.tempdir_in(std::env::temp_dir()) |
| 147 | + } |
| 148 | +} |
0 commit comments