Make cache_index_credentials() misuse resistant (#15546)

https://github.com/astral-sh/uv/issues/11836#issuecomment-3022735011 was
caused by a missing `cache_index_credentials()` call. This call was
always preceding a registry client builder. We can improve this
situation by caching index credentials in the registry client builder.
This commit is contained in:
konsti 2025-08-29 17:11:54 +02:00 committed by GitHub
parent d877899920
commit 882c9d9482
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
14 changed files with 34 additions and 55 deletions

View file

@ -48,7 +48,7 @@ use crate::{
/// A builder for an [`RegistryClient`].
#[derive(Debug, Clone)]
pub struct RegistryClientBuilder<'a> {
index_urls: IndexUrls,
index_locations: IndexLocations,
index_strategy: IndexStrategy,
torch_backend: Option<TorchStrategy>,
cache: Cache,
@ -58,7 +58,7 @@ pub struct RegistryClientBuilder<'a> {
impl RegistryClientBuilder<'_> {
pub fn new(cache: Cache) -> Self {
Self {
index_urls: IndexUrls::default(),
index_locations: IndexLocations::default(),
index_strategy: IndexStrategy::default(),
torch_backend: None,
cache,
@ -75,11 +75,8 @@ impl<'a> RegistryClientBuilder<'a> {
}
#[must_use]
pub fn index_locations(mut self, index_locations: &IndexLocations) -> Self {
self.index_urls = index_locations.index_urls();
self.base_client_builder = self
.base_client_builder
.indexes(Indexes::from(index_locations));
pub fn index_locations(mut self, index_locations: IndexLocations) -> Self {
self.index_locations = index_locations;
self
}
@ -183,9 +180,13 @@ impl<'a> RegistryClientBuilder<'a> {
}
pub fn build(self) -> RegistryClient {
self.index_locations.cache_index_credentials();
let index_urls = self.index_locations.index_urls();
// Build a base client
let builder = self
.base_client_builder
.indexes(Indexes::from(&self.index_locations))
.redirect(RedirectPolicy::RetriggerMiddleware);
let client = builder.build();
@ -197,7 +198,7 @@ impl<'a> RegistryClientBuilder<'a> {
let client = CachedClient::new(client);
RegistryClient {
index_urls: self.index_urls,
index_urls,
index_strategy: self.index_strategy,
torch_backend: self.torch_backend,
cache: self.cache,
@ -210,8 +211,14 @@ impl<'a> RegistryClientBuilder<'a> {
/// Share the underlying client between two different middleware configurations.
pub fn wrap_existing(self, existing: &BaseClient) -> RegistryClient {
self.index_locations.cache_index_credentials();
let index_urls = self.index_locations.index_urls();
// Wrap in any relevant middleware and handle connectivity.
let client = self.base_client_builder.wrap_existing(existing);
let client = self
.base_client_builder
.indexes(Indexes::from(&self.index_locations))
.wrap_existing(existing);
let timeout = client.timeout();
let connectivity = client.connectivity();
@ -220,7 +227,7 @@ impl<'a> RegistryClientBuilder<'a> {
let client = CachedClient::new(client);
RegistryClient {
index_urls: self.index_urls,
index_urls,
index_strategy: self.index_strategy,
torch_backend: self.torch_backend,
cache: self.cache,
@ -237,7 +244,7 @@ impl<'a> TryFrom<BaseClientBuilder<'a>> for RegistryClientBuilder<'a> {
fn try_from(value: BaseClientBuilder<'a>) -> Result<Self, Self::Error> {
Ok(Self {
index_urls: IndexUrls::default(),
index_locations: IndexLocations::default(),
index_strategy: IndexStrategy::default(),
torch_backend: None,
cache: Cache::temp()?,

View file

@ -527,8 +527,6 @@ async fn build_package(
.await?
.into_interpreter();
index_locations.cache_index_credentials();
// Read build constraints.
let build_constraints =
operations::read_constraints(build_constraints, &client_builder).await?;
@ -556,7 +554,7 @@ async fn build_package(
// Initialize the registry client.
let client = RegistryClientBuilder::try_from(client_builder)?
.cache(cache.clone())
.index_locations(index_locations)
.index_locations(index_locations.clone())
.index_strategy(index_strategy)
.keyring(keyring_provider)
.markers(interpreter.markers())

View file

@ -405,8 +405,6 @@ pub(crate) async fn pip_compile(
no_index,
);
index_locations.cache_index_credentials();
// Determine the PyTorch backend.
let torch_backend = torch_backend
.map(|mode| {
@ -424,7 +422,7 @@ pub(crate) async fn pip_compile(
// Initialize the registry client.
let client = RegistryClientBuilder::try_from(client_builder)?
.cache(cache.clone())
.index_locations(&index_locations)
.index_locations(index_locations.clone())
.index_strategy(index_strategy)
.torch_backend(torch_backend.clone())
.markers(interpreter.markers())

View file

@ -368,8 +368,6 @@ pub(crate) async fn pip_install(
no_index,
);
index_locations.cache_index_credentials();
// Determine the PyTorch backend.
let torch_backend = torch_backend
.map(|mode| {
@ -387,7 +385,7 @@ pub(crate) async fn pip_install(
// Initialize the registry client.
let client = RegistryClientBuilder::try_from(client_builder)?
.cache(cache.clone())
.index_locations(&index_locations)
.index_locations(index_locations.clone())
.index_strategy(index_strategy)
.torch_backend(torch_backend.clone())
.markers(interpreter.markers())

View file

@ -98,7 +98,7 @@ pub(crate) async fn pip_list(
// Initialize the registry client.
let client = RegistryClientBuilder::try_from(client_builder)?
.cache(cache.clone().with_refresh(Refresh::All(Timestamp::now())))
.index_locations(&index_locations)
.index_locations(index_locations)
.index_strategy(index_strategy)
.markers(environment.interpreter().markers())
.platform(environment.interpreter().platform())

View file

@ -292,8 +292,6 @@ pub(crate) async fn pip_sync(
no_index,
);
index_locations.cache_index_credentials();
// Determine the PyTorch backend.
let torch_backend = torch_backend
.map(|mode| {
@ -311,7 +309,7 @@ pub(crate) async fn pip_sync(
// Initialize the registry client.
let client = RegistryClientBuilder::try_from(client_builder)?
.cache(cache.clone())
.index_locations(&index_locations)
.index_locations(index_locations.clone())
.index_strategy(index_strategy)
.torch_backend(torch_backend.clone())
.markers(interpreter.markers())

View file

@ -98,7 +98,7 @@ pub(crate) async fn pip_tree(
// Initialize the registry client.
let client = RegistryClientBuilder::try_from(client_builder)?
.cache(cache.clone().with_refresh(Refresh::All(Timestamp::now())))
.index_locations(&index_locations)
.index_locations(index_locations)
.index_strategy(index_strategy)
.markers(environment.interpreter().markers())
.platform(environment.interpreter().platform())

View file

@ -399,11 +399,9 @@ pub(crate) async fn add(
let hasher = HashStrategy::default();
let sources = SourceStrategy::Enabled;
settings.resolver.index_locations.cache_index_credentials();
// Initialize the registry client.
let client = RegistryClientBuilder::try_from(client_builder)?
.index_locations(&settings.resolver.index_locations)
.index_locations(settings.resolver.index_locations.clone())
.index_strategy(settings.resolver.index_strategy)
.markers(target.interpreter().markers())
.platform(target.interpreter().platform())

View file

@ -628,8 +628,6 @@ async fn do_lock(
.keyring(*keyring_provider)
.allow_insecure_host(network_settings.allow_insecure_host.clone());
index_locations.cache_index_credentials();
for index in target.indexes() {
if let Some(credentials) = index.credentials() {
let credentials = Arc::new(credentials);
@ -643,7 +641,7 @@ async fn do_lock(
// Initialize the registry client.
let client = RegistryClientBuilder::try_from(client_builder)?
.cache(cache.clone())
.index_locations(index_locations)
.index_locations(index_locations.clone())
.index_strategy(*index_strategy)
.markers(interpreter.markers())
.platform(interpreter.platform())

View file

@ -1728,12 +1728,10 @@ pub(crate) async fn resolve_names(
.keyring(*keyring_provider)
.allow_insecure_host(network_settings.allow_insecure_host.clone());
index_locations.cache_index_credentials();
// Initialize the registry client.
let client = RegistryClientBuilder::try_from(client_builder)?
.cache(cache.clone())
.index_locations(index_locations)
.index_locations(index_locations.clone())
.index_strategy(*index_strategy)
.markers(interpreter.markers())
.platform(interpreter.platform())
@ -1904,12 +1902,10 @@ pub(crate) async fn resolve_environment(
let marker_env = pip::resolution_markers(None, python_platform, interpreter);
let python_requirement = PythonRequirement::from_interpreter(interpreter);
index_locations.cache_index_credentials();
// Initialize the registry client.
let client = RegistryClientBuilder::try_from(client_builder)?
.cache(cache.clone())
.index_locations(index_locations)
.index_locations(index_locations.clone())
.index_strategy(*index_strategy)
.markers(interpreter.markers())
.platform(interpreter.platform())
@ -2089,12 +2085,10 @@ pub(crate) async fn sync_environment(
let interpreter = venv.interpreter();
let tags = venv.interpreter().tags()?;
index_locations.cache_index_credentials();
// Initialize the registry client.
let client = RegistryClientBuilder::try_from(client_builder)?
.cache(cache.clone())
.index_locations(index_locations)
.index_locations(index_locations.clone())
.index_strategy(index_strategy)
.markers(interpreter.markers())
.platform(interpreter.platform())
@ -2318,12 +2312,10 @@ pub(crate) async fn update_environment(
}
}
index_locations.cache_index_credentials();
// Initialize the registry client.
let client = RegistryClientBuilder::try_from(client_builder)?
.cache(cache.clone())
.index_locations(index_locations)
.index_locations(index_locations.clone())
.index_strategy(*index_strategy)
.markers(interpreter.markers())
.platform(interpreter.platform())

View file

@ -718,15 +718,13 @@ pub(super) async fn do_sync(
// Constrain any build requirements marked as `match-runtime = true`.
let extra_build_requires = extra_build_requires.match_runtime(&resolution)?;
index_locations.cache_index_credentials();
// Populate credentials from the target.
store_credentials_from_target(target);
// Initialize the registry client.
let client = RegistryClientBuilder::try_from(client_builder)?
.cache(cache.clone())
.index_locations(index_locations)
.index_locations(index_locations.clone())
.index_strategy(index_strategy)
.markers(venv.interpreter().markers())
.platform(venv.interpreter().platform())

View file

@ -223,7 +223,7 @@ pub(crate) async fn tree(
.native_tls(network_settings.native_tls)
.connectivity(network_settings.connectivity)
.allow_insecure_host(network_settings.allow_insecure_host.clone())
.index_locations(index_locations)
.index_locations(index_locations.clone())
.keyring(*keyring_provider)
.build();
let download_concurrency = Semaphore::new(concurrency.downloads);

View file

@ -89,13 +89,12 @@ pub(crate) async fn publish(
// Initialize the registry client.
let check_url_client = if let Some(index_url) = &check_url {
index_locations.cache_index_credentials();
let registry_client_builder = RegistryClientBuilder::new(cache.clone())
.retries_from_env()?
.native_tls(network_settings.native_tls)
.connectivity(network_settings.connectivity)
.allow_insecure_host(network_settings.allow_insecure_host.clone())
.index_locations(&index_locations)
.index_locations(index_locations)
.keyring(keyring_provider);
Some(CheckUrlClient {
index_url: index_url.clone(),

View file

@ -176,8 +176,6 @@ pub(crate) async fn venv(
python.into_interpreter()
};
index_locations.cache_index_credentials();
// Check if the discovered Python version is incompatible with the current workspace
if let Some(requires_python) = requires_python {
match validate_project_requires_python(
@ -225,13 +223,10 @@ pub(crate) async fn venv(
// Extract the interpreter.
let interpreter = venv.interpreter();
// Add all authenticated sources to the cache.
index_locations.cache_index_credentials();
// Instantiate a client.
let client = RegistryClientBuilder::try_from(client_builder)?
.cache(cache.clone())
.index_locations(index_locations)
.index_locations(index_locations.clone())
.index_strategy(index_strategy)
.keyring(keyring_provider)
.allow_insecure_host(network_settings.allow_insecure_host.clone())