From c29afade8358c6bb7d4682e5faba84faaa709e86 Mon Sep 17 00:00:00 2001 From: Zanie Blue Date: Tue, 10 Dec 2024 22:17:57 -0600 Subject: [PATCH] Revert "Refactor unavailable metadata to shrink the resolver (#9769)" This reverts commit b751648bfef7712a53c9dc3bfdaaff084c01e76d. --- crates/uv-installer/src/site_packages.rs | 8 +- crates/uv-resolver/src/error.rs | 6 +- crates/uv-resolver/src/pubgrub/report.rs | 72 ++++++-- .../uv-resolver/src/resolver/availability.rs | 62 +++---- crates/uv-resolver/src/resolver/mod.rs | 166 ++++++++++++++---- crates/uv-resolver/src/resolver/provider.rs | 78 +++----- 6 files changed, 255 insertions(+), 137 deletions(-) diff --git a/crates/uv-installer/src/site_packages.rs b/crates/uv-installer/src/site_packages.rs index 065b81bf92d1..953e302a95e5 100644 --- a/crates/uv-installer/src/site_packages.rs +++ b/crates/uv-installer/src/site_packages.rs @@ -215,7 +215,7 @@ impl SitePackages { // Determine the dependencies for the given package. let Ok(metadata) = distribution.metadata() else { - diagnostics.push(SitePackagesDiagnostic::MetadataUnavailable { + diagnostics.push(SitePackagesDiagnostic::IncompletePackage { package: package.clone(), path: distribution.path().to_owned(), }); @@ -405,7 +405,7 @@ impl IntoIterator for SitePackages { #[derive(Debug)] pub enum SitePackagesDiagnostic { - MetadataUnavailable { + IncompletePackage { /// The package that is missing metadata. package: PackageName, /// The path to the package. @@ -445,7 +445,7 @@ impl Diagnostic for SitePackagesDiagnostic { /// Convert the diagnostic into a user-facing message. fn message(&self) -> String { match self { - Self::MetadataUnavailable { package, path } => format!( + Self::IncompletePackage { package, path } => format!( "The package `{package}` is broken or incomplete (unable to read `METADATA`). Consider recreating the virtualenv, or removing the package directory at: {}.", path.display(), ), Self::IncompatiblePythonVersion { @@ -482,7 +482,7 @@ impl Diagnostic for SitePackagesDiagnostic { /// Returns `true` if the [`PackageName`] is involved in this diagnostic. fn includes(&self, name: &PackageName) -> bool { match self { - Self::MetadataUnavailable { package, .. } => name == package, + Self::IncompletePackage { package, .. } => name == package, Self::IncompatiblePythonVersion { package, .. } => name == package, Self::MissingDependency { package, .. } => name == package, Self::IncompatibleDependency { diff --git a/crates/uv-resolver/src/error.rs b/crates/uv-resolver/src/error.rs index 027115b389d9..5c1da7aa4b0a 100644 --- a/crates/uv-resolver/src/error.rs +++ b/crates/uv-resolver/src/error.rs @@ -24,7 +24,7 @@ use crate::pubgrub::{PubGrubPackage, PubGrubPackageInner, PubGrubReportFormatter use crate::python_requirement::PythonRequirement; use crate::resolution::ConflictingDistributionError; use crate::resolver::{ - MetadataUnavailable, ResolverEnvironment, UnavailablePackage, UnavailableReason, + IncompletePackage, ResolverEnvironment, UnavailablePackage, UnavailableReason, }; use crate::Options; @@ -145,7 +145,7 @@ pub struct NoSolutionError { index_locations: IndexLocations, index_capabilities: IndexCapabilities, unavailable_packages: FxHashMap, - incomplete_packages: FxHashMap>, + incomplete_packages: FxHashMap>, fork_urls: ForkUrls, env: ResolverEnvironment, workspace_members: BTreeSet, @@ -163,7 +163,7 @@ impl NoSolutionError { index_locations: IndexLocations, index_capabilities: IndexCapabilities, unavailable_packages: FxHashMap, - incomplete_packages: FxHashMap>, + incomplete_packages: FxHashMap>, fork_urls: ForkUrls, env: ResolverEnvironment, workspace_members: BTreeSet, diff --git a/crates/uv-resolver/src/pubgrub/report.rs b/crates/uv-resolver/src/pubgrub/report.rs index 3e90c6ae85a8..a3f0358143da 100644 --- a/crates/uv-resolver/src/pubgrub/report.rs +++ b/crates/uv-resolver/src/pubgrub/report.rs @@ -18,7 +18,7 @@ use crate::error::ErrorTree; use crate::fork_urls::ForkUrls; use crate::prerelease::AllowPrerelease; use crate::python_requirement::{PythonRequirement, PythonRequirementSource}; -use crate::resolver::{MetadataUnavailable, UnavailablePackage, UnavailableReason}; +use crate::resolver::{IncompletePackage, UnavailablePackage, UnavailableReason}; use crate::{Flexibility, Options, RequiresPython, ResolverEnvironment}; use super::{PubGrubPackage, PubGrubPackageInner, PubGrubPython}; @@ -548,7 +548,7 @@ impl PubGrubReportFormatter<'_> { index_capabilities: &IndexCapabilities, available_indexes: &FxHashMap>, unavailable_packages: &FxHashMap, - incomplete_packages: &FxHashMap>, + incomplete_packages: &FxHashMap>, fork_urls: &ForkUrls, env: &ResolverEnvironment, workspace_members: &BTreeSet, @@ -679,7 +679,7 @@ impl PubGrubReportFormatter<'_> { index_capabilities: &IndexCapabilities, available_indexes: &FxHashMap>, unavailable_packages: &FxHashMap, - incomplete_packages: &FxHashMap>, + incomplete_packages: &FxHashMap>, hints: &mut IndexSet, ) { let no_find_links = index_locations.flat_indexes().peekable().peek().is_none(); @@ -694,6 +694,11 @@ impl PubGrubReportFormatter<'_> { Some(UnavailablePackage::Offline) => { hints.insert(PubGrubHint::Offline); } + Some(UnavailablePackage::MissingMetadata) => { + hints.insert(PubGrubHint::MissingPackageMetadata { + package: package.clone(), + }); + } Some(UnavailablePackage::InvalidMetadata(reason)) => { hints.insert(PubGrubHint::InvalidPackageMetadata { package: package.clone(), @@ -715,31 +720,37 @@ impl PubGrubReportFormatter<'_> { for (version, incomplete) in versions.iter().rev() { if set.contains(version) { match incomplete { - MetadataUnavailable::Offline => { + IncompletePackage::Offline => { hints.insert(PubGrubHint::Offline); } - MetadataUnavailable::InvalidMetadata(reason) => { + IncompletePackage::MissingMetadata => { + hints.insert(PubGrubHint::MissingVersionMetadata { + package: package.clone(), + version: version.clone(), + }); + } + IncompletePackage::InvalidMetadata(reason) => { hints.insert(PubGrubHint::InvalidVersionMetadata { package: package.clone(), version: version.clone(), - reason: reason.to_string(), + reason: reason.clone(), }); } - MetadataUnavailable::InconsistentMetadata(reason) => { + IncompletePackage::InconsistentMetadata(reason) => { hints.insert(PubGrubHint::InconsistentVersionMetadata { package: package.clone(), version: version.clone(), - reason: reason.to_string(), + reason: reason.clone(), }); } - MetadataUnavailable::InvalidStructure(reason) => { + IncompletePackage::InvalidStructure(reason) => { hints.insert(PubGrubHint::InvalidVersionStructure { package: package.clone(), version: version.clone(), - reason: reason.to_string(), + reason: reason.clone(), }); } - MetadataUnavailable::RequiresPython(requires_python, python_version) => { + IncompletePackage::RequiresPython(requires_python, python_version) => { hints.insert(PubGrubHint::IncompatibleBuildRequirement { package: package.clone(), version: version.clone(), @@ -871,6 +882,8 @@ pub(crate) enum PubGrubHint { NoIndex, /// A package was not found in the registry, but network access was disabled. Offline, + /// Metadata for a package could not be found. + MissingPackageMetadata { package: PubGrubPackage }, /// Metadata for a package could not be parsed. InvalidPackageMetadata { package: PubGrubPackage, @@ -883,6 +896,12 @@ pub(crate) enum PubGrubHint { // excluded from `PartialEq` and `Hash` reason: String, }, + /// Metadata for a package version could not be found. + MissingVersionMetadata { + package: PubGrubPackage, + // excluded from `PartialEq` and `Hash` + version: Version, + }, /// Metadata for a package version could not be parsed. InvalidVersionMetadata { package: PubGrubPackage, @@ -973,12 +992,18 @@ enum PubGrubHintCore { }, NoIndex, Offline, + MissingPackageMetadata { + package: PubGrubPackage, + }, InvalidPackageMetadata { package: PubGrubPackage, }, InvalidPackageStructure { package: PubGrubPackage, }, + MissingVersionMetadata { + package: PubGrubPackage, + }, InvalidVersionMetadata { package: PubGrubPackage, }, @@ -1027,12 +1052,18 @@ impl From for PubGrubHintCore { } PubGrubHint::NoIndex => Self::NoIndex, PubGrubHint::Offline => Self::Offline, + PubGrubHint::MissingPackageMetadata { package, .. } => { + Self::MissingPackageMetadata { package } + } PubGrubHint::InvalidPackageMetadata { package, .. } => { Self::InvalidPackageMetadata { package } } PubGrubHint::InvalidPackageStructure { package, .. } => { Self::InvalidPackageStructure { package } } + PubGrubHint::MissingVersionMetadata { package, .. } => { + Self::MissingVersionMetadata { package } + } PubGrubHint::InvalidVersionMetadata { package, .. } => { Self::InvalidVersionMetadata { package } } @@ -1131,6 +1162,15 @@ impl std::fmt::Display for PubGrubHint { ":".bold(), ) } + Self::MissingPackageMetadata { package } => { + write!( + f, + "{}{} Metadata for `{}` could not be found, as the wheel is missing a `METADATA` file", + "hint".bold().cyan(), + ":".bold(), + package.bold() + ) + } Self::InvalidPackageMetadata { package, reason } => { write!( f, @@ -1151,6 +1191,16 @@ impl std::fmt::Display for PubGrubHint { textwrap::indent(reason, " ") ) } + Self::MissingVersionMetadata { package, version } => { + write!( + f, + "{}{} Metadata for `{}` ({}) could not be found, as the wheel is missing a `METADATA` file", + "hint".bold().cyan(), + ":".bold(), + package.cyan(), + format!("v{version}").cyan(), + ) + } Self::InvalidVersionMetadata { package, version, diff --git a/crates/uv-resolver/src/resolver/availability.rs b/crates/uv-resolver/src/resolver/availability.rs index ba207056a7f2..c3e9067d9455 100644 --- a/crates/uv-resolver/src/resolver/availability.rs +++ b/crates/uv-resolver/src/resolver/availability.rs @@ -1,6 +1,5 @@ use std::fmt::{Display, Formatter}; -use crate::resolver::MetadataUnavailable; use uv_distribution_types::IncompatibleDist; use uv_pep440::{Version, VersionSpecifiers}; @@ -22,15 +21,17 @@ impl Display for UnavailableReason { } } -/// The package version is unavailable and cannot be used. Unlike [`MetadataUnavailable`], this +/// The package version is unavailable and cannot be used. Unlike [`PackageUnavailable`], this /// applies to a single version of the package. /// -/// Most variant are from [`MetadataResponse`] without the error source, since we don't format -/// the source and we want to merge unavailable messages across versions. +/// Most variant are from [`MetadataResponse`] without the error source (since we don't format +/// the source). #[derive(Debug, Clone, Eq, PartialEq)] pub(crate) enum UnavailableVersion { /// Version is incompatible because it has no usable distributions IncompatibleDist(IncompatibleDist), + /// The wheel metadata was not found. + MissingMetadata, /// The wheel metadata was found, but could not be parsed. InvalidMetadata, /// The wheel metadata was found, but the metadata was inconsistent. @@ -48,6 +49,7 @@ impl UnavailableVersion { pub(crate) fn message(&self) -> String { match self { UnavailableVersion::IncompatibleDist(invalid_dist) => format!("{invalid_dist}"), + UnavailableVersion::MissingMetadata => "not include a `METADATA` file".into(), UnavailableVersion::InvalidMetadata => "invalid metadata".into(), UnavailableVersion::InconsistentMetadata => "inconsistent metadata".into(), UnavailableVersion::InvalidStructure => "an invalid package format".into(), @@ -61,6 +63,7 @@ impl UnavailableVersion { pub(crate) fn singular_message(&self) -> String { match self { UnavailableVersion::IncompatibleDist(invalid_dist) => invalid_dist.singular_message(), + UnavailableVersion::MissingMetadata => format!("does {self}"), UnavailableVersion::InvalidMetadata => format!("has {self}"), UnavailableVersion::InconsistentMetadata => format!("has {self}"), UnavailableVersion::InvalidStructure => format!("has {self}"), @@ -72,6 +75,7 @@ impl UnavailableVersion { pub(crate) fn plural_message(&self) -> String { match self { UnavailableVersion::IncompatibleDist(invalid_dist) => invalid_dist.plural_message(), + UnavailableVersion::MissingMetadata => format!("do {self}"), UnavailableVersion::InvalidMetadata => format!("have {self}"), UnavailableVersion::InconsistentMetadata => format!("have {self}"), UnavailableVersion::InvalidStructure => format!("have {self}"), @@ -87,22 +91,6 @@ impl Display for UnavailableVersion { } } -impl From<&MetadataUnavailable> for UnavailableVersion { - fn from(reason: &MetadataUnavailable) -> Self { - match reason { - MetadataUnavailable::Offline => UnavailableVersion::Offline, - MetadataUnavailable::InvalidMetadata(_) => UnavailableVersion::InvalidMetadata, - MetadataUnavailable::InconsistentMetadata(_) => { - UnavailableVersion::InconsistentMetadata - } - MetadataUnavailable::InvalidStructure(_) => UnavailableVersion::InvalidStructure, - MetadataUnavailable::RequiresPython(requires_python, _python_version) => { - UnavailableVersion::RequiresPython(requires_python.clone()) - } - } - } -} - /// The package is unavailable and cannot be used. #[derive(Debug, Clone, Eq, PartialEq)] pub(crate) enum UnavailablePackage { @@ -112,6 +100,8 @@ pub(crate) enum UnavailablePackage { Offline, /// The package was not found in the registry. NotFound, + /// The package metadata was not found. + MissingMetadata, /// The package metadata was found, but could not be parsed. InvalidMetadata(String), /// The package has an invalid structure. @@ -124,6 +114,7 @@ impl UnavailablePackage { UnavailablePackage::NoIndex => "not found in the provided package locations", UnavailablePackage::Offline => "not found in the cache", UnavailablePackage::NotFound => "not found in the package registry", + UnavailablePackage::MissingMetadata => "not include a `METADATA` file", UnavailablePackage::InvalidMetadata(_) => "invalid metadata", UnavailablePackage::InvalidStructure(_) => "an invalid package format", } @@ -134,6 +125,7 @@ impl UnavailablePackage { UnavailablePackage::NoIndex => format!("was {self}"), UnavailablePackage::Offline => format!("was {self}"), UnavailablePackage::NotFound => format!("was {self}"), + UnavailablePackage::MissingMetadata => format!("does {self}"), UnavailablePackage::InvalidMetadata(_) => format!("has {self}"), UnavailablePackage::InvalidStructure(_) => format!("has {self}"), } @@ -146,20 +138,22 @@ impl Display for UnavailablePackage { } } -impl From<&MetadataUnavailable> for UnavailablePackage { - fn from(reason: &MetadataUnavailable) -> Self { - match reason { - MetadataUnavailable::Offline => Self::Offline, - MetadataUnavailable::InvalidMetadata(err) => Self::InvalidMetadata(err.to_string()), - MetadataUnavailable::InconsistentMetadata(err) => { - Self::InvalidMetadata(err.to_string()) - } - MetadataUnavailable::InvalidStructure(err) => Self::InvalidStructure(err.to_string()), - MetadataUnavailable::RequiresPython(..) => { - unreachable!("`requires-python` is only known upfront for registry distributions") - } - } - } +/// The package is unavailable at specific versions. +#[derive(Debug, Clone)] +pub(crate) enum IncompletePackage { + /// Network requests were disabled (i.e., `--offline`), and the wheel metadata was not found in the cache. + Offline, + /// The wheel metadata was not found. + MissingMetadata, + /// The wheel metadata was found, but could not be parsed. + InvalidMetadata(String), + /// The wheel metadata was found, but the metadata was inconsistent. + InconsistentMetadata(String), + /// The wheel has an invalid structure. + InvalidStructure(String), + /// 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), } #[derive(Debug, Clone)] diff --git a/crates/uv-resolver/src/resolver/mod.rs b/crates/uv-resolver/src/resolver/mod.rs index fe87350e1cf1..05f96399a430 100644 --- a/crates/uv-resolver/src/resolver/mod.rs +++ b/crates/uv-resolver/src/resolver/mod.rs @@ -55,7 +55,7 @@ use crate::python_requirement::PythonRequirement; use crate::resolution::ResolverOutput; use crate::resolution_mode::ResolutionStrategy; pub(crate) use crate::resolver::availability::{ - ResolverVersion, UnavailablePackage, UnavailableReason, UnavailableVersion, + IncompletePackage, ResolverVersion, UnavailablePackage, UnavailableReason, UnavailableVersion, }; use crate::resolver::batch_prefetch::BatchPrefetcher; pub use crate::resolver::derivation::DerivationChainBuilder; @@ -64,7 +64,6 @@ pub use crate::resolver::environment::ResolverEnvironment; pub(crate) use crate::resolver::fork_map::{ForkMap, ForkSet}; pub(crate) use crate::resolver::urls::Urls; use crate::universal_marker::{ConflictMarker, UniversalMarker}; -pub(crate) use provider::MetadataUnavailable; pub use crate::resolver::index::InMemoryIndex; use crate::resolver::indexes::Indexes; @@ -119,7 +118,7 @@ struct ResolverState { /// Incompatibilities for packages that are entirely unavailable. unavailable_packages: DashMap, /// Incompatibilities for packages that are unavailable at specific versions. - incomplete_packages: DashMap>, + incomplete_packages: DashMap>, /// The options that were used to configure this resolver. options: Options, /// The reporter to use for this resolver. @@ -355,7 +354,6 @@ impl ResolverState ResolverState &archive.metadata, - MetadataResponse::Unavailable(reason) => { + MetadataResponse::Offline => { self.unavailable_packages - .insert(name.clone(), reason.into()); + .insert(name.clone(), UnavailablePackage::Offline); + return Ok(None); + } + MetadataResponse::MissingMetadata => { + self.unavailable_packages + .insert(name.clone(), UnavailablePackage::MissingMetadata); + return Ok(None); + } + MetadataResponse::InvalidMetadata(err) => { + self.unavailable_packages.insert( + name.clone(), + UnavailablePackage::InvalidMetadata(err.to_string()), + ); + return Ok(None); + } + MetadataResponse::InconsistentMetadata(err) => { + self.unavailable_packages.insert( + name.clone(), + UnavailablePackage::InvalidMetadata(err.to_string()), + ); + return Ok(None); + } + MetadataResponse::InvalidStructure(err) => { + self.unavailable_packages.insert( + name.clone(), + UnavailablePackage::InvalidStructure(err.to_string()), + ); return Ok(None); } + MetadataResponse::RequiresPython(..) => { + unreachable!("`requires-python` is only known upfront for registry distributions") + } MetadataResponse::Error(dist, err) => { // TODO(charlie): Add derivation chain for URL dependencies. In practice, this isn't // critical since we fetch URL dependencies _prior_ to invoking the resolver. @@ -1291,20 +1318,82 @@ impl ResolverState &archive.metadata, - MetadataResponse::Unavailable(reason) => { - let unavailable_version = UnavailableVersion::from(reason); - let message = unavailable_version.singular_message(); - if let Some(err) = reason.source() { - // Show the detailed error for metadata parse errors. - warn!("{name} {message}: {err}"); - } else { - warn!("{name} {message}"); - } + MetadataResponse::Offline => { self.incomplete_packages .entry(name.clone()) .or_default() - .insert(version.clone(), reason.clone()); - return Ok(Dependencies::Unavailable(unavailable_version)); + .insert(version.clone(), IncompletePackage::Offline); + return Ok(Dependencies::Unavailable(UnavailableVersion::Offline)); + } + MetadataResponse::MissingMetadata => { + self.incomplete_packages + .entry(name.clone()) + .or_default() + .insert(version.clone(), IncompletePackage::MissingMetadata); + return Ok(Dependencies::Unavailable( + UnavailableVersion::MissingMetadata, + )); + } + MetadataResponse::InvalidMetadata(err) => { + warn!("Unable to extract metadata for {name}: {err}"); + self.incomplete_packages + .entry(name.clone()) + .or_default() + .insert( + version.clone(), + IncompletePackage::InvalidMetadata(err.to_string()), + ); + return Ok(Dependencies::Unavailable( + UnavailableVersion::InvalidMetadata, + )); + } + MetadataResponse::InconsistentMetadata(err) => { + warn!("Unable to extract metadata for {name}: {err}"); + self.incomplete_packages + .entry(name.clone()) + .or_default() + .insert( + version.clone(), + IncompletePackage::InconsistentMetadata(err.to_string()), + ); + return Ok(Dependencies::Unavailable( + UnavailableVersion::InconsistentMetadata, + )); + } + MetadataResponse::InvalidStructure(err) => { + warn!("Unable to extract metadata for {name}: {err}"); + self.incomplete_packages + .entry(name.clone()) + .or_default() + .insert( + version.clone(), + IncompletePackage::InvalidStructure(err.to_string()), + ); + return Ok(Dependencies::Unavailable( + UnavailableVersion::InvalidStructure, + )); + } + MetadataResponse::RequiresPython(requires_python, python_version) => { + warn!( + "Unable to extract metadata for {name}: {}", + uv_distribution::Error::RequiresPython( + requires_python.clone(), + python_version.clone() + ) + ); + self.incomplete_packages + .entry(name.clone()) + .or_default() + .insert( + version.clone(), + IncompletePackage::RequiresPython( + requires_python.clone(), + python_version.clone(), + ), + ); + return Ok(Dependencies::Unavailable( + UnavailableVersion::RequiresPython(requires_python.clone()), + )); } MetadataResponse::Error(dist, err) => { let chain = DerivationChainBuilder::from_state(id, version, pubgrub) @@ -1767,20 +1856,37 @@ impl ResolverState { - let dist_kind = match dist { - Dist::Built(_) => "built", - Dist::Source(_) => "source", - }; - trace!("Received {dist_kind} distribution metadata for: {dist}"); - if let MetadataResponse::Unavailable(reason) = &metadata { - let message = UnavailableVersion::from(reason).singular_message(); - if let Some(err) = reason.source() { - // Show the detailed error for metadata parse errors. - warn!("{dist} {message}: {err}"); - } else { - warn!("{dist} {message}"); + Some(Response::Dist { + dist: Dist::Built(dist), + metadata, + }) => { + trace!("Received built distribution metadata for: {dist}"); + match &metadata { + MetadataResponse::InvalidMetadata(err) => { + warn!("Unable to extract metadata for {dist}: {err}"); + } + MetadataResponse::InvalidStructure(err) => { + warn!("Unable to extract metadata for {dist}: {err}"); + } + _ => {} + } + self.index + .distributions() + .done(dist.version_id(), Arc::new(metadata)); + } + Some(Response::Dist { + dist: Dist::Source(dist), + metadata, + }) => { + trace!("Received source distribution metadata for: {dist}"); + match &metadata { + MetadataResponse::InvalidMetadata(err) => { + warn!("Unable to extract metadata for {dist}: {err}"); + } + MetadataResponse::InvalidStructure(err) => { + warn!("Unable to extract metadata for {dist}: {err}"); } + _ => {} } self.index .distributions() diff --git a/crates/uv-resolver/src/resolver/provider.rs b/crates/uv-resolver/src/resolver/provider.rs index 29e02384699e..943dfa864f4f 100644 --- a/crates/uv-resolver/src/resolver/provider.rs +++ b/crates/uv-resolver/src/resolver/provider.rs @@ -34,43 +34,21 @@ pub enum VersionsResponse { pub enum MetadataResponse { /// The wheel metadata was found and parsed successfully. Found(ArchiveMetadata), - /// A non-fatal error. - Unavailable(MetadataUnavailable), - /// The distribution could not be built or downloaded, a fatal error. - Error(Box, Arc), -} - -/// Non-fatal metadata fetching error. -/// -/// This is also the unavailability reasons for a package, while version unavailability is separate -/// in [`UnavailableVersion`]. -#[derive(Debug, Clone)] -pub enum MetadataUnavailable { - /// The wheel metadata was not found in the cache and the network is not available. - Offline, + /// The wheel metadata was not found. + MissingMetadata, /// The wheel metadata was found, but could not be parsed. - InvalidMetadata(Arc), + InvalidMetadata(Box), /// The wheel metadata was found, but the metadata was inconsistent. - InconsistentMetadata(Arc), + InconsistentMetadata(Box), /// The wheel has an invalid structure. - InvalidStructure(Arc), + InvalidStructure(Box), + /// The wheel metadata was not found in the cache and the network is not available. + Offline, /// 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), -} - -impl MetadataUnavailable { - /// Like [`std::error::Error::source`], but we don't want to derive the std error since our - /// formatting system is more custom. - pub(crate) fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { - match self { - MetadataUnavailable::Offline => None, - MetadataUnavailable::InvalidMetadata(err) => Some(err), - MetadataUnavailable::InconsistentMetadata(err) => Some(err), - MetadataUnavailable::InvalidStructure(err) => Some(err), - MetadataUnavailable::RequiresPython(_, _) => None, - } - } + /// The distribution could not be built or downloaded. + Error(Box, Arc), } pub trait ResolverProvider { @@ -211,39 +189,29 @@ impl<'a, Context: BuildContext> ResolverProvider for DefaultResolverProvider<'a, Ok(metadata) => Ok(MetadataResponse::Found(metadata)), Err(err) => match err { uv_distribution::Error::Client(client) => match client.into_kind() { - uv_client::ErrorKind::Offline(_) => { - Ok(MetadataResponse::Unavailable(MetadataUnavailable::Offline)) - } + uv_client::ErrorKind::Offline(_) => Ok(MetadataResponse::Offline), uv_client::ErrorKind::MetadataParseError(_, _, err) => { - Ok(MetadataResponse::Unavailable( - MetadataUnavailable::InvalidMetadata(Arc::new(*err)), - )) + Ok(MetadataResponse::InvalidMetadata(err)) + } + uv_client::ErrorKind::Metadata(_, err) => { + Ok(MetadataResponse::InvalidStructure(Box::new(err))) } - uv_client::ErrorKind::Metadata(_, err) => Ok(MetadataResponse::Unavailable( - MetadataUnavailable::InvalidStructure(Arc::new(err)), - )), kind => Err(uv_client::Error::from(kind).into()), }, uv_distribution::Error::WheelMetadataVersionMismatch { .. } => { - Ok(MetadataResponse::Unavailable( - MetadataUnavailable::InconsistentMetadata(Arc::new(err)), - )) + Ok(MetadataResponse::InconsistentMetadata(Box::new(err))) } uv_distribution::Error::WheelMetadataNameMismatch { .. } => { - Ok(MetadataResponse::Unavailable( - MetadataUnavailable::InconsistentMetadata(Arc::new(err)), - )) + Ok(MetadataResponse::InconsistentMetadata(Box::new(err))) + } + uv_distribution::Error::Metadata(err) => { + Ok(MetadataResponse::InvalidMetadata(Box::new(err))) + } + uv_distribution::Error::WheelMetadata(_, err) => { + Ok(MetadataResponse::InvalidStructure(err)) } - uv_distribution::Error::Metadata(err) => Ok(MetadataResponse::Unavailable( - MetadataUnavailable::InvalidMetadata(Arc::new(err)), - )), - uv_distribution::Error::WheelMetadata(_, err) => Ok(MetadataResponse::Unavailable( - MetadataUnavailable::InvalidStructure(Arc::new(*err)), - )), uv_distribution::Error::RequiresPython(requires_python, version) => { - Ok(MetadataResponse::Unavailable( - MetadataUnavailable::RequiresPython(requires_python, version), - )) + Ok(MetadataResponse::RequiresPython(requires_python, version)) } err => Ok(MetadataResponse::Error( Box::new(dist.clone()),