mirror of https://github.com/astral-sh/uv
Show resource and lockfile when waiting (#715)
We lock git checkout directories and the virtualenv to avoid two puffin instances running in parallel changing files at the same time and leading to a broken state. When one instance is blocking another, we need to inform the user (why is the program hanging?) and also add some information for them to debug the situation. The new messages will print ``` Waiting to acquire lock for /home/konsti/projects/puffin/.venv (lockfile: /home/konsti/projects/puffin/.venv/.lock) ``` or ``` Waiting to acquire lock for git+https://github.com/pydantic/pydantic-extra-types@0ce9f207a1e09a862287ab77512f0060c1625223 (lockfile: /home/konsti/projects/puffin/cache-all-kinds/git-v0/locks/f157fd329a506a34) ``` The messages aren't perfect but clear enough to see what the contention is and in the worst case to delete the lockfile. Fixes #714
This commit is contained in:
parent
e60f0ec732
commit
b7ad97a823
|
|
@ -1,3 +1,4 @@
|
||||||
|
use std::fmt::{Debug, Formatter};
|
||||||
use std::hash::{Hash, Hasher};
|
use std::hash::{Hash, Hasher};
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
|
|
||||||
|
|
@ -85,6 +86,12 @@ impl Hash for CanonicalUrl {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Display for CanonicalUrl {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
|
std::fmt::Display::fmt(&self.0, f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Like [`CanonicalUrl`], but attempts to represent an underlying source repository, abstracting
|
/// Like [`CanonicalUrl`], but attempts to represent an underlying source repository, abstracting
|
||||||
/// away details like the specific commit or branch, or the subdirectory to build within the
|
/// away details like the specific commit or branch, or the subdirectory to build within the
|
||||||
/// repository.
|
/// repository.
|
||||||
|
|
|
||||||
|
|
@ -653,7 +653,8 @@ impl<'a, T: BuildContext> SourceDistCachedBuilder<'a, T> {
|
||||||
// Avoid races between different processes, too.
|
// Avoid races between different processes, too.
|
||||||
let lock_dir = git_dir.join("locks");
|
let lock_dir = git_dir.join("locks");
|
||||||
fs::create_dir_all(&lock_dir).await?;
|
fs::create_dir_all(&lock_dir).await?;
|
||||||
let _lock = LockedFile::acquire(lock_dir.join(digest(&CanonicalUrl::new(url))))?;
|
let canonical_url = CanonicalUrl::new(url);
|
||||||
|
let _lock = LockedFile::acquire(lock_dir.join(digest(&canonical_url)), &canonical_url)?;
|
||||||
|
|
||||||
let DirectGitUrl { url, subdirectory } =
|
let DirectGitUrl { url, subdirectory } =
|
||||||
DirectGitUrl::try_from(url).map_err(SourceDistError::Git)?;
|
DirectGitUrl::try_from(url).map_err(SourceDistError::Git)?;
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
use std::fmt::Display;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
use fs2::FileExt;
|
use fs2::FileExt;
|
||||||
|
|
@ -99,14 +100,15 @@ pub fn directories(path: impl AsRef<Path>) -> impl Iterator<Item = PathBuf> {
|
||||||
pub struct LockedFile(fs_err::File);
|
pub struct LockedFile(fs_err::File);
|
||||||
|
|
||||||
impl LockedFile {
|
impl LockedFile {
|
||||||
pub fn acquire(path: impl AsRef<Path>) -> Result<Self, std::io::Error> {
|
pub fn acquire(path: impl AsRef<Path>, resource: impl Display) -> Result<Self, std::io::Error> {
|
||||||
let file = fs_err::File::create(path.as_ref())?;
|
let file = fs_err::File::create(path.as_ref())?;
|
||||||
match file.file().try_lock_exclusive() {
|
match file.file().try_lock_exclusive() {
|
||||||
Ok(()) => Ok(Self(file)),
|
Ok(()) => Ok(Self(file)),
|
||||||
Err(err) if err.kind() == std::io::ErrorKind::WouldBlock => {
|
Err(err) if err.kind() == std::io::ErrorKind::WouldBlock => {
|
||||||
warn_user!(
|
warn_user!(
|
||||||
"Waiting to acquire lock on {}",
|
"Waiting to acquire lock for {} (lockfile: {})",
|
||||||
path.as_ref().parent().unwrap_or(path.as_ref()).display()
|
resource,
|
||||||
|
path.as_ref().display()
|
||||||
);
|
);
|
||||||
file.file().lock_exclusive()?;
|
file.file().lock_exclusive()?;
|
||||||
Ok(Self(file))
|
Ok(Self(file))
|
||||||
|
|
|
||||||
|
|
@ -104,7 +104,7 @@ impl Virtualenv {
|
||||||
|
|
||||||
/// Lock the virtual environment to prevent concurrent writes.
|
/// Lock the virtual environment to prevent concurrent writes.
|
||||||
pub fn lock(&self) -> Result<LockedFile, std::io::Error> {
|
pub fn lock(&self) -> Result<LockedFile, std::io::Error> {
|
||||||
LockedFile::acquire(self.root.join(".lock"))
|
LockedFile::acquire(self.root.join(".lock"), self.root.display())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue