1use serde::{Deserialize, Serialize};
7#[cfg(feature = "openapi")]
8use utoipa::ToSchema;
9
10#[derive(Debug, Clone, Copy, PartialEq, Eq)]
12pub enum CargoBuildStrategy {
13 Native,
15 Zigbuild,
17 Xwin,
19}
20
21impl CargoBuildStrategy {
22 pub fn cargo_subcommand(&self) -> &'static str {
24 match self {
25 Self::Native => "build",
26 Self::Zigbuild => "zigbuild",
27 Self::Xwin => "xwin",
28 }
29 }
30
31 pub fn cargo_args(&self) -> Vec<&'static str> {
33 match self {
34 Self::Native => vec!["build"],
35 Self::Zigbuild => vec!["zigbuild"],
36 Self::Xwin => vec!["xwin", "build"],
37 }
38 }
39
40 pub fn display_name(&self) -> &'static str {
42 match self {
43 Self::Native => "cargo build",
44 Self::Zigbuild => "cargo zigbuild",
45 Self::Xwin => "cargo xwin build",
46 }
47 }
48
49 pub fn install_package(&self) -> Option<&'static str> {
51 match self {
52 Self::Native => None,
53 Self::Zigbuild => Some("cargo-zigbuild"),
54 Self::Xwin => Some("cargo-xwin"),
55 }
56 }
57}
58
59#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
61#[cfg_attr(feature = "openapi", derive(ToSchema))]
62#[serde(rename_all = "kebab-case")]
63pub enum SourceBinaryType {
64 Cli,
66 Terraform,
68 Agent,
70}
71
72impl SourceBinaryType {
73 pub fn binary_name(&self) -> &'static str {
75 match self {
76 SourceBinaryType::Cli => "alien-deploy",
77 SourceBinaryType::Terraform => "alien-terraform",
78 SourceBinaryType::Agent => "alien-agent",
79 }
80 }
81}
82
83impl std::fmt::Display for SourceBinaryType {
84 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
85 match self {
86 SourceBinaryType::Cli => write!(f, "cli"),
87 SourceBinaryType::Terraform => write!(f, "terraform"),
88 SourceBinaryType::Agent => write!(f, "agent"),
89 }
90 }
91}
92
93#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
98#[cfg_attr(feature = "openapi", derive(ToSchema))]
99#[serde(rename_all = "kebab-case")]
100pub enum BinaryTarget {
101 WindowsX64,
103 LinuxX64,
105 LinuxArm64,
107 DarwinArm64,
109}
110
111impl BinaryTarget {
112 pub const ALL: &'static [BinaryTarget] = &[
114 BinaryTarget::WindowsX64,
115 BinaryTarget::LinuxX64,
116 BinaryTarget::LinuxArm64,
117 BinaryTarget::DarwinArm64,
118 ];
119
120 pub const LINUX: &'static [BinaryTarget] = &[BinaryTarget::LinuxX64, BinaryTarget::LinuxArm64];
122
123 pub fn rust_target_triple(&self) -> &'static str {
125 match self {
126 Self::WindowsX64 => "x86_64-pc-windows-msvc",
127 Self::LinuxX64 => "x86_64-unknown-linux-musl",
128 Self::LinuxArm64 => "aarch64-unknown-linux-musl",
129 Self::DarwinArm64 => "aarch64-apple-darwin",
130 }
131 }
132
133 pub fn cargo_build_strategy(&self) -> CargoBuildStrategy {
140 match self {
141 Self::LinuxX64 | Self::LinuxArm64 => CargoBuildStrategy::Zigbuild,
142 Self::WindowsX64 => {
143 if cfg!(target_os = "windows") {
144 CargoBuildStrategy::Native
145 } else {
146 CargoBuildStrategy::Xwin
147 }
148 }
149 Self::DarwinArm64 => CargoBuildStrategy::Native,
150 }
151 }
152
153 pub fn binary_extension(&self) -> &'static str {
155 match self {
156 Self::WindowsX64 => ".exe",
157 _ => "",
158 }
159 }
160
161 pub fn runtime_platform_id(&self) -> &'static str {
163 match self {
164 Self::WindowsX64 => "windows-x64",
165 Self::LinuxX64 => "linux-x64",
166 Self::LinuxArm64 => "linux-aarch64",
167 Self::DarwinArm64 => "darwin-aarch64",
168 }
169 }
170
171 pub fn from_runtime_platform_id(id: &str) -> Option<Self> {
174 match id {
175 "windows-x64" => Some(Self::WindowsX64),
176 "linux-x64" => Some(Self::LinuxX64),
177 "linux-aarch64" => Some(Self::LinuxArm64),
178 "darwin-aarch64" => Some(Self::DarwinArm64),
179 _ => None,
180 }
181 }
182
183 pub fn oci_os(&self) -> &'static str {
185 match self {
186 Self::WindowsX64 => "windows",
187 Self::LinuxX64 | Self::LinuxArm64 => "linux",
188 Self::DarwinArm64 => "darwin",
189 }
190 }
191
192 pub fn oci_arch(&self) -> &'static str {
194 match self {
195 Self::WindowsX64 | Self::LinuxX64 => "amd64",
196 Self::LinuxArm64 | Self::DarwinArm64 => "arm64",
197 }
198 }
199
200 pub fn bun_target(&self) -> &'static str {
202 match self {
203 Self::WindowsX64 => "bun-windows-x64",
204 Self::LinuxX64 => "bun-linux-x64",
205 Self::LinuxArm64 => "bun-linux-arm64",
206 Self::DarwinArm64 => "bun-darwin-arm64",
207 }
208 }
209
210 pub fn terraform_key(&self) -> &'static str {
212 match self {
213 BinaryTarget::LinuxX64 => "linux_amd64",
214 BinaryTarget::LinuxArm64 => "linux_arm64",
215 BinaryTarget::DarwinArm64 => "darwin_arm64",
216 BinaryTarget::WindowsX64 => "windows_amd64",
217 }
218 }
219
220 pub fn terraform_os(&self) -> &'static str {
222 match self {
223 BinaryTarget::LinuxX64 | BinaryTarget::LinuxArm64 => "linux",
224 BinaryTarget::DarwinArm64 => "darwin",
225 BinaryTarget::WindowsX64 => "windows",
226 }
227 }
228
229 pub fn terraform_arch(&self) -> &'static str {
231 match self {
232 BinaryTarget::LinuxX64 | BinaryTarget::WindowsX64 => "amd64",
233 BinaryTarget::LinuxArm64 | BinaryTarget::DarwinArm64 => "arm64",
234 }
235 }
236
237 pub fn is_darwin(&self) -> bool {
239 matches!(self, Self::DarwinArm64)
240 }
241
242 pub fn is_windows(&self) -> bool {
244 matches!(self, Self::WindowsX64)
245 }
246
247 pub fn linux_container_target() -> Self {
251 match Self::current_os() {
252 Self::DarwinArm64 | Self::LinuxArm64 => Self::LinuxArm64,
253 Self::LinuxX64 | Self::WindowsX64 => Self::LinuxX64,
254 }
255 }
256
257 pub fn all() -> Vec<Self> {
259 Self::ALL.to_vec()
260 }
261
262 pub fn defaults_for_platform(platform: crate::Platform) -> Vec<Self> {
264 match platform {
265 crate::Platform::Aws => vec![Self::LinuxArm64],
266 crate::Platform::Gcp => vec![Self::LinuxX64],
267 crate::Platform::Azure => vec![Self::LinuxX64],
268 crate::Platform::Kubernetes => Self::LINUX.to_vec(),
269 crate::Platform::Local => vec![Self::current_os()],
270 crate::Platform::Test => vec![Self::LinuxX64],
271 }
272 }
273
274 pub fn current_os() -> Self {
276 #[cfg(all(target_os = "windows", target_arch = "x86_64"))]
277 return Self::WindowsX64;
278
279 #[cfg(all(target_os = "linux", target_arch = "x86_64"))]
280 return Self::LinuxX64;
281
282 #[cfg(all(target_os = "linux", target_arch = "aarch64"))]
283 return Self::LinuxArm64;
284
285 #[cfg(all(target_os = "macos", target_arch = "aarch64"))]
286 return Self::DarwinArm64;
287
288 #[cfg(not(any(
289 all(target_os = "windows", target_arch = "x86_64"),
290 all(target_os = "linux", target_arch = "x86_64"),
291 all(target_os = "linux", target_arch = "aarch64"),
292 all(target_os = "macos", target_arch = "aarch64")
293 )))]
294 {
295 Self::LinuxX64
296 }
297 }
298}
299
300impl std::fmt::Display for BinaryTarget {
301 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
302 match self {
303 BinaryTarget::WindowsX64 => write!(f, "windows-x64"),
304 BinaryTarget::LinuxX64 => write!(f, "linux-x64"),
305 BinaryTarget::LinuxArm64 => write!(f, "linux-arm64"),
306 BinaryTarget::DarwinArm64 => write!(f, "darwin-arm64"),
307 }
308 }
309}
310
311impl std::str::FromStr for BinaryTarget {
312 type Err = String;
313
314 fn from_str(s: &str) -> Result<Self, Self::Err> {
315 match s {
316 "windows-x64" => Ok(BinaryTarget::WindowsX64),
317 "linux-x64" => Ok(BinaryTarget::LinuxX64),
318 "linux-arm64" => Ok(BinaryTarget::LinuxArm64),
319 "darwin-arm64" => Ok(BinaryTarget::DarwinArm64),
320 _ => Err(format!("Unknown binary target: {}", s)),
321 }
322 }
323}
324
325#[cfg(test)]
326mod tests {
327 use super::BinaryTarget;
328 use crate::Platform;
329
330 #[test]
331 fn local_platform_defaults_to_current_host_target() {
332 assert_eq!(
333 BinaryTarget::defaults_for_platform(Platform::Local),
334 vec![BinaryTarget::current_os()]
335 );
336 }
337
338 #[test]
339 fn runtime_platform_id_round_trips() {
340 for target in BinaryTarget::ALL {
341 assert_eq!(
342 BinaryTarget::from_runtime_platform_id(target.runtime_platform_id()),
343 Some(*target),
344 "round-trip failed for {target}"
345 );
346 }
347 assert_eq!(
349 BinaryTarget::from_runtime_platform_id("linux-aarch64"),
350 Some(BinaryTarget::LinuxArm64)
351 );
352 assert_eq!(BinaryTarget::from_runtime_platform_id("linux-arm64"), None);
353 assert_eq!(BinaryTarget::from_runtime_platform_id("nonsense"), None);
354 }
355
356 #[test]
357 fn cloud_platform_defaults_remain_stable() {
358 assert_eq!(
359 BinaryTarget::defaults_for_platform(Platform::Aws),
360 vec![BinaryTarget::LinuxArm64]
361 );
362 assert_eq!(
363 BinaryTarget::defaults_for_platform(Platform::Gcp),
364 vec![BinaryTarget::LinuxX64]
365 );
366 assert_eq!(
367 BinaryTarget::defaults_for_platform(Platform::Azure),
368 vec![BinaryTarget::LinuxX64]
369 );
370 assert_eq!(
371 BinaryTarget::defaults_for_platform(Platform::Kubernetes),
372 vec![BinaryTarget::LinuxX64, BinaryTarget::LinuxArm64]
373 );
374 }
375}