diaryrs/src/args.rs

73 lines
1.9 KiB
Rust

use std::path::PathBuf;
use clap::{Parser, Subcommand};
use diaryrs::macros::UnwrapOrFatalAble;
use serde::Deserialize;
/// Overengineered and overly opinionated Rust-based diary keeper and processor.
/// Happy journaling!
#[derive(Parser)]
#[command(version, about)]
pub struct Args {
#[command(subcommand)]
pub cmd: Commands,
}
#[derive(Subcommand, Clone)]
pub enum Commands {
/// Print basic configuration information
Info,
/// Write diary entry file for today
Today,
/// Take inventory of the diary entries you have
Inventory,
}
#[derive(Debug, Deserialize)]
pub struct Config {
// Global options
/// The base path for diary entries
pub base_path: PathBuf,
/// Path where the config file was found. Not deserialised from the file
#[serde(skip_deserializing)]
pub config_path: PathBuf,
}
impl Config {
const CONFIG_PATHS: [&'static str; 5] = [
"diaryrs.toml",
"diary.toml",
"~/.config/diaryrs.toml",
"~/diaryrs.toml",
"~/.diaryrs.toml",
];
pub fn read() -> Result<Self, Box<dyn std::error::Error>> {
let (config_str, config_path) = try_files(
Vec::from(Self::CONFIG_PATHS)
.into_iter()
.map(|p| PathBuf::from(p))
.collect(),
)
.unwrap_or_fatal("No config file found");
let config: Config = toml::from_str(&config_str)?;
Ok(Config {
config_path,
..config
})
}
}
/// Try a list of file paths and return the contents of the first file
/// that exists. If all files have been tried none exist, None is returned
fn try_files(paths: Vec<PathBuf>) -> Option<(String, PathBuf)> {
for path in paths {
match std::fs::read_to_string(&path) {
Ok(contents) => return Some((contents, path)),
Err(_) => continue,
}
}
None
}