From 099fa52ade10d70d4c8929eccd00ca0cbfff06d9 Mon Sep 17 00:00:00 2001 From: Bela Stoyan Date: Sun, 2 Jul 2023 13:38:12 +0200 Subject: [PATCH 1/8] add hash spec --- .../rattler_conda_types/src/match_spec/mod.rs | 98 ++++++++++++++++--- .../src/match_spec/parse.rs | 48 +++++++++ 2 files changed, 130 insertions(+), 16 deletions(-) diff --git a/crates/rattler_conda_types/src/match_spec/mod.rs b/crates/rattler_conda_types/src/match_spec/mod.rs index acdc3b84e..564c72ca1 100644 --- a/crates/rattler_conda_types/src/match_spec/mod.rs +++ b/crates/rattler_conda_types/src/match_spec/mod.rs @@ -1,6 +1,7 @@ use crate::{PackageRecord, VersionSpec}; +use rattler_digest::{serde::SerializableHash, Md5Hash, Sha256Hash}; use serde::Serialize; -use serde_with::skip_serializing_none; +use serde_with::{serde_as, skip_serializing_none}; use std::fmt::{Debug, Display, Formatter}; pub mod matcher; @@ -109,6 +110,7 @@ use matcher::StringMatcher; /// /// Alternatively, an exact spec is given by `*[sha256=01ba4719c80b6fe911b091a7c05124b64eeece964e09c058ef8f9805daca546b]`. #[skip_serializing_none] +#[serde_as] #[derive(Debug, Default, Clone, Serialize, Eq, PartialEq)] pub struct MatchSpec { /// The name of the package @@ -127,6 +129,12 @@ pub struct MatchSpec { pub subdir: Option, /// The namespace of the package (currently not used) pub namespace: Option, + /// The md5 hash of the package + #[serde_as(as = "Option>")] + pub md5: Option, + /// The sha256 hash of the package + #[serde_as(as = "Option>")] + pub sha256: Option, } impl Display for MatchSpec { @@ -146,19 +154,26 @@ impl Display for MatchSpec { write!(f, "::")?; } - match &self.name { - Some(name) => write!(f, "{name}")?, - None => write!(f, "*")?, + if let Some(name) = &self.name { + write!(f, "{}", name)?; + } else { + write!(f, "*")?; } - match &self.version { - Some(version) => write!(f, " {version}")?, - None => (), + if let Some(version) = &self.version { + write!(f, " {}", version)?; } - match &self.build { - Some(build) => write!(f, " {build}")?, - None => (), + if let Some(build) = &self.build { + write!(f, " {}", build)?; + } + + if let Some(md5) = &self.md5 { + write!(f, " md5={md5:x}")?; + } + + if let Some(sha256) = &self.sha256 { + write!(f, " sha256={sha256:x}")?; } Ok(()) @@ -186,12 +201,29 @@ impl MatchSpec { } } + if let Some(md5_spec) = self.md5.as_ref() { + if let Some(md5_record) = record.md5.as_ref() { + if md5_spec != md5_record { + return false; + } + } + } + + if let Some(sha256_spec) = self.sha256.as_ref() { + if let Some(sha256_record) = record.sha256.as_ref() { + if sha256_spec != sha256_record { + return false; + } + } + } + true } } /// Similar to a [`MatchSpec`] but does not include the package name. This is useful in places /// where the package name is already known (e.g. `foo = "3.4.1 *cuda"`) +#[serde_as] #[skip_serializing_none] #[derive(Debug, Default, Clone, Serialize, Eq, PartialEq)] pub struct NamelessMatchSpec { @@ -209,6 +241,12 @@ pub struct NamelessMatchSpec { pub subdir: Option, /// The namespace of the package (currently not used) pub namespace: Option, + /// The md5 hash of the package + #[serde_as(as = "Option>")] + pub md5: Option, + /// The sha256 hash of the package + #[serde_as(as = "Option>")] + pub sha256: Option, } impl NamelessMatchSpec { @@ -226,20 +264,44 @@ impl NamelessMatchSpec { } } + if let Some(md5_spec) = self.md5.as_ref() { + if let Some(md5_record) = record.md5.as_ref() { + if md5_spec != md5_record { + return false; + } + } + } + + if let Some(sha256_spec) = self.sha256.as_ref() { + if let Some(sha256_record) = record.sha256.as_ref() { + if sha256_spec != sha256_record { + return false; + } + } + } + true } } impl Display for NamelessMatchSpec { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - match &self.version { - Some(version) => write!(f, "{version}")?, - None => write!(f, "*")?, + if let Some(version) = self.version.as_ref() { + write!(f, "{version}")?; + } else { + write!(f, "*")?; + } + + if let Some(build) = &self.build { + write!(f, " {}", build)?; + } + + if let Some(md5) = &self.md5 { + write!(f, " md5={md5:x}")?; } - match &self.build { - Some(build) => write!(f, " {build}")?, - None => (), + if let Some(sha256) = &self.sha256 { + write!(f, " sha256={sha256:x}")?; } // TODO: Add any additional properties as bracket arguments (e.g. `[channel=..]`) @@ -258,6 +320,8 @@ impl From for NamelessMatchSpec { channel: spec.channel, subdir: spec.subdir, namespace: spec.namespace, + md5: spec.md5, + sha256: spec.sha256, } } } @@ -274,6 +338,8 @@ impl MatchSpec { channel: spec.channel, subdir: spec.subdir, namespace: spec.namespace, + md5: spec.md5, + sha256: spec.sha256, } } } diff --git a/crates/rattler_conda_types/src/match_spec/parse.rs b/crates/rattler_conda_types/src/match_spec/parse.rs index 1d5644f7a..a7a0f11c6 100644 --- a/crates/rattler_conda_types/src/match_spec/parse.rs +++ b/crates/rattler_conda_types/src/match_spec/parse.rs @@ -12,6 +12,7 @@ use nom::error::{context, ContextError, ParseError}; use nom::multi::{separated_list0, separated_list1}; use nom::sequence::{delimited, preceded, separated_pair, terminated}; use nom::{Finish, IResult}; +use rattler_digest::{parse_digest_from_hex, Md5, Sha256}; use smallvec::SmallVec; use std::borrow::Cow; use std::num::ParseIntError; @@ -54,6 +55,9 @@ pub enum ParseMatchSpecError { #[error("invalid build number: {0}")] InvalidBuildNumber(#[from] ParseIntError), + + #[error("Unable to parse hash digest from hex")] + InvalidHashDigest, } impl FromStr for MatchSpec { @@ -183,6 +187,18 @@ fn parse_bracket_vec_into_components( "version" => match_spec.version = Some(VersionSpec::from_str(value)?), "build" => match_spec.build = Some(StringMatcher::from_str(value)?), "build_number" => match_spec.build_number = Some(value.parse()?), + "sha256" => { + match_spec.sha256 = Some( + parse_digest_from_hex::(value) + .ok_or(ParseMatchSpecError::InvalidHashDigest)?, + ) + } + "md5" => { + match_spec.md5 = Some( + parse_digest_from_hex::(value) + .ok_or(ParseMatchSpecError::InvalidHashDigest)?, + ) + } "fn" => match_spec.file_name = Some(value.to_string()), _ => Err(ParseMatchSpecError::InvalidBracketKey(key.to_owned()))?, } @@ -425,6 +441,7 @@ fn parse(input: &str) -> Result { #[cfg(test)] mod tests { + use rattler_digest::{parse_digest_from_hex, Sha256, Md5}; use serde::Serialize; use std::collections::BTreeMap; use std::str::FromStr; @@ -541,6 +558,37 @@ mod tests { assert_eq!(spec.channel, Some("conda-forge".to_string())); } + #[test] + fn test_hash_spec() { + let spec = MatchSpec::from_str("conda-forge::foo[md5=1234567890]"); + assert_eq!(spec, Err(ParseMatchSpecError::InvalidHashDigest)); + + let spec = MatchSpec::from_str("conda-forge::foo[sha256=1234567890]"); + assert_eq!(spec, Err(ParseMatchSpecError::InvalidHashDigest)); + + let spec = MatchSpec::from_str("conda-forge::foo[sha256=315f5bdb76d078c43b8ac0064e4a0164612b1fce77c869345bfc94c75894edd3]").unwrap(); + assert_eq!( + spec.sha256, + Some( + parse_digest_from_hex::( + "315f5bdb76d078c43b8ac0064e4a0164612b1fce77c869345bfc94c75894edd3" + ) + .unwrap() + ) + ); + + let spec = MatchSpec::from_str("conda-forge::foo[md5=8b1a9953c4611296a827abf8c47804d7]").unwrap(); + assert_eq!( + spec.md5, + Some( + parse_digest_from_hex::( + "8b1a9953c4611296a827abf8c47804d7" + ) + .unwrap() + ) + ); + } + #[test] fn test_parse_bracket_list() { assert_eq!( From ccca61c0a6c3651a0a4fbba9d6892b303e117926 Mon Sep 17 00:00:00 2001 From: Bela Stoyan Date: Sun, 2 Jul 2023 14:51:05 +0200 Subject: [PATCH 2/8] add matching tests --- .../rattler_conda_types/src/match_spec/mod.rs | 49 +++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/crates/rattler_conda_types/src/match_spec/mod.rs b/crates/rattler_conda_types/src/match_spec/mod.rs index 564c72ca1..fe6058f3a 100644 --- a/crates/rattler_conda_types/src/match_spec/mod.rs +++ b/crates/rattler_conda_types/src/match_spec/mod.rs @@ -343,3 +343,52 @@ impl MatchSpec { } } } + +#[cfg(test)] +mod tests { + use std::str::FromStr; + + use crate::{ + package::{IndexJson, PackageFile}, + MatchSpec, PackageRecord, + }; + + #[test] + fn test_digest_match() { + let package_dir = tempfile::tempdir().unwrap(); + let extract_result = rattler_package_streaming::fs::extract( + &crate::get_test_data_dir().join("mamba-1.0.0-py38hecfeebb_2.tar.bz2"), + package_dir.path(), + ) + .unwrap(); + + let index = IndexJson::from_package_directory(package_dir.path()).unwrap(); + let package_record = PackageRecord::from_index_json( + index, + None, + Some(extract_result.sha256), + Some(extract_result.md5), + ) + .unwrap(); + + let spec = MatchSpec::from_str("mamba[version==1.0, sha256=aaac4bc9c6916ecc0e33137431645b029ade22190c7144eead61446dcbcc6f97]").unwrap(); + assert!(!spec.matches(&package_record)); + + let spec = MatchSpec::from_str("mamba[version==1.0, sha256=f44c4bc9c6916ecc0e33137431645b029ade22190c7144eead61446dcbcc6f97]").unwrap(); + assert!(spec.matches(&package_record)); + + let spec = MatchSpec::from_str("mamba[version==1.0, md5=aaaa6252c964db3f3e41c7d30d07f6bf]") + .unwrap(); + assert!(!spec.matches(&package_record)); + + let spec = MatchSpec::from_str("mamba[version==1.0, md5=dede6252c964db3f3e41c7d30d07f6bf]") + .unwrap(); + assert!(spec.matches(&package_record)); + + let spec = MatchSpec::from_str("mamba[version==1.0, md5=dede6252c964db3f3e41c7d30d07f6bf, sha256=f44c4bc9c6916ecc0e33137431645b029ade22190c7144eead61446dcbcc6f97]").unwrap(); + assert!(spec.matches(&package_record)); + + let spec = MatchSpec::from_str("mamba[version==1.0, md5=dede6252c964db3f3e41c7d30d07f6bf, sha256=aaac4bc9c6916ecc0e33137431645b029ade22190c7144eead61446dcbcc6f97]").unwrap(); + assert!(!spec.matches(&package_record)); + } +} From cdcb51848a3eaa16f2181ea721b310e04ed57a8c Mon Sep 17 00:00:00 2001 From: Bela Stoyan Date: Sun, 2 Jul 2023 15:11:43 +0200 Subject: [PATCH 3/8] use match statement for self.name --- crates/rattler_conda_types/src/match_spec/mod.rs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/crates/rattler_conda_types/src/match_spec/mod.rs b/crates/rattler_conda_types/src/match_spec/mod.rs index fe6058f3a..8a697cc5f 100644 --- a/crates/rattler_conda_types/src/match_spec/mod.rs +++ b/crates/rattler_conda_types/src/match_spec/mod.rs @@ -148,18 +148,17 @@ impl Display for MatchSpec { write!(f, "/{}", subdir)?; } + match &self.name { + Some(name) => write!(f, "{name}")?, + None => write!(f, "*")?, + } + if let Some(namespace) = &self.namespace { write!(f, ":{}:", namespace)?; } else if self.channel.is_some() || self.subdir.is_some() { write!(f, "::")?; } - if let Some(name) = &self.name { - write!(f, "{}", name)?; - } else { - write!(f, "*")?; - } - if let Some(version) = &self.version { write!(f, " {}", version)?; } From c2cb35a1bc01e7da51160376bd59bdfce396bff1 Mon Sep 17 00:00:00 2001 From: Bela Stoyan Date: Sun, 2 Jul 2023 16:03:13 +0200 Subject: [PATCH 4/8] fix Diplay impl for MatchSpec / NamelessMatchSpec --- .../rattler_conda_types/src/match_spec/mod.rs | 44 ++++++++++--------- 1 file changed, 23 insertions(+), 21 deletions(-) diff --git a/crates/rattler_conda_types/src/match_spec/mod.rs b/crates/rattler_conda_types/src/match_spec/mod.rs index 8a697cc5f..94027e2b3 100644 --- a/crates/rattler_conda_types/src/match_spec/mod.rs +++ b/crates/rattler_conda_types/src/match_spec/mod.rs @@ -167,12 +167,18 @@ impl Display for MatchSpec { write!(f, " {}", build)?; } + let mut keys = Vec::new(); + if let Some(md5) = &self.md5 { - write!(f, " md5={md5:x}")?; + keys.push(format!("md5={md5:x}")); } if let Some(sha256) = &self.sha256 { - write!(f, " sha256={sha256:x}")?; + keys.push(format!("sha256={sha256:x}")); + } + + if !keys.is_empty() { + write!(f, "[{}]", keys.join(", "))?; } Ok(()) @@ -201,18 +207,14 @@ impl MatchSpec { } if let Some(md5_spec) = self.md5.as_ref() { - if let Some(md5_record) = record.md5.as_ref() { - if md5_spec != md5_record { - return false; - } + if !record.md5.as_ref().map_or(false, |md5_record| md5_spec == md5_record) { + return false; } } if let Some(sha256_spec) = self.sha256.as_ref() { - if let Some(sha256_record) = record.sha256.as_ref() { - if sha256_spec != sha256_record { - return false; - } + if !record.sha256.as_ref().map_or(false, |sha256_record| sha256_spec == sha256_record) { + return false; } } @@ -264,18 +266,14 @@ impl NamelessMatchSpec { } if let Some(md5_spec) = self.md5.as_ref() { - if let Some(md5_record) = record.md5.as_ref() { - if md5_spec != md5_record { - return false; - } + if !record.md5.as_ref().map_or(false, |md5_record| md5_spec == md5_record) { + return false; } } if let Some(sha256_spec) = self.sha256.as_ref() { - if let Some(sha256_record) = record.sha256.as_ref() { - if sha256_spec != sha256_record { - return false; - } + if !record.sha256.as_ref().map_or(false, |sha256_record| sha256_spec == sha256_record) { + return false; } } @@ -295,15 +293,19 @@ impl Display for NamelessMatchSpec { write!(f, " {}", build)?; } + let mut keys = Vec::new(); + if let Some(md5) = &self.md5 { - write!(f, " md5={md5:x}")?; + keys.push(format!("md5={md5:x}")); } if let Some(sha256) = &self.sha256 { - write!(f, " sha256={sha256:x}")?; + keys.push(format!("sha256={sha256:x}")); } - // TODO: Add any additional properties as bracket arguments (e.g. `[channel=..]`) + if !keys.is_empty() { + write!(f, "[{}]", keys.join(", "))?; + } Ok(()) } From 23d586bfa85b10af3f29c2cd4df66ebe91961ad4 Mon Sep 17 00:00:00 2001 From: Bela Stoyan Date: Sun, 2 Jul 2023 16:13:17 +0200 Subject: [PATCH 5/8] use fake PackageRecord --- .../rattler_conda_types/src/match_spec/mod.rs | 67 +++++++++++-------- .../src/match_spec/parse.rs | 12 ++-- .../rattler_conda_types/src/repo_data/mod.rs | 2 +- crates/rattler_conda_types/src/version/mod.rs | 2 +- 4 files changed, 44 insertions(+), 39 deletions(-) diff --git a/crates/rattler_conda_types/src/match_spec/mod.rs b/crates/rattler_conda_types/src/match_spec/mod.rs index 94027e2b3..9abf2a930 100644 --- a/crates/rattler_conda_types/src/match_spec/mod.rs +++ b/crates/rattler_conda_types/src/match_spec/mod.rs @@ -207,13 +207,21 @@ impl MatchSpec { } if let Some(md5_spec) = self.md5.as_ref() { - if !record.md5.as_ref().map_or(false, |md5_record| md5_spec == md5_record) { + if !record + .md5 + .as_ref() + .map_or(false, |md5_record| md5_spec == md5_record) + { return false; } } if let Some(sha256_spec) = self.sha256.as_ref() { - if !record.sha256.as_ref().map_or(false, |sha256_record| sha256_spec == sha256_record) { + if !record + .sha256 + .as_ref() + .map_or(false, |sha256_record| sha256_spec == sha256_record) + { return false; } } @@ -266,13 +274,21 @@ impl NamelessMatchSpec { } if let Some(md5_spec) = self.md5.as_ref() { - if !record.md5.as_ref().map_or(false, |md5_record| md5_spec == md5_record) { + if !record + .md5 + .as_ref() + .map_or(false, |md5_record| md5_spec == md5_record) + { return false; } } if let Some(sha256_spec) = self.sha256.as_ref() { - if !record.sha256.as_ref().map_or(false, |sha256_record| sha256_spec == sha256_record) { + if !record + .sha256 + .as_ref() + .map_or(false, |sha256_record| sha256_spec == sha256_record) + { return false; } } @@ -349,47 +365,40 @@ impl MatchSpec { mod tests { use std::str::FromStr; - use crate::{ - package::{IndexJson, PackageFile}, - MatchSpec, PackageRecord, - }; + use rattler_digest::{parse_digest_from_hex, Md5, Sha256}; + + use crate::{MatchSpec, PackageRecord, Version}; #[test] fn test_digest_match() { - let package_dir = tempfile::tempdir().unwrap(); - let extract_result = rattler_package_streaming::fs::extract( - &crate::get_test_data_dir().join("mamba-1.0.0-py38hecfeebb_2.tar.bz2"), - package_dir.path(), - ) - .unwrap(); - - let index = IndexJson::from_package_directory(package_dir.path()).unwrap(); - let package_record = PackageRecord::from_index_json( - index, - None, - Some(extract_result.sha256), - Some(extract_result.md5), - ) - .unwrap(); + let record = PackageRecord { + name: "mamba".to_string(), + version: Version::from_str("1.0").unwrap(), + sha256: parse_digest_from_hex::( + "f44c4bc9c6916ecc0e33137431645b029ade22190c7144eead61446dcbcc6f97", + ), + md5: parse_digest_from_hex::("dede6252c964db3f3e41c7d30d07f6bf"), + ..PackageRecord::default() + }; let spec = MatchSpec::from_str("mamba[version==1.0, sha256=aaac4bc9c6916ecc0e33137431645b029ade22190c7144eead61446dcbcc6f97]").unwrap(); - assert!(!spec.matches(&package_record)); + assert!(!spec.matches(&record)); let spec = MatchSpec::from_str("mamba[version==1.0, sha256=f44c4bc9c6916ecc0e33137431645b029ade22190c7144eead61446dcbcc6f97]").unwrap(); - assert!(spec.matches(&package_record)); + assert!(spec.matches(&record)); let spec = MatchSpec::from_str("mamba[version==1.0, md5=aaaa6252c964db3f3e41c7d30d07f6bf]") .unwrap(); - assert!(!spec.matches(&package_record)); + assert!(!spec.matches(&record)); let spec = MatchSpec::from_str("mamba[version==1.0, md5=dede6252c964db3f3e41c7d30d07f6bf]") .unwrap(); - assert!(spec.matches(&package_record)); + assert!(spec.matches(&record)); let spec = MatchSpec::from_str("mamba[version==1.0, md5=dede6252c964db3f3e41c7d30d07f6bf, sha256=f44c4bc9c6916ecc0e33137431645b029ade22190c7144eead61446dcbcc6f97]").unwrap(); - assert!(spec.matches(&package_record)); + assert!(spec.matches(&record)); let spec = MatchSpec::from_str("mamba[version==1.0, md5=dede6252c964db3f3e41c7d30d07f6bf, sha256=aaac4bc9c6916ecc0e33137431645b029ade22190c7144eead61446dcbcc6f97]").unwrap(); - assert!(!spec.matches(&package_record)); + assert!(!spec.matches(&record)); } } diff --git a/crates/rattler_conda_types/src/match_spec/parse.rs b/crates/rattler_conda_types/src/match_spec/parse.rs index a7a0f11c6..5b72fbcc3 100644 --- a/crates/rattler_conda_types/src/match_spec/parse.rs +++ b/crates/rattler_conda_types/src/match_spec/parse.rs @@ -441,7 +441,7 @@ fn parse(input: &str) -> Result { #[cfg(test)] mod tests { - use rattler_digest::{parse_digest_from_hex, Sha256, Md5}; + use rattler_digest::{parse_digest_from_hex, Md5, Sha256}; use serde::Serialize; use std::collections::BTreeMap; use std::str::FromStr; @@ -577,15 +577,11 @@ mod tests { ) ); - let spec = MatchSpec::from_str("conda-forge::foo[md5=8b1a9953c4611296a827abf8c47804d7]").unwrap(); + let spec = + MatchSpec::from_str("conda-forge::foo[md5=8b1a9953c4611296a827abf8c47804d7]").unwrap(); assert_eq!( spec.md5, - Some( - parse_digest_from_hex::( - "8b1a9953c4611296a827abf8c47804d7" - ) - .unwrap() - ) + Some(parse_digest_from_hex::("8b1a9953c4611296a827abf8c47804d7").unwrap()) ); } diff --git a/crates/rattler_conda_types/src/repo_data/mod.rs b/crates/rattler_conda_types/src/repo_data/mod.rs index 3da7c4312..76fa71fb5 100644 --- a/crates/rattler_conda_types/src/repo_data/mod.rs +++ b/crates/rattler_conda_types/src/repo_data/mod.rs @@ -62,7 +62,7 @@ pub struct ChannelInfo { #[serde_as] #[skip_serializing_none] #[sorted] -#[derive(Debug, Deserialize, Serialize, Eq, PartialEq, Ord, PartialOrd, Clone, Hash)] +#[derive(Debug, Deserialize, Serialize, Eq, PartialEq, Ord, PartialOrd, Clone, Hash, Default)] pub struct PackageRecord { /// Optionally the architecture the package supports pub arch: Option, diff --git a/crates/rattler_conda_types/src/version/mod.rs b/crates/rattler_conda_types/src/version/mod.rs index c2f64b19e..69b66aef2 100644 --- a/crates/rattler_conda_types/src/version/mod.rs +++ b/crates/rattler_conda_types/src/version/mod.rs @@ -128,7 +128,7 @@ const LOCAL_VERSION_OFFSET: u8 = 1; /// this problem by appending an underscore to plain version numbers: /// /// 1.0.1_ < 1.0.1a => True # ensure correct ordering for openssl -#[derive(Clone, Eq, Deserialize)] +#[derive(Clone, Eq, Deserialize, Default)] pub struct Version { /// A normed copy of the original version string trimmed and converted to lower case. /// Also dashes are replaced with underscores if the version string does not contain From ce2711e73b0f0791f48fb91c17c39815109174ed Mon Sep 17 00:00:00 2001 From: Bela Stoyan Date: Sun, 2 Jul 2023 16:24:33 +0200 Subject: [PATCH 6/8] add end2end test for matchspec format --- .../rattler_conda_types/src/match_spec/mod.rs | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/crates/rattler_conda_types/src/match_spec/mod.rs b/crates/rattler_conda_types/src/match_spec/mod.rs index 9abf2a930..38f4d0ed4 100644 --- a/crates/rattler_conda_types/src/match_spec/mod.rs +++ b/crates/rattler_conda_types/src/match_spec/mod.rs @@ -367,7 +367,25 @@ mod tests { use rattler_digest::{parse_digest_from_hex, Md5, Sha256}; - use crate::{MatchSpec, PackageRecord, Version}; + use crate::{MatchSpec, NamelessMatchSpec, PackageRecord, Version}; + + #[test] + fn test_matchspec_format_eq() { + let spec = MatchSpec::from_str("mamba[version==1.0, sha256=aaac4bc9c6916ecc0e33137431645b029ade22190c7144eead61446dcbcc6f97, md5=dede6252c964db3f3e41c7d30d07f6bf]").unwrap(); + let spec_as_string = spec.to_string(); + let rebuild_spec = MatchSpec::from_str(&spec_as_string).unwrap(); + + assert_eq!(spec, rebuild_spec) + } + + #[test] + fn test_nameless_matchspec_format_eq() { + let spec = NamelessMatchSpec::from_str("*[version==1.0, sha256=aaac4bc9c6916ecc0e33137431645b029ade22190c7144eead61446dcbcc6f97, md5=dede6252c964db3f3e41c7d30d07f6bf]").unwrap(); + let spec_as_string = spec.to_string(); + let rebuild_spec = NamelessMatchSpec::from_str(&spec_as_string).unwrap(); + + assert_eq!(spec, rebuild_spec) + } #[test] fn test_digest_match() { From 9324edb84cd3f916d0ad6e1d3f672da002172b2e Mon Sep 17 00:00:00 2001 From: Bela Stoyan Date: Sun, 2 Jul 2023 16:43:09 +0200 Subject: [PATCH 7/8] simplify compare --- .../rattler_conda_types/src/match_spec/mod.rs | 24 ++++--------------- 1 file changed, 4 insertions(+), 20 deletions(-) diff --git a/crates/rattler_conda_types/src/match_spec/mod.rs b/crates/rattler_conda_types/src/match_spec/mod.rs index 38f4d0ed4..f06fb6da8 100644 --- a/crates/rattler_conda_types/src/match_spec/mod.rs +++ b/crates/rattler_conda_types/src/match_spec/mod.rs @@ -207,21 +207,13 @@ impl MatchSpec { } if let Some(md5_spec) = self.md5.as_ref() { - if !record - .md5 - .as_ref() - .map_or(false, |md5_record| md5_spec == md5_record) - { + if Some(md5_spec) != record.md5.as_ref() { return false; } } if let Some(sha256_spec) = self.sha256.as_ref() { - if !record - .sha256 - .as_ref() - .map_or(false, |sha256_record| sha256_spec == sha256_record) - { + if Some(sha256_spec) != record.sha256.as_ref() { return false; } } @@ -274,21 +266,13 @@ impl NamelessMatchSpec { } if let Some(md5_spec) = self.md5.as_ref() { - if !record - .md5 - .as_ref() - .map_or(false, |md5_record| md5_spec == md5_record) - { + if Some(md5_spec) != record.md5.as_ref() { return false; } } if let Some(sha256_spec) = self.sha256.as_ref() { - if !record - .sha256 - .as_ref() - .map_or(false, |sha256_record| sha256_spec == sha256_record) - { + if Some(sha256_spec) != record.sha256.as_ref() { return false; } } From 1b335aaf48fd52292bffd97e983a42708cde6c24 Mon Sep 17 00:00:00 2001 From: Bela Stoyan Date: Sun, 2 Jul 2023 16:45:19 +0200 Subject: [PATCH 8/8] use match --- crates/rattler_conda_types/src/match_spec/mod.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/crates/rattler_conda_types/src/match_spec/mod.rs b/crates/rattler_conda_types/src/match_spec/mod.rs index f06fb6da8..404564290 100644 --- a/crates/rattler_conda_types/src/match_spec/mod.rs +++ b/crates/rattler_conda_types/src/match_spec/mod.rs @@ -283,10 +283,9 @@ impl NamelessMatchSpec { impl Display for NamelessMatchSpec { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - if let Some(version) = self.version.as_ref() { - write!(f, "{version}")?; - } else { - write!(f, "*")?; + match &self.version { + Some(version) => write!(f, "{version}")?, + None => write!(f, "*")?, } if let Some(build) = &self.build {