ghee 0.6.1

That thin layer of data change management over the filesystem
Documentation
use std::{
    env::{current_dir, set_current_dir},
    fs::{remove_dir_all, File},
    io::Write,
    ops::{Deref, DerefMut},
    path::{Path, PathBuf},
};

use ghee_lang::{Key, Xattr};
use tempdir::TempDir;

use crate::cmd::{idx, init, ins};

/** A test scenario
 *
 * dir1 is indexed by ['test1'] (xattr1)
 * dir2 is indexed by ['test2', 'test3'] (xattr2, xattr3)
 */
pub struct Scenario {
    /// Table indexed by xattr1
    pub dir1: TempDirAuto,

    /// Table indexed by (xattr2,xattr3)
    pub dir2: TempDirAuto,
    pub key1: Key,
    pub key2: Key,
    pub xattr1: Xattr,
    pub xattr2: Xattr,
    pub xattr3: Xattr,

    /// The unindexed attribute
    pub xattr4: Xattr,

    pub dir1path1: PathBuf,
    pub dir1path2: PathBuf,

    pub dir2path1: PathBuf,
    pub dir2path2: PathBuf,
}
impl Scenario {
    pub fn new(tag: &str) -> Self {
        let prefix = format!("ghee-test-scenario-{}", tag);
        let records_dir = TempDirAuto::new(format!("{}:records", prefix).as_str());
        let mut records_path = records_dir.clone();
        records_path.push("records.json");

        {
            let mut w = File::create(&records_path).unwrap();
            w.write_all(
                br#"{"test1": 0, "test2": 1, "test3": 2, "test4": 3}
{"test1": 10, "test2": 11, "test3": 12, "test4": 13}"#,
            )
            .unwrap();
        }

        let dir1 = TempDirAuto::new(format!("{}:1", prefix).as_str());

        let dir2 = TempDirAuto::new(format!("{}:2", prefix).as_str());

        let key1 = Key::from(vec!["test1"]);
        let xattr1 = key1.subkeys[0].clone();

        let key2 = Key::from(vec!["test2", "test3"]);
        let xattr2 = key2.subkeys[0].clone();
        let xattr3 = key2.subkeys[1].clone();

        let xattr4 = Xattr::from("test4");

        init(&dir1, &key1, false).unwrap();

        idx(&dir1, Some(&dir2), &key2, false).unwrap();

        ins(&dir1, &Some(records_path), false).unwrap();

        let dir1path1 = {
            let mut path = dir1.clone();
            path.push("0");
            path
        };

        let dir1path2 = {
            let mut path = dir1.clone();
            path.push("10");
            path
        };

        let dir2path1 = {
            let mut path = dir2.clone();
            path.push("1");
            path.push("2");
            path
        };

        let dir2path2 = {
            let mut path = dir2.clone();
            path.push("11");
            path.push("12");
            path
        };

        for path in vec![&dir1path1, &dir1path2, &dir2path1, &dir2path2] {
            assert!(
                path.exists(),
                "Path {} doesn't exist but should",
                path.display()
            );
        }

        Self {
            dir1,
            dir2,
            key1,
            key2,
            xattr1,
            xattr2,
            xattr3,
            xattr4,
            dir1path1,
            dir1path2,
            dir2path1,
            dir2path2,
        }
    }
}

/// Like TempDir, but deletes the directory on drop
#[derive(Debug)]
pub struct TempDirAuto {
    pub dir: PathBuf,
}

impl TempDirAuto {
    pub fn new(s: &str) -> Self {
        Self {
            dir: TempDir::new(s).unwrap().into_path(),
        }
    }

    /// Clones this path and pushes the new component; returns an
    /// independent, autodeleting path
    pub fn push<P: AsRef<Path>>(&self, p: P) -> Self {
        let mut dir = self.dir.clone();
        dir.push(p);
        Self { dir }
    }
}

impl Drop for TempDirAuto {
    fn drop(&mut self) {
        remove_dir_all(&self.dir).unwrap();
    }
}

impl AsMut<PathBuf> for TempDirAuto {
    fn as_mut(&mut self) -> &mut PathBuf {
        &mut self.dir
    }
}

impl AsRef<Path> for TempDirAuto {
    fn as_ref(&self) -> &Path {
        self.dir.as_path()
    }
}

impl AsRef<PathBuf> for TempDirAuto {
    fn as_ref(&self) -> &PathBuf {
        &self.dir
    }
}

impl Deref for TempDirAuto {
    type Target = PathBuf;

    fn deref(&self) -> &Self::Target {
        &self.dir
    }
}

impl DerefMut for TempDirAuto {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.dir
    }
}

pub struct CurrentDirGuard {
    pub prior_dir: PathBuf,
}

impl CurrentDirGuard {
    pub fn new<P: AsRef<Path>>(alt: P) -> Self {
        let alt = alt.as_ref().to_path_buf();
        let prior_dir = current_dir().unwrap();
        set_current_dir(&alt).unwrap();

        debug_assert_eq!(current_dir().unwrap(), alt);

        Self { prior_dir }
    }
}

impl Drop for CurrentDirGuard {
    fn drop(&mut self) {
        set_current_dir(&self.prior_dir).unwrap();
    }
}