use std::{env, path::PathBuf};
use figment::{
Figment, Provider,
providers::{Env, Format, Toml},
util::bool_from_str_or_int,
};
use serde::{Deserialize, Deserializer, Serialize};
use tap::prelude::*;
const CRATE_NAME: &str = clap::crate_name!();
const CONFIG_ITEM_ENV_PREFIX: &str = "PACAPTR_";
const CONFIG_FILE_ENV: &str = "PACAPTR_CONFIG";
#[must_use]
#[derive(Clone, Default, Debug, Serialize, Deserialize)]
#[allow(clippy::struct_excessive_bools)]
pub struct Config {
#[serde(default, deserialize_with = "bool_from_str_or_int")]
pub dry_run: bool,
#[serde(default, deserialize_with = "bool_from_str_or_int")]
pub needed: bool,
#[serde(default, deserialize_with = "bool_from_str_or_int")]
pub no_confirm: bool,
#[serde(default, deserialize_with = "bool_from_str_or_int")]
pub no_cache: bool,
#[serde(default, deserialize_with = "option_bool_from_str_or_int")]
pub quiet: Option<bool>,
pub default_pm: Option<String>,
}
fn option_bool_from_str_or_int<'de, D: Deserializer<'de>>(de: D) -> Result<Option<bool>, D::Error> {
bool_from_str_or_int(de).map(Some)
}
impl Config {
#[must_use]
pub fn quiet(&self) -> bool {
self.quiet
.unwrap_or_else(|| !console::Term::stdout().is_term())
}
pub fn join(&self, other: Self) -> Self {
Self {
dry_run: self.dry_run || other.dry_run,
needed: self.needed || other.dry_run,
no_confirm: self.no_confirm || other.no_confirm,
no_cache: self.no_cache || other.no_cache,
quiet: self.quiet.or(other.quiet),
default_pm: self.default_pm.clone().or(other.default_pm),
}
}
fn default_path() -> Option<PathBuf> {
env::var_os("XDG_CONFIG_HOME")
.map(PathBuf::from)
.filter(|p| p.is_absolute())
.or_else(|| dirs_next::home_dir().map(|p| p.join(".config")))
.tap_some_mut(|p| {
p.extend([CRATE_NAME, &format!("{CRATE_NAME}.toml")]);
})
}
fn custom_path() -> Option<PathBuf> {
env::var_os(CONFIG_FILE_ENV).map(PathBuf::from)
}
#[must_use]
pub fn file_provider() -> impl Provider {
Self::custom_path()
.or_else(Self::default_path)
.map_or_else(Figment::new, |f| Figment::from(Toml::file(f)))
}
#[must_use]
pub fn env_provider() -> impl Provider {
Env::prefixed(CONFIG_ITEM_ENV_PREFIX)
}
}