setuprs 0.1.6

setuprs is a versatile CLI and TUI application designed to streamline project management by enabling quick creation and cloning of project snapshots. Utilizing clap.rs for command-line functionality and ratatui.rs for an interactive text interface, setuprs offers a user-friendly solution for managing and replicating project scaffolds efficiently.
use std::{env, fmt::Display, fs, path::PathBuf, str::FromStr};

use serde_derive::Deserialize;
pub mod utils;

#[derive(PartialEq, Deserialize, Debug)]
pub struct Config {
    pub config_file_path: String,
    pub debug_mode: String,
    pub snapshots_path: String,
}

impl Config {
    pub fn new(config: &Option<PathBuf>) -> Self {
        let config_path: PathBuf = match config {
            Some(v) => v.clone(),
            _ => PathBuf::from(Self::default().config_file_path),
        };

        if let Ok(contents) = fs::read_to_string(config_path) {
            if let Ok(newconf) = toml::from_str::<Config>(&contents) {
                newconf
            } else {
                Config::default()
            }
        } else {
            Config::default()
        }
    }
}

impl Default for Config {
    fn default() -> Self {
        let home = env::var("HOME").unwrap();

        Self {
            config_file_path: format!("{home}/.config/setuprs/setuprs.toml"),
            debug_mode: "error".to_string(),
            snapshots_path: format!("{home}/.config/setuprs/snapshots/"),
        }
    }
}

impl Display for Config {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(
            f,
            "\n----------------------\nCONFIG\n----------------------\nConfig file path: {}\nSnapshots path: {}\nDebug mode: {}\n----------------------",
            self.config_file_path, self.snapshots_path, self.debug_mode
        )
    }
}

#[derive(Debug, PartialEq, Eq)]
pub struct ParseConfigError;

impl FromStr for Config {
    type Err = ParseConfigError;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        let mut config_file_path = None;
        let mut snapshot_path = None;
        let mut debug_mode = None;

        for line in s.lines() {
            let parts: Vec<&str> = line.split(':').map(|s| s.trim()).collect();

            if parts.len() == 2 {
                let (key, value) = (parts[0], parts[1]);

                match key {
                    "Config file path" => config_file_path = Some(value.to_string()),
                    "Snapshots path" => snapshot_path = Some(value.to_string()),
                    "Debug mode" => debug_mode = Some(value.to_string()),
                    _ => {}
                }
            }
        }

        Ok(Config {
            config_file_path: config_file_path.unwrap(),
            snapshots_path: snapshot_path.unwrap(),
            debug_mode: debug_mode.unwrap(),
        })
    }
}

#[derive(PartialEq, Deserialize, Debug)]
pub struct SetuprsConfig {
    pub project: Option<Project>,
    pub variables: Option<Vec<Variables>>,
}

#[derive(PartialEq, Deserialize, Debug)]
pub struct Project {
    pub name: String,
}

#[derive(PartialEq, Deserialize, Debug)]
pub struct Variables {
    pub name: String,
    pub default: Option<String>,
}

#[test]
fn toml_should_parse_setup_config_when_project_is_not_declared() {
    let setuprs_toml = "[[variables]]
name=\"var1\"
default=\"variable_default_value\"
[[variables]]
name=\"var2\"";
    toml::from_str::<SetuprsConfig>(setuprs_toml).unwrap();
}

#[test]
fn toml_should_parse_setup_config_with_all_variables() {
    let setuprs_toml = "[project]
name = \"project_name\"\n
[[variables]]
name=\"var1\"
default=\"variable_default_value\"
[[variables]]
name=\"var2\"";
    toml::from_str::<SetuprsConfig>(setuprs_toml).unwrap();
}

#[test]
#[should_panic]
fn toml_should_panic_when_variables_has_no_name() {
    let setuprs_toml = "[project]
name = \"project_name\"\n
[[variables]]";

    toml::from_str::<SetuprsConfig>(setuprs_toml).unwrap();
}

#[test]
#[should_panic]
fn toml_should_panic_when_project_has_no_name() {
    let setuprs_toml = "[project]\n
[[variables]]
name=\"var1\"
default=\"variable_default_value\"
[[variables]]
name=\"var2\"";

    toml::from_str::<SetuprsConfig>(setuprs_toml).unwrap();
}