Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions crates/pixi_build_backend/src/dependencies.rs
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,7 @@ fn convert_nameless_matchspec(spec: NamelessMatchSpec) -> pbt::BinaryPackageSpec
sha256: spec.sha256,
url: spec.url,
license: spec.license,
condition: spec.condition,
}
}

Expand Down
30 changes: 28 additions & 2 deletions crates/pixi_build_backend/src/specs_conversion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,7 @@ fn binary_package_spec_to_package_dependency(
sha256,
url,
license,
condition,
} = binary_spec;

// If the version is "*" and no other constraints are present, treat it as None
Expand All @@ -247,8 +248,9 @@ fn binary_package_spec_to_package_dependency(
&sha256,
&url,
&license,
&condition,
) {
(None, None, None, None, None, None, None, None, None) => {
(None, None, None, None, None, None, None, None, None, None) => {
version.filter(|v| v != &rattler_conda_types::VersionSpec::Any)
}
_ => Some(version.unwrap_or(rattler_conda_types::VersionSpec::Any)),
Expand All @@ -268,7 +270,7 @@ fn binary_package_spec_to_package_dependency(
sha256,
url,
license,
condition: None,
condition,
track_features: None,
flags: None,
license_family: None,
Expand Down Expand Up @@ -492,6 +494,30 @@ mod test {
assert_eq!(match_spec.to_string(), "python");
}

#[test]
fn test_binary_package_conversion_preserves_condition() {
use rattler_conda_types::{MatchSpecCondition, ParseMatchSpecOptions, RepodataRevision};

let name = PackageName::new_unchecked("numpy");
let condition = MatchSpecCondition::MatchSpec(Box::new(
MatchSpec::from_str(
"python >=3.10",
ParseMatchSpecOptions::lenient().with_repodata_revision(RepodataRevision::V3),
)
.unwrap(),
));
let spec = BinaryPackageSpec {
version: Some("*".parse().unwrap()),
condition: Some(condition.clone()),
..BinaryPackageSpec::default()
};
let match_spec = binary_package_spec_to_package_dependency(name, spec);
let PackageDependency::Binary(match_spec) = match_spec else {
panic!("expected binary dependency");
};
assert_eq!(match_spec.condition, Some(condition));
}

/// Regression test for <https://github.com/prefix-dev/pixi/issues/4526>:
/// `version = "*"` combined with a `build` constraint must preserve both
/// fields so the resulting `MatchSpec` round-trips correctly through its
Expand Down
7 changes: 6 additions & 1 deletion crates/pixi_build_backend/src/traits/package_spec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ impl PackageSpec for pbt::PackageSpec {
sha256,
url,
license,
condition,
} = spec;

version == &Some(rattler_conda_types::VersionSpec::Any)
Expand All @@ -75,6 +76,7 @@ impl PackageSpec for pbt::PackageSpec {
&& sha256.is_none()
&& url.is_none()
&& license.is_none()
&& condition.is_none()
}
_ => false,
}
Expand Down Expand Up @@ -131,7 +133,7 @@ impl BinarySpecExt for pbt::BinaryPackageSpec {
license: self.license.clone(),
extras: None,
namespace: None,
condition: None,
condition: self.condition.clone(),
track_features: None,
flags: None,
license_family: None,
Expand Down Expand Up @@ -166,6 +168,7 @@ mod tests {
sha256: None,
url: None,
license: None,
condition: None,
};

let package_spec = pbt::PackageSpec::Binary(binary_spec);
Expand Down Expand Up @@ -199,6 +202,7 @@ mod tests {
sha256: None,
url: None,
license: None,
condition: None,
};

let package_spec = pbt::PackageSpec::Binary(binary_spec);
Expand Down Expand Up @@ -230,6 +234,7 @@ mod tests {
sha256: None,
url: None,
license: None,
condition: None,
};

let package_spec = pbt::PackageSpec::Binary(binary_spec);
Expand Down
2 changes: 2 additions & 0 deletions crates/pixi_build_backend/src/variants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ pub fn can_be_used_as_variant(spec: &pbt::PackageSpec) -> bool {
sha256,
url,
license,
condition,
} = spec;

version == &Some(VersionSpec::Any)
Expand All @@ -33,6 +34,7 @@ pub fn can_be_used_as_variant(spec: &pbt::PackageSpec) -> bool {
&& sha256.is_none()
&& url.is_none()
&& license.is_none()
&& condition.is_none()
}
_ => false,
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,7 @@ fn convert_package_spec_to_v1(spec: &PackageSpec) -> PbtPackageSpec {
sha256: None,
url: None,
license: None,
condition: None,
})
}
PackageSpec::Source(source_spec) => {
Expand Down
1 change: 1 addition & 0 deletions crates/pixi_build_backend_passthrough/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -405,6 +405,7 @@ fn is_star_requirement(spec: &PackageSpec) -> bool {
sha256: None,
url: None,
license: None,
condition: None,
} => version
.as_ref()
.is_none_or(|v| matches!(v, VersionSpec::Any)),
Expand Down
6 changes: 5 additions & 1 deletion crates/pixi_build_type_conversions/src/project_model.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,13 @@ fn to_pixi_spec_v1(
build,
build_number,
extras: None,
flags: None,
subdir,
namespace: None,
license,
license_family: None,
condition: None,
track_features: None,
} = source
else {
unimplemented!(
Expand Down Expand Up @@ -103,7 +106,7 @@ fn to_pixi_spec_v1(
// These are currently explicitly ignored in the conversion
namespace: _,
extras: _,
condition: _,
condition,
track_features: _,
flags: _,
license_family: _,
Expand All @@ -119,6 +122,7 @@ fn to_pixi_spec_v1(
sha256,
url,
license,
condition,
})
}
};
Expand Down
13 changes: 12 additions & 1 deletion crates/pixi_build_types/src/project_model.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@
//! older pixi TOMLs keep loading, we can send them to the backend.
use ordermap::OrderMap;
use pixi_stable_hash::{IsDefault, StableHashBuilder};
use rattler_conda_types::{BuildNumber, BuildNumberSpec, StringMatcher, Version, VersionSpec};
use rattler_conda_types::{
BuildNumber, BuildNumberSpec, MatchSpecCondition, StringMatcher, Version, VersionSpec,
};
use rattler_digest::{Md5, Md5Hash, Sha256, Sha256Hash, serde::SerializableHash};
use serde::{Deserialize, Serialize};
use serde_with::{DeserializeFromStr, DisplayFromStr, SerializeDisplay, serde_as};
Expand Down Expand Up @@ -485,6 +487,9 @@ pub struct BinaryPackageSpec {
pub url: Option<Url>,
/// The license of the package
pub license: Option<String>,
/// The condition under which this match spec applies.
#[cfg_attr(feature = "schemars", schemars(with = "Option<serde_json::Value>"))]
pub condition: Option<MatchSpecCondition>,
}

impl From<VersionSpec> for BinaryPackageSpec {
Expand Down Expand Up @@ -533,6 +538,9 @@ impl std::fmt::Debug for BinaryPackageSpec {
if let Some(sha256) = &self.sha256 {
debug_struct.field("sha256", &format!("{sha256:x}"));
}
if let Some(condition) = &self.condition {
debug_struct.field("condition", condition);
}

debug_struct.finish()
}
Expand Down Expand Up @@ -837,12 +845,14 @@ impl Hash for BinaryPackageSpec {
/// field configurations produce different hashes while maintaining
/// forward/backward compatibility.
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
let condition = self.condition.as_ref().map(ToString::to_string);
StableHashBuilder::<H>::new()
.field("build", &self.build)
.field("build_number", &self.build_number)
.field("channel", &self.channel)
.field("file_name", &self.file_name)
.field("license", &self.license)
.field("condition", &condition)
.field("md5", &self.md5)
.field("sha256", &self.sha256)
.field("subdir", &self.subdir)
Expand Down Expand Up @@ -998,6 +1008,7 @@ mod tests {
sha256: None,
url: None,
license: None,
condition: None,
};
let hash2 = calculate_hash(&spec2);

Expand Down
18 changes: 12 additions & 6 deletions crates/pixi_cli/src/global/global_specs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@ use pixi_config::pixi_home;
use pixi_consts::consts;
use pixi_global::project::FromMatchSpecError;
use pixi_spec::{PixiSpec, Subdirectory, SubdirectoryError};
use rattler_conda_types::{ChannelConfig, MatchSpec, ParseMatchSpecError, ParseStrictness};
use rattler_conda_types::{
ChannelConfig, MatchSpec, ParseMatchSpecError, ParseMatchSpecOptions, RepodataRevision,
};
use typed_path::Utf8NativePathBuf;

use crate::has_specs::HasSpecs;
Expand Down Expand Up @@ -185,11 +187,15 @@ impl GlobalSpecs {
self.specs
.iter()
.map(|spec_str| {
let name = MatchSpec::from_str(spec_str, ParseStrictness::Lenient)?
.name
.as_exact()
.cloned()
.ok_or(GlobalSpecsConversionError::NameRequired)?;
let name = MatchSpec::from_str(
spec_str,
ParseMatchSpecOptions::lenient()
.with_repodata_revision(RepodataRevision::V3),
)?
.name
.as_exact()
.cloned()
.ok_or(GlobalSpecsConversionError::NameRequired)?;
Ok(pixi_global::project::GlobalSpec::new(
name,
pixi_spec.clone(),
Expand Down
9 changes: 6 additions & 3 deletions crates/pixi_cli/src/has_specs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use miette::IntoDiagnostic;
use pep508_rs::Requirement;
use pixi_core::Workspace;
use pixi_pypi_spec::PypiPackageName;
use rattler_conda_types::{MatchSpec, PackageName, ParseStrictness};
use rattler_conda_types::{MatchSpec, PackageName, ParseMatchSpecOptions, RepodataRevision};

/// A trait to facilitate extraction of packages data from arguments
pub(crate) trait HasSpecs {
Expand All @@ -14,8 +14,11 @@ pub(crate) trait HasSpecs {
self.packages()
.iter()
.map(|package| {
let spec =
MatchSpec::from_str(package, ParseStrictness::Lenient).into_diagnostic()?;
let spec = MatchSpec::from_str(
package,
ParseMatchSpecOptions::lenient().with_repodata_revision(RepodataRevision::V3),
)
.into_diagnostic()?;
let name = spec.name.as_exact().cloned().ok_or_else(|| {
miette::miette!("could not find exact package name in MatchSpec {}", spec)
})?;
Expand Down
8 changes: 6 additions & 2 deletions crates/pixi_cli/src/match_spec_or_path.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ use std::{
use dunce::canonicalize;
use pixi_spec::PathSpec;
use rattler_conda_types::{
MatchSpec, PackageName, ParseStrictness, package::CondaArchiveIdentifier,
MatchSpec, PackageName, ParseMatchSpecOptions, RepodataRevision,
package::CondaArchiveIdentifier,
};

/// Represents either a regular conda MatchSpec or a filesystem path to a conda artifact.
Expand Down Expand Up @@ -78,7 +79,10 @@ impl FromStr for MatchSpecOrPath {
})));
}

match MatchSpec::from_str(value, ParseStrictness::Lenient) {
match MatchSpec::from_str(
value,
ParseMatchSpecOptions::lenient().with_repodata_revision(RepodataRevision::V3),
) {
Ok(spec) => Ok(Self::MatchSpec(Box::new(spec))),
Err(parse_err) => {
if looks_like_path(value) {
Expand Down
10 changes: 10 additions & 0 deletions crates/pixi_command_dispatcher/src/build/conversion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,11 @@ pub fn from_source_spec_v1(source: SourcePackageSpec) -> pixi_spec::SourceSpec {
subdir,
license,
extras: None,
flags: None,
namespace: None,
license_family: None,
condition: None,
track_features: None,
}
}

Expand Down Expand Up @@ -93,6 +96,7 @@ pub fn from_binary_spec_v1(spec: BinaryPackageSpec) -> pixi_spec::BinarySpec {
md5: None,
sha256: None,
license: None,
condition: None,
url: _,
} => BinarySpec::Version(version),
BinaryPackageSpec {
Expand All @@ -105,15 +109,21 @@ pub fn from_binary_spec_v1(spec: BinaryPackageSpec) -> pixi_spec::BinarySpec {
md5,
sha256,
license,
condition,
url: _,
} => BinarySpec::DetailedVersion(Box::new(DetailedSpec {
version,
build,
build_number,
file_name,
extras: None,
flags: None,
channel: channel.map(NamedChannelOrUrl::Url),
subdir,
license,
license_family: None,
condition,
track_features: None,
md5,
sha256,
})),
Expand Down
Loading
Loading