1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
// config file parser
use crate::utils::BoxError;
use log::debug;
use serde_derive::{Deserialize, Serialize};
use std::collections::HashMap;
use std::fs::{read_to_string, File};
use std::path::PathBuf;

#[derive(Debug, Serialize, Deserialize, Default)]
pub struct Config {
    pub autodone: bool,
    pub database: HashMap<String, String>,
}

impl Config {
    pub fn new() -> Self {
        Config {
            autodone: false,
            database: HashMap::<String, String>::new(),
        }
    }

    pub fn save(&self, filepath: Option<&PathBuf>) -> Result<(), BoxError> {
        let cfgpath = get_config_path(filepath);
        let mut file = File::create(&cfgpath)?;
        self.save_to(&mut file)
    }

    pub fn save_to(&self, file: &mut impl std::io::Write) -> Result<(), BoxError> {
        let resultstr = toml::to_string(self)?;
        file.write_all(resultstr.as_bytes())?;
        Ok(())
    }

    pub fn load(filepath: Option<&PathBuf>) -> Result<Self, BoxError> {
        let cfgpath = get_config_path(filepath);
        let content = read_to_string(&cfgpath)?;
        let config: Config = toml::from_str(&content)?;
        Ok(config)
    }
}

pub fn get_config_path(filepath: Option<&PathBuf>) -> PathBuf {
    match filepath {
        None => {
            let mut tmp_path: PathBuf = dirs::home_dir().unwrap();
            tmp_path.push(".ttrackrrc");
            tmp_path
        }
        Some(filepath) => PathBuf::from(filepath),
    }
}

pub fn create_config(
    filepath: Option<&PathBuf>,
    dbfile: Option<&PathBuf>,
) -> Result<(bool, PathBuf), BoxError> {
    let cfgpath = get_config_path(filepath);
    debug!("using cfgpath: {:?} [exists:{}]", cfgpath, cfgpath.exists());
    if cfgpath.exists() {
        return Ok((false, cfgpath));
    }

    let mut dbpath: PathBuf;
    if let Some(path) = dbfile {
        dbpath = path.to_path_buf();
    } else {
        dbpath = dirs::home_dir().unwrap();
        dbpath.push(".ttrackr.db");
    }

    let mut config = Config::new();
    config
        .database
        .insert("path".to_owned(), dbpath.to_string_lossy().to_string());

    match config.save(filepath) {
        Ok(()) => Ok((true, cfgpath)),
        Err(err) => Err(err),
    }
}

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

    #[test]
    fn load_config_from_file() -> Result<(), BoxError> {
        let mut conf = Config::new();
        conf.database
            .insert("path".to_owned(), "/tmp/testfile".to_owned());
        let mut file = NamedTempFile::new()?;
        conf.save_to(&mut file)?;
        let check = Config::load(Some(&file.path().to_path_buf()))?;
        assert_eq!(conf.autodone, check.autodone);
        assert_eq!(conf.database, conf.database);
        Ok(())
    }
}