use std::env;
use crate::domain::errors::{AgentError, AgentResult, ErrorCode};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) struct Platform {
pub os: OperatingSystem,
pub arch: Architecture,
pub libc: Libc,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) enum OperatingSystem {
Linux,
MacOs,
Windows,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) enum Architecture {
X86_64,
Aarch64,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) enum Libc {
Glibc,
Musl,
NotApplicable,
}
impl Platform {
pub(crate) fn detect() -> AgentResult<Self> {
Self::from_parts(env::consts::OS, env::consts::ARCH, detected_linux_libc())
}
pub(crate) fn from_parts(os: &str, arch: &str, libc: Option<&str>) -> AgentResult<Self> {
let os = match os.to_ascii_lowercase().as_str() {
"linux" => OperatingSystem::Linux,
"macos" | "darwin" => OperatingSystem::MacOs,
"windows" => OperatingSystem::Windows,
_ => return Err(platform_error("unsupported operating system")),
};
let arch = match arch.to_ascii_lowercase().as_str() {
"x86_64" | "amd64" | "x64" => Architecture::X86_64,
"aarch64" | "arm64" => Architecture::Aarch64,
_ => return Err(platform_error("unsupported architecture")),
};
let libc = if os == OperatingSystem::Linux {
match libc.map(str::to_ascii_lowercase).as_deref() {
Some("glibc" | "gnu") => Libc::Glibc,
Some("musl") => Libc::Musl,
_ => return Err(platform_error("unsupported Linux libc")),
}
} else {
Libc::NotApplicable
};
Ok(Self { os, arch, libc })
}
pub(crate) fn supports_managed_install(self) -> bool {
matches!(
(self.os, self.arch, self.libc),
(OperatingSystem::Linux, Architecture::X86_64, Libc::Glibc)
| (OperatingSystem::Linux, Architecture::Aarch64, Libc::Glibc)
| (
OperatingSystem::MacOs,
Architecture::X86_64,
Libc::NotApplicable
)
| (
OperatingSystem::MacOs,
Architecture::Aarch64,
Libc::NotApplicable
)
)
}
}
fn detected_linux_libc() -> Option<&'static str> {
if env::consts::OS != "linux" {
return None;
}
if cfg!(target_env = "musl") {
Some("musl")
} else if cfg!(target_env = "gnu") {
Some("glibc")
} else {
None
}
}
fn platform_error(message: &'static str) -> AgentError {
AgentError::new(ErrorCode::InvalidMessage, message)
}