1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
use regex::Regex;
use std::fs::File;
use std::io::prelude::*;
use std::io::Error;
use utils;
#[derive(Debug, PartialEq)]
pub struct OSRelease {
pub distro: Option<String>,
pub version: Option<String>,
}
fn read_file(filename: &str) -> Result<String, Error> {
let mut file = File::open(filename)?;
let mut contents = String::new();
file.read_to_string(&mut contents)?;
Ok(contents)
}
pub fn retrieve() -> Option<OSRelease> {
if utils::file_exists("/etc/os-release") {
if let Ok(release) = read_file("/etc/os-release") {
Some(parse(release))
} else {
None
}
} else {
if let Ok(release) = read_file("/usr/lib/os-release") {
Some(parse(release))
} else {
None
}
}
}
pub fn parse(file: String) -> OSRelease {
let distrib_regex = Regex::new(r#"NAME="(\w+)"#).unwrap();
let version_regex = Regex::new(r#"VERSION_ID="?([\w\.]+)"#).unwrap();
let distro = match distrib_regex.captures_iter(&file).next() {
Some(m) => match m.get(1) {
Some(distro) => Some(distro.as_str().to_owned()),
None => None,
},
None => None,
};
let version = match version_regex.captures_iter(&file).next() {
Some(m) => match m.get(1) {
Some(version) => Some(version.as_str().to_owned()),
None => None,
},
None => None,
};
OSRelease { distro, version }
}
mod tests {
use super::*;
#[test]
fn parse_ubuntu_18_04_os_release() {
let sample = "\
NAME=\"Ubuntu\"\
VERSION=\"18.04 LTS (Bionic Beaver)\"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME=\"Ubuntu 18.04 LTS\"\
VERSION_ID=\"18.04\"\
HOME_URL=\"https://www.ubuntu.com/\"\
SUPPORT_URL=\"https://help.ubuntu.com/\"\
BUG_REPORT_URL=\"https://bugs.launchpad.net/ubuntu\"\
PRIVACY_POLICY_URL=\"https://www.ubuntu.com/legal/terms-and-policies/privacy-policy\"\
VERSION_CODENAME=bionic
UBUNTU_CODENAME=bionic
".to_string();
assert_eq!(
parse(sample),
OSRelease {
distro: Some("Ubuntu".to_string()),
version: Some("18.04".to_string()),
}
);
}
#[test]
fn parse_alpine_3_9_5_os_release() {
let sample = "\
NAME=\"Alpine Linux\"
ID=alpine
VERSION_ID=3.9.5
PRETTY_NAME=\"Alpine Linux v3.9\"
HOME_URL=\"https://alpinelinux.org/\"
BUG_REPORT_URL=\"https://bugs.alpinelinux.org/\"
".to_string();
assert_eq!(
parse(sample),
OSRelease {
distro: Some("Alpine".to_string()),
version: Some("3.9.5".to_string()),
}
);
}
#[test]
fn parse_deepin_20_3_os_release() {
let sample = "\
PRETTY_NAME=\"Deepin 20.3\"
NAME=\"Deepin\"
VERSION_ID=\"20.3\"
VERSION=\"20.3\"
ID=Deepin
HOME_URL=\"https://www.deepin.org/\"
".to_string();
assert_eq!(
parse(sample),
OSRelease {
distro: Some("Deepin".to_string()),
version: Some("20.3".to_string()),
}
);
}
}