use std::{fs, path::PathBuf};
use serde::Deserialize;
use thiserror::Error;
#[derive(Clone, Debug, Deserialize)]
pub struct Config {
pub database_url: String,
}
#[derive(Debug, Error)]
pub enum ConfigError {
#[error("failed to read config file: {0}")]
Read(#[source] std::io::Error),
#[error("failed to parse config: {0}")]
Parse(#[source] toml::de::Error),
#[error("no database URL provided; use --db or create {}", config_path().map(|p| p.display().to_string()).unwrap_or_else(|| "config file".to_string()))]
NoDatabaseUrl,
}
pub fn config_path() -> Option<PathBuf> {
dirs::config_dir().map(|p| p.join("postmodern").join("config.toml"))
}
pub fn load_config() -> Result<Option<Config>, ConfigError> {
let Some(path) = config_path() else {
return Ok(None);
};
if !path.exists() {
return Ok(None);
}
let contents = fs::read_to_string(&path).map_err(ConfigError::Read)?;
let config: Config = toml::from_str(&contents).map_err(ConfigError::Parse)?;
Ok(Some(config))
}
pub fn resolve_database_url(override_url: Option<String>) -> Result<String, ConfigError> {
if let Some(db) = override_url {
return Ok(db);
}
if let Some(config) = load_config()? {
return Ok(config.database_url);
}
Err(ConfigError::NoDatabaseUrl)
}