#![allow(dead_code)]
use std::fs;
use std::path::{Path, PathBuf};
use std::time::{Duration, Instant};
use tempfile::TempDir;
pub struct Workspace {
_tmp: TempDir,
root: PathBuf,
}
impl Workspace {
pub fn new() -> Self {
let tmp = tempfile::tempdir().expect("create a temp dir");
let root = tmp.path().to_path_buf();
Self { _tmp: tmp, root }
}
pub fn root(&self) -> &Path {
&self.root
}
pub fn write(&self, name: &str, contents: &str) -> PathBuf {
let rel = Path::new(name);
assert!(
rel.is_relative()
&& !rel
.components()
.any(|c| matches!(c, std::path::Component::ParentDir)),
"fixture path must stay inside the workspace; got {name}"
);
let path = self.root.join(rel);
if let Some(parent) = path.parent() {
fs::create_dir_all(parent).expect("create parent dirs");
}
fs::write(&path, contents).expect("write fixture file");
path
}
}
impl Default for Workspace {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug)]
pub enum PollError<E> {
Probe(E),
Deadline { what: String, waited: Duration },
}
pub fn poll_until<T, E, F>(what: &str, timeout: Duration, mut probe: F) -> Result<T, PollError<E>>
where
F: FnMut() -> Result<Option<T>, E>,
{
let start = Instant::now();
loop {
if let Some(value) = probe().map_err(PollError::Probe)? {
return Ok(value);
}
let waited = start.elapsed();
if waited >= timeout {
return Err(PollError::Deadline {
what: what.to_string(),
waited,
});
}
std::thread::sleep(Duration::from_millis(20));
}
}