waterui_cli/apple/
toolchain.rs

1//! Apple toolchain module
2
3use std::convert::Infallible;
4
5use serde::{Deserialize, Serialize};
6
7use crate::{
8    toolchain::{Toolchain, ToolchainError},
9    utils::{run_command, which},
10};
11
12/// Represents the complete Apple toolchain consisting of Xcode and an Apple SDK
13pub type AppleToolchain = (Xcode, AppleSdk);
14
15/// Represents the Xcode toolchain
16#[derive(Debug, Clone, Default)]
17pub struct Xcode;
18
19impl Toolchain for Xcode {
20    type Installation = Infallible;
21    async fn check(&self) -> Result<(), crate::toolchain::ToolchainError<Self::Installation>> {
22        // Check if Xcode is installed and available
23        if which("xcodebuild").await.is_ok() && which("xcode-select").await.is_ok() {
24            Ok(())
25        } else {
26            Err(ToolchainError::unfixable(
27                "Xcode is not installed or not found in PATH",
28                "Please install Xcode from the App Store or the Apple Developer website and ensure it's available in your PATH.",
29            ))
30        }
31    }
32}
33
34/// Represents an Apple SDK (e.g., iOS, macOS)
35#[derive(Debug, Deserialize, Serialize, Clone, Copy)]
36pub enum AppleSdk {
37    /// iOS SDK
38    #[serde(rename = "iOS")]
39    Ios,
40    /// macOS SDK
41    #[serde(rename = "macOS")]
42    Macos,
43    /// tvOS SDK
44    #[serde(rename = "tvOS")]
45    TvOs,
46    /// watchOS SDK
47    #[serde(rename = "watchOS")]
48    WatchOs,
49    /// visionOS SDK
50    #[serde(rename = "visionOS")]
51    VisionOs,
52}
53
54impl AppleSdk {
55    /// Get the SDK name as used by `xcrun`
56    #[must_use]
57    pub const fn sdk_name(&self) -> &str {
58        match self {
59            Self::Ios => "iphoneos",
60            Self::Macos => "macosx",
61            Self::TvOs => "appletvos",
62            Self::WatchOs => "watchos",
63            Self::VisionOs => "xros",
64        }
65    }
66}
67
68impl std::fmt::Display for AppleSdk {
69    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
70        serde_json::to_value(self).unwrap().as_str().unwrap().fmt(f)
71    }
72}
73
74impl Toolchain for AppleSdk {
75    type Installation = Infallible;
76    async fn check(&self) -> Result<(), crate::toolchain::ToolchainError<Self::Installation>> {
77        // Check if the required Apple SDK is available
78        let result = run_command("xcrun", ["--sdk", self.sdk_name(), "--show-sdk-path"]).await;
79
80        if result.is_err() {
81            return Err(ToolchainError::unfixable(
82                format!("{self} SDK is not installed or not available"),
83                format!(
84                    "Please install {self} SDK through Xcode or use xcode-select to configure the active developer directory."
85                ),
86            ));
87        }
88
89        Ok(())
90    }
91}