mirror of
https://github.com/astral-sh/uv.git
synced 2025-11-19 11:35:36 +00:00
Update virtual environment removal to delete pyvenv.cfg last (#14808)
An alternative to https://github.com/astral-sh/uv/pull/14569 This isn't a complete solution to https://github.com/astral-sh/uv/issues/13986, in the sense that it's still "fatal" to `uv sync` if we fail to delete an environment, but I think that's okay — deferring deletion is much more complicated. This at least doesn't break users once the deletion fails. The downside is we'll generally treat this virtual environment is valid, even if we nuked a bunch of it. Closes https://github.com/astral-sh/uv/issues/13986
This commit is contained in:
parent
8bffa693b4
commit
c8486da495
3 changed files with 34 additions and 10 deletions
|
|
@ -6,7 +6,7 @@ use thiserror::Error;
|
|||
use uv_configuration::PreviewMode;
|
||||
use uv_python::{Interpreter, PythonEnvironment};
|
||||
|
||||
pub use virtualenv::OnExisting;
|
||||
pub use virtualenv::{OnExisting, remove_virtualenv};
|
||||
|
||||
mod virtualenv;
|
||||
|
||||
|
|
|
|||
|
|
@ -97,7 +97,8 @@ pub(crate) fn create(
|
|||
}
|
||||
OnExisting::Remove => {
|
||||
debug!("Removing existing {name} due to `--clear`");
|
||||
remove_venv_directory(location)?;
|
||||
remove_virtualenv(location)?;
|
||||
fs::create_dir_all(location)?;
|
||||
}
|
||||
OnExisting::Fail
|
||||
if location
|
||||
|
|
@ -110,7 +111,8 @@ pub(crate) fn create(
|
|||
match confirm_clear(location, name)? {
|
||||
Some(true) => {
|
||||
debug!("Removing existing {name} due to confirmation");
|
||||
remove_venv_directory(location)?;
|
||||
remove_virtualenv(location)?;
|
||||
fs::create_dir_all(location)?;
|
||||
}
|
||||
Some(false) => {
|
||||
let hint = format!(
|
||||
|
|
@ -566,9 +568,10 @@ fn confirm_clear(location: &Path, name: &'static str) -> Result<Option<bool>, io
|
|||
}
|
||||
}
|
||||
|
||||
fn remove_venv_directory(location: &Path) -> Result<(), Error> {
|
||||
// On Windows, if the current executable is in the directory, guard against
|
||||
// self-deletion.
|
||||
/// Perform a safe removal of a virtual environment.
|
||||
pub fn remove_virtualenv(location: &Path) -> Result<(), Error> {
|
||||
// On Windows, if the current executable is in the directory, defer self-deletion since Windows
|
||||
// won't let you unlink a running executable.
|
||||
#[cfg(windows)]
|
||||
if let Ok(itself) = std::env::current_exe() {
|
||||
let target = std::path::absolute(location)?;
|
||||
|
|
@ -578,8 +581,27 @@ fn remove_venv_directory(location: &Path) -> Result<(), Error> {
|
|||
}
|
||||
}
|
||||
|
||||
// We defer removal of the `pyvenv.cfg` until the end, so if we fail to remove the environment,
|
||||
// uv can still identify it as a Python virtual environment that can be deleted.
|
||||
for entry in fs::read_dir(location)? {
|
||||
let entry = entry?;
|
||||
let path = entry.path();
|
||||
if path == location.join("pyvenv.cfg") {
|
||||
continue;
|
||||
}
|
||||
if path.is_dir() {
|
||||
fs::remove_dir_all(&path)?;
|
||||
} else {
|
||||
fs::remove_file(&path)?;
|
||||
}
|
||||
}
|
||||
|
||||
match fs::remove_file(location.join("pyvenv.cfg")) {
|
||||
Ok(()) => {}
|
||||
Err(err) if err.kind() == io::ErrorKind::NotFound => {}
|
||||
Err(err) => return Err(err.into()),
|
||||
}
|
||||
fs::remove_dir_all(location)?;
|
||||
fs::create_dir_all(location)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue