aether-utils 0.2.18

Shared utilities for the Aether AI agent framework
Documentation
use std::{
    env::temp_dir,
    fs::{create_dir_all, remove_dir_all},
    io::{self, Write},
    path::{Path, PathBuf},
};
use tempfile::Builder;
use uuid::Uuid;

#[derive(Debug)]
pub struct TempDir(PathBuf);

impl TempDir {
    pub fn new() -> Self {
        Self(temp_dir().join(format!("aether-{}", Uuid::new_v4())))
    }

    pub fn path(&self) -> &Path {
        &self.0
    }

    pub fn save(&self, label: &str, text: &str) -> io::Result<PathBuf> {
        create_dir_all(&self.0)?;
        let label = label.replace(|c: char| !c.is_ascii_alphanumeric() && c != '-' && c != '_', "_");
        let mut file = Builder::new().prefix(&format!("{label}-")).suffix(".txt").tempfile_in(&self.0)?;
        file.write_all(text.as_bytes())?;
        Ok(file.keep()?.1)
    }
}

impl Default for TempDir {
    fn default() -> Self {
        Self::new()
    }
}

impl Drop for TempDir {
    fn drop(&mut self) {
        let _ = remove_dir_all(&self.0);
    }
}

#[cfg(test)]
mod tests {
    use std::fs::{create_dir_all, read_to_string, write};

    use super::*;

    #[test]
    fn each_dir_is_unique() {
        assert_ne!(TempDir::new().path(), TempDir::new().path());
    }

    #[test]
    fn dropping_the_dir_deletes_what_was_written_into_it() {
        let dir = TempDir::new();
        create_dir_all(dir.path()).unwrap();
        write(dir.path().join("saved.txt"), "output").unwrap();
        let path = dir.path().to_path_buf();

        drop(dir);
        assert!(!path.exists());
    }

    #[test]
    fn save_creates_the_dir_and_keeps_labels_with_path_separators_inside_it() {
        let dir = TempDir::new();

        let saved = dir.save("../my/server__tool", "output").unwrap();

        assert_eq!(saved.parent(), Some(dir.path()));
        assert_eq!(read_to_string(saved).unwrap(), "output");
    }
}