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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions crates/pixi_core/src/install_pypi/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -346,6 +346,7 @@ impl<'a> PyPIEnvironmentUpdater<'a> {
&site_packages,
CachedWheels::new(registry_index, built_wheel_index),
&required_dists,
&setup.build_options,
)
.into_diagnostic()
.context("error while determining PyPI installation plan")?;
Expand Down
48 changes: 46 additions & 2 deletions crates/pixi_core/src/install_pypi/plan/cache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,23 @@

use uv_cache::{CacheBucket, WheelCache};
use uv_cache_info::Timestamp;
use uv_configuration::BuildOptions;
use uv_distribution::{BuiltWheelIndex, RegistryWheelIndex};
use uv_distribution::{HttpArchivePointer, LocalArchivePointer};
use uv_distribution_types::BuiltDist;
use uv_distribution_types::{CachedDirectUrlDist, CachedDist, Dist, Name, SourceDist};
use uv_pypi_types::VerbatimParsedUrl;

#[derive(thiserror::Error, Debug)]
pub enum DistCacheError {
#[error("URL dependency points to a wheel which conflicts with `--no-binary` option: {url}")]
NoBinaryConflictUrl { url: String },
#[error("Path dependency points to a wheel which conflicts with `--no-binary` option: {path}")]
NoBinaryConflictPath { path: String },
#[error(transparent)]
Distribution(#[from] uv_distribution::Error),
}

/// Provides cache lookup functionality for distributions.
/// This trait can also be used to mock the cache for testing purposes.
pub trait DistCache<'a> {
Expand All @@ -24,7 +35,8 @@ pub trait DistCache<'a> {
&mut self,
dist: &'a Dist,
uv_cache: &uv_cache::Cache,
) -> Result<Option<CachedDist>, uv_distribution::Error>;
build_options: &BuildOptions,
) -> Result<Option<CachedDist>, DistCacheError>;
}

