mirror of
https://github.com/astral-sh/uv.git
synced 2025-11-25 21:37:51 +00:00
Populate the in-memory index when resolving lookahead URLs (#2761)
## Summary Just ensures that we don't have to go back to the cache when resolving.
This commit is contained in:
parent
999d653404
commit
f2c9e88f3e
5 changed files with 68 additions and 13 deletions
|
|
@ -1,15 +1,17 @@
|
|||
use std::collections::VecDeque;
|
||||
|
||||
use anyhow::{Context, Result};
|
||||
use cache_key::CanonicalUrl;
|
||||
use futures::stream::FuturesUnordered;
|
||||
use futures::StreamExt;
|
||||
use rustc_hash::FxHashSet;
|
||||
|
||||
use distribution_types::{Dist, LocalEditable};
|
||||
use distribution_types::{Dist, DistributionMetadata, LocalEditable};
|
||||
use pep508_rs::{MarkerEnvironment, Requirement, VersionOrUrl};
|
||||
use pypi_types::Metadata23;
|
||||
use uv_client::RegistryClient;
|
||||
use uv_distribution::{DistributionDatabase, Reporter};
|
||||
use uv_resolver::InMemoryIndex;
|
||||
use uv_types::{BuildContext, Constraints, Overrides, RequestedRequirements};
|
||||
|
||||
/// A resolver for resolving lookahead requirements from direct URLs.
|
||||
|
|
@ -37,6 +39,8 @@ pub struct LookaheadResolver<'a, Context: BuildContext + Send + Sync> {
|
|||
overrides: &'a Overrides,
|
||||
/// The editable requirements for the project.
|
||||
editables: &'a [(LocalEditable, Metadata23)],
|
||||
/// The in-memory index for resolving dependencies.
|
||||
index: &'a InMemoryIndex,
|
||||
/// The database for fetching and building distributions.
|
||||
database: DistributionDatabase<'a, Context>,
|
||||
}
|
||||
|
|
@ -50,12 +54,14 @@ impl<'a, Context: BuildContext + Send + Sync> LookaheadResolver<'a, Context> {
|
|||
editables: &'a [(LocalEditable, Metadata23)],
|
||||
context: &'a Context,
|
||||
client: &'a RegistryClient,
|
||||
index: &'a InMemoryIndex,
|
||||
) -> Self {
|
||||
Self {
|
||||
requirements,
|
||||
constraints,
|
||||
overrides,
|
||||
editables,
|
||||
index,
|
||||
database: DistributionDatabase::new(client, context),
|
||||
}
|
||||
}
|
||||
|
|
@ -126,15 +132,34 @@ impl<'a, Context: BuildContext + Send + Sync> LookaheadResolver<'a, Context> {
|
|||
// Convert to a buildable distribution.
|
||||
let dist = Dist::from_url(requirement.name, url.clone())?;
|
||||
|
||||
// Run the PEP 517 build process to extract metadata from the source distribution.
|
||||
let (metadata, _precise) = self
|
||||
.database
|
||||
.get_or_build_wheel_metadata(&dist)
|
||||
.await
|
||||
.with_context(|| match &dist {
|
||||
Dist::Built(built) => format!("Failed to download: {built}"),
|
||||
Dist::Source(source) => format!("Failed to download and build: {source}"),
|
||||
})?;
|
||||
// Fetch the metadata for the distribution.
|
||||
let requires_dist = {
|
||||
// If the metadata is already in the index, return it.
|
||||
if let Some(metadata) = self.index.get_metadata(&dist.package_id()) {
|
||||
metadata.requires_dist.clone()
|
||||
} else {
|
||||
// Run the PEP 517 build process to extract metadata from the source distribution.
|
||||
let (metadata, precise) = self
|
||||
.database
|
||||
.get_or_build_wheel_metadata(&dist)
|
||||
.await
|
||||
.with_context(|| match &dist {
|
||||
Dist::Built(built) => format!("Failed to download: {built}"),
|
||||
Dist::Source(source) => format!("Failed to download and build: {source}"),
|
||||
})?;
|
||||
|
||||
// Insert the metadata into the index.
|
||||
self.index
|
||||
.insert_metadata(dist.package_id(), metadata.clone());
|
||||
|
||||
// Insert the redirect into the index.
|
||||
if let Some(precise) = precise {
|
||||
self.index.insert_redirect(CanonicalUrl::new(url), precise);
|
||||
}
|
||||
|
||||
metadata.requires_dist
|
||||
}
|
||||
};
|
||||
|
||||
// Consider the dependencies to be "direct" if the requirement is a local source tree.
|
||||
let direct = if let Dist::Source(source_dist) = &dist {
|
||||
|
|
@ -146,7 +171,7 @@ impl<'a, Context: BuildContext + Send + Sync> LookaheadResolver<'a, Context> {
|
|||
// Return the requirements from the metadata.
|
||||
Ok(Some(RequestedRequirements::new(
|
||||
requirement.extras,
|
||||
metadata.requires_dist,
|
||||
requires_dist,
|
||||
direct,
|
||||
)))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
use cache_key::CanonicalUrl;
|
||||
use dashmap::DashMap;
|
||||
use std::sync::Arc;
|
||||
use url::Url;
|
||||
|
||||
use distribution_types::PackageId;
|
||||
|
|
@ -24,3 +25,30 @@ pub struct InMemoryIndex {
|
|||
/// `git+https://github.com/pallets/flask.git@c2f65dd1cfff0672b902fd5b30815f0b4137214c`.
|
||||
pub(crate) redirects: DashMap<CanonicalUrl, Url>,
|
||||
}
|
||||
|
||||
impl InMemoryIndex {
|
||||
/// Insert a [`VersionsResponse`] into the index.
|
||||
pub fn insert_package(&self, package_name: PackageName, metadata: VersionsResponse) {
|
||||
self.packages.done(package_name, metadata);
|
||||
}
|
||||
|
||||
/// Insert a [`Metadata23`] into the index.
|
||||
pub fn insert_metadata(&self, package_id: PackageId, metadata: Metadata23) {
|
||||
self.distributions.done(package_id, metadata);
|
||||
}
|
||||
|
||||
/// Insert a redirect from a source URL to a target URL.
|
||||
pub fn insert_redirect(&self, source: CanonicalUrl, target: Url) {
|
||||
self.redirects.insert(source, target);
|
||||
}
|
||||
|
||||
/// Get the [`VersionsResponse`] for a given package name, without waiting.
|
||||
pub fn get_package(&self, package_name: &PackageName) -> Option<Arc<VersionsResponse>> {
|
||||
self.packages.get(package_name)
|
||||
}
|
||||
|
||||
/// Get the [`Metadata23`] for a given package ID, without waiting.
|
||||
pub fn get_metadata(&self, package_id: &PackageId) -> Option<Arc<Metadata23>> {
|
||||
self.distributions.get(package_id)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -345,6 +345,7 @@ pub(crate) async fn pip_compile(
|
|||
&editables,
|
||||
&build_dispatch,
|
||||
&client,
|
||||
&top_level_index,
|
||||
)
|
||||
.with_reporter(ResolverReporter::from(printer))
|
||||
.resolve(&markers)
|
||||
|
|
|
|||
|
|
@ -546,6 +546,7 @@ async fn resolve(
|
|||
&editables,
|
||||
build_dispatch,
|
||||
client,
|
||||
index,
|
||||
)
|
||||
.with_reporter(ResolverReporter::from(printer))
|
||||
.resolve(markers)
|
||||
|
|
|
|||
|
|
@ -1584,8 +1584,8 @@ fn conflicting_transitive_url_dependency() -> Result<()> {
|
|||
|
||||
----- stderr -----
|
||||
× No solution found when resolving dependencies:
|
||||
╰─▶ Because flask==3.0.0 depends on werkzeug>=3.0.0 and only werkzeug<3.0.0
|
||||
is available, we can conclude that flask==3.0.0 cannot be used.
|
||||
╰─▶ Because only werkzeug<3.0.0 is available and flask==3.0.0 depends on
|
||||
werkzeug>=3.0.0, we can conclude that flask==3.0.0 cannot be used.
|
||||
And because you require flask==3.0.0, we can conclude that the
|
||||
requirements are unsatisfiable.
|
||||
"###
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue