From be5374d0f7b0efa789216ce02b3dcadfd943b266 Mon Sep 17 00:00:00 2001 From: Wolf Vollprecht Date: Tue, 9 Jan 2024 19:43:18 +0100 Subject: [PATCH 1/3] make rip handle pre-releases more similar to pip --- .../src/resolve/dependency_provider.rs | 30 +++++++++++++------ .../src/resolve/solve.rs | 19 ++++++++++++ 2 files changed, 40 insertions(+), 9 deletions(-) diff --git a/crates/rattler_installs_packages/src/resolve/dependency_provider.rs b/crates/rattler_installs_packages/src/resolve/dependency_provider.rs index d9f53dfc..d5d6d1f2 100644 --- a/crates/rattler_installs_packages/src/resolve/dependency_provider.rs +++ b/crates/rattler_installs_packages/src/resolve/dependency_provider.rs @@ -1,3 +1,4 @@ +use super::solve::PreReleaseResolution; use super::SDistResolution; use crate::artifacts::SDist; use crate::artifacts::Wheel; @@ -172,20 +173,31 @@ impl<'db, 'i> PypiDependencyProvider<'db, 'i> { return Err("there are no packages available"); } - let mut artifacts = artifacts - .iter() - .filter(|a| a.filename.version().pre.is_none() && a.filename.version().dev.is_none()) - .collect::>(); + let mut artifacts = artifacts.iter().collect::>(); + // Filter yanked artifacts + artifacts.retain(|a| !a.yanked.yanked); if artifacts.is_empty() { - // Skip all prereleases - return Err("prereleases are not allowed"); + return Err("it is yanked"); + } + + let is_pre = |a: &ArtifactInfo| { + a.filename.version().pre.is_some() || a.filename.version().dev.is_some() + }; + // Filter based on pre-release resolution + match self.options.pre_release_resolution { + PreReleaseResolution::Disallow => artifacts.retain(|a| !is_pre(a)), + PreReleaseResolution::AllowIfNoOtherVersions + if !artifacts.iter().all(|a| is_pre(a)) => + { + artifacts.retain(|a| !is_pre(a)) + } + _ => {} } - // Filter yanked artifacts - artifacts.retain(|a| !a.yanked.yanked); if artifacts.is_empty() { - return Err("it is yanked"); + // Skip all prereleases + return Err("prereleases are not allowed"); } // This should keep only the wheels diff --git a/crates/rattler_installs_packages/src/resolve/solve.rs b/crates/rattler_installs_packages/src/resolve/solve.rs index c23abb4d..10357388 100644 --- a/crates/rattler_installs_packages/src/resolve/solve.rs +++ b/crates/rattler_installs_packages/src/resolve/solve.rs @@ -126,6 +126,21 @@ pub enum SDistResolution { OnlySDists, } +/// Defines how to pre-releases are handled during package resolution. +#[derive(Default, Debug, Clone, Copy, Eq, PartialOrd, PartialEq)] +pub enum PreReleaseResolution { + /// Don't allow pre-releases to be selected during resolution + Disallow, + + /// Allow pre-releases to be selected during resolution but only if there are no other versions + /// available (default) + #[default] + AllowIfNoOtherVersions, + + /// Allow pre-releases to be selected during resolution + Allow, +} + impl SDistResolution { /// Returns true if sdists are allowed to be selected during resolution pub fn allow_sdists(&self) -> bool { @@ -150,6 +165,10 @@ pub struct ResolveOptions { /// Defines what python interpreter to use for resolution. By default the python interpreter /// from the system is used. This is only used during resolution and building of wheel files pub python_location: PythonLocation, + + /// Defines whether pre-releases are allowed to be selected during resolution. By default + /// pre-releases are not allowed (only if there are no other versions available for a given dependency). + pub pre_release_resolution: PreReleaseResolution, } /// Resolves an environment that contains the given requirements and all dependencies of those From 4513f39f88e8717847d46c2a7d19932018fe701b Mon Sep 17 00:00:00 2001 From: Wolf Vollprecht Date: Tue, 9 Jan 2024 20:09:42 +0100 Subject: [PATCH 2/3] add cli flag and debug --- .../src/resolve/dependency_provider.rs | 10 ++++++++++ crates/rattler_installs_packages/src/resolve/mod.rs | 2 +- crates/rip_bin/src/main.rs | 12 ++++++++++++ 3 files changed, 23 insertions(+), 1 deletion(-) diff --git a/crates/rattler_installs_packages/src/resolve/dependency_provider.rs b/crates/rattler_installs_packages/src/resolve/dependency_provider.rs index d5d6d1f2..24d3f982 100644 --- a/crates/rattler_installs_packages/src/resolve/dependency_provider.rs +++ b/crates/rattler_installs_packages/src/resolve/dependency_provider.rs @@ -184,12 +184,22 @@ impl<'db, 'i> PypiDependencyProvider<'db, 'i> { let is_pre = |a: &ArtifactInfo| { a.filename.version().pre.is_some() || a.filename.version().dev.is_some() }; + + if artifacts.iter().all(|a| is_pre(a)) { + // Skip all prereleases + println!("All are pre-releases: "); + for artifact in artifacts.iter() { + println!("{}", artifact.filename); + } + } + // Filter based on pre-release resolution match self.options.pre_release_resolution { PreReleaseResolution::Disallow => artifacts.retain(|a| !is_pre(a)), PreReleaseResolution::AllowIfNoOtherVersions if !artifacts.iter().all(|a| is_pre(a)) => { + // println!("Removing prereleases because there are no other versions"); artifacts.retain(|a| !is_pre(a)) } _ => {} diff --git a/crates/rattler_installs_packages/src/resolve/mod.rs b/crates/rattler_installs_packages/src/resolve/mod.rs index c8f8d974..10f9d0da 100644 --- a/crates/rattler_installs_packages/src/resolve/mod.rs +++ b/crates/rattler_installs_packages/src/resolve/mod.rs @@ -11,4 +11,4 @@ mod dependency_provider; mod solve; -pub use solve::{resolve, PinnedPackage, ResolveOptions, SDistResolution}; +pub use solve::{resolve, PinnedPackage, ResolveOptions, SDistResolution, PreReleaseResolution}; diff --git a/crates/rip_bin/src/main.rs b/crates/rip_bin/src/main.rs index 8d0b4b26..6cd63f01 100644 --- a/crates/rip_bin/src/main.rs +++ b/crates/rip_bin/src/main.rs @@ -1,3 +1,4 @@ +use rattler_installs_packages::resolve::PreReleaseResolution; use rip_bin::{global_multi_progress, IndicatifWriter}; use std::collections::HashMap; use std::io::Write; @@ -40,6 +41,10 @@ struct Args { #[clap(flatten)] sdist_resolution: SDistResolution, + + /// Prefer pre-releases over normal releases + #[clap(long)] + pre: bool, } #[derive(Parser)] @@ -128,8 +133,15 @@ async fn actual_main() -> miette::Result<()> { compatible_tags.tags().format(", ") ); + let pre_release_resolution = if args.pre { + PreReleaseResolution::Allow + } else { + PreReleaseResolution::AllowIfNoOtherVersions + }; + let resolve_opts = ResolveOptions { sdist_resolution: args.sdist_resolution.into(), + pre_release_resolution, ..Default::default() }; // Solve the environment From 5d175d1243bde6e17e1fdb684c87b7e363c70d72 Mon Sep 17 00:00:00 2001 From: Wolf Vollprecht Date: Wed, 10 Jan 2024 09:15:06 +0100 Subject: [PATCH 3/3] refactor pre-release stuff slightly --- .../src/resolve/dependency_provider.rs | 37 ++++++++----------- .../src/resolve/mod.rs | 2 +- 2 files changed, 17 insertions(+), 22 deletions(-) diff --git a/crates/rattler_installs_packages/src/resolve/dependency_provider.rs b/crates/rattler_installs_packages/src/resolve/dependency_provider.rs index 24d3f982..a7304553 100644 --- a/crates/rattler_installs_packages/src/resolve/dependency_provider.rs +++ b/crates/rattler_installs_packages/src/resolve/dependency_provider.rs @@ -166,6 +166,7 @@ impl<'db, 'i> PypiDependencyProvider<'db, 'i> { fn filter_candidates<'a>( &self, artifacts: &'a [ArtifactInfo], + all_pre_release: bool, ) -> Result, &'static str> { // Filter only artifacts we can work with if artifacts.is_empty() { @@ -181,28 +182,17 @@ impl<'db, 'i> PypiDependencyProvider<'db, 'i> { return Err("it is yanked"); } - let is_pre = |a: &ArtifactInfo| { - a.filename.version().pre.is_some() || a.filename.version().dev.is_some() + // Filter based on pre-release resolution + let remove_pre_releases = match self.options.pre_release_resolution { + PreReleaseResolution::Disallow => true, + PreReleaseResolution::AllowIfNoOtherVersions => !all_pre_release, + PreReleaseResolution::Allow => false, }; - if artifacts.iter().all(|a| is_pre(a)) { - // Skip all prereleases - println!("All are pre-releases: "); - for artifact in artifacts.iter() { - println!("{}", artifact.filename); - } - } - - // Filter based on pre-release resolution - match self.options.pre_release_resolution { - PreReleaseResolution::Disallow => artifacts.retain(|a| !is_pre(a)), - PreReleaseResolution::AllowIfNoOtherVersions - if !artifacts.iter().all(|a| is_pre(a)) => - { - // println!("Removing prereleases because there are no other versions"); - artifacts.retain(|a| !is_pre(a)) - } - _ => {} + if remove_pre_releases { + artifacts.retain(|a| { + a.filename.version().pre.is_none() && a.filename.version().dev.is_none() + }) } if artifacts.is_empty() { @@ -388,6 +378,11 @@ impl<'p> DependencyProvider let mut candidates = Candidates::default(); let locked_package = self.locked_packages.get(package_name.base()); let favored_package = self.favored_packages.get(package_name.base()); + + let all_pre_release = artifacts + .iter() + .all(|(version, _)| version.pre.is_some() || version.dev.is_some()); + for (version, artifacts) in artifacts.iter() { // Skip this version if a locked or favored version exists for this version. It will be // added below. @@ -404,7 +399,7 @@ impl<'p> DependencyProvider candidates.candidates.push(solvable_id); // Determine the candidates - match self.filter_candidates(artifacts) { + match self.filter_candidates(artifacts, all_pre_release) { Ok(artifacts) => { self.cached_artifacts.insert(solvable_id, artifacts); } diff --git a/crates/rattler_installs_packages/src/resolve/mod.rs b/crates/rattler_installs_packages/src/resolve/mod.rs index 10f9d0da..ff90cd6a 100644 --- a/crates/rattler_installs_packages/src/resolve/mod.rs +++ b/crates/rattler_installs_packages/src/resolve/mod.rs @@ -11,4 +11,4 @@ mod dependency_provider; mod solve; -pub use solve::{resolve, PinnedPackage, ResolveOptions, SDistResolution, PreReleaseResolution}; +pub use solve::{resolve, PinnedPackage, PreReleaseResolution, ResolveOptions, SDistResolution};