ghee 0.6.1

That thin layer of data change management over the filesystem
Documentation
use std::{
    fs::{create_dir_all, File},
    path::PathBuf,
};

use anyhow::Result;
use path_absolutize::Absolutize;

use crate::{containing_table_info, write_xattr_values, xattr_values_from_path};

/**
 * Create a file at `path`; if part of a table, initialize its
 * xattrs from those inferred from the path.
 *
 * Parent directories will be created as necessary.
 */
pub fn touch(path: &PathBuf, create_parents: bool) -> Result<()> {
    let path = path.absolutize().unwrap().to_path_buf();
    if create_parents {
        if let Some(parent) = path.parent() {
            create_dir_all(parent)?;
        }
    }

    File::create(&path)?;

    if let Some(info) = containing_table_info(&path)? {
        let xattrs = xattr_values_from_path(info.key(), info.path_abs(), &path)?;

        write_xattr_values(path, &xattrs)?;
    }

    Ok(())
}

#[cfg(test)]
mod test {
    use ghee_lang::Key;

    use crate::{cmd::init, test_support::TempDirAuto, xattr_values};

    use super::touch;

    #[test]
    fn test_touch() {
        let dir = TempDirAuto::new("ghee-test-touch");

        let f = {
            let mut p = dir.clone();
            p.push("README.md");
            p
        };

        assert!(dir.exists());

        assert!(!f.exists());

        touch(&f, false).unwrap();

        assert!(f.exists());

        let xattrs = xattr_values(&f).unwrap();

        assert_eq!(xattrs.len(), 0);
    }

    #[test]
    fn test_touch_no_parent() {
        let dir = TempDirAuto::new("ghee-test-touch-no-parent");

        let sub = {
            let mut p = dir.clone();
            p.push("fasteners");
            p
        };

        let f = {
            let mut p = sub.clone();
            p.push("velcro");
            p
        };

        assert!(dir.exists());

        assert!(!sub.exists());

        assert!(!f.exists());

        touch(&f, false).expect_err("Should have failed due to nonexisting parent dir");
    }

    #[test]
    fn test_touch_create_parents() {
        let dir = TempDirAuto::new("ghee-test-touch-create-parents");

        let sub = {
            let mut p = dir.clone();
            p.push("fasteners");
            p
        };

        let f = {
            let mut p = sub.clone();
            p.push("velcro");
            p
        };

        assert!(dir.exists());

        assert!(!sub.exists());

        assert!(!f.exists());

        touch(&f, true).unwrap();

        assert!(dir.exists());

        assert!(sub.exists());

        assert!(f.exists());

        let xattrs = xattr_values(&f).unwrap();

        assert_eq!(xattrs.len(), 0);
    }

    #[test]
    fn test_touch_inferred_xattrs() {
        let dir = TempDirAuto::new("ghee-test-touch-inferred-xattrs");

        let key = Key::from_string("color,cost");

        init(&dir, &key, false).unwrap();

        let sub = {
            let mut p = dir.clone();
            p.push("red");
            p
        };

        let f = {
            let mut p = sub.clone();
            p.push("5");
            p
        };

        assert!(dir.exists());

        assert!(!sub.exists());

        assert!(!f.exists());

        touch(&f, true).unwrap();

        assert!(dir.exists());

        assert!(sub.exists());

        assert!(f.exists());

        let xattrs = xattr_values(&f).unwrap();

        assert_eq!(xattrs.len(), 2);

        assert!(xattrs.contains_key(&key.subkeys[0]));
        assert!(xattrs.contains_key(&key.subkeys[1]));
    }
}