use colored::Colorize;
use std::path::Path;
use regex::Regex;
#[derive(Debug)]
pub enum OSErrors {
NoSuchFile,
FailedToRead,
RegexError,
}
pub const OS_RELEASE_PATHS: [&str; 3] = ["/bedrock/etc/os-release", "/etc/os-release", "/usr/lib/os-release"];
impl std::fmt::Display for OSErrors {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let error_msg = match self {
OSErrors::NoSuchFile => "Couldn't find os-release",
OSErrors::FailedToRead => "Failed to read os-release",
OSErrors::RegexError => "Regex failed"
};
write!(f, "{}: {:?}", "OS Info Err".bold().red(), error_msg)
}
}
impl std::error::Error for OSErrors {}
pub fn get_os() -> Result<String, OSErrors> {
let os_release = match find_os_release() {
Ok(os) => os,
Err(_) => return Err(OSErrors::NoSuchFile),
};
match read_id_os_release(&os_release) {
Ok(os_value) => Ok(os_value),
Err(_) => return Err(OSErrors::FailedToRead),
}
}
pub fn get_os_version() -> Result<String, OSErrors> {
let os_release_path = match find_os_release() {
Ok(path) => path,
Err(_) => return Err(OSErrors::NoSuchFile),
};
let content = match std::fs::read_to_string(os_release_path) {
Ok(os_content) => os_content,
Err(_) => return Err(OSErrors::FailedToRead),
};
let reg = Regex::new(r#"(?m)^VERSION_ID=(?:(?:"(.*?)")|(?:(.*)))$"#)
.map_err(|_| OSErrors::RegexError)?;
let captures = reg.captures(&content).ok_or(OSErrors::RegexError)?;
captures
.get(2)
.or(captures.get(1))
.map(|m| m.as_str().to_string()).ok_or(OSErrors::FailedToRead)
}
pub fn find_os_release() -> Result<String, OSErrors> {
for os_release in OS_RELEASE_PATHS {
if Path::new(os_release).exists() {
return Ok(os_release.to_string())
}
}
Err(OSErrors::NoSuchFile)
}
fn read_id_os_release(path: &str) -> Result<String, OSErrors> {
let content = match std::fs::read_to_string(path) {
Ok(os_content) => os_content,
Err(_) => return Err(OSErrors::FailedToRead),
};
let re = Regex::new(r#"(?m)^ID=(?:(?:"(.*?)")|(?:(.*)))$"#).map_err(|_| OSErrors::RegexError)?;
let captures = re.captures(&content).ok_or(OSErrors::RegexError)?;
captures
.get(2)
.or(captures.get(1))
.map(|m| m.as_str().to_string()).ok_or(OSErrors::RegexError)
}