-
Notifications
You must be signed in to change notification settings - Fork 53
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Support for other distros with release files and added Alpine Linux (#48
) * added file support for alpine * committing to merge with master * finalizing alpine and fedora file support * fixing trailing newline character one file versions * general cleanup * simplifying * moving version trim to file_release->retrieve() * triming version for distros with no regex * Further simplifying. Also, added unit tests and doc comments * correct spelling * removing mod.rs.bk * Fixing format errors and removing .bk file * removing semi-colon from return statement * removing the last problematic semi-colon * fixing clippy errors * fixing clippy error * another clippy error
- Loading branch information
1 parent
a4ba18c
commit c82f1ac
Showing
10 changed files
with
284 additions
and
135 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,265 @@ | ||
use regex::Regex; | ||
|
||
use std::fs::{File, metadata}; | ||
use std::io::{Error, ErrorKind}; | ||
use std::io::prelude::*; | ||
|
||
use Type; | ||
|
||
/// `ReleaseFile` Structure | ||
/// Holds information about a distro specific release file. | ||
/// Information can include the type of distro, a human readable | ||
/// name for the distro, the distro version, the path to the | ||
/// release file (i.e: /etc/centos-release), a distro regex | ||
/// which will parse the name of the distro from the release | ||
/// file and a version regex which will parse the version | ||
/// from the release file. | ||
#[derive(Debug)] | ||
pub struct ReleaseFile { | ||
pub(crate) os_type: Type, | ||
pub distro: Option<String>, | ||
pub version: Option<String>, | ||
name: String, | ||
path: String, | ||
regex_distro: String, | ||
regex_version: String, | ||
} | ||
|
||
/// `ReleaseFile` Structure Default Values | ||
/// Sets all default values for a `ReleaseFile` | ||
/// structure. | ||
impl Default for ReleaseFile { | ||
fn default() -> Self { | ||
Self { | ||
os_type: Type::Unknown, | ||
distro: None, | ||
version: None, | ||
name: "".to_string(), | ||
path: "".to_string(), | ||
regex_distro: "".to_string(), | ||
regex_version: "".to_string(), | ||
} | ||
} | ||
} | ||
|
||
/// `ReleaseFile` Implementation | ||
/// Helper functions for a `ReleaseFile` structure | ||
impl ReleaseFile { | ||
/// ReleaseFile.exists() | ||
/// Does a release file exist? | ||
fn exists(&self) -> bool { | ||
let metadata = metadata(&self.path); | ||
|
||
match metadata { | ||
Ok(md) => md.is_dir() || md.is_file(), | ||
Err(_) => false, | ||
} | ||
} | ||
/// ReleaseFile.read() | ||
/// Get data inside of a release file. | ||
fn read(&self) -> Result<String, Error> { | ||
if self.exists() { | ||
let mut file = File::open(&self.path)?; | ||
let mut contents = String::new(); | ||
file.read_to_string(&mut contents)?; | ||
Ok(contents) | ||
} else { | ||
Err(Error::new(ErrorKind::NotFound, "File does not exist!")) | ||
} | ||
} | ||
/// ReleaseFile.parse() | ||
/// Parse the distrobution name and version information | ||
/// from a release file. | ||
fn parse(self) -> Result<Self, Error> { | ||
match self.read() { | ||
Ok(data) => { | ||
let distro = if !self.regex_distro.is_empty() { | ||
let distrib_regex = Regex::new(&self.regex_distro).unwrap(); | ||
match distrib_regex.captures_iter(&data).next() { | ||
Some(m) => { | ||
match m.get(1) { | ||
Some(distro) => Some(distro.as_str().to_owned()), | ||
None => None, | ||
} | ||
} | ||
None => None, | ||
} | ||
} else { | ||
Some(self.name.clone()) | ||
}; | ||
let version = if !self.regex_version.is_empty() { | ||
let version_regex = Regex::new(&self.regex_version).unwrap(); | ||
match version_regex.captures_iter(&data).next() { | ||
Some(m) => { | ||
match m.get(1) { | ||
Some(version) => Some(version.as_str().trim_right().to_owned()), | ||
None => None, | ||
} | ||
} | ||
None => None, | ||
} | ||
} else { | ||
Some(data.trim_right().to_string()) | ||
}; | ||
Ok(ReleaseFile { | ||
distro: distro, | ||
version: version, | ||
..self | ||
}) | ||
} | ||
Err(e) => Err(e), | ||
} | ||
} | ||
} | ||
|
||
/// distributions() | ||
/// Returns a vector of instantiated `ReleaseFile` | ||
/// structures. This vector contains all supported | ||
/// distributions and how to parse their version | ||
/// information from their release file. | ||
pub fn distributions() -> Vec<ReleaseFile> { | ||
vec![ | ||
ReleaseFile { | ||
os_type: Type::Centos, | ||
name: "CentOS".to_string(), | ||
path: "/etc/centos-release".to_string(), | ||
regex_distro: r"(\w+) Linux release".to_string(), | ||
regex_version: r"release\s([\w\.]+)".to_string(), | ||
..Default::default() | ||
}, | ||
ReleaseFile { | ||
os_type: Type::Fedora, | ||
name: "Fedora".to_string(), | ||
path: "/etc/fedora-release".to_string(), | ||
regex_distro: r"(\w+) release".to_string(), | ||
regex_version: r"release\s([\w\.]+)".to_string(), | ||
..Default::default() | ||
}, | ||
ReleaseFile { | ||
os_type: Type::Redhat, | ||
name: "Redhat".to_string(), | ||
path: "/etc/redhat-release".to_string(), | ||
regex_distro: r"(\w+) Linux release".to_string(), | ||
regex_version: r"release\s([\w\.]+)".to_string(), | ||
..Default::default() | ||
}, | ||
ReleaseFile { | ||
os_type: Type::Alpine, | ||
name: "Alpine".to_string(), | ||
path: "/etc/alpine-release".to_string(), | ||
..Default::default() | ||
}, | ||
] | ||
} | ||
|
||
/// retrieve() | ||
/// Parses the a vector of `ReleaseFile` structures. | ||
/// If the release file in `ReleaseFile`.path exists, | ||
/// the information will be parsed and returned. | ||
pub fn retrieve(distros: Vec<ReleaseFile>) -> Option<ReleaseFile> { | ||
let it = distros.into_iter(); | ||
for distro in it { | ||
match distro.parse() { | ||
Ok(release) => return Some(release), | ||
Err(_) => continue, | ||
} | ||
} | ||
|
||
None | ||
} | ||
|
||
#[cfg(test)] | ||
mod tests { | ||
use super::*; | ||
use std::path::PathBuf; | ||
|
||
#[test] | ||
pub fn test_file_centos() { | ||
let mut file = PathBuf::from(env!("CARGO_MANIFEST_DIR")); | ||
file.push("src/linux/tests/centos-release"); | ||
|
||
let distros: Vec<ReleaseFile> = vec![ | ||
ReleaseFile { | ||
os_type: Type::Centos, | ||
name: "CentOS".to_string(), | ||
path: file.into_os_string().into_string().unwrap(), | ||
regex_distro: r"(\w+) Linux release".to_string(), | ||
regex_version: r"release\s([\w\.]+)".to_string(), | ||
..Default::default() | ||
}, | ||
]; | ||
|
||
let result = retrieve(distros).unwrap(); | ||
assert_eq!(result.os_type, Type::Centos); | ||
assert_eq!(result.distro, Some("Centos".to_string())); | ||
assert_eq!(result.version, Some("XX".to_string())); | ||
assert_eq!(result.name, "CentOS".to_string()); | ||
} | ||
|
||
#[test] | ||
pub fn test_file_fedora() { | ||
let mut file = PathBuf::from(env!("CARGO_MANIFEST_DIR")); | ||
file.push("src/linux/tests/fedora-release"); | ||
|
||
let distros: Vec<ReleaseFile> = vec![ | ||
ReleaseFile { | ||
os_type: Type::Fedora, | ||
name: "Fedora".to_string(), | ||
path: file.into_os_string().into_string().unwrap(), | ||
regex_distro: r"(\w+) release".to_string(), | ||
regex_version: r"release\s([\w\.]+)".to_string(), | ||
..Default::default() | ||
}, | ||
]; | ||
|
||
let result = retrieve(distros).unwrap(); | ||
assert_eq!(result.os_type, Type::Fedora); | ||
assert_eq!(result.distro, Some("Fedora".to_string())); | ||
assert_eq!(result.version, Some("26".to_string())); | ||
assert_eq!(result.name, "Fedora".to_string()); | ||
} | ||
|
||
#[test] | ||
pub fn test_file_redhat() { | ||
let mut file = PathBuf::from(env!("CARGO_MANIFEST_DIR")); | ||
file.push("src/linux/tests/redhat-release"); | ||
|
||
let distros: Vec<ReleaseFile> = vec![ | ||
ReleaseFile { | ||
os_type: Type::Redhat, | ||
name: "Redhat".to_string(), | ||
path: file.into_os_string().into_string().unwrap(), | ||
regex_distro: r"(\w+) Linux release".to_string(), | ||
regex_version: r"release\s([\w\.]+)".to_string(), | ||
..Default::default() | ||
}, | ||
]; | ||
|
||
let result = retrieve(distros).unwrap(); | ||
assert_eq!(result.os_type, Type::Redhat); | ||
assert_eq!(result.distro, Some("Redhat".to_string())); | ||
assert_eq!(result.version, Some("XX".to_string())); | ||
assert_eq!(result.name, "Redhat".to_string()); | ||
} | ||
|
||
#[test] | ||
pub fn test_file_alpine() { | ||
let mut file = PathBuf::from(env!("CARGO_MANIFEST_DIR")); | ||
file.push("src/linux/tests/alpine-release"); | ||
|
||
let distros: Vec<ReleaseFile> = vec![ | ||
ReleaseFile { | ||
os_type: Type::Alpine, | ||
name: "Alpine".to_string(), | ||
path: file.into_os_string().into_string().unwrap(), | ||
..Default::default() | ||
}, | ||
]; | ||
|
||
let result = retrieve(distros).unwrap(); | ||
assert_eq!(result.os_type, Type::Alpine); | ||
assert_eq!(result.distro, Some("Alpine".to_string())); | ||
assert_eq!(result.version, Some("A.B.C".to_string())); | ||
assert_eq!(result.name, "Alpine".to_string()); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,4 @@ | ||
use regex::Regex; | ||
|
||
use std::process::Command; | ||
|
||
use {Info, Type, Version}; | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,20 +1,24 @@ | ||
mod lsb_release; | ||
mod rhel_release; | ||
mod utils; | ||
mod file_release; | ||
|
||
use {Info, Type, Version}; | ||
|
||
pub fn current_platform() -> Info { | ||
if lsb_release::is_available() { | ||
lsb_release::lsb_release() | ||
} else if utils::file_exists("/etc/redhat-release") || | ||
utils::file_exists("/etc/centos-release") | ||
{ | ||
rhel_release::rhel_release() | ||
} else { | ||
Info { | ||
os_type: Type::Linux, | ||
version: Version::unknown(), | ||
match file_release::retrieve(file_release::distributions()) { | ||
Some(release) => Info { | ||
os_type: release.os_type, | ||
version: release | ||
.version | ||
.map(|x| Version::custom(x, None)) | ||
.unwrap_or_else(Version::unknown), | ||
}, | ||
None => Info { | ||
os_type: Type::Linux, | ||
version: Version::unknown(), | ||
}, | ||
} | ||
} | ||
} |
Oops, something went wrong.