use std::path::PathBuf;
use anyhow::{anyhow, Context, Result};
use serde::{Deserialize, Serialize};
#[derive(Deserialize, Serialize)]
pub struct Config {
pub todo_file: PathBuf,
pub done_file: PathBuf,
}
static TODO_FILE: &str = "todo.txt";
static DONE_FILE: &str = "done.txt";
impl Config {
fn new() -> Result<Self> {
let mut todo_txt_path = std::path::PathBuf::new();
let mut done_txt_path = std::path::PathBuf::new();
set_default_path(&mut todo_txt_path, TODO_FILE)?;
set_default_path(&mut done_txt_path, DONE_FILE)?;
Ok(Config {
todo_file: todo_txt_path,
done_file: done_txt_path,
})
}
pub fn load(config_file_path: Option<PathBuf>) -> Result<Config> {
let mut file_path: PathBuf;
if let Some(file) = config_file_path.as_deref() {
file_path = file.to_path_buf();
} else {
file_path = get_configdir()?;
file_path.push("toddi");
file_path.push("config.toml");
match std::fs::exists(&file_path) {
Ok(value) => {
if !value {
println!("Default configuration file does not exist.");
match Config::new() {
Ok(config) => {
match toml::to_string(&config) {
Ok(conf_str) => {
if let Some(parent_dir) = file_path.parent() {
if !parent_dir.exists() {
std::fs::create_dir_all(parent_dir)?;
}
}
println!(
"Writing default configuration file: {}",
file_path.display()
);
std::fs::write(&file_path, &conf_str).with_context(
|| {
format!(
"Could not write file `{}`\nwith config: {}",
file_path.display(),
&conf_str
)
},
)?;
}
Err(err) => {
return Err(anyhow!(
"Could not serialize default configuration!\nError: {:?}",
err
));
}
};
}
Err(err) => {
return Err(anyhow!(
"Could not load configuration!\nError: {:?}",
err
))
}
};
}
}
Err(err) => {
return Err(anyhow!(
"Could not assess whether configuration file exists or not!\nError: {:?}",
err
))
}
}
}
let config_file = std::fs::read_to_string(&file_path)
.with_context(|| format!("could not read file `{}`", file_path.display()))?;
match toml::from_str(&config_file) {
Ok(parsed_config) => {
let parsed_config: Config = parsed_config;
Ok(parsed_config)
}
Err(err) => Err(anyhow!("Could not parse configuration!\nError: {:?}", err)),
}
}
}
fn set_default_path(path_buffer: &mut PathBuf, filename: &str) -> Result<()> {
let home_folder = get_homedir()?;
let default_folder = ".todo-txt";
path_buffer.push(&home_folder);
path_buffer.push(default_folder);
path_buffer.push(filename);
Ok(())
}
fn get_homedir() -> Result<PathBuf> {
if let Some(dir) = dirs::home_dir() {
Ok(dir)
} else {
Err(anyhow!(
"Issue with `dirs` crate: could not fetch home directory."
))
}
}
fn get_configdir() -> Result<PathBuf> {
if let Some(dir) = dirs::config_dir() {
Ok(dir)
} else {
Err(anyhow!(
"Issue with `dirs` crate: could not fetch configuration directory."
))
}
}