#![allow(dead_code)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[non_exhaustive]
pub enum InstallMethod {
Brew,
Cargo,
Nvm,
Pyenv,
Rustup,
Snap,
System,
NotFound,
Unknown,
}
impl InstallMethod {
pub fn as_str(&self) -> &'static str {
match self {
InstallMethod::Brew => "brew",
InstallMethod::Cargo => "cargo",
InstallMethod::Nvm => "nvm",
InstallMethod::Pyenv => "pyenv",
InstallMethod::Rustup => "rustup",
InstallMethod::Snap => "snap",
InstallMethod::System => "system",
InstallMethod::NotFound => "not_found",
InstallMethod::Unknown => "unknown",
}
}
}
impl std::fmt::Display for InstallMethod {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(self.as_str())
}
}
pub fn detect_install_method_for_tool(name: &str) -> InstallMethod {
match which::which(name) {
Ok(path) => detect_install_method_from_path(&path),
Err(_) => InstallMethod::NotFound,
}
}
pub fn detect_install_method_from_path(path: &std::path::Path) -> InstallMethod {
let s = path.to_string_lossy();
if s.contains("/homebrew/") || s.contains("/opt/homebrew/") || s.contains("/Cellar/") {
InstallMethod::Brew
} else if s.contains("/.cargo/") {
InstallMethod::Cargo
} else if s.contains("/.nvm/") {
InstallMethod::Nvm
} else if s.contains("/.pyenv/") {
InstallMethod::Pyenv
} else if s.contains("/.rustup/") {
InstallMethod::Rustup
} else if s.contains("/snap/") {
InstallMethod::Snap
} else if s.contains("/usr/bin/") || s.contains("/usr/local/bin/") {
InstallMethod::System
} else {
InstallMethod::Unknown
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::path::PathBuf;
#[test]
fn classifies_homebrew_apple_silicon_and_intel() {
assert_eq!(
detect_install_method_from_path(&PathBuf::from("/opt/homebrew/bin/jq")),
InstallMethod::Brew
);
assert_eq!(
detect_install_method_from_path(&PathBuf::from("/usr/local/Cellar/jq/1.7.1/bin/jq")),
InstallMethod::Brew
);
}
#[test]
fn classifies_cargo_pyenv_nvm_rustup_snap() {
assert_eq!(
detect_install_method_from_path(&PathBuf::from("/Users/x/.cargo/bin/cargo-watch")),
InstallMethod::Cargo
);
assert_eq!(
detect_install_method_from_path(&PathBuf::from(
"/home/u/.nvm/versions/node/v20/bin/node"
)),
InstallMethod::Nvm
);
assert_eq!(
detect_install_method_from_path(&PathBuf::from("/home/u/.pyenv/shims/python")),
InstallMethod::Pyenv
);
assert_eq!(
detect_install_method_from_path(&PathBuf::from(
"/home/u/.rustup/toolchains/x/bin/rustc"
)),
InstallMethod::Rustup
);
assert_eq!(
detect_install_method_from_path(&PathBuf::from("/snap/bin/code")),
InstallMethod::Snap
);
}
#[test]
fn classifies_system_paths() {
assert_eq!(
detect_install_method_from_path(&PathBuf::from("/usr/bin/git")),
InstallMethod::System
);
assert_eq!(
detect_install_method_from_path(&PathBuf::from("/usr/local/bin/jq")),
InstallMethod::System
);
}
#[test]
fn unknown_paths_classify_as_unknown() {
assert_eq!(
detect_install_method_from_path(&PathBuf::from("/tmp/foo/bar")),
InstallMethod::Unknown
);
}
#[test]
fn display_strings_are_stable() {
assert_eq!(InstallMethod::Brew.to_string(), "brew");
assert_eq!(InstallMethod::Cargo.to_string(), "cargo");
assert_eq!(InstallMethod::Nvm.to_string(), "nvm");
assert_eq!(InstallMethod::Pyenv.to_string(), "pyenv");
assert_eq!(InstallMethod::Rustup.to_string(), "rustup");
assert_eq!(InstallMethod::Snap.to_string(), "snap");
assert_eq!(InstallMethod::System.to_string(), "system");
assert_eq!(InstallMethod::NotFound.to_string(), "not_found");
assert_eq!(InstallMethod::Unknown.to_string(), "unknown");
}
}