Skip to content

Commit 762fbf6

Browse files
committed
Use async and write docs
1 parent 953f8b2 commit 762fbf6

File tree

27 files changed

+349
-301
lines changed

27 files changed

+349
-301
lines changed

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,7 @@ tempfile = { version = "3.14.0" }
181181
textwrap = { version = "0.16.1" }
182182
thiserror = { version = "2.0.0" }
183183
tl = { git = "https://github.com/astral-sh/tl.git", rev = "6e25b2ee2513d75385101a8ff9f591ef51f314ec" }
184-
tokio = { version = "1.40.0", features = ["fs", "io-util", "macros", "process", "rt", "signal", "sync"] }
184+
tokio = { version = "1.40.0", features = ["fs", "io-util", "macros", "process", "rt", "signal", "sync", "time"] }
185185
tokio-stream = { version = "0.1.16" }
186186
tokio-util = { version = "0.7.12", features = ["compat", "io"] }
187187
toml = { version = "0.9.2", features = ["fast_hash"] }

crates/uv-auth/src/middleware.rs

Lines changed: 38 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -60,53 +60,55 @@ impl NetrcMode {
6060

6161
/// Strategy for loading text-based credential files.
6262
enum TextStoreMode {
63-
Automatic(LazyLock<Option<TextCredentialStore>>),
63+
Automatic(tokio::sync::OnceCell<Option<TextCredentialStore>>),
6464
Enabled(TextCredentialStore),
6565
Disabled,
6666
}
6767

6868
impl Default for TextStoreMode {
6969
fn default() -> Self {
70-
// TODO(zanieb): Reconsider this pattern. We're just mirroring the [`NetrcMode`]
71-
// implementation for now.
72-
Self::Automatic(LazyLock::new(|| {
73-
let path = TextCredentialStore::default_file()
74-
.inspect_err(|err| {
75-
warn!("Failed to determine credentials file path: {}", err);
76-
})
77-
.ok()?;
78-
79-
match TextCredentialStore::read(&path) {
80-
Ok((store, _lock)) => {
81-
debug!("Loaded credential file {}", path.display());
82-
Some(store)
83-
}
84-
Err(err)
85-
if err
86-
.as_io_error()
87-
.is_some_and(|err| err.kind() == std::io::ErrorKind::NotFound) =>
88-
{
89-
debug!("No credentials file found at {}", path.display());
90-
None
91-
}
92-
Err(err) => {
93-
warn!(
94-
"Failed to load credentials from {}: {}",
95-
path.display(),
96-
err
97-
);
98-
None
99-
}
100-
}
101-
}))
70+
Self::Automatic(tokio::sync::OnceCell::new())
10271
}
10372
}
10473

10574
impl TextStoreMode {
75+
async fn load_default_store() -> Option<TextCredentialStore> {
76+
let path = TextCredentialStore::default_file()
77+
.inspect_err(|err| {
78+
warn!("Failed to determine credentials file path: {}", err);
79+
})
80+
.ok()?;
81+
82+
match TextCredentialStore::read(&path).await {
83+
Ok((store, _lock)) => {
84+
debug!("Loaded credential file {}", path.display());
85+
Some(store)
86+
}
87+
Err(err)
88+
if err
89+
.as_io_error()
90+
.is_some_and(|err| err.kind() == std::io::ErrorKind::NotFound) =>
91+
{
92+
debug!("No credentials file found at {}", path.display());
93+
None
94+
}
95+
Err(err) => {
96+
warn!(
97+
"Failed to load credentials from {}: {}",
98+
path.display(),
99+
err
100+
);
101+
None
102+
}
103+
}
104+
}
105+
106106
/// Get the parsed credential store, if enabled.
107-
fn get(&self) -> Option<&TextCredentialStore> {
107+
async fn get(&self) -> Option<&TextCredentialStore> {
108108
match self {
109-
Self::Automatic(lock) => lock.as_ref(),
109+
// TODO(zanieb): Reconsider this pattern. We're just mirroring the [`NetrcMode`]
110+
// implementation for now.
111+
Self::Automatic(lock) => lock.get_or_init(Self::load_default_store).await.as_ref(),
110112
Self::Enabled(store) => Some(store),
111113
Self::Disabled => None,
112114
}
@@ -724,7 +726,7 @@ impl AuthMiddleware {
724726
Some(credentials)
725727

726728
// Text credential store support.
727-
} else if let Some(credentials) = self.text_store.get().and_then(|text_store| {
729+
} else if let Some(credentials) = self.text_store.get().await.and_then(|text_store| {
728730
debug!("Checking text store for credentials for {url}");
729731
text_store.get_credentials(url, credentials.as_ref().and_then(|credentials| credentials.username())).cloned()
730732
}) {

crates/uv-auth/src/store.rs

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use rustc_hash::FxHashMap;
66
use serde::{Deserialize, Serialize};
77
use thiserror::Error;
88
use url::Url;
9-
use uv_fs::{LockedFile, LockedFileError, with_added_extension};
9+
use uv_fs::{LockedFile, LockedFileError, LockedFileMode, with_added_extension};
1010
use uv_preview::{Preview, PreviewFeatures};
1111
use uv_redacted::DisplaySafeUrl;
1212

@@ -29,15 +29,15 @@ pub enum AuthBackend {
2929
}
3030

3131
impl AuthBackend {
32-
pub fn from_settings(preview: Preview) -> Result<Self, TomlCredentialError> {
32+
pub async fn from_settings(preview: Preview) -> Result<Self, TomlCredentialError> {
3333
// If preview is enabled, we'll use the system-native store
3434
if preview.is_enabled(PreviewFeatures::NATIVE_AUTH) {
3535
return Ok(Self::System(KeyringProvider::native()));
3636
}
3737

3838
// Otherwise, we'll use the plaintext credential store
3939
let path = TextCredentialStore::default_file()?;
40-
match TextCredentialStore::read(&path) {
40+
match TextCredentialStore::read(&path).await {
4141
Ok((store, lock)) => Ok(Self::TextStore(store, lock)),
4242
Err(err)
4343
if err
@@ -46,7 +46,7 @@ impl AuthBackend {
4646
{
4747
Ok(Self::TextStore(
4848
TextCredentialStore::default(),
49-
TextCredentialStore::lock(&path)?,
49+
TextCredentialStore::lock(&path).await?,
5050
))
5151
}
5252
Err(err) => Err(err),
@@ -255,12 +255,12 @@ impl TextCredentialStore {
255255
}
256256

257257
/// Acquire a lock on the credentials file at the given path.
258-
pub fn lock(path: &Path) -> Result<LockedFile, TomlCredentialError> {
258+
pub async fn lock(path: &Path) -> Result<LockedFile, TomlCredentialError> {
259259
if let Some(parent) = path.parent() {
260260
fs::create_dir_all(parent)?;
261261
}
262262
let lock = with_added_extension(path, ".lock");
263-
Ok(LockedFile::acquire_blocking(lock, "credentials store")?)
263+
Ok(LockedFile::acquire(lock, LockedFileMode::Exclusive, "credentials store").await?)
264264
}
265265

266266
/// Read credentials from a file.
@@ -291,8 +291,8 @@ impl TextCredentialStore {
291291
/// Returns [`TextCredentialStore`] and a [`LockedFile`] to hold if mutating the store.
292292
///
293293
/// If the store will not be written to following the read, the lock can be dropped.
294-
pub fn read<P: AsRef<Path>>(path: P) -> Result<(Self, LockedFile), TomlCredentialError> {
295-
let lock = Self::lock(path.as_ref())?;
294+
pub async fn read<P: AsRef<Path>>(path: P) -> Result<(Self, LockedFile), TomlCredentialError> {
295+
let lock = Self::lock(path.as_ref()).await?;
296296
let store = Self::from_file(path)?;
297297
Ok((store, lock))
298298
}
@@ -468,8 +468,8 @@ mod tests {
468468
assert!(store.get_credentials(&url, None).is_none());
469469
}
470470

471-
#[test]
472-
fn test_file_operations() {
471+
#[tokio::test]
472+
async fn test_file_operations() {
473473
let mut temp_file = NamedTempFile::new().unwrap();
474474
writeln!(
475475
temp_file,
@@ -505,7 +505,7 @@ password = "pass2"
505505
store
506506
.write(
507507
temp_output.path(),
508-
TextCredentialStore::lock(temp_file.path()).unwrap(),
508+
TextCredentialStore::lock(temp_file.path()).await.unwrap(),
509509
)
510510
.unwrap();
511511

crates/uv-bench/benches/uv.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,10 @@ fn setup(manifest: Manifest) -> impl Fn(bool) {
5959
.build()
6060
.unwrap();
6161

62-
let cache = Cache::from_path("../../.cache").init().unwrap();
62+
let cache = Cache::from_path("../../.cache")
63+
.init_no_wait()
64+
.expect("No cache contention when running benchmarks")
65+
.unwrap();
6366
let interpreter = PythonEnvironment::from_root("../../.venv", &cache)
6467
.unwrap()
6568
.into_interpreter();

crates/uv-build-frontend/src/lib.rs

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ use uv_distribution_types::{
3636
ConfigSettings, ExtraBuildRequirement, ExtraBuildRequires, IndexLocations, Requirement,
3737
Resolution,
3838
};
39-
use uv_fs::LockedFile;
39+
use uv_fs::{LockedFile, LockedFileMode};
4040
use uv_fs::{PythonExt, Simplified};
4141
use uv_normalize::PackageName;
4242
use uv_pep440::Version;
@@ -493,12 +493,16 @@ impl SourceBuild {
493493
"uv-setuptools-{}.lock",
494494
cache_digest(&canonical_source_path)
495495
));
496-
source_tree_lock = LockedFile::acquire(lock_path, self.source_tree.to_string_lossy())
497-
.await
498-
.inspect_err(|err| {
499-
warn!("Failed to acquire build lock: {err}");
500-
})
501-
.ok();
496+
source_tree_lock = LockedFile::acquire(
497+
lock_path,
498+
LockedFileMode::Exclusive,
499+
self.source_tree.to_string_lossy(),
500+
)
501+
.await
502+
.inspect_err(|err| {
503+
warn!("Failed to acquire build lock: {err}");
504+
})
505+
.ok();
502506
}
503507
Ok(source_tree_lock)
504508
}

0 commit comments

Comments
 (0)