Allow --config-settings-package to apply configuration settings at the package level (#14573)
Some checks are pending
CI / Determine changes (push) Waiting to run
CI / lint (push) Waiting to run
CI / cargo clippy | ubuntu (push) Blocked by required conditions
CI / cargo clippy | windows (push) Blocked by required conditions
CI / cargo dev generate-all (push) Blocked by required conditions
CI / cargo shear (push) Waiting to run
CI / cargo test | ubuntu (push) Blocked by required conditions
CI / cargo test | macos (push) Blocked by required conditions
CI / cargo test | windows (push) Blocked by required conditions
CI / check windows trampoline | aarch64 (push) Blocked by required conditions
CI / check windows trampoline | i686 (push) Blocked by required conditions
CI / check windows trampoline | x86_64 (push) Blocked by required conditions
CI / test windows trampoline | i686 (push) Blocked by required conditions
CI / test windows trampoline | x86_64 (push) Blocked by required conditions
CI / typos (push) Waiting to run
CI / mkdocs (push) Waiting to run
CI / build binary | linux libc (push) Blocked by required conditions
CI / build binary | linux aarch64 (push) Blocked by required conditions
CI / build binary | linux musl (push) Blocked by required conditions
CI / build binary | macos aarch64 (push) Blocked by required conditions
CI / build binary | macos x86_64 (push) Blocked by required conditions
CI / build binary | windows x86_64 (push) Blocked by required conditions
CI / build binary | windows aarch64 (push) Blocked by required conditions
CI / build binary | msrv (push) Blocked by required conditions
CI / build binary | freebsd (push) Blocked by required conditions
CI / ecosystem test | pydantic/pydantic-core (push) Blocked by required conditions
CI / ecosystem test | prefecthq/prefect (push) Blocked by required conditions
CI / ecosystem test | pallets/flask (push) Blocked by required conditions
CI / smoke test | linux (push) Blocked by required conditions
CI / smoke test | linux aarch64 (push) Blocked by required conditions
CI / check system | alpine (push) Blocked by required conditions
CI / smoke test | macos (push) Blocked by required conditions
CI / smoke test | windows x86_64 (push) Blocked by required conditions
CI / smoke test | windows aarch64 (push) Blocked by required conditions
CI / integration test | conda on ubuntu (push) Blocked by required conditions
CI / integration test | deadsnakes python3.9 on ubuntu (push) Blocked by required conditions
CI / integration test | free-threaded on windows (push) Blocked by required conditions
CI / integration test | aarch64 windows implicit (push) Blocked by required conditions
CI / integration test | aarch64 windows explicit (push) Blocked by required conditions
CI / integration test | pypy on ubuntu (push) Blocked by required conditions
CI / integration test | pypy on windows (push) Blocked by required conditions
CI / integration test | graalpy on ubuntu (push) Blocked by required conditions
CI / integration test | graalpy on windows (push) Blocked by required conditions
CI / integration test | pyodide on ubuntu (push) Blocked by required conditions
CI / integration test | github actions (push) Blocked by required conditions
CI / integration test | free-threaded python on github actions (push) Blocked by required conditions
CI / integration test | determine publish changes (push) Blocked by required conditions
CI / integration test | registries (push) Blocked by required conditions
CI / integration test | uv publish (push) Blocked by required conditions
CI / integration test | uv_build (push) Blocked by required conditions
CI / check cache | ubuntu (push) Blocked by required conditions
CI / check cache | macos aarch64 (push) Blocked by required conditions
CI / check system | python on debian (push) Blocked by required conditions
CI / check system | python on fedora (push) Blocked by required conditions
CI / check system | python on ubuntu (push) Blocked by required conditions
CI / check system | python on rocky linux 8 (push) Blocked by required conditions
CI / check system | python on rocky linux 9 (push) Blocked by required conditions
CI / check system | graalpy on ubuntu (push) Blocked by required conditions
CI / check system | pypy on ubuntu (push) Blocked by required conditions
CI / check system | pyston (push) Blocked by required conditions
CI / check system | python on macos aarch64 (push) Blocked by required conditions
CI / check system | homebrew python on macos aarch64 (push) Blocked by required conditions
CI / check system | python on macos x86-64 (push) Blocked by required conditions
CI / check system | python3.10 on windows x86-64 (push) Blocked by required conditions
CI / check system | python3.10 on windows x86 (push) Blocked by required conditions
CI / check system | python3.13 on windows x86-64 (push) Blocked by required conditions
CI / check system | x86-64 python3.13 on windows aarch64 (push) Blocked by required conditions
CI / check system | aarch64 python3.13 on windows aarch64 (push) Blocked by required conditions
CI / check system | windows registry (push) Blocked by required conditions
CI / check system | python3.12 via chocolatey (push) Blocked by required conditions
CI / check system | python3.9 via pyenv (push) Blocked by required conditions
CI / check system | python3.13 (push) Blocked by required conditions
CI / check system | conda3.11 on macos aarch64 (push) Blocked by required conditions
CI / check system | conda3.8 on macos aarch64 (push) Blocked by required conditions
CI / check system | conda3.11 on linux x86-64 (push) Blocked by required conditions
CI / check system | conda3.8 on linux x86-64 (push) Blocked by required conditions
CI / check system | conda3.11 on windows x86-64 (push) Blocked by required conditions
CI / check system | conda3.8 on windows x86-64 (push) Blocked by required conditions
CI / check system | amazonlinux (push) Blocked by required conditions
CI / check system | embedded python3.10 on windows x86-64 (push) Blocked by required conditions
CI / benchmarks | walltime aarch64 linux (push) Blocked by required conditions
CI / benchmarks | instrumented (push) Blocked by required conditions

## Summary

Closes https://github.com/astral-sh/uv/issues/14564.

Closes https://github.com/astral-sh/uv/issues/10940.
This commit is contained in:
Charlie Marsh 2025-07-17 21:27:54 -04:00 committed by GitHub
parent a6a5e65e0c
commit e724ddc63f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
30 changed files with 927 additions and 58 deletions

View file

@ -1,10 +1,12 @@
use std::borrow::Cow;
use uv_cache::{Cache, CacheBucket, CacheShard, WheelCache};
use uv_cache_info::CacheInfo;
use uv_cache_key::cache_digest;
use uv_configuration::ConfigSettings;
use uv_configuration::{ConfigSettings, PackageConfigSettings};
use uv_distribution_types::{
DirectUrlSourceDist, DirectorySourceDist, GitSourceDist, Hashed, PathSourceDist,
};
use uv_normalize::PackageName;
use uv_platform_tags::Tags;
use uv_types::HashStrategy;
@ -18,7 +20,8 @@ pub struct BuiltWheelIndex<'a> {
cache: &'a Cache,
tags: &'a Tags,
hasher: &'a HashStrategy,
build_configuration: &'a ConfigSettings,
config_settings: &'a ConfigSettings,
config_settings_package: &'a PackageConfigSettings,
}
impl<'a> BuiltWheelIndex<'a> {
@ -27,13 +30,15 @@ impl<'a> BuiltWheelIndex<'a> {
cache: &'a Cache,
tags: &'a Tags,
hasher: &'a HashStrategy,
build_configuration: &'a ConfigSettings,
config_settings: &'a ConfigSettings,
config_settings_package: &'a PackageConfigSettings,
) -> Self {
Self {
cache,
tags,
hasher,
build_configuration,
config_settings,
config_settings_package,
}
}
@ -63,10 +68,11 @@ impl<'a> BuiltWheelIndex<'a> {
let cache_shard = cache_shard.shard(revision.id());
// If there are build settings, we need to scope to a cache shard.
let cache_shard = if self.build_configuration.is_empty() {
let config_settings = self.config_settings_for(&source_dist.name);
let cache_shard = if config_settings.is_empty() {
cache_shard
} else {
cache_shard.shard(cache_digest(self.build_configuration))
cache_shard.shard(cache_digest(&config_settings))
};
Ok(self.find(&cache_shard))
@ -100,10 +106,11 @@ impl<'a> BuiltWheelIndex<'a> {
let cache_shard = cache_shard.shard(revision.id());
// If there are build settings, we need to scope to a cache shard.
let cache_shard = if self.build_configuration.is_empty() {
let config_settings = self.config_settings_for(&source_dist.name);
let cache_shard = if config_settings.is_empty() {
cache_shard
} else {
cache_shard.shard(cache_digest(self.build_configuration))
cache_shard.shard(cache_digest(&config_settings))
};
Ok(self
@ -148,10 +155,11 @@ impl<'a> BuiltWheelIndex<'a> {
let cache_shard = cache_shard.shard(revision.id());
// If there are build settings, we need to scope to a cache shard.
let cache_shard = if self.build_configuration.is_empty() {
let config_settings = self.config_settings_for(&source_dist.name);
let cache_shard = if config_settings.is_empty() {
cache_shard
} else {
cache_shard.shard(cache_digest(self.build_configuration))
cache_shard.shard(cache_digest(&config_settings))
};
Ok(self
@ -174,10 +182,11 @@ impl<'a> BuiltWheelIndex<'a> {
);
// If there are build settings, we need to scope to a cache shard.
let cache_shard = if self.build_configuration.is_empty() {
let config_settings = self.config_settings_for(&source_dist.name);
let cache_shard = if config_settings.is_empty() {
cache_shard
} else {
cache_shard.shard(cache_digest(self.build_configuration))
cache_shard.shard(cache_digest(&config_settings))
};
self.find(&cache_shard)
@ -239,4 +248,13 @@ impl<'a> BuiltWheelIndex<'a> {
candidate
}
/// Determine the [`ConfigSettings`] for the given package name.
fn config_settings_for(&self, name: &PackageName) -> Cow<'_, ConfigSettings> {
if let Some(package_settings) = self.config_settings_package.get(name) {
Cow::Owned(package_settings.clone().merge(self.config_settings.clone()))
} else {
Cow::Borrowed(self.config_settings)
}
}
}

View file

@ -29,7 +29,7 @@ use uv_cache_key::cache_digest;
use uv_client::{
CacheControl, CachedClientError, Connectivity, DataWithCachePolicy, RegistryClient,
};
use uv_configuration::{BuildKind, BuildOutput, SourceStrategy};
use uv_configuration::{BuildKind, BuildOutput, ConfigSettings, SourceStrategy};
use uv_distribution_filename::{SourceDistExtension, WheelFilename};
use uv_distribution_types::{
BuildableSource, DirectorySourceUrl, GitSourceUrl, HashPolicy, Hashed, PathSourceUrl,
@ -373,6 +373,23 @@ impl<'a, T: BuildContext> SourceDistributionBuilder<'a, T> {
Ok(metadata)
}
/// Determine the [`ConfigSettings`] for the given package name.
fn config_settings_for(&self, name: Option<&PackageName>) -> Cow<'_, ConfigSettings> {
if let Some(name) = name {
if let Some(package_settings) = self.build_context.config_settings_package().get(name) {
Cow::Owned(
package_settings
.clone()
.merge(self.build_context.config_settings().clone()),
)
} else {
Cow::Borrowed(self.build_context.config_settings())
}
} else {
Cow::Borrowed(self.build_context.config_settings())
}
}
/// Build a source distribution from a remote URL.
async fn url<'data>(
&self,
@ -407,11 +424,11 @@ impl<'a, T: BuildContext> SourceDistributionBuilder<'a, T> {
let source_dist_entry = cache_shard.entry(SOURCE);
// If there are build settings, we need to scope to a cache shard.
let config_settings = self.build_context.config_settings();
let config_settings = self.config_settings_for(source.name());
let cache_shard = if config_settings.is_empty() {
cache_shard
} else {
cache_shard.shard(cache_digest(config_settings))
cache_shard.shard(cache_digest(&&config_settings))
};
// If the cache contains a compatible wheel, return it.
@ -580,11 +597,11 @@ impl<'a, T: BuildContext> SourceDistributionBuilder<'a, T> {
}
// If there are build settings, we need to scope to a cache shard.
let config_settings = self.build_context.config_settings();
let config_settings = self.config_settings_for(source.name());
let cache_shard = if config_settings.is_empty() {
cache_shard
} else {
cache_shard.shard(cache_digest(config_settings))
cache_shard.shard(cache_digest(&config_settings))
};
// Otherwise, we either need to build the metadata.
@ -779,11 +796,11 @@ impl<'a, T: BuildContext> SourceDistributionBuilder<'a, T> {
let source_entry = cache_shard.entry(SOURCE);
// If there are build settings, we need to scope to a cache shard.
let config_settings = self.build_context.config_settings();
let config_settings = self.config_settings_for(source.name());
let cache_shard = if config_settings.is_empty() {
cache_shard
} else {
cache_shard.shard(cache_digest(config_settings))
cache_shard.shard(cache_digest(&config_settings))
};
// If the cache contains a compatible wheel, return it.
@ -941,11 +958,11 @@ impl<'a, T: BuildContext> SourceDistributionBuilder<'a, T> {
}
// If there are build settings, we need to scope to a cache shard.
let config_settings = self.build_context.config_settings();
let config_settings = self.config_settings_for(source.name());
let cache_shard = if config_settings.is_empty() {
cache_shard
} else {
cache_shard.shard(cache_digest(config_settings))
cache_shard.shard(cache_digest(&config_settings))
};
// Otherwise, we need to build a wheel.
@ -1083,11 +1100,11 @@ impl<'a, T: BuildContext> SourceDistributionBuilder<'a, T> {
let cache_shard = cache_shard.shard(revision.id());
// If there are build settings, we need to scope to a cache shard.
let config_settings = self.build_context.config_settings();
let config_settings = self.config_settings_for(source.name());
let cache_shard = if config_settings.is_empty() {
cache_shard
} else {
cache_shard.shard(cache_digest(config_settings))
cache_shard.shard(cache_digest(&config_settings))
};
// If the cache contains a compatible wheel, return it.
@ -1271,11 +1288,11 @@ impl<'a, T: BuildContext> SourceDistributionBuilder<'a, T> {
}
// If there are build settings, we need to scope to a cache shard.
let config_settings = self.build_context.config_settings();
let config_settings = self.config_settings_for(source.name());
let cache_shard = if config_settings.is_empty() {
cache_shard
} else {
cache_shard.shard(cache_digest(config_settings))
cache_shard.shard(cache_digest(&config_settings))
};
// Otherwise, we need to build a wheel.
@ -1476,11 +1493,11 @@ impl<'a, T: BuildContext> SourceDistributionBuilder<'a, T> {
let _lock = cache_shard.lock().await.map_err(Error::CacheWrite)?;
// If there are build settings, we need to scope to a cache shard.
let config_settings = self.build_context.config_settings();
let config_settings = self.config_settings_for(source.name());
let cache_shard = if config_settings.is_empty() {
cache_shard
} else {
cache_shard.shard(cache_digest(config_settings))
cache_shard.shard(cache_digest(&config_settings))
};
// If the cache contains a compatible wheel, return it.
@ -1779,11 +1796,11 @@ impl<'a, T: BuildContext> SourceDistributionBuilder<'a, T> {
}
// If there are build settings, we need to scope to a cache shard.
let config_settings = self.build_context.config_settings();
let config_settings = self.config_settings_for(source.name());
let cache_shard = if config_settings.is_empty() {
cache_shard
} else {
cache_shard.shard(cache_digest(config_settings))
cache_shard.shard(cache_digest(&config_settings))
};
// Otherwise, we need to build a wheel.