Always store registry index on resolution packages (#11815)

## Summary

Closes https://github.com/astral-sh/uv/issues/11776.
This commit is contained in:
Charlie Marsh 2025-02-26 21:46:37 -05:00 committed by GitHub
parent fb35875f24
commit 7f4269ed08
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 231 additions and 50 deletions

View file

@ -541,27 +541,48 @@ impl ResolverOutput {
// 3. Look for hashes from the registry, which are served at the package level.
if url.is_none() {
let versions_response = if let Some(index) = index {
in_memory.explicit().get(&(name.clone(), index.clone()))
} else {
in_memory.implicit().get(name)
};
// Query the implicit and explicit indexes (lazily) for the hashes.
let implicit_response = in_memory.implicit().get(name);
let mut explicit_response = None;
if let Some(versions_response) = versions_response {
if let VersionsResponse::Found(ref version_maps) = *versions_response {
if let Some(digests) = version_maps
.iter()
.find_map(|version_map| version_map.hashes(version))
.map(|digests| {
let mut digests = HashDigests::from(digests);
digests.sort_unstable();
digests
})
{
if !digests.is_empty() {
return digests;
}
// Search in the implicit indexes.
let hashes = implicit_response
.as_ref()
.and_then(|response| {
if let VersionsResponse::Found(version_maps) = &**response {
Some(version_maps)
} else {
None
}
})
.into_iter()
.flatten()
.filter(|version_map| version_map.index() == index)
.find_map(|version_map| version_map.hashes(version))
.or_else(|| {
// Search in the explicit indexes.
explicit_response = index
.and_then(|index| in_memory.explicit().get(&(name.clone(), index.clone())));
explicit_response
.as_ref()
.and_then(|response| {
if let VersionsResponse::Found(version_maps) = &**response {
Some(version_maps)
} else {
None
}
})
.into_iter()
.flatten()
.filter(|version_map| version_map.index() == index)
.find_map(|version_map| version_map.hashes(version))
});
if let Some(hashes) = hashes {
let mut digests = HashDigests::from(hashes);
digests.sort_unstable();
if !digests.is_empty() {
return digests;
}
}
}

View file

@ -2819,6 +2819,27 @@ impl ForkState {
self
}
/// Returns the URL or index for a package and version.
///
/// In practice, exactly one of the returned values will be `Some`.
fn source(
&self,
name: &PackageName,
version: &Version,
) -> (Option<&VerbatimParsedUrl>, Option<&IndexUrl>) {
let url = self.fork_urls.get(name);
let index = url
.is_none()
.then(|| {
self.pins
.get(name, version)
.expect("Every package should be pinned")
.index()
})
.flatten();
(url, index)
}
fn into_resolution(self) -> Resolution {
let solution: FxHashMap<_, _> = self.pubgrub.partial_solution.extract_solution().collect();
let edge_count: usize = solution
@ -2865,10 +2886,10 @@ impl ForkState {
_ => continue,
};
let self_url = self_name.as_ref().and_then(|name| self.fork_urls.get(name));
let self_index = self_name
.as_ref()
.and_then(|name| self.fork_indexes.get(name));
let (self_url, self_index) = self_name
.map(|self_name| self.source(self_name, self_version))
.unwrap_or((None, None));
match **dependency_package {
PubGrubPackageInner::Package {
@ -2894,8 +2915,8 @@ impl ForkState {
}
}
let to_url = self.fork_urls.get(dependency_name);
let to_index = self.fork_indexes.get(dependency_name);
let (to_url, to_index) = self.source(dependency_name, dependency_version);
let edge = ResolutionDependencyEdge {
from: self_name.cloned(),
from_version: self_version.clone(),
@ -2926,8 +2947,8 @@ impl ForkState {
}
}
let to_url = self.fork_urls.get(dependency_name);
let to_index = self.fork_indexes.get(dependency_name);
let (to_url, to_index) = self.source(dependency_name, dependency_version);
let edge = ResolutionDependencyEdge {
from: self_name.cloned(),
from_version: self_version.clone(),
@ -2957,10 +2978,9 @@ impl ForkState {
"Extras should be flattened"
);
}
let (to_url, to_index) = self.source(dependency_name, dependency_version);
// Insert an edge from the dependent package to the extra package.
let to_url = self.fork_urls.get(dependency_name);
let to_index = self.fork_indexes.get(dependency_name);
let edge = ResolutionDependencyEdge {
from: self_name.cloned(),
from_version: self_version.clone(),
@ -2979,8 +2999,6 @@ impl ForkState {
edges.push(edge);
// Insert an edge from the dependent package to the base package.
let to_url = self.fork_urls.get(dependency_name);
let to_index = self.fork_indexes.get(dependency_name);
let edge = ResolutionDependencyEdge {
from: self_name.cloned(),
from_version: self_version.clone(),
@ -3009,10 +3027,10 @@ impl ForkState {
"Groups should be flattened"
);
let (to_url, to_index) = self.source(dependency_name, dependency_version);
// Add an edge from the dependent package to the dev package, but _not_ the
// base package.
let to_url = self.fork_urls.get(dependency_name);
let to_index = self.fork_indexes.get(dependency_name);
let edge = ResolutionDependencyEdge {
from: self_name.cloned(),
from_version: self_version.clone(),
@ -3046,13 +3064,14 @@ impl ForkState {
marker: MarkerTree::TRUE,
} = &*self.pubgrub.package_store[package]
{
let (url, index) = self.source(name, &version);
Some((
ResolutionPackage {
name: name.clone(),
extra: extra.clone(),
dev: dev.clone(),
url: self.fork_urls.get(name).cloned(),
index: self.fork_indexes.get(name).cloned(),
url: url.cloned(),
index: index.cloned(),
},
version,
))
@ -3091,10 +3110,9 @@ pub(crate) struct ResolutionPackage {
pub(crate) name: PackageName,
pub(crate) extra: Option<ExtraName>,
pub(crate) dev: Option<GroupName>,
/// For index packages, this is `None`.
/// For registry packages, this is `None`; otherwise, the direct URL of the distribution.
pub(crate) url: Option<VerbatimParsedUrl>,
/// For URL packages, this is `None`, and is only `Some` for packages that are pinned to a
/// specific index via `tool.uv.sources`.
/// For URL packages, this is `None`; otherwise, the index URL of the distribution.
pub(crate) index: Option<IndexUrl>,
}

View file

@ -203,13 +203,10 @@ impl VersionMap {
/// Return the [`Hashes`] for the given version, if any.
pub(crate) fn hashes(&self, version: &Version) -> Option<&[HashDigest]> {
match self.inner {
VersionMapInner::Eager(ref eager) => eager
.map
.get(version)
.map(uv_distribution_types::PrioritizedDist::hashes),
VersionMapInner::Lazy(ref lazy) => lazy
.get(version)
.map(uv_distribution_types::PrioritizedDist::hashes),
VersionMapInner::Eager(ref eager) => {
eager.map.get(version).map(PrioritizedDist::hashes)
}
VersionMapInner::Lazy(ref lazy) => lazy.get(version).map(PrioritizedDist::hashes),
}
}