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::{
fs,
path::{Path, PathBuf},
process,
};
use clap::Parser;
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)]
pub struct Configs {
#[serde(default = "default_example_value")]
pub example_value: i32,
#[serde(default = "default_no_startup_msg")]
pub no_startup_message: bool,
/// this struct may hold all configuration
pub struct Config {
pub startup_msg: bool,
}
/// what the fuck serde why do i need this
fn default_example_value() -> i32 {
43
}
fn default_no_startup_msg() -> bool {
false
}
impl Config {
pub fn read() -> Self {
let args = Args::parse();
let cfg = Configs::read(args.config_file);
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),
Self {
// this is negated because to an outward api, the negative is more intuitive,
// while in the source the other way around is more intuitive
startup_msg: !(args.no_startup_message || cfg.no_startup_message),
}
}
}

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 cli::Args;
use config::Config;
use welcome_msg::print_startup_msg;
use crate::config::Configs;
mod cli;
mod config;
mod error_reporting;
mod welcome_msg;
fn main() {
let args = Args::parse();
let cfg = Configs::read(args.config_file);
let cfg = Config::read();
if !(args.no_startup_message || cfg.no_startup_message) {
if cfg.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]
serde = { workspace = true, features = [ "derive" ] }
ron = { workspace = true }
ron = "0.8"