mirror of
https://github.com/astral-sh/uv.git
synced 2025-11-19 19:44:40 +00:00
Avoid removing empty directories when constructing virtual environments (#14822)
Closes https://github.com/astral-sh/uv/issues/14815
I tested this with the docker-compose reproduction. You can also see a
regression test change at
2ae4464b7e
This commit is contained in:
parent
f0151f3a18
commit
076677da20
2 changed files with 59 additions and 8 deletions
|
|
@ -10,7 +10,7 @@ use fs_err as fs;
|
||||||
use fs_err::File;
|
use fs_err::File;
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use owo_colors::OwoColorize;
|
use owo_colors::OwoColorize;
|
||||||
use tracing::debug;
|
use tracing::{debug, trace};
|
||||||
|
|
||||||
use uv_configuration::PreviewMode;
|
use uv_configuration::PreviewMode;
|
||||||
use uv_fs::{CWD, Simplified, cachedir};
|
use uv_fs::{CWD, Simplified, cachedir};
|
||||||
|
|
@ -85,6 +85,18 @@ pub(crate) fn create(
|
||||||
format!("File exists at `{}`", location.user_display()),
|
format!("File exists at `{}`", location.user_display()),
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
|
Ok(metadata)
|
||||||
|
if metadata.is_dir()
|
||||||
|
&& location
|
||||||
|
.read_dir()
|
||||||
|
.is_ok_and(|mut dir| dir.next().is_none()) =>
|
||||||
|
{
|
||||||
|
// If it's an empty directory, we can proceed
|
||||||
|
trace!(
|
||||||
|
"Using empty directory at `{}` for virtual environment",
|
||||||
|
location.user_display()
|
||||||
|
);
|
||||||
|
}
|
||||||
Ok(metadata) if metadata.is_dir() => {
|
Ok(metadata) if metadata.is_dir() => {
|
||||||
let name = if uv_fs::is_virtualenv_base(location) {
|
let name = if uv_fs::is_virtualenv_base(location) {
|
||||||
"virtual environment"
|
"virtual environment"
|
||||||
|
|
@ -100,13 +112,6 @@ pub(crate) fn create(
|
||||||
remove_virtualenv(location)?;
|
remove_virtualenv(location)?;
|
||||||
fs::create_dir_all(location)?;
|
fs::create_dir_all(location)?;
|
||||||
}
|
}
|
||||||
OnExisting::Fail
|
|
||||||
if location
|
|
||||||
.read_dir()
|
|
||||||
.is_ok_and(|mut dir| dir.next().is_none()) =>
|
|
||||||
{
|
|
||||||
debug!("Ignoring empty directory");
|
|
||||||
}
|
|
||||||
OnExisting::Fail => {
|
OnExisting::Fail => {
|
||||||
match confirm_clear(location, name)? {
|
match confirm_clear(location, name)? {
|
||||||
Some(true) => {
|
Some(true) => {
|
||||||
|
|
|
||||||
|
|
@ -11393,3 +11393,49 @@ fn sync_config_settings_package() -> Result<()> {
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Ensure that when we sync to an empty virtual environment directory, we don't attempt to remove
|
||||||
|
/// it, which breaks Docker volume mounts.
|
||||||
|
#[test]
|
||||||
|
#[cfg(unix)]
|
||||||
|
fn sync_does_not_remove_empty_virtual_environment_directory() -> Result<()> {
|
||||||
|
use std::os::unix::fs::PermissionsExt;
|
||||||
|
|
||||||
|
let context = TestContext::new_with_versions(&["3.12"]);
|
||||||
|
|
||||||
|
let project_dir = context.temp_dir.child("project");
|
||||||
|
fs_err::create_dir(&project_dir)?;
|
||||||
|
|
||||||
|
let pyproject_toml = project_dir.child("pyproject.toml");
|
||||||
|
pyproject_toml.write_str(
|
||||||
|
r#"
|
||||||
|
[project]
|
||||||
|
name = "project"
|
||||||
|
version = "0.1.0"
|
||||||
|
requires-python = ">=3.12"
|
||||||
|
dependencies = ["iniconfig"]
|
||||||
|
"#,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
let venv_dir = project_dir.child(".venv");
|
||||||
|
fs_err::create_dir(&venv_dir)?;
|
||||||
|
|
||||||
|
// Ensure the parent is read-only, to prevent deletion of the virtual environment
|
||||||
|
fs_err::set_permissions(&project_dir, std::fs::Permissions::from_mode(0o555))?;
|
||||||
|
|
||||||
|
// Note we do _not_ fail to create the virtual environment — we fail later when writing to the
|
||||||
|
// project directory
|
||||||
|
uv_snapshot!(context.filters(), context.sync().current_dir(&project_dir), @r"
|
||||||
|
success: false
|
||||||
|
exit_code: 2
|
||||||
|
----- stdout -----
|
||||||
|
|
||||||
|
----- stderr -----
|
||||||
|
Using CPython 3.12.[X] interpreter at: [PYTHON-3.12]
|
||||||
|
Creating virtual environment at: .venv
|
||||||
|
Resolved 2 packages in [TIME]
|
||||||
|
error: failed to write to file `[TEMP_DIR]/project/uv.lock`: Permission denied (os error 13)
|
||||||
|
");
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue