Skip to content

Commit 81b723f

Browse files
committed
Refuse to remove non-virtual environments in uv venv
1 parent 0ef2f9f commit 81b723f

File tree

2 files changed

+16
-2
lines changed

2 files changed

+16
-2
lines changed

crates/uv-virtualenv/src/lib.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
use std::io;
2-
use std::path::Path;
2+
use std::path::{Path, PathBuf};
33

44
use thiserror::Error;
55

66
use uv_preview::Preview;
77
use uv_python::{Interpreter, PythonEnvironment};
8+
use uv_fs::{Simplified};
89

910
pub use virtualenv::{OnExisting, remove_virtualenv};
1011

@@ -20,6 +21,8 @@ pub enum Error {
2021
NotFound(String),
2122
#[error(transparent)]
2223
Python(#[from] uv_python::managed::Error),
24+
#[error("The directory at `{}` is not a virtual environment; remove it manually to proceed", _0.user_display())]
25+
NonVirtualEnvironment(PathBuf),
2326
}
2427

2528
/// The value to use for the shell prompt when inside a virtual environment.

crates/uv-virtualenv/src/virtualenv.rs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,8 @@ pub(crate) fn create(
110110
);
111111
}
112112
Ok(metadata) if metadata.is_dir() => {
113-
let name = if uv_fs::is_virtualenv_base(location) {
113+
let is_virtualenv = uv_fs::is_virtualenv_base(location);
114+
let name = if is_virtualenv {
114115
"virtual environment"
115116
} else {
116117
"directory"
@@ -120,6 +121,11 @@ pub(crate) fn create(
120121
debug!("Allowing existing {name} due to `--allow-existing`");
121122
}
122123
OnExisting::Remove => {
124+
// Refuse to remove a non-virtual environment, even if `--clear` is provided.
125+
if !is_virtualenv {
126+
return Err(Error::NonVirtualEnvironment(location.to_path_buf()));
127+
}
128+
123129
debug!("Removing existing {name} due to `--clear`");
124130
// Before removing the virtual environment, we need to canonicalize the path
125131
// because `Path::metadata` will follow the symlink but we're still operating on
@@ -131,6 +137,11 @@ pub(crate) fn create(
131137
fs::create_dir_all(&location)?;
132138
}
133139
OnExisting::Fail => {
140+
// Refuse to remove a non-virtual environment.
141+
if !is_virtualenv {
142+
return Err(Error::NonVirtualEnvironment(location.to_path_buf()));
143+
}
144+
134145
match confirm_clear(location, name)? {
135146
Some(true) => {
136147
debug!("Removing existing {name} due to confirmation");

0 commit comments

Comments
 (0)