From e8ba04aab70186c48adf78f0f88eeaeea25989ea Mon Sep 17 00:00:00 2001 From: Julian Stecklina Date: Wed, 22 Nov 2023 19:20:38 +0100 Subject: [PATCH 1/2] tool: extend SystemdVersion with patch level --- rust/tool/systemd/src/version.rs | 47 ++++++++++++++++++++++++++------ 1 file changed, 39 insertions(+), 8 deletions(-) diff --git a/rust/tool/systemd/src/version.rs b/rust/tool/systemd/src/version.rs index 0a088f8..e773ab4 100644 --- a/rust/tool/systemd/src/version.rs +++ b/rust/tool/systemd/src/version.rs @@ -10,10 +10,20 @@ use lanzaboote_tool::pe; /// A systemd version. /// -/// The version is parsed into a u32 tuple because systemd does not follow strict semver -/// conventions. A major version without a minor version, e.g. "252" is represented as `(252, 0)`. +/// systemd does not follow semver standards, but we try to map it anyway. Version components that are not there are treated as zero. +/// +/// A notible quirk here is our handling of release candidate +/// versions. We treat 255-rc2 as 255.-1.2, which should give us the +/// correct ordering. #[derive(PartialEq, PartialOrd, Eq, Debug)] -pub struct SystemdVersion(u32, u32); +pub struct SystemdVersion { + major: u32, + + /// This is a signed integer, so we can model "rc" versions as -1 here. + minor: i32, + + patch: u32, +} impl SystemdVersion { /// Read the systemd version from the `.osrel` section of a systemd-boot binary. @@ -55,10 +65,31 @@ impl FromStr for SystemdVersion { let major = split_version .first() + .copied() .context("Failed to parse major version.")?; - let minor = split_version.get(1).unwrap_or(&0); + let minor = split_version + .get(1) + .copied() + .unwrap_or(0) + .try_into() + .unwrap(); - Ok(Self(major.to_owned(), minor.to_owned())) + Ok(Self { + major, + minor, + patch: 0, + }) + } +} + +#[cfg(test)] +impl From<(u32, i32, u32)> for SystemdVersion { + fn from(value: (u32, i32, u32)) -> Self { + SystemdVersion { + major: value.0, + minor: value.1, + patch: value.2, + } } } @@ -68,9 +99,9 @@ mod tests { #[test] fn parse_version_correctly() { - assert_eq!(parse_version("253"), SystemdVersion(253, 0)); - assert_eq!(parse_version("252.4"), SystemdVersion(252, 4)); - assert_eq!(parse_version("251.11"), SystemdVersion(251, 11)); + assert_eq!(parse_version("253"), (253, 0, 0).into()); + assert_eq!(parse_version("252.4"), (252, 4, 0).into()); + assert_eq!(parse_version("251.11"), (251, 11, 0).into()); } #[test] From dd18daae09eef95695e31546ed91713273434384 Mon Sep 17 00:00:00 2001 From: Julian Stecklina Date: Wed, 22 Nov 2023 19:41:56 +0100 Subject: [PATCH 2/2] tool: parse systemd rc versions --- rust/tool/systemd/src/version.rs | 49 ++++++++++++++++---------------- 1 file changed, 25 insertions(+), 24 deletions(-) diff --git a/rust/tool/systemd/src/version.rs b/rust/tool/systemd/src/version.rs index e773ab4..60c29a8 100644 --- a/rust/tool/systemd/src/version.rs +++ b/rust/tool/systemd/src/version.rs @@ -56,29 +56,28 @@ impl FromStr for SystemdVersion { type Err = anyhow::Error; fn from_str(s: &str) -> Result { - let split_version = s - .split('.') - .take(2) - .map(u32::from_str) - .collect::, std::num::ParseIntError>>() - .context("Failed to parse version string into u32 vector.")?; - - let major = split_version - .first() - .copied() - .context("Failed to parse major version.")?; - let minor = split_version - .get(1) - .copied() - .unwrap_or(0) - .try_into() - .unwrap(); - - Ok(Self { - major, - minor, - patch: 0, - }) + if let Some((major_str, rc_str)) = s.split_once("-rc") { + // A version that looks like: 253-rc2 + Ok(Self { + major: major_str.parse()?, + minor: -1, + patch: rc_str.parse()?, + }) + } else if let Some((major_str, minor_str)) = s.split_once('.') { + // A version that looks like: 253.7 + Ok(Self { + major: major_str.parse()?, + minor: minor_str.parse()?, + patch: 0, + }) + } else { + // A version that looks like: 253 + Ok(Self { + major: s.parse()?, + minor: 0, + patch: 0, + }) + } } } @@ -102,6 +101,7 @@ mod tests { assert_eq!(parse_version("253"), (253, 0, 0).into()); assert_eq!(parse_version("252.4"), (252, 4, 0).into()); assert_eq!(parse_version("251.11"), (251, 11, 0).into()); + assert_eq!(parse_version("251-rc7"), (251, -1, 7).into()); } #[test] @@ -109,6 +109,8 @@ mod tests { assert!(parse_version("253") > parse_version("252")); assert!(parse_version("253") > parse_version("252.4")); assert!(parse_version("251.8") == parse_version("251.8")); + assert!(parse_version("251-rc5") > parse_version("251-rc4")); + assert!(parse_version("251") > parse_version("251-rc9")); } #[test] @@ -116,7 +118,6 @@ mod tests { parse_version_error(""); parse_version_error("213;k;13"); parse_version_error("-1.3.123"); - parse_version_error("253-rc1"); } fn parse_version(input: &str) -> SystemdVersion {