start working on a cli app #7
|
@ -14,6 +14,7 @@ pub struct Config {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Config {
|
impl Config {
|
||||||
|
/// Get the configs from all possible places (args, file, env...)
|
||||||
pub fn read() -> Self {
|
pub fn read() -> Self {
|
||||||
let args = Args::parse();
|
let args = Args::parse();
|
||||||
let config_path = if let Some(config_path) = args.config_path {
|
let config_path = if let Some(config_path) = args.config_path {
|
||||||
|
@ -22,6 +23,7 @@ impl Config {
|
||||||
find_config_file()
|
find_config_file()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// try to read a maybe existing config file
|
||||||
let file_config = if let Ok(config_path) = config_path {
|
let file_config = if let Ok(config_path) = config_path {
|
||||||
let file_config = Configs::read(config_path);
|
let file_config = Configs::read(config_path);
|
||||||
|
|
||||||
|
@ -52,13 +54,22 @@ impl Config {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub mod error {
|
pub mod error {
|
||||||
|
/// Errors that can occur when reading configs
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum ConfigError {
|
pub enum ConfigError {
|
||||||
|
/// The config dir doesn't exist
|
||||||
NoConfigDir,
|
NoConfigDir,
|
||||||
|
/// We didn't find a config file in the config dir
|
||||||
NoConfigFileFound,
|
NoConfigFileFound,
|
||||||
|
/// An io error happened while reading/opening it!
|
||||||
IoError(std::io::Error),
|
IoError(std::io::Error),
|
||||||
|
/// The given extension (via an argument) isn't known.
|
||||||
|
///
|
||||||
|
/// Occurs if the extension is neither `.json` nor `.ron` (including if there is no extension, in which case this will be `None`).
|
||||||
UnknownExtension(Option<String>),
|
UnknownExtension(Option<String>),
|
||||||
|
/// Wrapper around an `Error` from `serde_json`
|
||||||
SerdeJsonError(serde_json::Error),
|
SerdeJsonError(serde_json::Error),
|
||||||
|
/// Wrapper around a `SpannedError` from `ron`
|
||||||
SerdeRonError(ron::error::SpannedError),
|
SerdeRonError(ron::error::SpannedError),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,9 @@ pub(crate) struct Args {
|
||||||
/// Read this config file.
|
/// Read this config file.
|
||||||
#[arg(short, long)]
|
#[arg(short, long)]
|
||||||
pub config_path: Option<PathBuf>,
|
pub config_path: Option<PathBuf>,
|
||||||
|
/// Turn off the startup message.
|
||||||
schrottkatze marked this conversation as resolved
Outdated
|
|||||||
|
///
|
||||||
|
/// The startup message is not constant and depends on the time.
|
||||||
#[arg(long, env = "NO_STARTUP_MESSAGE", default_value = "false")]
|
#[arg(long, env = "NO_STARTUP_MESSAGE", default_value = "false")]
|
||||||
pub no_startup_message: bool,
|
pub no_startup_message: bool,
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,7 @@ use super::error::ConfigError;
|
||||||
pub struct Configs {
|
pub struct Configs {
|
||||||
#[serde(default = "default_example_value")]
|
#[serde(default = "default_example_value")]
|
||||||
pub example_value: i32,
|
pub example_value: i32,
|
||||||
#[serde(default = "default_no_startup_msg")]
|
#[serde(default)]
|
||||||
schrottkatze marked this conversation as resolved
Outdated
multisamplednight
commented
Since the default is
If you do desire to keep the functions to allow more detailed behavior in future, I suggest renaming 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.
|
|||||||
pub no_startup_message: bool,
|
pub no_startup_message: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,10 +20,7 @@ fn default_example_value() -> i32 {
|
||||||
43
|
43
|
||||||
}
|
}
|
||||||
|
|
||||||
fn default_no_startup_msg() -> bool {
|
/// Find the location of a config file and check if there is, in fact, a file
|
||||||
false
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(super) fn find_config_file() -> Result<PathBuf, ConfigError> {
|
pub(super) fn find_config_file() -> Result<PathBuf, ConfigError> {
|
||||||
let Some(config_path) = dirs::config_dir() else {
|
let Some(config_path) = dirs::config_dir() else {
|
||||||
return Err(ConfigError::NoConfigDir);
|
return Err(ConfigError::NoConfigDir);
|
||||||
|
|
|
@ -2,16 +2,19 @@ use std::process;
|
||||||
|
|
||||||
use ron::error::Position;
|
use ron::error::Position;
|
||||||
|
|
||||||
|
/// Report an `Error` from the `serde_json` crate
|
||||||
pub fn report_serde_json_err(src: &str, err: serde_json::Error) -> ! {
|
pub fn report_serde_json_err(src: &str, err: serde_json::Error) -> ! {
|
||||||
report_serde_err(src, err.line(), err.column(), err.to_string())
|
report_serde_err(src, err.line(), err.column(), err.to_string())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Report a `SpannedError` from the `ron` crate
|
||||||
pub fn report_serde_ron_err(src: &str, err: ron::error::SpannedError) -> ! {
|
pub fn report_serde_ron_err(src: &str, err: ron::error::SpannedError) -> ! {
|
||||||
let Position { line, col } = err.position;
|
let Position { line, col } = err.position;
|
||||||
report_serde_err(src, line, col, err.to_string())
|
report_serde_err(src, line, col, err.to_string())
|
||||||
}
|
}
|
||||||
multisamplednight marked this conversation as resolved
Outdated
multisamplednight
commented
Maybe Then that streamlined error could report a bit more specific using Maybe `report_serde_err` could take a custom error, which the errors from `ron` and `serde_json` are converted into.
Then that streamlined error could report a bit more specific using `serde_error::Error::classify` and `ron::Error`.
schrottkatze
commented
ye, that's a hack bc i was too lazy to implement a proper error type ^^' ye, that's a hack bc i was too lazy to implement a proper error type ^^'
|
|||||||
|
|
||||||
pub fn report_serde_err(src: &str, line: usize, col: usize, msg: String) -> ! {
|
/// Basic function for reporting serde type of errors
|
||||||
|
fn report_serde_err(src: &str, line: usize, col: usize, msg: String) -> ! {
|
||||||
use ariadne::{Label, Report, Source};
|
use ariadne::{Label, Report, Source};
|
||||||
let offset = try_reconstruct_loc(src, line, col);
|
let offset = try_reconstruct_loc(src, line, col);
|
||||||
|
|
||||||
|
@ -24,6 +27,8 @@ pub fn report_serde_err(src: &str, line: usize, col: usize, msg: String) -> ! {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
process::exit(1);
|
process::exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Reconstruct a byte offset from the line + column numbers typical from serde crates
|
||||||
fn try_reconstruct_loc(src: &str, line_nr: usize, col_nr: usize) -> usize {
|
fn try_reconstruct_loc(src: &str, line_nr: usize, col_nr: usize) -> usize {
|
||||||
let (line_nr, col_nr) = (line_nr - 1, col_nr - 1);
|
let (line_nr, col_nr) = (line_nr - 1, col_nr - 1);
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,14 @@
|
||||||
use time::{Month, OffsetDateTime};
|
use time::{Month, OffsetDateTime};
|
||||||
|
|
||||||
|
/// Print the startup message which changes depending on system time.
|
||||||
pub fn print_startup_msg() {
|
pub fn print_startup_msg() {
|
||||||
// now or fallback to utc
|
// now or fallback to utc
|
||||||
multisamplednight marked this conversation as resolved
Outdated
multisamplednight
commented
Can always use Can always use `now_utc`, since no calculations are performed based on the timezone.
schrottkatze
commented
the day might very well be timezone dependent, depending on where you live though? the day might very well be timezone dependent, depending on where you live though?
multisamplednight
commented
Nevermind, I misinterpreted
Nevermind, I misinterpreted `now_utc`. I thought it'd return the current system time and assume it to be UTC (like `SystemTime::now` does), but it doesn't:
```
>> :dep time = { features = ["local-offset"] }
Compiling libc v0.2.152
Compiling powerfmt v0.2.0
Compiling num_threads v0.1.6
Compiling deranged v0.3.11
Compiling time v0.3.31
>> use time::OffsetDateTime;
>> OffsetDateTime::now_utc()
2024-01-12 21:03:54.32211146 +00:00:00
>> OffsetDateTime::now_local()
Ok(2024-01-12 22:03:58.663618677 +01:00:00)
```
|
|||||||
let now = OffsetDateTime::now_local().unwrap_or_else(|_| OffsetDateTime::now_utc());
|
let now = OffsetDateTime::now_local().unwrap_or_else(|_| OffsetDateTime::now_utc());
|
||||||
|
|
||||||
if now.month() == Month::June {
|
if now.month() == Month::June {
|
||||||
|
// pride startup message
|
||||||
println!("Hello, thanks for using iOwO and happy pride month!");
|
println!("Hello, thanks for using iOwO and happy pride month!");
|
||||||
|
// TODO: proper link with explaination
|
||||||
println!("Why pride month is important in {}", now.year());
|
println!("Why pride month is important in {}", now.year());
|
||||||
} else {
|
} else {
|
||||||
println!("Hello, thanks for using iOwO! :3");
|
println!("Hello, thanks for using iOwO! :3");
|
||||||
|
|
Might want a
clap::builder::BoolishValueParser
here.How do I use that with claps derive api?
Through