mirror of https://github.com/astral-sh/uv
Remove subdirectory support
This commit is contained in:
parent
ed48a81fa7
commit
36a8b04d34
|
|
@ -1,7 +1,7 @@
|
|||
use anstream::println;
|
||||
use anyhow::Result;
|
||||
use clap::Parser;
|
||||
|
||||
use tokio::sync::Semaphore;
|
||||
use uv_cache::{Cache, CacheArgs};
|
||||
use uv_client::{BaseClientBuilder, RegistryClientBuilder};
|
||||
use uv_distribution_types::IndexUrl;
|
||||
|
|
@ -27,9 +27,10 @@ pub(crate) async fn list_packages(
|
|||
.build();
|
||||
|
||||
let index_url = IndexUrl::parse(&args.url, None)?;
|
||||
let index = client.fetch_simple_index(&index_url).await?;
|
||||
let concurrency = Semaphore::new(Semaphore::MAX_PERMITS);
|
||||
let index = client.fetch_simple_index(&index_url, &concurrency).await?;
|
||||
|
||||
for package_name in index.iter() {
|
||||
for package_name in &index.projects {
|
||||
println!("{}", package_name);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -590,12 +590,16 @@ impl<'a, Context: BuildContext> DistributionDatabase<'a, Context> {
|
|||
) -> Result<Option<LocalWheel>, Error> {
|
||||
let Some(index) = self
|
||||
.resolver
|
||||
.get_cached_distribution(&BuildableSource::Dist(source), Some(tags), &self.client)
|
||||
.get_cached_distribution(source, Some(tags), &self.client)
|
||||
.await?
|
||||
else {
|
||||
return Ok(None);
|
||||
};
|
||||
for prioritized_dist in index.iter() {
|
||||
for prioritized_dist in index
|
||||
.get(source.name())
|
||||
.iter()
|
||||
.flat_map(|index| index.iter())
|
||||
{
|
||||
let Some(compatible_dist) = prioritized_dist.get() else {
|
||||
continue;
|
||||
};
|
||||
|
|
@ -627,6 +631,9 @@ impl<'a, Context: BuildContext> DistributionDatabase<'a, Context> {
|
|||
source: &BuildableSource<'_>,
|
||||
hashes: HashPolicy<'_>,
|
||||
) -> Result<Option<ArchiveMetadata>, Error> {
|
||||
let BuildableSource::Dist(source) = source else {
|
||||
return Ok(None);
|
||||
};
|
||||
let Some(index) = self
|
||||
.resolver
|
||||
.get_cached_distribution(source, None, &self.client)
|
||||
|
|
@ -634,7 +641,11 @@ impl<'a, Context: BuildContext> DistributionDatabase<'a, Context> {
|
|||
else {
|
||||
return Ok(None);
|
||||
};
|
||||
for prioritized_dist in index.iter() {
|
||||
for prioritized_dist in index
|
||||
.get(source.name())
|
||||
.iter()
|
||||
.flat_map(|index| index.iter())
|
||||
{
|
||||
let Some(compatible_dist) = prioritized_dist.get() else {
|
||||
continue;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
use std::borrow::Cow;
|
||||
use std::collections::BTreeMap;
|
||||
use std::collections::btree_map::Entry;
|
||||
use std::path::Path;
|
||||
use std::sync::Arc;
|
||||
|
||||
use blake2::Digest;
|
||||
|
|
@ -11,15 +9,15 @@ use tracing::{debug, instrument, warn};
|
|||
|
||||
use uv_auth::PyxTokenStore;
|
||||
use uv_cache_key::RepositoryUrl;
|
||||
use uv_client::{MetadataFormat, SimpleIndexMetadata, VersionFiles};
|
||||
use uv_client::{MetadataFormat, VersionFiles};
|
||||
use uv_configuration::BuildOptions;
|
||||
use uv_distribution_filename::{DistFilename, SourceDistFilename, WheelFilename};
|
||||
use uv_distribution_types::{
|
||||
BuildableSource, File, HashComparison, HashPolicy, IncompatibleSource, IncompatibleWheel,
|
||||
IndexFormat, IndexMetadata, IndexUrl, PrioritizedDist, RegistryBuiltWheel, RegistrySourceDist,
|
||||
SourceDist, SourceDistCompatibility, SourceUrl, WheelCompatibility,
|
||||
File, HashComparison, HashPolicy, IncompatibleSource, IncompatibleWheel, IndexFormat,
|
||||
IndexMetadata, IndexUrl, PrioritizedDist, RegistryBuiltWheel, RegistrySourceDist, SourceDist,
|
||||
SourceDistCompatibility, WheelCompatibility,
|
||||
};
|
||||
use uv_git_types::{GitOid, GitUrl};
|
||||
use uv_git_types::GitOid;
|
||||
use uv_normalize::PackageName;
|
||||
use uv_pep440::Version;
|
||||
use uv_pep508::VerbatimUrl;
|
||||
|
|
@ -53,12 +51,12 @@ impl<'a, T: BuildContext> RemoteCacheResolver<'a, T> {
|
|||
/// Return the cached Git index for the given distribution, if any.
|
||||
pub(crate) async fn get_cached_distribution(
|
||||
&self,
|
||||
source: &BuildableSource<'_>,
|
||||
dist: &SourceDist,
|
||||
tags: Option<&Tags>,
|
||||
client: &ManagedClient<'a>,
|
||||
) -> Result<Option<GitIndex>, Error> {
|
||||
// Fetch the entries for the given distribution.
|
||||
let entries = self.get_or_fetch_index(source, client).await?;
|
||||
let entries = self.get_or_fetch_index(dist, client).await?;
|
||||
if entries.is_empty() {
|
||||
return Ok(None);
|
||||
}
|
||||
|
|
@ -76,79 +74,45 @@ impl<'a, T: BuildContext> RemoteCacheResolver<'a, T> {
|
|||
/// Fetch the remote Git index for the given distribution.
|
||||
async fn get_or_fetch_index(
|
||||
&self,
|
||||
source: &BuildableSource<'_>,
|
||||
dist: &SourceDist,
|
||||
client: &ManagedClient<'a>,
|
||||
) -> Result<Vec<GitIndexEntry>, Error> {
|
||||
#[derive(Debug)]
|
||||
struct BuildableGitSource<'a> {
|
||||
git: &'a GitUrl,
|
||||
subdirectory: Option<&'a Path>,
|
||||
name: Option<&'a PackageName>,
|
||||
}
|
||||
|
||||
let Some(workspace) = &self.workspace else {
|
||||
return Ok(Vec::default());
|
||||
};
|
||||
|
||||
let source = match source {
|
||||
BuildableSource::Dist(SourceDist::Git(dist)) => BuildableGitSource {
|
||||
git: &dist.git,
|
||||
subdirectory: dist.subdirectory.as_deref(),
|
||||
name: Some(&dist.name),
|
||||
},
|
||||
BuildableSource::Url(SourceUrl::Git(url)) => BuildableGitSource {
|
||||
git: url.git,
|
||||
subdirectory: url.subdirectory,
|
||||
name: None,
|
||||
},
|
||||
_ => {
|
||||
let Some(store) = &self.store else {
|
||||
return Ok(Vec::default());
|
||||
}
|
||||
};
|
||||
|
||||
let Some(precise) = self.build_context.git().get_precise(source.git) else {
|
||||
let SourceDist::Git(dist) = dist else {
|
||||
return Ok(Vec::default());
|
||||
};
|
||||
|
||||
let Some(precise) = self.build_context.git().get_precise(&dist.git) else {
|
||||
return Ok(Vec::default());
|
||||
};
|
||||
|
||||
// Determine the cache key for the Git source.
|
||||
let cache_key = GitCacheKey {
|
||||
repository: RepositoryUrl::new(source.git.repository()),
|
||||
repository: RepositoryUrl::new(dist.git.repository()),
|
||||
precise,
|
||||
subdirectory: source.subdirectory,
|
||||
};
|
||||
let digest = cache_key.digest();
|
||||
let index = IndexUrl::from(
|
||||
VerbatimUrl::parse_url(format!(
|
||||
"http://localhost:8000/v1/git/{workspace}/{}/{}/{}",
|
||||
|
||||
// Add the cache key to the URL.
|
||||
let url = {
|
||||
let mut url = store.api().clone();
|
||||
url.set_path(&format!(
|
||||
"v1/cache/{workspace}/{}/{}/{}",
|
||||
&digest[..2],
|
||||
&digest[2..4],
|
||||
&digest[4..],
|
||||
))
|
||||
.unwrap(),
|
||||
);
|
||||
debug!("Using remote Git index URL: {}", index);
|
||||
|
||||
// Determine the package name.
|
||||
let name = if let Some(name) = source.name {
|
||||
Cow::Borrowed(name)
|
||||
} else {
|
||||
// Fetch the list of packages from the Simple API.
|
||||
let SimpleIndexMetadata { projects } = client
|
||||
.manual(|client, semaphore| client.fetch_simple_index(&index, semaphore))
|
||||
.await?;
|
||||
|
||||
// Ensure that the index contains exactly one package.
|
||||
let mut packages = projects.into_iter();
|
||||
let Some(name) = packages.next() else {
|
||||
debug!("Remote Git index at `{index}` contains no packages");
|
||||
return Ok(Vec::default());
|
||||
};
|
||||
if packages.next().is_some() {
|
||||
debug!("Remote Git index at `{index}` contains multiple packages");
|
||||
return Ok(Vec::default());
|
||||
}
|
||||
Cow::Owned(name)
|
||||
));
|
||||
url
|
||||
};
|
||||
let index = IndexUrl::from(VerbatimUrl::from_url(url));
|
||||
debug!("Using remote Git index URL: {index}");
|
||||
|
||||
// Store the index entries in a cache, to avoid redundant fetches.
|
||||
{
|
||||
|
|
@ -166,7 +130,7 @@ impl<'a, T: BuildContext> RemoteCacheResolver<'a, T> {
|
|||
let archives = client
|
||||
.manual(|client, semaphore| {
|
||||
client.simple_detail(
|
||||
name.as_ref(),
|
||||
&dist.name,
|
||||
Some(metadata.as_ref()),
|
||||
self.build_context.capabilities(),
|
||||
semaphore,
|
||||
|
|
@ -184,9 +148,10 @@ impl<'a, T: BuildContext> RemoteCacheResolver<'a, T> {
|
|||
let files = rkyv::deserialize::<VersionFiles, rkyv::rancor::Error>(&datum.files)
|
||||
.expect("archived version files always deserializes");
|
||||
for (filename, file) in files.all() {
|
||||
if *filename.name() != *name {
|
||||
if *filename.name() != dist.name {
|
||||
warn!(
|
||||
"Skipping file `{filename}` from remote Git index at `{index}` due to name mismatch (expected: `{name}`)"
|
||||
"Skipping file `{filename}` from remote Git index at `{index}` due to name mismatch (expected: `{}`)",
|
||||
dist.name
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
|
@ -249,11 +214,9 @@ impl GitIndex {
|
|||
Self(index)
|
||||
}
|
||||
|
||||
/// Returns an [`Iterator`] over the distributions.
|
||||
pub(crate) fn iter(&self) -> impl Iterator<Item = &PrioritizedDist> {
|
||||
self.0
|
||||
.iter()
|
||||
.flat_map(|(.., distributions)| distributions.0.iter().map(|(.., dist)| dist))
|
||||
/// Return the [`GitIndexDistributions`] for the given package name, if any.
|
||||
pub(crate) fn get(&self, name: &PackageName) -> Option<&GitIndexDistributions> {
|
||||
self.0.get(name)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -262,6 +225,11 @@ impl GitIndex {
|
|||
pub(crate) struct GitIndexDistributions(BTreeMap<Version, PrioritizedDist>);
|
||||
|
||||
impl GitIndexDistributions {
|
||||
/// Returns an [`Iterator`] over the distributions.
|
||||
pub(crate) fn iter(&self) -> impl Iterator<Item = &PrioritizedDist> {
|
||||
self.0.iter().map(|(.., dist)| dist)
|
||||
}
|
||||
|
||||
/// Add the given [`File`] to the [`GitIndexDistributions`] for the given package.
|
||||
fn add_file(
|
||||
&mut self,
|
||||
|
|
@ -421,36 +389,25 @@ impl GitIndexCache {
|
|||
|
||||
/// A cache key for a Git repository at a precise commit.
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
struct GitCacheKey<'a> {
|
||||
struct GitCacheKey {
|
||||
repository: RepositoryUrl,
|
||||
precise: GitOid,
|
||||
subdirectory: Option<&'a Path>,
|
||||
}
|
||||
|
||||
impl GitCacheKey<'_> {
|
||||
impl GitCacheKey {
|
||||
/// Compute the digest for the Git cache key.
|
||||
fn digest(&self) -> String {
|
||||
let mut hasher = blake2::Blake2b::<blake2::digest::consts::U32>::new();
|
||||
hasher.update(self.repository.as_str().as_bytes());
|
||||
hasher.update(b"/");
|
||||
hasher.update(self.precise.as_str().as_bytes());
|
||||
if let Some(subdirectory) = self
|
||||
.subdirectory
|
||||
.and_then(|subdirectory| subdirectory.to_str())
|
||||
{
|
||||
hasher.update(b"?subdirectory=");
|
||||
hasher.update(subdirectory.as_bytes());
|
||||
}
|
||||
hex::encode(hasher.finalize())
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for GitCacheKey<'_> {
|
||||
impl std::fmt::Display for GitCacheKey {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{}/{}", self.repository, self.precise.as_str())?;
|
||||
if let Some(subdirectory) = &self.subdirectory {
|
||||
write!(f, "?subdirectory={}", subdirectory.display())?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue