Skip to main content

cli/sys/
detect.rs

1use anyhow::{Result, bail};
2
3/// Detect the current OS identifier using `std::env::consts::OS` and, on Linux,
4/// the `ID=` field from `/etc/os-release`.
5pub async fn detect_os_id() -> Result<String> {
6    let os_release = tokio::fs::read_to_string("/etc/os-release").await.ok();
7    detect_os_id_from(std::env::consts::OS, os_release.as_deref())
8}
9
10fn detect_os_id_from(os: &str, os_release: Option<&str>) -> Result<String> {
11    match os {
12        "macos" => Ok("macos".to_string()),
13        "windows" => Ok("windows".to_string()),
14        "linux" => {
15            if let Some(content) = os_release {
16                for line in content.lines() {
17                    if let Some(id) = line.strip_prefix("ID=") {
18                        return Ok(id.trim_matches('"').to_lowercase());
19                    }
20                }
21            }
22            bail!(
23                "Could not detect Linux distribution. \
24                 Expected ID= in /etc/os-release. Supported: ubuntu"
25            )
26        }
27        other => bail!(
28            "Unsupported platform '{}'. Supported targets: ubuntu (Linux), macos, windows",
29            other
30        ),
31    }
32}
33
34#[cfg(test)]
35mod tests {
36    use super::*;
37
38    #[test]
39    fn detects_macos() {
40        let result = detect_os_id_from("macos", None).unwrap();
41        assert_eq!(result, "macos");
42    }
43
44    #[test]
45    fn detects_windows() {
46        let result = detect_os_id_from("windows", None).unwrap();
47        assert_eq!(result, "windows");
48    }
49
50    #[test]
51    fn detects_ubuntu_from_os_release() {
52        let os_release = "PRETTY_NAME=\"Ubuntu 22.04\"\nID=ubuntu\nVERSION_ID=\"22.04\"\n";
53        let result = detect_os_id_from("linux", Some(os_release)).unwrap();
54        assert_eq!(result, "ubuntu");
55    }
56
57    #[test]
58    fn detects_quoted_id() {
59        let os_release = "ID=\"ubuntu\"\n";
60        let result = detect_os_id_from("linux", Some(os_release)).unwrap();
61        assert_eq!(result, "ubuntu");
62    }
63
64    #[test]
65    fn lowercases_id() {
66        let os_release = "ID=Debian\n";
67        let result = detect_os_id_from("linux", Some(os_release)).unwrap();
68        assert_eq!(result, "debian");
69    }
70
71    #[test]
72    fn errors_on_linux_without_os_release() {
73        let err = detect_os_id_from("linux", None).unwrap_err();
74        assert!(err.to_string().contains("os-release"));
75    }
76
77    #[test]
78    fn errors_on_unsupported_platform() {
79        let err = detect_os_id_from("freebsd", None).unwrap_err();
80        assert!(err.to_string().contains("freebsd"));
81    }
82}