#[derive(Debug, Clone, PartialEq, Eq)]
pub enum InstallMethod {
Source(std::path::PathBuf),
CargoInstall,
PrebuiltBinary,
}
impl InstallMethod {
pub fn detect() -> Self {
let exe = match std::env::current_exe() {
Ok(p) => p,
Err(_) => return Self::PrebuiltBinary,
};
if let Some(project_root) = find_cargo_project(&exe) {
return Self::Source(project_root);
}
if is_in_cargo_bin(&exe) {
return Self::CargoInstall;
}
Self::PrebuiltBinary
}
pub fn description(&self) -> &'static str {
match self {
Self::Source(_) => "source build",
Self::CargoInstall => "cargo install",
Self::PrebuiltBinary => "pre-built binary",
}
}
}
fn find_cargo_project(exe: &std::path::Path) -> Option<std::path::PathBuf> {
let mut dir = exe.parent()?.to_path_buf();
loop {
if dir.join("Cargo.toml").exists() {
return Some(dir);
}
if !dir.pop() {
return None;
}
}
}
fn is_in_cargo_bin(exe: &std::path::Path) -> bool {
let cargo_bin = cargo_bin_dir();
match cargo_bin {
Some(dir) => exe.parent().map(|p| p == dir).unwrap_or(false),
None => false,
}
}
fn cargo_bin_dir() -> Option<std::path::PathBuf> {
if let Ok(cargo_home) = std::env::var("CARGO_HOME") {
return Some(std::path::PathBuf::from(cargo_home).join("bin"));
}
dirs::home_dir().map(|h| h.join(".cargo").join("bin"))
}
pub fn platform_suffix() -> Option<&'static str> {
match (std::env::consts::OS, std::env::consts::ARCH) {
("macos", "aarch64") => Some("macos-arm64"),
("macos", "x86_64") => Some("macos-amd64"),
("linux", "x86_64") => Some("linux-amd64"),
("linux", "aarch64") => Some("linux-arm64"),
("windows", "x86_64") => Some("windows-amd64"),
_ => None,
}
}
pub fn binary_name() -> &'static str {
if std::env::consts::OS == "windows" {
"opencrabs.exe"
} else {
"opencrabs"
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn detect_returns_some_variant() {
let method = InstallMethod::detect();
let _ = method.description();
}
#[test]
fn source_description() {
let m = InstallMethod::Source(std::path::PathBuf::from("/tmp"));
assert_eq!(m.description(), "source build");
}
#[test]
fn cargo_install_description() {
assert_eq!(InstallMethod::CargoInstall.description(), "cargo install");
}
#[test]
fn prebuilt_description() {
assert_eq!(
InstallMethod::PrebuiltBinary.description(),
"pre-built binary"
);
}
#[test]
fn platform_suffix_is_some_on_supported() {
if matches!(
(std::env::consts::OS, std::env::consts::ARCH),
("macos", "aarch64")
| ("macos", "x86_64")
| ("linux", "x86_64")
| ("linux", "aarch64")
| ("windows", "x86_64")
) {
assert!(platform_suffix().is_some());
}
}
#[test]
fn binary_name_matches_platform() {
let name = binary_name();
if std::env::consts::OS == "windows" {
assert_eq!(name, "opencrabs.exe");
} else {
assert_eq!(name, "opencrabs");
}
}
}