use std::env;
use std::error;
use std::fs::{self};
#[cfg(target_family = "unix")]
use std::os::unix::fs::symlink;
use std::path::{Path, PathBuf};
use std::result;
pub const TEMP_DIRECTORY_NAME: &str = "paq";
pub type Result<T> = result::Result<T, Box<dyn error::Error + Send + Sync>>;
#[macro_export]
macro_rules! err {
($($tt:tt)*) => {
Box::<dyn error::Error + Send + Sync>::from(format!($($tt)*))
}
}
#[derive(Debug)]
pub struct TempDir(PathBuf);
#[cfg(feature = "test-cleanup")]
impl Drop for TempDir {
fn drop(&mut self) {
fs::remove_dir_all(&self.0).unwrap();
}
}
impl TempDir {
pub fn new(name: &str) -> Result<TempDir> {
static TRIES: usize = 100;
let tmpdir = env::temp_dir();
for _ in 0..TRIES {
let root_path = tmpdir.join(TEMP_DIRECTORY_NAME);
let iteration_path = root_path.join(name);
if iteration_path.is_dir() {
continue;
}
fs::create_dir_all(&iteration_path)
.map_err(|e| err!("failed to create {}: {}", iteration_path.display(), e))?;
return Ok(TempDir(iteration_path));
}
Err(err!("failed to create temp dir after {} tries", TRIES))
}
pub fn new_file(&self, name: &str, data: &[u8]) -> Result<()> {
let file_path = PathBuf::from(format!("{}/{}", self.path().display(), name));
fs::write(file_path.as_os_str(), data).expect("Unable to write file");
Ok(())
}
pub fn read_file(&self, name: &str) -> Result<Vec<u8>> {
let file_path = PathBuf::from(format!("{}/{}", self.path().display(), name));
Ok(fs::read(file_path.as_os_str()).expect("Unable to read file"))
}
#[cfg(target_family = "unix")]
pub fn new_symlink(&self, name: &str, target: PathBuf) -> Result<()> {
let symlink_path = PathBuf::from(format!("{}/{}", self.path().display(), name));
symlink(target.as_os_str(), symlink_path.as_os_str())
.expect("Unable to create symlink");
Ok(
(),
)
}
pub fn path(&self) -> &Path {
&self.0
}
}