From d74147d81490ae68244a7172ef345788d1a96126 Mon Sep 17 00:00:00 2001 From: Bas Zalmstra Date: Sat, 4 Jan 2025 11:24:43 +0100 Subject: [PATCH] fix: parsing of >=2.*.* (#1006) --- .../src/match_spec/parse.rs | 4 ++++ ...arse__tests__test_from_string_Lenient.snap | 4 ++++ ...parse__tests__test_from_string_Strict.snap | 2 ++ ...ts__test_nameless_from_string_Lenient.snap | 3 +++ ...sts__test_nameless_from_string_Strict.snap | 2 ++ .../src/version_spec/mod.rs | 10 +++++++++ .../src/version_spec/parse.rs | 22 ++++++++++++++++--- 7 files changed, 44 insertions(+), 3 deletions(-) diff --git a/crates/rattler_conda_types/src/match_spec/parse.rs b/crates/rattler_conda_types/src/match_spec/parse.rs index 03d62f1a9..f27b06788 100644 --- a/crates/rattler_conda_types/src/match_spec/parse.rs +++ b/crates/rattler_conda_types/src/match_spec/parse.rs @@ -1058,6 +1058,8 @@ mod tests { "./relative/channel::package", "python[channel=https://conda.anaconda.org/python/conda,version=3.9]", "channel/win-64::foobar[channel=conda-forge, subdir=linux-64]", + // Issue #1004 + "numpy>=2.*.*", ]; let evaluated: IndexMap<_, _> = specs @@ -1128,6 +1130,8 @@ mod tests { // subdir in brackets take precedence "[version=3.9, subdir=linux-64]", "==3.9[subdir=linux-64, build_number=\"0\"]", + // Issue #1004 + ">=2.*.*", ]; let evaluated: IndexMap<_, _> = specs diff --git a/crates/rattler_conda_types/src/match_spec/snapshots/rattler_conda_types__match_spec__parse__tests__test_from_string_Lenient.snap b/crates/rattler_conda_types/src/match_spec/snapshots/rattler_conda_types__match_spec__parse__tests__test_from_string_Lenient.snap index e1dab9eda..671727f9a 100644 --- a/crates/rattler_conda_types/src/match_spec/snapshots/rattler_conda_types__match_spec__parse__tests__test_from_string_Lenient.snap +++ b/crates/rattler_conda_types/src/match_spec/snapshots/rattler_conda_types__match_spec__parse__tests__test_from_string_Lenient.snap @@ -1,6 +1,7 @@ --- source: crates/rattler_conda_types/src/match_spec/parse.rs expression: evaluated +snapshot_kind: text --- blas *.* mkl: name: blas @@ -138,3 +139,6 @@ rust ~=1.2.3: base_url: "https://conda.anaconda.org/conda-forge" name: conda-forge subdir: linux-64 +numpy>=2.*.*: + name: numpy + version: ">=2" diff --git a/crates/rattler_conda_types/src/match_spec/snapshots/rattler_conda_types__match_spec__parse__tests__test_from_string_Strict.snap b/crates/rattler_conda_types/src/match_spec/snapshots/rattler_conda_types__match_spec__parse__tests__test_from_string_Strict.snap index 67efcec59..815b26d59 100644 --- a/crates/rattler_conda_types/src/match_spec/snapshots/rattler_conda_types__match_spec__parse__tests__test_from_string_Strict.snap +++ b/crates/rattler_conda_types/src/match_spec/snapshots/rattler_conda_types__match_spec__parse__tests__test_from_string_Strict.snap @@ -108,3 +108,5 @@ rust ~=1.2.3: base_url: "https://conda.anaconda.org/conda-forge" name: conda-forge subdir: linux-64 +numpy>=2.*.*: + error: "invalid version constraint: regex constraints are not supported" diff --git a/crates/rattler_conda_types/src/match_spec/snapshots/rattler_conda_types__match_spec__parse__tests__test_nameless_from_string_Lenient.snap b/crates/rattler_conda_types/src/match_spec/snapshots/rattler_conda_types__match_spec__parse__tests__test_nameless_from_string_Lenient.snap index 78a021e2f..3292989fa 100644 --- a/crates/rattler_conda_types/src/match_spec/snapshots/rattler_conda_types__match_spec__parse__tests__test_nameless_from_string_Lenient.snap +++ b/crates/rattler_conda_types/src/match_spec/snapshots/rattler_conda_types__match_spec__parse__tests__test_nameless_from_string_Lenient.snap @@ -1,6 +1,7 @@ --- source: crates/rattler_conda_types/src/match_spec/parse.rs expression: evaluated +snapshot_kind: text --- 2.7|>=3.6: version: "==2.7|>=3.6" @@ -57,3 +58,5 @@ expression: evaluated op: Eq rhs: 0 subdir: linux-64 +">=2.*.*": + version: ">=2" diff --git a/crates/rattler_conda_types/src/match_spec/snapshots/rattler_conda_types__match_spec__parse__tests__test_nameless_from_string_Strict.snap b/crates/rattler_conda_types/src/match_spec/snapshots/rattler_conda_types__match_spec__parse__tests__test_nameless_from_string_Strict.snap index 6b1f2850c..e8363448a 100644 --- a/crates/rattler_conda_types/src/match_spec/snapshots/rattler_conda_types__match_spec__parse__tests__test_nameless_from_string_Strict.snap +++ b/crates/rattler_conda_types/src/match_spec/snapshots/rattler_conda_types__match_spec__parse__tests__test_nameless_from_string_Strict.snap @@ -54,3 +54,5 @@ snapshot_kind: text op: Eq rhs: 0 subdir: linux-64 +">=2.*.*": + error: "invalid version constraint: regex constraints are not supported" diff --git a/crates/rattler_conda_types/src/version_spec/mod.rs b/crates/rattler_conda_types/src/version_spec/mod.rs index d6498a15e..3d147ad50 100644 --- a/crates/rattler_conda_types/src/version_spec/mod.rs +++ b/crates/rattler_conda_types/src/version_spec/mod.rs @@ -506,6 +506,16 @@ mod tests { assert!(VersionSpec::from_str("0.2.18.*.", ParseStrictness::Strict).is_err()); } + #[test] + fn issue_1004() { + assert_eq!( + VersionSpec::from_str(">=2.*.*", ParseStrictness::Lenient).unwrap(), + VersionSpec::from_str(">=2", ParseStrictness::Lenient).unwrap() + ); + + assert!(VersionSpec::from_str("0.2.18.*.*", ParseStrictness::Strict).is_err()); + } + #[test] fn issue_bracket_printing() { let v = VersionSpec::from_str("(>=1,<2)|>3", ParseStrictness::Lenient).unwrap(); diff --git a/crates/rattler_conda_types/src/version_spec/parse.rs b/crates/rattler_conda_types/src/version_spec/parse.rs index c534e5a53..03a3bb153 100644 --- a/crates/rattler_conda_types/src/version_spec/parse.rs +++ b/crates/rattler_conda_types/src/version_spec/parse.rs @@ -221,12 +221,14 @@ fn logical_constraint_parser( } // The version ends in a wildcard pattern ( - "*" | ".*", + version_remainder, Some(VersionOperators::Range( RangeOperator::GreaterEquals | RangeOperator::Greater, )), Lenient, - ) => VersionOperators::Range(RangeOperator::GreaterEquals), + ) if is_star_or_star_dot_star(version_remainder) => { + VersionOperators::Range(RangeOperator::GreaterEquals) + } ( "*" | ".*", Some(VersionOperators::Exact(EqualityOperator::NotEquals)), @@ -236,7 +238,9 @@ fn logical_constraint_parser( // even in strict mode we allow this. VersionOperators::StrictRange(StrictRangeOperator::NotStartsWith) } - ("*" | ".*", Some(op), Lenient) => { + (version_remainder, Some(op), Lenient) + if is_star_or_star_dot_star(version_remainder) => + { // In lenient mode we simply ignore the glob. op } @@ -307,6 +311,18 @@ pub fn looks_like_infinite_starts_with(input: &str) -> bool { false } +/// Returns true if the input is `*` or a sequence of `.*`. +pub fn is_star_or_star_dot_star(input: &str) -> bool { + if input == "*" { + return true; + } + let mut input = input; + while let Some(rest) = input.strip_suffix(".*") { + input = rest; + } + input.is_empty() +} + /// Parses a version constraint. pub fn constraint_parser( strictness: ParseStrictness,