From 585abc6892c5d1a30b0c5e406138b9c92f03e7a7 Mon Sep 17 00:00:00 2001 From: Charlie Marsh Date: Wed, 13 Nov 2024 15:25:14 -0500 Subject: [PATCH] Defer reporting of build failures in resolver --- crates/uv-resolver/src/error.rs | 11 ++- crates/uv-resolver/src/lock/mod.rs | 2 +- crates/uv-resolver/src/resolver/mod.rs | 104 +++++++++++--------- crates/uv-resolver/src/resolver/provider.rs | 8 +- 4 files changed, 72 insertions(+), 53 deletions(-) diff --git a/crates/uv-resolver/src/error.rs b/crates/uv-resolver/src/error.rs index f3cbfbb9d953..87a9ab0f48dd 100644 --- a/crates/uv-resolver/src/error.rs +++ b/crates/uv-resolver/src/error.rs @@ -32,6 +32,9 @@ pub enum ResolveError { #[error(transparent)] Client(#[from] uv_client::Error), + #[error(transparent)] + Distribution(#[from] uv_distribution::Error), + #[error("The channel closed unexpectedly")] ChannelClosed, @@ -94,20 +97,20 @@ pub enum ResolveError { ParsedUrl(#[from] uv_pypi_types::ParsedUrlError), #[error("Failed to download `{0}`")] - Download(Box, #[source] uv_distribution::Error), + Download(Box, #[source] Arc), #[error("Failed to download and build `{0}`")] - DownloadAndBuild(Box, #[source] uv_distribution::Error), + DownloadAndBuild(Box, #[source] Arc), #[error("Failed to read `{0}`")] - Read(Box, #[source] uv_distribution::Error), + Read(Box, #[source] Arc), // TODO(zanieb): Use `thiserror` in `InstalledDist` so we can avoid chaining `anyhow` #[error("Failed to read metadata from installed package `{0}`")] ReadInstalled(Box, #[source] anyhow::Error), #[error("Failed to build `{0}`")] - Build(Box, #[source] uv_distribution::Error), + Build(Box, #[source] Arc), #[error(transparent)] NoSolution(#[from] NoSolutionError), diff --git a/crates/uv-resolver/src/lock/mod.rs b/crates/uv-resolver/src/lock/mod.rs index f1e65ff649c6..ac6756e5b54d 100644 --- a/crates/uv-resolver/src/lock/mod.rs +++ b/crates/uv-resolver/src/lock/mod.rs @@ -1241,7 +1241,7 @@ enum TagPolicy<'tags> { /// Exclusively consider wheels that match the specified platform tags. Required(&'tags Tags), /// Prefer wheels that match the specified platform tags, but fall back to incompatible wheels - /// if necessary. + /// if necessary. Preferred(&'tags Tags), } diff --git a/crates/uv-resolver/src/resolver/mod.rs b/crates/uv-resolver/src/resolver/mod.rs index 5b2d0998907c..2242e36f706d 100644 --- a/crates/uv-resolver/src/resolver/mod.rs +++ b/crates/uv-resolver/src/resolver/mod.rs @@ -945,6 +945,32 @@ impl ResolverState { unreachable!("`requires-python` is only known upfront for registry distributions") } + MetadataResponse::Error(dist, err) => { + return Err(match &**dist { + Dist::Built(built_dist @ BuiltDist::Path(_)) => { + ResolveError::Read(Box::new(built_dist.clone()), (*err).clone()) + } + Dist::Source(source_dist @ SourceDist::Path(_)) => { + ResolveError::Build(Box::new(source_dist.clone()), (*err).clone()) + } + Dist::Source(source_dist @ SourceDist::Directory(_)) => { + ResolveError::Build(Box::new(source_dist.clone()), (*err).clone()) + } + Dist::Built(built_dist) => { + ResolveError::Download(Box::new(built_dist.clone()), (*err).clone()) + } + Dist::Source(source_dist) => { + if source_dist.is_local() { + ResolveError::Build(Box::new(source_dist.clone()), (*err).clone()) + } else { + ResolveError::DownloadAndBuild( + Box::new(source_dist.clone()), + (*err).clone(), + ) + } + } + }); + } }; let version = &metadata.version; @@ -1331,6 +1357,35 @@ impl ResolverState { + return Err(match &**dist { + Dist::Built(built_dist @ BuiltDist::Path(_)) => { + ResolveError::Read(Box::new(built_dist.clone()), (*err).clone()) + } + Dist::Source(source_dist @ SourceDist::Path(_)) => { + ResolveError::Build(Box::new(source_dist.clone()), (*err).clone()) + } + Dist::Source(source_dist @ SourceDist::Directory(_)) => { + ResolveError::Build(Box::new(source_dist.clone()), (*err).clone()) + } + Dist::Built(built_dist) => { + ResolveError::Download(Box::new(built_dist.clone()), (*err).clone()) + } + Dist::Source(source_dist) => { + if source_dist.is_local() { + ResolveError::Build( + Box::new(source_dist.clone()), + (*err).clone(), + ) + } else { + ResolveError::DownloadAndBuild( + Box::new(source_dist.clone()), + (*err).clone(), + ) + } + } + }); + } }; if let Some(err) = @@ -1791,28 +1846,7 @@ impl ResolverState { - ResolveError::Read(Box::new(built_dist), err) - } - Dist::Source(source_dist @ SourceDist::Path(_)) => { - ResolveError::Build(Box::new(source_dist), err) - } - Dist::Source(source_dist @ SourceDist::Directory(_)) => { - ResolveError::Build(Box::new(source_dist), err) - } - Dist::Built(built_dist) => { - ResolveError::Download(Box::new(built_dist), err) - } - Dist::Source(source_dist) => { - if source_dist.is_local() { - ResolveError::Build(Box::new(source_dist), err) - } else { - ResolveError::DownloadAndBuild(Box::new(source_dist), err) - } - } - })?; + .await?; Ok(Some(Response::Dist { dist, metadata })) } @@ -1928,31 +1962,7 @@ impl ResolverState { - ResolveError::Read(Box::new(built_dist), err) - } - Dist::Source(source_dist @ SourceDist::Path(_)) => { - ResolveError::Build(Box::new(source_dist), err) - } - Dist::Source(source_dist @ SourceDist::Directory(_)) => { - ResolveError::Build(Box::new(source_dist), err) - } - Dist::Built(built_dist) => { - ResolveError::Download(Box::new(built_dist), err) - } - Dist::Source(source_dist) => { - if source_dist.is_local() { - ResolveError::Build(Box::new(source_dist), err) - } else { - ResolveError::DownloadAndBuild( - Box::new(source_dist), - err, - ) - } - } - })?; + .await?; Response::Dist { dist, metadata } } diff --git a/crates/uv-resolver/src/resolver/provider.rs b/crates/uv-resolver/src/resolver/provider.rs index c9f7c04a0957..b17ae7ff76f7 100644 --- a/crates/uv-resolver/src/resolver/provider.rs +++ b/crates/uv-resolver/src/resolver/provider.rs @@ -1,4 +1,5 @@ use std::future::Future; +use std::sync::Arc; use uv_configuration::BuildOptions; use uv_distribution::{ArchiveMetadata, DistributionDatabase}; @@ -46,6 +47,8 @@ pub enum MetadataResponse { /// The source distribution has a `requires-python` requirement that is not met by the installed /// Python version (and static metadata is not available). RequiresPython(VersionSpecifiers, Version), + /// The distribution could not be built or downloaded. + Error(Box, Arc), } pub trait ResolverProvider { @@ -210,7 +213,10 @@ impl<'a, Context: BuildContext> ResolverProvider for DefaultResolverProvider<'a, uv_distribution::Error::RequiresPython(requires_python, version) => { Ok(MetadataResponse::RequiresPython(requires_python, version)) } - err => Err(err), + err => Ok(MetadataResponse::Error( + Box::new(dist.clone()), + Arc::new(err), + )), }, } }