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