diff --git a/Cargo.lock b/Cargo.lock index dbbfa8b41..07396ff49 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5095,11 +5095,11 @@ dependencies = [ "toml", "tracing", "url", - "uv-dirs", "uv-keyring", "uv-once-map", "uv-redacted", "uv-small-str", + "uv-state", "uv-static", "uv-warnings", "wiremock", diff --git a/crates/uv-auth/Cargo.toml b/crates/uv-auth/Cargo.toml index 327e6c487..cf28700f2 100644 --- a/crates/uv-auth/Cargo.toml +++ b/crates/uv-auth/Cargo.toml @@ -10,12 +10,12 @@ doctest = false workspace = true [dependencies] -uv-dirs = { workspace = true } uv-keyring = { workspace = true, features = ["apple-native", "secret-service", "windows-native"] } uv-once-map = { workspace = true } uv-redacted = { workspace = true } uv-small-str = { workspace = true } uv-static = { workspace = true } +uv-state = { workspace = true } uv-warnings = { workspace = true } anyhow = { workspace = true } diff --git a/crates/uv-auth/src/middleware.rs b/crates/uv-auth/src/middleware.rs index 5e3350e96..46bffb1d6 100644 --- a/crates/uv-auth/src/middleware.rs +++ b/crates/uv-auth/src/middleware.rs @@ -65,25 +65,25 @@ impl Default for TextStoreMode { // TODO(zanieb): Reconsider this pattern. We're just mirroring the [`NetrcMode`] // implementation for now. Self::Automatic(LazyLock::new(|| { - let state_dir = uv_dirs::user_state_dir()?; - let credentials_path = state_dir.join("credentials").join("credentials.toml"); + let path = TextCredentialStore::default_file() + .inspect_err(|err| { + warn!("Failed to determine credentials file path: {}", err); + }) + .ok()?; - match TextCredentialStore::from_file(&credentials_path) { + match TextCredentialStore::from_file(&path) { Ok(store) => { - debug!("Loaded credential file {}", credentials_path.display()); + debug!("Loaded credential file {}", path.display()); Some(store) } Err(TomlCredentialError::Io(err)) if err.kind() == std::io::ErrorKind::NotFound => { - debug!( - "No credentials file found at {}", - credentials_path.display() - ); + debug!("No credentials file found at {}", path.display()); None } Err(err) => { warn!( "Failed to load credentials from {}: {}", - credentials_path.display(), + path.display(), err ); None diff --git a/crates/uv-auth/src/store.rs b/crates/uv-auth/src/store.rs index d06ff0d13..dd3bbbd3e 100644 --- a/crates/uv-auth/src/store.rs +++ b/crates/uv-auth/src/store.rs @@ -9,6 +9,9 @@ use tracing::debug; use url::Url; use uv_redacted::DisplaySafeUrl; +use uv_state::{StateBucket, StateStore}; +use uv_static::EnvVars; + use crate::Credentials; use crate::credentials::{Password, Username}; use crate::realm::Realm; @@ -182,12 +185,22 @@ pub struct TextCredentialStore { } impl TextCredentialStore { - /// Return the default credential file path. + /// Return the directory for storing credentials. + fn directory_path() -> Result { + if let Some(dir) = std::env::var_os(EnvVars::UV_CREDENTIALS_DIR) + .filter(|s| !s.is_empty()) + .map(PathBuf::from) + { + return Ok(dir); + } + + Ok(StateStore::from_settings(None)?.bucket(StateBucket::Credentials)) + } + + /// Return the standard file path for storing credentials. pub fn default_file() -> Result { - let state_dir = - uv_dirs::user_state_dir().ok_or(TomlCredentialError::CredentialsDirError)?; - let credentials_dir = state_dir.join("credentials"); - Ok(credentials_dir.join("credentials.toml")) + let dir = Self::directory_path()?; + Ok(dir.join("credentials.toml")) } /// Read credentials from a file. diff --git a/crates/uv-static/src/env_vars.rs b/crates/uv-static/src/env_vars.rs index e6427c0f3..4419a7eeb 100644 --- a/crates/uv-static/src/env_vars.rs +++ b/crates/uv-static/src/env_vars.rs @@ -45,6 +45,9 @@ impl EnvVars { /// directory for caching instead of the default cache directory. pub const UV_CACHE_DIR: &'static str = "UV_CACHE_DIR"; + /// The directory for storage of credentials when using a plain text backend. + pub const UV_CREDENTIALS_DIR: &'static str = "UV_CREDENTIALS_DIR"; + /// Equivalent to the `--no-cache` command-line argument. If set, uv will not use the /// cache for any operations. pub const UV_NO_CACHE: &'static str = "UV_NO_CACHE"; diff --git a/docs/reference/environment.md b/docs/reference/environment.md index 3b017178d..00cd39760 100644 --- a/docs/reference/environment.md +++ b/docs/reference/environment.md @@ -55,6 +55,10 @@ local `uv.toml` file to use as the configuration file. Equivalent to the `--constraint` command-line argument. If set, uv will use this file as the constraints file. Uses space-separated list of files. +### `UV_CREDENTIALS_DIR` + +The directory for storage of credentials when using a plain text backend. + ### `UV_CUSTOM_COMPILE_COMMAND` Equivalent to the `--custom-compile-command` command-line argument.