From 43fd98feb0366b6a76ce067383ae96c566dc9660 Mon Sep 17 00:00:00 2001 From: Ruben Arts Date: Fri, 10 Nov 2023 15:45:51 +0100 Subject: [PATCH 1/8] refactor: make the channel in the matchspec struct an actual channel --- crates/rattler_conda_types/src/channel/mod.rs | 23 +++++++++++++++++-- .../rattler_conda_types/src/match_spec/mod.rs | 21 ++++++++++------- .../src/match_spec/parse.rs | 16 ++++++------- crates/rattler_solve/src/resolvo/mod.rs | 14 ++++++----- 4 files changed, 49 insertions(+), 25 deletions(-) diff --git a/crates/rattler_conda_types/src/channel/mod.rs b/crates/rattler_conda_types/src/channel/mod.rs index 84c7697d6..5fb4ad383 100644 --- a/crates/rattler_conda_types/src/channel/mod.rs +++ b/crates/rattler_conda_types/src/channel/mod.rs @@ -2,7 +2,7 @@ use std::borrow::Cow; use std::path::{Component, Path, PathBuf}; use std::str::FromStr; -use serde::{Deserialize, Serialize}; +use serde::{Deserialize, Serialize, Deserializer}; use smallvec::SmallVec; use thiserror::Error; use url::Url; @@ -38,7 +38,7 @@ impl Default for ChannelConfig { } /// `Channel`s are the primary source of package information. -#[derive(Debug, Clone, Serialize, Eq, PartialEq, Hash)] +#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, Hash)] pub struct Channel { /// The platforms supported by this channel, or None if no explicit platforms have been /// specified. @@ -194,6 +194,25 @@ impl Channel { pub fn canonical_name(&self) -> String { self.base_url.to_string() } + + /// Deserialize channel from string + pub fn deserialize_optional<'de, D>(deserializer: D) -> Result, D::Error> + where + D: Deserializer<'de>, + { + let s: Option = Option::deserialize(deserializer)?; + + match s { + Some(str_val) => { + let config = ChannelConfig::default(); + + Channel::from_str(&str_val, &config) + .map(Some) + .map_err(serde::de::Error::custom) + } + None => Ok(None), + } + } } #[derive(Debug, Error, Clone, Eq, PartialEq)] diff --git a/crates/rattler_conda_types/src/match_spec/mod.rs b/crates/rattler_conda_types/src/match_spec/mod.rs index 3e6989e9c..aa9c54a04 100644 --- a/crates/rattler_conda_types/src/match_spec/mod.rs +++ b/crates/rattler_conda_types/src/match_spec/mod.rs @@ -5,6 +5,7 @@ use serde_with::{serde_as, skip_serializing_none, DisplayFromStr}; use std::fmt::{Debug, Display, Formatter}; use std::hash::Hash; +use crate::Channel; pub mod matcher; pub mod parse; @@ -64,7 +65,7 @@ use matcher::StringMatcher; /// # Examples: /// /// ```rust -/// use rattler_conda_types::{MatchSpec, VersionSpec, StringMatcher, PackageName}; +/// use rattler_conda_types::{MatchSpec, VersionSpec, StringMatcher, PackageName, Channel}; /// use std::str::FromStr; /// /// let spec = MatchSpec::from_str("foo 1.0 py27_0").unwrap(); @@ -80,18 +81,18 @@ use matcher::StringMatcher; /// let spec = MatchSpec::from_str(r#"conda-forge::foo[version="1.0.*"]"#).unwrap(); /// assert_eq!(spec.name, Some(PackageName::new_unchecked("foo"))); /// assert_eq!(spec.version, Some(VersionSpec::from_str("1.0.*").unwrap())); -/// assert_eq!(spec.channel, Some("conda-forge".to_string())); +/// assert_eq!(spec.channel, Some(Channel::from_str("conda-forge", &Default::default()).unwrap())); /// /// let spec = MatchSpec::from_str("conda-forge/linux-64::foo>=1.0").unwrap(); /// assert_eq!(spec.name, Some(PackageName::new_unchecked("foo"))); /// assert_eq!(spec.version, Some(VersionSpec::from_str(">=1.0").unwrap())); -/// assert_eq!(spec.channel, Some("conda-forge".to_string())); +/// assert_eq!(spec.channel, Some(Channel::from_str("conda-forge", &Default::default()).unwrap())); /// assert_eq!(spec.subdir, Some("linux-64".to_string())); /// /// let spec = MatchSpec::from_str("*/linux-64::foo>=1.0").unwrap(); /// assert_eq!(spec.name, Some(PackageName::new_unchecked("foo"))); /// assert_eq!(spec.version, Some(VersionSpec::from_str(">=1.0").unwrap())); -/// assert_eq!(spec.channel, Some("*".to_string())); +/// assert_eq!(spec.channel, Some(Channel::from_str("*", &Default::default()).unwrap())); /// assert_eq!(spec.subdir, Some("linux-64".to_string())); /// /// let spec = MatchSpec::from_str(r#"foo[build="py2*"]"#).unwrap(); @@ -125,7 +126,8 @@ pub struct MatchSpec { /// Match the specific filename of the package pub file_name: Option, /// The channel of the package - pub channel: Option, + #[serde(deserialize_with = "Channel::deserialize_optional")] + pub channel: Option, /// The subdir of the channel pub subdir: Option, /// The namespace of the package (currently not used) @@ -141,8 +143,10 @@ pub struct MatchSpec { impl Display for MatchSpec { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { if let Some(channel) = &self.channel { - // TODO: namespace - write!(f, "{}", channel)?; + if let Some(name) = &channel.name { + // TODO: namespace + write!(f, "{}", name)?; + } } if let Some(subdir) = &self.subdir { @@ -264,7 +268,8 @@ pub struct NamelessMatchSpec { /// Match the specific filename of the package pub file_name: Option, /// The channel of the package - pub channel: Option, + #[serde(deserialize_with = "Channel::deserialize_optional")] + pub channel: Option, /// The subdir of the channel pub subdir: Option, /// The namespace of the package (currently not used) diff --git a/crates/rattler_conda_types/src/match_spec/parse.rs b/crates/rattler_conda_types/src/match_spec/parse.rs index 831a1c01d..6d0aba64c 100644 --- a/crates/rattler_conda_types/src/match_spec/parse.rs +++ b/crates/rattler_conda_types/src/match_spec/parse.rs @@ -4,9 +4,7 @@ use crate::build_spec::{BuildNumberSpec, ParseBuildNumberSpecError}; use crate::package::ArchiveType; use crate::version_spec::version_tree::{recognize_constraint, recognize_version}; use crate::version_spec::{is_start_of_version_constraint, ParseVersionSpecError}; -use crate::{ - InvalidPackageNameError, NamelessMatchSpec, PackageName, ParseChannelError, VersionSpec, -}; +use crate::{Channel, InvalidPackageNameError, NamelessMatchSpec, PackageName, ParseChannelError, VersionSpec}; use nom::branch::alt; use nom::bytes::complete::{tag, take_till1, take_until, take_while, take_while1}; use nom::character::complete::{char, multispace0, one_of}; @@ -397,10 +395,10 @@ fn parse(input: &str) -> Result { if let Some(channel_str) = channel_str { if let Some((channel, subdir)) = channel_str.rsplit_once('/') { - nameless_match_spec.channel = Some(channel.to_string()); + nameless_match_spec.channel = Some(Channel::from_str(channel, &Default::default())?); nameless_match_spec.subdir = Some(subdir.to_string()); } else { - nameless_match_spec.channel = Some(channel_str.to_string()); + nameless_match_spec.channel = Some(Channel::from_str(channel_str, &Default::default())?); } } @@ -473,7 +471,7 @@ mod tests { split_version_and_build, strip_brackets, BracketVec, MatchSpec, ParseMatchSpecError, }; use crate::match_spec::parse::parse_bracket_list; - use crate::{BuildNumberSpec, NamelessMatchSpec, VersionSpec}; + use crate::{BuildNumberSpec, Channel, NamelessMatchSpec, VersionSpec}; use smallvec::smallvec; #[test] @@ -573,18 +571,18 @@ mod tests { let spec = MatchSpec::from_str("conda-forge::foo[version=\"1.0.*\"]").unwrap(); assert_eq!(spec.name, Some("foo".parse().unwrap())); assert_eq!(spec.version, Some(VersionSpec::from_str("1.0.*").unwrap())); - assert_eq!(spec.channel, Some("conda-forge".to_string())); + assert_eq!(spec.channel, Some(Channel::from_str("conda-forge", &Default::default()).unwrap())); let spec = MatchSpec::from_str("conda-forge::foo[version=1.0.*]").unwrap(); assert_eq!(spec.name, Some("foo".parse().unwrap())); assert_eq!(spec.version, Some(VersionSpec::from_str("1.0.*").unwrap())); - assert_eq!(spec.channel, Some("conda-forge".to_string())); + assert_eq!(spec.channel, Some(Channel::from_str("conda-forge", &Default::default()).unwrap())); let spec = MatchSpec::from_str(r#"conda-forge::foo[version=1.0.*, build_number=">6"]"#).unwrap(); assert_eq!(spec.name, Some("foo".parse().unwrap())); assert_eq!(spec.version, Some(VersionSpec::from_str("1.0.*").unwrap())); - assert_eq!(spec.channel, Some("conda-forge".to_string())); + assert_eq!(spec.channel, Some(Channel::from_str("conda-forge", &Default::default()).unwrap())); assert_eq!( spec.build_number, Some(BuildNumberSpec::from_str(">6").unwrap()) diff --git a/crates/rattler_solve/src/resolvo/mod.rs b/crates/rattler_solve/src/resolvo/mod.rs index a2819f0b9..5cd2e9e42 100644 --- a/crates/rattler_solve/src/resolvo/mod.rs +++ b/crates/rattler_solve/src/resolvo/mod.rs @@ -3,8 +3,8 @@ use crate::{IntoRepoData, SolveError, SolverRepoData, SolverTask}; use rattler_conda_types::package::ArchiveType; use rattler_conda_types::{ - GenericVirtualPackage, MatchSpec, NamelessMatchSpec, PackageRecord, ParseMatchSpecError, - RepoDataRecord, + GenericVirtualPackage, MatchSpec, NamelessMatchSpec, PackageRecord, + ParseMatchSpecError, RepoDataRecord, }; use resolvo::{ Candidates, Dependencies, DependencyProvider, NameId, Pool, SolvableDisplay, SolvableId, @@ -259,14 +259,16 @@ impl<'a> CondaDependencyProvider<'a> { }) { // Check if the spec has a channel, and compare it to the repodata channel if let Some(spec_channel) = &spec.channel { - if !&record.channel.contains(spec_channel) { + if record.channel != spec_channel.base_url.to_string() { tracing::debug!("Ignoring {} from {} because it was not requested from that channel.", &record.package_record.name.as_normalized(), &record.channel); // Add record to the excluded with reason of being in the non requested channel. + let message = format!( + "candidate not in requested channel: '{}'", + spec_channel.name.clone().map(|s| s.to_string()).unwrap_or(spec_channel.base_url.to_string()) + ); candidates.excluded.push(( solvable_id, - pool.intern_string(format!( - "candidate not in requested channel: '{spec_channel}'" - )), + pool.intern_string(message), )); continue; } From 506fac8814d2ebd2dbb2fc2e2bef6330771ddb85 Mon Sep 17 00:00:00 2001 From: Ruben Arts Date: Fri, 10 Nov 2023 16:11:30 +0100 Subject: [PATCH 2/8] fmt & clippy --- crates/rattler_conda_types/src/channel/mod.rs | 6 ++--- .../src/match_spec/parse.rs | 23 +++++++++++++++---- crates/rattler_solve/src/resolvo/mod.rs | 16 +++++++------ 3 files changed, 30 insertions(+), 15 deletions(-) diff --git a/crates/rattler_conda_types/src/channel/mod.rs b/crates/rattler_conda_types/src/channel/mod.rs index 5fb4ad383..645ddf63b 100644 --- a/crates/rattler_conda_types/src/channel/mod.rs +++ b/crates/rattler_conda_types/src/channel/mod.rs @@ -2,7 +2,7 @@ use std::borrow::Cow; use std::path::{Component, Path, PathBuf}; use std::str::FromStr; -use serde::{Deserialize, Serialize, Deserializer}; +use serde::{Deserialize, Deserializer, Serialize}; use smallvec::SmallVec; use thiserror::Error; use url::Url; @@ -197,8 +197,8 @@ impl Channel { /// Deserialize channel from string pub fn deserialize_optional<'de, D>(deserializer: D) -> Result, D::Error> - where - D: Deserializer<'de>, + where + D: Deserializer<'de>, { let s: Option = Option::deserialize(deserializer)?; diff --git a/crates/rattler_conda_types/src/match_spec/parse.rs b/crates/rattler_conda_types/src/match_spec/parse.rs index 6d0aba64c..580116963 100644 --- a/crates/rattler_conda_types/src/match_spec/parse.rs +++ b/crates/rattler_conda_types/src/match_spec/parse.rs @@ -4,7 +4,10 @@ use crate::build_spec::{BuildNumberSpec, ParseBuildNumberSpecError}; use crate::package::ArchiveType; use crate::version_spec::version_tree::{recognize_constraint, recognize_version}; use crate::version_spec::{is_start_of_version_constraint, ParseVersionSpecError}; -use crate::{Channel, InvalidPackageNameError, NamelessMatchSpec, PackageName, ParseChannelError, VersionSpec}; +use crate::{ + Channel, InvalidPackageNameError, NamelessMatchSpec, PackageName, ParseChannelError, + VersionSpec, +}; use nom::branch::alt; use nom::bytes::complete::{tag, take_till1, take_until, take_while, take_while1}; use nom::character::complete::{char, multispace0, one_of}; @@ -398,7 +401,8 @@ fn parse(input: &str) -> Result { nameless_match_spec.channel = Some(Channel::from_str(channel, &Default::default())?); nameless_match_spec.subdir = Some(subdir.to_string()); } else { - nameless_match_spec.channel = Some(Channel::from_str(channel_str, &Default::default())?); + nameless_match_spec.channel = + Some(Channel::from_str(channel_str, &Default::default())?); } } @@ -571,18 +575,27 @@ mod tests { let spec = MatchSpec::from_str("conda-forge::foo[version=\"1.0.*\"]").unwrap(); assert_eq!(spec.name, Some("foo".parse().unwrap())); assert_eq!(spec.version, Some(VersionSpec::from_str("1.0.*").unwrap())); - assert_eq!(spec.channel, Some(Channel::from_str("conda-forge", &Default::default()).unwrap())); + assert_eq!( + spec.channel, + Some(Channel::from_str("conda-forge", &Default::default()).unwrap()) + ); let spec = MatchSpec::from_str("conda-forge::foo[version=1.0.*]").unwrap(); assert_eq!(spec.name, Some("foo".parse().unwrap())); assert_eq!(spec.version, Some(VersionSpec::from_str("1.0.*").unwrap())); - assert_eq!(spec.channel, Some(Channel::from_str("conda-forge", &Default::default()).unwrap())); + assert_eq!( + spec.channel, + Some(Channel::from_str("conda-forge", &Default::default()).unwrap()) + ); let spec = MatchSpec::from_str(r#"conda-forge::foo[version=1.0.*, build_number=">6"]"#).unwrap(); assert_eq!(spec.name, Some("foo".parse().unwrap())); assert_eq!(spec.version, Some(VersionSpec::from_str("1.0.*").unwrap())); - assert_eq!(spec.channel, Some(Channel::from_str("conda-forge", &Default::default()).unwrap())); + assert_eq!( + spec.channel, + Some(Channel::from_str("conda-forge", &Default::default()).unwrap()) + ); assert_eq!( spec.build_number, Some(BuildNumberSpec::from_str(">6").unwrap()) diff --git a/crates/rattler_solve/src/resolvo/mod.rs b/crates/rattler_solve/src/resolvo/mod.rs index 5cd2e9e42..c0e138542 100644 --- a/crates/rattler_solve/src/resolvo/mod.rs +++ b/crates/rattler_solve/src/resolvo/mod.rs @@ -3,8 +3,8 @@ use crate::{IntoRepoData, SolveError, SolverRepoData, SolverTask}; use rattler_conda_types::package::ArchiveType; use rattler_conda_types::{ - GenericVirtualPackage, MatchSpec, NamelessMatchSpec, PackageRecord, - ParseMatchSpecError, RepoDataRecord, + GenericVirtualPackage, MatchSpec, NamelessMatchSpec, PackageRecord, ParseMatchSpecError, + RepoDataRecord, }; use resolvo::{ Candidates, Dependencies, DependencyProvider, NameId, Pool, SolvableDisplay, SolvableId, @@ -264,12 +264,14 @@ impl<'a> CondaDependencyProvider<'a> { // Add record to the excluded with reason of being in the non requested channel. let message = format!( "candidate not in requested channel: '{}'", - spec_channel.name.clone().map(|s| s.to_string()).unwrap_or(spec_channel.base_url.to_string()) + spec_channel + .name + .clone() + .unwrap_or(spec_channel.base_url.to_string()) ); - candidates.excluded.push(( - solvable_id, - pool.intern_string(message), - )); + candidates + .excluded + .push((solvable_id, pool.intern_string(message))); continue; } } From 33e5596faa2c5484f5840fe8d80c2e1271d5037e Mon Sep 17 00:00:00 2001 From: Ruben Arts Date: Fri, 10 Nov 2023 16:22:39 +0100 Subject: [PATCH 3/8] clippy --- crates/rattler_conda_types/src/channel/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/rattler_conda_types/src/channel/mod.rs b/crates/rattler_conda_types/src/channel/mod.rs index 645ddf63b..d40563e8e 100644 --- a/crates/rattler_conda_types/src/channel/mod.rs +++ b/crates/rattler_conda_types/src/channel/mod.rs @@ -206,7 +206,7 @@ impl Channel { Some(str_val) => { let config = ChannelConfig::default(); - Channel::from_str(&str_val, &config) + Channel::from_str(str_val, &config) .map(Some) .map_err(serde::de::Error::custom) } From 2a3c3cace447a02f8b0deb9ad18bfd2230fb8e31 Mon Sep 17 00:00:00 2001 From: Ruben Arts Date: Sat, 11 Nov 2023 16:29:12 +0100 Subject: [PATCH 4/8] make channel a Arc in the match spec --- crates/rattler_conda_types/Cargo.toml | 2 +- crates/rattler_conda_types/src/channel/mod.rs | 5 +++-- crates/rattler_conda_types/src/match_spec/mod.rs | 13 +++++++------ crates/rattler_conda_types/src/match_spec/parse.rs | 11 ++++++----- 4 files changed, 17 insertions(+), 14 deletions(-) diff --git a/crates/rattler_conda_types/Cargo.toml b/crates/rattler_conda_types/Cargo.toml index bcca4a58d..0e4b260e8 100644 --- a/crates/rattler_conda_types/Cargo.toml +++ b/crates/rattler_conda_types/Cargo.toml @@ -19,7 +19,7 @@ itertools = "0.11.0" lazy-regex = "3.0.2" nom = "7.1.3" regex = "1.9.6" -serde = { version = "1.0.188", features = ["derive"] } +serde = { version = "1.0.188", features = ["derive", "rc"] } serde_json = "1.0.107" serde_yaml = "0.9.25" serde_with = { version = "3.3.0", features = ["indexmap_2"] } diff --git a/crates/rattler_conda_types/src/channel/mod.rs b/crates/rattler_conda_types/src/channel/mod.rs index d40563e8e..b767ae3a5 100644 --- a/crates/rattler_conda_types/src/channel/mod.rs +++ b/crates/rattler_conda_types/src/channel/mod.rs @@ -1,6 +1,7 @@ use std::borrow::Cow; use std::path::{Component, Path, PathBuf}; use std::str::FromStr; +use std::sync::Arc; use serde::{Deserialize, Deserializer, Serialize}; use smallvec::SmallVec; @@ -196,7 +197,7 @@ impl Channel { } /// Deserialize channel from string - pub fn deserialize_optional<'de, D>(deserializer: D) -> Result, D::Error> + pub fn deserialize_optional<'de, D>(deserializer: D) -> Result>, D::Error> where D: Deserializer<'de>, { @@ -207,7 +208,7 @@ impl Channel { let config = ChannelConfig::default(); Channel::from_str(str_val, &config) - .map(Some) + .map(|channel|Some(Arc::new(channel))) .map_err(serde::de::Error::custom) } None => Ok(None), diff --git a/crates/rattler_conda_types/src/match_spec/mod.rs b/crates/rattler_conda_types/src/match_spec/mod.rs index aa9c54a04..55e321f69 100644 --- a/crates/rattler_conda_types/src/match_spec/mod.rs +++ b/crates/rattler_conda_types/src/match_spec/mod.rs @@ -4,6 +4,7 @@ use serde::{Deserialize, Serialize}; use serde_with::{serde_as, skip_serializing_none, DisplayFromStr}; use std::fmt::{Debug, Display, Formatter}; use std::hash::Hash; +use std::sync::Arc; use crate::Channel; pub mod matcher; @@ -67,6 +68,7 @@ use matcher::StringMatcher; /// ```rust /// use rattler_conda_types::{MatchSpec, VersionSpec, StringMatcher, PackageName, Channel}; /// use std::str::FromStr; +/// use std::sync::Arc; /// /// let spec = MatchSpec::from_str("foo 1.0 py27_0").unwrap(); /// assert_eq!(spec.name, Some(PackageName::new_unchecked("foo"))); @@ -81,18 +83,18 @@ use matcher::StringMatcher; /// let spec = MatchSpec::from_str(r#"conda-forge::foo[version="1.0.*"]"#).unwrap(); /// assert_eq!(spec.name, Some(PackageName::new_unchecked("foo"))); /// assert_eq!(spec.version, Some(VersionSpec::from_str("1.0.*").unwrap())); -/// assert_eq!(spec.channel, Some(Channel::from_str("conda-forge", &Default::default()).unwrap())); +/// assert_eq!(spec.channel, Some(Channel::from_str("conda-forge", &Default::default()).map(|channel| Arc::new(channel)).unwrap())); /// /// let spec = MatchSpec::from_str("conda-forge/linux-64::foo>=1.0").unwrap(); /// assert_eq!(spec.name, Some(PackageName::new_unchecked("foo"))); /// assert_eq!(spec.version, Some(VersionSpec::from_str(">=1.0").unwrap())); -/// assert_eq!(spec.channel, Some(Channel::from_str("conda-forge", &Default::default()).unwrap())); +/// assert_eq!(spec.channel, Some(Channel::from_str("conda-forge", &Default::default()).map(|channel| Arc::new(channel)).unwrap())); /// assert_eq!(spec.subdir, Some("linux-64".to_string())); /// /// let spec = MatchSpec::from_str("*/linux-64::foo>=1.0").unwrap(); /// assert_eq!(spec.name, Some(PackageName::new_unchecked("foo"))); /// assert_eq!(spec.version, Some(VersionSpec::from_str(">=1.0").unwrap())); -/// assert_eq!(spec.channel, Some(Channel::from_str("*", &Default::default()).unwrap())); +/// assert_eq!(spec.channel, Some(Channel::from_str("*", &Default::default()).map(|channel| Arc::new(channel)).unwrap())); /// assert_eq!(spec.subdir, Some("linux-64".to_string())); /// /// let spec = MatchSpec::from_str(r#"foo[build="py2*"]"#).unwrap(); @@ -126,8 +128,7 @@ pub struct MatchSpec { /// Match the specific filename of the package pub file_name: Option, /// The channel of the package - #[serde(deserialize_with = "Channel::deserialize_optional")] - pub channel: Option, + pub channel: Option>, /// The subdir of the channel pub subdir: Option, /// The namespace of the package (currently not used) @@ -269,7 +270,7 @@ pub struct NamelessMatchSpec { pub file_name: Option, /// The channel of the package #[serde(deserialize_with = "Channel::deserialize_optional")] - pub channel: Option, + pub channel: Option>, /// The subdir of the channel pub subdir: Option, /// The namespace of the package (currently not used) diff --git a/crates/rattler_conda_types/src/match_spec/parse.rs b/crates/rattler_conda_types/src/match_spec/parse.rs index 580116963..963ec15ef 100644 --- a/crates/rattler_conda_types/src/match_spec/parse.rs +++ b/crates/rattler_conda_types/src/match_spec/parse.rs @@ -398,11 +398,11 @@ fn parse(input: &str) -> Result { if let Some(channel_str) = channel_str { if let Some((channel, subdir)) = channel_str.rsplit_once('/') { - nameless_match_spec.channel = Some(Channel::from_str(channel, &Default::default())?); + nameless_match_spec.channel = Some(Channel::from_str(channel, &Default::default())?.into()); nameless_match_spec.subdir = Some(subdir.to_string()); } else { nameless_match_spec.channel = - Some(Channel::from_str(channel_str, &Default::default())?); + Some(Channel::from_str(channel_str, &Default::default())?.into()); } } @@ -470,6 +470,7 @@ mod tests { use serde::Serialize; use std::collections::BTreeMap; use std::str::FromStr; + use std::sync::Arc; use super::{ split_version_and_build, strip_brackets, BracketVec, MatchSpec, ParseMatchSpecError, @@ -577,7 +578,7 @@ mod tests { assert_eq!(spec.version, Some(VersionSpec::from_str("1.0.*").unwrap())); assert_eq!( spec.channel, - Some(Channel::from_str("conda-forge", &Default::default()).unwrap()) + Some(Channel::from_str("conda-forge", &Default::default()).map(|channel| Arc::new(channel)).unwrap()) ); let spec = MatchSpec::from_str("conda-forge::foo[version=1.0.*]").unwrap(); @@ -585,7 +586,7 @@ mod tests { assert_eq!(spec.version, Some(VersionSpec::from_str("1.0.*").unwrap())); assert_eq!( spec.channel, - Some(Channel::from_str("conda-forge", &Default::default()).unwrap()) + Some(Channel::from_str("conda-forge", &Default::default()).map(|channel| Arc::new(channel)).unwrap()) ); let spec = @@ -594,7 +595,7 @@ mod tests { assert_eq!(spec.version, Some(VersionSpec::from_str("1.0.*").unwrap())); assert_eq!( spec.channel, - Some(Channel::from_str("conda-forge", &Default::default()).unwrap()) + Some(Channel::from_str("conda-forge", &Default::default()).map(|channel| Arc::new(channel)).unwrap()) ); assert_eq!( spec.build_number, From 1cbead5cc21272673bc24cd87df55a71a8c109f8 Mon Sep 17 00:00:00 2001 From: Ruben Arts Date: Sat, 11 Nov 2023 16:30:25 +0100 Subject: [PATCH 5/8] fmt --- crates/rattler_conda_types/src/channel/mod.rs | 2 +- .../src/match_spec/parse.rs | 21 +++++++++++++++---- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/crates/rattler_conda_types/src/channel/mod.rs b/crates/rattler_conda_types/src/channel/mod.rs index b767ae3a5..2dcfd75c9 100644 --- a/crates/rattler_conda_types/src/channel/mod.rs +++ b/crates/rattler_conda_types/src/channel/mod.rs @@ -208,7 +208,7 @@ impl Channel { let config = ChannelConfig::default(); Channel::from_str(str_val, &config) - .map(|channel|Some(Arc::new(channel))) + .map(|channel| Some(Arc::new(channel))) .map_err(serde::de::Error::custom) } None => Ok(None), diff --git a/crates/rattler_conda_types/src/match_spec/parse.rs b/crates/rattler_conda_types/src/match_spec/parse.rs index 963ec15ef..b1b8ceea9 100644 --- a/crates/rattler_conda_types/src/match_spec/parse.rs +++ b/crates/rattler_conda_types/src/match_spec/parse.rs @@ -398,7 +398,8 @@ fn parse(input: &str) -> Result { if let Some(channel_str) = channel_str { if let Some((channel, subdir)) = channel_str.rsplit_once('/') { - nameless_match_spec.channel = Some(Channel::from_str(channel, &Default::default())?.into()); + nameless_match_spec.channel = + Some(Channel::from_str(channel, &Default::default())?.into()); nameless_match_spec.subdir = Some(subdir.to_string()); } else { nameless_match_spec.channel = @@ -578,7 +579,11 @@ mod tests { assert_eq!(spec.version, Some(VersionSpec::from_str("1.0.*").unwrap())); assert_eq!( spec.channel, - Some(Channel::from_str("conda-forge", &Default::default()).map(|channel| Arc::new(channel)).unwrap()) + Some( + Channel::from_str("conda-forge", &Default::default()) + .map(|channel| Arc::new(channel)) + .unwrap() + ) ); let spec = MatchSpec::from_str("conda-forge::foo[version=1.0.*]").unwrap(); @@ -586,7 +591,11 @@ mod tests { assert_eq!(spec.version, Some(VersionSpec::from_str("1.0.*").unwrap())); assert_eq!( spec.channel, - Some(Channel::from_str("conda-forge", &Default::default()).map(|channel| Arc::new(channel)).unwrap()) + Some( + Channel::from_str("conda-forge", &Default::default()) + .map(|channel| Arc::new(channel)) + .unwrap() + ) ); let spec = @@ -595,7 +604,11 @@ mod tests { assert_eq!(spec.version, Some(VersionSpec::from_str("1.0.*").unwrap())); assert_eq!( spec.channel, - Some(Channel::from_str("conda-forge", &Default::default()).map(|channel| Arc::new(channel)).unwrap()) + Some( + Channel::from_str("conda-forge", &Default::default()) + .map(|channel| Arc::new(channel)) + .unwrap() + ) ); assert_eq!( spec.build_number, From f38a84a45e17a9a90d7eb41e6fc6b000dc089b1a Mon Sep 17 00:00:00 2001 From: Ruben Arts Date: Mon, 13 Nov 2023 15:08:58 +0100 Subject: [PATCH 6/8] misc: Move deserialize function --- crates/rattler_conda_types/src/channel/mod.rs | 19 ------------- .../rattler_conda_types/src/match_spec/mod.rs | 27 +++++++++++++++++-- 2 files changed, 25 insertions(+), 21 deletions(-) diff --git a/crates/rattler_conda_types/src/channel/mod.rs b/crates/rattler_conda_types/src/channel/mod.rs index 2dcfd75c9..a75bff852 100644 --- a/crates/rattler_conda_types/src/channel/mod.rs +++ b/crates/rattler_conda_types/src/channel/mod.rs @@ -195,25 +195,6 @@ impl Channel { pub fn canonical_name(&self) -> String { self.base_url.to_string() } - - /// Deserialize channel from string - pub fn deserialize_optional<'de, D>(deserializer: D) -> Result>, D::Error> - where - D: Deserializer<'de>, - { - let s: Option = Option::deserialize(deserializer)?; - - match s { - Some(str_val) => { - let config = ChannelConfig::default(); - - Channel::from_str(str_val, &config) - .map(|channel| Some(Arc::new(channel))) - .map_err(serde::de::Error::custom) - } - None => Ok(None), - } - } } #[derive(Debug, Error, Clone, Eq, PartialEq)] diff --git a/crates/rattler_conda_types/src/match_spec/mod.rs b/crates/rattler_conda_types/src/match_spec/mod.rs index 55e321f69..54533d62d 100644 --- a/crates/rattler_conda_types/src/match_spec/mod.rs +++ b/crates/rattler_conda_types/src/match_spec/mod.rs @@ -1,12 +1,14 @@ use crate::{build_spec::BuildNumberSpec, PackageName, PackageRecord, VersionSpec}; use rattler_digest::{serde::SerializableHash, Md5Hash, Sha256Hash}; -use serde::{Deserialize, Serialize}; +use serde::{Deserialize, Deserializer, Serialize}; use serde_with::{serde_as, skip_serializing_none, DisplayFromStr}; use std::fmt::{Debug, Display, Formatter}; use std::hash::Hash; use std::sync::Arc; use crate::Channel; +use crate::ChannelConfig; + pub mod matcher; pub mod parse; @@ -269,7 +271,7 @@ pub struct NamelessMatchSpec { /// Match the specific filename of the package pub file_name: Option, /// The channel of the package - #[serde(deserialize_with = "Channel::deserialize_optional")] + #[serde(deserialize_with = "deserialize_channel")] pub channel: Option>, /// The subdir of the channel pub subdir: Option, @@ -377,6 +379,27 @@ impl MatchSpec { } } +/// Deserialize channel from string +/// TODO: This should be refactored so that the front ends are the one setting the channel config, +/// and rattler only takes care of the url. +fn deserialize_channel<'de, D>(deserializer: D) -> Result>, D::Error> + where + D: Deserializer<'de>, +{ + let s: Option = Option::deserialize(deserializer)?; + + match s { + Some(str_val) => { + let config = ChannelConfig::default(); + + Channel::from_str(str_val, &config) + .map(|channel| Some(Arc::new(channel))) + .map_err(serde::de::Error::custom) + } + None => Ok(None), + } +} + #[cfg(test)] mod tests { use std::str::FromStr; From 9abe7b7000b8914118b57087f3b75ca3a6184938 Mon Sep 17 00:00:00 2001 From: Ruben Arts Date: Mon, 13 Nov 2023 15:11:20 +0100 Subject: [PATCH 7/8] fmt/clippy --- crates/rattler_conda_types/src/channel/mod.rs | 3 +-- crates/rattler_conda_types/src/match_spec/mod.rs | 4 ++-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/crates/rattler_conda_types/src/channel/mod.rs b/crates/rattler_conda_types/src/channel/mod.rs index a75bff852..9fc2d426b 100644 --- a/crates/rattler_conda_types/src/channel/mod.rs +++ b/crates/rattler_conda_types/src/channel/mod.rs @@ -1,9 +1,8 @@ use std::borrow::Cow; use std::path::{Component, Path, PathBuf}; use std::str::FromStr; -use std::sync::Arc; -use serde::{Deserialize, Deserializer, Serialize}; +use serde::{Deserialize, Serialize}; use smallvec::SmallVec; use thiserror::Error; use url::Url; diff --git a/crates/rattler_conda_types/src/match_spec/mod.rs b/crates/rattler_conda_types/src/match_spec/mod.rs index 54533d62d..290e7119d 100644 --- a/crates/rattler_conda_types/src/match_spec/mod.rs +++ b/crates/rattler_conda_types/src/match_spec/mod.rs @@ -383,8 +383,8 @@ impl MatchSpec { /// TODO: This should be refactored so that the front ends are the one setting the channel config, /// and rattler only takes care of the url. fn deserialize_channel<'de, D>(deserializer: D) -> Result>, D::Error> - where - D: Deserializer<'de>, +where + D: Deserializer<'de>, { let s: Option = Option::deserialize(deserializer)?; From e129c89175295846a9eb30ce53f25933d156c5da Mon Sep 17 00:00:00 2001 From: Ruben Arts Date: Tue, 14 Nov 2023 09:17:58 +0100 Subject: [PATCH 8/8] misc: remove unneeded deserialize --- crates/rattler_conda_types/src/channel/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/rattler_conda_types/src/channel/mod.rs b/crates/rattler_conda_types/src/channel/mod.rs index 9fc2d426b..84c7697d6 100644 --- a/crates/rattler_conda_types/src/channel/mod.rs +++ b/crates/rattler_conda_types/src/channel/mod.rs @@ -38,7 +38,7 @@ impl Default for ChannelConfig { } /// `Channel`s are the primary source of package information. -#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, Hash)] +#[derive(Debug, Clone, Serialize, Eq, PartialEq, Hash)] pub struct Channel { /// The platforms supported by this channel, or None if no explicit platforms have been /// specified.