From cb64f5b9993eabcf18aa9d19669e0d2ea2d5f641 Mon Sep 17 00:00:00 2001 From: Jonathan VIRGA Date: Fri, 24 Nov 2023 15:11:42 +0100 Subject: [PATCH 1/3] Handle float timestamp. --- Cargo.lock | 2 +- linux-package-analyzer/Cargo.toml | 2 +- rpm-repository/CHANGELOG.md | 4 + rpm-repository/Cargo.toml | 2 +- rpm-repository/src/metadata/repomd.rs | 58 +++++++++- .../src/testdata/with-float-timestamp.xml | 107 ++++++++++++++++++ 6 files changed, 170 insertions(+), 5 deletions(-) create mode 100644 rpm-repository/src/testdata/with-float-timestamp.xml diff --git a/Cargo.lock b/Cargo.lock index 4d1060eb7..32a17deae 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2602,7 +2602,7 @@ checksum = "3582f63211428f83597b51b2ddb88e2a91a9d52d12831f9d08f5e624e8977422" [[package]] name = "rpm-repository" -version = "0.2.0" +version = "0.3.0-dev" dependencies = [ "async-compression", "digest 0.10.7", diff --git a/linux-package-analyzer/Cargo.toml b/linux-package-analyzer/Cargo.toml index ce07e8264..fdc420dd1 100644 --- a/linux-package-analyzer/Cargo.toml +++ b/linux-package-analyzer/Cargo.toml @@ -38,7 +38,7 @@ version = "0.17.0" path = "../debian-packaging" [dependencies.rpm-repository] -version = "0.2.0" +version = "0.3.0-dev" path = "../rpm-repository" # rpm-rs seems to be unmaintained and its old dependencies are holding us back. diff --git a/rpm-repository/CHANGELOG.md b/rpm-repository/CHANGELOG.md index 743e28e4f..76457765e 100644 --- a/rpm-repository/CHANGELOG.md +++ b/rpm-repository/CHANGELOG.md @@ -6,6 +6,10 @@ Released on ReleaseDate. +### Changed + +* Handle float timestamp in `repomd.xml` (but saved rounded `u64` value). + ## 0.2.0 Released on 2023-11-03. diff --git a/rpm-repository/Cargo.toml b/rpm-repository/Cargo.toml index 842f53bea..0f964ce0e 100644 --- a/rpm-repository/Cargo.toml +++ b/rpm-repository/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rpm-repository" -version = "0.2.0" +version = "0.3.0-dev" edition = "2021" authors = ["Gregory Szorc "] license = "MPL-2.0" diff --git a/rpm-repository/src/metadata/repomd.rs b/rpm-repository/src/metadata/repomd.rs index c64398375..956215bc9 100644 --- a/rpm-repository/src/metadata/repomd.rs +++ b/rpm-repository/src/metadata/repomd.rs @@ -10,7 +10,10 @@ use { io::ContentDigest, }, serde::{Deserialize, Serialize}, + serde::{Deserializer, Serializer}, + serde::de::{Error, Visitor}, std::io::Read, + std::fmt::Formatter, }; /// A `repomd.xml` file. @@ -49,7 +52,7 @@ pub struct RepoMdData { /// Size in bytes of the file as stored in the repository. pub size: Option, /// Time file was created/modified. - pub timestamp: Option, + pub timestamp: Option, /// Content checksum of the decoded (often decompressed) file. #[serde(rename = "open-checksum")] pub open_checksum: Option, @@ -93,15 +96,66 @@ pub struct Location { pub href: String, } +struct TimestampVisitor; + +impl<'de> Visitor<'de> for TimestampVisitor { + type Value = u64; + + fn expecting(&self, formatter: &mut Formatter) -> std::fmt::Result { + formatter.write_str("a positive number") + } + + fn visit_u64(self, v: u64) -> std::result::Result where E: Error { + // Keep the same value + Ok(v) + } + + fn visit_f64(self, v: f64) -> std::result::Result where E: Error { + use std::u64; + // Round to the nearest `u64` + if v < u64::MIN as f64 || v > u64::MAX as f64{ + return Err(E::custom(format!("Invalid timestamp: {}", v))) + } + Ok(v.round() as u64) + } +} + +/// Time file was created/modified. +#[derive(Clone, Debug, PartialEq)] +pub struct Timestamp(u64); + +impl Serialize for Timestamp { + fn serialize(&self, serializer: S) -> std::result::Result where S: Serializer { + serializer.serialize_u64(self.0) + } +} + +impl<'de> Deserialize<'de> for Timestamp { + fn deserialize(deserializer: D) -> std::result::Result where D: Deserializer<'de> { + Ok(Self(deserializer.deserialize_f64(TimestampVisitor)?)) + } +} + + #[cfg(test)] mod test { use super::*; const FEDORA_35_REPOMD_XML: &str = include_str!("../testdata/fedora-35-repodata.xml"); + const WITH_FLOAT_TIMESTAMP: &str = include_str!("../testdata/with-float-timestamp.xml"); #[test] fn fedora_35_parse() -> Result<()> { - RepoMd::from_xml(FEDORA_35_REPOMD_XML)?; + let result = RepoMd::from_xml(FEDORA_35_REPOMD_XML)?; + assert_eq!(result.data[0].timestamp, Some(Timestamp(1635225121))); + + Ok(()) + } + + #[test] + fn with_float_timestamp_parse() -> Result<()> { + let result = RepoMd::from_xml(WITH_FLOAT_TIMESTAMP)?; + assert_eq!(result.data[0].timestamp, Some(Timestamp(1635225122))); Ok(()) } diff --git a/rpm-repository/src/testdata/with-float-timestamp.xml b/rpm-repository/src/testdata/with-float-timestamp.xml new file mode 100644 index 000000000..61aeafdce --- /dev/null +++ b/rpm-repository/src/testdata/with-float-timestamp.xml @@ -0,0 +1,107 @@ + + + 1635225124 + + 2311f37b3cdc06f72a535cb394e155c41e683edbeb4adfadc37bbfa090736d20 + 2cc3c948f5b5542ea6472d187d53df13a9598a4ca7323850758cd8ed87bc7767 + + 1635225121.75 + 529838 + 4430568 + + + 1c27df5e0ce2b7d8f4d20301dd0c52774e34ca0b3935b0232c799c0012d92dea + f158c554baf9ad0c4a9119f1342a151e6f1d9e995065ef347c19941ec1f5b1ed + + 1635225121 + 1278036 + 14044647 + + + ccf942ff083cfd01aeac3811774aa7060c9eed55a4796547c1e0f127204a2cb6 + 7beed2d2bd07cbd8b2b3344a7738ab442a6fc154c2c1941ae32bab0b6d057883 + + 1635225121 + 504983 + 4911790 + + + 39d24ea1e128cb95071b36586363230c682584d4ac410330920b9dc2cc291487 + 61d268ba791b40580cbcd1739cd6be75f188ce797abcc085c3e010658d5adab0 + + 1635225122 + 791392 + 4296704 + 10 + + + 6b14ebdbfd00c0765de56f0724fcb5aea9273284382e99442cf2fd3586f0a6e9 + 830fbfc293695e9edebe7b2055d5ca209b076b45e69b45de750316a57bb9ab80 + + 1635225123 + 1216724 + 7237632 + 10 + + + 9e236d3288e09791773e41bd2dfa5933976cca7a95305570bfd975dc5bcc1d3d + bec8e6cf16eec2328b98d8514ae348a395db847ce9a2e164c683cf91911fa5e3 + + 1635225122 + 379168 + 4505600 + 10 + + + 52749b7d111c47548c5a68c5d6daf2449415b1b55be94f9e84fb0f97452a2e09 + 2cc3c948f5b5542ea6472d187d53df13a9598a4ca7323850758cd8ed87bc7767 + 4ea6c649505d487a853c08c76809fd7628cb2b841c97bf9dcad36c9c84635da9 + + 1635225121 + 1059955 + 4430568 + 20571 + + + 69259bbcbef93b2cc7ff36a1d1cfb80fd15c4e62564b7c3904636bd47cd8cfe1 + f158c554baf9ad0c4a9119f1342a151e6f1d9e995065ef347c19941ec1f5b1ed + f7ba84d8d4149caf5e355f44388022cce45f5a25f623d6ef31cebc3be4350b41 + + 1635225121 + 1350659 + 14044647 + 20640 + + + f1ab54978eec08eaa17b9295ea3e4cb13966aa5346ad2f46aa1b75c1af1be92e + 7beed2d2bd07cbd8b2b3344a7738ab442a6fc154c2c1941ae32bab0b6d057883 + 8329ea8316f1590970c89aa0fcfb70d668cb67fde413b8e82dfc6f8b3914d06f + + 1635225121 + 708993 + 4911790 + 20564 + + + 4fcfe2d7ab9cf7375051a27642d473314cb2b8f2d3d98cd09b9561428203a9e3 + + 1635225090 + 106236 + + + 20c70a35954eef42f88e532ba9cda00b65eb78fea9bd2e2e9681ea5e47016276 + + 1635225121 + 23368 + + + 85221f4de87a3a3e1dffd01990821992fffe7059101fdfeca45b78bc2abcb0e3 + 20c70a35954eef42f88e532ba9cda00b65eb78fea9bd2e2e9681ea5e47016276 + 63adce3e9909362a0d33edf8985786c7a700817352da6c30a22d6a215078d088 + + 1635225124 + 29665 + 23368 + 158 + + From cbd40184d531b978445f35a3fb84d16c43f1c09d Mon Sep 17 00:00:00 2001 From: Jonathan VIRGA Date: Wed, 3 Jul 2024 10:25:11 +0200 Subject: [PATCH 2/3] Use float instead of `Timestamp` --- rpm-repository/src/metadata/repomd.rs | 50 ++------------------------- 1 file changed, 3 insertions(+), 47 deletions(-) diff --git a/rpm-repository/src/metadata/repomd.rs b/rpm-repository/src/metadata/repomd.rs index 956215bc9..8846ba9d8 100644 --- a/rpm-repository/src/metadata/repomd.rs +++ b/rpm-repository/src/metadata/repomd.rs @@ -10,10 +10,7 @@ use { io::ContentDigest, }, serde::{Deserialize, Serialize}, - serde::{Deserializer, Serializer}, - serde::de::{Error, Visitor}, std::io::Read, - std::fmt::Formatter, }; /// A `repomd.xml` file. @@ -52,7 +49,7 @@ pub struct RepoMdData { /// Size in bytes of the file as stored in the repository. pub size: Option, /// Time file was created/modified. - pub timestamp: Option, + pub timestamp: Option, /// Content checksum of the decoded (often decompressed) file. #[serde(rename = "open-checksum")] pub open_checksum: Option, @@ -96,47 +93,6 @@ pub struct Location { pub href: String, } -struct TimestampVisitor; - -impl<'de> Visitor<'de> for TimestampVisitor { - type Value = u64; - - fn expecting(&self, formatter: &mut Formatter) -> std::fmt::Result { - formatter.write_str("a positive number") - } - - fn visit_u64(self, v: u64) -> std::result::Result where E: Error { - // Keep the same value - Ok(v) - } - - fn visit_f64(self, v: f64) -> std::result::Result where E: Error { - use std::u64; - // Round to the nearest `u64` - if v < u64::MIN as f64 || v > u64::MAX as f64{ - return Err(E::custom(format!("Invalid timestamp: {}", v))) - } - Ok(v.round() as u64) - } -} - -/// Time file was created/modified. -#[derive(Clone, Debug, PartialEq)] -pub struct Timestamp(u64); - -impl Serialize for Timestamp { - fn serialize(&self, serializer: S) -> std::result::Result where S: Serializer { - serializer.serialize_u64(self.0) - } -} - -impl<'de> Deserialize<'de> for Timestamp { - fn deserialize(deserializer: D) -> std::result::Result where D: Deserializer<'de> { - Ok(Self(deserializer.deserialize_f64(TimestampVisitor)?)) - } -} - - #[cfg(test)] mod test { use super::*; @@ -147,7 +103,7 @@ mod test { #[test] fn fedora_35_parse() -> Result<()> { let result = RepoMd::from_xml(FEDORA_35_REPOMD_XML)?; - assert_eq!(result.data[0].timestamp, Some(Timestamp(1635225121))); + assert_eq!(result.data[0].timestamp, Some(1635225121.)); Ok(()) } @@ -155,7 +111,7 @@ mod test { #[test] fn with_float_timestamp_parse() -> Result<()> { let result = RepoMd::from_xml(WITH_FLOAT_TIMESTAMP)?; - assert_eq!(result.data[0].timestamp, Some(Timestamp(1635225122))); + assert_eq!(result.data[0].timestamp, Some(1635225121.75)); Ok(()) } From e42ae095b615e61daca172872551f4757c9d9c5b Mon Sep 17 00:00:00 2001 From: Jonathan VIRGA Date: Wed, 3 Jul 2024 10:25:40 +0200 Subject: [PATCH 3/3] Comment test that use missing online file. --- rpm-repository/src/http.rs | 56 +++++++++++++++++++------------------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/rpm-repository/src/http.rs b/rpm-repository/src/http.rs index baf88ece6..ff1175687 100644 --- a/rpm-repository/src/http.rs +++ b/rpm-repository/src/http.rs @@ -179,31 +179,31 @@ impl MetadataReader for HttpMetadataClient { } } -#[cfg(test)] -mod test { - use super::*; - - const FEDORA_37_URL: &str = - "https://download-ib01.fedoraproject.org/pub/fedora/linux/releases/37/Server/x86_64/os"; - - #[tokio::test] - async fn fedora_37() -> Result<()> { - let root = HttpRepositoryClient::new(FEDORA_37_URL)?; - - let metadata = root.metadata_reader().await?; - - let primary = metadata.primary_packages().await?; - - let zlib = primary - .packages - .iter() - .find(|entry| entry.name == "zlib") - .unwrap(); - - assert_eq!(zlib.package_type, "rpm"); - // This could change if a new version is released. - assert!(zlib.version.version.starts_with("1.2")); - - Ok(()) - } -} +// #[cfg(test)] +// mod test { +// use super::*; +// +// const FEDORA_37_URL: &str = +// "https://download-ib01.fedoraproject.org/pub/fedora/linux/releases/37/Server/x86_64/os"; +// +// #[tokio::test] +// async fn fedora_37() -> Result<()> { +// let root = HttpRepositoryClient::new(FEDORA_37_URL)?; +// +// let metadata = root.metadata_reader().await?; +// +// let primary = metadata.primary_packages().await?; +// +// let zlib = primary +// .packages +// .iter() +// .find(|entry| entry.name == "zlib") +// .unwrap(); +// +// assert_eq!(zlib.package_type, "rpm"); +// // This could change if a new version is released. +// assert!(zlib.version.version.starts_with("1.2")); +// +// Ok(()) +// } +// }