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
21#[derive(Debug, Clone, Copy, PartialEq, Eq)]
23pub enum BuildHost {
24 LinuxX64,
26 LinuxArm64,
28 WindowsX64,
30 WindowsArm64,
32 DarwinX64,
34 DarwinArm64,
36 Unsupported,
38}
39
40impl BuildHost {
41 pub fn current() -> Self {
43 match (std::env::consts::OS, std::env::consts::ARCH) {
44 ("linux", "x86_64") => Self::LinuxX64,
45 ("linux", "aarch64") => Self::LinuxArm64,
46 ("windows", "x86_64") => Self::WindowsX64,
47 ("windows", "aarch64") => Self::WindowsArm64,
48 ("macos", "x86_64") => Self::DarwinX64,
49 ("macos", "aarch64") => Self::DarwinArm64,
50 _ => Self::Unsupported,
51 }
52 }
53
54 pub fn id(self) -> &'static str {
56 match self {
57 Self::LinuxX64 => "linux-x64",
58 Self::LinuxArm64 => "linux-arm64",
59 Self::WindowsX64 => "windows-x64",
60 Self::WindowsArm64 => "windows-arm64",
61 Self::DarwinX64 => "darwin-x64",
62 Self::DarwinArm64 => "darwin-arm64",
63 Self::Unsupported => "unsupported",
64 }
65 }
66}
67
68impl CargoBuildStrategy {
69 pub fn cargo_subcommand(&self) -> &'static str {
71 match self {
72 Self::Native => "build",
73 Self::Zigbuild => "zigbuild",
74 Self::Xwin => "xwin",
75 }
76 }
77
78 pub fn cargo_args(&self) -> Vec<&'static str> {
80 match self {
81 Self::Native => vec!["build"],
82 Self::Zigbuild => vec!["zigbuild"],
83 Self::Xwin => vec!["xwin", "build"],
84 }
85 }
86
87 pub fn display_name(&self) -> &'static str {
89 match self {
90 Self::Native => "cargo build",
91 Self::Zigbuild => "cargo zigbuild",
92 Self::Xwin => "cargo xwin build",
93 }
94 }
95
96 pub fn install_package(&self) -> Option<&'static str> {
98 match self {
99 Self::Native => None,
100 Self::Zigbuild => Some("cargo-zigbuild"),
101 Self::Xwin => Some("cargo-xwin"),
102 }
103 }
104}
105
106#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
108#[cfg_attr(feature = "openapi", derive(ToSchema))]
109#[serde(rename_all = "kebab-case")]
110pub enum SourceBinaryType {
111 Cli,
113 Terraform,
115 Operator,
117}
118
119impl SourceBinaryType {
120 pub fn binary_name(&self) -> &'static str {
122 match self {
123 SourceBinaryType::Cli => "alien-deploy",
124 SourceBinaryType::Terraform => "alien-terraform",
125 SourceBinaryType::Operator => "alien-operator",
126 }
127 }
128}
129
130impl std::fmt::Display for SourceBinaryType {
131 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
132 match self {
133 SourceBinaryType::Cli => write!(f, "cli"),
134 SourceBinaryType::Terraform => write!(f, "terraform"),
135 SourceBinaryType::Operator => write!(f, "operator"),
136 }
137 }
138}
139
140#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
145#[cfg_attr(feature = "openapi", derive(ToSchema))]
146#[serde(rename_all = "kebab-case")]
147pub enum BinaryTarget {
148 WindowsX64,
150 LinuxX64,
152 LinuxArm64,
154 DarwinArm64,
156}
157
158impl BinaryTarget {
159 pub const ALL: &'static [BinaryTarget] = &[
161 BinaryTarget::WindowsX64,
162 BinaryTarget::LinuxX64,
163 BinaryTarget::LinuxArm64,
164 BinaryTarget::DarwinArm64,
165 ];
166
167 pub const LINUX: &'static [BinaryTarget] = &[BinaryTarget::LinuxX64, BinaryTarget::LinuxArm64];
169
170 pub fn rust_target_triple(&self) -> &'static str {
172 match self {
173 Self::WindowsX64 => "x86_64-pc-windows-msvc",
174 Self::LinuxX64 => "x86_64-unknown-linux-musl",
175 Self::LinuxArm64 => "aarch64-unknown-linux-musl",
176 Self::DarwinArm64 => "aarch64-apple-darwin",
177 }
178 }
179
180 pub fn cargo_build_strategy(&self) -> CargoBuildStrategy {
188 self.cargo_build_strategy_for(BuildHost::current())
189 }
190
191 pub fn cargo_build_strategy_for(&self, host: BuildHost) -> CargoBuildStrategy {
193 match (self, host) {
194 (Self::LinuxX64, BuildHost::LinuxX64)
195 | (Self::LinuxArm64, BuildHost::LinuxArm64)
196 | (Self::WindowsX64, BuildHost::WindowsX64)
197 | (Self::DarwinArm64, BuildHost::DarwinArm64 | BuildHost::DarwinX64) => {
198 CargoBuildStrategy::Native
199 }
200 (Self::WindowsX64, _) => CargoBuildStrategy::Xwin,
201 (Self::LinuxX64 | Self::LinuxArm64, _) => CargoBuildStrategy::Zigbuild,
202 (Self::DarwinArm64, _) => CargoBuildStrategy::Native,
204 }
205 }
206
207 pub fn binary_extension(&self) -> &'static str {
209 match self {
210 Self::WindowsX64 => ".exe",
211 _ => "",
212 }
213 }
214
215 pub fn runtime_platform_id(&self) -> &'static str {
217 match self {
218 Self::WindowsX64 => "windows-x64",
219 Self::LinuxX64 => "linux-x64",
220 Self::LinuxArm64 => "linux-aarch64",
221 Self::DarwinArm64 => "darwin-aarch64",
222 }
223 }
224
225 pub fn from_runtime_platform_id(id: &str) -> Option<Self> {
228 match id {
229 "windows-x64" => Some(Self::WindowsX64),
230 "linux-x64" => Some(Self::LinuxX64),
231 "linux-aarch64" => Some(Self::LinuxArm64),
232 "darwin-aarch64" => Some(Self::DarwinArm64),
233 _ => None,
234 }
235 }
236
237 pub fn oci_os(&self) -> &'static str {
239 match self {
240 Self::WindowsX64 => "windows",
241 Self::LinuxX64 | Self::LinuxArm64 => "linux",
242 Self::DarwinArm64 => "darwin",
243 }
244 }
245
246 pub fn oci_arch(&self) -> &'static str {
248 match self {
249 Self::WindowsX64 | Self::LinuxX64 => "amd64",
250 Self::LinuxArm64 | Self::DarwinArm64 => "arm64",
251 }
252 }
253
254 pub fn bun_target(&self) -> &'static str {
256 match self {
257 Self::WindowsX64 => "bun-windows-x64",
258 Self::LinuxX64 => "bun-linux-x64",
259 Self::LinuxArm64 => "bun-linux-arm64",
260 Self::DarwinArm64 => "bun-darwin-arm64",
261 }
262 }
263
264 pub fn terraform_key(&self) -> &'static str {
266 match self {
267 BinaryTarget::LinuxX64 => "linux_amd64",
268 BinaryTarget::LinuxArm64 => "linux_arm64",
269 BinaryTarget::DarwinArm64 => "darwin_arm64",
270 BinaryTarget::WindowsX64 => "windows_amd64",
271 }
272 }
273
274 pub fn terraform_os(&self) -> &'static str {
276 match self {
277 BinaryTarget::LinuxX64 | BinaryTarget::LinuxArm64 => "linux",
278 BinaryTarget::DarwinArm64 => "darwin",
279 BinaryTarget::WindowsX64 => "windows",
280 }
281 }
282
283 pub fn terraform_arch(&self) -> &'static str {
285 match self {
286 BinaryTarget::LinuxX64 | BinaryTarget::WindowsX64 => "amd64",
287 BinaryTarget::LinuxArm64 | BinaryTarget::DarwinArm64 => "arm64",
288 }
289 }
290
291 pub fn is_darwin(&self) -> bool {
293 matches!(self, Self::DarwinArm64)
294 }
295
296 pub fn is_windows(&self) -> bool {
298 matches!(self, Self::WindowsX64)
299 }
300
301 pub fn linux_container_target() -> Self {
305 match Self::current_os() {
306 Self::DarwinArm64 | Self::LinuxArm64 => Self::LinuxArm64,
307 Self::LinuxX64 | Self::WindowsX64 => Self::LinuxX64,
308 }
309 }
310
311 pub fn all() -> Vec<Self> {
313 Self::ALL.to_vec()
314 }
315
316 pub fn defaults_for_platform(platform: crate::Platform) -> Vec<Self> {
318 match platform {
319 crate::Platform::Aws => vec![Self::LinuxArm64],
320 crate::Platform::Gcp => vec![Self::LinuxX64],
321 crate::Platform::Azure => vec![Self::LinuxX64],
322 crate::Platform::Kubernetes => Self::LINUX.to_vec(),
323 crate::Platform::Machines => Self::LINUX.to_vec(),
324 crate::Platform::Local => vec![Self::current_os()],
325 crate::Platform::Test => vec![Self::LinuxX64],
326 }
327 }
328
329 pub fn current_os() -> Self {
331 match BuildHost::current() {
332 BuildHost::WindowsX64 => Self::WindowsX64,
333 BuildHost::LinuxX64 => Self::LinuxX64,
334 BuildHost::LinuxArm64 => Self::LinuxArm64,
335 BuildHost::DarwinArm64 => Self::DarwinArm64,
336 host => panic!("unsupported Alien host: {}", host.id()),
337 }
338 }
339}
340
341impl std::fmt::Display for BinaryTarget {
342 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
343 match self {
344 BinaryTarget::WindowsX64 => write!(f, "windows-x64"),
345 BinaryTarget::LinuxX64 => write!(f, "linux-x64"),
346 BinaryTarget::LinuxArm64 => write!(f, "linux-arm64"),
347 BinaryTarget::DarwinArm64 => write!(f, "darwin-arm64"),
348 }
349 }
350}
351
352impl std::str::FromStr for BinaryTarget {
353 type Err = String;
354
355 fn from_str(s: &str) -> Result<Self, Self::Err> {
356 match s {
357 "windows-x64" => Ok(BinaryTarget::WindowsX64),
358 "linux-x64" => Ok(BinaryTarget::LinuxX64),
359 "linux-arm64" => Ok(BinaryTarget::LinuxArm64),
360 "darwin-arm64" => Ok(BinaryTarget::DarwinArm64),
361 _ => Err(format!("Unknown binary target: {}", s)),
362 }
363 }
364}
365
366#[cfg(test)]
367mod tests {
368 use super::{BinaryTarget, BuildHost, CargoBuildStrategy};
369 use crate::Platform;
370
371 #[test]
372 fn local_platform_defaults_to_current_host_target() {
373 assert_eq!(
374 BinaryTarget::defaults_for_platform(Platform::Local),
375 vec![BinaryTarget::current_os()]
376 );
377 }
378
379 #[test]
380 fn runtime_platform_id_round_trips() {
381 for target in BinaryTarget::ALL {
382 assert_eq!(
383 BinaryTarget::from_runtime_platform_id(target.runtime_platform_id()),
384 Some(*target),
385 "round-trip failed for {target}"
386 );
387 }
388 assert_eq!(
390 BinaryTarget::from_runtime_platform_id("linux-aarch64"),
391 Some(BinaryTarget::LinuxArm64)
392 );
393 assert_eq!(BinaryTarget::from_runtime_platform_id("linux-arm64"), None);
394 assert_eq!(BinaryTarget::from_runtime_platform_id("nonsense"), None);
395 }
396
397 #[test]
398 fn cloud_platform_defaults_remain_stable() {
399 assert_eq!(
400 BinaryTarget::defaults_for_platform(Platform::Aws),
401 vec![BinaryTarget::LinuxArm64]
402 );
403 assert_eq!(
404 BinaryTarget::defaults_for_platform(Platform::Gcp),
405 vec![BinaryTarget::LinuxX64]
406 );
407 assert_eq!(
408 BinaryTarget::defaults_for_platform(Platform::Azure),
409 vec![BinaryTarget::LinuxX64]
410 );
411 assert_eq!(
412 BinaryTarget::defaults_for_platform(Platform::Kubernetes),
413 vec![BinaryTarget::LinuxX64, BinaryTarget::LinuxArm64]
414 );
415 }
416
417 #[test]
418 fn cargo_build_strategy_uses_native_tools_only_on_compatible_hosts() {
419 assert_eq!(
420 BinaryTarget::LinuxX64.cargo_build_strategy_for(BuildHost::LinuxX64),
421 CargoBuildStrategy::Native
422 );
423 assert_eq!(
424 BinaryTarget::LinuxArm64.cargo_build_strategy_for(BuildHost::LinuxArm64),
425 CargoBuildStrategy::Native
426 );
427 assert_eq!(
428 BinaryTarget::LinuxArm64.cargo_build_strategy_for(BuildHost::LinuxX64),
429 CargoBuildStrategy::Zigbuild
430 );
431 assert_eq!(
432 BinaryTarget::WindowsX64.cargo_build_strategy_for(BuildHost::WindowsX64),
433 CargoBuildStrategy::Native
434 );
435 assert_eq!(
436 BinaryTarget::WindowsX64.cargo_build_strategy_for(BuildHost::DarwinArm64),
437 CargoBuildStrategy::Xwin
438 );
439 assert_eq!(
440 BinaryTarget::DarwinArm64.cargo_build_strategy_for(BuildHost::DarwinX64),
441 CargoBuildStrategy::Native
442 );
443 }
444}