mod action;
mod detect;
mod install;
#[cfg(test)]
mod tests;
use std::path::Path;
use indexmap::IndexMap;
use smol_str::SmolStr;
use super::pkg_config_files::PkgConfigFiles;
pub(crate) use action::PkgShellConfig;
pub use action::{ActionKind, ShellInitAction};
pub use detect::DetectStrategy;
pub(crate) use detect::which_on_path;
#[allow(unused_imports)]
pub use install::BrewHint;
pub use install::InstallHint;
#[derive(serde::Deserialize, schemars::JsonSchema, Debug, Clone, Copy, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub(crate) enum Shell {
Bash,
Zsh,
}
#[derive(serde::Deserialize, schemars::JsonSchema, Debug, Clone, Copy, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub enum Os {
Linux,
Macos,
}
impl Os {
pub fn current() -> Option<Self> {
match std::env::consts::OS {
"linux" => Some(Self::Linux),
"macos" => Some(Self::Macos),
_ => None,
}
}
}
#[derive(serde::Deserialize, schemars::JsonSchema, Debug, Clone, PartialEq, Default)]
#[serde(rename_all = "snake_case")]
pub(crate) enum PkgEnable {
#[default]
On,
Detect,
Disabled,
}
#[derive(serde::Deserialize, schemars::JsonSchema, Debug, Clone, PartialEq, Default)]
pub struct PkgConfig {
#[serde(default)]
pub(super) enable: PkgEnable,
#[serde(default)]
pub(super) detect: Option<DetectStrategy>,
#[serde(default)]
pub(super) inputs: IndexMap<SmolStr, SmolStr>,
#[serde(default)]
pub(super) supported_os: Vec<Os>,
#[serde(default)]
pub(super) supported_shells: Vec<Shell>,
#[serde(default)]
pub name: Option<SmolStr>,
#[serde(default)]
pub description: Option<String>,
pub install_hint: InstallHint,
#[serde(default)]
pub(crate) shell: PkgShellConfig,
#[serde(default)]
pub(super) configs: Vec<PkgConfigFiles>,
}
impl PkgConfig {
pub fn is_installed(&self, home: &Path, system_inputs: &IndexMap<SmolStr, SmolStr>) -> bool {
if !self.supports_current_os() {
return false;
}
match self.enable {
PkgEnable::On | PkgEnable::Detect => {
let Some(detect) = self.detect.as_ref() else {
return true;
};
let lookup = [&self.inputs, system_inputs];
detect.check(home, &lookup)
}
PkgEnable::Disabled => false,
}
}
pub fn enable_on_but_detect_missing(
&self,
home: &Path,
system_inputs: &IndexMap<SmolStr, SmolStr>,
) -> bool {
if !matches!(self.enable, PkgEnable::On) {
return false;
}
if !self.supports_current_os() {
return false;
}
let Some(detect) = self.detect.as_ref() else {
return false;
};
let lookup = [&self.inputs, system_inputs];
!detect.check(home, &lookup)
}
pub fn enable_on_and_detect_matches(
&self,
home: &Path,
system_inputs: &IndexMap<SmolStr, SmolStr>,
) -> bool {
if !matches!(self.enable, PkgEnable::On) {
return false;
}
if !self.supports_current_os() {
return false;
}
let Some(detect) = self.detect.as_ref() else {
return false;
};
let lookup = [&self.inputs, system_inputs];
detect.check(home, &lookup)
}
pub fn is_disabled(&self) -> bool {
matches!(self.enable, PkgEnable::Disabled)
}
pub fn matched_detect(
&self,
home: &Path,
system_inputs: &IndexMap<SmolStr, SmolStr>,
) -> Option<&DetectStrategy> {
if !self.supports_current_os() {
return None;
}
match self.enable {
PkgEnable::On | PkgEnable::Detect => {
let detect = self.detect.as_ref()?;
let lookup = [&self.inputs, system_inputs];
detect.check(home, &lookup).then_some(detect)
}
PkgEnable::Disabled => None,
}
}
pub(crate) fn supports_current_os(&self) -> bool {
self.supported_os.is_empty()
|| Os::current().is_some_and(|os| self.supported_os.contains(&os))
}
pub(crate) fn supports_shell(&self, shell: Option<Shell>) -> bool {
self.supported_shells.is_empty()
|| shell.is_some_and(|s| self.supported_shells.contains(&s))
}
pub(crate) fn inputs(&self) -> &IndexMap<SmolStr, SmolStr> {
&self.inputs
}
pub(super) fn configs(&self) -> &[PkgConfigFiles] {
&self.configs
}
}