use std::convert::Infallible;
use serde::{Deserialize, Serialize};
use crate::{
toolchain::{Toolchain, ToolchainError},
utils::{run_command, which},
};
pub type AppleToolchain = (Xcode, AppleSdk);
#[derive(Debug, Clone, Default)]
pub struct Xcode;
impl Toolchain for Xcode {
type Installation = Infallible;
async fn check(&self) -> Result<(), crate::toolchain::ToolchainError<Self::Installation>> {
if which("xcodebuild").await.is_ok() && which("xcode-select").await.is_ok() {
Ok(())
} else {
Err(ToolchainError::unfixable(
"Xcode is not installed or not found in PATH",
"Please install Xcode from the App Store or the Apple Developer website and ensure it's available in your PATH.",
))
}
}
}
#[derive(Debug, Deserialize, Serialize, Clone, Copy)]
pub enum AppleSdk {
#[serde(rename = "iOS")]
Ios,
#[serde(rename = "macOS")]
Macos,
#[serde(rename = "tvOS")]
TvOs,
#[serde(rename = "watchOS")]
WatchOs,
#[serde(rename = "visionOS")]
VisionOs,
}
impl AppleSdk {
#[must_use]
pub const fn sdk_name(&self) -> &str {
match self {
Self::Ios => "iphoneos",
Self::Macos => "macosx",
Self::TvOs => "appletvos",
Self::WatchOs => "watchos",
Self::VisionOs => "xros",
}
}
}
impl std::fmt::Display for AppleSdk {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
serde_json::to_value(self).unwrap().as_str().unwrap().fmt(f)
}
}
impl Toolchain for AppleSdk {
type Installation = Infallible;
async fn check(&self) -> Result<(), crate::toolchain::ToolchainError<Self::Installation>> {
let result = run_command("xcrun", ["--sdk", self.sdk_name(), "--show-sdk-path"]).await;
if result.is_err() {
return Err(ToolchainError::unfixable(
format!("{self} SDK is not installed or not available"),
format!(
"Please install {self} SDK through Xcode or use xcode-select to configure the active developer directory."
),
));
}
Ok(())
}
}