2024-09-16 22:49:28 +02:00
|
|
|
use std::{env, path::PathBuf, sync::atomic::AtomicBool};
|
2024-08-22 20:40:12 +02:00
|
|
|
|
|
|
|
use directories::ProjectDirs;
|
|
|
|
use dotenv::from_path;
|
2024-09-16 22:49:28 +02:00
|
|
|
use thiserror::Error;
|
2024-08-22 20:40:12 +02:00
|
|
|
|
|
|
|
const CONFIG_FILE_NAME: &str = ".env";
|
|
|
|
|
2024-09-16 22:49:28 +02:00
|
|
|
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),
|
|
|
|
}
|
|
|
|
|
2024-08-22 20:40:12 +02:00
|
|
|
pub fn get_config_dirs() -> Vec<PathBuf> {
|
|
|
|
let mut config_dirs = vec![
|
|
|
|
PathBuf::from(""), // Current directory
|
|
|
|
];
|
|
|
|
if let Ok(manifest_dir) = env::var("CARGO_MANIFEST_DIR") {
|
|
|
|
config_dirs.push(PathBuf::from(manifest_dir));
|
|
|
|
}
|
|
|
|
if let Some(proj_dirs) = ProjectDirs::from("org", "P4pillon", "Krys4lide") {
|
|
|
|
config_dirs.push(proj_dirs.config_dir().to_path_buf());
|
|
|
|
}
|
|
|
|
config_dirs
|
|
|
|
}
|
|
|
|
|
2024-09-16 22:49:28 +02:00
|
|
|
pub fn get_config_files() -> Result<Vec<PathBuf>, ConfigError> {
|
2024-08-22 20:40:12 +02:00
|
|
|
let config_dirs = get_config_dirs();
|
|
|
|
let mut config_files = Vec::new();
|
|
|
|
for config_dir in config_dirs.iter() {
|
|
|
|
let config_file = config_dir.join(CONFIG_FILE_NAME);
|
|
|
|
if config_file.exists() {
|
|
|
|
config_files.push(config_file);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if config_files.is_empty() {
|
2024-09-16 22:49:28 +02:00
|
|
|
return Err(ConfigError::ConfigFileNotFound(
|
|
|
|
CONFIG_FILE_NAME.to_string(),
|
|
|
|
config_dirs,
|
|
|
|
));
|
2024-08-22 20:40:12 +02:00
|
|
|
}
|
|
|
|
Ok(config_files)
|
|
|
|
}
|
|
|
|
|
2024-09-16 22:49:28 +02:00
|
|
|
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(());
|
|
|
|
}
|
2024-08-22 20:40:12 +02:00
|
|
|
let config_files = get_config_files()?;
|
|
|
|
// Load the first config file found
|
|
|
|
// TODO: add a verbose log to list all config files found
|
|
|
|
println!(
|
|
|
|
"DEBUG: Config files found (1st loaded): {:#?}",
|
|
|
|
config_files
|
|
|
|
);
|
2024-09-16 22:49:28 +02:00
|
|
|
from_path(config_files[0].as_path()).map_err(ConfigError::LoadConfigError)?;
|
|
|
|
CONFIG_INITIALIZED.store(true, std::sync::atomic::Ordering::Relaxed);
|
|
|
|
Ok(())
|
2024-08-22 20:40:12 +02:00
|
|
|
}
|