start working on a cli app #7
5 changed files with 94 additions and 74 deletions
|
@ -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),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
75
crates/app/src/config/config_file.rs
Normal file
75
crates/app/src/config/config_file.rs
Normal 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
|
||||
#[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),
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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
multisamplednight
commented
Might want to streamline those two, in order to avoid accidentally checking only one of them in future. The 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.
schrottkatze
commented
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
multisamplednight
commented
You don't need to use You don't _need_ to use `figment`. Custom merge logic works fine, too.
|
||||
|
|
|
@ -7,4 +7,4 @@ edition = "2021"
|
|||
|
||||
[dependencies]
|
||||
serde = { workspace = true, features = [ "derive" ] }
|
||||
ron = { workspace = true }
|
||||
ron = "0.8"
|
||||
|
|
Loading…
Reference in a new issue
Since the default is
false
which is also returned by `bool::default, the extra function is not necessary:If you do desire to keep the functions to allow more detailed behavior in future, I suggest renaming
default_no_startup_msg
to to justbool_false
and creating abool_true
counterpart once necessary.