Skip to main content

mj_controller/targets/
platform.rs

1use super::*;
2
3#[derive(Debug, Clone, Copy, PartialEq, Eq)]
4pub enum TargetOs {
5    Linux,
6    Darwin,
7}
8
9/// Platform of the execution boundary, which may differ from both the
10/// controller and the host of a Linux container.
11#[derive(Debug, Clone, Copy, PartialEq, Eq)]
12pub struct TargetPlatform {
13    pub os: TargetOs,
14    pub architecture: &'static str,
15}
16
17impl TargetPlatform {
18    pub fn parse(uname: &str) -> Result<Self> {
19        let mut fields = uname.split_whitespace();
20        let os = match fields.next() {
21            Some("Linux") => TargetOs::Linux,
22            Some("Darwin") => TargetOs::Darwin,
23            other => bail!("unsupported target operating system {other:?}"),
24        };
25        let architecture = normalize_architecture(fields.next().unwrap_or_default())?;
26        ensure!(
27            fields.next().is_none(),
28            "invalid target platform response {uname:?}"
29        );
30        Ok(Self { os, architecture })
31    }
32}
33
34pub fn normalize_architecture(architecture: &str) -> Result<&'static str> {
35    match architecture {
36        "x86_64" | "amd64" => Ok("x86_64"),
37        "aarch64" | "arm64" => Ok("aarch64"),
38        other => bail!("unsupported target architecture {other:?}"),
39    }
40}
41
42pub fn platform_probe(locator: &TargetLocator) -> CommandSpec {
43    locator_command(locator, vec!["uname".into(), "-sm".into()]).purpose("detect target platform")
44}
45
46#[cfg(test)]
47mod tests {
48    use super::*;
49
50    #[test]
51    fn detects_supported_platforms_and_rejects_unknown_responses() {
52        for (text, os, architecture) in [
53            ("Darwin arm64\n", TargetOs::Darwin, "aarch64"),
54            ("Darwin x86_64\n", TargetOs::Darwin, "x86_64"),
55            ("Linux aarch64\n", TargetOs::Linux, "aarch64"),
56            ("Linux x86_64\n", TargetOs::Linux, "x86_64"),
57        ] {
58            assert_eq!(
59                TargetPlatform::parse(text).unwrap(),
60                TargetPlatform { os, architecture }
61            );
62        }
63        for text in [
64            "FreeBSD arm64",
65            "Linux riscv64",
66            "Darwin",
67            "",
68            "Linux x86_64 junk",
69        ] {
70            assert!(TargetPlatform::parse(text).is_err(), "{text}");
71        }
72    }
73}