/// Provides both access to registry dists and locally built dists
Expand All @@ -44,13 +56,27 @@ impl<'a> DistCache<'a> for CachedWheels<'a> {
&mut self,
dist: &'a Dist,
uv_cache: &uv_cache::Cache,
) -> Result<Option<CachedDist>, uv_distribution::Error> {
build_options: &BuildOptions,
) -> Result<Option<CachedDist>, DistCacheError> {
// Check if installation of a binary version of the package should be allowed.
// we do not allow to set `no_binary` just yet but lets handle it here
// because, then this just works
let no_binary = build_options.no_binary_package(dist.name());
// We can set no-build
let no_build = build_options.no_build_package(dist.name());

match dist {
Dist::Built(BuiltDist::Registry(wheel)) => {
let cached = self.registry.get(wheel.name()).find_map(|entry| {
if entry.index.url() != &wheel.best_wheel().index {
return None;
}
if entry.built && no_build {
return None;
}
if !entry.built && no_binary {
return None;
}
if entry.dist.filename == wheel.best_wheel().filename {
Some(&entry.dist)
} else {
Expand All @@ -65,6 +91,12 @@ impl<'a> DistCache<'a> for CachedWheels<'a> {
}
}
Dist::Built(BuiltDist::DirectUrl(wheel)) => {
if no_binary {
return Err(DistCacheError::NoBinaryConflictUrl {
url: wheel.url.to_string(),
});
}

// Find the exact wheel from the cache, since we know the filename in advance.
let cache_entry = uv_cache
.shard(
Expand Down Expand Up @@ -101,6 +133,12 @@ impl<'a> DistCache<'a> for CachedWheels<'a> {
}
}
Dist::Built(BuiltDist::Path(wheel)) => {
if no_binary {
return Err(DistCacheError::NoBinaryConflictPath {
path: wheel.url.to_string(),
});
}

// Validate that the path exists.
if !wheel.install_path.exists() {
return Ok(None);
Expand Down Expand Up @@ -175,6 +213,12 @@ impl<'a> DistCache<'a> for CachedWheels<'a> {
if entry.dist.filename.name != *sdist.name() {
return None;
}
if entry.built && no_build {
return None;
}
if !entry.built && no_binary {
return None;
}
if entry.dist.filename.version == sdist.version {
Some(&entry.dist)
} else {
Expand Down
5 changes: 3 additions & 2 deletions crates/pixi_core/src/install_pypi/plan/installation_source.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,8 @@ pub fn decide_installation_source<'a>(
dist: &'a Dist,
dist_cache: &mut impl DistCache<'a>,
operation: Operation,
) -> Result<InstallationSources, uv_distribution::Error> {
build_options: &uv_configuration::BuildOptions,
) -> Result<InstallationSources, super::DistCacheError> {
let mut installation_sources = InstallationSources::new();
// First, check if we need to revalidate the package
// then we should get it from the remote
Expand All @@ -94,7 +95,7 @@ pub fn decide_installation_source<'a>(
}

// Check if the distribution is cached
match dist_cache.is_cached(dist, uv_cache)? {
match dist_cache.is_cached(dist, uv_cache, build_options)? {
Some(cached_dist) => {
installation_sources.add_cached(&cached_dist, operation.cached());
}
Expand Down
2 changes: 1 addition & 1 deletion crates/pixi_core/src/install_pypi/plan/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ mod reasons;
mod required_dists;
mod validation;

pub use cache::CachedWheels;
pub use cache::{CachedWheels, DistCacheError};
pub(crate) use models::NeedReinstall;
pub use models::PyPIInstallationPlan;
pub use planner::InstallPlanner;
Expand Down
6 changes: 6 additions & 0 deletions crates/pixi_core/src/install_pypi/plan/planner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use std::{
};

use super::{
cache::DistCacheError,
installation_source::{self, Operation},
validation::NeedsReinstallError,
};
Expand Down Expand Up @@ -46,6 +47,8 @@ pub enum InstallPlannerError {
UvConversion(#[from] pixi_uv_conversions::ConversionError),
#[error(transparent)]
RetrieveDistFromCache(#[from] uv_distribution::Error),
#[error(transparent)]
DistCache(#[from] DistCacheError),
}

impl InstallPlanner {
Expand Down Expand Up @@ -75,6 +78,7 @@ impl InstallPlanner {
site_packages: &'a Installed,
mut dist_cache: Cached,
required_dists: &'a RequiredDists,
build_options: &uv_configuration::BuildOptions,
) -> Result<PyPIInstallationPlan, InstallPlannerError> {
// Convert RequiredDists to the reference map for internal processing
let required_dists_map = required_dists.as_ref_map();
Expand Down Expand Up @@ -140,6 +144,7 @@ impl InstallPlanner {
required_dist,
&mut dist_cache,
Operation::Reinstall,
build_options,
)
.map_err(InstallPlannerError::from)?;

Expand All @@ -162,6 +167,7 @@ impl InstallPlanner {
dist,
&mut dist_cache,
Operation::Install,
build_options,
)
.map_err(InstallPlannerError::from)?;

Expand Down
6 changes: 4 additions & 2 deletions crates/pixi_core/src/install_pypi/plan/test/harness.rs
Original file line number Diff line number Diff line change
Expand Up @@ -406,7 +406,8 @@ impl<'a> DistCache<'a> for NoCache {
&mut self,
_dist: &'a uv_distribution_types::Dist,
_uv_cache: &uv_cache::Cache,
) -> Result<Option<uv_distribution_types::CachedDist>, uv_distribution::Error> {
_build_options: &uv_configuration::BuildOptions,
) -> Result<Option<uv_distribution_types::CachedDist>, super::super::DistCacheError> {
Ok(None)
}
}
Expand All @@ -418,7 +419,8 @@ impl<'a> DistCache<'a> for AllCached {
&mut self,
dist: &'a uv_distribution_types::Dist,
_uv_cache: &uv_cache::Cache,
) -> Result<Option<uv_distribution_types::CachedDist>, uv_distribution::Error> {
_build_options: &uv_configuration::BuildOptions,
) -> Result<Option<uv_distribution_types::CachedDist>, super::super::DistCacheError> {
match dist {
uv_distribution_types::Dist::Built(BuiltDist::Registry(wheel)) => {
let dist = CachedRegistryDist {
Expand Down
Loading
Loading