diff --git a/crates/rattler_conda_types/src/channel/mod.rs b/crates/rattler_conda_types/src/channel/mod.rs
index f0d0fb79d..23f758122 100644
--- a/crates/rattler_conda_types/src/channel/mod.rs
+++ b/crates/rattler_conda_types/src/channel/mod.rs
@@ -198,6 +198,10 @@ impl Channel {
}
}
} else {
+ // Validate that the channel is a valid name
+ if channel.contains([':', '\\']) {
+ return Err(ParseChannelError::InvalidName(channel.to_owned()));
+ }
Channel {
platforms,
..Channel::from_name(channel, config)
@@ -367,6 +371,10 @@ pub enum ParseChannelError {
#[error("invalid path '{0}'")]
InvalidPath(String),
+ /// Error when the channel name is invalid.
+ #[error("invalid channel name: '{0}'")]
+ InvalidName(String),
+
/// The root directory is not an absolute path
#[error("root directory from channel config is not an absolute path")]
NonAbsoluteRootDir(PathBuf),
@@ -541,6 +549,12 @@ mod tests {
channel.base_url().to_string(),
"https://conda.anaconda.org/conda-forge/"
);
+
+ let channel = Channel::from_str(
+ "https://conda.anaconda.org/conda-forge/label/rust_dev",
+ &config,
+ );
+ assert_eq!(channel.unwrap().name(), "conda-forge/label/rust_dev",);
}
#[test]
diff --git a/crates/rattler_conda_types/src/match_spec/mod.rs b/crates/rattler_conda_types/src/match_spec/mod.rs
index 95f4c2d0b..18d4a00b7 100644
--- a/crates/rattler_conda_types/src/match_spec/mod.rs
+++ b/crates/rattler_conda_types/src/match_spec/mod.rs
@@ -89,11 +89,12 @@ use matcher::StringMatcher;
/// assert_eq!(spec.version, Some(VersionSpec::from_str("1.0.*", Strict).unwrap()));
/// assert_eq!(spec.channel, Some(Channel::from_str("conda-forge", &channel_config).map(|channel| Arc::new(channel)).unwrap()));
///
-/// let spec = MatchSpec::from_str("conda-forge/linux-64::foo >=1.0", Strict).unwrap();
+/// let spec = MatchSpec::from_str(r#"conda-forge::foo >=1.0[subdir="linux-64"]"#, Strict).unwrap();
/// assert_eq!(spec.name, Some(PackageName::new_unchecked("foo")));
/// assert_eq!(spec.version, Some(VersionSpec::from_str(">=1.0", Strict).unwrap()));
/// assert_eq!(spec.channel, Some(Channel::from_str("conda-forge", &channel_config).map(|channel| Arc::new(channel)).unwrap()));
/// assert_eq!(spec.subdir, Some("linux-64".to_string()));
+/// assert_eq!(spec, MatchSpec::from_str("conda-forge/linux-64::foo >=1.0", Strict).unwrap());
///
/// let spec = MatchSpec::from_str("*/linux-64::foo >=1.0", Strict).unwrap();
/// assert_eq!(spec.name, Some(PackageName::new_unchecked("foo")));
diff --git a/crates/rattler_conda_types/src/match_spec/parse.rs b/crates/rattler_conda_types/src/match_spec/parse.rs
index e24816e66..11e7030ce 100644
--- a/crates/rattler_conda_types/src/match_spec/parse.rs
+++ b/crates/rattler_conda_types/src/match_spec/parse.rs
@@ -1,4 +1,4 @@
-use std::{borrow::Cow, ops::Not, str::FromStr};
+use std::{borrow::Cow, ops::Not, str::FromStr, sync::Arc};
use nom::{
branch::alt,
@@ -32,7 +32,7 @@ use crate::{
Channel, ChannelConfig, InvalidPackageNameError, NamelessMatchSpec, PackageName,
ParseChannelError, ParseStrictness,
ParseStrictness::{Lenient, Strict},
- ParseVersionError, VersionSpec,
+ ParseVersionError, Platform, VersionSpec,
};
/// The type of parse error that occurred when parsing match spec.
@@ -54,10 +54,6 @@ pub enum ParseMatchSpecError {
#[error("invalid bracket")]
InvalidBracket,
- /// Invalid number of colons in match spec
- #[error("invalid number of colons")]
- InvalidNumberOfColons,
-
/// Invalid channel provided in match spec
#[error("invalid channel")]
ParseChannelError(#[from] ParseChannelError),
@@ -266,6 +262,7 @@ fn parse_bracket_vec_into_components(
match_spec.url = Some(url);
}
+ "subdir" => match_spec.subdir = Some(value.to_string()),
// TODO: Still need to add `track_features`, `features`, `license` and `license_family`
// to the match spec.
_ => Err(ParseMatchSpecError::InvalidBracketKey(key.to_owned()))?,
@@ -276,7 +273,12 @@ fn parse_bracket_vec_into_components(
}
/// Parses an url or path like string into an url.
-fn parse_url_like(input: &str) -> Result