From e6cf81998c9216ed7531fbf14581e437b7801997 Mon Sep 17 00:00:00 2001 From: Bas Zalmstra <4995967+baszalmstra@users.noreply.github.com> Date: Tue, 22 Jul 2025 00:26:14 +0200 Subject: [PATCH 01/11] feat: implement extras with conditional dependencies --- Cargo.lock | 3 +- Cargo.toml | 2 +- crates/rattler-bin/src/commands/create.rs | 4 +- .../src/repo_data_record.rs | 2 +- crates/rattler_solve/Cargo.toml | 2 +- crates/rattler_solve/src/libsolv_c/mod.rs | 2 +- .../src/resolvo/conda_sorting.rs | 49 +- crates/rattler_solve/src/resolvo/mod.rs | 810 ++++----- crates/rattler_solve/tests/backends.rs | 355 +--- crates/rattler_solve/tests/backends.rs~ | 1446 +++++++++++++++++ crates/rattler_solve/tests/sorting.rs | 4 +- .../noarch/repodata.json | 577 +------ 12 files changed, 2002 insertions(+), 1254 deletions(-) create mode 100644 crates/rattler_solve/tests/backends.rs~ diff --git a/Cargo.lock b/Cargo.lock index 83cac4deb4..8cded35549 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5155,8 +5155,7 @@ dependencies = [ [[package]] name = "resolvo" version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dba027c8e5dd4b5e5a690cfcfb3900d5ffe6985adb048cbd111d5aa596a6c0c8" +source = "git+https://github.com/baszalmstra/resolvo?branch=condition-dependencies#6cc440f9f92a0a88dc323f7c1f653ba85deddbe1" dependencies = [ "ahash", "bitvec", diff --git a/Cargo.toml b/Cargo.toml index c40576758f..9031247d1f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -126,7 +126,7 @@ regex = "1.11.1" reqwest = { version = "0.12.15", default-features = false } reqwest-middleware = "0.4.2" reqwest-retry = "0.7.0" -resolvo = { version = "0.9.1" } +resolvo = { git = "https://github.com/baszalmstra/resolvo", branch ="condition-dependencies" } # hold back at 0.4.0 until `reqwest-retry` is updated retry-policies = { version = "0.4.0", default-features = false } rmp-serde = { version = "1.3.0" } diff --git a/crates/rattler-bin/src/commands/create.rs b/crates/rattler-bin/src/commands/create.rs index a55760f4a3..0d08ec6320 100644 --- a/crates/rattler-bin/src/commands/create.rs +++ b/crates/rattler-bin/src/commands/create.rs @@ -295,7 +295,7 @@ pub async fn create(opt: Opt) -> anyhow::Result<()> { if transaction.operations.is_empty() { println!("No operations necessary"); } else { - print_transaction(&transaction, solver_result.features); + print_transaction(&transaction, solver_result.extras); } return Ok(()); @@ -326,7 +326,7 @@ pub async fn create(opt: Opt) -> anyhow::Result<()> { console::style(console::Emoji("✔", "")).green(), install_start.elapsed() ); - print_transaction(&result.transaction, solver_result.features); + print_transaction(&result.transaction, solver_result.extras); } Ok(()) diff --git a/crates/rattler_conda_types/src/repo_data_record.rs b/crates/rattler_conda_types/src/repo_data_record.rs index 82ef880106..27a3fcd273 100644 --- a/crates/rattler_conda_types/src/repo_data_record.rs +++ b/crates/rattler_conda_types/src/repo_data_record.rs @@ -40,5 +40,5 @@ pub struct SolverResult { /// The records that are part of the solution to the solver task. pub records: Vec, /// The features of the records that are part of the solution to the solver task. - pub features: HashMap>, + pub extras: HashMap>, } diff --git a/crates/rattler_solve/Cargo.toml b/crates/rattler_solve/Cargo.toml index e5d5684f6c..91fac1f220 100644 --- a/crates/rattler_solve/Cargo.toml +++ b/crates/rattler_solve/Cargo.toml @@ -41,7 +41,7 @@ default = ["resolvo"] libsolv_c = ["dep:rattler_libsolv_c", "dep:libc"] resolvo_diagnostics = ["resolvo?/diagnostics"] resolvo = ["dep:resolvo", "dep:futures"] -experimental_extras = [] +experimental_extras = ["rattler_conda_types/experimental_extras"] [[bench]] name = "bench" diff --git a/crates/rattler_solve/src/libsolv_c/mod.rs b/crates/rattler_solve/src/libsolv_c/mod.rs index b643b2e0e9..d9688477d1 100644 --- a/crates/rattler_solve/src/libsolv_c/mod.rs +++ b/crates/rattler_solve/src/libsolv_c/mod.rs @@ -287,7 +287,7 @@ impl super::SolverImpl for Solver { Ok(SolverResult { records: required_records, - features: HashMap::new(), + extras: HashMap::new(), }) } } diff --git a/crates/rattler_solve/src/resolvo/conda_sorting.rs b/crates/rattler_solve/src/resolvo/conda_sorting.rs index d1444541e4..41ed7a14cb 100644 --- a/crates/rattler_solve/src/resolvo/conda_sorting.rs +++ b/crates/rattler_solve/src/resolvo/conda_sorting.rs @@ -94,7 +94,7 @@ impl<'a, 'repo> SolvableSorter<'a, 'repo> { }; // Otherwise, select the variant with the highest version - match (self.strategy, a_record.version().cmp(b_record.version())) { + match (self.strategy, a_record.version().cmp(&b_record.version())) { (CompareStrategy::Default, Ordering::Greater) | (CompareStrategy::LowestVersion, Ordering::Less) => return Ordering::Less, (CompareStrategy::Default, Ordering::Less) @@ -191,7 +191,7 @@ impl<'a, 'repo> SolvableSorter<'a, 'repo> { Err(_) => return, }; - for requirement in &known.requirements { + for requirement in known.requirements.iter().map(|r| &r.requirement) { let version_set_id = match requirement { // Ignore union requirements, these do not occur in the conda ecosystem // currently @@ -359,29 +359,32 @@ pub(super) fn find_highest_version( let pool = &solver.provider().pool; - candidates + let mut highest_version = None; + for record in candidates .iter() .map(|id| &pool.resolve_solvable(*id).record) - .fold(None, |init, record| { - Some(init.map_or_else( - || { - ( - record.version().clone(), - !record.track_features().is_empty(), - ) - }, - |(version, has_tracked_features)| { - if &version < record.version() { - ( - record.version().clone(), - !record.track_features().is_empty(), - ) - } else { - (version, has_tracked_features) - } - }, - )) - }) + { + let (version, has_tracked_features) = match record { + SolverPackageRecord::Record(record) => ( + record.package_record.version.version(), + !record.package_record.track_features.is_empty(), + ), + SolverPackageRecord::VirtualPackage(record) => (&record.version, false), + SolverPackageRecord::Extra { .. } => continue, + }; + highest_version = highest_version.map_or_else( + || Some((version.clone(), has_tracked_features)), + |(highest_version, current_has_tracked_features)| { + if version > &highest_version { + Some((version.clone(), has_tracked_features)) + } else { + Some((highest_version, current_has_tracked_features)) + } + }, + ); + } + + highest_version }) .clone() } diff --git a/crates/rattler_solve/src/resolvo/mod.rs b/crates/rattler_solve/src/resolvo/mod.rs index 353ba678f7..6b038ffdc7 100644 --- a/crates/rattler_solve/src/resolvo/mod.rs +++ b/crates/rattler_solve/src/resolvo/mod.rs @@ -6,22 +6,21 @@ use std::{ collections::{HashMap, HashSet}, fmt::{Display, Formatter}, marker::PhantomData, - ops::Deref, }; use chrono::{DateTime, Utc}; use conda_sorting::SolvableSorter; use itertools::Itertools; use rattler_conda_types::{ - package::ArchiveType, version_spec::EqualityOperator, BuildNumberSpec, GenericVirtualPackage, - MatchSpec, Matches, NamelessMatchSpec, OrdOperator, PackageName, PackageRecord, - ParseMatchSpecError, ParseStrictness, RepoDataRecord, SolverResult, StringMatcher, VersionSpec, + package::ArchiveType, GenericVirtualPackage, MatchSpec, Matches, NamelessMatchSpec, + PackageName, ParseMatchSpecError, ParseStrictness, RepoDataRecord, SolverResult, }; use resolvo::{ utils::{Pool, VersionSet}, - Candidates, Dependencies, DependencyProvider, HintDependenciesAvailable, Interner, - KnownDependencies, NameId, Problem, Requirement, SolvableId, Solver as LibSolvRsSolver, - SolverCache, StringId, UnsolvableOrCancelled, VersionSetId, VersionSetUnionId, + Candidates, Condition, ConditionId, ConditionalRequirement, Dependencies, DependencyProvider, + HintDependenciesAvailable, Interner, KnownDependencies, NameId, Problem, SolvableId, + Solver as LibSolvRsSolver, SolverCache, StringId, UnsolvableOrCancelled, VersionSetId, + VersionSetUnionId, }; use crate::{ @@ -50,52 +49,35 @@ impl<'a> FromIterator<&'a RepoDataRecord> for RepoData<'a> { impl<'a> SolverRepoData<'a> for RepoData<'a> {} /// Wrapper around `MatchSpec` so that we can use it in the `resolvo` pool +#[allow(clippy::large_enum_variant)] #[derive(Debug, Clone, Eq, PartialEq, Hash)] -pub struct SolverMatchSpec<'a> { - inner: NamelessMatchSpec, - feature: Option, - _marker: PhantomData<&'a PackageRecord>, -} +pub enum SolverMatchSpec<'a> { + /// Represents a requirement on another package. + MatchSpec(NamelessMatchSpec), -impl<'a> SolverMatchSpec<'a> { - /// Returns a reference to this match spec with the given feature enabled - pub fn with_feature(&self, feature: String) -> SolverMatchSpec<'a> { - Self { - inner: self.inner.clone(), - feature: Some(feature), - _marker: self._marker, - } - } + /// The name already uniquely identifies a single package. So we don't need + /// any special "spec". here. + Extra, - /// Returns a mutable reference to this match spec after enabling the given - /// feature - pub fn set_feature(&mut self, feature: String) -> &SolverMatchSpec<'a> { - self.feature = Some(feature); - self - } + /// A helper variant to make sure we can add a lifetime to this enum. + _Phantom(PhantomData<&'a ()>), } impl From for SolverMatchSpec<'_> { fn from(value: NamelessMatchSpec) -> Self { - Self { - inner: value, - feature: None, - _marker: PhantomData, - } + SolverMatchSpec::MatchSpec(value) } } impl Display for SolverMatchSpec<'_> { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", self.inner) - } -} - -impl Deref for SolverMatchSpec<'_> { - type Target = NamelessMatchSpec; - - fn deref(&self) -> &Self::Target { - &self.inner + match self { + SolverMatchSpec::MatchSpec(spec) => { + write!(f, "{spec}") + } + SolverMatchSpec::Extra => Ok(()), + SolverMatchSpec::_Phantom(_) => unreachable!(), + } } } @@ -109,11 +91,18 @@ pub enum SolverPackageRecord<'a> { /// Represents a record from the repodata Record(&'a RepoDataRecord), - /// Represents a record with a specific feature enabled - RecordWithFeature(&'a RepoDataRecord, String), - /// Represents a virtual package. VirtualPackage(&'a GenericVirtualPackage), + + /// Represents a named extra for a particular package name. e.g. + /// `numpy[blas]` + Extra { + /// The name of the package + package: PackageName, + + /// The extra to activate in the package + extra: String, + }, } impl PartialOrd for SolverPackageRecord<'_> { @@ -126,7 +115,8 @@ impl Ord for SolverPackageRecord<'_> { fn cmp(&self, other: &Self) -> Ordering { self.name() .cmp(other.name()) - .then_with(|| self.version().cmp(other.version())) + .then_with(|| self.extra().cmp(&other.extra())) + .then_with(|| self.version().cmp(&other.version())) .then_with(|| self.build_number().cmp(&other.build_number())) .then_with(|| self.timestamp().cmp(&other.timestamp())) } @@ -135,47 +125,46 @@ impl Ord for SolverPackageRecord<'_> { impl SolverPackageRecord<'_> { fn name(&self) -> &PackageName { match self { - SolverPackageRecord::Record(rec) | SolverPackageRecord::RecordWithFeature(rec, _) => { - &rec.package_record.name - } + SolverPackageRecord::Record(rec) => &rec.package_record.name, + SolverPackageRecord::Extra { package, .. } => package, SolverPackageRecord::VirtualPackage(rec) => &rec.name, } } - fn version(&self) -> &rattler_conda_types::Version { + fn extra(&self) -> Option<&String> { match self { - SolverPackageRecord::Record(rec) | SolverPackageRecord::RecordWithFeature(rec, _) => { - rec.package_record.version.version() - } - SolverPackageRecord::VirtualPackage(rec) => &rec.version, + SolverPackageRecord::Extra { extra, .. } => Some(extra), + SolverPackageRecord::Record(_) | SolverPackageRecord::VirtualPackage(_) => None, + } + } + + fn version(&self) -> Option<&rattler_conda_types::Version> { + match self { + SolverPackageRecord::Record(rec) => Some(rec.package_record.version.version()), + SolverPackageRecord::VirtualPackage(rec) => Some(&rec.version), + SolverPackageRecord::Extra { .. } => None, } } fn track_features(&self) -> &[String] { const EMPTY: [String; 0] = []; match self { - SolverPackageRecord::Record(rec) | SolverPackageRecord::RecordWithFeature(rec, _) => { - &rec.package_record.track_features - } - SolverPackageRecord::VirtualPackage(_rec) => &EMPTY, + SolverPackageRecord::Record(rec) => &rec.package_record.track_features, + SolverPackageRecord::Extra { .. } | SolverPackageRecord::VirtualPackage(..) => &EMPTY, } } fn build_number(&self) -> u64 { match self { - SolverPackageRecord::Record(rec) | SolverPackageRecord::RecordWithFeature(rec, _) => { - rec.package_record.build_number - } - SolverPackageRecord::VirtualPackage(_rec) => 0, + SolverPackageRecord::Record(rec) => rec.package_record.build_number, + SolverPackageRecord::Extra { .. } | SolverPackageRecord::VirtualPackage(..) => 0, } } fn timestamp(&self) -> Option<&chrono::DateTime> { match self { - SolverPackageRecord::Record(rec) | SolverPackageRecord::RecordWithFeature(rec, _) => { - rec.package_record.timestamp.as_ref() - } - SolverPackageRecord::VirtualPackage(_rec) => None, + SolverPackageRecord::Record(rec) => rec.package_record.timestamp.as_ref(), + SolverPackageRecord::Extra { .. } | SolverPackageRecord::VirtualPackage(..) => None, } } } @@ -186,8 +175,8 @@ impl Display for SolverPackageRecord<'_> { SolverPackageRecord::Record(rec) => { write!(f, "{}", &rec.package_record) } - SolverPackageRecord::RecordWithFeature(rec, feature) => { - write!(f, "{}[{}]", &rec.package_record, feature) + SolverPackageRecord::Extra { package, extra } => { + write!(f, "{}[{}]", package.as_normalized(), extra) } SolverPackageRecord::VirtualPackage(rec) => { write!(f, "{rec}") @@ -199,18 +188,24 @@ impl Display for SolverPackageRecord<'_> { /// Represents the type of name that is being used in the pool. #[derive(Debug, Clone, Eq, PartialEq, Hash)] pub enum NameType { - /// A package name without a feature. + /// A simple package Base(String), - /// A package name with a feature. - BaseWithFeature(String, String), + /// An extra of a package (e.g. `numpy[blas]`) + Extra { + /// The package name + package: String, + + /// The extra to activate. + extra: String, + }, } impl Display for NameType { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { match self { NameType::Base(name) => write!(f, "{name}"), - NameType::BaseWithFeature(name, feature) => write!(f, "{name}[{feature}]"), + NameType::Extra { package, extra } => write!(f, "{package}[{extra}]"), } } } @@ -218,14 +213,20 @@ impl Display for NameType { impl Ord for NameType { fn cmp(&self, other: &Self) -> std::cmp::Ordering { match (self, other) { - // Compare names first - (NameType::Base(name1), NameType::Base(name2)) - | (NameType::BaseWithFeature(name1, _), NameType::BaseWithFeature(name2, _)) => { - name1.cmp(name2) - } - // WithoutFeature comes before WithFeature - (NameType::Base(_), NameType::BaseWithFeature(_, _)) => std::cmp::Ordering::Greater, - (NameType::BaseWithFeature(_, _), NameType::Base(_)) => std::cmp::Ordering::Less, + // Compare names first, then extras + (NameType::Base(name1), NameType::Base(name2)) => name1.cmp(name2), + ( + NameType::Extra { + package: a, + extra: extra_a, + }, + NameType::Extra { + package: b, + extra: extra_b, + }, + ) => a.cmp(b).then_with(|| extra_a.cmp(extra_b)), + (NameType::Base(_), NameType::Extra { .. }) => std::cmp::Ordering::Greater, + (NameType::Extra { .. }, NameType::Base(_)) => std::cmp::Ordering::Less, } } } @@ -236,9 +237,9 @@ impl PartialOrd for NameType { } } -impl From<&str> for NameType { - fn from(value: &str) -> Self { - NameType::Base(value.to_owned()) +impl From<&PackageName> for NameType { + fn from(value: &PackageName) -> Self { + NameType::Base(value.as_normalized().to_owned()) } } @@ -249,8 +250,11 @@ impl From<&str> for NameType { pub struct CondaDependencyProvider<'a> { /// The pool that deduplicates data used by the provider. pub pool: Pool, NameType>, + conditions: RefCell>, + name_to_condition: RefCell>, - records: HashMap, + /// Holds all the cached candidates for each package name. + records: HashMap, matchspec_to_highest_version: RefCell>>, @@ -279,21 +283,25 @@ impl<'a> CondaDependencyProvider<'a> { strategy: SolveStrategy, ) -> Result { let pool = Pool::default(); - let mut records: HashMap = HashMap::default(); + let mut records: HashMap = HashMap::default(); // Add virtual packages to the records for virtual_package in virtual_packages { - let name = pool.intern_package_name(virtual_package.name.as_normalized()); + let name = pool.intern_package_name(&virtual_package.name); let solvable = pool.intern_solvable(name, SolverPackageRecord::VirtualPackage(virtual_package)); - records.entry(name).or_default().candidates.push(solvable); + records + .entry(virtual_package.name.as_normalized().to_owned()) + .or_default() + .candidates + .push(solvable); } // Compute the direct dependencies let direct_dependencies = match_specs .iter() .filter_map(|spec| spec.name.as_ref()) - .map(|name| pool.intern_package_name(name.as_normalized())) + .map(|name| pool.intern_package_name(name)) .collect(); // TODO: Normalize these channel names to urls so we can compare them correctly. @@ -375,142 +383,127 @@ impl<'a> CondaDependencyProvider<'a> { } for record in ordered_repodata { - let package_name = - pool.intern_package_name(record.package_record.name.as_normalized()); + let package_name = pool.intern_package_name(&record.package_record.name); let solvable_id = pool.intern_solvable(package_name, SolverPackageRecord::Record(record)); - // Collect all candidates first - let mut all_entries = vec![(package_name, solvable_id)]; + // Update records with all entries in a single mutable borrow + let candidates = records + .entry(record.package_record.name.as_normalized().to_owned()) + .or_default(); + candidates.candidates.push(solvable_id); - // Add feature-enabled solvables - for feature in record.package_record.extra_depends.keys() { - let package_name_with_feature = - pool.intern_package_name(NameType::BaseWithFeature( - record.package_record.name.as_normalized().to_owned(), - feature.clone(), - )); - let feature_solvable = pool.intern_solvable( - package_name_with_feature, - SolverPackageRecord::RecordWithFeature(record, feature.clone()), - ); - let package_name_with_feature = - pool.intern_package_name(NameType::BaseWithFeature( - record.package_record.name.as_normalized().to_owned(), - feature.clone(), + // Filter out any records that are newer than a specific date. + match (&exclude_newer, &record.package_record.timestamp) { + (Some(exclude_newer), Some(record_timestamp)) + if record_timestamp > exclude_newer => + { + let reason = pool.intern_string(format!( + "the package is uploaded after the cutoff date of {exclude_newer}" )); - - all_entries.push((package_name_with_feature, feature_solvable)); - } - - // Update records with all entries in a single mutable borrow - for (pkg_name, solvable) in all_entries { - let candidates = records.entry(pkg_name).or_default(); - candidates.candidates.push(solvable); - - // Filter out any records that are newer than a specific date. - match (&exclude_newer, &record.package_record.timestamp) { - (Some(exclude_newer), Some(record_timestamp)) - if record_timestamp > exclude_newer => - { - let reason = pool.intern_string(format!( - "the package is uploaded after the cutoff date of {exclude_newer}" - )); - candidates.excluded.push((solvable, reason)); - } - _ => {} + candidates.excluded.push((solvable_id, reason)); } + _ => {} + } - // Add to excluded when package is not in the specified channel. - if !channel_specific_specs.is_empty() { - if let Some(spec) = channel_specific_specs.iter().find(|&&spec| { - spec.name - .as_ref() - .expect("expecting a name") - .as_normalized() - == record.package_record.name.as_normalized() - }) { - // Check if the spec has a channel, and compare it to the repodata - // channel - if let Some(spec_channel) = &spec.channel { - if record.channel.as_ref() != Some(&spec_channel.canonical_name()) { - tracing::debug!("Ignoring {} {} because it was not requested from that channel.", &record.package_record.name.as_normalized(), match &record.channel { + // Add to excluded when package is not in the specified channel. + if !channel_specific_specs.is_empty() { + if let Some(spec) = channel_specific_specs.iter().find(|&&spec| { + spec.name + .as_ref() + .expect("expecting a name") + .as_normalized() + == record.package_record.name.as_normalized() + }) { + // Check if the spec has a channel, and compare it to the repodata + // channel + if let Some(spec_channel) = &spec.channel { + if record.channel.as_ref() != Some(&spec_channel.canonical_name()) { + tracing::debug!("Ignoring {} {} because it was not requested from that channel.", &record.package_record.name.as_normalized(), match &record.channel { Some(channel) => format!("from {}", &channel), None => "without a channel".to_string(), }); - // 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() - .unwrap_or(spec_channel.base_url.to_string()) - ); - candidates - .excluded - .push((solvable, pool.intern_string(message))); - continue; - } + // 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() + .unwrap_or(spec_channel.base_url.to_string()) + ); + candidates + .excluded + .push((solvable_id, pool.intern_string(message))); + continue; } } } + } - // Enforce channel priority - if let (Some(first_channel), ChannelPriority::Strict) = ( - package_name_found_in_channel - .get(record.package_record.name.as_normalized()), - channel_priority, - ) { - // Add the record to the excluded list when it is from a different channel. - if first_channel != &&record.channel { - if let Some(channel) = &record.channel { - tracing::debug!( - "Ignoring '{}' from '{}' because of strict channel priority.", - &record.package_record.name.as_normalized(), - channel - ); - candidates.excluded.push(( - solvable, - pool.intern_string(format!( - "due to strict channel priority not using this option from: '{channel}'", - )), - )); - } else { - tracing::debug!( + // Enforce channel priority + if let (Some(first_channel), ChannelPriority::Strict) = ( + package_name_found_in_channel.get(record.package_record.name.as_normalized()), + channel_priority, + ) { + // Add the record to the excluded list when it is from a different channel. + if first_channel != &&record.channel { + if let Some(channel) = &record.channel { + tracing::debug!( + "Ignoring '{}' from '{}' because of strict channel priority.", + &record.package_record.name.as_normalized(), + channel + ); + candidates.excluded.push(( + solvable_id, + pool.intern_string(format!( + "due to strict channel priority not using this option from: '{channel}'", + )), + )); + } else { + tracing::debug!( "Ignoring '{}' without a channel because of strict channel priority.", &record.package_record.name.as_normalized(), ); - candidates.excluded.push(( - solvable, - pool.intern_string("due to strict channel priority not using from an unknown channel".to_string()), - )); - } - continue; + candidates.excluded.push(( + solvable_id, + pool.intern_string("due to strict channel priority not using from an unknown channel".to_string()), + )); } - } else { - package_name_found_in_channel.insert( - record.package_record.name.as_normalized().to_string(), - &record.channel, - ); + continue; } + } else { + package_name_found_in_channel.insert( + record.package_record.name.as_normalized().to_string(), + &record.channel, + ); } } } // Add favored packages to the records for favored_record in favored_records { - let name = pool.intern_package_name(favored_record.package_record.name.as_normalized()); + let name = pool.intern_package_name(&favored_record.package_record.name); let solvable = pool.intern_solvable(name, SolverPackageRecord::Record(favored_record)); - let candidates = records.entry(name).or_default(); + let candidates = records + .entry( + favored_record + .package_record + .name + .as_normalized() + .to_owned(), + ) + .or_default(); candidates.candidates.push(solvable); candidates.favored = Some(solvable); } for locked_record in locked_records { - let name = pool.intern_package_name(locked_record.package_record.name.as_normalized()); + let name = pool.intern_package_name(&locked_record.package_record.name); let solvable = pool.intern_solvable(name, SolverPackageRecord::Record(locked_record)); - let candidates = records.entry(name).or_default(); + let candidates = records + .entry(locked_record.package_record.name.as_normalized().to_owned()) + .or_default(); candidates.candidates.push(solvable); candidates.locked = Some(solvable); } @@ -522,6 +515,8 @@ impl<'a> CondaDependencyProvider<'a> { Ok(Self { pool, + conditions: RefCell::default(), + name_to_condition: RefCell::default(), records, matchspec_to_highest_version: RefCell::default(), parse_match_spec_cache: RefCell::default(), @@ -532,8 +527,29 @@ impl<'a> CondaDependencyProvider<'a> { } /// Returns all package names - pub fn package_names(&self) -> impl Iterator + '_ { - self.records.keys().copied() + pub fn package_names(&self) -> impl Iterator + use<'_, 'a> { + self.records + .keys() + .map(|n| self.pool.intern_package_name(NameType::Base(n.to_owned()))) + } + + fn alloc_condition(&self, condition: Condition) -> ConditionId { + let mut conditions = self.conditions.borrow_mut(); + let id = conditions.len(); + conditions.push(condition); + ConditionId::new(id as u32) + } + + fn extra_condition(&self, package: &PackageName, extra: &str) -> ConditionId { + let name_id = self.pool.intern_package_name(NameType::Extra { + package: package.as_normalized().to_owned(), + extra: extra.to_owned(), + }); + let mut name_to_condition = self.name_to_condition.borrow_mut(); + *name_to_condition.entry(name_id).or_insert_with(|| { + let version_set = extra_version_set(&self.pool, package.clone(), extra.to_owned()); + self.alloc_condition(Condition::Requirement(version_set)) + }) } } @@ -562,7 +578,7 @@ impl Interner for CondaDependencyProvider<'_> { let versions = solvables .iter() - .map(|&id| self.pool.resolve_solvable(id).record.version()) + .filter_map(|&id| self.pool.resolve_solvable(id).record.version()) .sorted() .format(" | "); @@ -589,6 +605,10 @@ impl Interner for CondaDependencyProvider<'_> { fn solvable_name(&self, solvable: SolvableId) -> NameId { self.pool.resolve_solvable(solvable).name } + + fn resolve_condition(&self, condition: ConditionId) -> Condition { + self.conditions.borrow()[condition.as_u32() as usize].clone() + } } impl DependencyProvider for CondaDependencyProvider<'_> { @@ -626,108 +646,100 @@ impl DependencyProvider for CondaDependencyProvider<'_> { } async fn get_candidates(&self, name: NameId) -> Option { - self.records.get(&name).cloned() + match self.pool.resolve_package_name(name) { + NameType::Base(name) => self.records.get(name).cloned(), + NameType::Extra { package, extra } => { + // For extras, we need to create a new candidates object + // that contains only the extra solvable. + let extra_solvable = add_extra( + &self.pool, + PackageName::new_unchecked(package), + extra.clone(), + ); + Some(Candidates { + candidates: vec![extra_solvable], + favored: None, + locked: None, + excluded: Vec::new(), + hint_dependencies_available: HintDependenciesAvailable::All, + }) + } + } } async fn get_dependencies(&self, solvable: SolvableId) -> Dependencies { let mut dependencies = KnownDependencies::default(); - // Get the record and any feature that might be enabled - let (record, feature) = match &self.pool.resolve_solvable(solvable).record { - SolverPackageRecord::Record(rec) => (rec, None), - SolverPackageRecord::RecordWithFeature(rec, feature) => (rec, Some(feature)), - SolverPackageRecord::VirtualPackage(_) => return Dependencies::Known(dependencies), + let record = match &self.pool.resolve_solvable(solvable).record { + SolverPackageRecord::Record(rec) => rec, + SolverPackageRecord::Extra { .. } | SolverPackageRecord::VirtualPackage(_) => { + return Dependencies::Known(dependencies) + } }; let mut parse_match_spec_cache = self.parse_match_spec_cache.borrow_mut(); - // If this is a feature-enabled package, add its feature dependencies - if let Some(feature_name) = feature { - // Find the feature's dependencies - if let Some(deps) = record.package_record.extra_depends.get(feature_name) { - // Add each dependency for this feature - for req in deps { - let version_set_id = match parse_match_spec( - &self.pool, - req, - &mut parse_match_spec_cache, - ) { - Ok(version_set_id) => version_set_id, - Err(e) => { - let reason = self.pool.intern_string(format!( - "the optional dependency '{req}' for feature '{feature_name}' failed to parse: {e}" - )); - return Dependencies::Unknown(reason); - } - }; - - dependencies - .requirements - .extend(version_set_id.into_iter().map(Requirement::from)); - } + // Add regular dependencies + for depends in record.package_record.depends.iter() { + let version_set_id = + match parse_match_spec(&self.pool, depends, &mut parse_match_spec_cache) { + Ok(version_set_id) => version_set_id, + Err(e) => { + let reason = self.pool.intern_string(format!( + "the dependency '{depends}' failed to parse: {e}", + )); - // Add a dependency back to the base package with exact version - let base_spec = MatchSpec { - name: Some(record.package_record.name.clone()), - version: Some(VersionSpec::Exact( - EqualityOperator::Equals, - record.package_record.version.version().clone(), - )), - build: Some(StringMatcher::Exact(record.package_record.build.clone())), - build_number: Some(BuildNumberSpec::new( - OrdOperator::Eq, - record.package_record.build_number, - )), - subdir: Some(record.package_record.subdir.clone()), - md5: record.package_record.md5, - sha256: record.package_record.sha256, - extras: None, - ..Default::default() + return Dependencies::Unknown(reason); + } }; - let (name, nameless_spec) = base_spec.into_nameless(); - let name_id = self.pool.intern_package_name( - name.expect("cannot use matchspec without a name") - .as_normalized(), - ); - let version_set_id = self.pool.intern_version_set(name_id, nameless_spec.into()); - dependencies.requirements.push(version_set_id.into()); - } - } else { - // Add regular dependencies - for depends in record.package_record.depends.iter() { - let version_set_id = - match parse_match_spec(&self.pool, depends, &mut parse_match_spec_cache) { - Ok(version_set_id) => version_set_id, - Err(e) => { - let reason = self.pool.intern_string(format!( - "the dependency '{depends}' failed to parse: {e}", - )); + dependencies + .requirements + .extend(version_set_id.into_iter().map(ConditionalRequirement::from)); + } - return Dependencies::Unknown(reason); - } - }; + // Add constraints from the record + for constrains in record.package_record.constrains.iter() { + let version_set_ids = + match parse_match_spec(&self.pool, constrains, &mut parse_match_spec_cache) { + Ok(version_set_id) => version_set_id, + Err(e) => { + let reason = self.pool.intern_string(format!( + "the constrains '{constrains}' failed to parse: {e}", + )); - dependencies - .requirements - .extend(version_set_id.into_iter().map(Requirement::from)); - } + return Dependencies::Unknown(reason); + } + }; + dependencies.constrains.extend(version_set_ids); + } - for constrains in record.package_record.constrains.iter() { - let version_set_id = - match parse_match_spec(&self.pool, constrains, &mut parse_match_spec_cache) { - Ok(version_set_id) => version_set_id, - Err(e) => { - let reason = self.pool.intern_string(format!( - "the constrains '{constrains}' failed to parse: {e}", - )); + // Add extras + for (extra, matchspec) in record + .package_record + .extra_depends + .iter() + .flat_map(|(extra, deps)| deps.iter().map(move |dep| (extra, dep))) + { + let version_set_ids = + match parse_match_spec(&self.pool, matchspec, &mut parse_match_spec_cache) { + Ok(version_set_id) => version_set_id, + Err(e) => { + let reason = self.pool.intern_string(format!( + "the constrains '{matchspec}' failed to parse: {e}", + )); - return Dependencies::Unknown(reason); - } - }; - for version_set_id in version_set_id { - dependencies.constrains.push(version_set_id); - } + return Dependencies::Unknown(reason); + } + }; + + // Add them as conditional requirements (e.g. `numpy; if extra`). + let condition_id = self.extra_condition(&record.package_record.name, extra); + for version_set_id in version_set_ids { + dependencies.requirements.push(ConditionalRequirement { + requirement: version_set_id.into(), + condition: Some(condition_id), + }); } } @@ -741,53 +753,54 @@ impl DependencyProvider for CondaDependencyProvider<'_> { inverse: bool, ) -> Vec { let spec = self.pool.resolve_version_set(version_set); - - candidates - .iter() - .copied() - .filter(|c| { - let record = &self.pool.resolve_solvable(*c).record; - match record { - SolverPackageRecord::Record(rec) => { - // Base package matches if spec matches and no features are required - - spec.matches(*rec) != inverse - } - SolverPackageRecord::RecordWithFeature(rec, feature) => { - // Feature-enabled package matches if spec matches and feature is required - - if spec.matches(*rec) { - if let Some(spec_feature) = &spec.feature { - (*spec_feature == *feature) != inverse - } else { - inverse - } - } else { - inverse - } - } - SolverPackageRecord::VirtualPackage(GenericVirtualPackage { - version, - build_string, - .. - }) => { - if let Some(spec) = spec.version.as_ref() { - if !spec.matches(version) { - return inverse; + match spec { + SolverMatchSpec::MatchSpec(spec) => { + candidates + .iter() + .copied() + .filter(|c| { + let record = &self.pool.resolve_solvable(*c).record; + match record { + SolverPackageRecord::Record(rec) => { + // Base package matches if spec matches and no features are required + spec.matches(*rec) != inverse } - } + SolverPackageRecord::VirtualPackage(GenericVirtualPackage { + version, + build_string, + .. + }) => { + if let Some(spec) = spec.version.as_ref() { + if !spec.matches(version) { + return inverse; + } + } - if let Some(build_match) = spec.build.as_ref() { - if !build_match.matches(build_string) { - return inverse; + if let Some(build_match) = spec.build.as_ref() { + if !build_match.matches(build_string) { + return inverse; + } + } + + !inverse + } + SolverPackageRecord::Extra { .. } => { + unreachable!("extras should never be compared to matchspecs") } } - - !inverse - } + }) + .collect() + } + SolverMatchSpec::Extra => { + // Extras are already filtered by name. + if inverse { + Vec::new() + } else { + candidates.to_vec() } - }) - .collect() + } + SolverMatchSpec::_Phantom(_) => unreachable!(), + } } fn should_cancel_with_value(&self) -> Option> { @@ -835,56 +848,30 @@ impl super::SolverImpl for Solver { // Construct the requirements that the solver needs to satisfy. let virtual_package_requirements = task.virtual_packages.iter().map(|spec| { - let name_id = provider.pool.intern_package_name(spec.name.as_normalized()); + let name_id = provider.pool.intern_package_name(&spec.name); provider .pool .intern_version_set(name_id, NamelessMatchSpec::default().into()) }); - let root_requirements = task.specs.iter().flat_map(|spec| { - let (name, nameless_spec) = spec.clone().into_nameless(); - let features = &spec.extras; - let name = name.expect("cannot use matchspec without a name"); - let name_id = provider.pool.intern_package_name(name.as_normalized()); - let mut reqs = vec![provider - .pool - .intern_version_set(name_id, nameless_spec.clone().into())]; - - // Add requirements for optional features if specified - if let Some(features) = features { - for feature in features { - // Create a version set that matches the feature-enabled package - let package_name_with_feature = NameType::BaseWithFeature( - name.as_normalized().to_owned(), - feature.to_string(), - ); - let feature_name_id = - provider.pool.intern_package_name(package_name_with_feature); - - let mut solver_match_spec: SolverMatchSpec<'_> = nameless_spec.clone().into(); - let _ = solver_match_spec.set_feature(feature.to_string()); - - let feature_version_set = provider - .pool - .intern_version_set(feature_name_id, solver_match_spec); - reqs.push(feature_version_set); - } - } - reqs - }); + let root_requirements = task + .specs + .into_iter() + .flat_map(|spec| version_sets_for_match_spec(&provider.pool, spec)); - let all_requirements: Vec = virtual_package_requirements + let all_requirements: Vec<_> = virtual_package_requirements .chain(root_requirements) - .map(Requirement::from) + .map(ConditionalRequirement::from) .collect(); let root_constraints = task .constraints .iter() .map(|spec| { - let (name, spec) = spec.clone().into_nameless(); - let name = name.expect("cannot use matchspec without a name"); - let name_id = provider.pool.intern_package_name(name.as_normalized()); + let (Some(name), spec) = spec.clone().into_nameless() else { + unimplemented!("matchspecs without a name are not supported"); + }; + let name_id = provider.pool.intern_package_name(&name); provider.pool.intern_version_set(name_id, spec.into()) }) .collect(); @@ -907,7 +894,7 @@ impl super::SolverImpl for Solver { })?; // Get the resulting packages from the solver. - let mut features: HashMap> = HashMap::new(); + let mut extras: HashMap> = HashMap::new(); let mut records = Vec::new(); for id in solvables { @@ -915,17 +902,17 @@ impl super::SolverImpl for Solver { SolverPackageRecord::Record(rec) => { records.push((*rec).clone()); } - SolverPackageRecord::RecordWithFeature(rec, feature) => { - features - .entry(rec.package_record.name.clone()) + SolverPackageRecord::Extra { package, extra } => { + extras + .entry(package.clone()) .or_default() - .push(feature.clone()); + .push(extra.clone()); } SolverPackageRecord::VirtualPackage(_) => {} } } - Ok(SolverResult { records, features }) + Ok(SolverResult { records, extras }) } } @@ -938,39 +925,72 @@ fn parse_match_spec( return Ok(spec_id.clone()); } + // Parse the match spec and extract the name of the package it depends on. let match_spec = MatchSpec::from_str(spec_str, ParseStrictness::Lenient)?; - let (name, spec) = match_spec.into_nameless(); - let mut version_set_ids = vec![]; - if let Some(ref features) = spec.extras { - let spec_with_feature: SolverMatchSpec<'_> = spec.clone().into(); - - for feature in features { - let name_with_feature = NameType::BaseWithFeature( - name.as_ref() - .expect("Packages with no name are not supported") - .as_normalized() - .to_owned(), - feature.to_string(), - ); - let dependency_name = pool.intern_package_name(name_with_feature); - - let version_set_id = pool.intern_version_set( - dependency_name, - spec_with_feature.with_feature(feature.to_string()), - ); - version_set_ids.push(version_set_id); - } - } else { - let dependency_name = pool.intern_package_name( - name.as_ref() - .expect("Packages with no name are not supported") - .as_normalized(), - ); - let version_set_id = pool.intern_version_set(dependency_name, spec.into()); - version_set_ids.push(version_set_id); - } + // Get the version sets for the match spec. + let version_set_ids = version_sets_for_match_spec(pool, match_spec); + + // Store in the match spec cache parse_match_spec_cache.insert(spec_str.to_string(), version_set_ids.clone()); Ok(version_set_ids) } + +fn version_sets_for_match_spec( + pool: &Pool, NameType>, + spec: MatchSpec, +) -> Vec { + let (Some(name), spec) = spec.into_nameless() else { + unimplemented!("matchspecs without a name are not supported"); + }; + + // Add a dependency on each extra. + let mut version_set_ids = vec![]; + for extra in spec.extras.iter().flatten() { + version_set_ids.push(extra_version_set(pool, name.clone(), extra.clone())); + } + + // Create a version set for the match spec itself. + let dependency_name = pool.intern_package_name(&name); + let version_set_id = pool.intern_version_set(dependency_name, spec.into()); + version_set_ids.push(version_set_id); + + version_set_ids +} + +/// Adds a particular "extra" to the set of solvables +pub fn add_extra( + pool: &Pool, NameType>, + package_name: PackageName, + extra: String, +) -> SolvableId { + let name = NameType::Extra { + package: package_name.as_normalized().to_owned(), + extra: extra.clone(), + }; + let name_id = pool.intern_package_name(name); + + // Ensure that there is a single solvable for this extra. + pool.intern_solvable( + name_id, + SolverPackageRecord::Extra { + package: package_name, + extra, + }, + ) +} + +/// Returns a version set for a particular package name and extra. +pub fn extra_version_set( + pool: &Pool, NameType>, + package_name: PackageName, + extra: String, +) -> VersionSetId { + let name = NameType::Extra { + package: package_name.as_normalized().to_owned(), + extra, + }; + let name_id = pool.intern_package_name(name); + pool.intern_version_set(name_id, SolverMatchSpec::Extra) +} diff --git a/crates/rattler_solve/tests/backends.rs b/crates/rattler_solve/tests/backends.rs index b0bea48a5b..43467137d7 100644 --- a/crates/rattler_solve/tests/backends.rs +++ b/crates/rattler_solve/tests/backends.rs @@ -724,14 +724,13 @@ mod resolvo { use rattler_solve::{SolveStrategy, SolverImpl, SolverTask}; use url::Url; + #[cfg(feature = "experimental_extras")] + use super::dummy_channel_with_optional_dependencies_json_path; use super::{ dummy_channel_json_path, installed_package, solve, solve_real_world, FromStr, GenericVirtualPackage, SimpleSolveTask, SolveError, Version, }; - #[cfg(feature = "experimental_extras")] - use super::dummy_channel_with_optional_dependencies_json_path; - solver_backend_tests!(rattler_solve::resolvo::Solver); #[test] @@ -976,361 +975,117 @@ mod resolvo { insta::assert_snapshot!(result.unwrap_err()); } - #[cfg(feature = "experimental_extras")] - /// Installs `foo` while enabling a single optional dependency `[with-latest-bors]`. - /// This should pull in `bors >=2.0`. - #[test] - fn test_solve_dummy_repo_extra_depends_foo_latest_bors_resolvo() { - let mut result = solve::( - &[dummy_channel_with_optional_dependencies_json_path()], - SimpleSolveTask { - specs: &["foo[extras=[with-latest-bors]]"], - ..SimpleSolveTask::default() - }, - ) - .unwrap(); - - result - .records - .sort_by(|a, b| a.package_record.name.cmp(&b.package_record.name)); - - assert_eq!(result.records.len(), 2); - assert_eq!(result.records[1].package_record.name.as_normalized(), "foo"); - assert_eq!( - result.features.get("foo"), - Some(&vec!["with-latest-bors".to_string()]) - ); - assert_eq!( - result.records[1].package_record.version, - Version::from_str("2.0.2").unwrap(), - "expected lowest version of foobar" - ); - - assert_eq!( - result.records[0].package_record.name.as_normalized(), - "bors" - ); - assert_eq!( - result.records[0].package_record.version, - Version::from_str("2.1").unwrap(), - "expected highest compatible version of bors" - ); - } + /// A test that checks that extras can be used to select optional dependencies. #[cfg(feature = "experimental_extras")] - /// Installs `cuda-version` with `[with-cudadev]` which depends on `"foo >=4.0.2", "bar >=1.2.3"`. #[test] - fn test_solve_dummy_repo_extra_depends_cuda_dev_resolvo() { + fn test_optional_dependency() { let mut result = solve::( &[dummy_channel_with_optional_dependencies_json_path()], SimpleSolveTask { - specs: &["cuda-version[extras=[with-cudadev]]"], + specs: &["foo[extras=[with-bar]]"], ..SimpleSolveTask::default() }, ) .unwrap(); + // Sort the records by package name to make the test deterministic result .records .sort_by(|a, b| a.package_record.name.cmp(&b.package_record.name)); - assert_eq!(result.records.len(), 3); - assert_eq!(result.records[0].package_record.name.as_normalized(), "bar"); - - assert_eq!( - result.records[0].package_record.version, - Version::from_str("1.2.3").unwrap(), - "expected version 1.2.3 of bar" - ); - - // The cuda-version with feature `with-cudadev`: - assert_eq!( - result.records[1].package_record.name.as_normalized(), - "cuda-version" - ); - assert_eq!( - result.records[1].package_record.version, - Version::from_str("12.5").unwrap(), - "expected version 12.5 of cuda-version" - ); - - assert_eq!( - result.features.get("cuda-version"), - Some(&vec!["with-cudadev".to_string()]) - ); - - assert_eq!(result.records[2].package_record.name.as_normalized(), "foo"); - assert_eq!( - result.records[2].package_record.version, - Version::from_str("4.0.2").unwrap(), - "expected version 4.0.2 of foo" - ); - } - - #[cfg(feature = "experimental_extras")] - /// Attempts to enable two optional features that conflict: `[with-oldbors,with-latest-bors]`. - /// This should fail because one requests `bors <2.0` and the other requests `bors >=2.0`. - #[test] - fn test_solve_dummy_repo_extra_depends_conflict_resolvo() { - let result = solve::( - &[dummy_channel_with_optional_dependencies_json_path()], - SimpleSolveTask { - specs: &["foo[extras=[with-oldbors,with-latest-bors]]"], - ..SimpleSolveTask::default() - }, - ); - - insta::assert_snapshot!(result.unwrap_err()); - } - - #[cfg(feature = "experimental_extras")] - /// Enables multiple optional dependencies in the same spec (like `[with-baz2,with-bar]`). - /// This should pull in `baz >=2.0` and `bar >=1.2.3` if both can coexist. - #[test] - fn test_solve_dummy_repo_extra_depends_foo_multi_resolvo() { - let mut result = solve::( - &[dummy_channel_with_optional_dependencies_json_path()], - SimpleSolveTask { - specs: &["foo[extras=[with-baz2,with-bar]]"], - ..SimpleSolveTask::default() - }, - ) - .unwrap(); - - result - .records - .sort_by(|a, b| a.package_record.name.cmp(&b.package_record.name)); - - assert_eq!(result.records.len(), 3); + // Collect the extras into a vector + let extras = result.features.into_iter().collect_vec(); + // Make sure we have two packages `foo` and `bar` + assert_eq!(result.records.len(), 2); assert_eq!(result.records[0].package_record.name.as_normalized(), "bar"); - assert_eq!( - result.records[0].package_record.version, - Version::from_str("1.2.3").unwrap(), - "expected version 1.2.3 of bar" - ); - - assert_eq!(result.records[1].package_record.name.as_normalized(), "baz"); - assert_eq!( - result.records[1].package_record.version, - Version::from_str("2.0").unwrap(), - "expected version 2.0 of baz" - ); - - assert_eq!(result.records[2].package_record.name.as_normalized(), "foo"); - assert_eq!( - result.records[2].package_record.version, - Version::from_str("3.0.2").unwrap(), - "expected version 3.0.2 of foo" - ); - let mut features = result.features.get("foo").unwrap().clone(); - features.sort(); - result.features.insert("foo".parse().unwrap(), features); - assert_eq!( - result.features.get("foo"), - Some(&vec!["with-bar".to_string(), "with-baz2".to_string()]) - ); - } - - #[cfg(feature = "experimental_extras")] - /// Should install xfoo with the feature with-issue717 which requires `with-issue717[with-bors21]` hence pulling in bors 2.1 as well - #[test] - fn test_solve_dummy_repo_extra_depends_xfoo_extra_depends_with_features() { - let mut result = solve::( - &[dummy_channel_with_optional_dependencies_json_path()], - SimpleSolveTask { - specs: &["xfoo[extras=[with-issue717]]"], - ..SimpleSolveTask::default() - }, - ) - .unwrap(); - - result - .records - .sort_by(|a, b| a.package_record.name.cmp(&b.package_record.name)); - - assert_eq!(result.records.len(), 3); - assert_eq!( - result.records[0].package_record.name.as_normalized(), - "bors" - ); - assert_eq!( - result.records[0].package_record.version, - Version::from_str("2.1").unwrap(), - "expected version 2.1 of bors" - ); - - assert_eq!( - result.records[1].package_record.name.as_normalized(), - "issue_717" - ); - assert_eq!( - result.records[1].package_record.version, - Version::from_str("2.1").unwrap(), - "expected version 2.1 of issue_717" - ); - - assert_eq!( - result.records[2].package_record.name.as_normalized(), - "xfoo" - ); - assert_eq!( - result.records[2].package_record.version, - Version::from_str("2.0").unwrap(), - "expected version 2.0 of xfoo" - ); - assert_eq!( - result.features.get("xfoo"), - Some(&vec!["with-issue717".to_string()]) - ); - } - - #[cfg(feature = "experimental_extras")] - /// Tests what happens when a feature depends on the base package but with another feature enabled - #[test] - fn test_solve_dummy_repo_extra_depends_recursive_feature() { - let result = solve::( - &[dummy_channel_with_optional_dependencies_json_path()], - SimpleSolveTask { - specs: &["foo[extras=[with-recursive]]"], - ..SimpleSolveTask::default() - }, - ); - - // Sort records by name for stable test results - insta::assert_snapshot!(result.unwrap_err()); - } - - #[cfg(feature = "experimental_extras")] - /// Tests that an optional dependency can restrict the highest version of a base dependency - #[test] - fn test_solve_dummy_repo_extra_depends_version_restriction() { - let result = solve::( - &[dummy_channel_with_optional_dependencies_json_path()], - SimpleSolveTask { - specs: &["foo[extras=[with-version-restrict]]"], - ..SimpleSolveTask::default() - }, - ) - .unwrap(); - - assert_eq!(result.records.len(), 1); - // Both records should be foo - assert_eq!(result.records[0].package_record.name.as_normalized(), "foo"); - assert_eq!( - result.records[0].package_record.version, - Version::from_str("3.0.2").unwrap(), - "expected version 3.0.2 of foo due to version restriction from feature" - ); - assert_eq!( - result.features.get("foo"), - Some(&vec!["with-version-restrict".to_string()]) - ); - } - - #[cfg(feature = "experimental_extras")] - /// Tests what happens if a feature introduces a dependency on the base package itself - #[test] - fn test_solve_dummy_repo_extra_depends_self_dependency() { - let mut result = solve::( - &[dummy_channel_with_optional_dependencies_json_path()], - SimpleSolveTask { - specs: &["foo[extras=[with-self]]"], - ..SimpleSolveTask::default() - }, - ) - .unwrap(); - - // Sort records by name for stable test results - result - .records - .sort_by(|a, b| a.package_record.name.cmp(&b.package_record.name)); + assert_eq!(result.records[1].package_record.name.as_normalized(), "foo"); - assert_eq!(result.records.len(), 1); - // Both records should be foo - assert_eq!(result.records[0].package_record.name.as_normalized(), "foo"); - assert_eq!( - result.records[0].package_record.version, - Version::from_str("2.0.2").unwrap(), - "expected version 2.0.2 of foo" - ); - assert_eq!( - result.features.get("foo"), - Some(&vec!["with-self".to_string()]) - ); + // Make sure there is an extra feature `with-bar` for `foo` + assert_eq!(extras.len(), 1); + assert_eq!(extras[0].0.as_normalized(), "foo"); + assert_eq!(extras[0].1, vec!["with-bar"]); } + /// A test that checks that extras influence the version selection of other packages. #[cfg(feature = "experimental_extras")] - /// Tests what happens if there are two packages for foo but only the package with the lower version has the package that is requested #[test] - fn test_solve_dummy_repo_extra_depends_feature_only_in_older() { + fn test_optional_dependency_restrict() { let mut result = solve::( &[dummy_channel_with_optional_dependencies_json_path()], SimpleSolveTask { - specs: &["foo[extras=[legacy-only]]"], + specs: &["foo[extras=[with-bar]]", "bar"], ..SimpleSolveTask::default() }, ) .unwrap(); - // Sort records by name for stable test results + // Sort the records by package name to make the test deterministic result .records .sort_by(|a, b| a.package_record.name.cmp(&b.package_record.name)); + // Even though 2 versions of `bar` are available, we should have + // selected the one with version "1" because it is restricted by the + // extra added to foo. assert_eq!(result.records.len(), 2); - - // Both records should be foo + assert_eq!(result.records[0].file_name, "bar-1-xxx.tar.bz2"); assert_eq!(result.records[1].package_record.name.as_normalized(), "foo"); - assert_eq!( - result.records[1].package_record.version, - Version::from_str("2.0.2").unwrap(), - "expected older version 2.0.2 of foo since it has the required feature" - ); - assert_eq!( - result.features.get("foo"), - Some(&vec!["legacy-only".to_string()]) - ); - - assert_eq!(result.records[0].package_record.name.as_normalized(), "bar"); - assert_eq!( - result.records[0].package_record.version, - Version::from_str("1.2.3").unwrap(), - "expected version 1.2.3 of bar" - ); } + /// A test that checks that if two extras have conflicting dependencies the + /// solution is unsolvable. #[cfg(feature = "experimental_extras")] - /// Test what happens if a feature is requested that doesn't exist #[test] - fn test_solve_dummy_repo_extra_depends_nonexistent_feature() { + fn test_optional_dependency_conflicting_extras() { let result = solve::( &[dummy_channel_with_optional_dependencies_json_path()], SimpleSolveTask { - specs: &["foo[extras=[does-not-exist]]"], + specs: &["conflicting-extras[extras=[extra1, extra2]]"], ..SimpleSolveTask::default() }, ); - assert_eq!( - result.unwrap_err().to_string(), - "Cannot solve the request because of: No candidates were found for foo[does-not-exist] *.\n" - ); + insta::assert_snapshot!(result.unwrap_err(), @r###" + Cannot solve the request because of: The following packages are incompatible + ├─ conflicting-extras[extra1] can be installed with any of the following options: + │ └─ conflicting-extras[extra1] + ├─ conflicting-extras[extra2] can be installed with any of the following options: + │ └─ conflicting-extras[extra2] + └─ conflicting-extras * cannot be installed because there are no viable options: + └─ conflicting-extras 1 would require + ├─ bar >=2, which can be installed with any of the following options: + │ └─ bar 2 + └─ bar <2, which cannot be installed because there are no viable options: + └─ bar 1, which conflicts with the versions reported above. + "###); } + /// A test that checks that extras can cause conflicts with other package + /// dependencies. #[cfg(feature = "experimental_extras")] - /// Test what happens when the only package that provides a certain feature cannot be selected due to a conflict #[test] - fn test_solve_dummy_repo_extra_depends_feature_conflict() { + fn test_optional_dependency_conflicting_with_package() { let result = solve::( &[dummy_channel_with_optional_dependencies_json_path()], SimpleSolveTask { - specs: &["foo[extras=[with-bar]]", "foo>=4.0"], + specs: &["conflicting-extras[extras=[extra1]]", "bar>=2"], ..SimpleSolveTask::default() }, ); - insta::assert_snapshot!(result.unwrap_err()); + insta::assert_snapshot!(result.unwrap_err(), @r###" + Cannot solve the request because of: The following packages are incompatible + ├─ conflicting-extras[extra1] can be installed with any of the following options: + │ └─ conflicting-extras[extra1] + ├─ bar >=2 can be installed with any of the following options: + │ └─ bar 2 + └─ conflicting-extras * cannot be installed because there are no viable options: + └─ conflicting-extras 1 would require + └─ bar <2, which cannot be installed because there are no viable options: + └─ bar 1, which conflicts with the versions reported above. + "###); } } diff --git a/crates/rattler_solve/tests/backends.rs~ b/crates/rattler_solve/tests/backends.rs~ new file mode 100644 index 0000000000..43467137d7 --- /dev/null +++ b/crates/rattler_solve/tests/backends.rs~ @@ -0,0 +1,1446 @@ +use std::{collections::BTreeMap, str::FromStr, time::Instant}; + +use chrono::{DateTime, Utc}; +use once_cell::sync::Lazy; +use rattler_conda_types::{ + Channel, ChannelConfig, GenericVirtualPackage, MatchSpec, NoArchType, PackageRecord, + ParseStrictness, RepoData, RepoDataRecord, SolverResult, Version, +}; +use rattler_repodata_gateway::sparse::{PackageFormatSelection, SparseRepoData}; +use rattler_solve::{ChannelPriority, SolveError, SolveStrategy, SolverImpl, SolverTask}; +use url::Url; + +fn channel_config() -> ChannelConfig { + ChannelConfig::default_with_root_dir(std::env::current_dir().unwrap()) +} + +fn conda_json_path() -> String { + format!( + "{}/{}", + env!("CARGO_MANIFEST_DIR"), + "../../test-data/channels/conda-forge/linux-64/repodata.json" + ) +} + +fn conda_json_path_noarch() -> String { + format!( + "{}/{}", + env!("CARGO_MANIFEST_DIR"), + "../../test-data/channels/conda-forge/noarch/repodata.json" + ) +} + +fn pytorch_json_path() -> String { + format!( + "{}/{}", + env!("CARGO_MANIFEST_DIR"), + "../../test-data/channels/pytorch/linux-64/repodata.json" + ) +} + +fn dummy_channel_json_path() -> String { + format!( + "{}/{}", + env!("CARGO_MANIFEST_DIR"), + "../../test-data/channels/dummy/linux-64/repodata.json" + ) +} + +#[cfg(feature = "experimental_extras")] +fn dummy_channel_with_optional_dependencies_json_path() -> String { + format!( + "{}/{}", + env!("CARGO_MANIFEST_DIR"), + "../../test-data/channels/dummy-optional-dependencies/noarch/repodata.json" + ) +} + +fn dummy_md5_hash() -> rattler_digest::Md5Hash { + rattler_digest::parse_digest_from_hex::("b3af409bb8423187c75e6c7f5b683908") + .unwrap() +} + +fn dummy_sha256_hash() -> rattler_digest::Sha256Hash { + rattler_digest::parse_digest_from_hex::( + "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad", + ) + .unwrap() +} + +fn read_repodata(path: &str) -> Vec { + let repo_data: RepoData = + serde_json::from_str(&std::fs::read_to_string(path).unwrap()).unwrap(); + repo_data.into_repo_data_records(&Channel::from_str("conda-forge", &channel_config()).unwrap()) +} + +fn read_sparse_repodata(path: &str) -> SparseRepoData { + SparseRepoData::from_file( + Channel::from_str("dummy", &channel_config()).unwrap(), + "dummy".to_string(), + path, + None, + ) + .unwrap() +} + +fn installed_package( + channel: &str, + subdir: &str, + name: &str, + version: &str, + build: &str, + build_number: u64, +) -> RepoDataRecord { + RepoDataRecord { + url: Url::from_str("http://example.com").unwrap(), + channel: Some(channel.to_string()), + file_name: "dummy-filename".to_string(), + package_record: PackageRecord { + name: name.parse().unwrap(), + version: version.parse().unwrap(), + build: build.to_string(), + build_number, + subdir: subdir.to_string(), + md5: Some(dummy_md5_hash()), + sha256: Some(dummy_sha256_hash()), + size: None, + arch: None, + extra_depends: BTreeMap::new(), + platform: None, + depends: Vec::new(), + constrains: Vec::new(), + track_features: Vec::new(), + features: None, + noarch: NoArchType::default(), + license: None, + license_family: None, + timestamp: None, + legacy_bz2_size: None, + legacy_bz2_md5: None, + purls: None, + python_site_packages_path: None, + run_exports: None, + }, + } +} + +fn solve_real_world(specs: Vec<&str>) -> Vec { + let specs = specs + .iter() + .map(|s| MatchSpec::from_str(s, ParseStrictness::Lenient).unwrap()) + .collect::>(); + + let sparse_repo_data = read_real_world_repo_data(); + + let names = specs.iter().filter_map(|s| s.name.as_ref().cloned()); + let available_packages = SparseRepoData::load_records_recursive( + sparse_repo_data, + names, + None, + PackageFormatSelection::default(), + ) + .unwrap(); + + let solver_task = SolverTask { + specs: specs.clone(), + ..SolverTask::from_iter(&available_packages) + }; + + let pkgs1 = match T::default().solve(solver_task) { + Ok(result) => result.records, + Err(e) => panic!("{e}"), + }; + + let extract_pkgs = |records: Vec| { + let mut pkgs = records + .into_iter() + .map(|pkg| { + format!( + "{} {} {}", + pkg.package_record.name.as_normalized(), + pkg.package_record.version, + pkg.package_record.build + ) + }) + .collect::>(); + + // The order of packages is nondeterministic, so we sort them to ensure we can + // compare them to a previous run + pkgs.sort(); + pkgs + }; + + extract_pkgs(pkgs1) +} + +fn read_real_world_repo_data() -> &'static Vec { + static REPO_DATA: Lazy> = Lazy::new(|| { + let json_file = conda_json_path(); + let json_file_noarch = conda_json_path_noarch(); + + vec![ + read_sparse_repodata(&json_file), + read_sparse_repodata(&json_file_noarch), + ] + }); + + &REPO_DATA +} + +fn read_pytorch_sparse_repo_data() -> &'static SparseRepoData { + static REPO_DATA: Lazy = Lazy::new(|| { + let pytorch = pytorch_json_path(); + SparseRepoData::from_file( + Channel::from_str("pytorch", &channel_config()).unwrap(), + "pytorch".to_string(), + pytorch, + None, + ) + .unwrap() + }); + + &REPO_DATA +} + +fn read_conda_forge_sparse_repo_data() -> &'static SparseRepoData { + static REPO_DATA: Lazy = Lazy::new(|| { + let conda_forge = conda_json_path(); + SparseRepoData::from_file( + Channel::from_str("conda-forge", &channel_config()).unwrap(), + "conda-forge".to_string(), + conda_forge, + None, + ) + .unwrap() + }); + &REPO_DATA +} +macro_rules! solver_backend_tests { + ($T:path) => { + use chrono::{DateTime, Utc}; + use itertools::Itertools; + + #[test] + fn test_solve_quetz() { + insta::assert_yaml_snapshot!(solve_real_world::<$T>(vec!["quetz",])); + } + + #[test] + fn test_solve_xtensor_xsimd() { + insta::assert_yaml_snapshot!(solve_real_world::<$T>(vec!["xtensor", "xsimd",])); + } + + #[test] + fn test_solve_tensorflow() { + insta::assert_yaml_snapshot!(solve_real_world::<$T>(vec!["tensorflow"])); + } + + #[test] + fn test_solve_tensorboard() { + insta::assert_yaml_snapshot!(solve_real_world::<$T>(vec![ + "tensorboard=2.1.1", + "grpc-cpp=1.39.1" + ])); + } + + #[test] + fn test_solve_python() { + insta::assert_yaml_snapshot!(solve_real_world::<$T>(vec!["python=3.9"])); + } + + #[test] + fn test_solve_python_numpy() { + insta::assert_yaml_snapshot!(solve_real_world::<$T>(vec![ + "numpy==1.23.2", + "scipy==1.8.1", + "python=3.9.*" + ])); + } + + #[test] + fn test_solve_favored() { + let result = solve::<$T>( + &[dummy_channel_json_path()], + SimpleSolveTask { + specs: &["bors"], + installed_packages: vec![installed_package( + "conda-forge", + "linux-64", + "bors", + "1.0", + "bla_1", + 1, + )], + ..SimpleSolveTask::default() + }, + ) + .unwrap(); + + assert_eq!(result.records.len(), 1); + assert_eq!(result.records[0].package_record.to_string(), "bors=1.0=bla_1"); + } + + #[test] + fn test_solve_with_error() { + let result = solve::<$T>( + &[dummy_channel_json_path()], + SimpleSolveTask { + specs: &["foobar >=2", "bors >= 2"], + ..SimpleSolveTask::default() + }, + ); + + assert!(result.is_err()); + + let err = result.err().unwrap(); + insta::assert_snapshot!(err); + } + + #[test] + fn test_solve_dummy_repo_install_non_existent() { + let result = solve::<$T>( + &[dummy_channel_json_path()], + SimpleSolveTask { + specs: &["asdfasdf", "foo<4"], + ..SimpleSolveTask::default() + }, + ); + + assert!(result.is_err()); + + let err = result.err().unwrap(); + insta::assert_debug_snapshot!(err); + } + + #[test] + fn test_solve_dummy_repo_missing_virtual_package() { + let result = solve::<$T>( + &[dummy_channel_json_path()], + SimpleSolveTask { + specs: &["bar"], + ..SimpleSolveTask::default() + }, + ); + + assert!(matches!(result.err(), Some(SolveError::Unsolvable(_)))); + } + + #[test] + fn test_solve_dummy_repo_with_virtual_package() { + let pkgs = solve::<$T>( + &[dummy_channel_json_path()], + SimpleSolveTask { + specs: &["bar"], + virtual_packages: vec![GenericVirtualPackage { + name: rattler_conda_types::PackageName::new_unchecked("__unix"), + version: Version::from_str("0").unwrap(), + build_string: "0".to_string(), + }], + ..SimpleSolveTask::default() + }, + ) + .unwrap(); + + assert_eq!(pkgs.records.len(), 1); + + let info = &pkgs.records[0]; + assert_eq!("bar", info.package_record.name.as_normalized()); + assert_eq!("1.2.3", &info.package_record.version.to_string()); + } + + #[test] + fn test_solve_dummy_repo_install_new() { + let pkgs = solve::<$T>( + &[dummy_channel_json_path()], + SimpleSolveTask { + specs: &["foo<4"], + ..SimpleSolveTask::default() + }, + ) + .unwrap(); + + assert_eq!(1, pkgs.records.len()); + let info = &pkgs.records[0]; + + assert_eq!("foo-3.0.2-py36h1af98f8_3.conda", info.file_name); + assert_eq!( + "https://conda.anaconda.org/conda-forge/linux-64/foo-3.0.2-py36h1af98f8_3.conda", + info.url.to_string() + ); + assert_eq!(Some("https://conda.anaconda.org/conda-forge/"), info.channel.as_deref()); + assert_eq!("foo", info.package_record.name.as_normalized()); + assert_eq!("linux-64", info.package_record.subdir); + assert_eq!("3.0.2", info.package_record.version.to_string()); + assert_eq!("py36h1af98f8_3", info.package_record.build); + assert_eq!(3, info.package_record.build_number); + assert_eq!( + rattler_digest::parse_digest_from_hex::( + "67a63bec3fd3205170eaad532d487595b8aaceb9814d13c6858d7bac3ef24cd4" + ) + .as_ref() + .unwrap(), + info.package_record.sha256.as_ref().unwrap() + ); + assert_eq!( + rattler_digest::parse_digest_from_hex::( + "fb731d9290f0bcbf3a054665f33ec94f" + ) + .as_ref() + .unwrap(), + info.package_record.md5.as_ref().unwrap() + ); + } + + #[test] + fn test_solve_dummy_repo_prefers_conda_package() { + // There following package is provided as .tar.bz and as .conda in repodata.json + let match_spec = "foo=3.0.2=py36h1af98f8_1"; + + let operations = solve::<$T>( + &[dummy_channel_json_path()], + SimpleSolveTask { + specs: &[match_spec], + ..SimpleSolveTask::default() + }, + ) + .unwrap(); + + // The .conda entry is selected for installing + assert_eq!(operations.records.len(), 1); + assert_eq!(operations.records[0].file_name, "foo-3.0.2-py36h1af98f8_1.conda"); + } + + #[test] + fn test_solve_dummy_repo_install_noop() { + let already_installed = vec![installed_package( + "conda-forge", + "linux-64", + "foo", + "3.0.2", + "py36h1af98f8_1", + 1, + )]; + + let pkgs = solve::<$T>( + &[dummy_channel_json_path()], + SimpleSolveTask { + specs: &["foo<4"], + installed_packages: already_installed, + ..SimpleSolveTask::default() + }, + ) + .unwrap(); + + assert_eq!(1, pkgs.records.len()); + + // Install + let info = &pkgs.records[0]; + assert_eq!("foo", info.package_record.name.as_normalized()); + assert_eq!("3.0.2", &info.package_record.version.to_string()); + } + + #[test] + fn test_solve_dummy_repo_upgrade() { + let already_installed = vec![installed_package( + "conda-forge", + "linux-64", + "foo", + "3.0.2", + "py36h1af98f8_1", + 1, + )]; + + let pkgs = solve::<$T>( + &[dummy_channel_json_path()], + SimpleSolveTask { + specs: &["foo>=4"], + installed_packages: already_installed, + ..SimpleSolveTask::default() + }, + ) + .unwrap(); + + // Install + let info = &pkgs.records[0]; + assert_eq!("foo", info.package_record.name.as_normalized()); + assert_eq!("4.0.2", &info.package_record.version.to_string()); + } + + #[test] + fn test_solve_dummy_repo_downgrade() { + let already_installed = vec![installed_package( + "conda-forge", + "linux-64", + "foo", + "4.0.2", + "py36h1af98f8_1", + 1, + )]; + + let pkgs = solve::<$T>( + &[dummy_channel_json_path()], + SimpleSolveTask { + specs: &["foo<4"], + installed_packages: already_installed, + ..SimpleSolveTask::default() + }, + ) + .unwrap(); + + assert_eq!(pkgs.records.len(), 1); + + // Uninstall + let info = &pkgs.records[0]; + assert_eq!("foo", info.package_record.name.as_normalized()); + assert_eq!("3.0.2", &info.package_record.version.to_string()); + } + + #[test] + fn test_solve_dummy_repo_remove() { + let already_installed = vec![installed_package( + "conda-forge", + "linux-64", + "foo", + "3.0.2", + "py36h1af98f8_1", + 1, + )]; + + let pkgs = solve::<$T>( + &[dummy_channel_json_path()], + SimpleSolveTask { + installed_packages: already_installed, + ..SimpleSolveTask::default() + }, + ) + .unwrap(); + + // Should be no packages! + assert_eq!(0, pkgs.records.len()); + } + + #[test] + fn test_exclude_newer() { + let date = "2021-12-12T12:12:12Z".parse::>().unwrap(); + + let pkgs = solve::<$T>( + &[dummy_channel_json_path()], + SimpleSolveTask { + specs: &["foo"], + exclude_newer: Some(date), + ..SimpleSolveTask::default() + }, + ) + .unwrap(); + + assert_eq!(1, pkgs.records.len()); + + let info = &pkgs.records[0]; + assert_eq!("foo", info.package_record.name.as_normalized()); + assert_eq!("3.0.2", &info.package_record.version.to_string(), + "although there is a newer version available we expect an older version of foo because we exclude the newer version based on the timestamp"); + assert_eq!(&info.file_name, "foo-3.0.2-py36h1af98f8_1.tar.bz2", "even though there is a conda version available we expect the tar.bz2 version because we exclude the .conda version based on the timestamp"); + } + + #[test] + fn test_duplicate_record() { + use rattler_solve::SolverImpl; + + let mut records = super::read_repodata(&dummy_channel_json_path()); + records.push(records[0].clone()); + + let task = rattler_solve::SolverTask::from_iter([&records]); + + let result = <$T>::default().solve(task); + match result { + Err(rattler_solve::SolveError::DuplicateRecords(_)) => {} + _ => panic!("expected a DuplicateRecord error"), + } + } + + #[test] + fn test_constraints() { + // There following package is provided as .tar.bz and as .conda in repodata.json + let mut operations = solve::<$T>( + &[dummy_channel_json_path()], + SimpleSolveTask { + specs: &["foobar"], + constraints: vec!["bors <=1", "nonexisting"], + ..SimpleSolveTask::default() + }, + ) + .unwrap(); + + // Sort operations by file name to make the test deterministic + operations.records.sort_by(|a, b| a.file_name.cmp(&b.file_name)); + + assert_eq!(operations.records.len(), 2); + assert_eq!(operations.records[0].file_name, "bors-1.0-bla_1.tar.bz2"); + assert_eq!(operations.records[1].file_name, "foobar-2.1-bla_1.tar.bz2"); + } + + #[test] + fn test_virtual_package_constrains() { + // This tests that a package that has a constrains on a virtual package is + // properly restricted. + let result = solve::<$T>( + &[dummy_channel_json_path()], + SimpleSolveTask { + specs: &["cuda-version"], + virtual_packages: vec![GenericVirtualPackage { + name: "__cuda".parse().unwrap(), + version: Version::from_str("1").unwrap(), + build_string: "0".to_string(), + }], + ..SimpleSolveTask::default() + }, + ); + + let output = match result { + Ok(pkgs) => pkgs + .records + .iter() + .format_with("\n", |pkg, f| { + f(&format_args!( + "{}={}={}", + pkg.package_record.name.as_normalized(), + pkg.package_record.version.as_str(), + &pkg.package_record.build + )) + }) + .to_string(), + Err(e) => e.to_string(), + }; + + insta::assert_snapshot!(output); + } + }; +} + +#[cfg(feature = "libsolv_c")] +mod libsolv_c { + #![allow(unused_imports)] // For some reason windows thinks this is an unused import. + + use rattler_solve::{ChannelPriority, SolveStrategy}; + + use super::{ + dummy_channel_json_path, installed_package, solve, solve_real_world, FromStr, + GenericVirtualPackage, SimpleSolveTask, SolveError, Version, + }; + + solver_backend_tests!(rattler_solve::libsolv_c::Solver); + + #[test] + #[cfg(target_family = "unix")] + fn test_solve_with_cached_solv_file_install_new() { + use rattler_conda_types::{Channel, ChannelConfig, MatchSpec, RepoDataRecord}; + use rattler_solve::{SolverImpl, SolverTask}; + + use super::read_repodata; + + let repo_data = read_repodata(&dummy_channel_json_path()); + + let cached_repo_data = rattler_solve::libsolv_c::cache_repodata( + Channel::from_str( + "conda-forge", + &ChannelConfig::default_with_root_dir(std::env::current_dir().unwrap()), + ) + .unwrap() + .platform_url(rattler_conda_types::Platform::Linux64) + .to_string(), + &repo_data, + None, + ) + .unwrap(); + + let libsolv_repodata = rattler_solve::libsolv_c::RepoData { + records: repo_data.iter().collect(), + solv_file: Some(&cached_repo_data), + }; + + let specs: Vec = vec!["foo<4".parse().unwrap()]; + + let pkgs: Vec = rattler_solve::libsolv_c::Solver + .solve(SolverTask { + locked_packages: Vec::new(), + virtual_packages: Vec::new(), + available_packages: [libsolv_repodata], + specs, + constraints: Vec::new(), + pinned_packages: Vec::new(), + timeout: None, + channel_priority: ChannelPriority::default(), + exclude_newer: None, + strategy: SolveStrategy::default(), + }) + .unwrap() + .records; + + if pkgs.is_empty() { + println!("No packages in the environment!"); + } + + assert_eq!(1, pkgs.len()); + let info = &pkgs[0]; + + assert_eq!("foo-3.0.2-py36h1af98f8_3.conda", info.file_name); + assert_eq!( + "https://conda.anaconda.org/conda-forge/linux-64/foo-3.0.2-py36h1af98f8_3.conda", + info.url.to_string() + ); + assert_eq!( + Some("https://conda.anaconda.org/conda-forge/"), + info.channel.as_deref() + ); + assert_eq!("foo", info.package_record.name.as_normalized()); + assert_eq!("linux-64", info.package_record.subdir); + assert_eq!("3.0.2", info.package_record.version.to_string()); + assert_eq!("py36h1af98f8_3", info.package_record.build); + assert_eq!(3, info.package_record.build_number); + assert_eq!( + rattler_digest::parse_digest_from_hex::( + "67a63bec3fd3205170eaad532d487595b8aaceb9814d13c6858d7bac3ef24cd4" + ) + .as_ref() + .unwrap(), + info.package_record.sha256.as_ref().unwrap() + ); + assert_eq!( + rattler_digest::parse_digest_from_hex::( + "fb731d9290f0bcbf3a054665f33ec94f" + ) + .as_ref() + .unwrap(), + info.package_record.md5.as_ref().unwrap() + ); + } +} + +#[cfg(feature = "resolvo")] +mod resolvo { + use rattler_conda_types::{ + MatchSpec, PackageRecord, ParseStrictness, RepoDataRecord, VersionWithSource, + }; + use rattler_solve::{SolveStrategy, SolverImpl, SolverTask}; + use url::Url; + + #[cfg(feature = "experimental_extras")] + use super::dummy_channel_with_optional_dependencies_json_path; + use super::{ + dummy_channel_json_path, installed_package, solve, solve_real_world, FromStr, + GenericVirtualPackage, SimpleSolveTask, SolveError, Version, + }; + + solver_backend_tests!(rattler_solve::resolvo::Solver); + + #[test] + fn test_solve_locked() { + let result = solve::( + &[dummy_channel_json_path()], + SimpleSolveTask { + specs: &["bors >=2"], + pinned_packages: vec![installed_package( + "conda-forge", + "linux-64", + "bors", + "1.0", + "bla_1", + 1, + )], + ..SimpleSolveTask::default() + }, + ); + + // We expect an error here. `bors` is pinnend to 1, but we try to install `>=2`. + insta::assert_snapshot!(result.unwrap_err()); + } + + #[test] + fn test_issue_717() { + let result = solve::( + &[dummy_channel_json_path()], + SimpleSolveTask { + specs: &["issue_717"], + ..SimpleSolveTask::default() + }, + ); + + // We expect an error here. `bors` is pinnend to 1, but we try to install `>=2`. + insta::assert_snapshot!(result.unwrap_err()); + } + + #[test] + fn test_exclude_newer_error() { + let date = "2021-12-12T12:12:12Z".parse::>().unwrap(); + + let result = solve::( + &[dummy_channel_json_path()], + SimpleSolveTask { + specs: &["foo>=4"], + exclude_newer: Some(date), + ..SimpleSolveTask::default() + }, + ); + + // We expect an error here. `bors` is pinnend to 1, but we try to install `>=2`. + insta::assert_snapshot!(result.unwrap_err()); + } + + #[test] + fn test_lowest_version_strategy_highest_build_number() { + let result = solve::( + &[dummy_channel_json_path()], + SimpleSolveTask { + specs: &["foo"], + strategy: rattler_solve::SolveStrategy::LowestVersion, + ..SimpleSolveTask::default() + }, + ) + .unwrap(); + + assert_eq!(result.records.len(), 1); + assert_eq!( + result.records[0].package_record.version, + Version::from_str("3.0.2").unwrap() + ); + assert_eq!( + result.records[0].package_record.build_number, 3, + "expected the highest build number" + ); + } + + #[test] + fn test_lowest_version_strategy_all() { + let result = solve::( + &[dummy_channel_json_path()], + SimpleSolveTask { + specs: &["foobar"], + strategy: rattler_solve::SolveStrategy::LowestVersion, + ..SimpleSolveTask::default() + }, + ) + .unwrap(); + + assert_eq!(result.records.len(), 2); + assert_eq!( + result.records[0].package_record.name.as_normalized(), + "foobar" + ); + assert_eq!( + result.records[0].package_record.version, + Version::from_str("2.0").unwrap(), + "expected lowest version of foobar" + ); + + assert_eq!( + result.records[1].package_record.name.as_normalized(), + "bors" + ); + assert_eq!( + result.records[1].package_record.version, + Version::from_str("1.0").unwrap(), + "expected lowest version of bors" + ); + } + + #[test] + fn test_lowest_direct_version_strategy() { + let result = solve::( + &[dummy_channel_json_path()], + SimpleSolveTask { + specs: &["foobar"], + strategy: rattler_solve::SolveStrategy::LowestVersionDirect, + ..SimpleSolveTask::default() + }, + ) + .unwrap(); + + assert_eq!(result.records.len(), 2); + assert_eq!( + result.records[0].package_record.name.as_normalized(), + "foobar" + ); + assert_eq!( + result.records[0].package_record.version, + Version::from_str("2.0").unwrap(), + "expected lowest version of foobar" + ); + + assert_eq!( + result.records[1].package_record.name.as_normalized(), + "bors" + ); + assert_eq!( + result.records[1].package_record.version, + Version::from_str("1.2.1").unwrap(), + "expected highest compatible version of bors" + ); + } + + /// Try to solve a package with a direct url, and then try to do it again + /// without having it in the repodata. + #[test] + fn test_solve_on_url() { + let url_str = + "https://conda.anaconda.org/conda-forge/linux-64/_libgcc_mutex-0.1-conda_forge.tar.bz2"; + let url = Url::parse(url_str).unwrap(); + + // Create a match spec for a package that is not in the repodata + let specs: Vec<_> = vec![MatchSpec::from_str(url_str, ParseStrictness::Lenient).unwrap()]; + + // Create RepoData with only the package from the url, so the solver can find it + let package_record = PackageRecord::new( + // // Only defining the name, version and url is enough for the solver to find the + // package direct_url: Some(url.clone()), + "_libgcc_mutex".parse().unwrap(), + VersionWithSource::from_str("0.1").unwrap(), + "0".to_string(), + ); + let repo_data: Vec = vec![RepoDataRecord { + package_record: package_record.clone(), + // Mocking the rest of the fields + file_name: url_str.to_string(), + url: url.clone(), + channel: None, + }]; + + // Completely clean solver task, except for the specs and RepoData + let task = SolverTask { + locked_packages: vec![], + virtual_packages: vec![], + specs: specs.clone(), + constraints: vec![], + pinned_packages: vec![], + exclude_newer: None, + strategy: SolveStrategy::default(), + ..SolverTask::from_iter([&repo_data]) + }; + + let pkgs: Vec = rattler_solve::resolvo::Solver.solve(task).unwrap().records; + + assert_eq!(pkgs.len(), 1); + assert_eq!(pkgs[0].package_record.name.as_normalized(), "_libgcc_mutex"); + assert_eq!(pkgs[0].url, url.clone()); + assert_eq!( + pkgs[0].package_record.version, + Version::from_str("0.1").unwrap(), + "expected lowest version of _libgcc_mutex" + ); + + // ----------------------------------------------------------------------------------------- + // Break the url in the repodata, making it not a direct url record. + + let repo_data: Vec = vec![RepoDataRecord { + package_record, + file_name: url_str.to_string(), + url: Url::from_str("https://false.dont").unwrap(), + channel: None, + }]; + + // Completely clean solver task, except for the specs and RepoData + let task = SolverTask { + locked_packages: vec![], + virtual_packages: vec![], + specs, + constraints: vec![], + pinned_packages: vec![], + exclude_newer: None, + strategy: SolveStrategy::default(), + ..SolverTask::from_iter([&repo_data]) + }; + + let solve_error = rattler_solve::resolvo::Solver.solve(task).unwrap_err(); + + assert!(matches!(solve_error, SolveError::Unsolvable(_))); + } + + #[test] + fn test_panic_on_constraint() { + let result = solve::( + &[dummy_channel_json_path()], + SimpleSolveTask { + specs: &["xbar"], + constraints: vec!["xfoo==1"], + pinned_packages: vec![installed_package( + "conda-forge", + "linux-64", + "xfoo", + "1", + "xxx", + 1, + )], + ..SimpleSolveTask::default() + }, + ); + + insta::assert_snapshot!(result.unwrap_err()); + } + + /// A test that checks that extras can be used to select optional dependencies. + #[cfg(feature = "experimental_extras")] + #[test] + fn test_optional_dependency() { + let mut result = solve::( + &[dummy_channel_with_optional_dependencies_json_path()], + SimpleSolveTask { + specs: &["foo[extras=[with-bar]]"], + ..SimpleSolveTask::default() + }, + ) + .unwrap(); + + // Sort the records by package name to make the test deterministic + result + .records + .sort_by(|a, b| a.package_record.name.cmp(&b.package_record.name)); + + // Collect the extras into a vector + let extras = result.features.into_iter().collect_vec(); + + // Make sure we have two packages `foo` and `bar` + assert_eq!(result.records.len(), 2); + assert_eq!(result.records[0].package_record.name.as_normalized(), "bar"); + assert_eq!(result.records[1].package_record.name.as_normalized(), "foo"); + + // Make sure there is an extra feature `with-bar` for `foo` + assert_eq!(extras.len(), 1); + assert_eq!(extras[0].0.as_normalized(), "foo"); + assert_eq!(extras[0].1, vec!["with-bar"]); + } + + /// A test that checks that extras influence the version selection of other packages. + #[cfg(feature = "experimental_extras")] + #[test] + fn test_optional_dependency_restrict() { + let mut result = solve::( + &[dummy_channel_with_optional_dependencies_json_path()], + SimpleSolveTask { + specs: &["foo[extras=[with-bar]]", "bar"], + ..SimpleSolveTask::default() + }, + ) + .unwrap(); + + // Sort the records by package name to make the test deterministic + result + .records + .sort_by(|a, b| a.package_record.name.cmp(&b.package_record.name)); + + // Even though 2 versions of `bar` are available, we should have + // selected the one with version "1" because it is restricted by the + // extra added to foo. + assert_eq!(result.records.len(), 2); + assert_eq!(result.records[0].file_name, "bar-1-xxx.tar.bz2"); + assert_eq!(result.records[1].package_record.name.as_normalized(), "foo"); + } + + /// A test that checks that if two extras have conflicting dependencies the + /// solution is unsolvable. + #[cfg(feature = "experimental_extras")] + #[test] + fn test_optional_dependency_conflicting_extras() { + let result = solve::( + &[dummy_channel_with_optional_dependencies_json_path()], + SimpleSolveTask { + specs: &["conflicting-extras[extras=[extra1, extra2]]"], + ..SimpleSolveTask::default() + }, + ); + + insta::assert_snapshot!(result.unwrap_err(), @r###" + Cannot solve the request because of: The following packages are incompatible + ├─ conflicting-extras[extra1] can be installed with any of the following options: + │ └─ conflicting-extras[extra1] + ├─ conflicting-extras[extra2] can be installed with any of the following options: + │ └─ conflicting-extras[extra2] + └─ conflicting-extras * cannot be installed because there are no viable options: + └─ conflicting-extras 1 would require + ├─ bar >=2, which can be installed with any of the following options: + │ └─ bar 2 + └─ bar <2, which cannot be installed because there are no viable options: + └─ bar 1, which conflicts with the versions reported above. + "###); + } + + /// A test that checks that extras can cause conflicts with other package + /// dependencies. + #[cfg(feature = "experimental_extras")] + #[test] + fn test_optional_dependency_conflicting_with_package() { + let result = solve::( + &[dummy_channel_with_optional_dependencies_json_path()], + SimpleSolveTask { + specs: &["conflicting-extras[extras=[extra1]]", "bar>=2"], + ..SimpleSolveTask::default() + }, + ); + + insta::assert_snapshot!(result.unwrap_err(), @r###" + Cannot solve the request because of: The following packages are incompatible + ├─ conflicting-extras[extra1] can be installed with any of the following options: + │ └─ conflicting-extras[extra1] + ├─ bar >=2 can be installed with any of the following options: + │ └─ bar 2 + └─ conflicting-extras * cannot be installed because there are no viable options: + └─ conflicting-extras 1 would require + └─ bar <2, which cannot be installed because there are no viable options: + └─ bar 1, which conflicts with the versions reported above. + "###); + } +} + +#[derive(Default)] +struct SimpleSolveTask<'a> { + specs: &'a [&'a str], + constraints: Vec<&'a str>, + installed_packages: Vec, + pinned_packages: Vec, + virtual_packages: Vec, + exclude_newer: Option>, + strategy: SolveStrategy, +} + +fn solve( + repo_path: &[String], + task: SimpleSolveTask<'_>, +) -> Result { + let repo_data = repo_path + .iter() + .map(|path| read_repodata(path)) + .collect::>(); + + let specs: Vec<_> = task + .specs + .iter() + .map(|m| MatchSpec::from_str(m, ParseStrictness::Lenient).unwrap()) + .collect(); + + let constraints = task + .constraints + .into_iter() + .map(|m| MatchSpec::from_str(m, ParseStrictness::Lenient).unwrap()) + .collect(); + + let task = SolverTask { + locked_packages: task.installed_packages, + virtual_packages: task.virtual_packages, + specs, + constraints, + pinned_packages: task.pinned_packages, + exclude_newer: task.exclude_newer, + strategy: task.strategy, + ..SolverTask::from_iter(&repo_data) + }; + + let pkgs = T::default().solve(task)?; + + if pkgs.records.is_empty() { + println!("No packages in the environment!"); + } + + Ok(pkgs) +} + +#[derive(Default)] +struct CompareTask<'a> { + specs: Vec<&'a str>, + exclude_newer: Option>, +} + +fn compare_solve(task: CompareTask<'_>) { + let specs = task + .specs + .iter() + .map(|s| MatchSpec::from_str(s, ParseStrictness::Lenient).unwrap()) + .collect::>(); + + let sparse_repo_data = read_real_world_repo_data(); + + let names = specs.iter().filter_map(|s| s.name.as_ref().cloned()); + let available_packages = SparseRepoData::load_records_recursive( + sparse_repo_data, + names, + None, + PackageFormatSelection::default(), + ) + .unwrap(); + + let extract_pkgs = |records: Vec| { + let mut pkgs = records + .into_iter() + .map(|pkg| { + format!( + "{} {} {}", + pkg.package_record.name.as_normalized(), + pkg.package_record.version, + pkg.package_record.build + ) + }) + .collect::>(); + + // The order of packages is nondeterministic, so we sort them to ensure we can + // compare them to a previous run + pkgs.sort(); + pkgs + }; + + let mut results = Vec::new(); + + #[cfg(feature = "libsolv_c")] + { + let start_solve = Instant::now(); + results.push(( + "libsolv_c", + extract_pkgs( + rattler_solve::libsolv_c::Solver + .solve(SolverTask { + specs: specs.clone(), + exclude_newer: task.exclude_newer, + ..SolverTask::from_iter(&available_packages) + }) + .unwrap() + .records, + ), + )); + let end_solve = Instant::now(); + println!("libsolv_c took {}ms", (end_solve - start_solve).as_millis()); + } + + #[cfg(feature = "resolvo")] + { + let start_solve = Instant::now(); + results.push(( + "resolvo", + extract_pkgs( + rattler_solve::resolvo::Solver + .solve(SolverTask { + specs: specs.clone(), + exclude_newer: task.exclude_newer, + ..SolverTask::from_iter(&available_packages) + }) + .unwrap() + .records, + ), + )); + let end_solve = Instant::now(); + println!("resolvo took {}ms", (end_solve - start_solve).as_millis()); + } + + results.into_iter().fold(None, |previous, current| { + let previous = match previous { + Some(previous) => previous, + None => return Some(current), + }; + + similar_asserts::assert_eq!( + &previous.1, + ¤t.1, + "The result between {} and {} differs", + &previous.0, + ¤t.0 + ); + + Some(current) + }); +} + +#[test] +fn compare_solve_tensorboard() { + compare_solve(CompareTask { + specs: vec!["tensorboard=2.1.1", "grpc-cpp=1.39.1"], + ..CompareTask::default() + }); +} + +#[test] +fn compare_solve_python() { + compare_solve(CompareTask { + specs: vec!["python=3.9"], + ..CompareTask::default() + }); +} + +#[test] +fn compare_solve_tensorflow() { + compare_solve(CompareTask { + specs: vec!["tensorflow"], + ..CompareTask::default() + }); +} + +#[test] +fn compare_solve_quetz() { + compare_solve(CompareTask { + specs: vec!["quetz"], + ..CompareTask::default() + }); +} + +#[test] +fn compare_solve_xtensor_xsimd() { + compare_solve(CompareTask { + specs: vec!["xtensor", "xsimd"], + ..CompareTask::default() + }); +} + +fn solve_to_get_channel_of_spec( + spec_str: &str, + expected_channel: &str, + repo_data: Vec<&SparseRepoData>, + channel_priority: ChannelPriority, +) { + let spec = MatchSpec::from_str(spec_str, ParseStrictness::Lenient).unwrap(); + let specs = vec![spec.clone()]; + let names = specs.iter().filter_map(|s| s.name.as_ref().cloned()); + + let available_packages = SparseRepoData::load_records_recursive( + repo_data, + names, + None, + PackageFormatSelection::default(), + ) + .unwrap(); + + let task = SolverTask { + specs: specs.clone(), + channel_priority, + ..SolverTask::from_iter(&available_packages) + }; + + let result: Vec = T::default().solve(task).unwrap().records; + + let record = result.iter().find(|record| { + record.package_record.name.as_normalized() == spec.name.as_ref().unwrap().as_normalized() + }); + assert_eq!(record.unwrap().channel, Some(expected_channel.to_string())); +} + +#[test] +fn channel_specific_requirement() { + let repodata = vec![ + read_conda_forge_sparse_repo_data(), + read_pytorch_sparse_repo_data(), + ]; + solve_to_get_channel_of_spec::( + "conda-forge::pytorch-cpu", + "https://conda.anaconda.org/conda-forge/", + repodata.clone(), + ChannelPriority::Strict, + ); + solve_to_get_channel_of_spec::( + "conda-forge::pytorch-cpu", + "https://conda.anaconda.org/conda-forge/", + repodata.clone(), + ChannelPriority::Disabled, + ); + solve_to_get_channel_of_spec::( + "pytorch::pytorch-cpu", + "https://conda.anaconda.org/pytorch/", + repodata.clone(), + ChannelPriority::Strict, + ); + solve_to_get_channel_of_spec::( + "pytorch::pytorch-cpu", + "https://conda.anaconda.org/pytorch/", + repodata, + ChannelPriority::Disabled, + ); +} + +#[test] +fn channel_priority_strict() { + // Solve with conda-forge as the first channel + let repodata = vec![ + read_conda_forge_sparse_repo_data(), + read_pytorch_sparse_repo_data(), + ]; + solve_to_get_channel_of_spec::( + "pytorch-cpu", + "https://conda.anaconda.org/conda-forge/", + repodata, + ChannelPriority::Strict, + ); + + // Solve with pytorch as the first channel + let repodata = vec![ + read_pytorch_sparse_repo_data(), + read_conda_forge_sparse_repo_data(), + ]; + solve_to_get_channel_of_spec::( + "pytorch-cpu", + "https://conda.anaconda.org/pytorch/", + repodata, + ChannelPriority::Strict, + ); +} + +#[test] +#[should_panic( + expected = "called `Result::unwrap()` on an `Err` value: Unsolvable([\"The following packages \ + are incompatible\\n└─ pytorch-cpu ==0.4.1 py36_cpu_1 cannot be installed because there are no \ + viable options:\\n └─ pytorch-cpu 0.4.1 is excluded because due to strict channel priority \ + not using this option from: 'https://conda.anaconda.org/pytorch/'\\n\"])" +)] +fn channel_priority_strict_panic() { + let repodata = vec![ + read_conda_forge_sparse_repo_data(), + read_pytorch_sparse_repo_data(), + ]; + solve_to_get_channel_of_spec::( + "pytorch-cpu=0.4.1=py36_cpu_1", + "https://conda.anaconda.org/pytorch/", + repodata, + ChannelPriority::Strict, + ); +} + +#[test] +fn channel_priority_disabled() { + let repodata = vec![ + read_conda_forge_sparse_repo_data(), + read_pytorch_sparse_repo_data(), + ]; + solve_to_get_channel_of_spec::( + "pytorch-cpu=0.4.1=py36_cpu_1", + "https://conda.anaconda.org/pytorch/", + repodata, + ChannelPriority::Disabled, + ); +} + +#[cfg(feature = "libsolv_c")] +#[test] +#[should_panic( + expected = "called `Result::unwrap()` on an `Err` value: Unsolvable([\"package \ + pytorch-cpu-0.4.1-py36_cpu_1 is excluded by strict repo priority\"])" +)] +fn channel_priority_strict_libsolv_c() { + let repodata = vec![ + read_conda_forge_sparse_repo_data(), + read_pytorch_sparse_repo_data(), + ]; + + solve_to_get_channel_of_spec::( + "pytorch-cpu=0.4.1=py36_cpu_1", + "https://conda.anaconda.org/pytorch/", + repodata, + ChannelPriority::Strict, + ); +} + +#[cfg(feature = "libsolv_c")] +#[test] +fn channel_priority_disabled_libsolv_c() { + let repodata = vec![ + read_conda_forge_sparse_repo_data(), + read_pytorch_sparse_repo_data(), + ]; + + solve_to_get_channel_of_spec::( + "pytorch-cpu=0.4.1=py36_cpu_1", + "https://conda.anaconda.org/pytorch/", + repodata, + ChannelPriority::Disabled, + ); +} diff --git a/crates/rattler_solve/tests/sorting.rs b/crates/rattler_solve/tests/sorting.rs index 5dba6d1a14..54836ace0a 100644 --- a/crates/rattler_solve/tests/sorting.rs +++ b/crates/rattler_solve/tests/sorting.rs @@ -54,9 +54,7 @@ fn create_sorting_snapshot(package_name: &str, strategy: SolveStrategy) -> Strin ) .expect("failed to create dependency provider"); - let name = dependency_provider - .pool - .intern_package_name(package_name.as_normalized()); + let name = dependency_provider.pool.intern_package_name(&package_name); let version_set = dependency_provider .pool .intern_version_set(name, match_spec.into_nameless().1.into()); diff --git a/test-data/channels/dummy-optional-dependencies/noarch/repodata.json b/test-data/channels/dummy-optional-dependencies/noarch/repodata.json index 7afe3fa037..f14c614aa7 100644 --- a/test-data/channels/dummy-optional-dependencies/noarch/repodata.json +++ b/test-data/channels/dummy-optional-dependencies/noarch/repodata.json @@ -1,528 +1,55 @@ { - "info": { - "subdir": "noarch", - "base_url": "../linux-64" - }, - "packages": { - "cuda-version-12.5-hd4f0392_3.conda": { - "build": "hd4f0392_3", - "build_number": 3, - "depends": [], - "constrains": [ - "__cuda >=12.1" - ], - "license": "LicenseRef-NVIDIA-End-User-License-Agreement", - "license_family": "LicenseRef-NVIDIA-End-User-License-Agreement", - "md5": "6ae1a563a4aa61e55e8ae8260f0d021b", - "name": "cuda-version", - "sha256": "e45a5d14909296abd0784a073da9ee5c420fa58671fbc999f8a9ec898cf3486b", - "size": 21151, - "subdir": "noarch", - "timestamp": 1716314536803, - "version": "12.5", - "extra_depends": { - "with-cudadev": [ - "foo >=4.0.2", - "bar >=1.2.3" - ] - } - }, - "foo-2.0.2-py36h1af98f8_1.tar.bz2": { - "build": "py36h1af98f8_1", - "build_number": 1, - "depends": [], - "license": "MIT", - "license_family": "MIT", - "md5": "d65ab674acf3b7294ebacaec05fc5b54", - "name": "foo", - "sha256": "1154fceeb5c4ee9bb97d245713ac21eb1910237c724d2b7103747215663273c2", - "size": 414494, - "subdir": "noarch", - "timestamp": 1605110689658, - "version": "2.0.2", - "extra_depends": { - "with-oldbors": [ - "bors <2.0" - ], - "with-latest-bors": [ - "bors >=2.0" - ], - "legacy-only": [ - "bar >=1.0" - ], - "with-recursive": [ - "foo[extras=[with-bar]]" - ], - "with-self": [ - "foo >=2.0" - ] - } - }, - "foo-3.0.2-py36h1af98f8_1.conda": { - "build": "py36h1af98f8_1", - "build_number": 1, - "depends": [], - "license": "MIT", - "license_family": "MIT", - "md5": "fb731d9290f0bcbf3a054665f33ec94f", - "name": "foo", - "sha256": "67a63bec3fd3205170eaad532d487595b8aaceb9814d13c6858d7bac3ef24cd4", - "size": 414494, - "subdir": "noarch", - "timestamp": 1715610974000, - "version": "3.0.2", - "extra_depends": { - "with-baz2": [ - "baz >=2.0" - ], - "with-bar": [ - "bar >=1.2.3" - ], - "with-version-restrict": [ - "foo <3.0.3" - ] - } - }, - "foo-3.0.3-py36h1af98f8_2.conda": { - "build": "py36h1af98f8_2", - "build_number": 2, - "depends": [], - "license": "MIT", - "license_family": "MIT", - "md5": "fb731d9290f0bcbf3a054665f33ec94f", - "name": "foo", - "sha256": "67a63bec3fd3205170eaad532d487595b8aaceb9814d13c6858d7bac3ef24cd4", - "size": 414494, - "subdir": "noarch", - "timestamp": 1715610974000, - "version": "3.0.3", - "extra_depends": { - "with-foobar21": [ - "foobar >=2.1" - ], - "with-bors2": [ - "bors >=1.2.1" - ] - } - }, - "foo-3.0.4-py36h1af98f8_3.conda": { - "build": "py36h1af98f8_3", - "build_number": 3, - "depends": [], - "constrains": [ - "bors <2.0" - ], - "license": "MIT", - "license_family": "MIT", - "md5": "fb731d9290f0bcbf3a054665f33ec94f", - "name": "foo", - "sha256": "67a63bec3fd3205170eaad532d487595b8aaceb9814d13c6858d7bac3ef24cd4", - "size": 414494, - "subdir": "noarch", - "timestamp": 1715610974000, - "version": "3.0.4", - "extra_depends": { - "with-issue717": [ - "issue_717 >=2.1" - ], - "with-xfoo2": [ - "xfoo >=2" - ] - } - }, - "foo-3.1.0-py36h1af98f8_1.conda": { - "build": "py36h1af98f8_1", - "build_number": 1, - "depends": [], - "license": "MIT", - "license_family": "MIT", - "md5": "fb731d9290f0bcbf3a054665f33ec94f", - "name": "foo", - "sha256": "67a63bec3fd3205170eaad532d487595b8aaceb9814d13c6858d7bac3ef24cd4", - "size": 414494, - "subdir": "noarch", - "timestamp": 1715610974000, - "version": "3.1.0", - "extra_depends": { - "with-bar": [ - "bar >=1.2.3" - ] - } - }, - "foo-3.2.0-py36h1af98f8_1.conda": { - "build": "py36h1af98f8_1", - "build_number": 1, - "depends": [], - "license": "MIT", - "license_family": "MIT", - "md5": "fb731d9290f0bcbf3a054665f33ec94f", - "name": "foo", - "sha256": "67a63bec3fd3205170eaad532d487595b8aaceb9814d13c6858d7bac3ef24cd4", - "size": 414494, - "subdir": "noarch", - "timestamp": 1715610974000, - "version": "3.2.0", - "extra_depends": { - "with-bar": [ - "bar >=1.2.3" - ] - } - }, - "foo-3.3.0-py36h1af98f8_1.conda": { - "build": "py36h1af98f8_1", - "build_number": 1, - "depends": [], - "license": "MIT", - "license_family": "MIT", - "md5": "fb731d9290f0bcbf3a054665f33ec94f", - "name": "foo", - "sha256": "67a63bec3fd3205170eaad532d487595b8aaceb9814d13c6858d7bac3ef24cd4", - "size": 414494, - "subdir": "noarch", - "timestamp": 1715610974000, - "version": "3.3.0", - "extra_depends": { - "with-bar": [ - "bar >=1.2.3" - ] - } - }, - "foo-3.4.0-py36h1af98f8_1.conda": { - "build": "py36h1af98f8_1", - "build_number": 1, - "depends": [], - "license": "MIT", - "license_family": "MIT", - "md5": "fb731d9290f0bcbf3a054665f33ec94f", - "name": "foo", - "sha256": "67a63bec3fd3205170eaad532d487595b8aaceb9814d13c6858d7bac3ef24cd4", - "size": 414494, - "subdir": "noarch", - "timestamp": 1715610974000, - "version": "3.4.0", - "extra_depends": { - "with-bar": [ - "bar >=1.2.3" - ] - } - }, - "foo-3.5.0-py36h1af98f8_1.conda": { - "build": "py36h1af98f8_1", - "build_number": 1, - "depends": [], - "license": "MIT", - "license_family": "MIT", - "md5": "fb731d9290f0bcbf3a054665f33ec94f", - "name": "foo", - "sha256": "67a63bec3fd3205170eaad532d487595b8aaceb9814d13c6858d7bac3ef24cd4", - "size": 414494, - "subdir": "noarch", - "timestamp": 1715610974000, - "version": "3.5.0", - "extra_depends": { - "with-bar": [ - "bar >=1.2.3" - ] - } - }, - "foo-4.0.2-py36h1af98f8_2.tar.bz2": { - "build": "py36h1af98f8_2", - "build_number": 1, - "depends": [], - "license": "MIT", - "license_family": "MIT", - "md5": "bc13aa58e2092bcb0b97c561373d3905", - "name": "foo", - "sha256": "97ec377d2ad83dfef1194b7aa31b0c9076194e10d995a6e696c9d07dd782b14a", - "size": 414494, - "subdir": "noarch", - "timestamp": 1715610974000, - "version": "4.0.2", - "extra_depends": { - "with-xbar": [ - "xbar >=1" - ] - } - }, - "bar-1.0-unix_py36h1af98f8_2.tar.bz2": { - "build": "unix_py36h1af98f8_2", - "build_number": 1, - "depends": [ - ], - "license": "MIT", - "license_family": "MIT", - "md5": "bc13aa58e2092bcb0b97c561373d3905", - "name": "bar", - "sha256": "97ec377d2ad83dfef1194b7aa31b0c9076194e10d995a6e696c9d07dd782b14a", - "size": 414494, - "subdir": "noarch", - "timestamp": 1605110689658, - "version": "1.2.3", - "extra_depends": { - "with-xfoo": [ - "xfoo >=1" - ] - } - }, - "baz-1.0-unix_py36h1af98f8_2.tar.bz2": { - "build": "unix_py36h1af98f8_2", - "build_number": 1, - "depends": [ - "__unix" - ], - "license": "MIT", - "license_family": "MIT", - "md5": "bc13aa58e2092bcb0b97c561373d3905", - "name": "baz", - "sha256": "97ec377d2ad83dfef1194b7aa31b0c9076194e10d995a6e696c9d07dd782b14a", - "size": 414494, - "subdir": "noarch", - "timestamp": 1605110689658, - "version": "1.2.3", - "extra_depends": { - "with-foobar": [ - "foobar >=2.0" - ] - } - }, - "baz-2.0-unix_py36h1af98f8_2.tar.bz2": { - "build": "unix_py36h1af98f8_2", - "build_number": 1, - "depends": [], - "license": "MIT", - "license_family": "MIT", - "md5": "bc13aa58e2092bcb0b97c561373d3905", - "name": "baz", - "sha256": "97ec377d2ad83dfef1194b7aa31b0c9076194e10d995a6e696c9d07dd782b14a", - "size": 414494, - "subdir": "noarch", - "timestamp": 1715610974000, - "version": "2.0", - "extra_depends": { - "with-bors": [ - "bors >=2.0" - ] - } - }, - "bors-1.0-bla_1.tar.bz2": { - "build": "bla_1", - "build_number": 1, - "depends": [], - "license": "MIT", - "license_family": "MIT", - "md5": "bc13aa58e2092bcb0b97c561373d3905", - "name": "bors", - "sha256": "97ec377d2ad83dfef1194b7aa31b0c9076194e10d995a6e696c9d07dd782b14a", - "size": 414494, - "subdir": "noarch", - "timestamp": 1605110689658, - "version": "1.0", - "extra_depends": { - "with-baz10": [ - "baz >=1.0" - ] - } - }, - "bors-1.1-bla_1.tar.bz2": { - "build": "bla_1", - "build_number": 1, - "depends": [], - "license": "MIT", - "license_family": "MIT", - "md5": "bc13aa58e2092bcb0b97c561373d3905", - "name": "bors", - "sha256": "97ec377d2ad83dfef1194b7aa31b0c9076194e10d995a6e696c9d07dd782b14a", - "size": 414494, - "subdir": "noarch", - "timestamp": 1605110689658, - "version": "1.1", - "extra_depends": { - "with-foobar20": [ - "foobar >=2.0" - ] - } - }, - "bors-1.2.1-bla_1.tar.bz2": { - "build": "bla_1", - "build_number": 1, - "depends": [], - "license": "MIT", - "license_family": "MIT", - "md5": "bc13aa58e2092bcb0b97c561373d3905", - "name": "bors", - "sha256": "97ec377d2ad83dfef1194b7aa31b0c9076194e10d995a6e696c9d07dd782b14a", - "size": 414494, - "subdir": "noarch", - "timestamp": 1605110689658, - "version": "1.2.1", - "extra_depends": { - "with-baz2": [ - "baz >=2.0" - ] - } - }, - "bors-2.0-bla_1.tar.bz2": { - "build": "bla_1", - "build_number": 1, - "depends": [], - "license": "MIT", - "license_family": "MIT", - "md5": "bc13aa58e2092bcb0b97c561373d3905", - "name": "bors", - "sha256": "97ec377d2ad83dfef1194b7aa31b0c9076194e10d995a6e696c9d07dd782b14a", - "size": 414494, - "subdir": "noarch", - "timestamp": 1715610974000, - "version": "2.0", - "extra_depends": { - "with-xbar": [ - "xbar >=1" - ] - } - }, - "bors-2.1-bla_1.tar.bz2": { - "build": "bla_1", - "build_number": 1, - "depends": [], - "license": "MIT", - "license_family": "MIT", - "md5": "bc13aa58e2092bcb0b97c561373d3905", - "name": "bors", - "sha256": "97ec377d2ad83dfef1194b7aa31b0c9076194e10d995a6e696c9d07dd782b14a", - "size": 414494, - "subdir": "noarch", - "timestamp": 1715610974000, - "version": "2.1", - "extra_depends": { - "with-cuda": [ - "cuda-version >=12.5" - ] - } - }, - "foobar-2.0-bla_1.tar.bz2": { - "build": "bla_1", - "build_number": 1, - "depends": [ - "bors <2.0" - ], - "license": "MIT", - "license_family": "MIT", - "md5": "bc13aa58e2092bcb0b97c561373d3905", - "name": "foobar", - "sha256": "97ec377d2ad83dfef1194b7aa31b0c9076194e10d995a6e696c9d07dd782b14a", - "size": 414494, - "subdir": "noarch", - "timestamp": 1605110689658, - "version": "2.0", - "extra_depends": { - "with-baz10": [ - "baz >=1.0" - ] - } - }, - "foobar-2.1-bla_1.tar.bz2": { - "build": "bla_1", - "build_number": 1, - "depends": [ - "bors <2.0" - ], - "license": "MIT", - "license_family": "MIT", - "md5": "bc13aa58e2092bcb0b97c561373d3905", - "name": "foobar", - "sha256": "97ec377d2ad83dfef1194b7aa31b0c9076194e10d995a6e696c9d07dd782b14a", - "size": 414494, - "subdir": "noarch", - "timestamp": 1715610974000, - "version": "2.1", - "extra_depends": { - "with-baz2": [ - "baz >=2.0" - ] - } - }, - "issue_717-2.1-bla_1.tar.bz2": { - "build": "issue_717", - "build_number": 0, - "depends": [], - "constrains": [ - "ray[version=>=2.9.0, extras=[default,data]]" - ], - "license": "MIT", - "license_family": "MIT", - "md5": "bc13aa58e2092bcb0b97c561373d3905", - "name": "issue_717", - "sha256": "97ec377d2ad83dfef1194b7aa31b0c9076194e10d995a6e696c9d07dd782b14a", - "size": 414494, - "subdir": "noarch", - "timestamp": 1715610974000, - "version": "2.1", - "extra_depends": { - "with-bors21": [ - "bors >=2.1" - ] - } - }, - "xfoo-1-xxx.tar.bz2": { - "build": "xxx", - "build_number": 0, - "depends": [], - "license": "MIT", - "license_family": "MIT", - "md5": "bc13aa58e2092bcb0b97c561373d3905", - "name": "xfoo", - "sha256": "97ec377d2ad83dfef1194b7aa31b0c9076194e10d995a6e696c9d07dd782b14a", - "size": 414494, - "subdir": "noarch", - "timestamp": 1715610974000, - "version": "1", - "extra_depends": { - "with-cuda": [ - "cuda-version >=12.5" - ] - } - }, - "xfoo-2-xxx.tar.bz2": { - "build": "xxx", - "build_number": 0, - "depends": [], - "license": "MIT", - "license_family": "MIT", - "md5": "bc13aa58e2092bcb0b97c561373d3905", - "name": "xfoo", - "sha256": "97ec377d2ad83dfef1194b7aa31b0c9076194e10d995a6e696c9d07dd782b14a", - "size": 414494, - "subdir": "noarch", - "timestamp": 1715610974000, - "version": "2", - "extra_depends": { - "with-issue717": [ - "issue_717[version=>=2.1, extras=[with-bors21]]" - ] - } - }, - "xbar-1-xxx.tar.bz2": { - "build": "xxx", - "build_number": 0, - "depends": [ - "xfoo >=2" - ], - "license": "MIT", - "license_family": "MIT", - "md5": "bc13aa58e2092bcb0b97c561373d3905", - "name": "xbar", - "sha256": "97ec377d2ad83dfef1194b7aa31b0c9076194e10d995a6e696c9d07dd782b14a", - "size": 414494, - "subdir": "noarch", - "timestamp": 1715610974000, - "version": "1", - "extra_depends": { - "with-foo4": [ - "foo >=4.0.2" - ] - } + "info": { + "subdir": "noarch", + "base_url": "../linux-64" + }, + "packages": { + "foo-1-xxx.tar.bz2": { + "name": "foo", + "version": "1", + "build": "xxx", + "build_number": 0, + "depends": [], + "subdir": "linux-64", + "extra_depends": { + "with-bar": [ + "bar <2" + ] } }, - "packages.conda": {}, - "repodata_version": 2 - } + "bar-1-xxx.tar.bz2": { + "name": "bar", + "version": "1", + "build": "xxx", + "build_number": 0, + "depends": [], + "subdir": "linux-64" + }, + "bar-2-xxx.tar.bz2": { + "name": "bar", + "version": "2", + "build": "xxx", + "build_number": 0, + "depends": [], + "subdir": "linux-64" + }, + "conflicting-extras-1-xxx.tar.bz2": { + "name": "conflicting-extras", + "version": "1", + "build": "xxx", + "build_number": 0, + "depends": [], + "subdir": "linux-64", + "extra_depends": { + "extra1": [ + "bar <2" + ], + "extra2": [ + "bar >=2" + ] + } + } + }, + "packages.conda": {}, + "repodata_version": 2 +} From c582555d58479a86ee4d6b262afe2b6247083d9e Mon Sep 17 00:00:00 2001 From: Wolf Vollprecht Date: Fri, 25 Jul 2025 23:38:29 +0200 Subject: [PATCH 02/11] fix doc issue --- crates/rattler_solve/src/resolvo/mod.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/crates/rattler_solve/src/resolvo/mod.rs b/crates/rattler_solve/src/resolvo/mod.rs index 0c8da6ceb2..8c01f2ab58 100644 --- a/crates/rattler_solve/src/resolvo/mod.rs +++ b/crates/rattler_solve/src/resolvo/mod.rs @@ -85,7 +85,8 @@ impl<'a> VersionSet for SolverMatchSpec<'a> { type V = SolverPackageRecord<'a>; } -/// Wrapper around [`PackageRecord`] so that we can use it in resolvo pool +/// Wrapper around [`RepoDataRecord`] so that we can use it in resolvo pool. +/// Also represents a virtual package or an extra of a package. #[derive(Eq, PartialEq)] pub enum SolverPackageRecord<'a> { /// Represents a record from the repodata From 6fe9a51f1a8a00c1b52bd23ab32086b364284ad7 Mon Sep 17 00:00:00 2001 From: Wolf Vollprecht Date: Fri, 25 Jul 2025 23:39:13 +0200 Subject: [PATCH 03/11] remove weird file --- crates/rattler_solve/tests/backends.rs~ | 1446 ----------------------- 1 file changed, 1446 deletions(-) delete mode 100644 crates/rattler_solve/tests/backends.rs~ diff --git a/crates/rattler_solve/tests/backends.rs~ b/crates/rattler_solve/tests/backends.rs~ deleted file mode 100644 index 43467137d7..0000000000 --- a/crates/rattler_solve/tests/backends.rs~ +++ /dev/null @@ -1,1446 +0,0 @@ -use std::{collections::BTreeMap, str::FromStr, time::Instant}; - -use chrono::{DateTime, Utc}; -use once_cell::sync::Lazy; -use rattler_conda_types::{ - Channel, ChannelConfig, GenericVirtualPackage, MatchSpec, NoArchType, PackageRecord, - ParseStrictness, RepoData, RepoDataRecord, SolverResult, Version, -}; -use rattler_repodata_gateway::sparse::{PackageFormatSelection, SparseRepoData}; -use rattler_solve::{ChannelPriority, SolveError, SolveStrategy, SolverImpl, SolverTask}; -use url::Url; - -fn channel_config() -> ChannelConfig { - ChannelConfig::default_with_root_dir(std::env::current_dir().unwrap()) -} - -fn conda_json_path() -> String { - format!( - "{}/{}", - env!("CARGO_MANIFEST_DIR"), - "../../test-data/channels/conda-forge/linux-64/repodata.json" - ) -} - -fn conda_json_path_noarch() -> String { - format!( - "{}/{}", - env!("CARGO_MANIFEST_DIR"), - "../../test-data/channels/conda-forge/noarch/repodata.json" - ) -} - -fn pytorch_json_path() -> String { - format!( - "{}/{}", - env!("CARGO_MANIFEST_DIR"), - "../../test-data/channels/pytorch/linux-64/repodata.json" - ) -} - -fn dummy_channel_json_path() -> String { - format!( - "{}/{}", - env!("CARGO_MANIFEST_DIR"), - "../../test-data/channels/dummy/linux-64/repodata.json" - ) -} - -#[cfg(feature = "experimental_extras")] -fn dummy_channel_with_optional_dependencies_json_path() -> String { - format!( - "{}/{}", - env!("CARGO_MANIFEST_DIR"), - "../../test-data/channels/dummy-optional-dependencies/noarch/repodata.json" - ) -} - -fn dummy_md5_hash() -> rattler_digest::Md5Hash { - rattler_digest::parse_digest_from_hex::("b3af409bb8423187c75e6c7f5b683908") - .unwrap() -} - -fn dummy_sha256_hash() -> rattler_digest::Sha256Hash { - rattler_digest::parse_digest_from_hex::( - "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad", - ) - .unwrap() -} - -fn read_repodata(path: &str) -> Vec { - let repo_data: RepoData = - serde_json::from_str(&std::fs::read_to_string(path).unwrap()).unwrap(); - repo_data.into_repo_data_records(&Channel::from_str("conda-forge", &channel_config()).unwrap()) -} - -fn read_sparse_repodata(path: &str) -> SparseRepoData { - SparseRepoData::from_file( - Channel::from_str("dummy", &channel_config()).unwrap(), - "dummy".to_string(), - path, - None, - ) - .unwrap() -} - -fn installed_package( - channel: &str, - subdir: &str, - name: &str, - version: &str, - build: &str, - build_number: u64, -) -> RepoDataRecord { - RepoDataRecord { - url: Url::from_str("http://example.com").unwrap(), - channel: Some(channel.to_string()), - file_name: "dummy-filename".to_string(), - package_record: PackageRecord { - name: name.parse().unwrap(), - version: version.parse().unwrap(), - build: build.to_string(), - build_number, - subdir: subdir.to_string(), - md5: Some(dummy_md5_hash()), - sha256: Some(dummy_sha256_hash()), - size: None, - arch: None, - extra_depends: BTreeMap::new(), - platform: None, - depends: Vec::new(), - constrains: Vec::new(), - track_features: Vec::new(), - features: None, - noarch: NoArchType::default(), - license: None, - license_family: None, - timestamp: None, - legacy_bz2_size: None, - legacy_bz2_md5: None, - purls: None, - python_site_packages_path: None, - run_exports: None, - }, - } -} - -fn solve_real_world(specs: Vec<&str>) -> Vec { - let specs = specs - .iter() - .map(|s| MatchSpec::from_str(s, ParseStrictness::Lenient).unwrap()) - .collect::>(); - - let sparse_repo_data = read_real_world_repo_data(); - - let names = specs.iter().filter_map(|s| s.name.as_ref().cloned()); - let available_packages = SparseRepoData::load_records_recursive( - sparse_repo_data, - names, - None, - PackageFormatSelection::default(), - ) - .unwrap(); - - let solver_task = SolverTask { - specs: specs.clone(), - ..SolverTask::from_iter(&available_packages) - }; - - let pkgs1 = match T::default().solve(solver_task) { - Ok(result) => result.records, - Err(e) => panic!("{e}"), - }; - - let extract_pkgs = |records: Vec| { - let mut pkgs = records - .into_iter() - .map(|pkg| { - format!( - "{} {} {}", - pkg.package_record.name.as_normalized(), - pkg.package_record.version, - pkg.package_record.build - ) - }) - .collect::>(); - - // The order of packages is nondeterministic, so we sort them to ensure we can - // compare them to a previous run - pkgs.sort(); - pkgs - }; - - extract_pkgs(pkgs1) -} - -fn read_real_world_repo_data() -> &'static Vec { - static REPO_DATA: Lazy> = Lazy::new(|| { - let json_file = conda_json_path(); - let json_file_noarch = conda_json_path_noarch(); - - vec![ - read_sparse_repodata(&json_file), - read_sparse_repodata(&json_file_noarch), - ] - }); - - &REPO_DATA -} - -fn read_pytorch_sparse_repo_data() -> &'static SparseRepoData { - static REPO_DATA: Lazy = Lazy::new(|| { - let pytorch = pytorch_json_path(); - SparseRepoData::from_file( - Channel::from_str("pytorch", &channel_config()).unwrap(), - "pytorch".to_string(), - pytorch, - None, - ) - .unwrap() - }); - - &REPO_DATA -} - -fn read_conda_forge_sparse_repo_data() -> &'static SparseRepoData { - static REPO_DATA: Lazy = Lazy::new(|| { - let conda_forge = conda_json_path(); - SparseRepoData::from_file( - Channel::from_str("conda-forge", &channel_config()).unwrap(), - "conda-forge".to_string(), - conda_forge, - None, - ) - .unwrap() - }); - &REPO_DATA -} -macro_rules! solver_backend_tests { - ($T:path) => { - use chrono::{DateTime, Utc}; - use itertools::Itertools; - - #[test] - fn test_solve_quetz() { - insta::assert_yaml_snapshot!(solve_real_world::<$T>(vec!["quetz",])); - } - - #[test] - fn test_solve_xtensor_xsimd() { - insta::assert_yaml_snapshot!(solve_real_world::<$T>(vec!["xtensor", "xsimd",])); - } - - #[test] - fn test_solve_tensorflow() { - insta::assert_yaml_snapshot!(solve_real_world::<$T>(vec!["tensorflow"])); - } - - #[test] - fn test_solve_tensorboard() { - insta::assert_yaml_snapshot!(solve_real_world::<$T>(vec![ - "tensorboard=2.1.1", - "grpc-cpp=1.39.1" - ])); - } - - #[test] - fn test_solve_python() { - insta::assert_yaml_snapshot!(solve_real_world::<$T>(vec!["python=3.9"])); - } - - #[test] - fn test_solve_python_numpy() { - insta::assert_yaml_snapshot!(solve_real_world::<$T>(vec![ - "numpy==1.23.2", - "scipy==1.8.1", - "python=3.9.*" - ])); - } - - #[test] - fn test_solve_favored() { - let result = solve::<$T>( - &[dummy_channel_json_path()], - SimpleSolveTask { - specs: &["bors"], - installed_packages: vec![installed_package( - "conda-forge", - "linux-64", - "bors", - "1.0", - "bla_1", - 1, - )], - ..SimpleSolveTask::default() - }, - ) - .unwrap(); - - assert_eq!(result.records.len(), 1); - assert_eq!(result.records[0].package_record.to_string(), "bors=1.0=bla_1"); - } - - #[test] - fn test_solve_with_error() { - let result = solve::<$T>( - &[dummy_channel_json_path()], - SimpleSolveTask { - specs: &["foobar >=2", "bors >= 2"], - ..SimpleSolveTask::default() - }, - ); - - assert!(result.is_err()); - - let err = result.err().unwrap(); - insta::assert_snapshot!(err); - } - - #[test] - fn test_solve_dummy_repo_install_non_existent() { - let result = solve::<$T>( - &[dummy_channel_json_path()], - SimpleSolveTask { - specs: &["asdfasdf", "foo<4"], - ..SimpleSolveTask::default() - }, - ); - - assert!(result.is_err()); - - let err = result.err().unwrap(); - insta::assert_debug_snapshot!(err); - } - - #[test] - fn test_solve_dummy_repo_missing_virtual_package() { - let result = solve::<$T>( - &[dummy_channel_json_path()], - SimpleSolveTask { - specs: &["bar"], - ..SimpleSolveTask::default() - }, - ); - - assert!(matches!(result.err(), Some(SolveError::Unsolvable(_)))); - } - - #[test] - fn test_solve_dummy_repo_with_virtual_package() { - let pkgs = solve::<$T>( - &[dummy_channel_json_path()], - SimpleSolveTask { - specs: &["bar"], - virtual_packages: vec![GenericVirtualPackage { - name: rattler_conda_types::PackageName::new_unchecked("__unix"), - version: Version::from_str("0").unwrap(), - build_string: "0".to_string(), - }], - ..SimpleSolveTask::default() - }, - ) - .unwrap(); - - assert_eq!(pkgs.records.len(), 1); - - let info = &pkgs.records[0]; - assert_eq!("bar", info.package_record.name.as_normalized()); - assert_eq!("1.2.3", &info.package_record.version.to_string()); - } - - #[test] - fn test_solve_dummy_repo_install_new() { - let pkgs = solve::<$T>( - &[dummy_channel_json_path()], - SimpleSolveTask { - specs: &["foo<4"], - ..SimpleSolveTask::default() - }, - ) - .unwrap(); - - assert_eq!(1, pkgs.records.len()); - let info = &pkgs.records[0]; - - assert_eq!("foo-3.0.2-py36h1af98f8_3.conda", info.file_name); - assert_eq!( - "https://conda.anaconda.org/conda-forge/linux-64/foo-3.0.2-py36h1af98f8_3.conda", - info.url.to_string() - ); - assert_eq!(Some("https://conda.anaconda.org/conda-forge/"), info.channel.as_deref()); - assert_eq!("foo", info.package_record.name.as_normalized()); - assert_eq!("linux-64", info.package_record.subdir); - assert_eq!("3.0.2", info.package_record.version.to_string()); - assert_eq!("py36h1af98f8_3", info.package_record.build); - assert_eq!(3, info.package_record.build_number); - assert_eq!( - rattler_digest::parse_digest_from_hex::( - "67a63bec3fd3205170eaad532d487595b8aaceb9814d13c6858d7bac3ef24cd4" - ) - .as_ref() - .unwrap(), - info.package_record.sha256.as_ref().unwrap() - ); - assert_eq!( - rattler_digest::parse_digest_from_hex::( - "fb731d9290f0bcbf3a054665f33ec94f" - ) - .as_ref() - .unwrap(), - info.package_record.md5.as_ref().unwrap() - ); - } - - #[test] - fn test_solve_dummy_repo_prefers_conda_package() { - // There following package is provided as .tar.bz and as .conda in repodata.json - let match_spec = "foo=3.0.2=py36h1af98f8_1"; - - let operations = solve::<$T>( - &[dummy_channel_json_path()], - SimpleSolveTask { - specs: &[match_spec], - ..SimpleSolveTask::default() - }, - ) - .unwrap(); - - // The .conda entry is selected for installing - assert_eq!(operations.records.len(), 1); - assert_eq!(operations.records[0].file_name, "foo-3.0.2-py36h1af98f8_1.conda"); - } - - #[test] - fn test_solve_dummy_repo_install_noop() { - let already_installed = vec![installed_package( - "conda-forge", - "linux-64", - "foo", - "3.0.2", - "py36h1af98f8_1", - 1, - )]; - - let pkgs = solve::<$T>( - &[dummy_channel_json_path()], - SimpleSolveTask { - specs: &["foo<4"], - installed_packages: already_installed, - ..SimpleSolveTask::default() - }, - ) - .unwrap(); - - assert_eq!(1, pkgs.records.len()); - - // Install - let info = &pkgs.records[0]; - assert_eq!("foo", info.package_record.name.as_normalized()); - assert_eq!("3.0.2", &info.package_record.version.to_string()); - } - - #[test] - fn test_solve_dummy_repo_upgrade() { - let already_installed = vec![installed_package( - "conda-forge", - "linux-64", - "foo", - "3.0.2", - "py36h1af98f8_1", - 1, - )]; - - let pkgs = solve::<$T>( - &[dummy_channel_json_path()], - SimpleSolveTask { - specs: &["foo>=4"], - installed_packages: already_installed, - ..SimpleSolveTask::default() - }, - ) - .unwrap(); - - // Install - let info = &pkgs.records[0]; - assert_eq!("foo", info.package_record.name.as_normalized()); - assert_eq!("4.0.2", &info.package_record.version.to_string()); - } - - #[test] - fn test_solve_dummy_repo_downgrade() { - let already_installed = vec![installed_package( - "conda-forge", - "linux-64", - "foo", - "4.0.2", - "py36h1af98f8_1", - 1, - )]; - - let pkgs = solve::<$T>( - &[dummy_channel_json_path()], - SimpleSolveTask { - specs: &["foo<4"], - installed_packages: already_installed, - ..SimpleSolveTask::default() - }, - ) - .unwrap(); - - assert_eq!(pkgs.records.len(), 1); - - // Uninstall - let info = &pkgs.records[0]; - assert_eq!("foo", info.package_record.name.as_normalized()); - assert_eq!("3.0.2", &info.package_record.version.to_string()); - } - - #[test] - fn test_solve_dummy_repo_remove() { - let already_installed = vec![installed_package( - "conda-forge", - "linux-64", - "foo", - "3.0.2", - "py36h1af98f8_1", - 1, - )]; - - let pkgs = solve::<$T>( - &[dummy_channel_json_path()], - SimpleSolveTask { - installed_packages: already_installed, - ..SimpleSolveTask::default() - }, - ) - .unwrap(); - - // Should be no packages! - assert_eq!(0, pkgs.records.len()); - } - - #[test] - fn test_exclude_newer() { - let date = "2021-12-12T12:12:12Z".parse::>().unwrap(); - - let pkgs = solve::<$T>( - &[dummy_channel_json_path()], - SimpleSolveTask { - specs: &["foo"], - exclude_newer: Some(date), - ..SimpleSolveTask::default() - }, - ) - .unwrap(); - - assert_eq!(1, pkgs.records.len()); - - let info = &pkgs.records[0]; - assert_eq!("foo", info.package_record.name.as_normalized()); - assert_eq!("3.0.2", &info.package_record.version.to_string(), - "although there is a newer version available we expect an older version of foo because we exclude the newer version based on the timestamp"); - assert_eq!(&info.file_name, "foo-3.0.2-py36h1af98f8_1.tar.bz2", "even though there is a conda version available we expect the tar.bz2 version because we exclude the .conda version based on the timestamp"); - } - - #[test] - fn test_duplicate_record() { - use rattler_solve::SolverImpl; - - let mut records = super::read_repodata(&dummy_channel_json_path()); - records.push(records[0].clone()); - - let task = rattler_solve::SolverTask::from_iter([&records]); - - let result = <$T>::default().solve(task); - match result { - Err(rattler_solve::SolveError::DuplicateRecords(_)) => {} - _ => panic!("expected a DuplicateRecord error"), - } - } - - #[test] - fn test_constraints() { - // There following package is provided as .tar.bz and as .conda in repodata.json - let mut operations = solve::<$T>( - &[dummy_channel_json_path()], - SimpleSolveTask { - specs: &["foobar"], - constraints: vec!["bors <=1", "nonexisting"], - ..SimpleSolveTask::default() - }, - ) - .unwrap(); - - // Sort operations by file name to make the test deterministic - operations.records.sort_by(|a, b| a.file_name.cmp(&b.file_name)); - - assert_eq!(operations.records.len(), 2); - assert_eq!(operations.records[0].file_name, "bors-1.0-bla_1.tar.bz2"); - assert_eq!(operations.records[1].file_name, "foobar-2.1-bla_1.tar.bz2"); - } - - #[test] - fn test_virtual_package_constrains() { - // This tests that a package that has a constrains on a virtual package is - // properly restricted. - let result = solve::<$T>( - &[dummy_channel_json_path()], - SimpleSolveTask { - specs: &["cuda-version"], - virtual_packages: vec![GenericVirtualPackage { - name: "__cuda".parse().unwrap(), - version: Version::from_str("1").unwrap(), - build_string: "0".to_string(), - }], - ..SimpleSolveTask::default() - }, - ); - - let output = match result { - Ok(pkgs) => pkgs - .records - .iter() - .format_with("\n", |pkg, f| { - f(&format_args!( - "{}={}={}", - pkg.package_record.name.as_normalized(), - pkg.package_record.version.as_str(), - &pkg.package_record.build - )) - }) - .to_string(), - Err(e) => e.to_string(), - }; - - insta::assert_snapshot!(output); - } - }; -} - -#[cfg(feature = "libsolv_c")] -mod libsolv_c { - #![allow(unused_imports)] // For some reason windows thinks this is an unused import. - - use rattler_solve::{ChannelPriority, SolveStrategy}; - - use super::{ - dummy_channel_json_path, installed_package, solve, solve_real_world, FromStr, - GenericVirtualPackage, SimpleSolveTask, SolveError, Version, - }; - - solver_backend_tests!(rattler_solve::libsolv_c::Solver); - - #[test] - #[cfg(target_family = "unix")] - fn test_solve_with_cached_solv_file_install_new() { - use rattler_conda_types::{Channel, ChannelConfig, MatchSpec, RepoDataRecord}; - use rattler_solve::{SolverImpl, SolverTask}; - - use super::read_repodata; - - let repo_data = read_repodata(&dummy_channel_json_path()); - - let cached_repo_data = rattler_solve::libsolv_c::cache_repodata( - Channel::from_str( - "conda-forge", - &ChannelConfig::default_with_root_dir(std::env::current_dir().unwrap()), - ) - .unwrap() - .platform_url(rattler_conda_types::Platform::Linux64) - .to_string(), - &repo_data, - None, - ) - .unwrap(); - - let libsolv_repodata = rattler_solve::libsolv_c::RepoData { - records: repo_data.iter().collect(), - solv_file: Some(&cached_repo_data), - }; - - let specs: Vec = vec!["foo<4".parse().unwrap()]; - - let pkgs: Vec = rattler_solve::libsolv_c::Solver - .solve(SolverTask { - locked_packages: Vec::new(), - virtual_packages: Vec::new(), - available_packages: [libsolv_repodata], - specs, - constraints: Vec::new(), - pinned_packages: Vec::new(), - timeout: None, - channel_priority: ChannelPriority::default(), - exclude_newer: None, - strategy: SolveStrategy::default(), - }) - .unwrap() - .records; - - if pkgs.is_empty() { - println!("No packages in the environment!"); - } - - assert_eq!(1, pkgs.len()); - let info = &pkgs[0]; - - assert_eq!("foo-3.0.2-py36h1af98f8_3.conda", info.file_name); - assert_eq!( - "https://conda.anaconda.org/conda-forge/linux-64/foo-3.0.2-py36h1af98f8_3.conda", - info.url.to_string() - ); - assert_eq!( - Some("https://conda.anaconda.org/conda-forge/"), - info.channel.as_deref() - ); - assert_eq!("foo", info.package_record.name.as_normalized()); - assert_eq!("linux-64", info.package_record.subdir); - assert_eq!("3.0.2", info.package_record.version.to_string()); - assert_eq!("py36h1af98f8_3", info.package_record.build); - assert_eq!(3, info.package_record.build_number); - assert_eq!( - rattler_digest::parse_digest_from_hex::( - "67a63bec3fd3205170eaad532d487595b8aaceb9814d13c6858d7bac3ef24cd4" - ) - .as_ref() - .unwrap(), - info.package_record.sha256.as_ref().unwrap() - ); - assert_eq!( - rattler_digest::parse_digest_from_hex::( - "fb731d9290f0bcbf3a054665f33ec94f" - ) - .as_ref() - .unwrap(), - info.package_record.md5.as_ref().unwrap() - ); - } -} - -#[cfg(feature = "resolvo")] -mod resolvo { - use rattler_conda_types::{ - MatchSpec, PackageRecord, ParseStrictness, RepoDataRecord, VersionWithSource, - }; - use rattler_solve::{SolveStrategy, SolverImpl, SolverTask}; - use url::Url; - - #[cfg(feature = "experimental_extras")] - use super::dummy_channel_with_optional_dependencies_json_path; - use super::{ - dummy_channel_json_path, installed_package, solve, solve_real_world, FromStr, - GenericVirtualPackage, SimpleSolveTask, SolveError, Version, - }; - - solver_backend_tests!(rattler_solve::resolvo::Solver); - - #[test] - fn test_solve_locked() { - let result = solve::( - &[dummy_channel_json_path()], - SimpleSolveTask { - specs: &["bors >=2"], - pinned_packages: vec![installed_package( - "conda-forge", - "linux-64", - "bors", - "1.0", - "bla_1", - 1, - )], - ..SimpleSolveTask::default() - }, - ); - - // We expect an error here. `bors` is pinnend to 1, but we try to install `>=2`. - insta::assert_snapshot!(result.unwrap_err()); - } - - #[test] - fn test_issue_717() { - let result = solve::( - &[dummy_channel_json_path()], - SimpleSolveTask { - specs: &["issue_717"], - ..SimpleSolveTask::default() - }, - ); - - // We expect an error here. `bors` is pinnend to 1, but we try to install `>=2`. - insta::assert_snapshot!(result.unwrap_err()); - } - - #[test] - fn test_exclude_newer_error() { - let date = "2021-12-12T12:12:12Z".parse::>().unwrap(); - - let result = solve::( - &[dummy_channel_json_path()], - SimpleSolveTask { - specs: &["foo>=4"], - exclude_newer: Some(date), - ..SimpleSolveTask::default() - }, - ); - - // We expect an error here. `bors` is pinnend to 1, but we try to install `>=2`. - insta::assert_snapshot!(result.unwrap_err()); - } - - #[test] - fn test_lowest_version_strategy_highest_build_number() { - let result = solve::( - &[dummy_channel_json_path()], - SimpleSolveTask { - specs: &["foo"], - strategy: rattler_solve::SolveStrategy::LowestVersion, - ..SimpleSolveTask::default() - }, - ) - .unwrap(); - - assert_eq!(result.records.len(), 1); - assert_eq!( - result.records[0].package_record.version, - Version::from_str("3.0.2").unwrap() - ); - assert_eq!( - result.records[0].package_record.build_number, 3, - "expected the highest build number" - ); - } - - #[test] - fn test_lowest_version_strategy_all() { - let result = solve::( - &[dummy_channel_json_path()], - SimpleSolveTask { - specs: &["foobar"], - strategy: rattler_solve::SolveStrategy::LowestVersion, - ..SimpleSolveTask::default() - }, - ) - .unwrap(); - - assert_eq!(result.records.len(), 2); - assert_eq!( - result.records[0].package_record.name.as_normalized(), - "foobar" - ); - assert_eq!( - result.records[0].package_record.version, - Version::from_str("2.0").unwrap(), - "expected lowest version of foobar" - ); - - assert_eq!( - result.records[1].package_record.name.as_normalized(), - "bors" - ); - assert_eq!( - result.records[1].package_record.version, - Version::from_str("1.0").unwrap(), - "expected lowest version of bors" - ); - } - - #[test] - fn test_lowest_direct_version_strategy() { - let result = solve::( - &[dummy_channel_json_path()], - SimpleSolveTask { - specs: &["foobar"], - strategy: rattler_solve::SolveStrategy::LowestVersionDirect, - ..SimpleSolveTask::default() - }, - ) - .unwrap(); - - assert_eq!(result.records.len(), 2); - assert_eq!( - result.records[0].package_record.name.as_normalized(), - "foobar" - ); - assert_eq!( - result.records[0].package_record.version, - Version::from_str("2.0").unwrap(), - "expected lowest version of foobar" - ); - - assert_eq!( - result.records[1].package_record.name.as_normalized(), - "bors" - ); - assert_eq!( - result.records[1].package_record.version, - Version::from_str("1.2.1").unwrap(), - "expected highest compatible version of bors" - ); - } - - /// Try to solve a package with a direct url, and then try to do it again - /// without having it in the repodata. - #[test] - fn test_solve_on_url() { - let url_str = - "https://conda.anaconda.org/conda-forge/linux-64/_libgcc_mutex-0.1-conda_forge.tar.bz2"; - let url = Url::parse(url_str).unwrap(); - - // Create a match spec for a package that is not in the repodata - let specs: Vec<_> = vec![MatchSpec::from_str(url_str, ParseStrictness::Lenient).unwrap()]; - - // Create RepoData with only the package from the url, so the solver can find it - let package_record = PackageRecord::new( - // // Only defining the name, version and url is enough for the solver to find the - // package direct_url: Some(url.clone()), - "_libgcc_mutex".parse().unwrap(), - VersionWithSource::from_str("0.1").unwrap(), - "0".to_string(), - ); - let repo_data: Vec = vec![RepoDataRecord { - package_record: package_record.clone(), - // Mocking the rest of the fields - file_name: url_str.to_string(), - url: url.clone(), - channel: None, - }]; - - // Completely clean solver task, except for the specs and RepoData - let task = SolverTask { - locked_packages: vec![], - virtual_packages: vec![], - specs: specs.clone(), - constraints: vec![], - pinned_packages: vec![], - exclude_newer: None, - strategy: SolveStrategy::default(), - ..SolverTask::from_iter([&repo_data]) - }; - - let pkgs: Vec = rattler_solve::resolvo::Solver.solve(task).unwrap().records; - - assert_eq!(pkgs.len(), 1); - assert_eq!(pkgs[0].package_record.name.as_normalized(), "_libgcc_mutex"); - assert_eq!(pkgs[0].url, url.clone()); - assert_eq!( - pkgs[0].package_record.version, - Version::from_str("0.1").unwrap(), - "expected lowest version of _libgcc_mutex" - ); - - // ----------------------------------------------------------------------------------------- - // Break the url in the repodata, making it not a direct url record. - - let repo_data: Vec = vec![RepoDataRecord { - package_record, - file_name: url_str.to_string(), - url: Url::from_str("https://false.dont").unwrap(), - channel: None, - }]; - - // Completely clean solver task, except for the specs and RepoData - let task = SolverTask { - locked_packages: vec![], - virtual_packages: vec![], - specs, - constraints: vec![], - pinned_packages: vec![], - exclude_newer: None, - strategy: SolveStrategy::default(), - ..SolverTask::from_iter([&repo_data]) - }; - - let solve_error = rattler_solve::resolvo::Solver.solve(task).unwrap_err(); - - assert!(matches!(solve_error, SolveError::Unsolvable(_))); - } - - #[test] - fn test_panic_on_constraint() { - let result = solve::( - &[dummy_channel_json_path()], - SimpleSolveTask { - specs: &["xbar"], - constraints: vec!["xfoo==1"], - pinned_packages: vec![installed_package( - "conda-forge", - "linux-64", - "xfoo", - "1", - "xxx", - 1, - )], - ..SimpleSolveTask::default() - }, - ); - - insta::assert_snapshot!(result.unwrap_err()); - } - - /// A test that checks that extras can be used to select optional dependencies. - #[cfg(feature = "experimental_extras")] - #[test] - fn test_optional_dependency() { - let mut result = solve::( - &[dummy_channel_with_optional_dependencies_json_path()], - SimpleSolveTask { - specs: &["foo[extras=[with-bar]]"], - ..SimpleSolveTask::default() - }, - ) - .unwrap(); - - // Sort the records by package name to make the test deterministic - result - .records - .sort_by(|a, b| a.package_record.name.cmp(&b.package_record.name)); - - // Collect the extras into a vector - let extras = result.features.into_iter().collect_vec(); - - // Make sure we have two packages `foo` and `bar` - assert_eq!(result.records.len(), 2); - assert_eq!(result.records[0].package_record.name.as_normalized(), "bar"); - assert_eq!(result.records[1].package_record.name.as_normalized(), "foo"); - - // Make sure there is an extra feature `with-bar` for `foo` - assert_eq!(extras.len(), 1); - assert_eq!(extras[0].0.as_normalized(), "foo"); - assert_eq!(extras[0].1, vec!["with-bar"]); - } - - /// A test that checks that extras influence the version selection of other packages. - #[cfg(feature = "experimental_extras")] - #[test] - fn test_optional_dependency_restrict() { - let mut result = solve::( - &[dummy_channel_with_optional_dependencies_json_path()], - SimpleSolveTask { - specs: &["foo[extras=[with-bar]]", "bar"], - ..SimpleSolveTask::default() - }, - ) - .unwrap(); - - // Sort the records by package name to make the test deterministic - result - .records - .sort_by(|a, b| a.package_record.name.cmp(&b.package_record.name)); - - // Even though 2 versions of `bar` are available, we should have - // selected the one with version "1" because it is restricted by the - // extra added to foo. - assert_eq!(result.records.len(), 2); - assert_eq!(result.records[0].file_name, "bar-1-xxx.tar.bz2"); - assert_eq!(result.records[1].package_record.name.as_normalized(), "foo"); - } - - /// A test that checks that if two extras have conflicting dependencies the - /// solution is unsolvable. - #[cfg(feature = "experimental_extras")] - #[test] - fn test_optional_dependency_conflicting_extras() { - let result = solve::( - &[dummy_channel_with_optional_dependencies_json_path()], - SimpleSolveTask { - specs: &["conflicting-extras[extras=[extra1, extra2]]"], - ..SimpleSolveTask::default() - }, - ); - - insta::assert_snapshot!(result.unwrap_err(), @r###" - Cannot solve the request because of: The following packages are incompatible - ├─ conflicting-extras[extra1] can be installed with any of the following options: - │ └─ conflicting-extras[extra1] - ├─ conflicting-extras[extra2] can be installed with any of the following options: - │ └─ conflicting-extras[extra2] - └─ conflicting-extras * cannot be installed because there are no viable options: - └─ conflicting-extras 1 would require - ├─ bar >=2, which can be installed with any of the following options: - │ └─ bar 2 - └─ bar <2, which cannot be installed because there are no viable options: - └─ bar 1, which conflicts with the versions reported above. - "###); - } - - /// A test that checks that extras can cause conflicts with other package - /// dependencies. - #[cfg(feature = "experimental_extras")] - #[test] - fn test_optional_dependency_conflicting_with_package() { - let result = solve::( - &[dummy_channel_with_optional_dependencies_json_path()], - SimpleSolveTask { - specs: &["conflicting-extras[extras=[extra1]]", "bar>=2"], - ..SimpleSolveTask::default() - }, - ); - - insta::assert_snapshot!(result.unwrap_err(), @r###" - Cannot solve the request because of: The following packages are incompatible - ├─ conflicting-extras[extra1] can be installed with any of the following options: - │ └─ conflicting-extras[extra1] - ├─ bar >=2 can be installed with any of the following options: - │ └─ bar 2 - └─ conflicting-extras * cannot be installed because there are no viable options: - └─ conflicting-extras 1 would require - └─ bar <2, which cannot be installed because there are no viable options: - └─ bar 1, which conflicts with the versions reported above. - "###); - } -} - -#[derive(Default)] -struct SimpleSolveTask<'a> { - specs: &'a [&'a str], - constraints: Vec<&'a str>, - installed_packages: Vec, - pinned_packages: Vec, - virtual_packages: Vec, - exclude_newer: Option>, - strategy: SolveStrategy, -} - -fn solve( - repo_path: &[String], - task: SimpleSolveTask<'_>, -) -> Result { - let repo_data = repo_path - .iter() - .map(|path| read_repodata(path)) - .collect::>(); - - let specs: Vec<_> = task - .specs - .iter() - .map(|m| MatchSpec::from_str(m, ParseStrictness::Lenient).unwrap()) - .collect(); - - let constraints = task - .constraints - .into_iter() - .map(|m| MatchSpec::from_str(m, ParseStrictness::Lenient).unwrap()) - .collect(); - - let task = SolverTask { - locked_packages: task.installed_packages, - virtual_packages: task.virtual_packages, - specs, - constraints, - pinned_packages: task.pinned_packages, - exclude_newer: task.exclude_newer, - strategy: task.strategy, - ..SolverTask::from_iter(&repo_data) - }; - - let pkgs = T::default().solve(task)?; - - if pkgs.records.is_empty() { - println!("No packages in the environment!"); - } - - Ok(pkgs) -} - -#[derive(Default)] -struct CompareTask<'a> { - specs: Vec<&'a str>, - exclude_newer: Option>, -} - -fn compare_solve(task: CompareTask<'_>) { - let specs = task - .specs - .iter() - .map(|s| MatchSpec::from_str(s, ParseStrictness::Lenient).unwrap()) - .collect::>(); - - let sparse_repo_data = read_real_world_repo_data(); - - let names = specs.iter().filter_map(|s| s.name.as_ref().cloned()); - let available_packages = SparseRepoData::load_records_recursive( - sparse_repo_data, - names, - None, - PackageFormatSelection::default(), - ) - .unwrap(); - - let extract_pkgs = |records: Vec| { - let mut pkgs = records - .into_iter() - .map(|pkg| { - format!( - "{} {} {}", - pkg.package_record.name.as_normalized(), - pkg.package_record.version, - pkg.package_record.build - ) - }) - .collect::>(); - - // The order of packages is nondeterministic, so we sort them to ensure we can - // compare them to a previous run - pkgs.sort(); - pkgs - }; - - let mut results = Vec::new(); - - #[cfg(feature = "libsolv_c")] - { - let start_solve = Instant::now(); - results.push(( - "libsolv_c", - extract_pkgs( - rattler_solve::libsolv_c::Solver - .solve(SolverTask { - specs: specs.clone(), - exclude_newer: task.exclude_newer, - ..SolverTask::from_iter(&available_packages) - }) - .unwrap() - .records, - ), - )); - let end_solve = Instant::now(); - println!("libsolv_c took {}ms", (end_solve - start_solve).as_millis()); - } - - #[cfg(feature = "resolvo")] - { - let start_solve = Instant::now(); - results.push(( - "resolvo", - extract_pkgs( - rattler_solve::resolvo::Solver - .solve(SolverTask { - specs: specs.clone(), - exclude_newer: task.exclude_newer, - ..SolverTask::from_iter(&available_packages) - }) - .unwrap() - .records, - ), - )); - let end_solve = Instant::now(); - println!("resolvo took {}ms", (end_solve - start_solve).as_millis()); - } - - results.into_iter().fold(None, |previous, current| { - let previous = match previous { - Some(previous) => previous, - None => return Some(current), - }; - - similar_asserts::assert_eq!( - &previous.1, - ¤t.1, - "The result between {} and {} differs", - &previous.0, - ¤t.0 - ); - - Some(current) - }); -} - -#[test] -fn compare_solve_tensorboard() { - compare_solve(CompareTask { - specs: vec!["tensorboard=2.1.1", "grpc-cpp=1.39.1"], - ..CompareTask::default() - }); -} - -#[test] -fn compare_solve_python() { - compare_solve(CompareTask { - specs: vec!["python=3.9"], - ..CompareTask::default() - }); -} - -#[test] -fn compare_solve_tensorflow() { - compare_solve(CompareTask { - specs: vec!["tensorflow"], - ..CompareTask::default() - }); -} - -#[test] -fn compare_solve_quetz() { - compare_solve(CompareTask { - specs: vec!["quetz"], - ..CompareTask::default() - }); -} - -#[test] -fn compare_solve_xtensor_xsimd() { - compare_solve(CompareTask { - specs: vec!["xtensor", "xsimd"], - ..CompareTask::default() - }); -} - -fn solve_to_get_channel_of_spec( - spec_str: &str, - expected_channel: &str, - repo_data: Vec<&SparseRepoData>, - channel_priority: ChannelPriority, -) { - let spec = MatchSpec::from_str(spec_str, ParseStrictness::Lenient).unwrap(); - let specs = vec![spec.clone()]; - let names = specs.iter().filter_map(|s| s.name.as_ref().cloned()); - - let available_packages = SparseRepoData::load_records_recursive( - repo_data, - names, - None, - PackageFormatSelection::default(), - ) - .unwrap(); - - let task = SolverTask { - specs: specs.clone(), - channel_priority, - ..SolverTask::from_iter(&available_packages) - }; - - let result: Vec = T::default().solve(task).unwrap().records; - - let record = result.iter().find(|record| { - record.package_record.name.as_normalized() == spec.name.as_ref().unwrap().as_normalized() - }); - assert_eq!(record.unwrap().channel, Some(expected_channel.to_string())); -} - -#[test] -fn channel_specific_requirement() { - let repodata = vec![ - read_conda_forge_sparse_repo_data(), - read_pytorch_sparse_repo_data(), - ]; - solve_to_get_channel_of_spec::( - "conda-forge::pytorch-cpu", - "https://conda.anaconda.org/conda-forge/", - repodata.clone(), - ChannelPriority::Strict, - ); - solve_to_get_channel_of_spec::( - "conda-forge::pytorch-cpu", - "https://conda.anaconda.org/conda-forge/", - repodata.clone(), - ChannelPriority::Disabled, - ); - solve_to_get_channel_of_spec::( - "pytorch::pytorch-cpu", - "https://conda.anaconda.org/pytorch/", - repodata.clone(), - ChannelPriority::Strict, - ); - solve_to_get_channel_of_spec::( - "pytorch::pytorch-cpu", - "https://conda.anaconda.org/pytorch/", - repodata, - ChannelPriority::Disabled, - ); -} - -#[test] -fn channel_priority_strict() { - // Solve with conda-forge as the first channel - let repodata = vec![ - read_conda_forge_sparse_repo_data(), - read_pytorch_sparse_repo_data(), - ]; - solve_to_get_channel_of_spec::( - "pytorch-cpu", - "https://conda.anaconda.org/conda-forge/", - repodata, - ChannelPriority::Strict, - ); - - // Solve with pytorch as the first channel - let repodata = vec![ - read_pytorch_sparse_repo_data(), - read_conda_forge_sparse_repo_data(), - ]; - solve_to_get_channel_of_spec::( - "pytorch-cpu", - "https://conda.anaconda.org/pytorch/", - repodata, - ChannelPriority::Strict, - ); -} - -#[test] -#[should_panic( - expected = "called `Result::unwrap()` on an `Err` value: Unsolvable([\"The following packages \ - are incompatible\\n└─ pytorch-cpu ==0.4.1 py36_cpu_1 cannot be installed because there are no \ - viable options:\\n └─ pytorch-cpu 0.4.1 is excluded because due to strict channel priority \ - not using this option from: 'https://conda.anaconda.org/pytorch/'\\n\"])" -)] -fn channel_priority_strict_panic() { - let repodata = vec![ - read_conda_forge_sparse_repo_data(), - read_pytorch_sparse_repo_data(), - ]; - solve_to_get_channel_of_spec::( - "pytorch-cpu=0.4.1=py36_cpu_1", - "https://conda.anaconda.org/pytorch/", - repodata, - ChannelPriority::Strict, - ); -} - -#[test] -fn channel_priority_disabled() { - let repodata = vec![ - read_conda_forge_sparse_repo_data(), - read_pytorch_sparse_repo_data(), - ]; - solve_to_get_channel_of_spec::( - "pytorch-cpu=0.4.1=py36_cpu_1", - "https://conda.anaconda.org/pytorch/", - repodata, - ChannelPriority::Disabled, - ); -} - -#[cfg(feature = "libsolv_c")] -#[test] -#[should_panic( - expected = "called `Result::unwrap()` on an `Err` value: Unsolvable([\"package \ - pytorch-cpu-0.4.1-py36_cpu_1 is excluded by strict repo priority\"])" -)] -fn channel_priority_strict_libsolv_c() { - let repodata = vec![ - read_conda_forge_sparse_repo_data(), - read_pytorch_sparse_repo_data(), - ]; - - solve_to_get_channel_of_spec::( - "pytorch-cpu=0.4.1=py36_cpu_1", - "https://conda.anaconda.org/pytorch/", - repodata, - ChannelPriority::Strict, - ); -} - -#[cfg(feature = "libsolv_c")] -#[test] -fn channel_priority_disabled_libsolv_c() { - let repodata = vec![ - read_conda_forge_sparse_repo_data(), - read_pytorch_sparse_repo_data(), - ]; - - solve_to_get_channel_of_spec::( - "pytorch-cpu=0.4.1=py36_cpu_1", - "https://conda.anaconda.org/pytorch/", - repodata, - ChannelPriority::Disabled, - ); -} From f2256abe19acdb2631a639055083308e0fe2b9d5 Mon Sep 17 00:00:00 2001 From: Wolf Vollprecht Date: Fri, 25 Jul 2025 23:42:10 +0200 Subject: [PATCH 04/11] remove trailing whitespace --- crates/rattler_solve/tests/backends.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/rattler_solve/tests/backends.rs b/crates/rattler_solve/tests/backends.rs index 1b10dfb7f6..90d575351e 100644 --- a/crates/rattler_solve/tests/backends.rs +++ b/crates/rattler_solve/tests/backends.rs @@ -1050,9 +1050,9 @@ mod resolvo { insta::assert_snapshot!(result.unwrap_err(), @r###" Cannot solve the request because of: The following packages are incompatible ├─ conflicting-extras[extra1] can be installed with any of the following options: - │ └─ conflicting-extras[extra1] + │ └─ conflicting-extras[extra1] ├─ conflicting-extras[extra2] can be installed with any of the following options: - │ └─ conflicting-extras[extra2] + │ └─ conflicting-extras[extra2] └─ conflicting-extras * cannot be installed because there are no viable options: └─ conflicting-extras 1 would require ├─ bar >=2, which can be installed with any of the following options: @@ -1078,7 +1078,7 @@ mod resolvo { insta::assert_snapshot!(result.unwrap_err(), @r###" Cannot solve the request because of: The following packages are incompatible ├─ conflicting-extras[extra1] can be installed with any of the following options: - │ └─ conflicting-extras[extra1] + │ └─ conflicting-extras[extra1] ├─ bar >=2 can be installed with any of the following options: │ └─ bar 2 └─ conflicting-extras * cannot be installed because there are no viable options: From 53596c83d2affbf2450807af9a21e8b2f1ab59f2 Mon Sep 17 00:00:00 2001 From: Wolf Vollprecht Date: Sun, 27 Jul 2025 14:39:41 +0200 Subject: [PATCH 05/11] make benchmarks compile and fix clippy --- crates/rattler_solve/benches/sorting_bench.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/crates/rattler_solve/benches/sorting_bench.rs b/crates/rattler_solve/benches/sorting_bench.rs index d1dc3df82d..772ee296d3 100644 --- a/crates/rattler_solve/benches/sorting_bench.rs +++ b/crates/rattler_solve/benches/sorting_bench.rs @@ -40,9 +40,7 @@ fn bench_sort(c: &mut Criterion, sparse_repo_data: &SparseRepoData, spec: &str) ) .expect("failed to create dependency provider"); - let name = dependency_provider - .pool - .intern_package_name(package_name.as_normalized()); + let name = dependency_provider.pool.intern_package_name(&package_name); let version_set = dependency_provider .pool .intern_version_set(name, match_spec.into_nameless().1.into()); From 3fe9740be00f89521823eb63303ee83c90a54226 Mon Sep 17 00:00:00 2001 From: Wolf Vollprecht Date: Sun, 27 Jul 2025 14:51:15 +0200 Subject: [PATCH 06/11] one more --- crates/rattler_solve/tests/backends.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/rattler_solve/tests/backends.rs b/crates/rattler_solve/tests/backends.rs index 90d575351e..8018bc1a05 100644 --- a/crates/rattler_solve/tests/backends.rs +++ b/crates/rattler_solve/tests/backends.rs @@ -995,7 +995,7 @@ mod resolvo { .sort_by(|a, b| a.package_record.name.cmp(&b.package_record.name)); // Collect the extras into a vector - let extras = result.features.into_iter().collect_vec(); + let extras = result.extras.into_iter().collect_vec(); // Make sure we have two packages `foo` and `bar` assert_eq!(result.records.len(), 2); From 2bcb0c96bb90208b170bb1381708ccb890ef9deb Mon Sep 17 00:00:00 2001 From: Wolf Vollprecht Date: Thu, 31 Jul 2025 08:42:40 +0200 Subject: [PATCH 07/11] fix whitespace trouble --- Cargo.lock | 3 +-- Cargo.toml | 2 +- crates/rattler_solve/src/resolvo/mod.rs | 3 ++- crates/rattler_solve/tests/backends.rs | 6 +++--- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 94e8843dab..af0944b12d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5180,8 +5180,7 @@ dependencies = [ [[package]] name = "resolvo" version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "037a5f3f35329f29885132d030c628f3142d2a098d0abb30513c572b900692fd" +source = "git+https://github.com/wolfv/resolvo?branch=whitespace#322265a1d23ac3c0f6b8396de20fa3c2278a3dee" dependencies = [ "ahash", "bitvec", diff --git a/Cargo.toml b/Cargo.toml index 304ef32aa2..8dfc0e83dc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -126,7 +126,7 @@ regex = "1.11.1" reqwest = { version = "0.12.15", default-features = false } reqwest-middleware = "0.4.2" reqwest-retry = "0.7.0" -resolvo = { version = "0.10.0" } +resolvo = { git = "https://github.com/wolfv/resolvo", branch = "whitespace" } # hold back at 0.4.0 until `reqwest-retry` is updated retry-policies = { version = "0.4.0", default-features = false } rmp-serde = { version = "1.3.0" } diff --git a/crates/rattler_solve/src/resolvo/mod.rs b/crates/rattler_solve/src/resolvo/mod.rs index 8c01f2ab58..33270a2b6e 100644 --- a/crates/rattler_solve/src/resolvo/mod.rs +++ b/crates/rattler_solve/src/resolvo/mod.rs @@ -575,7 +575,8 @@ impl Interner for CondaDependencyProvider<'_> { .format(" | "); let name = self.display_solvable_name(solvables[0]); - format!("{name} {versions}") + let result = format!("{name} {versions}"); + result.trim_end().to_string() } fn display_name(&self, name: NameId) -> impl Display + '_ { diff --git a/crates/rattler_solve/tests/backends.rs b/crates/rattler_solve/tests/backends.rs index 8018bc1a05..0c526dd6b9 100644 --- a/crates/rattler_solve/tests/backends.rs +++ b/crates/rattler_solve/tests/backends.rs @@ -1049,9 +1049,9 @@ mod resolvo { insta::assert_snapshot!(result.unwrap_err(), @r###" Cannot solve the request because of: The following packages are incompatible - ├─ conflicting-extras[extra1] can be installed with any of the following options: + ├─ conflicting-extras[extra1] can be installed with any of the following options: │ └─ conflicting-extras[extra1] - ├─ conflicting-extras[extra2] can be installed with any of the following options: + ├─ conflicting-extras[extra2] can be installed with any of the following options: │ └─ conflicting-extras[extra2] └─ conflicting-extras * cannot be installed because there are no viable options: └─ conflicting-extras 1 would require @@ -1077,7 +1077,7 @@ mod resolvo { insta::assert_snapshot!(result.unwrap_err(), @r###" Cannot solve the request because of: The following packages are incompatible - ├─ conflicting-extras[extra1] can be installed with any of the following options: + ├─ conflicting-extras[extra1] can be installed with any of the following options: │ └─ conflicting-extras[extra1] ├─ bar >=2 can be installed with any of the following options: │ └─ bar 2 From 788fcb80b827d2d38701fdc49309226aa8ebe953 Mon Sep 17 00:00:00 2001 From: Bas Zalmstra <4995967+baszalmstra@users.noreply.github.com> Date: Mon, 11 Aug 2025 13:15:17 +0200 Subject: [PATCH 08/11] fix: code review thingy --- crates/rattler_solve/src/resolvo/mod.rs | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/crates/rattler_solve/src/resolvo/mod.rs b/crates/rattler_solve/src/resolvo/mod.rs index 33270a2b6e..3dfc4e9b73 100644 --- a/crates/rattler_solve/src/resolvo/mod.rs +++ b/crates/rattler_solve/src/resolvo/mod.rs @@ -254,7 +254,7 @@ pub struct CondaDependencyProvider<'a> { name_to_condition: RefCell>, /// Holds all the cached candidates for each package name. - records: HashMap, + records: HashMap, matchspec_to_highest_version: RefCell>>, @@ -283,7 +283,7 @@ impl<'a> CondaDependencyProvider<'a> { strategy: SolveStrategy, ) -> Result { let pool = Pool::default(); - let mut records: HashMap = HashMap::default(); + let mut records: HashMap = HashMap::default(); // Add virtual packages to the records for virtual_package in virtual_packages { @@ -291,7 +291,7 @@ impl<'a> CondaDependencyProvider<'a> { let solvable = pool.intern_solvable(name, SolverPackageRecord::VirtualPackage(virtual_package)); records - .entry(virtual_package.name.as_normalized().to_owned()) + .entry(name) .or_default() .candidates .push(solvable); @@ -389,7 +389,7 @@ impl<'a> CondaDependencyProvider<'a> { // Update records with all entries in a single mutable borrow let candidates = records - .entry(record.package_record.name.as_normalized().to_owned()) + .entry(package_name) .or_default(); candidates.candidates.push(solvable_id); @@ -486,11 +486,7 @@ impl<'a> CondaDependencyProvider<'a> { let solvable = pool.intern_solvable(name, SolverPackageRecord::Record(favored_record)); let candidates = records .entry( - favored_record - .package_record - .name - .as_normalized() - .to_owned(), + name ) .or_default(); candidates.candidates.push(solvable); @@ -501,7 +497,7 @@ impl<'a> CondaDependencyProvider<'a> { let name = pool.intern_package_name(&locked_record.package_record.name); let solvable = pool.intern_solvable(name, SolverPackageRecord::Record(locked_record)); let candidates = records - .entry(locked_record.package_record.name.as_normalized().to_owned()) + .entry(name) .or_default(); candidates.candidates.push(solvable); candidates.locked = Some(solvable); @@ -528,7 +524,7 @@ impl<'a> CondaDependencyProvider<'a> { pub fn package_names(&self) -> impl Iterator + use<'_, 'a> { self.records .keys() - .map(|n| self.pool.intern_package_name(NameType::Base(n.to_owned()))) + .copied() } fn extra_condition(&self, package: &PackageName, extra: &str) -> ConditionId { @@ -640,7 +636,7 @@ impl DependencyProvider for CondaDependencyProvider<'_> { async fn get_candidates(&self, name: NameId) -> Option { match self.pool.resolve_package_name(name) { - NameType::Base(name) => self.records.get(name).cloned(), + NameType::Base(_) => self.records.get(&name).cloned(), NameType::Extra { package, extra } => { // For extras, we need to create a new candidates object // that contains only the extra solvable. From 3c36fef2b6fd443ba646b3191d931904d3596084 Mon Sep 17 00:00:00 2001 From: Bas Zalmstra <4995967+baszalmstra@users.noreply.github.com> Date: Mon, 11 Aug 2025 13:41:07 +0200 Subject: [PATCH 09/11] merge main --- Cargo.lock | 56 +- Cargo.toml | 2 +- crates/rattler-bin/Cargo.toml | 2 +- crates/rattler_cache/Cargo.toml | 1 + crates/rattler_cache/src/package_cache/mod.rs | 10 +- crates/rattler_package_streaming/src/lib.rs | 15 +- crates/rattler_package_streaming/src/read.rs | 133 +- .../src/resolvo/conda_sorting.rs | 4 +- crates/rattler_solve/src/resolvo/mod.rs | 8 +- js-rattler/Cargo.lock | 45 +- js-rattler/package-lock.json | 314 ++--- pixi.lock | 1151 +++++++++-------- pixi.toml | 2 +- py-rattler/Cargo.lock | 80 +- 14 files changed, 943 insertions(+), 880 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index af0944b12d..5179d688f8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1099,9 +1099,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.30" +version = "1.2.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "deec109607ca693028562ed836a5f1c4b8bd77755c4e132fc5ce11b0b6211ae7" +checksum = "c3a42d84bb6b69d3a8b3eaacf0d88f179e1929695e1ad012b6cf64d9caaa5fd2" dependencies = [ "jobserver", "libc", @@ -1194,9 +1194,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.41" +version = "4.5.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be92d32e80243a54711e5d7ce823c35c41c9d929dc4ab58e1276f625841aadf9" +checksum = "ed87a9d530bb41a67537289bafcac159cb3ee28460e0a4571123d2a778a6a882" dependencies = [ "clap_builder", "clap_derive", @@ -1215,9 +1215,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.41" +version = "4.5.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "707eab41e9622f9139419d573eca0900137718000c517d47da73045f54331c3d" +checksum = "64f4f3f3c77c94aff3c7e9aac9a2ca1974a5adf392a8bb751e827d6d127ab966" dependencies = [ "anstream", "anstyle", @@ -2253,9 +2253,9 @@ dependencies = [ [[package]] name = "google-cloud-auth" -version = "0.22.1" +version = "0.22.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1c68b38bb7fa9161988cd28b5973457c6ee111b04a3e64db287c3ebc1c386eb" +checksum = "290a18c1cc7c02934c1b88920af8b55ff588ff2ef47f35dae5fc1f10f2056538" dependencies = [ "async-trait", "base64 0.22.1", @@ -2699,7 +2699,7 @@ dependencies = [ "libc", "percent-encoding", "pin-project-lite", - "socket2 0.6.0", + "socket2 0.5.10", "system-configuration", "tokio", "tower-service", @@ -3116,7 +3116,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "07033963ba89ebaf1584d767badaa2e8fcec21aedea6b8c0346d487d49c28667" dependencies = [ "cfg-if", - "windows-targets 0.53.2", + "windows-targets 0.48.5", ] [[package]] @@ -4207,7 +4207,7 @@ dependencies = [ "once_cell", "socket2 0.5.10", "tracing", - "windows-sys 0.59.0", + "windows-sys 0.52.0", ] [[package]] @@ -4426,6 +4426,7 @@ dependencies = [ "rattler_digest", "rattler_networking", "rattler_package_streaming", + "rattler_redaction", "rayon", "reqwest", "reqwest-middleware", @@ -4505,7 +4506,7 @@ dependencies = [ "serde_json", "tempfile", "thiserror 2.0.12", - "toml 0.9.3", + "toml 0.9.5", "tracing", "url", ] @@ -5180,7 +5181,8 @@ dependencies = [ [[package]] name = "resolvo" version = "0.10.0" -source = "git+https://github.com/wolfv/resolvo?branch=whitespace#322265a1d23ac3c0f6b8396de20fa3c2278a3dee" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "037a5f3f35329f29885132d030c628f3142d2a098d0abb30513c572b900692fd" dependencies = [ "ahash", "bitvec", @@ -5334,7 +5336,7 @@ dependencies = [ "errno", "libc", "linux-raw-sys 0.4.15", - "windows-sys 0.59.0", + "windows-sys 0.52.0", ] [[package]] @@ -5665,9 +5667,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.141" +version = "1.0.142" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30b9eff21ebe718216c6ec64e1d9ac57087aad11efc64e32002bce4a0d4c03d3" +checksum = "030fedb782600dcbd6f02d479bf0d817ac3bb40d644745b769d6a96bc3afc5a7" dependencies = [ "indexmap 2.10.0", "itoa", @@ -6159,7 +6161,7 @@ dependencies = [ "getrandom 0.3.3", "once_cell", "rustix 1.0.8", - "windows-sys 0.59.0", + "windows-sys 0.52.0", ] [[package]] @@ -6389,9 +6391,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.15" +version = "0.7.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66a539a9ad6d5d281510d5bd368c973d636c02dbf8a67300bfb6b950696ad7df" +checksum = "14307c986784f72ef81c89db7d9e28d6ac26d16213b109ea501696195e6e3ce5" dependencies = [ "bytes", "futures-core", @@ -6412,9 +6414,9 @@ dependencies = [ [[package]] name = "toml" -version = "0.9.3" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e06723639aaded957e5a80be250c1f82f274b9d23ebb4d94163668470623461c" +checksum = "75129e1dc5000bfbaa9fee9d1b21f974f9fbad9daec557a521ee6e080825f6e8" dependencies = [ "indexmap 2.10.0", "serde", @@ -6453,9 +6455,9 @@ dependencies = [ [[package]] name = "toml_parser" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97200572db069e74c512a14117b296ba0a80a30123fbbb5aa1f4a348f639ca30" +checksum = "b551886f449aa90d4fe2bdaa9f4a2577ad2dde302c61ecf262d80b116db95c10" dependencies = [ "winnow", ] @@ -6631,9 +6633,9 @@ checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" [[package]] name = "trybuild" -version = "1.0.106" +version = "1.0.110" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65af40ad689f2527aebbd37a0a816aea88ff5f774ceabe99de5be02f2f91dae2" +checksum = "32e257d7246e7a9fd015fb0b28b330a8d4142151a33f03e6a497754f4b1f6a8e" dependencies = [ "dissimilar", "glob", @@ -6642,7 +6644,7 @@ dependencies = [ "serde_json", "target-triple", "termcolor", - "toml 0.9.3", + "toml 0.9.5", ] [[package]] @@ -7061,7 +7063,7 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" dependencies = [ - "windows-sys 0.59.0", + "windows-sys 0.52.0", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 8dfc0e83dc..304ef32aa2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -126,7 +126,7 @@ regex = "1.11.1" reqwest = { version = "0.12.15", default-features = false } reqwest-middleware = "0.4.2" reqwest-retry = "0.7.0" -resolvo = { git = "https://github.com/wolfv/resolvo", branch = "whitespace" } +resolvo = { version = "0.10.0" } # hold back at 0.4.0 until `reqwest-retry` is updated retry-policies = { version = "0.4.0", default-features = false } rmp-serde = { version = "1.3.0" } diff --git a/crates/rattler-bin/Cargo.toml b/crates/rattler-bin/Cargo.toml index ab4ee8cafe..1a3e9c755f 100644 --- a/crates/rattler-bin/Cargo.toml +++ b/crates/rattler-bin/Cargo.toml @@ -29,7 +29,7 @@ indicatif = { workspace = true } once_cell = { workspace = true } rattler = { workspace = true, features = ["indicatif"] } rattler_conda_types = { workspace = true, default-features = false } -rattler_networking = { workspace = true, default-features = false, features = ["gcs", "s3", "system-integration"] } +rattler_networking = { workspace = true, default-features = false, features = ["gcs", "s3", "system-integration", "netrc-rs"] } rattler_repodata_gateway = { workspace = true, default-features = false, features = ["gateway"] } rattler_solve = { workspace = true, default-features = false, features = ["resolvo", "libsolv_c"] } rattler_virtual_packages = { workspace = true, default-features = false } diff --git a/crates/rattler_cache/Cargo.toml b/crates/rattler_cache/Cargo.toml index 56460f34f1..0f52e9a9dc 100644 --- a/crates/rattler_cache/Cargo.toml +++ b/crates/rattler_cache/Cargo.toml @@ -28,6 +28,7 @@ itertools = { workspace = true } parking_lot = { workspace = true } rattler_conda_types = { workspace = true, default-features = false } rattler_digest = { workspace = true, default-features = false } +rattler_redaction = { workspace = true, default-features = false } rattler_networking = { workspace = true, default-features = false } rattler_package_streaming = { workspace = true, default-features = false, features = ["reqwest"] } reqwest = { workspace = true } diff --git a/crates/rattler_cache/src/package_cache/mod.rs b/crates/rattler_cache/src/package_cache/mod.rs index dae8e79ec8..5f71d11f87 100644 --- a/crates/rattler_cache/src/package_cache/mod.rs +++ b/crates/rattler_cache/src/package_cache/mod.rs @@ -22,6 +22,7 @@ use rattler_conda_types::package::ArchiveIdentifier; use rattler_digest::Sha256Hash; use rattler_networking::retry_policies::{DoNotRetryPolicy, RetryDecision, RetryPolicy}; use rattler_package_streaming::{DownloadReporter, ExtractError}; +use rattler_redaction::Redact; pub use reporter::CacheReporter; use simple_spawn_blocking::Cancelled; use tracing::instrument; @@ -284,8 +285,11 @@ impl PackageCache { // Delete the package if the hash does not match tokio_fs::remove_dir_all(&destination).await.unwrap(); return Err(ExtractError::HashMismatch { + url: url.clone().redact().to_string(), + destination: destination.display().to_string(), expected: format!("{md5:x}"), actual: format!("{:x}", result.md5), + total_size: result.total_size, }); } } @@ -295,8 +299,11 @@ impl PackageCache { // Delete the package if the hash does not match tokio_fs::remove_dir_all(&destination).await.unwrap(); return Err(ExtractError::HashMismatch { + url: url.clone().redact().to_string(), + destination: destination.display().to_string(), expected: format!("{sha256:x}"), actual: format!("{:x}", result.sha256), + total_size: result.total_size, }); } } @@ -448,7 +455,8 @@ where tracing::debug!("cache directory does not exist, fetching package"); } else if hash_mismatch { tracing::warn!( - "hash mismatch, wanted a package with hash {} but the cached package has hash {}, fetching package", + "hash mismatch, wanted a package at location {} with hash {} but the cached package has hash {}, fetching package", + path.display(), given_sha.map_or(String::from(""), |s| format!("{s:x}")), locked_sha256.map_or(String::from(""), |s| format!("{s:x}")) ); diff --git a/crates/rattler_package_streaming/src/lib.rs b/crates/rattler_package_streaming/src/lib.rs index 7e09d84344..5af2fc4848 100644 --- a/crates/rattler_package_streaming/src/lib.rs +++ b/crates/rattler_package_streaming/src/lib.rs @@ -28,8 +28,16 @@ pub enum ExtractError { #[error("an io error occurred: {0}")] IoError(#[from] std::io::Error), - #[error("hash mismatch: expected {expected}, got {actual}")] - HashMismatch { expected: String, actual: String }, + #[error( + "hash mismatch when extracting {url} to {destination}: expected {expected}, got {actual}, total size {total_size} bytes" + )] + HashMismatch { + url: String, + destination: String, + expected: String, + actual: String, + total_size: u64, + }, #[error("could not create the destination path: {0}")] CouldNotCreateDestination(#[source] std::io::Error), @@ -87,6 +95,9 @@ pub struct ExtractResult { /// The Md5 hash of the extracted archive. pub md5: Md5Hash, + + /// The total size of the extracted archive in bytes. + pub total_size: u64, } /// A trait that can be implemented to report download progress. diff --git a/crates/rattler_package_streaming/src/read.rs b/crates/rattler_package_streaming/src/read.rs index 30a55b978f..f06e196d4f 100644 --- a/crates/rattler_package_streaming/src/read.rs +++ b/crates/rattler_package_streaming/src/read.rs @@ -2,7 +2,6 @@ //! [`std::io::Read`] trait. use super::{ExtractError, ExtractResult}; -use rattler_digest::HashingReader; use std::io::{copy, Seek, SeekFrom}; use std::mem::ManuallyDrop; use std::{ffi::OsStr, io::Read, path::Path}; @@ -30,23 +29,10 @@ pub fn extract_tar_bz2( ) -> Result { std::fs::create_dir_all(destination).map_err(ExtractError::CouldNotCreateDestination)?; - // Wrap the reading in additional readers that will compute the hashes of the file while its - // being read. - let sha256_reader = rattler_digest::HashingReader::<_, rattler_digest::Sha256>::new(reader); - let mut md5_reader = - rattler_digest::HashingReader::<_, rattler_digest::Md5>::new(sha256_reader); - - // Unpack the archive - stream_tar_bz2(&mut md5_reader).unpack(destination)?; - - // Read the file to the end to make sure the hash is properly computed. - std::io::copy(&mut md5_reader, &mut std::io::sink())?; - - // Get the hashes - let (sha256_reader, md5) = md5_reader.finalize(); - let (_, sha256) = sha256_reader.finalize(); - - Ok(ExtractResult { sha256, md5 }) + process_with_hashing(reader, |reader| { + stream_tar_bz2(reader).unpack(destination)?; + Ok(()) + }) } /// Extracts the contents of a `.conda` package archive. @@ -57,17 +43,12 @@ pub fn extract_conda_via_streaming( // Construct the destination path if it doesnt exist yet std::fs::create_dir_all(destination).map_err(ExtractError::CouldNotCreateDestination)?; - // Wrap the reading in additional readers that will compute the hashes of the file while its - // being read. - let sha256_reader = rattler_digest::HashingReader::<_, rattler_digest::Sha256>::new(reader); - let mut md5_reader = - rattler_digest::HashingReader::<_, rattler_digest::Md5>::new(sha256_reader); - - // Iterate over all entries in the zip-file and extract them one-by-one - while let Some(file) = read_zipfile_from_stream(&mut md5_reader)? { - extract_zipfile(file, destination)?; - } - compute_hashes(md5_reader) + process_with_hashing(reader, |reader| { + while let Some(file) = read_zipfile_from_stream(reader)? { + extract_zipfile(file, destination)?; + } + Ok(()) + }) } /// Extracts the contents of a .conda package archive by fully reading the stream and then decompressing @@ -81,24 +62,19 @@ pub fn extract_conda_via_buffering( } std::fs::create_dir_all(destination).map_err(ExtractError::CouldNotCreateDestination)?; - // Create a SpooledTempFile with a 5MB limit - let mut temp_file = SpooledTempFile::new(5 * 1024 * 1024); - let sha256_reader = rattler_digest::HashingReader::<_, rattler_digest::Sha256>::new(reader); - let mut md5_reader = - rattler_digest::HashingReader::<_, rattler_digest::Md5>::new(sha256_reader); - - copy(&mut md5_reader, &mut temp_file)?; - temp_file.seek(SeekFrom::Start(0))?; - let mut archive = ZipArchive::new(temp_file)?; - - for i in 0..archive.len() { - let file = archive.by_index(i)?; - extract_zipfile(file, destination)?; - } - // Read the file to the end to make sure the hash is properly computed. - std::io::copy(&mut md5_reader, &mut std::io::sink())?; - - compute_hashes(md5_reader) + process_with_hashing(reader, |reader| { + // Create a SpooledTempFile with a 5MB limit + let mut temp_file = SpooledTempFile::new(5 * 1024 * 1024); + copy(reader, &mut temp_file)?; + temp_file.seek(SeekFrom::Start(0))?; + let mut archive = ZipArchive::new(temp_file)?; + + for i in 0..archive.len() { + let file = archive.by_index(i)?; + extract_zipfile(file, destination)?; + } + Ok(()) + }) } fn extract_zipfile( @@ -128,15 +104,64 @@ fn extract_zipfile( Ok(()) } -fn compute_hashes( - mut md5_reader: HashingReader, rattler_digest::Md5>, -) -> Result { - // Read the file to the end to make sure the hash is properly computed. - std::io::copy(&mut md5_reader, &mut std::io::sink())?; +// Define a custom reader to track file size +struct SizeCountingReader { + inner: R, + size: u64, +} + +impl SizeCountingReader { + fn new(inner: R) -> Self { + Self { inner, size: 0 } + } + + fn finalize(self) -> (R, u64) { + (self.inner, self.size) + } +} + +impl Read for SizeCountingReader { + fn read(&mut self, buf: &mut [u8]) -> std::io::Result { + let bytes_read = self.inner.read(buf)?; + self.size += bytes_read as u64; + Ok(bytes_read) + } +} + +/// Helper function to compute hashes and size while processing a tar archive +fn process_with_hashing(reader: R, processor: F) -> Result +where + R: Read, + E: From, + F: FnOnce( + &mut SizeCountingReader< + &mut rattler_digest::HashingReader< + rattler_digest::HashingReader, + rattler_digest::Md5, + >, + >, + ) -> Result<(), E>, +{ + // Wrap the reading in additional readers that will compute the hashes of the file while its + // being read, and count the total size. + let sha256_reader = rattler_digest::HashingReader::<_, rattler_digest::Sha256>::new(reader); + let mut md5_reader = + rattler_digest::HashingReader::<_, rattler_digest::Md5>::new(sha256_reader); + let mut size_reader = SizeCountingReader::new(&mut md5_reader); + + processor(&mut size_reader)?; + + // Read the file to the end to make sure the hash is properly computed + std::io::copy(&mut size_reader, &mut std::io::sink())?; - // Get the hashes + // Get the size and hashes + let (_, total_size) = size_reader.finalize(); let (sha256_reader, md5) = md5_reader.finalize(); let (_, sha256) = sha256_reader.finalize(); - Ok(ExtractResult { sha256, md5 }) + Ok(ExtractResult { + sha256, + md5, + total_size, + }) } diff --git a/crates/rattler_solve/src/resolvo/conda_sorting.rs b/crates/rattler_solve/src/resolvo/conda_sorting.rs index 22d1b855f5..96726e2b13 100644 --- a/crates/rattler_solve/src/resolvo/conda_sorting.rs +++ b/crates/rattler_solve/src/resolvo/conda_sorting.rs @@ -191,8 +191,8 @@ impl<'a, 'repo> SolvableSorter<'a, 'repo> { Err(_) => return, }; - for requirement in known.requirements.iter().map(|r| &r.requirement) { - let version_set_id = match requirement { + for requirement in &known.requirements { + let version_set_id = match &requirement.requirement { // Ignore union requirements, these do not occur in the conda ecosystem // currently Requirement::Union(_) => { diff --git a/crates/rattler_solve/src/resolvo/mod.rs b/crates/rattler_solve/src/resolvo/mod.rs index 3dfc4e9b73..0a2bbab960 100644 --- a/crates/rattler_solve/src/resolvo/mod.rs +++ b/crates/rattler_solve/src/resolvo/mod.rs @@ -552,6 +552,10 @@ impl Interner for CondaDependencyProvider<'_> { &self.pool.resolve_solvable(solvable).record } + fn resolve_condition(&self, condition: ConditionId) -> Condition { + self.pool.resolve_condition(condition).clone() + } + fn version_sets_in_union( &self, version_set_union: VersionSetUnionId, @@ -594,10 +598,6 @@ impl Interner for CondaDependencyProvider<'_> { fn solvable_name(&self, solvable: SolvableId) -> NameId { self.pool.resolve_solvable(solvable).name } - - fn resolve_condition(&self, condition: ConditionId) -> Condition { - self.pool.resolve_condition(condition).clone() - } } impl DependencyProvider for CondaDependencyProvider<'_> { diff --git a/js-rattler/Cargo.lock b/js-rattler/Cargo.lock index a340041a17..36fb0c5217 100644 --- a/js-rattler/Cargo.lock +++ b/js-rattler/Cargo.lock @@ -530,7 +530,7 @@ checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" [[package]] name = "file_url" -version = "0.2.5" +version = "0.2.6" dependencies = [ "itertools", "percent-encoding", @@ -786,7 +786,7 @@ dependencies = [ "futures-core", "futures-sink", "http", - "indexmap 2.9.0", + "indexmap 2.10.0", "slab", "tokio", "tokio-util", @@ -1137,9 +1137,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.9.0" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e" +checksum = "fe4cd85333e22411419a0bcae1297d25e58c9443848b11dc6a86fefe8c78a661" dependencies = [ "equivalent", "hashbrown 0.15.4", @@ -1515,12 +1515,14 @@ checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "petgraph" -version = "0.7.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3672b37090dbd86368a4145bc067582552b29c27377cad4e0a306c97f9bd7772" +checksum = "54acf3a685220b533e437e264e4d932cfbdc4cc7ec0cd232ed73c08d03b8a7ca" dependencies = [ "fixedbitset", - "indexmap 2.9.0", + "hashbrown 0.15.4", + "indexmap 2.10.0", + "serde", ] [[package]] @@ -1790,7 +1792,7 @@ dependencies = [ [[package]] name = "rattler_cache" -version = "0.3.26" +version = "0.3.29" dependencies = [ "anyhow", "dashmap", @@ -1806,6 +1808,7 @@ dependencies = [ "rattler_digest", "rattler_networking", "rattler_package_streaming", + "rattler_redaction", "rayon", "reqwest", "reqwest-middleware", @@ -1820,7 +1823,7 @@ dependencies = [ [[package]] name = "rattler_conda_types" -version = "0.35.6" +version = "0.37.0" dependencies = [ "chrono", "core-foundation", @@ -1830,7 +1833,7 @@ dependencies = [ "fxhash", "glob", "hex", - "indexmap 2.9.0", + "indexmap 2.10.0", "itertools", "lazy-regex", "nom", @@ -1859,7 +1862,7 @@ dependencies = [ [[package]] name = "rattler_digest" -version = "1.1.4" +version = "1.1.5" dependencies = [ "blake2", "digest", @@ -1883,7 +1886,7 @@ dependencies = [ [[package]] name = "rattler_networking" -version = "0.25.6" +version = "0.25.8" dependencies = [ "anyhow", "async-trait", @@ -1905,7 +1908,7 @@ dependencies = [ [[package]] name = "rattler_package_streaming" -version = "0.22.45" +version = "0.22.48" dependencies = [ "bzip2", "chrono", @@ -1942,7 +1945,7 @@ dependencies = [ [[package]] name = "rattler_repodata_gateway" -version = "0.23.7" +version = "0.23.10" dependencies = [ "anyhow", "async-compression", @@ -1998,7 +2001,7 @@ dependencies = [ [[package]] name = "rattler_solve" -version = "2.1.6" +version = "2.1.8" dependencies = [ "chrono", "futures", @@ -2160,16 +2163,16 @@ dependencies = [ [[package]] name = "resolvo" -version = "0.9.1" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dba027c8e5dd4b5e5a690cfcfb3900d5ffe6985adb048cbd111d5aa596a6c0c8" +checksum = "037a5f3f35329f29885132d030c628f3142d2a098d0abb30513c572b900692fd" dependencies = [ "ahash", "bitvec", "elsa", "event-listener", "futures", - "indexmap 2.9.0", + "indexmap 2.10.0", "itertools", "petgraph", "tracing", @@ -2469,7 +2472,7 @@ dependencies = [ "chrono", "hex", "indexmap 1.9.3", - "indexmap 2.9.0", + "indexmap 2.10.0", "schemars", "serde", "serde_derive", @@ -2496,7 +2499,7 @@ version = "0.9.34+deprecated" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" dependencies = [ - "indexmap 2.9.0", + "indexmap 2.10.0", "itoa", "ryu", "serde", @@ -3604,7 +3607,7 @@ dependencies = [ "arbitrary", "crc32fast", "flate2", - "indexmap 2.9.0", + "indexmap 2.10.0", "memchr", "time", "zopfli", diff --git a/js-rattler/package-lock.json b/js-rattler/package-lock.json index 8156a623a4..c583fad221 100644 --- a/js-rattler/package-lock.json +++ b/js-rattler/package-lock.json @@ -1129,9 +1129,9 @@ } }, "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.45.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.45.1.tgz", - "integrity": "sha512-NEySIFvMY0ZQO+utJkgoMiCAjMrGvnbDLHvcmlA33UXJpYBCvlBEbMMtV837uCkS+plG2umfhn0T5mMAxGrlRA==", + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.46.2.tgz", + "integrity": "sha512-Zj3Hl6sN34xJtMv7Anwb5Gu01yujyE/cLBDB2gnHTAHaWS1Z38L7kuSG+oAh0giZMqG060f/YBStXtMH6FvPMA==", "cpu": [ "arm" ], @@ -1143,9 +1143,9 @@ ] }, "node_modules/@rollup/rollup-android-arm64": { - "version": "4.45.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.45.1.tgz", - "integrity": "sha512-ujQ+sMXJkg4LRJaYreaVx7Z/VMgBBd89wGS4qMrdtfUFZ+TSY5Rs9asgjitLwzeIbhwdEhyj29zhst3L1lKsRQ==", + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.46.2.tgz", + "integrity": "sha512-nTeCWY83kN64oQ5MGz3CgtPx8NSOhC5lWtsjTs+8JAJNLcP3QbLCtDDgUKQc/Ro/frpMq4SHUaHN6AMltcEoLQ==", "cpu": [ "arm64" ], @@ -1157,9 +1157,9 @@ ] }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.45.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.45.1.tgz", - "integrity": "sha512-FSncqHvqTm3lC6Y13xncsdOYfxGSLnP+73k815EfNmpewPs+EyM49haPS105Rh4aF5mJKywk9X0ogzLXZzN9lA==", + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.46.2.tgz", + "integrity": "sha512-HV7bW2Fb/F5KPdM/9bApunQh68YVDU8sO8BvcW9OngQVN3HHHkw99wFupuUJfGR9pYLLAjcAOA6iO+evsbBaPQ==", "cpu": [ "arm64" ], @@ -1171,9 +1171,9 @@ ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.45.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.45.1.tgz", - "integrity": "sha512-2/vVn/husP5XI7Fsf/RlhDaQJ7x9zjvC81anIVbr4b/f0xtSmXQTFcGIQ/B1cXIYM6h2nAhJkdMHTnD7OtQ9Og==", + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.46.2.tgz", + "integrity": "sha512-SSj8TlYV5nJixSsm/y3QXfhspSiLYP11zpfwp6G/YDXctf3Xkdnk4woJIF5VQe0of2OjzTt8EsxnJDCdHd2xMA==", "cpu": [ "x64" ], @@ -1185,9 +1185,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.45.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.45.1.tgz", - "integrity": "sha512-4g1kaDxQItZsrkVTdYQ0bxu4ZIQ32cotoQbmsAnW1jAE4XCMbcBPDirX5fyUzdhVCKgPcrwWuucI8yrVRBw2+g==", + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.46.2.tgz", + "integrity": "sha512-ZyrsG4TIT9xnOlLsSSi9w/X29tCbK1yegE49RYm3tu3wF1L/B6LVMqnEWyDB26d9Ecx9zrmXCiPmIabVuLmNSg==", "cpu": [ "arm64" ], @@ -1199,9 +1199,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.45.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.45.1.tgz", - "integrity": "sha512-L/6JsfiL74i3uK1Ti2ZFSNsp5NMiM4/kbbGEcOCps99aZx3g8SJMO1/9Y0n/qKlWZfn6sScf98lEOUe2mBvW9A==", + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.46.2.tgz", + "integrity": "sha512-pCgHFoOECwVCJ5GFq8+gR8SBKnMO+xe5UEqbemxBpCKYQddRQMgomv1104RnLSg7nNvgKy05sLsY51+OVRyiVw==", "cpu": [ "x64" ], @@ -1213,9 +1213,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.45.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.45.1.tgz", - "integrity": "sha512-RkdOTu2jK7brlu+ZwjMIZfdV2sSYHK2qR08FUWcIoqJC2eywHbXr0L8T/pONFwkGukQqERDheaGTeedG+rra6Q==", + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.46.2.tgz", + "integrity": "sha512-EtP8aquZ0xQg0ETFcxUbU71MZlHaw9MChwrQzatiE8U/bvi5uv/oChExXC4mWhjiqK7azGJBqU0tt5H123SzVA==", "cpu": [ "arm" ], @@ -1227,9 +1227,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.45.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.45.1.tgz", - "integrity": "sha512-3kJ8pgfBt6CIIr1o+HQA7OZ9mp/zDk3ctekGl9qn/pRBgrRgfwiffaUmqioUGN9hv0OHv2gxmvdKOkARCtRb8Q==", + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.46.2.tgz", + "integrity": "sha512-qO7F7U3u1nfxYRPM8HqFtLd+raev2K137dsV08q/LRKRLEc7RsiDWihUnrINdsWQxPR9jqZ8DIIZ1zJJAm5PjQ==", "cpu": [ "arm" ], @@ -1241,9 +1241,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.45.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.45.1.tgz", - "integrity": "sha512-k3dOKCfIVixWjG7OXTCOmDfJj3vbdhN0QYEqB+OuGArOChek22hn7Uy5A/gTDNAcCy5v2YcXRJ/Qcnm4/ma1xw==", + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.46.2.tgz", + "integrity": "sha512-3dRaqLfcOXYsfvw5xMrxAk9Lb1f395gkoBYzSFcc/scgRFptRXL9DOaDpMiehf9CO8ZDRJW2z45b6fpU5nwjng==", "cpu": [ "arm64" ], @@ -1255,9 +1255,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.45.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.45.1.tgz", - "integrity": "sha512-PmI1vxQetnM58ZmDFl9/Uk2lpBBby6B6rF4muJc65uZbxCs0EA7hhKCk2PKlmZKuyVSHAyIw3+/SiuMLxKxWog==", + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.46.2.tgz", + "integrity": "sha512-fhHFTutA7SM+IrR6lIfiHskxmpmPTJUXpWIsBXpeEwNgZzZZSg/q4i6FU4J8qOGyJ0TR+wXBwx/L7Ho9z0+uDg==", "cpu": [ "arm64" ], @@ -1269,9 +1269,9 @@ ] }, "node_modules/@rollup/rollup-linux-loongarch64-gnu": { - "version": "4.45.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.45.1.tgz", - "integrity": "sha512-9UmI0VzGmNJ28ibHW2GpE2nF0PBQqsyiS4kcJ5vK+wuwGnV5RlqdczVocDSUfGX/Na7/XINRVoUgJyFIgipoRg==", + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.46.2.tgz", + "integrity": "sha512-i7wfGFXu8x4+FRqPymzjD+Hyav8l95UIZ773j7J7zRYc3Xsxy2wIn4x+llpunexXe6laaO72iEjeeGyUFmjKeA==", "cpu": [ "loong64" ], @@ -1282,10 +1282,10 @@ "linux" ] }, - "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { - "version": "4.45.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.45.1.tgz", - "integrity": "sha512-7nR2KY8oEOUTD3pBAxIBBbZr0U7U+R9HDTPNy+5nVVHDXI4ikYniH1oxQz9VoB5PbBU1CZuDGHkLJkd3zLMWsg==", + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.46.2.tgz", + "integrity": "sha512-B/l0dFcHVUnqcGZWKcWBSV2PF01YUt0Rvlurci5P+neqY/yMKchGU8ullZvIv5e8Y1C6wOn+U03mrDylP5q9Yw==", "cpu": [ "ppc64" ], @@ -1297,9 +1297,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.45.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.45.1.tgz", - "integrity": "sha512-nlcl3jgUultKROfZijKjRQLUu9Ma0PeNv/VFHkZiKbXTBQXhpytS8CIj5/NfBeECZtY2FJQubm6ltIxm/ftxpw==", + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.46.2.tgz", + "integrity": "sha512-32k4ENb5ygtkMwPMucAb8MtV8olkPT03oiTxJbgkJa7lJ7dZMr0GCFJlyvy+K8iq7F/iuOr41ZdUHaOiqyR3iQ==", "cpu": [ "riscv64" ], @@ -1311,9 +1311,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-musl": { - "version": "4.45.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.45.1.tgz", - "integrity": "sha512-HJV65KLS51rW0VY6rvZkiieiBnurSzpzore1bMKAhunQiECPuxsROvyeaot/tcK3A3aGnI+qTHqisrpSgQrpgA==", + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.46.2.tgz", + "integrity": "sha512-t5B2loThlFEauloaQkZg9gxV05BYeITLvLkWOkRXogP4qHXLkWSbSHKM9S6H1schf/0YGP/qNKtiISlxvfmmZw==", "cpu": [ "riscv64" ], @@ -1325,9 +1325,9 @@ ] }, "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.45.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.45.1.tgz", - "integrity": "sha512-NITBOCv3Qqc6hhwFt7jLV78VEO/il4YcBzoMGGNxznLgRQf43VQDae0aAzKiBeEPIxnDrACiMgbqjuihx08OOw==", + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.46.2.tgz", + "integrity": "sha512-YKjekwTEKgbB7n17gmODSmJVUIvj8CX7q5442/CK80L8nqOUbMtf8b01QkG3jOqyr1rotrAnW6B/qiHwfcuWQA==", "cpu": [ "s390x" ], @@ -1339,9 +1339,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.45.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.45.1.tgz", - "integrity": "sha512-+E/lYl6qu1zqgPEnTrs4WysQtvc/Sh4fC2nByfFExqgYrqkKWp1tWIbe+ELhixnenSpBbLXNi6vbEEJ8M7fiHw==", + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.46.2.tgz", + "integrity": "sha512-Jj5a9RUoe5ra+MEyERkDKLwTXVu6s3aACP51nkfnK9wJTraCC8IMe3snOfALkrjTYd2G1ViE1hICj0fZ7ALBPA==", "cpu": [ "x64" ], @@ -1353,9 +1353,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.45.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.45.1.tgz", - "integrity": "sha512-a6WIAp89p3kpNoYStITT9RbTbTnqarU7D8N8F2CV+4Cl9fwCOZraLVuVFvlpsW0SbIiYtEnhCZBPLoNdRkjQFw==", + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.46.2.tgz", + "integrity": "sha512-7kX69DIrBeD7yNp4A5b81izs8BqoZkCIaxQaOpumcJ1S/kmqNFjPhDu1LHeVXv0SexfHQv5cqHsxLOjETuqDuA==", "cpu": [ "x64" ], @@ -1367,9 +1367,9 @@ ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.45.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.45.1.tgz", - "integrity": "sha512-T5Bi/NS3fQiJeYdGvRpTAP5P02kqSOpqiopwhj0uaXB6nzs5JVi2XMJb18JUSKhCOX8+UE1UKQufyD6Or48dJg==", + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.46.2.tgz", + "integrity": "sha512-wiJWMIpeaak/jsbaq2HMh/rzZxHVW1rU6coyeNNpMwk5isiPjSTx0a4YLSlYDwBH/WBvLz+EtsNqQScZTLJy3g==", "cpu": [ "arm64" ], @@ -1381,9 +1381,9 @@ ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.45.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.45.1.tgz", - "integrity": "sha512-lxV2Pako3ujjuUe9jiU3/s7KSrDfH6IgTSQOnDWr9aJ92YsFd7EurmClK0ly/t8dzMkDtd04g60WX6yl0sGfdw==", + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.46.2.tgz", + "integrity": "sha512-gBgaUDESVzMgWZhcyjfs9QFK16D8K6QZpwAaVNJxYDLHWayOta4ZMjGm/vsAEy3hvlS2GosVFlBlP9/Wb85DqQ==", "cpu": [ "ia32" ], @@ -1395,9 +1395,9 @@ ] }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.45.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.45.1.tgz", - "integrity": "sha512-M/fKi4sasCdM8i0aWJjCSFm2qEnYRR8AMLG2kxp6wD13+tMGA4Z1tVAuHkNRjud5SW2EM3naLuK35w9twvf6aA==", + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.46.2.tgz", + "integrity": "sha512-CvUo2ixeIQGtF6WvuB87XWqPQkoFAFqW+HUo/WzHwuHDvIwZCtjdWXoYCcr06iKGydiqTclC4jU/TNObC/xKZg==", "cpu": [ "x64" ], @@ -1739,13 +1739,6 @@ "sprintf-js": "~1.0.2" } }, - "node_modules/async": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz", - "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==", - "dev": true, - "license": "MIT" - }, "node_modules/axios": { "version": "0.26.1", "resolved": "https://registry.npmjs.org/axios/-/axios-0.26.1.tgz", @@ -2388,22 +2381,6 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/ejs": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.10.tgz", - "integrity": "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "jake": "^10.8.5" - }, - "bin": { - "ejs": "bin/cli.js" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/electron-to-chromium": { "version": "1.5.107", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.107.tgz", @@ -2601,39 +2578,6 @@ } } }, - "node_modules/filelist": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.4.tgz", - "integrity": "sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "minimatch": "^5.0.1" - } - }, - "node_modules/filelist/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/filelist/node_modules/minimatch": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", - "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/fill-range": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", @@ -2855,6 +2799,28 @@ "dev": true, "license": "ISC" }, + "node_modules/handlebars": { + "version": "4.7.8", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.8.tgz", + "integrity": "sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "minimist": "^1.2.5", + "neo-async": "^2.6.2", + "source-map": "^0.6.1", + "wordwrap": "^1.0.0" + }, + "bin": { + "handlebars": "bin/handlebars" + }, + "engines": { + "node": ">=0.4.7" + }, + "optionalDependencies": { + "uglify-js": "^3.1.4" + } + }, "node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -3151,38 +3117,6 @@ "node": ">=8" } }, - "node_modules/jake": { - "version": "10.9.2", - "resolved": "https://registry.npmjs.org/jake/-/jake-10.9.2.tgz", - "integrity": "sha512-2P4SQ0HrLQ+fw6llpLnOaGAvN2Zu6778SJMrCUwns4fOoG9ayrTiZk3VV8sCPkVZF8ab0zksVpS8FDY5pRCNBA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "async": "^3.2.3", - "chalk": "^4.0.2", - "filelist": "^1.0.4", - "minimatch": "^3.1.2" - }, - "bin": { - "jake": "bin/cli.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/jake/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, "node_modules/jest": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest/-/jest-29.7.0.tgz", @@ -4580,6 +4514,13 @@ "dev": true, "license": "MIT" }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true, + "license": "MIT" + }, "node_modules/nice-try": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", @@ -5070,9 +5011,9 @@ } }, "node_modules/rollup": { - "version": "4.45.1", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.45.1.tgz", - "integrity": "sha512-4iya7Jb76fVpQyLoiVpzUrsjQ12r3dM7fIVz+4NwoYvZOShknRmiv+iu9CClZml5ZLGb0XMcYLutK6w9tgxHDw==", + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.46.2.tgz", + "integrity": "sha512-WMmLFI+Boh6xbop+OAGo9cQ3OgX9MIg7xOQjn+pTCwOkk+FNDAeAemXkJ3HzDJrVXleLOFVa1ipuc1AmEx1Dwg==", "dev": true, "license": "MIT", "dependencies": { @@ -5086,26 +5027,26 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.45.1", - "@rollup/rollup-android-arm64": "4.45.1", - "@rollup/rollup-darwin-arm64": "4.45.1", - "@rollup/rollup-darwin-x64": "4.45.1", - "@rollup/rollup-freebsd-arm64": "4.45.1", - "@rollup/rollup-freebsd-x64": "4.45.1", - "@rollup/rollup-linux-arm-gnueabihf": "4.45.1", - "@rollup/rollup-linux-arm-musleabihf": "4.45.1", - "@rollup/rollup-linux-arm64-gnu": "4.45.1", - "@rollup/rollup-linux-arm64-musl": "4.45.1", - "@rollup/rollup-linux-loongarch64-gnu": "4.45.1", - "@rollup/rollup-linux-powerpc64le-gnu": "4.45.1", - "@rollup/rollup-linux-riscv64-gnu": "4.45.1", - "@rollup/rollup-linux-riscv64-musl": "4.45.1", - "@rollup/rollup-linux-s390x-gnu": "4.45.1", - "@rollup/rollup-linux-x64-gnu": "4.45.1", - "@rollup/rollup-linux-x64-musl": "4.45.1", - "@rollup/rollup-win32-arm64-msvc": "4.45.1", - "@rollup/rollup-win32-ia32-msvc": "4.45.1", - "@rollup/rollup-win32-x64-msvc": "4.45.1", + "@rollup/rollup-android-arm-eabi": "4.46.2", + "@rollup/rollup-android-arm64": "4.46.2", + "@rollup/rollup-darwin-arm64": "4.46.2", + "@rollup/rollup-darwin-x64": "4.46.2", + "@rollup/rollup-freebsd-arm64": "4.46.2", + "@rollup/rollup-freebsd-x64": "4.46.2", + "@rollup/rollup-linux-arm-gnueabihf": "4.46.2", + "@rollup/rollup-linux-arm-musleabihf": "4.46.2", + "@rollup/rollup-linux-arm64-gnu": "4.46.2", + "@rollup/rollup-linux-arm64-musl": "4.46.2", + "@rollup/rollup-linux-loongarch64-gnu": "4.46.2", + "@rollup/rollup-linux-ppc64-gnu": "4.46.2", + "@rollup/rollup-linux-riscv64-gnu": "4.46.2", + "@rollup/rollup-linux-riscv64-musl": "4.46.2", + "@rollup/rollup-linux-s390x-gnu": "4.46.2", + "@rollup/rollup-linux-x64-gnu": "4.46.2", + "@rollup/rollup-linux-x64-musl": "4.46.2", + "@rollup/rollup-win32-arm64-msvc": "4.46.2", + "@rollup/rollup-win32-ia32-msvc": "4.46.2", + "@rollup/rollup-win32-x64-msvc": "4.46.2", "fsevents": "~2.3.2" } }, @@ -5596,15 +5537,15 @@ } }, "node_modules/ts-jest": { - "version": "29.4.0", - "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.4.0.tgz", - "integrity": "sha512-d423TJMnJGu80/eSgfQ5w/R+0zFJvdtTxwtF9KzFFunOpSeD+79lHJQIiAhluJoyGRbvj9NZJsl9WjCUo0ND7Q==", + "version": "29.4.1", + "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.4.1.tgz", + "integrity": "sha512-SaeUtjfpg9Uqu8IbeDKtdaS0g8lS6FT6OzM3ezrDfErPJPHNDo/Ey+VFGP1bQIDfagYDLyRpd7O15XpG1Es2Uw==", "dev": true, "license": "MIT", "dependencies": { "bs-logger": "^0.2.6", - "ejs": "^3.1.10", "fast-json-stable-stringify": "^2.1.0", + "handlebars": "^4.7.8", "json5": "^2.2.3", "lodash.memoize": "^4.1.2", "make-error": "^1.3.6", @@ -5756,6 +5697,20 @@ "dev": true, "license": "MIT" }, + "node_modules/uglify-js": { + "version": "3.19.3", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.19.3.tgz", + "integrity": "sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==", + "dev": true, + "license": "BSD-2-Clause", + "optional": true, + "bin": { + "uglifyjs": "bin/uglifyjs" + }, + "engines": { + "node": ">=0.8.0" + } + }, "node_modules/undici-types": { "version": "6.20.0", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", @@ -5870,6 +5825,13 @@ "node": ">= 8" } }, + "node_modules/wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", + "dev": true, + "license": "MIT" + }, "node_modules/wrap-ansi": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", diff --git a/pixi.lock b/pixi.lock index 6f9a91fff3..d779eb0a21 100644 --- a/pixi.lock +++ b/pixi.lock @@ -12,25 +12,26 @@ environments: - conda: https://prefix.dev/conda-forge/linux-64/binutils_linux-64-2.43-h4852527_4.conda - conda: https://prefix.dev/conda-forge/linux-64/bzip2-1.0.8-h4bc722e_7.conda - conda: https://prefix.dev/conda-forge/linux-64/c-ares-1.34.4-hb9d3cd8_0.conda - - conda: https://prefix.dev/conda-forge/linux-64/c-compiler-1.10.0-h2b85faf_0.conda + - conda: https://prefix.dev/conda-forge/linux-64/c-compiler-1.11.0-h4d9bdce_0.conda - conda: https://prefix.dev/conda-forge/linux-64/ca-certificates-2025.1.31-hbcca054_0.conda - conda: https://prefix.dev/conda-forge/linux-64/cargo-nextest-0.9.91-h6c30b3d_0.conda - conda: https://prefix.dev/conda-forge/linux-64/clang-18-18.1.8-default_hb5137d0_7.conda - conda: https://prefix.dev/conda-forge/linux-64/clang-18.1.8-default_h9e3a008_7.conda - conda: https://prefix.dev/conda-forge/linux-64/cmake-3.26.4-hcfe8598_0.conda - - conda: https://prefix.dev/conda-forge/linux-64/compilers-1.10.0-ha770c72_0.conda - - conda: https://prefix.dev/conda-forge/linux-64/cxx-compiler-1.10.0-h1a2810e_0.conda + - conda: https://prefix.dev/conda-forge/linux-64/compilers-1.11.0-ha770c72_0.conda + - conda: https://prefix.dev/conda-forge/linux-64/conda-gcc-specs-14.3.0-hb991d5c_3.conda + - conda: https://prefix.dev/conda-forge/linux-64/cxx-compiler-1.11.0-hfcd1e18_0.conda - conda: https://prefix.dev/conda-forge/linux-64/expat-2.6.4-h5888daf_0.conda - - conda: https://prefix.dev/conda-forge/linux-64/fortran-compiler-1.10.0-h36df796_0.conda - - conda: https://prefix.dev/conda-forge/linux-64/gcc-13.3.0-h9576a4e_2.conda - - conda: https://prefix.dev/conda-forge/linux-64/gcc_impl_linux-64-13.3.0-h1e990d8_2.conda - - conda: https://prefix.dev/conda-forge/linux-64/gcc_linux-64-13.3.0-h6f18a23_11.conda - - conda: https://prefix.dev/conda-forge/linux-64/gfortran-13.3.0-h9576a4e_2.conda - - conda: https://prefix.dev/conda-forge/linux-64/gfortran_impl_linux-64-13.3.0-h84c1745_2.conda - - conda: https://prefix.dev/conda-forge/linux-64/gfortran_linux-64-13.3.0-h1917dac_11.conda - - conda: https://prefix.dev/conda-forge/linux-64/gxx-13.3.0-h9576a4e_2.conda - - conda: https://prefix.dev/conda-forge/linux-64/gxx_impl_linux-64-13.3.0-hae580e1_2.conda - - conda: https://prefix.dev/conda-forge/linux-64/gxx_linux-64-13.3.0-hb14504d_11.conda + - conda: https://prefix.dev/conda-forge/linux-64/fortran-compiler-1.11.0-h9bea470_0.conda + - conda: https://prefix.dev/conda-forge/linux-64/gcc-14.3.0-he448592_3.conda + - conda: https://prefix.dev/conda-forge/linux-64/gcc_impl_linux-64-14.3.0-hd9e9e21_3.conda + - conda: https://prefix.dev/conda-forge/linux-64/gcc_linux-64-14.3.0-h1382650_11.conda + - conda: https://prefix.dev/conda-forge/linux-64/gfortran-14.3.0-he448592_3.conda + - conda: https://prefix.dev/conda-forge/linux-64/gfortran_impl_linux-64-14.3.0-h7db7018_3.conda + - conda: https://prefix.dev/conda-forge/linux-64/gfortran_linux-64-14.3.0-h30a37f7_11.conda + - conda: https://prefix.dev/conda-forge/linux-64/gxx-14.3.0-he448592_3.conda + - conda: https://prefix.dev/conda-forge/linux-64/gxx_impl_linux-64-14.3.0-he663afc_3.conda + - conda: https://prefix.dev/conda-forge/linux-64/gxx_linux-64-14.3.0-ha7acb78_11.conda - conda: https://prefix.dev/conda-forge/linux-64/icu-75.1-he02047a_0.conda - conda: https://prefix.dev/conda-forge/noarch/kernel-headers_linux-64-3.10.0-he073ed8_18.conda - conda: https://prefix.dev/conda-forge/linux-64/keyutils-1.6.1-h166bdaf_0.tar.bz2 @@ -41,22 +42,22 @@ environments: - conda: https://prefix.dev/conda-forge/linux-64/libedit-3.1.20250104-pl5321h7949ede_0.conda - conda: https://prefix.dev/conda-forge/linux-64/libev-4.33-hd590300_2.conda - conda: https://prefix.dev/conda-forge/linux-64/libexpat-2.6.4-h5888daf_0.conda - - conda: https://prefix.dev/conda-forge/linux-64/libgcc-14.2.0-h767d61c_2.conda - - conda: https://prefix.dev/conda-forge/noarch/libgcc-devel_linux-64-13.3.0-hc03c837_102.conda - - conda: https://prefix.dev/conda-forge/linux-64/libgcc-ng-14.2.0-h69a702a_2.conda - - conda: https://prefix.dev/conda-forge/linux-64/libgfortran5-14.2.0-hf1ad2bd_2.conda - - conda: https://prefix.dev/conda-forge/linux-64/libgomp-14.2.0-h767d61c_2.conda + - conda: https://prefix.dev/conda-forge/linux-64/libgcc-15.1.0-h767d61c_3.conda + - conda: https://prefix.dev/conda-forge/noarch/libgcc-devel_linux-64-14.3.0-h85bb3a7_103.conda + - conda: https://prefix.dev/conda-forge/linux-64/libgcc-ng-15.1.0-h69a702a_3.conda + - conda: https://prefix.dev/conda-forge/linux-64/libgfortran5-15.1.0-hcea5267_3.conda + - conda: https://prefix.dev/conda-forge/linux-64/libgomp-15.1.0-h767d61c_3.conda - conda: https://prefix.dev/conda-forge/linux-64/libhwloc-2.11.2-default_h0d58e46_1001.conda - conda: https://prefix.dev/conda-forge/linux-64/libiconv-1.18-h4ce23a2_1.conda - conda: https://prefix.dev/conda-forge/linux-64/libllvm18-18.1.8-ha7bfdaf_3.conda - conda: https://prefix.dev/conda-forge/linux-64/liblzma-5.6.4-hb9d3cd8_0.conda - conda: https://prefix.dev/conda-forge/linux-64/liblzma-devel-5.6.4-hb9d3cd8_0.conda - conda: https://prefix.dev/conda-forge/linux-64/libnghttp2-1.58.0-h47da74e_1.conda - - conda: https://prefix.dev/conda-forge/linux-64/libsanitizer-13.3.0-he8ea267_2.conda + - conda: https://prefix.dev/conda-forge/linux-64/libsanitizer-14.3.0-hd08acf3_3.conda - conda: https://prefix.dev/conda-forge/linux-64/libssh2-1.11.0-h0841786_0.conda - - conda: https://prefix.dev/conda-forge/linux-64/libstdcxx-14.2.0-h8f9b012_2.conda - - conda: https://prefix.dev/conda-forge/noarch/libstdcxx-devel_linux-64-13.3.0-hc03c837_102.conda - - conda: https://prefix.dev/conda-forge/linux-64/libstdcxx-ng-14.2.0-h4852527_2.conda + - conda: https://prefix.dev/conda-forge/linux-64/libstdcxx-15.1.0-h8f9b012_3.conda + - conda: https://prefix.dev/conda-forge/noarch/libstdcxx-devel_linux-64-14.3.0-h85bb3a7_103.conda + - conda: https://prefix.dev/conda-forge/linux-64/libstdcxx-ng-15.1.0-h4852527_3.conda - conda: https://prefix.dev/conda-forge/linux-64/libuv-1.50.0-hb9d3cd8_0.conda - conda: https://prefix.dev/conda-forge/linux-64/libxml2-2.13.6-h8d12d68_0.conda - conda: https://prefix.dev/conda-forge/linux-64/libzlib-1.3.1-hb9d3cd8_2.conda @@ -81,45 +82,46 @@ environments: osx-64: - conda: https://prefix.dev/conda-forge/osx-64/bzip2-1.0.8-hfdf4475_7.conda - conda: https://prefix.dev/conda-forge/osx-64/c-ares-1.34.4-hf13058a_0.conda - - conda: https://prefix.dev/conda-forge/osx-64/c-compiler-1.10.0-h09a7c41_0.conda + - conda: https://prefix.dev/conda-forge/osx-64/c-compiler-1.11.0-h7a00415_0.conda - conda: https://prefix.dev/conda-forge/osx-64/ca-certificates-2025.1.31-h8857fd0_0.conda - conda: https://prefix.dev/conda-forge/osx-64/cargo-nextest-0.9.91-hd2571bf_0.conda - - conda: https://prefix.dev/conda-forge/osx-64/cctools-1010.6-ha66f10e_6.conda - - conda: https://prefix.dev/conda-forge/osx-64/cctools_osx-64-1010.6-hd19c6af_6.conda - - conda: https://prefix.dev/conda-forge/osx-64/clang-18-18.1.8-default_h3571c67_10.conda - - conda: https://prefix.dev/conda-forge/osx-64/clang-18.1.8-default_h576c50e_10.conda - - conda: https://prefix.dev/conda-forge/osx-64/clang_impl_osx-64-18.1.8-h6a44ed1_25.conda - - conda: https://prefix.dev/conda-forge/osx-64/clang_osx-64-18.1.8-h7e5c614_25.conda - - conda: https://prefix.dev/conda-forge/osx-64/clangxx-18.1.8-default_heb2e8d1_10.conda - - conda: https://prefix.dev/conda-forge/osx-64/clangxx_impl_osx-64-18.1.8-h4b7810f_25.conda - - conda: https://prefix.dev/conda-forge/osx-64/clangxx_osx-64-18.1.8-h7e5c614_25.conda + - conda: https://prefix.dev/conda-forge/osx-64/cctools-1021.4-h67a6458_1.conda + - conda: https://prefix.dev/conda-forge/osx-64/cctools_osx-64-1021.4-haa85c18_1.conda + - conda: https://prefix.dev/conda-forge/osx-64/clang-19-19.1.7-default_h3571c67_3.conda + - conda: https://prefix.dev/conda-forge/osx-64/clang-19.1.7-default_h576c50e_3.conda + - conda: https://prefix.dev/conda-forge/osx-64/clang_impl_osx-64-19.1.7-hc73cdc9_25.conda + - conda: https://prefix.dev/conda-forge/osx-64/clang_osx-64-19.1.7-h7e5c614_25.conda + - conda: https://prefix.dev/conda-forge/osx-64/clangxx-19.1.7-default_heb2e8d1_3.conda + - conda: https://prefix.dev/conda-forge/osx-64/clangxx_impl_osx-64-19.1.7-hb295874_25.conda + - conda: https://prefix.dev/conda-forge/osx-64/clangxx_osx-64-19.1.7-h7e5c614_25.conda - conda: https://prefix.dev/conda-forge/osx-64/cmake-3.26.4-hf40c264_0.conda - - conda: https://prefix.dev/conda-forge/osx-64/compiler-rt-18.1.8-h1020d70_1.conda - - conda: https://prefix.dev/conda-forge/noarch/compiler-rt_osx-64-18.1.8-hf2b8a54_1.conda - - conda: https://prefix.dev/conda-forge/osx-64/cxx-compiler-1.10.0-h20888b2_0.conda + - conda: https://prefix.dev/conda-forge/osx-64/compiler-rt-19.1.7-h52031e2_0.conda + - conda: https://prefix.dev/conda-forge/noarch/compiler-rt_osx-64-19.1.7-hc6f8467_0.conda + - conda: https://prefix.dev/conda-forge/osx-64/cxx-compiler-1.11.0-h307afc9_0.conda - conda: https://prefix.dev/conda-forge/osx-64/expat-2.6.4-h240833e_0.conda + - conda: https://prefix.dev/conda-forge/osx-64/icu-75.1-h120a0e1_0.conda - conda: https://prefix.dev/conda-forge/osx-64/krb5-1.21.2-hb884880_0.conda - - conda: https://prefix.dev/conda-forge/osx-64/ld64-951.9-h4e51db5_6.conda - - conda: https://prefix.dev/conda-forge/osx-64/ld64_osx-64-951.9-h33512f0_6.conda - - conda: https://prefix.dev/conda-forge/osx-64/libclang-cpp18.1-18.1.8-default_h3571c67_10.conda + - conda: https://prefix.dev/conda-forge/osx-64/ld64-954.16-hc3792c1_1.conda + - conda: https://prefix.dev/conda-forge/osx-64/ld64_osx-64-954.16-hf1c22e8_1.conda + - conda: https://prefix.dev/conda-forge/osx-64/libclang-cpp19.1-19.1.7-default_h3571c67_3.conda - conda: https://prefix.dev/conda-forge/osx-64/libcurl-8.8.0-hf9fcc65_0.conda - conda: https://prefix.dev/conda-forge/osx-64/libcxx-19.1.7-hf95d169_0.conda - - conda: https://prefix.dev/conda-forge/osx-64/libcxx-devel-18.1.8-h7c275be_8.conda + - conda: https://prefix.dev/conda-forge/osx-64/libcxx-devel-19.1.7-h7c275be_1.conda - conda: https://prefix.dev/conda-forge/osx-64/libedit-3.1.20250104-pl5321ha958ccf_0.conda - conda: https://prefix.dev/conda-forge/osx-64/libev-4.33-h10d778d_2.conda - conda: https://prefix.dev/conda-forge/osx-64/libexpat-2.6.4-h240833e_0.conda - conda: https://prefix.dev/conda-forge/osx-64/libiconv-1.18-h4b5e92a_1.conda - - conda: https://prefix.dev/conda-forge/osx-64/libllvm18-18.1.8-default_h3571c67_5.conda + - conda: https://prefix.dev/conda-forge/osx-64/libllvm19-19.1.7-hc29ff6c_1.conda - conda: https://prefix.dev/conda-forge/osx-64/liblzma-5.6.4-hd471939_0.conda - conda: https://prefix.dev/conda-forge/osx-64/liblzma-devel-5.6.4-hd471939_0.conda - conda: https://prefix.dev/conda-forge/osx-64/libnghttp2-1.58.0-h64cf6d3_1.conda - conda: https://prefix.dev/conda-forge/osx-64/libssh2-1.11.0-hd019ec5_0.conda - conda: https://prefix.dev/conda-forge/osx-64/libuv-1.50.0-h4cb831e_0.conda - - conda: https://prefix.dev/conda-forge/osx-64/libxml2-2.14.0-he8ee3e7_0.conda + - conda: https://prefix.dev/conda-forge/osx-64/libxml2-2.13.7-hebb159f_0.conda - conda: https://prefix.dev/conda-forge/osx-64/libzlib-1.3.1-hd23fc13_2.conda - conda: https://prefix.dev/conda-forge/osx-64/llvm-openmp-19.1.7-ha54dae1_0.conda - - conda: https://prefix.dev/conda-forge/osx-64/llvm-tools-18-18.1.8-default_h3571c67_5.conda - - conda: https://prefix.dev/conda-forge/osx-64/llvm-tools-18.1.8-default_h3571c67_5.conda + - conda: https://prefix.dev/conda-forge/osx-64/llvm-tools-19-19.1.7-he90a8e3_1.conda + - conda: https://prefix.dev/conda-forge/osx-64/llvm-tools-19.1.7-h3fe3016_1.conda - conda: https://prefix.dev/conda-forge/osx-64/make-4.4.1-h00291cd_2.conda - conda: https://prefix.dev/conda-forge/osx-64/ncurses-6.5-h0622a9a_3.conda - conda: https://prefix.dev/conda-forge/osx-64/openssl-3.3.0-h87427d6_3.conda @@ -138,31 +140,31 @@ environments: osx-arm64: - conda: https://prefix.dev/conda-forge/osx-arm64/bzip2-1.0.8-h99b78c6_7.conda - conda: https://prefix.dev/conda-forge/osx-arm64/c-ares-1.34.4-h5505292_0.conda - - conda: https://prefix.dev/conda-forge/osx-arm64/c-compiler-1.10.0-hdf49b6b_0.conda + - conda: https://prefix.dev/conda-forge/osx-arm64/c-compiler-1.11.0-h61f9b84_0.conda - conda: https://prefix.dev/conda-forge/osx-arm64/ca-certificates-2025.1.31-hf0a4a13_0.conda - conda: https://prefix.dev/conda-forge/osx-arm64/cargo-nextest-0.9.91-h8dba533_0.conda - - conda: https://prefix.dev/conda-forge/osx-arm64/cctools-1010.6-hb4fb6a3_6.conda - - conda: https://prefix.dev/conda-forge/osx-arm64/cctools_osx-arm64-1010.6-h3b4f5d3_6.conda - - conda: https://prefix.dev/conda-forge/osx-arm64/clang-18-18.1.8-default_hf90f093_10.conda - - conda: https://prefix.dev/conda-forge/osx-arm64/clang-18.1.8-default_h474c9e2_10.conda - - conda: https://prefix.dev/conda-forge/osx-arm64/clang_impl_osx-arm64-18.1.8-h2ae9ea5_25.conda - - conda: https://prefix.dev/conda-forge/osx-arm64/clang_osx-arm64-18.1.8-h07b0088_25.conda - - conda: https://prefix.dev/conda-forge/osx-arm64/clangxx-18.1.8-default_h1ffe849_10.conda - - conda: https://prefix.dev/conda-forge/osx-arm64/clangxx_impl_osx-arm64-18.1.8-h555f467_25.conda - - conda: https://prefix.dev/conda-forge/osx-arm64/clangxx_osx-arm64-18.1.8-h07b0088_25.conda + - conda: https://prefix.dev/conda-forge/osx-arm64/cctools-1021.4-hd01ab73_1.conda + - conda: https://prefix.dev/conda-forge/osx-arm64/cctools_osx-arm64-1021.4-haeb51d2_1.conda + - conda: https://prefix.dev/conda-forge/osx-arm64/clang-19-19.1.7-default_hf90f093_3.conda + - conda: https://prefix.dev/conda-forge/osx-arm64/clang-19.1.7-default_h474c9e2_3.conda + - conda: https://prefix.dev/conda-forge/osx-arm64/clang_impl_osx-arm64-19.1.7-h76e6a08_25.conda + - conda: https://prefix.dev/conda-forge/osx-arm64/clang_osx-arm64-19.1.7-h07b0088_25.conda + - conda: https://prefix.dev/conda-forge/osx-arm64/clangxx-19.1.7-default_h1ffe849_3.conda + - conda: https://prefix.dev/conda-forge/osx-arm64/clangxx_impl_osx-arm64-19.1.7-h276745f_25.conda + - conda: https://prefix.dev/conda-forge/osx-arm64/clangxx_osx-arm64-19.1.7-h07b0088_25.conda - conda: https://prefix.dev/conda-forge/osx-arm64/cmake-3.26.4-hc0af03a_0.conda - - conda: https://prefix.dev/conda-forge/osx-arm64/compiler-rt-18.1.8-h856b3c1_1.conda - - conda: https://prefix.dev/conda-forge/noarch/compiler-rt_osx-arm64-18.1.8-h832e737_1.conda - - conda: https://prefix.dev/conda-forge/osx-arm64/cxx-compiler-1.10.0-hba80287_0.conda + - conda: https://prefix.dev/conda-forge/osx-arm64/compiler-rt-19.1.7-hd2aecb6_0.conda + - conda: https://prefix.dev/conda-forge/noarch/compiler-rt_osx-arm64-19.1.7-h7969c41_0.conda + - conda: https://prefix.dev/conda-forge/osx-arm64/cxx-compiler-1.11.0-h88570a1_0.conda - conda: https://prefix.dev/conda-forge/osx-arm64/expat-2.6.4-h286801f_0.conda - conda: https://prefix.dev/conda-forge/osx-arm64/icu-75.1-hfee45f7_0.conda - conda: https://prefix.dev/conda-forge/osx-arm64/krb5-1.21.2-h92f50d5_0.conda - - conda: https://prefix.dev/conda-forge/osx-arm64/ld64-951.9-h4c6efb1_6.conda - - conda: https://prefix.dev/conda-forge/osx-arm64/ld64_osx-arm64-951.9-hb6b49e2_6.conda - - conda: https://prefix.dev/conda-forge/osx-arm64/libclang-cpp18.1-18.1.8-default_hf90f093_10.conda + - conda: https://prefix.dev/conda-forge/osx-arm64/ld64-954.16-he86490a_1.conda + - conda: https://prefix.dev/conda-forge/osx-arm64/ld64_osx-arm64-954.16-hc42d924_1.conda + - conda: https://prefix.dev/conda-forge/osx-arm64/libclang-cpp19.1-19.1.7-default_hf90f093_3.conda - conda: https://prefix.dev/conda-forge/osx-arm64/libcurl-8.8.0-h7b6f9a7_0.conda - conda: https://prefix.dev/conda-forge/osx-arm64/libcxx-19.1.7-ha82da77_0.conda - - conda: https://prefix.dev/conda-forge/osx-arm64/libcxx-devel-18.1.8-h6dc3340_8.conda + - conda: https://prefix.dev/conda-forge/osx-arm64/libcxx-devel-19.1.7-h6dc3340_1.conda - conda: https://prefix.dev/conda-forge/osx-arm64/libedit-3.1.20250104-pl5321hafb1f1b_0.conda - conda: https://prefix.dev/conda-forge/osx-arm64/libev-4.33-h93a5062_2.conda - conda: https://prefix.dev/conda-forge/osx-arm64/libexpat-2.6.4-h286801f_0.conda @@ -170,17 +172,17 @@ environments: - conda: https://prefix.dev/conda-forge/osx-arm64/libglib-2.82.2-hdff4504_1.conda - conda: https://prefix.dev/conda-forge/osx-arm64/libiconv-1.18-hfe07756_1.conda - conda: https://prefix.dev/conda-forge/osx-arm64/libintl-0.23.1-h493aca8_0.conda - - conda: https://prefix.dev/conda-forge/osx-arm64/libllvm18-18.1.8-default_hb458b26_5.conda + - conda: https://prefix.dev/conda-forge/osx-arm64/libllvm19-19.1.7-hc4b4ae8_1.conda - conda: https://prefix.dev/conda-forge/osx-arm64/liblzma-5.6.4-h39f12f2_0.conda - conda: https://prefix.dev/conda-forge/osx-arm64/liblzma-devel-5.6.4-h39f12f2_0.conda - conda: https://prefix.dev/conda-forge/osx-arm64/libnghttp2-1.58.0-ha4dd798_1.conda - conda: https://prefix.dev/conda-forge/osx-arm64/libssh2-1.11.0-h7a5bd25_0.conda - conda: https://prefix.dev/conda-forge/osx-arm64/libuv-1.50.0-h5505292_0.conda - - conda: https://prefix.dev/conda-forge/osx-arm64/libxml2-2.14.0-h178c5d8_0.conda + - conda: https://prefix.dev/conda-forge/osx-arm64/libxml2-2.13.7-h178c5d8_0.conda - conda: https://prefix.dev/conda-forge/osx-arm64/libzlib-1.3.1-h8359307_2.conda - conda: https://prefix.dev/conda-forge/osx-arm64/llvm-openmp-19.1.7-hdb05f8b_0.conda - - conda: https://prefix.dev/conda-forge/osx-arm64/llvm-tools-18-18.1.8-default_hb458b26_5.conda - - conda: https://prefix.dev/conda-forge/osx-arm64/llvm-tools-18.1.8-default_hb458b26_5.conda + - conda: https://prefix.dev/conda-forge/osx-arm64/llvm-tools-19-19.1.7-h87a4c7e_1.conda + - conda: https://prefix.dev/conda-forge/osx-arm64/llvm-tools-19.1.7-hd2aecb6_1.conda - conda: https://prefix.dev/conda-forge/osx-arm64/make-4.4.1-hc9fafa5_2.conda - conda: https://prefix.dev/conda-forge/osx-arm64/ncurses-6.5-h5e97a16_3.conda - conda: https://prefix.dev/conda-forge/osx-arm64/openssl-3.3.0-hfb2fe0b_3.conda @@ -203,7 +205,7 @@ environments: - conda: https://prefix.dev/conda-forge/win-64/ca-certificates-2025.1.31-h56e8100_0.conda - conda: https://prefix.dev/conda-forge/win-64/cargo-nextest-0.9.91-ha073cba_0.conda - conda: https://prefix.dev/conda-forge/win-64/cmake-3.26.4-h1537add_0.conda - - conda: https://prefix.dev/conda-forge/win-64/cxx-compiler-1.10.0-h1c1089f_0.conda + - conda: https://prefix.dev/conda-forge/win-64/cxx-compiler-1.11.0-h1c1089f_0.conda - conda: https://prefix.dev/conda-forge/win-64/libffi-3.4.6-h537db12_0.conda - conda: https://prefix.dev/conda-forge/win-64/libgcc-14.2.0-h1383e82_2.conda - conda: https://prefix.dev/conda-forge/win-64/libglib-2.82.2-h7025463_1.conda @@ -512,38 +514,41 @@ packages: license_family: MIT size: 179496 timestamp: 1734208291879 -- conda: https://prefix.dev/conda-forge/linux-64/c-compiler-1.10.0-h2b85faf_0.conda - sha256: 70be54bfe92b72794f664ad95b6fcef74d508710a9b2d790bc9c69f5a40239c3 - md5: 9256b7e5e900a1b98aedc8d6ffe91bec +- conda: https://prefix.dev/conda-forge/linux-64/c-compiler-1.11.0-h4d9bdce_0.conda + sha256: 8e7a40f16400d7839c82581410aa05c1f8324a693c9d50079f8c50dc9fb241f0 + md5: abd85120de1187b0d1ec305c2173c71b depends: - binutils - gcc - - gcc_linux-64 13.* + - gcc_linux-64 14.* license: BSD-3-Clause - size: 6667 - timestamp: 1751115555092 -- conda: https://prefix.dev/conda-forge/osx-64/c-compiler-1.10.0-h09a7c41_0.conda - sha256: 6a3f6b72bf5ad154630f79bd600f6ccf0f5c6a4be5297e4831d63016f4220e62 - md5: 7b7c12e4774b83c18612c78073d12adc + license_family: BSD + size: 6693 + timestamp: 1753098721814 +- conda: https://prefix.dev/conda-forge/osx-64/c-compiler-1.11.0-h7a00415_0.conda + sha256: 2bd1cf3d26789b7e1d04e914ccd169bd618fceed68abf7b6a305266b88dcf861 + md5: 2b23ec416cef348192a5a17737ddee60 depends: - cctools >=949.0.1 - - clang_osx-64 18.* + - clang_osx-64 19.* - ld64 >=530 - llvm-openmp license: BSD-3-Clause - size: 6773 - timestamp: 1751115657381 -- conda: https://prefix.dev/conda-forge/osx-arm64/c-compiler-1.10.0-hdf49b6b_0.conda - sha256: efc71f2ae5901bea633c67468b3aa774b6bcf46c9433e1ab5d640e3faf1680b9 - md5: 7ca1bdcc45db75f54ed7b3ac969ed888 + license_family: BSD + size: 6695 + timestamp: 1753098825695 +- conda: https://prefix.dev/conda-forge/osx-arm64/c-compiler-1.11.0-h61f9b84_0.conda + sha256: b51bd1551cfdf41500f732b4bd1e4e70fb1e74557165804a648f32fa9c671eec + md5: 148516e0c9edf4e9331a4d53ae806a9b depends: - cctools >=949.0.1 - - clang_osx-arm64 18.* + - clang_osx-arm64 19.* - ld64 >=530 - llvm-openmp license: BSD-3-Clause - size: 6758 - timestamp: 1751115540465 + license_family: BSD + size: 6697 + timestamp: 1753098737760 - conda: https://prefix.dev/conda-forge/linux-64/ca-certificates-2025.1.31-hbcca054_0.conda sha256: bf832198976d559ab44d6cdb315642655547e26d826e34da67cbee6624cda189 md5: 19f3a56f68d2fd06c516076bff482c52 @@ -616,66 +621,66 @@ packages: license_family: MIT size: 5128636 timestamp: 1739520725827 -- conda: https://prefix.dev/conda-forge/osx-64/cctools-1010.6-ha66f10e_6.conda - sha256: c716942cddaaf6afb618da32020c5a8ab2aec547bd3f0766c40b95680b998f05 - md5: a126dcde2752751ac781b67238f7fac4 +- conda: https://prefix.dev/conda-forge/osx-64/cctools-1021.4-h67a6458_1.conda + sha256: 8e33799b8513dadde735273532318f40493499abcba49cafdae45e040896c6b7 + md5: d40f6a13fcae56b9f0f90c8ee26f29c7 depends: - - cctools_osx-64 1010.6 hd19c6af_6 - - ld64 951.9 h4e51db5_6 - - libllvm18 >=18.1.8,<18.2.0a0 + - cctools_osx-64 1021.4 haa85c18_1 + - ld64 954.16 hc3792c1_1 + - libllvm19 >=19.1.7,<19.2.0a0 license: APSL-2.0 license_family: Other - size: 22135 - timestamp: 1743872208832 -- conda: https://prefix.dev/conda-forge/osx-arm64/cctools-1010.6-hb4fb6a3_6.conda - sha256: 393fc3bf21b0187384e652aa4fab184d633e57e3e63f2b10f16a3d5f7bb0717b - md5: e0ba8df6997102eb4d367e3e70f90778 - depends: - - cctools_osx-arm64 1010.6 h3b4f5d3_6 - - ld64 951.9 h4c6efb1_6 - - libllvm18 >=18.1.8,<18.2.0a0 + size: 21650 + timestamp: 1752907781714 +- conda: https://prefix.dev/conda-forge/osx-arm64/cctools-1021.4-hd01ab73_1.conda + sha256: 7908271f73bf19b208895df56f9a1ef73f9fe020f71180b4745835bc490471a8 + md5: 0e8adae6bc50f150c35ac51b2851d6aa + depends: + - cctools_osx-arm64 1021.4 haeb51d2_1 + - ld64 954.16 he86490a_1 + - libllvm19 >=19.1.7,<19.2.0a0 license: APSL-2.0 license_family: Other - size: 22254 - timestamp: 1743872374133 -- conda: https://prefix.dev/conda-forge/osx-64/cctools_osx-64-1010.6-hd19c6af_6.conda - sha256: 7b2b765be41040c749d10ba848c4afbaae89a9ebb168bbf809c8133486f39bcb - md5: 4694e9e497454a8ce5b9fb61e50d9c5d + size: 21660 + timestamp: 1752907658137 +- conda: https://prefix.dev/conda-forge/osx-64/cctools_osx-64-1021.4-haa85c18_1.conda + sha256: f70aa8a4afbbb0aaa685bdb6c2afdb5dcf3cd16f154935697a2d73ffc82c9f20 + md5: 3d0efe1461e5558fdb78118735e9bd06 depends: - __osx >=10.13 - - ld64_osx-64 >=951.9,<951.10.0a0 + - ld64_osx-64 >=954.16,<954.17.0a0 - libcxx - - libllvm18 >=18.1.8,<18.2.0a0 + - libllvm19 >=19.1.7,<19.2.0a0 - libzlib >=1.3.1,<2.0a0 - - llvm-tools 18.1.* + - llvm-tools 19.1.* - sigtool constrains: - - clang 18.1.* - - cctools 1010.6.* - - ld64 951.9.* + - clang 19.1.* + - ld64 954.16.* + - cctools 1021.4.* license: APSL-2.0 license_family: Other - size: 1119992 - timestamp: 1743872180962 -- conda: https://prefix.dev/conda-forge/osx-arm64/cctools_osx-arm64-1010.6-h3b4f5d3_6.conda - sha256: 6e9463499dddad0ee61c999031c84bd1b8233676bcd220aece1b754667c680d7 - md5: b876da50fbe92a19737933c7aa92fb02 + size: 791799 + timestamp: 1752907740554 +- conda: https://prefix.dev/conda-forge/osx-arm64/cctools_osx-arm64-1021.4-haeb51d2_1.conda + sha256: 47b76be8fed6e1d3e6fb418d98930337a99f16639910bea35451a6776b81bd2f + md5: e173bd2f669898a681b307400e900335 depends: - __osx >=11.0 - - ld64_osx-arm64 >=951.9,<951.10.0a0 + - ld64_osx-arm64 >=954.16,<954.17.0a0 - libcxx - - libllvm18 >=18.1.8,<18.2.0a0 + - libllvm19 >=19.1.7,<19.2.0a0 - libzlib >=1.3.1,<2.0a0 - - llvm-tools 18.1.* + - llvm-tools 19.1.* - sigtool constrains: - - cctools 1010.6.* - - ld64 951.9.* - - clang 18.1.* + - cctools 1021.4.* + - ld64 954.16.* + - clang 19.1.* license: APSL-2.0 license_family: Other - size: 1103413 - timestamp: 1743872332962 + size: 792286 + timestamp: 1752907619396 - conda: https://prefix.dev/conda-forge/linux-64/cffi-1.17.1-py312h06ac9bb_0.conda sha256: cba6ea83c4b0b4f5b5dc59cb19830519b28f95d7ebef7c9c5cf1c14843621457 md5: a861504bbea4161a9170b85d4d2be840 @@ -752,24 +757,24 @@ packages: license_family: Apache size: 71043 timestamp: 1738271899246 -- conda: https://prefix.dev/conda-forge/osx-64/clang-18.1.8-default_h576c50e_10.conda - sha256: 663d5c8d26e4f467075a49df26624a95efc69ba275cd0fb823979e06964f024f - md5: 350a10c62423982b0c80a043b9921c00 +- conda: https://prefix.dev/conda-forge/osx-64/clang-19.1.7-default_h576c50e_3.conda + sha256: 838abc0a72f1227cac837b9350809d7c852e5e4e69952b21789f12ae1557bcce + md5: 7b5ece07d175b7175b4a544f9835683a depends: - - clang-18 18.1.8 default_h3571c67_10 + - clang-19 19.1.7 default_h3571c67_3 license: Apache-2.0 WITH LLVM-exception license_family: Apache - size: 75476 - timestamp: 1747763835551 -- conda: https://prefix.dev/conda-forge/osx-arm64/clang-18.1.8-default_h474c9e2_10.conda - sha256: 2f8ad9fa2e345c62daaa0978b8ae578ff46b89c068d4666da1b95d77599a1de2 - md5: 1824da9753ade2d34291175377387bbe + size: 24253 + timestamp: 1747709797405 +- conda: https://prefix.dev/conda-forge/osx-arm64/clang-19.1.7-default_h474c9e2_3.conda + sha256: e2061f7a16ae5a381d7f66b5ccd91a92b7ad6ac356f1d2ee2934015581eb3bf7 + md5: b5a92027d9f6136108beeda7b6edfec9 depends: - - clang-18 18.1.8 default_hf90f093_10 + - clang-19 19.1.7 default_hf90f093_3 license: Apache-2.0 WITH LLVM-exception license_family: Apache - size: 75645 - timestamp: 1747715057267 + size: 24360 + timestamp: 1747709802932 - conda: https://prefix.dev/conda-forge/linux-64/clang-18-18.1.8-default_hb5137d0_7.conda sha256: d703875711c68e745ee221d5af736f9137d9a582475b743c967edefa899dcb11 md5: 008ded7331a8b5f5f9a5daa8e4fe0d84 @@ -783,138 +788,138 @@ packages: license_family: Apache size: 822892 timestamp: 1738271833111 -- conda: https://prefix.dev/conda-forge/osx-64/clang-18-18.1.8-default_h3571c67_10.conda - sha256: cb06e7522fdd4d3f42d8c09a6caad216e40ee650340e72e01ca30689fac4f862 - md5: 62e1cd0882dad47d6a6878ad037f7b9d +- conda: https://prefix.dev/conda-forge/osx-64/clang-19-19.1.7-default_h3571c67_3.conda + sha256: 6ff0928325ea99a65b1c3dc0a212fd0cb5b65884657c8d3c0bcffc038d092431 + md5: 5bd5cda534488611b3970b768139127c depends: - __osx >=10.13 - - libclang-cpp18.1 18.1.8 default_h3571c67_10 - - libcxx >=18.1.8 - - libllvm18 >=18.1.8,<18.2.0a0 + - libclang-cpp19.1 19.1.7 default_h3571c67_3 + - libcxx >=19.1.7 + - libllvm19 >=19.1.7,<19.2.0a0 license: Apache-2.0 WITH LLVM-exception license_family: Apache - size: 811399 - timestamp: 1747763724121 -- conda: https://prefix.dev/conda-forge/osx-arm64/clang-18-18.1.8-default_hf90f093_10.conda - sha256: 64bbc372d2ab22a73deb6cbf7b2a3bade0572901b2639427a5f469b2ba6e438a - md5: 2cf44d7e80e11704eaa56eb823b5c821 + size: 766607 + timestamp: 1747709700983 +- conda: https://prefix.dev/conda-forge/osx-arm64/clang-19-19.1.7-default_hf90f093_3.conda + sha256: c7f21028560ee5cc72d882d930b56c8521126987308819c37b97e1760d3e39bc + md5: 8ea1b606f2c5cb255b53c868d1eb8dbc depends: - __osx >=11.0 - - libclang-cpp18.1 18.1.8 default_hf90f093_10 - - libcxx >=18.1.8 - - libllvm18 >=18.1.8,<18.2.0a0 + - libclang-cpp19.1 19.1.7 default_hf90f093_3 + - libcxx >=19.1.7 + - libllvm19 >=19.1.7,<19.2.0a0 license: Apache-2.0 WITH LLVM-exception license_family: Apache - size: 812786 - timestamp: 1747714916284 -- conda: https://prefix.dev/conda-forge/osx-64/clang_impl_osx-64-18.1.8-h6a44ed1_25.conda - sha256: fffb43ba2a04e6b25484840818628397be320f4ff0e5efcce8167f9d06216a94 - md5: bfc995f8ab9e8c22ebf365844da3383d + size: 760894 + timestamp: 1747709675681 +- conda: https://prefix.dev/conda-forge/osx-64/clang_impl_osx-64-19.1.7-hc73cdc9_25.conda + sha256: 88edc0b34affbfffcec5ffea59b432ee3dd114124fd4d5f992db6935421f4a64 + md5: 76954503be09430fb7f4683a61ffb7b0 depends: - cctools_osx-64 - - clang 18.1.8.* - - compiler-rt 18.1.8.* + - clang 19.1.7.* + - compiler-rt 19.1.7.* - ld64_osx-64 - - llvm-tools 18.1.8.* + - llvm-tools 19.1.7.* license: BSD-3-Clause license_family: BSD - size: 18256 - timestamp: 1748575659622 -- conda: https://prefix.dev/conda-forge/osx-arm64/clang_impl_osx-arm64-18.1.8-h2ae9ea5_25.conda - sha256: 35273ca91fb998f979402c76066af008ad3108a61a3b161d881fcb37700a48bb - md5: 9eb023cfc47dac4c22097b9344a943b4 + size: 18175 + timestamp: 1748575764900 +- conda: https://prefix.dev/conda-forge/osx-arm64/clang_impl_osx-arm64-19.1.7-h76e6a08_25.conda + sha256: ee3c0976bde0ac19f84d29213ea3d9c3fd9c56d56c33ee471a8680cf69307ce1 + md5: a4e2f211f7c3cf582a6cb447bee2cad9 depends: - cctools_osx-arm64 - - clang 18.1.8.* - - compiler-rt 18.1.8.* + - clang 19.1.7.* + - compiler-rt 19.1.7.* - ld64_osx-arm64 - - llvm-tools 18.1.8.* + - llvm-tools 19.1.7.* license: BSD-3-Clause license_family: BSD - size: 18331 - timestamp: 1748575702758 -- conda: https://prefix.dev/conda-forge/osx-64/clang_osx-64-18.1.8-h7e5c614_25.conda - sha256: 7f6aea0def866f1664b3ddf730d91e1b94da734b585c3e49cd51d3c4c66a1a49 - md5: 1fea06d9ced6b87fe63384443bc2efaf + size: 18159 + timestamp: 1748575942374 +- conda: https://prefix.dev/conda-forge/osx-64/clang_osx-64-19.1.7-h7e5c614_25.conda + sha256: 6435fdeae76f72109bc9c7b41596104075a2a8a9df3ee533bd98bb06548bbc83 + md5: a526ba9df7e7d5448d57b33941614dae depends: - - clang_impl_osx-64 18.1.8 h6a44ed1_25 + - clang_impl_osx-64 19.1.7 hc73cdc9_25 license: BSD-3-Clause license_family: BSD - size: 21534 - timestamp: 1748575663505 -- conda: https://prefix.dev/conda-forge/osx-arm64/clang_osx-arm64-18.1.8-h07b0088_25.conda - sha256: 4d1e695cd776783f6192fb8d4c7892c03e9f1f185dbb96cefdaab2f183430281 - md5: d9ee862b94f4049c9e121e6dd18cc874 + size: 21473 + timestamp: 1748575768567 +- conda: https://prefix.dev/conda-forge/osx-arm64/clang_osx-arm64-19.1.7-h07b0088_25.conda + sha256: 92a45a972af5eba3b7fca66880c3d5bdf73d0c69a3e21d1b3999fb9b5be1b323 + md5: 1b53cb5305ae53b5aeba20e58c625d96 depends: - - clang_impl_osx-arm64 18.1.8 h2ae9ea5_25 + - clang_impl_osx-arm64 19.1.7 h76e6a08_25 license: BSD-3-Clause license_family: BSD - size: 21563 - timestamp: 1748575706504 -- conda: https://prefix.dev/conda-forge/osx-64/clangxx-18.1.8-default_heb2e8d1_10.conda - sha256: 40e617f28eadab9e84c05d048a23934531847e0975b134a0a36ebb1816f8895a - md5: c39251c90faf5ba495d9f9ef88d7563e - depends: - - clang 18.1.8 default_h576c50e_10 - - libcxx-devel 18.1.8.* + size: 21337 + timestamp: 1748575949016 +- conda: https://prefix.dev/conda-forge/osx-64/clangxx-19.1.7-default_heb2e8d1_3.conda + sha256: 5870bdbd2c15abf84692f6069b2181a7a28f76451b28fc8e986b978d4f5c577f + md5: 1c1bbb9fb93dcf58f4dc6e308b1af083 + depends: + - clang 19.1.7 default_h576c50e_3 + - libcxx-devel 19.1.* license: Apache-2.0 WITH LLVM-exception license_family: Apache - size: 75639 - timestamp: 1747763857597 -- conda: https://prefix.dev/conda-forge/osx-arm64/clangxx-18.1.8-default_h1ffe849_10.conda - sha256: d6ebfaf4faf73a88cb4fbb20611fd01c646c2d5e742a11d59a702afef94d2246 - md5: 70e3f72ecc72f451524c3b5a4d50e383 - depends: - - clang 18.1.8 default_h474c9e2_10 - - libcxx-devel 18.1.8.* + size: 24370 + timestamp: 1747709814665 +- conda: https://prefix.dev/conda-forge/osx-arm64/clangxx-19.1.7-default_h1ffe849_3.conda + sha256: c6094b6c846248930ab2f559b04e14f9d6463e1c88b9d33b479bf27df916d6d7 + md5: 8b6dff933df21ccf744b5ecbc9dfd3ab + depends: + - clang 19.1.7 default_h474c9e2_3 + - libcxx-devel 19.1.* license: Apache-2.0 WITH LLVM-exception license_family: Apache - size: 75736 - timestamp: 1747715078489 -- conda: https://prefix.dev/conda-forge/osx-64/clangxx_impl_osx-64-18.1.8-h4b7810f_25.conda - sha256: 1b2ee79318f37b356d36cbcfc46ff8a0a4e1d8e5fdaed1e5dbc5a2b58cacbad7 - md5: c03c94381d9ffbec45c98b800e7d3e86 - depends: - - clang_osx-64 18.1.8 h7e5c614_25 - - clangxx 18.1.8.* - - libcxx >=18 - - libllvm18 >=18.1.8,<18.2.0a0 + size: 24486 + timestamp: 1747709816351 +- conda: https://prefix.dev/conda-forge/osx-64/clangxx_impl_osx-64-19.1.7-hb295874_25.conda + sha256: 8a2571da4bd90e3fc4523e962d6562607df133694a409959ec9c7ac4292bd676 + md5: 9fe0247ba2650f90c650001f88a87076 + depends: + - clang_osx-64 19.1.7 h7e5c614_25 + - clangxx 19.1.7.* + - libcxx >=19 + - libllvm19 >=19.1.7,<19.2.0a0 license: BSD-3-Clause license_family: BSD - size: 18390 - timestamp: 1748575690740 -- conda: https://prefix.dev/conda-forge/osx-arm64/clangxx_impl_osx-arm64-18.1.8-h555f467_25.conda - sha256: d0fb67a4ed19e9b40db08fce19afb342dcebc3609374a1b86c0d7a40abaf655c - md5: 4d72782682bc7d61a3612fea2c93299f - depends: - - clang_osx-arm64 18.1.8 h07b0088_25 - - clangxx 18.1.8.* - - libcxx >=18 - - libllvm18 >=18.1.8,<18.2.0a0 + size: 18289 + timestamp: 1748575802444 +- conda: https://prefix.dev/conda-forge/osx-arm64/clangxx_impl_osx-arm64-19.1.7-h276745f_25.conda + sha256: b997d325da6ca60e71937b9e28f114893401ca7cf94c4007d744e402a25c2c52 + md5: 5eeaa7b2dd32f62eb3beb0d6ba1e664f + depends: + - clang_osx-arm64 19.1.7 h07b0088_25 + - clangxx 19.1.7.* + - libcxx >=19 + - libllvm19 >=19.1.7,<19.2.0a0 license: BSD-3-Clause license_family: BSD - size: 18459 - timestamp: 1748575734378 -- conda: https://prefix.dev/conda-forge/osx-64/clangxx_osx-64-18.1.8-h7e5c614_25.conda - sha256: 1a1a31eae8b491104d33d422b57578f041d34afafb4da0a7355ef16fd5174090 - md5: 2e5c84e93a3519d77a0d8d9b3ea664fd - depends: - - clang_osx-64 18.1.8 h7e5c614_25 - - clangxx_impl_osx-64 18.1.8 h4b7810f_25 + size: 18297 + timestamp: 1748576000726 +- conda: https://prefix.dev/conda-forge/osx-64/clangxx_osx-64-19.1.7-h7e5c614_25.conda + sha256: 81365d98e1bb5f98a7acd1bde86ccf534b36c78bfae601e2c26a73d8de52da1e + md5: d0b5d9264d40ae1420e31c9066a1dcf0 + depends: + - clang_osx-64 19.1.7 h7e5c614_25 + - clangxx_impl_osx-64 19.1.7 hb295874_25 license: BSD-3-Clause license_family: BSD - size: 19947 - timestamp: 1748575697030 -- conda: https://prefix.dev/conda-forge/osx-arm64/clangxx_osx-arm64-18.1.8-h07b0088_25.conda - sha256: aae6cad658c9899f13d5941bcadc942f1a471acdfc43cd86c3635d0e353babc9 - md5: 4280e791148c1f9a3f8c0660d7a54acb - depends: - - clang_osx-arm64 18.1.8 h07b0088_25 - - clangxx_impl_osx-arm64 18.1.8 h555f467_25 + size: 19873 + timestamp: 1748575806458 +- conda: https://prefix.dev/conda-forge/osx-arm64/clangxx_osx-arm64-19.1.7-h07b0088_25.conda + sha256: 93801e6e821ae703d03629b1b993dbae1920b80012818edd5fcd18a9055897ce + md5: 4e09188aa8def7d8b3ae149aa856c0e5 + depends: + - clang_osx-arm64 19.1.7 h07b0088_25 + - clangxx_impl_osx-arm64 19.1.7 h276745f_25 license: BSD-3-Clause license_family: BSD - size: 19924 - timestamp: 1748575738546 + size: 19709 + timestamp: 1748576006669 - conda: https://prefix.dev/conda-forge/linux-64/cmake-3.26.4-hcfe8598_0.conda sha256: 37533b572a676017704c989c392998c344e889010786d6555dccdfc524a8e238 md5: 1714cf0f0facaeb609a0846e4270aff2 @@ -987,101 +992,112 @@ packages: license_family: BSD size: 15107993 timestamp: 1684462053404 -- conda: https://prefix.dev/conda-forge/osx-64/compiler-rt-18.1.8-h1020d70_1.conda - sha256: 30bd259ad8909c02ee9da8b13bf7c9f6dc0f4d6fa3c5d1cd82213180ca5f9c03 - md5: bc1714a1e73be18e411cff30dc1fe011 +- conda: https://prefix.dev/conda-forge/osx-64/compiler-rt-19.1.7-h52031e2_0.conda + sha256: 781b70f7475d387183fba59b5d88e874ec976458b893ec4e8c4c2564944aa680 + md5: 8098d99b4c30adb2f9cc18f8584d0b45 depends: - __osx >=10.13 - - clang 18.1.8.* - - clangxx 18.1.8.* - - compiler-rt_osx-64 18.1.8.* + - clang 19.1.7.* + - compiler-rt_osx-64 19.1.7.* license: Apache-2.0 WITH LLVM-exception license_family: APACHE - size: 95345 - timestamp: 1725258125808 -- conda: https://prefix.dev/conda-forge/osx-arm64/compiler-rt-18.1.8-h856b3c1_1.conda - sha256: 41e47093d3a03f0f81f26f66e5652a5b5c58589eafe59fbf67e8d60a3b30cdf7 - md5: 1f40b72021aa770bb56ffefe298f02a7 + size: 96517 + timestamp: 1736976706563 +- conda: https://prefix.dev/conda-forge/osx-arm64/compiler-rt-19.1.7-hd2aecb6_0.conda + sha256: db920f02717984329375c0c188335c23104895b0e5a2da295e475dabe4192c69 + md5: 28f46d13b77fcc390c84ca49b68b9ecb depends: - __osx >=11.0 - - clang 18.1.8.* - - clangxx 18.1.8.* - - compiler-rt_osx-arm64 18.1.8.* + - clang 19.1.7.* + - compiler-rt_osx-arm64 19.1.7.* license: Apache-2.0 WITH LLVM-exception license_family: APACHE - size: 95451 - timestamp: 1725258159749 -- conda: https://prefix.dev/conda-forge/noarch/compiler-rt_osx-64-18.1.8-hf2b8a54_1.conda - sha256: 1230fe22d190002693ba77cf8af754416d6ea7121707b74a7cd8ddc537f98bdb - md5: 76f906e6bdc58976c5593f650290ae20 - depends: - - clang 18.1.8.* - - clangxx 18.1.8.* + size: 96534 + timestamp: 1736976644597 +- conda: https://prefix.dev/conda-forge/noarch/compiler-rt_osx-64-19.1.7-hc6f8467_0.conda + sha256: bc64b862791161f90adb0e9b91290091604a3791e4434cb3901c13101136255b + md5: d5216811ea499344af3f05f71b922637 + depends: + - clang 19.1.7.* constrains: - - compiler-rt 18.1.8 + - compiler-rt 19.1.7 + - clangxx 19.1.7 license: Apache-2.0 WITH LLVM-exception license_family: APACHE - size: 10420490 - timestamp: 1725258080385 -- conda: https://prefix.dev/conda-forge/noarch/compiler-rt_osx-arm64-18.1.8-h832e737_1.conda - sha256: 97cc5d6a54dd159ddd2789a68245c6651915071b79f674e83dbc660f3ed760a9 - md5: f158d25465221c90668482b69737fee6 - depends: - - clang 18.1.8.* - - clangxx 18.1.8.* + size: 10666253 + timestamp: 1736976649189 +- conda: https://prefix.dev/conda-forge/noarch/compiler-rt_osx-arm64-19.1.7-h7969c41_0.conda + sha256: 6d9701824622609a47aae525d0a527e46dd7bbdc3f5648a3035df177f93d858e + md5: bb78d3cc0758bb3fc3cb0fab51ec4424 + depends: + - clang 19.1.7.* constrains: - - compiler-rt 18.1.8 + - clangxx 19.1.7 + - compiler-rt 19.1.7 license: Apache-2.0 WITH LLVM-exception license_family: APACHE - size: 10583287 - timestamp: 1725258124186 -- conda: https://prefix.dev/conda-forge/linux-64/compilers-1.10.0-ha770c72_0.conda - sha256: 17661cca0b6b70156a5d4a639c926bff0106576b5af5c8cab7afd9cd3cfa287b - md5: 993ae32cac4879279af74ba12aa0979c - depends: - - c-compiler 1.10.0 h2b85faf_0 - - cxx-compiler 1.10.0 h1a2810e_0 - - fortran-compiler 1.10.0 h36df796_0 + size: 10796006 + timestamp: 1736976593839 +- conda: https://prefix.dev/conda-forge/linux-64/compilers-1.11.0-ha770c72_0.conda + sha256: 5709f2cbfeb8690317ba702611bdf711a502b417fecda6ad3313e501f6f8bd61 + md5: fdcf2e31dd960ef7c5daa9f2c95eff0e + depends: + - c-compiler 1.11.0 h4d9bdce_0 + - cxx-compiler 1.11.0 hfcd1e18_0 + - fortran-compiler 1.11.0 h9bea470_0 license: BSD-3-Clause license_family: BSD - size: 7452 - timestamp: 1751115555727 -- conda: https://prefix.dev/conda-forge/linux-64/cxx-compiler-1.10.0-h1a2810e_0.conda - sha256: 88ff4a72ad70a3b9a20a0296e395c0caaa6dc0a0e46a752aa683fb42be03facd - md5: 3cd322edac3d40904ff07355a8be8086 + size: 7482 + timestamp: 1753098722454 +- conda: https://prefix.dev/conda-forge/linux-64/conda-gcc-specs-14.3.0-hb991d5c_3.conda + sha256: a95aa22a1c6af8cbc4a01cb03e00d60fad5b9b0b7d5b200d64270eb5d3831ea8 + md5: 85a2a894a53a4cdd67508e165911e8fc + depends: + - gcc_impl_linux-64 >=14.3.0,<14.3.1.0a0 + license: GPL-3.0-only WITH GCC-exception-3.1 + license_family: GPL + size: 33024 + timestamp: 1750808574793 +- conda: https://prefix.dev/conda-forge/linux-64/cxx-compiler-1.11.0-hfcd1e18_0.conda + sha256: 3fcc97ae3e89c150401a50a4de58794ffc67b1ed0e1851468fcc376980201e25 + md5: 5da8c935dca9186673987f79cef0b2a5 depends: - - c-compiler 1.10.0 h2b85faf_0 + - c-compiler 1.11.0 h4d9bdce_0 - gxx - - gxx_linux-64 13.* + - gxx_linux-64 14.* license: BSD-3-Clause - size: 6633 - timestamp: 1751115555450 -- conda: https://prefix.dev/conda-forge/osx-64/cxx-compiler-1.10.0-h20888b2_0.conda - sha256: 15f6ea7258555b2e34d147d378f4e8e08343ca3e71a18bd98b89a3dbc43142a2 - md5: b3a935ade707c54ebbea5f8a7c6f4549 - depends: - - c-compiler 1.10.0 h09a7c41_0 - - clangxx_osx-64 18.* + license_family: BSD + size: 6635 + timestamp: 1753098722177 +- conda: https://prefix.dev/conda-forge/osx-64/cxx-compiler-1.11.0-h307afc9_0.conda + sha256: d6976f8d8b51486072abfe1e76a733688380dcbd1a8e993a43d59b80f7288478 + md5: 463bb03bb27f9edc167fb3be224efe96 + depends: + - c-compiler 1.11.0 h7a00415_0 + - clangxx_osx-64 19.* license: BSD-3-Clause - size: 6785 - timestamp: 1751115659099 -- conda: https://prefix.dev/conda-forge/osx-arm64/cxx-compiler-1.10.0-hba80287_0.conda - sha256: 52cbfc615a9727294fccdd507f11919ca01ff29bd928bb5aa0b211697a983e9f - md5: 7fca30a1585a85ec8ab63579afcac5d3 - depends: - - c-compiler 1.10.0 hdf49b6b_0 - - clangxx_osx-arm64 18.* + license_family: BSD + size: 6732 + timestamp: 1753098827160 +- conda: https://prefix.dev/conda-forge/osx-arm64/cxx-compiler-1.11.0-h88570a1_0.conda + sha256: 99800d97a3a2ee9920dfc697b6d4c64e46dc7296c78b1b6c746ff1c24dea5e6c + md5: 043afed05ca5a0f2c18252ae4378bdee + depends: + - c-compiler 1.11.0 h61f9b84_0 + - clangxx_osx-arm64 19.* license: BSD-3-Clause - size: 6784 - timestamp: 1751115541888 -- conda: https://prefix.dev/conda-forge/win-64/cxx-compiler-1.10.0-h1c1089f_0.conda - sha256: 123ef5fd4829b7c78d49df141bbdf6120fc63a17538b2209d56a6f4dc5eccf21 - md5: 1c4dad99c85e243e25828c6f12f28e0d + license_family: BSD + size: 6715 + timestamp: 1753098739952 +- conda: https://prefix.dev/conda-forge/win-64/cxx-compiler-1.11.0-h1c1089f_0.conda + sha256: c888f4fe9ec117c1c01bfaa4c722ca475ebbb341c92d1718afa088bb0d710619 + md5: 4d94d3c01add44dc9d24359edf447507 depends: - vs2022_win-64 license: BSD-3-Clause - size: 6987 - timestamp: 1751115642859 + license_family: BSD + size: 6957 + timestamp: 1753098809481 - conda: https://prefix.dev/conda-forge/noarch/distlib-0.3.9-pyhd8ed1ab_1.conda sha256: 0e160c21776bd881b79ce70053e59736f51036784fa43a50da10a04f0c1b9c45 md5: 8d88f4a2242e6b96f9ecff9a6a05b2f1 @@ -1130,122 +1146,124 @@ packages: license: Unlicense size: 17544 timestamp: 1737517924333 -- conda: https://prefix.dev/conda-forge/linux-64/fortran-compiler-1.10.0-h36df796_0.conda - sha256: 451852c7f5ef20344e966bdfd8dfe26021819257fe37a019d4e2655b1c5f6057 - md5: e2d49a61c0ebc4ee2c7779d940f2f3e7 +- conda: https://prefix.dev/conda-forge/linux-64/fortran-compiler-1.11.0-h9bea470_0.conda + sha256: 53e5562ede83b478ebe9f4fc3d3b4eff5b627883f48aa0bf412e8fd90b5d6113 + md5: d5596f445a1273ddc5ea68864c01b69f depends: - binutils - - c-compiler 1.10.0 h2b85faf_0 + - c-compiler 1.11.0 h4d9bdce_0 - gfortran - - gfortran_linux-64 13.* + - gfortran_linux-64 14.* license: BSD-3-Clause - size: 6650 - timestamp: 1751115555592 -- conda: https://prefix.dev/conda-forge/linux-64/gcc-13.3.0-h9576a4e_2.conda - sha256: 300f077029e7626d69cc250a69acd6018c1fced3f5bf76adf37854f3370d2c45 - md5: d92e51bf4b6bdbfe45e5884fb0755afe - depends: - - gcc_impl_linux-64 13.3.0.* + license_family: BSD + size: 6656 + timestamp: 1753098722318 +- conda: https://prefix.dev/conda-forge/linux-64/gcc-14.3.0-he448592_3.conda + sha256: 0eab90b25d866d5106ad0ca14ebde427c0d0e1920c61449e1c4ce7a1657d913a + md5: cbcad61e1c13b5724cb58863f126333e + depends: + - conda-gcc-specs + - gcc_impl_linux-64 14.3.0.* license: BSD-3-Clause license_family: BSD - size: 55246 - timestamp: 1740240578937 -- conda: https://prefix.dev/conda-forge/linux-64/gcc_impl_linux-64-13.3.0-h1e990d8_2.conda - sha256: c3e9f243ea8292eecad78bb200d8f5b590e0f82bf7e7452a3a7c8df4eea6f774 - md5: f46cf0acdcb6019397d37df1e407ab91 + size: 30858 + timestamp: 1750808690439 +- conda: https://prefix.dev/conda-forge/linux-64/gcc_impl_linux-64-14.3.0-hd9e9e21_3.conda + sha256: 0047d4da9f48b731a089d70b60a21031b809791089170f163d6660512676ebd9 + md5: 12a6a74cab2878a284f9af96f3e1a1e8 depends: - binutils_impl_linux-64 >=2.40 - - libgcc >=13.3.0 - - libgcc-devel_linux-64 13.3.0 hc03c837_102 - - libgomp >=13.3.0 - - libsanitizer 13.3.0 he8ea267_2 - - libstdcxx >=13.3.0 + - libgcc >=14.3.0 + - libgcc-devel_linux-64 14.3.0 h85bb3a7_103 + - libgomp >=14.3.0 + - libsanitizer 14.3.0 hd08acf3_3 + - libstdcxx >=14.3.0 - sysroot_linux-64 license: GPL-3.0-only WITH GCC-exception-3.1 license_family: GPL - size: 66770653 - timestamp: 1740240400031 -- conda: https://prefix.dev/conda-forge/linux-64/gcc_linux-64-13.3.0-h6f18a23_11.conda - sha256: b2533388ec510ef0fc95774f15fdfb89582623049494506ea27622333f90bc09 - md5: 639ef869618e311eee4888fcb40747e2 + size: 71226373 + timestamp: 1750808482839 +- conda: https://prefix.dev/conda-forge/linux-64/gcc_linux-64-14.3.0-h1382650_11.conda + sha256: 0d7fe52c578ef99f03defe8cab5308124b388c694e88f5494716d11532a6d12a + md5: 2e650506e6371ac4289c9bf7fc207f3b depends: - binutils_linux-64 - - gcc_impl_linux-64 13.3.0.* + - gcc_impl_linux-64 14.3.0.* - sysroot_linux-64 license: BSD-3-Clause license_family: BSD - size: 32538 - timestamp: 1748905867619 -- conda: https://prefix.dev/conda-forge/linux-64/gfortran-13.3.0-h9576a4e_2.conda - sha256: 9425741d57bbcf918fe98cb375508f31de0daa655f3cebe100a43cf7cb46ec39 - md5: 19e6d3c9cde10a0a9a170a684082588e - depends: - - gcc 13.3.0.* - - gcc_impl_linux-64 13.3.0.* - - gfortran_impl_linux-64 13.3.0.* + size: 32512 + timestamp: 1748905876846 +- conda: https://prefix.dev/conda-forge/linux-64/gfortran-14.3.0-he448592_3.conda + sha256: f4c9035cf8983dc0127e3a667dceaf302e0a875626d58ffad193f2177db19c37 + md5: 2c3bdb97d37bce8ffbf98dde5f4166f7 + depends: + - gcc 14.3.0.* + - gcc_impl_linux-64 14.3.0.* + - gfortran_impl_linux-64 14.3.0.* license: BSD-3-Clause license_family: BSD - size: 54740 - timestamp: 1740240701423 -- conda: https://prefix.dev/conda-forge/linux-64/gfortran_impl_linux-64-13.3.0-h84c1745_2.conda - sha256: 03a45f58b41909d4189fb81ec7f971b60aaccf95a3953049d93ae7d06eb19000 - md5: 4e21ed177b76537067736f20f54fee0a - depends: - - gcc_impl_linux-64 >=13.3.0 - - libgcc >=13.3.0 - - libgfortran5 >=13.3.0 - - libstdcxx >=13.3.0 + size: 30294 + timestamp: 1750808700785 +- conda: https://prefix.dev/conda-forge/linux-64/gfortran_impl_linux-64-14.3.0-h7db7018_3.conda + sha256: 4f68996404d623a0fd093ffb62896b69e06bbc4f4a46f5f1659599572cc91172 + md5: 20d3edd920a9c2395663e4d39e2b3802 + depends: + - gcc_impl_linux-64 >=14.3.0 + - libgcc >=14.3.0 + - libgfortran5 >=14.3.0 + - libstdcxx >=14.3.0 - sysroot_linux-64 license: GPL-3.0-only WITH GCC-exception-3.1 license_family: GPL - size: 15923784 - timestamp: 1740240635243 -- conda: https://prefix.dev/conda-forge/linux-64/gfortran_linux-64-13.3.0-h1917dac_11.conda - sha256: e51bcd274ca1ff67b4f32cd772317f43a7f43dad1f8c07d400b4918a9f88b006 - md5: 85b2fa3c287710011199f5da1bac5b43 + size: 17275951 + timestamp: 1750808631416 +- conda: https://prefix.dev/conda-forge/linux-64/gfortran_linux-64-14.3.0-h30a37f7_11.conda + sha256: 4075b0d224adbe0ec7f71586b80805d15d86164eab754851a1515e069b0aa222 + md5: 8caf7dd31e00bfdd2b00cc672ea6fa33 depends: - binutils_linux-64 - - gcc_linux-64 13.3.0 h6f18a23_11 - - gfortran_impl_linux-64 13.3.0.* + - gcc_linux-64 14.3.0 h1382650_11 + - gfortran_impl_linux-64 14.3.0.* - sysroot_linux-64 license: BSD-3-Clause license_family: BSD - size: 30896 - timestamp: 1748905884078 -- conda: https://prefix.dev/conda-forge/linux-64/gxx-13.3.0-h9576a4e_2.conda - sha256: fa9d0171c17e4c4203a4199fcc35571a25c1f16c0ad992080d4f0ced53bf5aa5 - md5: 07e8df00b7cd3084ad3ef598ce32a71c - depends: - - gcc 13.3.0.* - - gxx_impl_linux-64 13.3.0.* + size: 30838 + timestamp: 1748905893216 +- conda: https://prefix.dev/conda-forge/linux-64/gxx-14.3.0-he448592_3.conda + sha256: 270d78236cd2a1e0cc42f722807508631b7d13d4165751911c38cf390f26db5e + md5: f4075be80543f21ffed9592b2a3150e3 + depends: + - gcc 14.3.0.* + - gxx_impl_linux-64 14.3.0.* license: BSD-3-Clause license_family: BSD - size: 54718 - timestamp: 1740240712365 -- conda: https://prefix.dev/conda-forge/linux-64/gxx_impl_linux-64-13.3.0-hae580e1_2.conda - sha256: 7cb36526a5c3e75ae07452aee5c9b6219f62fad9f85cc6d1dab5b21d1c4cc996 - md5: b55f02540605c322a47719029f8404cc - depends: - - gcc_impl_linux-64 13.3.0 h1e990d8_2 - - libstdcxx-devel_linux-64 13.3.0 hc03c837_102 + size: 30277 + timestamp: 1750808711942 +- conda: https://prefix.dev/conda-forge/linux-64/gxx_impl_linux-64-14.3.0-he663afc_3.conda + sha256: 2d6923f30622fcba78cb85687d9cd54df77d4d25e4dba8687bb712eb8bfd4d9b + md5: bb5fcb5c14e9e4b0304a63ced52e41bb + depends: + - gcc_impl_linux-64 14.3.0 hd9e9e21_3 + - libstdcxx-devel_linux-64 14.3.0 h85bb3a7_103 - sysroot_linux-64 - tzdata license: GPL-3.0-only WITH GCC-exception-3.1 license_family: GPL - size: 13362974 - timestamp: 1740240672045 -- conda: https://prefix.dev/conda-forge/linux-64/gxx_linux-64-13.3.0-hb14504d_11.conda - sha256: dda6a2765249c40168defea26aa67ff37d4d9fd214fb6e8d4fe0f434033bef87 - md5: 2ca7575e4f2da39c5ee260e022ab1a6f + size: 14731173 + timestamp: 1750808663844 +- conda: https://prefix.dev/conda-forge/linux-64/gxx_linux-64-14.3.0-ha7acb78_11.conda + sha256: 6c06752e4773dfd61a1928e9f7e9d21c3b97068daf27b84696c33057a091fe27 + md5: d4af016b3511135302a19f2a58544fcd depends: - binutils_linux-64 - - gcc_linux-64 13.3.0 h6f18a23_11 - - gxx_impl_linux-64 13.3.0.* + - gcc_linux-64 14.3.0 h1382650_11 + - gxx_impl_linux-64 14.3.0.* - sysroot_linux-64 license: BSD-3-Clause license_family: BSD - size: 30844 - timestamp: 1748905886442 + size: 30802 + timestamp: 1748905895571 - conda: https://prefix.dev/conda-forge/linux-64/icu-75.1-he02047a_0.conda sha256: 71e750d509f5fa3421087ba88ef9a7b9be11c53174af3aa4d06aff4c18b38e8e md5: 8b189310083baabfb622af68fd9d3ae3 @@ -1257,6 +1275,15 @@ packages: license_family: MIT size: 12129203 timestamp: 1720853576813 +- conda: https://prefix.dev/conda-forge/osx-64/icu-75.1-h120a0e1_0.conda + sha256: 2e64307532f482a0929412976c8450c719d558ba20c0962832132fd0d07ba7a7 + md5: d68d48a3060eb5abdc1cdc8e2a3a5966 + depends: + - __osx >=10.13 + license: MIT + license_family: MIT + size: 11761697 + timestamp: 1720853679409 - conda: https://prefix.dev/conda-forge/osx-arm64/icu-75.1-hfee45f7_0.conda sha256: 9ba12c93406f3df5ab0a43db8a4b4ef67a5871dfd401010fbe29b218b2cbe620 md5: 5eb22c1d7b3fc4abb50d92d621583137 @@ -1331,68 +1358,68 @@ packages: license_family: MIT size: 1195575 timestamp: 1692098070699 -- conda: https://prefix.dev/conda-forge/osx-64/ld64-951.9-h4e51db5_6.conda - sha256: e40a618bfa56eba6f18bc30ec45e5b63797e5be0c64b632a09e13853b216ed8c - md5: 45bf526d53b1bc95bc0b932a91a41576 +- conda: https://prefix.dev/conda-forge/osx-64/ld64-954.16-hc3792c1_1.conda + sha256: ef7703f6497bec3b697146b79152168289bcb1def0092231c1ea9e583ab00ea1 + md5: 6f0c87894e26b71fc87972b5c023ce36 depends: - - ld64_osx-64 951.9 h33512f0_6 - - libllvm18 >=18.1.8,<18.2.0a0 + - ld64_osx-64 954.16 hf1c22e8_1 + - libllvm19 >=19.1.7,<19.2.0a0 constrains: - - cctools_osx-64 1010.6.* - - cctools 1010.6.* + - cctools 1021.4.* + - cctools_osx-64 1021.4.* license: APSL-2.0 license_family: Other - size: 19401 - timestamp: 1743872196322 -- conda: https://prefix.dev/conda-forge/osx-arm64/ld64-951.9-h4c6efb1_6.conda - sha256: 2c796872c89dee18c8455bd5e4d7dcc6c4f8544c873856d12a64585ac60e315f - md5: f756d0a0ffba157687a29077f3408016 - depends: - - ld64_osx-arm64 951.9 hb6b49e2_6 - - libllvm18 >=18.1.8,<18.2.0a0 + size: 18915 + timestamp: 1752907763574 +- conda: https://prefix.dev/conda-forge/osx-arm64/ld64-954.16-he86490a_1.conda + sha256: 378a5a356a505df676dbda84ce5e635c0e774a64547428a260d4ee874184b31e + md5: d811f6f0b3cf0ae1c9035062385f3f7d + depends: + - ld64_osx-arm64 954.16 hc42d924_1 + - libllvm19 >=19.1.7,<19.2.0a0 constrains: - - cctools 1010.6.* - - cctools_osx-arm64 1010.6.* + - cctools 1021.4.* + - cctools_osx-arm64 1021.4.* license: APSL-2.0 license_family: Other - size: 19446 - timestamp: 1743872353403 -- conda: https://prefix.dev/conda-forge/osx-64/ld64_osx-64-951.9-h33512f0_6.conda - sha256: e048342a05e77440f355c46a47871dc71d9d8884a4bf73dedf1a16c84aabb834 - md5: 6cd120f5c9dae65b858e1fad2b7959a0 + size: 18956 + timestamp: 1752907637806 +- conda: https://prefix.dev/conda-forge/osx-64/ld64_osx-64-954.16-hf1c22e8_1.conda + sha256: 2b9264aa7349023f9d0b8bc14fed4d72f50bf1d6651c90bb6786cd02f18ed77c + md5: c58dd9842c39dc9269124f2eb716d70c depends: - __osx >=10.13 - libcxx - - libllvm18 >=18.1.8,<18.2.0a0 + - libllvm19 >=19.1.7,<19.2.0a0 - sigtool - tapi >=1300.6.5,<1301.0a0 constrains: - - cctools_osx-64 1010.6.* - - ld 951.9.* - - clang >=18.1.8,<19.0a0 - - cctools 1010.6.* + - ld 954.16.* + - cctools 1021.4.* + - cctools_osx-64 1021.4.* + - clang >=19.1.7,<20.0a0 license: APSL-2.0 license_family: Other - size: 1099095 - timestamp: 1743872136626 -- conda: https://prefix.dev/conda-forge/osx-arm64/ld64_osx-arm64-951.9-hb6b49e2_6.conda - sha256: 5ab2c15358d0ebfe26bafd2f768f524962f1a785c81d42518afb4f5d397e83f9 - md5: 61743b006633f5e1f9aa9e707f44fcb1 + size: 1094401 + timestamp: 1752907681528 +- conda: https://prefix.dev/conda-forge/osx-arm64/ld64_osx-arm64-954.16-hc42d924_1.conda + sha256: 26c724309bd33da834f244fa0f0313fb3c3142f460ab35b5301fdf599455e0b3 + md5: 002c036f577b8f79993648a56e05a86c depends: - __osx >=11.0 - libcxx - - libllvm18 >=18.1.8,<18.2.0a0 + - libllvm19 >=19.1.7,<19.2.0a0 - sigtool - tapi >=1300.6.5,<1301.0a0 constrains: - - ld 951.9.* - - clang >=18.1.8,<19.0a0 - - cctools_osx-arm64 1010.6.* - - cctools 1010.6.* + - cctools 1021.4.* + - ld 954.16.* + - cctools_osx-arm64 1021.4.* + - clang >=19.1.7,<20.0a0 license: APSL-2.0 license_family: Other - size: 1022641 - timestamp: 1743872275249 + size: 1023767 + timestamp: 1752907577001 - conda: https://prefix.dev/conda-forge/linux-64/ld_impl_linux-64-2.43-h712a8e2_4.conda sha256: db73f38155d901a610b2320525b9dd3b31e4949215c870685fd92ea61b5ce472 md5: 01f8d123c96816249efd255a31ad7712 @@ -1416,28 +1443,28 @@ packages: license_family: Apache size: 19270692 timestamp: 1738271687132 -- conda: https://prefix.dev/conda-forge/osx-64/libclang-cpp18.1-18.1.8-default_h3571c67_10.conda - sha256: f30dd87230aadda44f566b79782a61fbf7214e0099741c822045cc91d085e0ce - md5: bf6753267e6f848f369c5bc2373dddd6 +- conda: https://prefix.dev/conda-forge/osx-64/libclang-cpp19.1-19.1.7-default_h3571c67_3.conda + sha256: 527a96d48122dfd99e955dd73077f52a0e0bbec7eea08bbe4dc2ba12c1905b37 + md5: 2ec1f70656609b17b438ac07e1b2b611 depends: - __osx >=10.13 - - libcxx >=18.1.8 - - libllvm18 >=18.1.8,<18.2.0a0 + - libcxx >=19.1.7 + - libllvm19 >=19.1.7,<19.2.0a0 license: Apache-2.0 WITH LLVM-exception license_family: Apache - size: 13907371 - timestamp: 1747763588968 -- conda: https://prefix.dev/conda-forge/osx-arm64/libclang-cpp18.1-18.1.8-default_hf90f093_10.conda - sha256: c1eee43ffc0c229bd222a3a56e99c5d6689ed0402cb69c1f5ea2f96e18e5d984 - md5: af31a578be7de7b05a067a57f2d059e5 + size: 14708000 + timestamp: 1747709593789 +- conda: https://prefix.dev/conda-forge/osx-arm64/libclang-cpp19.1-19.1.7-default_hf90f093_3.conda + sha256: 581014d18bb6a9c2c7b46ca932b338b54b351bd8e9ccfd5ad665fd2d9810b8d0 + md5: 560546d163a6622b494ce92204e67540 depends: - __osx >=11.0 - - libcxx >=18.1.8 - - libllvm18 >=18.1.8,<18.2.0a0 + - libcxx >=19.1.7 + - libllvm19 >=19.1.7,<19.2.0a0 license: Apache-2.0 WITH LLVM-exception license_family: Apache - size: 13330110 - timestamp: 1747714807051 + size: 14084825 + timestamp: 1747709563086 - conda: https://prefix.dev/conda-forge/linux-64/libcurl-8.8.0-hca28451_0.conda sha256: 45aec0ffc6fe3fd4c0083b815aa102b8103380acc2b6714fb272d921acc68ab2 md5: f21c27f076a07907e70c49bb57bd0f20 @@ -1499,24 +1526,24 @@ packages: license_family: Apache size: 523505 timestamp: 1736877862502 -- conda: https://prefix.dev/conda-forge/osx-64/libcxx-devel-18.1.8-h7c275be_8.conda - sha256: cb3cce2b312aa1fb7391672807001bbab4d6e2deb16d912caecf6219f58ee1f4 - md5: a9513c41f070a9e2d5c370ba5d6c0c00 +- conda: https://prefix.dev/conda-forge/osx-64/libcxx-devel-19.1.7-h7c275be_1.conda + sha256: d1ee08b0614d8f9bca84aa91b4015c5efa96162fd865590a126544243699dfc6 + md5: 0f3f15e69e98ce9b3307c1d8309d1659 depends: - - libcxx >=18.1.8 + - libcxx >=19.1.7 license: Apache-2.0 WITH LLVM-exception license_family: Apache - size: 794361 - timestamp: 1742451346844 -- conda: https://prefix.dev/conda-forge/osx-arm64/libcxx-devel-18.1.8-h6dc3340_8.conda - sha256: ff83d001603476033eca155ce77f7ba614d9dc70c5811e2ce9915a3cadacb56f - md5: fdf0850d6d1496f33e3996e377f605ed + size: 826706 + timestamp: 1742451299167 +- conda: https://prefix.dev/conda-forge/osx-arm64/libcxx-devel-19.1.7-h6dc3340_1.conda + sha256: 6dd08a65b8ef162b058dc931aba3bdb6274ba5f05b6c86fbd0c23f2eafc7cc47 + md5: 1399af81db60d441e7c6577307d5cf82 depends: - - libcxx >=18.1.8 + - libcxx >=19.1.7 license: Apache-2.0 WITH LLVM-exception license_family: Apache - size: 794791 - timestamp: 1742451369695 + size: 825628 + timestamp: 1742451285589 - conda: https://prefix.dev/conda-forge/linux-64/libedit-3.1.20250104-pl5321h7949ede_0.conda sha256: d789471216e7aba3c184cd054ed61ce3f6dac6f87a50ec69291b9297f8c18724 md5: c277e0a4d549b03ac1e9d6cbbe3d017b @@ -1671,6 +1698,19 @@ packages: license_family: GPL size: 847885 timestamp: 1740240653082 +- conda: https://prefix.dev/conda-forge/linux-64/libgcc-15.1.0-h767d61c_3.conda + sha256: 59a87161212abe8acc57d318b0cc8636eb834cdfdfddcf1f588b5493644b39a3 + md5: 9e60c55e725c20d23125a5f0dd69af5d + depends: + - __glibc >=2.17,<3.0.a0 + - _openmp_mutex >=4.5 + constrains: + - libgcc-ng ==15.1.0=*_3 + - libgomp 15.1.0 h767d61c_3 + license: GPL-3.0-only WITH GCC-exception-3.1 + license_family: GPL + size: 824921 + timestamp: 1750808216066 - conda: https://prefix.dev/conda-forge/win-64/libgcc-14.2.0-h1383e82_2.conda sha256: fddf2fc037bc95adb3b369e8866da8a71b6a67ebcfc4d7035ac4208309dc9e72 md5: 4a74c1461a0ba47a3346c04bdccbe2ad @@ -1685,15 +1725,15 @@ packages: license_family: GPL size: 666343 timestamp: 1740240717807 -- conda: https://prefix.dev/conda-forge/noarch/libgcc-devel_linux-64-13.3.0-hc03c837_102.conda - sha256: 538544a2e0651bfeb0348ca6469b6b608606f6080a0b5a531af3a3852fec0215 - md5: 4c1d6961a6a54f602ae510d9bf31fa60 +- conda: https://prefix.dev/conda-forge/noarch/libgcc-devel_linux-64-14.3.0-h85bb3a7_103.conda + sha256: 81d51ff07d3faf3daf99a8a3f0e49e8289c94dec7d6ed4c7d28eebeb5d3b7f1a + md5: fc4911352ac0969aa171031fa4ba29d0 depends: - __unix license: GPL-3.0-only WITH GCC-exception-3.1 license_family: GPL - size: 2597400 - timestamp: 1740240211859 + size: 2725528 + timestamp: 1750808302968 - conda: https://prefix.dev/conda-forge/linux-64/libgcc-ng-14.2.0-h69a702a_2.conda sha256: fb7558c328b38b2f9d2e412c48da7890e7721ba018d733ebdfea57280df01904 md5: a2222a6ada71fb478682efe483ce0f92 @@ -1703,18 +1743,27 @@ packages: license_family: GPL size: 53758 timestamp: 1740240660904 -- conda: https://prefix.dev/conda-forge/linux-64/libgfortran5-14.2.0-hf1ad2bd_2.conda - sha256: c17b7cf3073a1f4e1f34d50872934fa326346e104d3c445abc1e62481ad6085c - md5: 556a4fdfac7287d349b8f09aba899693 +- conda: https://prefix.dev/conda-forge/linux-64/libgcc-ng-15.1.0-h69a702a_3.conda + sha256: b0b0a5ee6ce645a09578fc1cb70c180723346f8a45fdb6d23b3520591c6d6996 + md5: e66f2b8ad787e7beb0f846e4bd7e8493 + depends: + - libgcc 15.1.0 h767d61c_3 + license: GPL-3.0-only WITH GCC-exception-3.1 + license_family: GPL + size: 29033 + timestamp: 1750808224854 +- conda: https://prefix.dev/conda-forge/linux-64/libgfortran5-15.1.0-hcea5267_3.conda + sha256: eea6c3cf22ad739c279b4d665e6cf20f8081f483b26a96ddd67d4df3c88dfa0a + md5: 530566b68c3b8ce7eec4cd047eae19fe depends: - __glibc >=2.17,<3.0.a0 - - libgcc >=14.2.0 + - libgcc >=15.1.0 constrains: - - libgfortran 14.2.0 + - libgfortran 15.1.0 license: GPL-3.0-only WITH GCC-exception-3.1 license_family: GPL - size: 1461978 - timestamp: 1740240671964 + size: 1565627 + timestamp: 1750808236464 - conda: https://prefix.dev/conda-forge/osx-arm64/libglib-2.82.2-hdff4504_1.conda sha256: d002aeaa51424e331f8504a54b6ba4388a6011a0ebcac29296f3d14282bf733b md5: 849da57c370384ce48bef2e050488882 @@ -1756,6 +1805,15 @@ packages: license_family: GPL size: 459862 timestamp: 1740240588123 +- conda: https://prefix.dev/conda-forge/linux-64/libgomp-15.1.0-h767d61c_3.conda + sha256: 43710ab4de0cd7ff8467abff8d11e7bb0e36569df04ce1c099d48601818f11d1 + md5: 3cd1a7238a0dd3d0860fdefc496cc854 + depends: + - __glibc >=2.17,<3.0.a0 + license: GPL-3.0-only WITH GCC-exception-3.1 + license_family: GPL + size: 447068 + timestamp: 1750808138400 - conda: https://prefix.dev/conda-forge/win-64/libgomp-14.2.0-h1383e82_2.conda sha256: 674ec5f1bf319eac98d0d6ecb9c38e0192f3cf41969a5621d62a7e695e1aa9f3 md5: dd6b1ab49e28bcb6154cd131acec985b @@ -1845,32 +1903,32 @@ packages: license_family: Apache size: 38299762 timestamp: 1737843272034 -- conda: https://prefix.dev/conda-forge/osx-64/libllvm18-18.1.8-default_h3571c67_5.conda - sha256: 6ea08f3343727d171981be54e92117bea0da4199f227efe47c605e0ee345cf33 - md5: 01dd8559b569ad39b64fef0a61ded1e9 +- conda: https://prefix.dev/conda-forge/osx-64/libllvm19-19.1.7-hc29ff6c_1.conda + sha256: 2b9aa347ea26e911b925aca1e96ac595f9ceacbd6ab2d7b15fbdd42b90f6a9a3 + md5: a937150d07aa51b50ded6a0816df4a5a depends: - __osx >=10.13 - libcxx >=18 - - libxml2 >=2.14.0,<2.15.0a0 + - libxml2 >=2.13.5,<2.14.0a0 - libzlib >=1.3.1,<2.0a0 - - zstd >=1.5.7,<1.6.0a0 + - zstd >=1.5.6,<1.6.0a0 license: Apache-2.0 WITH LLVM-exception license_family: Apache - size: 27768928 - timestamp: 1743989832901 -- conda: https://prefix.dev/conda-forge/osx-arm64/libllvm18-18.1.8-default_hb458b26_5.conda - sha256: fbc2dd45ef620fd6282a5ad6a25260df921760d717ac727bf62e7702279ec9cc - md5: ce107cf167da0a1abbccc0c8f979ef59 + size: 28848197 + timestamp: 1737782191240 +- conda: https://prefix.dev/conda-forge/osx-arm64/libllvm19-19.1.7-hc4b4ae8_1.conda + sha256: 5a1d3e7505e8ce6055c3aa361ae660916122089a80abfb009d8d4c49238a7ea4 + md5: 020aeb16fc952ac441852d8eba2cf2fd depends: - __osx >=11.0 - libcxx >=18 - - libxml2 >=2.14.0,<2.15.0a0 + - libxml2 >=2.13.5,<2.14.0a0 - libzlib >=1.3.1,<2.0a0 - - zstd >=1.5.7,<1.6.0a0 + - zstd >=1.5.6,<1.6.0a0 license: Apache-2.0 WITH LLVM-exception license_family: Apache - size: 25982718 - timestamp: 1743989933062 + size: 27012197 + timestamp: 1737781370567 - conda: https://prefix.dev/conda-forge/linux-64/liblzma-5.6.4-hb9d3cd8_0.conda sha256: cad52e10319ca4585bc37f0bc7cce99ec7c15dc9168e42ccb96b741b0a27db3f md5: 42d5b6a0f30d3c10cd88cb8584fda1cb @@ -1988,17 +2046,17 @@ packages: license_family: GPL size: 33408 timestamp: 1697359010159 -- conda: https://prefix.dev/conda-forge/linux-64/libsanitizer-13.3.0-he8ea267_2.conda - sha256: 27c4c8bf8e2dd60182d47274389be7c70446df6ed5344206266321ee749158b4 - md5: 2b6cdf7bb95d3d10ef4e38ce0bc95dba +- conda: https://prefix.dev/conda-forge/linux-64/libsanitizer-14.3.0-hd08acf3_3.conda + sha256: b9c75b534d3e6e6beec48e316fac44592126be861def4d0d161dbb0b9adcaf68 + md5: 66f4c3def354c5a6dd0c830db7341fa7 depends: - __glibc >=2.17,<3.0.a0 - - libgcc >=13.3.0 - - libstdcxx >=13.3.0 + - libgcc >=14.3.0 + - libstdcxx >=14.3.0 license: GPL-3.0-only WITH GCC-exception-3.1 license_family: GPL - size: 4155341 - timestamp: 1740240344242 + size: 5072646 + timestamp: 1750808425881 - conda: https://prefix.dev/conda-forge/linux-64/libsqlite-3.49.1-hee588c1_1.conda sha256: 7a09eef804ef7cf4d88215c2297eabb72af8ad0bd5b012060111c289f14bbe7d md5: 73cea06049cc4174578b432320a003b8 @@ -2078,24 +2136,34 @@ packages: license_family: GPL size: 3884556 timestamp: 1740240685253 -- conda: https://prefix.dev/conda-forge/noarch/libstdcxx-devel_linux-64-13.3.0-hc03c837_102.conda - sha256: abc89056d4ca7debe938504b3b6d9ccc6d7a0f0b528fe3409230636a21e81002 - md5: aa38de2738c5f4a72a880e3d31ffe8b4 +- conda: https://prefix.dev/conda-forge/linux-64/libstdcxx-15.1.0-h8f9b012_3.conda + sha256: 7650837344b7850b62fdba02155da0b159cf472b9ab59eb7b472f7bd01dff241 + md5: 6d11a5edae89fe413c0569f16d308f5a + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc 15.1.0 h767d61c_3 + license: GPL-3.0-only WITH GCC-exception-3.1 + license_family: GPL + size: 3896407 + timestamp: 1750808251302 +- conda: https://prefix.dev/conda-forge/noarch/libstdcxx-devel_linux-64-14.3.0-h85bb3a7_103.conda + sha256: 0a2a6298beb7225bb850011241b5be9dbeef52e5942d74c592f577b16c38334f + md5: 8f310e4b92c1b1ec1bd3ee16931c149f depends: - __unix license: GPL-3.0-only WITH GCC-exception-3.1 license_family: GPL - size: 12873130 - timestamp: 1740240239655 -- conda: https://prefix.dev/conda-forge/linux-64/libstdcxx-ng-14.2.0-h4852527_2.conda - sha256: e86f38b007cf97cc2c67cd519f2de12a313c4ee3f5ef11652ad08932a5e34189 - md5: c75da67f045c2627f59e6fcb5f4e3a9b + size: 14063448 + timestamp: 1750808328742 +- conda: https://prefix.dev/conda-forge/linux-64/libstdcxx-ng-15.1.0-h4852527_3.conda + sha256: bbaea1ecf973a7836f92b8ebecc94d3c758414f4de39d2cc6818a3d10cb3216b + md5: 57541755b5a51691955012b8e197c06c depends: - - libstdcxx 14.2.0 h8f9b012_2 + - libstdcxx 15.1.0 h8f9b012_3 license: GPL-3.0-only WITH GCC-exception-3.1 license_family: GPL - size: 53830 - timestamp: 1740240722530 + size: 29093 + timestamp: 1750808292700 - conda: https://prefix.dev/conda-forge/linux-64/libuuid-2.38.1-h0b41bf4_0.conda sha256: 787eb542f055a2b3de553614b25f09eefb0a0931b0c87dbcce6efdfd92f04f18 md5: 40b61aab5c7ba9ff276c41cfffe6b80b @@ -2166,23 +2234,22 @@ packages: license_family: MIT size: 690296 timestamp: 1739952967309 -- conda: https://prefix.dev/conda-forge/osx-64/libxml2-2.14.0-he8ee3e7_0.conda - sha256: 778e742422656a69a86d75f95da7d18bb4238caec86ed2da41c17ef98e8d3ed9 - md5: 6684bede5bc812bd7f5e80e5bac581f2 +- conda: https://prefix.dev/conda-forge/osx-64/libxml2-2.13.7-hebb159f_0.conda + sha256: 21119df0a2267a9fc52d67bdf55e5449a2cdcc799865e2f90ab734fd61234ed8 + md5: 45786cf4067df4fbe9faf3d1c25d3acf depends: - __osx >=10.13 + - icu >=75.1,<76.0a0 - libiconv >=1.18,<2.0a0 - liblzma >=5.6.4,<6.0a0 - libzlib >=1.3.1,<2.0a0 - constrains: - - icu <0.0a0 license: MIT license_family: MIT - size: 591674 - timestamp: 1743771237588 -- conda: https://prefix.dev/conda-forge/osx-arm64/libxml2-2.14.0-h178c5d8_0.conda - sha256: efee42564a8b3e5077d805f9aa6779aededa4f773b33d5baa9132dbb91d6372e - md5: 724823cce387493f5c8ad42206a06019 + size: 609769 + timestamp: 1743091248758 +- conda: https://prefix.dev/conda-forge/osx-arm64/libxml2-2.13.7-h178c5d8_0.conda + sha256: d3ddc9ae8a5474f16f213ca41b3eda394e1eb1253f3ac85d3c6c99adcfb226d8 + md5: aa838a099ba09429cb80cc876b032ac4 depends: - __osx >=11.0 - icu >=75.1,<76.0a0 @@ -2191,8 +2258,8 @@ packages: - libzlib >=1.3.1,<2.0a0 license: MIT license_family: MIT - size: 565240 - timestamp: 1743771370341 + size: 582736 + timestamp: 1743091513375 - conda: https://prefix.dev/conda-forge/linux-64/libzlib-1.3.1-hb9d3cd8_2.conda sha256: d4bfe88d7cb447768e31650f06257995601f89076080e76df55e3112d4e47dc4 md5: edb0dca6bc32e4f4789199455a1dbeb8 @@ -2262,70 +2329,64 @@ packages: license_family: APACHE size: 280830 timestamp: 1736986295869 -- conda: https://prefix.dev/conda-forge/osx-64/llvm-tools-18.1.8-default_h3571c67_5.conda - sha256: 084f1504b38608542f6ff816f9ff7e7ae9ec38b454604144e8ac0d0ec0415f82 - md5: cc07ff74d2547da1f1452c42b67bafd6 +- conda: https://prefix.dev/conda-forge/osx-64/llvm-tools-19.1.7-h3fe3016_1.conda + sha256: 473bc7c6edba8a19e17774545e5b582a7097fcadf0ed8ae16c5b39df955e248a + md5: 9275202e21af00428e7cc23d28b2d2ca depends: - __osx >=10.13 - - libllvm18 18.1.8 default_h3571c67_5 - - libxml2 >=2.14.0,<2.15.0a0 - - libzlib >=1.3.1,<2.0a0 - - llvm-tools-18 18.1.8 default_h3571c67_5 - - zstd >=1.5.7,<1.6.0a0 + - libllvm19 19.1.7 hc29ff6c_1 + - llvm-tools-19 19.1.7 he90a8e3_1 constrains: - - llvm 18.1.8 - - clang-tools 18.1.8 - - llvmdev 18.1.8 - - clang 18.1.8 + - llvmdev 19.1.7 + - clang 19.1.7 + - clang-tools 19.1.7 + - llvm 19.1.7 license: Apache-2.0 WITH LLVM-exception license_family: Apache - size: 92923 - timestamp: 1743990036185 -- conda: https://prefix.dev/conda-forge/osx-arm64/llvm-tools-18.1.8-default_hb458b26_5.conda - sha256: caa3f3fcc12b84e815a431706634eb850f05eaafc073ca1216e3fd87ec93134c - md5: 704b3d78d5cd327f3ce1372d07be01fd + size: 87412 + timestamp: 1737782713306 +- conda: https://prefix.dev/conda-forge/osx-arm64/llvm-tools-19.1.7-hd2aecb6_1.conda + sha256: 0537eb46cd766bdae85cbdfc4dfb3a4d70a85c6c088a33722104bbed78256eca + md5: b79a1a40211c67a3ae5dbd0cb36604d2 depends: - __osx >=11.0 - - libllvm18 18.1.8 default_hb458b26_5 - - libxml2 >=2.14.0,<2.15.0a0 - - libzlib >=1.3.1,<2.0a0 - - llvm-tools-18 18.1.8 default_hb458b26_5 - - zstd >=1.5.7,<1.6.0a0 + - libllvm19 19.1.7 hc4b4ae8_1 + - llvm-tools-19 19.1.7 h87a4c7e_1 constrains: - - llvm 18.1.8 - - llvmdev 18.1.8 - - clang-tools 18.1.8 - - clang 18.1.8 + - clang-tools 19.1.7 + - clang 19.1.7 + - llvm 19.1.7 + - llvmdev 19.1.7 license: Apache-2.0 WITH LLVM-exception license_family: Apache - size: 92544 - timestamp: 1743990114058 -- conda: https://prefix.dev/conda-forge/osx-64/llvm-tools-18-18.1.8-default_h3571c67_5.conda - sha256: 80e64944776325ebf5c30d3bd588bb29768c589418286ddfb277818a32161128 - md5: 4391981e855468ced32ca1940b3d7613 + size: 87945 + timestamp: 1737781780073 +- conda: https://prefix.dev/conda-forge/osx-64/llvm-tools-19-19.1.7-he90a8e3_1.conda + sha256: f61ff471024bdf1964c06b30dd46d44f6bc2d1af3c1d924a3448cd2e0ce611c6 + md5: eb6f2bb07f6409f943ee12fabd23bea7 depends: - __osx >=10.13 - - libllvm18 18.1.8 default_h3571c67_5 - - libxml2 >=2.14.0,<2.15.0a0 + - libcxx >=18 + - libllvm19 19.1.7 hc29ff6c_1 - libzlib >=1.3.1,<2.0a0 - - zstd >=1.5.7,<1.6.0a0 + - zstd >=1.5.6,<1.6.0a0 license: Apache-2.0 WITH LLVM-exception license_family: Apache - size: 25076183 - timestamp: 1743989960006 -- conda: https://prefix.dev/conda-forge/osx-arm64/llvm-tools-18-18.1.8-default_hb458b26_5.conda - sha256: 5e12079d864b5ab523cb18e3b9f37dd4764d67a2dfc4450b49b3ad8ebd9cd4d8 - md5: c8734b82ae16cf86b7f74140f09f9121 + size: 17631684 + timestamp: 1737782657331 +- conda: https://prefix.dev/conda-forge/osx-arm64/llvm-tools-19-19.1.7-h87a4c7e_1.conda + sha256: 74588508746622baae1bb9c6a69ef571af68dfc7af2bd09546aff26ab3d31764 + md5: ebaf5f56104cdb0481fda2a6069f85bf depends: - __osx >=11.0 - - libllvm18 18.1.8 default_hb458b26_5 - - libxml2 >=2.14.0,<2.15.0a0 + - libcxx >=18 + - libllvm19 19.1.7 hc4b4ae8_1 - libzlib >=1.3.1,<2.0a0 - - zstd >=1.5.7,<1.6.0a0 + - zstd >=1.5.6,<1.6.0a0 license: Apache-2.0 WITH LLVM-exception license_family: Apache - size: 23239573 - timestamp: 1743990043950 + size: 16079459 + timestamp: 1737781718971 - conda: https://prefix.dev/conda-forge/linux-64/make-4.4.1-hb9d3cd8_2.conda sha256: d652c7bd4d3b6f82b0f6d063b0d8df6f54cc47531092d7ff008e780f3261bdda md5: 33405d2a66b1411db9f7242c8b97c9e7 diff --git a/pixi.toml b/pixi.toml index 12e1737ac3..4cc98575c2 100644 --- a/pixi.toml +++ b/pixi.toml @@ -23,7 +23,7 @@ rattler = "cargo run --bin rattler --release --" doc = "RUSTDOCFLAGS='-Dwarnings -Wunreachable-pub' cargo doc --no-deps --all --all-features" [dependencies] -cxx-compiler = "~=1.10.0" +cxx-compiler = "~=1.11.0" openssl = "~=3.1" make = "~=4.3" pkg-config = "~=0.29.2" diff --git a/py-rattler/Cargo.lock b/py-rattler/Cargo.lock index ad8ed6328b..2ef70192ea 100644 --- a/py-rattler/Cargo.lock +++ b/py-rattler/Cargo.lock @@ -1129,19 +1129,6 @@ version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e57e3272f0190c3f1584272d613719ba5fc7df7f4942fe542e63d949cf3a649b" -[[package]] -name = "console" -version = "0.15.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "054ccb5b10f9f2cbf51eb355ca1d05c2d279ce1804688d0db74b4733a5aeafd8" -dependencies = [ - "encode_unicode", - "libc", - "once_cell", - "unicode-width", - "windows-sys 0.59.0", -] - [[package]] name = "console" version = "0.16.0" @@ -1721,7 +1708,7 @@ dependencies = [ [[package]] name = "file_url" -version = "0.2.5" +version = "0.2.6" dependencies = [ "itertools 0.14.0", "percent-encoding", @@ -2007,9 +1994,9 @@ dependencies = [ [[package]] name = "google-cloud-auth" -version = "0.21.0" +version = "0.22.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a65fb515e1e726bc58b925fc876e8f02b626ab574b15c8f3fa53cb08177a7815" +checksum = "290a18c1cc7c02934c1b88920af8b55ff588ff2ef47f35dae5fc1f10f2056538" dependencies = [ "async-trait", "base64 0.22.1", @@ -2017,6 +2004,7 @@ dependencies = [ "google-cloud-gax", "http 1.3.1", "reqwest", + "rustc_version", "rustls 0.23.29", "rustls-pemfile 2.2.0", "serde", @@ -2596,7 +2584,7 @@ version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "70a646d946d06bedbbc4cac4c218acf4bbf2d87757a784857025f4d447e4e1cd" dependencies = [ - "console 0.16.0", + "console", "portable-atomic", "unicode-width", "unit-prefix", @@ -3143,12 +3131,11 @@ checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad" [[package]] name = "opendal" -version = "0.53.3" +version = "0.54.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f947c4efbca344c1a125753366033c8107f552b2e3f8251815ed1908f116ca3e" +checksum = "ffb9838d0575c6dbaf3fcec7255af8d5771996d4af900bbb6fa9a314dec00a1a" dependencies = [ "anyhow", - "async-trait", "backon", "base64 0.22.1", "bytes", @@ -3313,7 +3300,7 @@ checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" [[package]] name = "path_resolver" -version = "0.1.1" +version = "0.1.2" dependencies = [ "fs-err", "indexmap 2.10.0", @@ -3366,12 +3353,14 @@ checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "petgraph" -version = "0.7.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3672b37090dbd86368a4145bc067582552b29c27377cad4e0a306c97f9bd7772" +checksum = "54acf3a685220b533e437e264e4d932cfbdc4cc7ec0cd232ed73c08d03b8a7ca" dependencies = [ "fixedbitset", + "hashbrown 0.15.4", "indexmap 2.10.0", + "serde", ] [[package]] @@ -3900,10 +3889,10 @@ dependencies = [ [[package]] name = "rattler" -version = "0.34.7" +version = "0.34.11" dependencies = [ "anyhow", - "console 0.15.11", + "console", "digest", "dirs", "fs-err", @@ -3942,7 +3931,7 @@ dependencies = [ [[package]] name = "rattler_cache" -version = "0.3.26" +version = "0.3.29" dependencies = [ "anyhow", "dashmap", @@ -3958,6 +3947,7 @@ dependencies = [ "rattler_digest", "rattler_networking", "rattler_package_streaming", + "rattler_redaction", "rayon", "reqwest", "reqwest-middleware", @@ -3972,7 +3962,7 @@ dependencies = [ [[package]] name = "rattler_conda_types" -version = "0.35.6" +version = "0.37.0" dependencies = [ "chrono", "core-foundation 0.10.1", @@ -4010,9 +4000,9 @@ dependencies = [ [[package]] name = "rattler_config" -version = "0.2.3" +version = "0.2.5" dependencies = [ - "console 0.15.11", + "console", "fs-err", "indexmap 2.10.0", "rattler_conda_types", @@ -4026,7 +4016,7 @@ dependencies = [ [[package]] name = "rattler_digest" -version = "1.1.4" +version = "1.1.5" dependencies = [ "blake2", "digest", @@ -4042,14 +4032,14 @@ dependencies = [ [[package]] name = "rattler_index" -version = "0.24.4" +version = "0.24.7" dependencies = [ "anyhow", "bytes", "chrono", "clap", "clap-verbosity-flag", - "console 0.15.11", + "console", "fs-err", "futures", "fxhash", @@ -4075,7 +4065,7 @@ dependencies = [ [[package]] name = "rattler_lock" -version = "0.23.11" +version = "0.23.13" dependencies = [ "chrono", "file_url", @@ -4107,7 +4097,7 @@ dependencies = [ [[package]] name = "rattler_menuinst" -version = "0.2.17" +version = "0.2.20" dependencies = [ "chrono", "configparser", @@ -4135,7 +4125,7 @@ dependencies = [ [[package]] name = "rattler_networking" -version = "0.25.6" +version = "0.25.8" dependencies = [ "anyhow", "async-trait", @@ -4163,7 +4153,7 @@ dependencies = [ [[package]] name = "rattler_package_streaming" -version = "0.22.45" +version = "0.22.48" dependencies = [ "bzip2", "chrono", @@ -4191,7 +4181,7 @@ dependencies = [ [[package]] name = "rattler_pty" -version = "0.2.4" +version = "0.2.6" dependencies = [ "libc", "nix 0.30.1", @@ -4209,7 +4199,7 @@ dependencies = [ [[package]] name = "rattler_repodata_gateway" -version = "0.23.7" +version = "0.23.10" dependencies = [ "anyhow", "async-compression", @@ -4265,7 +4255,7 @@ dependencies = [ [[package]] name = "rattler_shell" -version = "0.24.4" +version = "0.24.7" dependencies = [ "anyhow", "enum_dispatch", @@ -4283,7 +4273,7 @@ dependencies = [ [[package]] name = "rattler_solve" -version = "2.1.6" +version = "2.1.8" dependencies = [ "chrono", "futures", @@ -4299,7 +4289,7 @@ dependencies = [ [[package]] name = "rattler_virtual_packages" -version = "2.0.19" +version = "2.1.1" dependencies = [ "archspec", "libloading", @@ -4531,9 +4521,9 @@ dependencies = [ [[package]] name = "resolvo" -version = "0.9.1" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dba027c8e5dd4b5e5a690cfcfb3900d5ffe6985adb048cbd111d5aa596a6c0c8" +checksum = "037a5f3f35329f29885132d030c628f3142d2a098d0abb30513c572b900692fd" dependencies = [ "ahash", "bitvec", @@ -4968,9 +4958,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.141" +version = "1.0.142" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30b9eff21ebe718216c6ec64e1d9ac57087aad11efc64e32002bce4a0d4c03d3" +checksum = "030fedb782600dcbd6f02d479bf0d817ac3bb40d644745b769d6a96bc3afc5a7" dependencies = [ "indexmap 2.10.0", "itoa", From a665c0965cbbc057536c8f2e87212c328d2865de Mon Sep 17 00:00:00 2001 From: Bas Zalmstra <4995967+baszalmstra@users.noreply.github.com> Date: Mon, 11 Aug 2025 13:44:51 +0200 Subject: [PATCH 10/11] fix: formatting --- crates/rattler_solve/src/resolvo/mod.rs | 24 +++++------------------- 1 file changed, 5 insertions(+), 19 deletions(-) diff --git a/crates/rattler_solve/src/resolvo/mod.rs b/crates/rattler_solve/src/resolvo/mod.rs index 0a2bbab960..787d22c603 100644 --- a/crates/rattler_solve/src/resolvo/mod.rs +++ b/crates/rattler_solve/src/resolvo/mod.rs @@ -290,11 +290,7 @@ impl<'a> CondaDependencyProvider<'a> { let name = pool.intern_package_name(&virtual_package.name); let solvable = pool.intern_solvable(name, SolverPackageRecord::VirtualPackage(virtual_package)); - records - .entry(name) - .or_default() - .candidates - .push(solvable); + records.entry(name).or_default().candidates.push(solvable); } // Compute the direct dependencies @@ -388,9 +384,7 @@ impl<'a> CondaDependencyProvider<'a> { pool.intern_solvable(package_name, SolverPackageRecord::Record(record)); // Update records with all entries in a single mutable borrow - let candidates = records - .entry(package_name) - .or_default(); + let candidates = records.entry(package_name).or_default(); candidates.candidates.push(solvable_id); // Filter out any records that are newer than a specific date. @@ -484,11 +478,7 @@ impl<'a> CondaDependencyProvider<'a> { for favored_record in favored_records { let name = pool.intern_package_name(&favored_record.package_record.name); let solvable = pool.intern_solvable(name, SolverPackageRecord::Record(favored_record)); - let candidates = records - .entry( - name - ) - .or_default(); + let candidates = records.entry(name).or_default(); candidates.candidates.push(solvable); candidates.favored = Some(solvable); } @@ -496,9 +486,7 @@ impl<'a> CondaDependencyProvider<'a> { for locked_record in locked_records { let name = pool.intern_package_name(&locked_record.package_record.name); let solvable = pool.intern_solvable(name, SolverPackageRecord::Record(locked_record)); - let candidates = records - .entry(name) - .or_default(); + let candidates = records.entry(name).or_default(); candidates.candidates.push(solvable); candidates.locked = Some(solvable); } @@ -522,9 +510,7 @@ impl<'a> CondaDependencyProvider<'a> { /// Returns all package names pub fn package_names(&self) -> impl Iterator + use<'_, 'a> { - self.records - .keys() - .copied() + self.records.keys().copied() } fn extra_condition(&self, package: &PackageName, extra: &str) -> ConditionId { From f2c96a99a3c2a8046821461c03c62be800cb9f70 Mon Sep 17 00:00:00 2001 From: Bas Zalmstra <4995967+baszalmstra@users.noreply.github.com> Date: Mon, 11 Aug 2025 13:48:18 +0200 Subject: [PATCH 11/11] bump resolvo --- Cargo.lock | 4 ++-- py-rattler/Cargo.lock | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5179d688f8..ba9af29361 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5180,9 +5180,9 @@ dependencies = [ [[package]] name = "resolvo" -version = "0.10.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "037a5f3f35329f29885132d030c628f3142d2a098d0abb30513c572b900692fd" +checksum = "670175f9a825ad2419bea0e14bfe74e5dcc0227ec7a652a655b1c11e2b911754" dependencies = [ "ahash", "bitvec", diff --git a/py-rattler/Cargo.lock b/py-rattler/Cargo.lock index 2ef70192ea..b99d576b53 100644 --- a/py-rattler/Cargo.lock +++ b/py-rattler/Cargo.lock @@ -4521,9 +4521,9 @@ dependencies = [ [[package]] name = "resolvo" -version = "0.10.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "037a5f3f35329f29885132d030c628f3142d2a098d0abb30513c572b900692fd" +checksum = "670175f9a825ad2419bea0e14bfe74e5dcc0227ec7a652a655b1c11e2b911754" dependencies = [ "ahash", "bitvec",