dirmux 0.1.1

Directory and git repository command running program
Documentation
use crate::dirs::write_file;
use crate::dirs::FileFormat;
use crate::options::TagSubcommands::*;
use crate::options::*;
use anyhow::Result;
use std::path::PathBuf;

pub fn handle(tagopts: &TagOpts, filename: &PathBuf, file: &FileFormat) -> Result<()> {
    let dir = std::env::current_dir()?;
    let new_file = match &tagopts.action {
        Add(opts) => add(file, opts, &dir),
        Remove(opts) => remove(file, opts, &dir),
        Gc => gc(file),
    }?;
    write_file(&new_file, filename)?;
    Ok(())
}

fn add(file: &FileFormat, opts: &TagAddOpts, cwd: &PathBuf) -> Result<FileFormat> {
    let mut f = file.clone();
    let dir = opts.path.clone().unwrap_or(cwd.to_owned());
    f.add(opts.tag.clone(), &dir);
    Ok(f)
}

fn remove(file: &FileFormat, opts: &TagRemoveOpts, cwd: &PathBuf) -> Result<FileFormat> {
    let mut f = file.clone();
    let dir = opts.path.clone().unwrap_or(cwd.to_owned());
    f.remove(opts.tag.clone(), &dir);
    Ok(f)
}

fn gc(file: &FileFormat) -> Result<FileFormat> {
    let mut f = file.clone();
    f.retain(|x| x.is_dir());
    Ok(f)
}

#[test]
fn test_add() -> Result<()> {
    let opts = TagAddOpts {
        tag: String::from("dev"),
        path: None,
    };
    let mut prior = FileFormat::blank();
    let dir = std::env::current_dir()?;
    let subsequent = add(&prior, &opts, &dir)?;

    assert_ne!(prior, subsequent);
    prior.add(String::from("dev"), &dir);
    assert_eq!(prior, subsequent);
    Ok(())
}

#[test]
fn test_add_exact() -> Result<()> {
    let opts = TagAddOpts {
        tag: String::from("dev"),
        path: Some(PathBuf::from("/dev/null")),
    };
    let mut prior = FileFormat::blank();
    let dir = std::env::current_dir()?;
    let subsequent = add(&prior, &opts, &dir)?;

    assert_ne!(prior, subsequent);
    prior.add(String::from("dev"), &opts.path.unwrap());
    assert_eq!(prior, subsequent);
    Ok(())
}

#[test]
fn test_remove() -> Result<()> {
    let opts_add = TagAddOpts {
        tag: String::from("dev"),
        path: None,
    };
    let opts_rem = TagRemoveOpts {
        tag: String::from("dev"),
        path: None,
    };
    let prior = FileFormat::blank();
    let dir = std::env::current_dir()?;
    let subsequent = add(&prior, &opts_add, &dir)?;
    assert_ne!(prior, subsequent);
    let subsequent = remove(&subsequent, &opts_rem, &dir)?;
    assert_eq!(prior, subsequent);
    Ok(())
}

#[test]
fn test_gc() -> Result<()> {
    let mut expected = FileFormat::blank();
    let dir = std::env::current_dir()?;
    expected.add(String::from("exists"), &dir);
    let mut filled = expected.clone();
    filled.add(
        String::from("non-existing"),
        &PathBuf::from("/dev/does/not/exist"),
    );
    assert_ne!(expected, filled);
    let result = gc(&filled)?;
    assert_eq!(expected, result);
    Ok(())
}