liftoff 0.1.1

Get your coding project off the ground fast. See repo
Documentation
use crate::{*, error::KickError};
use clap::ArgMatches;
use leg;
use std::{
    env,
    fs,
    path::{Path, PathBuf},
};

pub fn config_path_from_input(matches: &ArgMatches) -> Result<PathBuf, KickError> {
    let config_arg = matches.value_of("config").unwrap(); // safe to unwrap, required by clap
    let config_path = PathBuf::from(config_arg);
    if config_path.exists() && config_path.is_file() {
        return Ok(config_path);
    }

    if !consts::LIFTOFF_CONFIG_TEMPLATE_ARGS
        .iter()
        .any(|&config| config == config_arg)
    {
        Err(KickError::InvalidConfigFileError(config_arg.to_string()))
    } else {
        Ok(Path::new(consts::LIFTOFF_HOME)
            .join("configs/")
            .join(config_arg)
            .with_extension("sane"))
    }
}

pub fn prep(matches: &ArgMatches) -> Result<(), KickError> {
    let config_arg = matches.value_of("identifier").unwrap(); // safe to unwrap, required by clap
    let config_path = Path::new(consts::LIFTOFF_HOME)
        .join("configs/")
        .join(config_arg)
        .with_extension("sane");

    let file_name = matches.value_of("name").unwrap(); // safe to unwrap, required by clap
    let target = &env::current_dir()?.join(&file_name);

    if !&config_path.exists() {
        Err(KickError::InvalidConfigFileError(format!("{}", config_path.display())))
    } else {
        files::copy(&config_path, &target)
    }
}

pub fn save(matches: &ArgMatches) -> Result<(), KickError> {
    let config_arg = matches.value_of("name").unwrap(); // safe to unwrap, required by clap
    let config_path = Path::new(&config_arg);
    if !config_path.exists() {
        return Err(KickError::InvalidConfigFileError(config_arg.to_string()))
    }

    let target = Path::new(consts::LIFTOFF_HOME)
        .join("configs/")
        .join(config_arg);

    if target.exists() && matches.occurrences_of("force") == 0 {
        pexit!("This would overwrite the default config file. Please rename or run with `-f`");
    }

    files::copy(&config_path, &target)
}

pub fn install() -> Result<(), KickError> {
    let configs_path = Path::new(consts::LIFTOFF_HOME).join("configs");

    let licenses_path = Path::new(consts::LIFTOFF_HOME).join("licenses");
    files::mkdir(&configs_path)?;
    files::mkdir(&licenses_path)?;

    pinfo!(
        "Installing templates from LIFTOFF_repo/files/configs in {}",
        configs_path.display()
    );
    for link in consts::LIFTOFF_CONFIG_LINKS.iter() {
        let filename = link.rsplit("/").next().unwrap();
        web::download(link, &configs_path.join(filename))?;
    }

    pinfo!(
        "Installing licenses from LIFTOFF_repo/files/licenses in {}",
        configs_path.display()
    );
    for link in consts::LIFTOFF_LICENSE_LINKS.iter() {
        let filename = link.rsplit("/").next().unwrap();
        web::download(link, &licenses_path.join(filename))?;
    }

    psuccess!("Successfully installed files");

    Ok(())
}

// TODO proper errors in error.rs, no need for match
pub fn uninstall() -> Result<(), KickError> {
    pwarn!("Uninstalling files in {}", consts::LIFTOFF_HOME);
    let home_path = Path::new(consts::LIFTOFF_HOME);
    if Path::exists(home_path) {
        match fs::remove_dir_all(home_path) {
            Ok(_) => psuccess!("Successfully uninstalled files"),
            Err(e) => {
                perror!("Couldn't uninstall: {:?}", e);
                return Err(error::KickError::FileError(e));
            }
        }
    } else {
        pinfo!("Nothing to uninstall");
    }

    Ok(())
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    #[ignore]
    fn test_install_and_uninstall() {
        install().unwrap();
        let home_path = Path::new(consts::LIFTOFF_HOME);
        let configs_path = home_path.join("configs");
        let licenses_path = home_path.join("licenses");
        assert!(Path::exists(&configs_path.as_path()));
        assert!(Path::exists(&licenses_path.as_path()));
        for link in consts::LIFTOFF_CONFIG_LINKS.iter() {
            let filename = link.rsplit("/").next().unwrap();
            assert!(Path::exists(configs_path.join(filename).as_path()));
        }

        for link in consts::LIFTOFF_LICENSE_LINKS.iter() {
            let filename = link.rsplit("/").next().unwrap();
            assert!(Path::exists(licenses_path.join(filename).as_path()));
        }

        uninstall().unwrap();
        assert!(!Path::exists(&home_path));
        install().unwrap(); // so i don't have to reinstall every time....
    }
}