mirror of
https://github.com/astral-sh/uv.git
synced 2025-11-23 04:55:28 +00:00
Lock entire virtualenv during modifying commands (#695)
These commands all assume that the `site-packages` are constant throughout. Closes #691.
This commit is contained in:
parent
207bb83a1c
commit
98fcb76015
10 changed files with 53 additions and 39 deletions
|
|
@ -1,8 +1,11 @@
|
|||
use std::path::{Path, PathBuf};
|
||||
|
||||
use fs2::FileExt;
|
||||
use fs_err as fs;
|
||||
use tempfile::NamedTempFile;
|
||||
use tracing::warn;
|
||||
use tracing::{error, warn};
|
||||
|
||||
use puffin_warnings::warn_user;
|
||||
|
||||
/// Write `data` to `path` atomically using a temporary file and atomic rename.
|
||||
pub async fn write_atomic(path: impl AsRef<Path>, data: impl AsRef<[u8]>) -> std::io::Result<()> {
|
||||
|
|
@ -90,3 +93,34 @@ pub fn directories(path: impl AsRef<Path>) -> impl Iterator<Item = PathBuf> {
|
|||
})
|
||||
.map(|entry| entry.path())
|
||||
}
|
||||
|
||||
/// A file lock that is automatically released when dropped.
|
||||
#[derive(Debug)]
|
||||
pub struct LockedFile(fs_err::File);
|
||||
|
||||
impl LockedFile {
|
||||
pub fn acquire(path: impl AsRef<Path>) -> Result<Self, std::io::Error> {
|
||||
let file = fs_err::File::create(path.as_ref())?;
|
||||
match file.file().try_lock_exclusive() {
|
||||
Ok(()) => Ok(Self(file)),
|
||||
Err(err) if err.kind() == std::io::ErrorKind::WouldBlock => {
|
||||
warn_user!("Waiting to acquire lock on directory");
|
||||
file.file().lock_exclusive()?;
|
||||
Ok(Self(file))
|
||||
}
|
||||
Err(err) => Err(err),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for LockedFile {
|
||||
fn drop(&mut self) {
|
||||
if let Err(err) = self.0.file().unlock() {
|
||||
error!(
|
||||
"Failed to unlock {}; program may be stuck: {}",
|
||||
self.0.path().display(),
|
||||
err
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue