start working on a cli app #7

Merged
schrottkatze merged 12 commits from :app into main 2024-01-20 19:09:52 +00:00
5 changed files with 94 additions and 74 deletions
Showing only changes of commit ea2e5d6075 - Show all commits

View file

@ -1,74 +1,24 @@
use std::{ use clap::Parser;
fs,
path::{Path, PathBuf},
process,
};
use serde::{Deserialize, Serialize}; use self::{cli::Args, config_file::Configs};
use crate::error_reporting::{report_serde_json_err, report_serde_ron_err}; mod cli;
mod config_file;
#[derive(Debug, Serialize, Deserialize)] /// this struct may hold all configuration
pub struct Configs { pub struct Config {
#[serde(default = "default_example_value")] pub startup_msg: bool,
pub example_value: i32,
#[serde(default = "default_no_startup_msg")]
pub no_startup_message: bool,
} }
/// what the fuck serde why do i need this impl Config {
fn default_example_value() -> i32 { pub fn read() -> Self {
43 let args = Args::parse();
} let cfg = Configs::read(args.config_file);
fn default_no_startup_msg() -> bool {
false
}
impl Configs { Self {
pub fn read(custom_path: Option<PathBuf>) -> Self { // this is negated because to an outward api, the negative is more intuitive,
use owo_colors::OwoColorize; // while in the source the other way around is more intuitive
let p = match custom_path { startup_msg: !(args.no_startup_message || cfg.no_startup_message),
Some(p) => p,
None => {
let config_path = dirs::config_dir().expect("config dir should exist");
let ron_path = config_path.with_file_name("config.ron");
let json_path = config_path.with_file_name("config.json");
if Path::new(&ron_path).exists() {
ron_path
} else if Path::new(&json_path).exists() {
json_path
} else {
eprintln!("{}: couldn't find config file", "Fatal error".red());
process::exit(1)
}
}
};
match p.extension().map(|v| v.to_str().unwrap()) {
Some("ron") => Self::read_json(&fs::read_to_string(p).unwrap()),
Some("json") => Self::read_ron(&fs::read_to_string(p).unwrap()),
None | Some(_) => {
eprintln!(
"{}: couldn't determine config file type",
"Fatal error".red()
);
process::exit(1)
}
}
}
pub fn read_json(config_text: &str) -> Configs {
match serde_json::from_str(config_text) {
Ok(c) => c,
Err(e) => report_serde_json_err(config_text, e),
}
}
pub fn read_ron(config_text: &str) -> Configs {
match ron::from_str(config_text) {
Ok(c) => c,
Err(e) => report_serde_ron_err(config_text, e),
} }
} }
} }

View file

@ -0,0 +1,75 @@
use std::{
fs,
path::{Path, PathBuf},
process,
};
use serde::{Deserialize, Serialize};
use crate::error_reporting::{report_serde_json_err, report_serde_ron_err};
#[derive(Debug, Serialize, Deserialize)]
pub struct Configs {
#[serde(default = "default_example_value")]
pub example_value: i32,
schrottkatze marked this conversation as resolved Outdated

Since the default is false which is also returned by `bool::default, the extra function is not necessary:

-    #[serde(default = "default_no_startup_msg")]
+    #[serde(default)]

If you do desire to keep the functions to allow more detailed behavior in future, I suggest renaming default_no_startup_msg to to just bool_false and creating a bool_true counterpart once necessary.

Since the default is `false` which is also returned by `bool::default, the extra function is not necessary: ```diff - #[serde(default = "default_no_startup_msg")] + #[serde(default)] ``` If you do desire to keep the functions to allow more detailed behavior in future, I suggest renaming `default_no_startup_msg` to to just `bool_false` and creating a `bool_true` counterpart once necessary.
#[serde(default = "default_no_startup_msg")]
pub no_startup_message: bool,
}
/// what the fuck serde why do i need this
pub(crate) fn default_example_value() -> i32 {
43
}
pub(crate) fn default_no_startup_msg() -> bool {
false
}
impl Configs {
pub fn read(custom_path: Option<PathBuf>) -> Self {
use owo_colors::OwoColorize;
let p = match custom_path {
Some(p) => p,
None => {
let config_path = dirs::config_dir().expect("config dir should exist");
let ron_path = config_path.with_file_name("config.ron");
let json_path = config_path.with_file_name("config.json");
if Path::new(&ron_path).exists() {
ron_path
} else if Path::new(&json_path).exists() {
json_path
} else {
eprintln!("{}: couldn't find config file", "Fatal error".red());
process::exit(1)
}
}
};
match p.extension().map(|v| v.to_str().unwrap()) {
Some("ron") => Self::read_json(&fs::read_to_string(p).unwrap()),
Some("json") => Self::read_ron(&fs::read_to_string(p).unwrap()),
None | Some(_) => {
eprintln!(
"{}: couldn't determine config file type",
"Fatal error".red()
);
process::exit(1)
}
}
}
pub fn read_json(config_text: &str) -> Configs {
match serde_json::from_str(config_text) {
Ok(c) => c,
Err(e) => report_serde_json_err(config_text, e),
}
}
pub fn read_ron(config_text: &str) -> Configs {
match ron::from_str(config_text) {
Ok(c) => c,
Err(e) => report_serde_ron_err(config_text, e),
}
}
}

View file

@ -1,19 +1,14 @@
use clap::Parser; use config::Config;
use cli::Args;
use welcome_msg::print_startup_msg; use welcome_msg::print_startup_msg;
use crate::config::Configs;
mod cli;
mod config; mod config;
mod error_reporting; mod error_reporting;
mod welcome_msg; mod welcome_msg;
fn main() { fn main() {
let args = Args::parse(); let cfg = Config::read();
let cfg = Configs::read(args.config_file);
if !(args.no_startup_message || cfg.no_startup_message) { if cfg.startup_msg {
print_startup_msg(); print_startup_msg();
} }
} }
multisamplednight marked this conversation as resolved Outdated

Might want to streamline those two, in order to avoid accidentally checking only one of them in future.

The figment crate might be worth looking at in that case.

Might want to streamline those two, in order to avoid accidentally checking only one of them in future. The `figment` crate might be worth looking at in that case.

i'd prefer to try at least to some degree reduce dependencies, but i'll work on something like that then

i'd prefer to try at least to some degree reduce dependencies, but i'll work on something like that then

You don't need to use figment. Custom merge logic works fine, too.

You don't _need_ to use `figment`. Custom merge logic works fine, too.

View file

@ -7,4 +7,4 @@ edition = "2021"
[dependencies] [dependencies]
serde = { workspace = true, features = [ "derive" ] } serde = { workspace = true, features = [ "derive" ] }
ron = { workspace = true } ron = "0.8"