Skip to main content

cmdhub_cli/
os_detector.rs

1use std::path::Path;
2
3pub fn detect_os() -> Option<String> {
4    if std::env::consts::OS == "macos" {
5        return Some("macos".to_string());
6    }
7    parse_os_release(Path::new("/etc/os-release"))
8}
9
10fn parse_os_release(path: &Path) -> Option<String> {
11    let content = std::fs::read_to_string(path).ok()?;
12    let mut id = None;
13    let mut id_like = None;
14
15    for line in content.lines() {
16        let trimmed = line.trim();
17        if let Some(val) = trimmed.strip_prefix("ID=") {
18            id = Some(strip_quotes(val));
19        } else if let Some(val) = trimmed.strip_prefix("ID_LIKE=") {
20            id_like = Some(strip_quotes(val));
21        }
22    }
23
24    if let Some(ref val) = id {
25        if is_recognized_os(val) {
26            return Some(val.clone());
27        }
28    }
29
30    if let Some(ref val) = id_like {
31        for word in val.split_whitespace() {
32            if is_recognized_os(word) {
33                return Some(word.to_string());
34            }
35        }
36    }
37    id
38}
39
40fn strip_quotes(s: &str) -> String {
41    s.trim_matches(|c| c == '"' || c == '\'').to_string()
42}
43
44fn is_recognized_os(s: &str) -> bool {
45    matches!(
46        s,
47        "macos"
48            | "arch"
49            | "ubuntu"
50            | "debian"
51            | "fedora"
52            | "centos"
53            | "rhel"
54            | "gentoo"
55            | "alpine"
56            | "opensuse"
57            | "nixos"
58    )
59}
60
61#[cfg(test)]
62mod tests {
63    use super::*;
64    use std::io::Write;
65
66    #[test]
67    fn test_os_release_parsing() {
68        let tmp = tempfile::NamedTempFile::new().unwrap();
69        write!(
70            tmp.as_file(),
71            "NAME=\"Ubuntu\"\nID=\"ubuntu\"\nID_LIKE=\"debian\"\n"
72        )
73        .unwrap();
74        assert_eq!(parse_os_release(tmp.path()), Some("ubuntu".to_string()));
75
76        let tmp_mint = tempfile::NamedTempFile::new().unwrap();
77        write!(
78            tmp_mint.as_file(),
79            "NAME=\"Linux Mint\"\nID=linuxmint\nID_LIKE=\"ubuntu debian\"\n"
80        )
81        .unwrap();
82        assert_eq!(
83            parse_os_release(tmp_mint.path()),
84            Some("ubuntu".to_string())
85        );
86    }
87}