use serde::{Deserialize, Serialize};
#[cfg(feature = "openapi")]
use utoipa::ToSchema;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum CargoBuildStrategy {
Native,
Zigbuild,
Xwin,
}
impl CargoBuildStrategy {
pub fn cargo_subcommand(&self) -> &'static str {
match self {
Self::Native => "build",
Self::Zigbuild => "zigbuild",
Self::Xwin => "xwin",
}
}
pub fn cargo_args(&self) -> Vec<&'static str> {
match self {
Self::Native => vec!["build"],
Self::Zigbuild => vec!["zigbuild"],
Self::Xwin => vec!["xwin", "build"],
}
}
pub fn display_name(&self) -> &'static str {
match self {
Self::Native => "cargo build",
Self::Zigbuild => "cargo zigbuild",
Self::Xwin => "cargo xwin build",
}
}
pub fn install_package(&self) -> Option<&'static str> {
match self {
Self::Native => None,
Self::Zigbuild => Some("cargo-zigbuild"),
Self::Xwin => Some("cargo-xwin"),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[cfg_attr(feature = "openapi", derive(ToSchema))]
#[serde(rename_all = "kebab-case")]
pub enum SourceBinaryType {
Cli,
Terraform,
Agent,
}
impl SourceBinaryType {
pub fn binary_name(&self) -> &'static str {
match self {
SourceBinaryType::Cli => "alien-deploy",
SourceBinaryType::Terraform => "alien-terraform",
SourceBinaryType::Agent => "alien-agent",
}
}
}
impl std::fmt::Display for SourceBinaryType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
SourceBinaryType::Cli => write!(f, "cli"),
SourceBinaryType::Terraform => write!(f, "terraform"),
SourceBinaryType::Agent => write!(f, "agent"),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[cfg_attr(feature = "openapi", derive(ToSchema))]
#[serde(rename_all = "kebab-case")]
pub enum BinaryTarget {
WindowsX64,
LinuxX64,
LinuxArm64,
DarwinArm64,
}
impl BinaryTarget {
pub const ALL: &'static [BinaryTarget] = &[
BinaryTarget::WindowsX64,
BinaryTarget::LinuxX64,
BinaryTarget::LinuxArm64,
BinaryTarget::DarwinArm64,
];
pub const LINUX: &'static [BinaryTarget] = &[BinaryTarget::LinuxX64, BinaryTarget::LinuxArm64];
pub fn rust_target_triple(&self) -> &'static str {
match self {
Self::WindowsX64 => "x86_64-pc-windows-msvc",
Self::LinuxX64 => "x86_64-unknown-linux-musl",
Self::LinuxArm64 => "aarch64-unknown-linux-musl",
Self::DarwinArm64 => "aarch64-apple-darwin",
}
}
pub fn cargo_build_strategy(&self) -> CargoBuildStrategy {
match self {
Self::LinuxX64 | Self::LinuxArm64 => CargoBuildStrategy::Zigbuild,
Self::WindowsX64 => {
if cfg!(target_os = "windows") {
CargoBuildStrategy::Native
} else {
CargoBuildStrategy::Xwin
}
}
Self::DarwinArm64 => CargoBuildStrategy::Native,
}
}
pub fn binary_extension(&self) -> &'static str {
match self {
Self::WindowsX64 => ".exe",
_ => "",
}
}
pub fn runtime_platform_id(&self) -> &'static str {
match self {
Self::WindowsX64 => "windows-x64",
Self::LinuxX64 => "linux-x64",
Self::LinuxArm64 => "linux-aarch64",
Self::DarwinArm64 => "darwin-aarch64",
}
}
pub fn from_runtime_platform_id(id: &str) -> Option<Self> {
match id {
"windows-x64" => Some(Self::WindowsX64),
"linux-x64" => Some(Self::LinuxX64),
"linux-aarch64" => Some(Self::LinuxArm64),
"darwin-aarch64" => Some(Self::DarwinArm64),
_ => None,
}
}
pub fn oci_os(&self) -> &'static str {
match self {
Self::WindowsX64 => "windows",
Self::LinuxX64 | Self::LinuxArm64 => "linux",
Self::DarwinArm64 => "darwin",
}
}
pub fn oci_arch(&self) -> &'static str {
match self {
Self::WindowsX64 | Self::LinuxX64 => "amd64",
Self::LinuxArm64 | Self::DarwinArm64 => "arm64",
}
}
pub fn bun_target(&self) -> &'static str {
match self {
Self::WindowsX64 => "bun-windows-x64",
Self::LinuxX64 => "bun-linux-x64",
Self::LinuxArm64 => "bun-linux-arm64",
Self::DarwinArm64 => "bun-darwin-arm64",
}
}
pub fn terraform_key(&self) -> &'static str {
match self {
BinaryTarget::LinuxX64 => "linux_amd64",
BinaryTarget::LinuxArm64 => "linux_arm64",
BinaryTarget::DarwinArm64 => "darwin_arm64",
BinaryTarget::WindowsX64 => "windows_amd64",
}
}
pub fn terraform_os(&self) -> &'static str {
match self {
BinaryTarget::LinuxX64 | BinaryTarget::LinuxArm64 => "linux",
BinaryTarget::DarwinArm64 => "darwin",
BinaryTarget::WindowsX64 => "windows",
}
}
pub fn terraform_arch(&self) -> &'static str {
match self {
BinaryTarget::LinuxX64 | BinaryTarget::WindowsX64 => "amd64",
BinaryTarget::LinuxArm64 | BinaryTarget::DarwinArm64 => "arm64",
}
}
pub fn is_darwin(&self) -> bool {
matches!(self, Self::DarwinArm64)
}
pub fn is_windows(&self) -> bool {
matches!(self, Self::WindowsX64)
}
pub fn linux_container_target() -> Self {
match Self::current_os() {
Self::DarwinArm64 | Self::LinuxArm64 => Self::LinuxArm64,
Self::LinuxX64 | Self::WindowsX64 => Self::LinuxX64,
}
}
pub fn all() -> Vec<Self> {
Self::ALL.to_vec()
}
pub fn defaults_for_platform(platform: crate::Platform) -> Vec<Self> {
match platform {
crate::Platform::Aws => vec![Self::LinuxArm64],
crate::Platform::Gcp => vec![Self::LinuxX64],
crate::Platform::Azure => vec![Self::LinuxX64],
crate::Platform::Kubernetes => Self::LINUX.to_vec(),
crate::Platform::Local => vec![Self::current_os()],
crate::Platform::Test => vec![Self::LinuxX64],
}
}
pub fn current_os() -> Self {
#[cfg(all(target_os = "windows", target_arch = "x86_64"))]
return Self::WindowsX64;
#[cfg(all(target_os = "linux", target_arch = "x86_64"))]
return Self::LinuxX64;
#[cfg(all(target_os = "linux", target_arch = "aarch64"))]
return Self::LinuxArm64;
#[cfg(all(target_os = "macos", target_arch = "aarch64"))]
return Self::DarwinArm64;
#[cfg(not(any(
all(target_os = "windows", target_arch = "x86_64"),
all(target_os = "linux", target_arch = "x86_64"),
all(target_os = "linux", target_arch = "aarch64"),
all(target_os = "macos", target_arch = "aarch64")
)))]
{
Self::LinuxX64
}
}
}
impl std::fmt::Display for BinaryTarget {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
BinaryTarget::WindowsX64 => write!(f, "windows-x64"),
BinaryTarget::LinuxX64 => write!(f, "linux-x64"),
BinaryTarget::LinuxArm64 => write!(f, "linux-arm64"),
BinaryTarget::DarwinArm64 => write!(f, "darwin-arm64"),
}
}
}
impl std::str::FromStr for BinaryTarget {
type Err = String;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"windows-x64" => Ok(BinaryTarget::WindowsX64),
"linux-x64" => Ok(BinaryTarget::LinuxX64),
"linux-arm64" => Ok(BinaryTarget::LinuxArm64),
"darwin-arm64" => Ok(BinaryTarget::DarwinArm64),
_ => Err(format!("Unknown binary target: {}", s)),
}
}
}
#[cfg(test)]
mod tests {
use super::BinaryTarget;
use crate::Platform;
#[test]
fn local_platform_defaults_to_current_host_target() {
assert_eq!(
BinaryTarget::defaults_for_platform(Platform::Local),
vec![BinaryTarget::current_os()]
);
}
#[test]
fn runtime_platform_id_round_trips() {
for target in BinaryTarget::ALL {
assert_eq!(
BinaryTarget::from_runtime_platform_id(target.runtime_platform_id()),
Some(*target),
"round-trip failed for {target}"
);
}
assert_eq!(
BinaryTarget::from_runtime_platform_id("linux-aarch64"),
Some(BinaryTarget::LinuxArm64)
);
assert_eq!(BinaryTarget::from_runtime_platform_id("linux-arm64"), None);
assert_eq!(BinaryTarget::from_runtime_platform_id("nonsense"), None);
}
#[test]
fn cloud_platform_defaults_remain_stable() {
assert_eq!(
BinaryTarget::defaults_for_platform(Platform::Aws),
vec![BinaryTarget::LinuxArm64]
);
assert_eq!(
BinaryTarget::defaults_for_platform(Platform::Gcp),
vec![BinaryTarget::LinuxX64]
);
assert_eq!(
BinaryTarget::defaults_for_platform(Platform::Azure),
vec![BinaryTarget::LinuxX64]
);
assert_eq!(
BinaryTarget::defaults_for_platform(Platform::Kubernetes),
vec![BinaryTarget::LinuxX64, BinaryTarget::LinuxArm64]
);
}
}