Skip to content

Add helper for parsing the current macOS version #6072

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Apr 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion talpid-platform-metadata/src/android.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,5 +37,5 @@ pub fn extra_metadata() -> HashMap<String, String> {
}

fn get_prop(property: &str) -> Option<String> {
command_stdout_lossy("getprop", &[property])
command_stdout_lossy("getprop", &[property]).ok()
}
5 changes: 2 additions & 3 deletions talpid-platform-metadata/src/command.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
use std::process::Command;
use std::{io, process::Command};

/// Helper for getting stdout of some command as a String. Ignores the exit code of the command.
pub fn command_stdout_lossy(cmd: &str, args: &[&str]) -> Option<String> {
pub fn command_stdout_lossy(cmd: &str, args: &[&str]) -> io::Result<String> {
Command::new(cmd)
.args(args)
.output()
.map(|output| String::from_utf8_lossy(&output.stdout).trim().to_string())
.ok()
}
2 changes: 2 additions & 0 deletions talpid-platform-metadata/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ mod imp;
#[path = "android.rs"]
mod imp;

#[cfg(target_os = "macos")]
pub use self::imp::MacosVersion;
#[cfg(windows)]
pub use self::imp::WindowsVersion;
pub use self::imp::{extra_metadata, short_version, version};
20 changes: 11 additions & 9 deletions talpid-platform-metadata/src/linux.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,13 +68,15 @@ fn read_os_release_file() -> Result<String, Option<String>> {
}

fn parse_lsb_release() -> Option<String> {
command_stdout_lossy("lsb_release", &["-ds"]).and_then(|output| {
if output.is_empty() {
None
} else {
Some(output)
}
})
command_stdout_lossy("lsb_release", &["-ds"])
.ok()
.and_then(|output| {
if output.is_empty() {
None
} else {
Some(output)
}
})
}

pub fn extra_metadata() -> impl Iterator<Item = (String, String)> {
Expand All @@ -86,7 +88,7 @@ pub fn extra_metadata() -> impl Iterator<Item = (String, String)> {
/// `uname -r` outputs a single line containing only the kernel version:
/// > 5.9.15
fn kernel_version() -> Option<(String, String)> {
let kernel = command_stdout_lossy("uname", &["-r"])?;
let kernel = command_stdout_lossy("uname", &["-r"]).ok()?;
Some(("kernel".to_string(), kernel))
}

Expand All @@ -112,7 +114,7 @@ fn wg_version() -> Option<(String, String)> {
/// > systemd 246 (246)
/// > +PAM +AUDIT -SELINUX +IMA +APPARMOR +SMACK -SYSVINIT +UTMP +LIBCRYPTSETUP +GCRYPT -GNUTLS +ACL
fn systemd_version() -> Option<(String, String)> {
let systemd_version_output = command_stdout_lossy("systemctl", &["--version"])?;
let systemd_version_output = command_stdout_lossy("systemctl", &["--version"]).ok()?;
let version = systemd_version_output.lines().next()?.to_string();
Some(("systemd".to_string(), version))
}
80 changes: 73 additions & 7 deletions talpid-platform-metadata/src/macos.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
mod command;

use command::command_stdout_lossy;
use std::io;

pub fn version() -> String {
let version = run_sw_vers().unwrap_or(String::from("N/A"));
let version = MacosVersion::new()
.map(|version| version.version())
.unwrap_or(String::from("N/A"));
format!("macOS {}", version)
}

pub fn short_version() -> String {
let version = run_sw_vers()
.and_then(parse_short_version_output)
.map(|(major, minor)| format!("{}.{}", major, minor))
let version = MacosVersion::new()
.map(|version| version.short_version())
.unwrap_or(String::from("N/A"));
format!("macOS {}", version)
}
Expand All @@ -18,14 +21,77 @@ pub fn extra_metadata() -> impl Iterator<Item = (String, String)> {
std::iter::empty()
}

#[derive(Debug, PartialEq)]
pub struct MacosVersion {
raw_version: String,
major: u32,
minor: u32,
patch: u32,
}

impl MacosVersion {
pub fn new() -> Result<MacosVersion, io::Error> {
Self::from_raw_version(&run_sw_vers()?)
}

fn from_raw_version(version_string: &str) -> Result<MacosVersion, io::Error> {
let (major, minor, patch) = parse_version_output(version_string).ok_or(io::Error::new(
io::ErrorKind::InvalidInput,
"Failed to parse raw version string",
))?;
Ok(MacosVersion {
raw_version: version_string.to_owned(),
major,
minor,
patch,
})
}

/// Return the current version as a string (e.g. 14.2.1)
pub fn version(&self) -> String {
self.raw_version.clone()
}

/// Return the current version as a string (e.g. 14.2), not including the patch version
pub fn short_version(&self) -> String {
format!("{}.{}", self.major_version(), self.minor_version())
}

pub fn major_version(&self) -> u32 {
self.major
}

pub fn minor_version(&self) -> u32 {
self.minor
}

pub fn patch_version(&self) -> u32 {
self.patch
}
}

/// Outputs a string in a format `$major.$minor.$patch`, e.g. `11.0.1`
fn run_sw_vers() -> Option<String> {
fn run_sw_vers() -> io::Result<String> {
command_stdout_lossy("sw_vers", &["-productVersion"])
}

fn parse_short_version_output(output: String) -> Option<(u32, u32)> {
fn parse_version_output(output: &str) -> Option<(u32, u32, u32)> {
let mut parts = output.split('.');
let major = parts.next()?.parse().ok()?;
let minor = parts.next()?.parse().ok()?;
Some((major, minor))
let patch = parts
.next()
.and_then(|patch| patch.parse().ok())
.unwrap_or(0);
Some((major, minor, patch))
}

#[test]
fn test_version_parsing() {
// % sw_vers --productVersion
// 14.2.1
let version = MacosVersion::from_raw_version("14.2.1").expect("failed to parse version");
assert_eq!(version.major_version(), 14);
assert_eq!(version.minor_version(), 2);
assert_eq!(version.patch_version(), 1);
}
Loading