feat: migrate utils::config from anyhow to thiserror and handle a "single config init" mechanism

This commit is contained in:
Florian Briand 2024-09-16 22:49:28 +02:00
parent 262b450c75
commit 8fdb74dbae
Signed by: florian_briand
GPG Key ID: CC981B9E6B98E70B
3 changed files with 33 additions and 10 deletions

View File

@ -9,7 +9,7 @@ use thiserror::Error;
use crate::cps::lire_carte;
use crate::libssv::{SSV_InitLIB2, SSV_LireConfig};
use ::utils::config::load_config;
use ::utils::config::{load_config, ConfigError};
#[derive(Error, Debug)]
pub enum SSVDemoError {
@ -17,6 +17,8 @@ pub enum SSVDemoError {
CartePSReading(#[from] crate::cps::CartePSError),
#[error(transparent)]
SSVLibErrorCode(#[from] crate::libssv::LibSSVError),
#[error(transparent)]
Configuration(#[from] ConfigError),
}
fn ssv_init_lib_2() -> Result<(), SSVDemoError> {
@ -69,7 +71,7 @@ pub fn demo() -> Result<(), SSVDemoError> {
println!("------- Demo for the SSV library --------");
load_config()?;
load_config(None)?;
ssv_init_lib_2()?;

View File

@ -7,3 +7,4 @@ edition = "2021"
anyhow = "1.0"
directories = "5.0"
dotenv = "0.15"
thiserror = "1.0"

View File

@ -1,11 +1,23 @@
use std::{env, path::PathBuf};
use std::{env, path::PathBuf, sync::atomic::AtomicBool};
use anyhow::{bail, Context, Result};
use directories::ProjectDirs;
use dotenv::from_path;
use thiserror::Error;
const CONFIG_FILE_NAME: &str = ".env";
static CONFIG_INITIALIZED: AtomicBool = AtomicBool::new(false);
#[derive(Debug, Error)]
pub enum ConfigError {
#[error("No config file {0} found in the following directories: {1:#?}")]
ConfigFileNotFound(String, Vec<PathBuf>),
#[error("Failed to load config file: {0}")]
LoadConfigError(#[from] dotenv::Error),
#[error("Environment variable error: {0}")]
EnvVarError(#[from] std::env::VarError),
}
pub fn get_config_dirs() -> Vec<PathBuf> {
let mut config_dirs = vec![
PathBuf::from(""), // Current directory
@ -19,7 +31,7 @@ pub fn get_config_dirs() -> Vec<PathBuf> {
config_dirs
}
pub fn get_config_files() -> Result<Vec<PathBuf>> {
pub fn get_config_files() -> Result<Vec<PathBuf>, ConfigError> {
let config_dirs = get_config_dirs();
let mut config_files = Vec::new();
for config_dir in config_dirs.iter() {
@ -29,14 +41,20 @@ pub fn get_config_files() -> Result<Vec<PathBuf>> {
}
}
if config_files.is_empty() {
bail!(
"No config file {CONFIG_FILE_NAME} found in the following directories: {config_dirs:#?}"
);
return Err(ConfigError::ConfigFileNotFound(
CONFIG_FILE_NAME.to_string(),
config_dirs,
));
}
Ok(config_files)
}
pub fn load_config() -> Result<()> {
pub fn load_config(force: Option<bool>) -> Result<(), ConfigError> {
let force = force.unwrap_or(false);
if CONFIG_INITIALIZED.load(std::sync::atomic::Ordering::Relaxed) && force {
println!("DEBUG: Config already initialized, skipping");
return Ok(());
}
let config_files = get_config_files()?;
// Load the first config file found
// TODO: add a verbose log to list all config files found
@ -44,5 +62,7 @@ pub fn load_config() -> Result<()> {
"DEBUG: Config files found (1st loaded): {:#?}",
config_files
);
from_path(config_files[0].as_path()).context("Failed to load config file")
from_path(config_files[0].as_path()).map_err(ConfigError::LoadConfigError)?;
CONFIG_INITIALIZED.store(true, std::sync::atomic::Ordering::Relaxed);
Ok(())
}