use std::path::Path;
use std::path::PathBuf;
use crate::prelude::*;
use uuid::Uuid;
#[derive(Debug)]
pub struct TempDir {
path: AbsPathBuf,
keep: bool,
}
impl AsRef<Path> for TempDir {
fn as_ref(&self) -> &Path { &self.path }
}
impl std::ops::Deref for TempDir {
type Target = AbsPathBuf;
fn deref(&self) -> &Self::Target { &self.path }
}
impl Default for TempDir {
fn default() -> Self { Self::new().unwrap() }
}
impl TempDir {
pub fn new() -> FsResult<Self> {
let temp_dir = std::env::temp_dir();
let dir_name = format!("beet_tmp_{}", Uuid::new_v4().to_string());
let dir_path = temp_dir.join(dir_name);
Self::new_with_path(dir_path)
}
pub fn new_workspace() -> FsResult<Self> {
let workspace_root = fs_ext::workspace_root();
let dir_name =
format!("target/tmp/beet_tmp_{}", Uuid::new_v4().to_string());
let dir_path = workspace_root.join(dir_name);
Self::new_with_path(dir_path)
}
fn new_with_path(path: PathBuf) -> FsResult<Self> {
if path.exists() {
return Err(FsError::AlreadyExists { path });
}
fs_ext::create_dir_all(&path)?;
Ok(Self {
path: AbsPathBuf::new(path)?,
keep: false,
})
}
pub fn path(&self) -> &AbsPathBuf { &self.path }
pub fn keep(mut self) -> Self {
self.keep = true;
self
}
}
impl Drop for TempDir {
fn drop(&mut self) {
if !self.keep {
fs_ext::remove(&self.path).ok();
}
}
}
#[cfg(test)]
mod tests {
use crate::prelude::*;
#[test]
fn test_tempdir_new_creates_and_cleans_up() {
let dir_path;
{
let temp = TempDir::new().expect("Failed to create temp directory");
dir_path = temp.path.clone();
dir_path.exists().xpect_true();
dir_path.is_dir().xpect_true();
}
dir_path.exists().xpect_false();
}
#[test]
fn test_tempdir_workspace_relative_creates_and_cleans_up() {
let dir_path;
{
let temp = TempDir::new_workspace()
.expect("Failed to create workspace-relative temp directory");
dir_path = temp.path.clone();
dir_path.exists().xpect_true();
dir_path.is_dir().xpect_true();
let path_str = dir_path.to_string();
path_str.contains("target/tmp/beet_tmp_").xpect_true();
}
dir_path.exists().xpect_false();
}
#[test]
fn test_tempdir_unique_names() {
let temp1 =
TempDir::new().expect("Failed to create first temp directory");
let temp2 =
TempDir::new().expect("Failed to create second temp directory");
temp1.path().clone().xpect_not_eq(temp2.path().clone());
}
#[test]
fn test_tempdir_keep_prevents_cleanup() {
let dir_path;
{
let temp = TempDir::new()
.expect("Failed to create temp directory")
.keep();
dir_path = temp.path().clone();
dir_path.exists().xpect_true();
}
dir_path.exists().xpect_true();
fs_ext::remove(&dir_path).ok();
}
}