use super::error::KResult;
use ahash::AHashSet;
use camino::Utf8PathBuf;
use eyre::WrapErr;
use globset::Glob;
use globset::GlobSet;
use parking_lot::Mutex;
use rune::ContextError;
use rune::Module;
use std::str::FromStr;
const DEFAULT_EARLY: &[&str] = &["/etc/passwd", "/etc/group", "/etc/shadow", "/etc/gshadow"];
const DEFAUT_SENSITIVE: &[&str] = &[
"/etc/shadow",
"/etc/shadow-",
"/etc/gshadow",
"/etc/gshadow-",
];
#[derive(Debug, rune::Any)]
#[rune(item = ::settings)]
pub struct Settings {
file_backend: Mutex<Option<paketkoll_types::backend::Backend>>,
enabled_pkg_backends: Mutex<AHashSet<paketkoll_types::backend::Backend>>,
early_configs: Mutex<AHashSet<Utf8PathBuf>>,
sensitive_configs: Mutex<AHashSet<Utf8PathBuf>>,
diff: Mutex<Vec<String>>,
pager: Mutex<Vec<String>>,
save_prefix: Mutex<String>,
}
impl Default for Settings {
fn default() -> Self {
Self {
file_backend: Mutex::new(None),
enabled_pkg_backends: Mutex::new(AHashSet::new()),
early_configs: Mutex::new(AHashSet::from_iter(DEFAULT_EARLY.iter().map(Into::into))),
sensitive_configs: Mutex::new(AHashSet::from_iter(
DEFAUT_SENSITIVE.iter().map(Into::into),
)),
diff: Mutex::new(vec!["diff".into(), "-Naur".into()]),
pager: Mutex::new(vec![]),
save_prefix: Mutex::new(String::new()),
}
}
}
impl Settings {
pub fn is_file_backend_enabled(&self, backend: paketkoll_types::backend::Backend) -> bool {
let guard = self.file_backend.lock();
*guard == Some(backend)
}
pub fn is_pkg_backend_enabled(&self, backend: paketkoll_types::backend::Backend) -> bool {
let guard = self.enabled_pkg_backends.lock();
guard.contains(&backend)
}
pub fn file_backend(&self) -> Option<paketkoll_types::backend::Backend> {
let guard = self.file_backend.lock();
*guard
}
pub fn enabled_pkg_backends(
&self,
) -> impl Iterator<Item = paketkoll_types::backend::Backend> + use<> {
let guard = self.enabled_pkg_backends.lock();
let v: Vec<_> = guard.iter().copied().collect();
v.into_iter()
}
pub fn early_configs(&self) -> eyre::Result<GlobSet> {
let guard = self.early_configs.lock();
let mut builder = GlobSet::builder();
for p in guard.iter() {
builder.add(Glob::new(p.as_str()).context(
"Failed to parse one or more early configuration path as a regular expressions",
)?);
}
builder
.build()
.wrap_err("Failed to build globset for early configs")
}
pub fn sensitive_configs(&self) -> eyre::Result<GlobSet> {
let guard = self.sensitive_configs.lock();
let mut builder = GlobSet::builder();
for p in guard.iter() {
builder.add(Glob::new(p.as_str()).context(
"Failed to parse one or more sensitive configuration path as a regular expressions",
)?);
}
builder
.build()
.wrap_err("Failed to build globset for sensitive configs")
}
pub fn diff(&self) -> Vec<String> {
let guard = self.diff.lock();
guard.clone()
}
pub fn pager(&self) -> Vec<String> {
let guard = self.pager.lock();
if !guard.is_empty() {
guard.clone()
} else {
vec![std::env::var("PAGER").ok().unwrap_or_else(|| "less".into())]
}
}
pub fn save_prefix(&self) -> String {
let guard = self.save_prefix.lock();
guard.clone()
}
}
impl Settings {
#[rune::function]
pub fn set_file_backend(&self, name: &str) -> KResult<()> {
let backend = paketkoll_types::backend::Backend::from_str(name)
.wrap_err_with(|| format!("Unknown backend {name}"))?;
let mut guard = self.file_backend.lock();
if guard.is_some() {
tracing::warn!("File backend was set more than once");
}
*guard = Some(backend);
Ok(())
}
#[rune::function]
pub fn enable_pkg_backend(&self, name: &str) -> KResult<()> {
let backend = paketkoll_types::backend::Backend::from_str(name)
.wrap_err_with(|| format!("Unknown backend {name}"))?;
let before = self.enabled_pkg_backends.lock().insert(backend);
if !before {
tracing::warn!("Package backend {name} was enabled more than once");
}
Ok(())
}
#[rune::function]
pub fn early_config(&self, path: &str) {
let before = self.early_configs.lock().insert(path.into());
if !before {
tracing::warn!("Early config {path} was added more than once");
}
}
#[rune::function]
pub fn sensitive_config(&self, path: &str) {
let before = self.sensitive_configs.lock().insert(path.into());
if !before {
tracing::warn!("Sensitive config {path} was added more than once");
}
}
#[rune::function]
pub fn set_diff(&self, cmd: Vec<String>) {
let mut guard = self.diff.lock();
*guard = cmd;
}
#[rune::function]
pub fn set_pager(&self, cmd: Vec<String>) {
let mut guard = self.pager.lock();
*guard = cmd;
}
#[rune::function]
pub fn set_save_prefix(&self, prefix: &str) {
let mut guard = self.save_prefix.lock();
*guard = prefix.into();
}
}
#[rune::module(::settings)]
pub(crate) fn module() -> Result<Module, ContextError> {
let mut m = Module::from_meta(module_meta)?;
m.ty::<Settings>()?;
m.function_meta(Settings::set_file_backend)?;
m.function_meta(Settings::enable_pkg_backend)?;
m.function_meta(Settings::early_config)?;
m.function_meta(Settings::sensitive_config)?;
m.function_meta(Settings::set_diff)?;
m.function_meta(Settings::set_pager)?;
m.function_meta(Settings::set_save_prefix)?;
Ok(m)
}