mirror of https://github.com/astral-sh/uv
Detect cases where uv partially removed a virtual environment and retry
This commit is contained in:
parent
081e2010df
commit
89edcbefd3
|
|
@ -920,7 +920,9 @@ impl ProjectInterpreter {
|
|||
));
|
||||
}
|
||||
InvalidEnvironmentKind::MissingExecutable(_) => {
|
||||
if fs_err::read_dir(&root).is_ok_and(|mut dir| dir.next().is_some()) {
|
||||
if fs_err::read_dir(&root).is_ok_and(|mut dir| dir.next().is_some())
|
||||
&& !root.join(".uv-partial-rm").try_exists().unwrap_or(false)
|
||||
{
|
||||
return Err(ProjectError::InvalidProjectEnvironmentDir(
|
||||
root,
|
||||
"it is not a valid Python environment (no Python executable was found)"
|
||||
|
|
@ -1294,6 +1296,9 @@ impl ProjectEnvironment {
|
|||
// Unless it's empty, in which case we just ignore it
|
||||
if root.read_dir().is_ok_and(|mut dir| dir.next().is_none()) {
|
||||
false
|
||||
// Or, if there's a marker file indicating a previous removal failed
|
||||
} else if root.join(".uv-partial-rm").try_exists().unwrap_or(false) {
|
||||
true
|
||||
} else {
|
||||
return Err(ProjectError::InvalidProjectEnvironmentDir(
|
||||
root,
|
||||
|
|
@ -1363,7 +1368,23 @@ impl ProjectEnvironment {
|
|||
)?;
|
||||
}
|
||||
Err(e) if e.kind() == std::io::ErrorKind::NotFound => {}
|
||||
Err(e) => return Err(e.into()),
|
||||
Err(e) => {
|
||||
// Try to write a marker to indicate that we failed to remove the entire
|
||||
// environment, so when the next command runs we can attempt to remove
|
||||
// it even if a `pyvenv.cfg` marker was removed
|
||||
match fs_err::write(root.join(".uv-partial-rm"), "") {
|
||||
Ok(()) => {
|
||||
debug!(
|
||||
"Wrote `.uv-partial-rm` marker to partially deleted environment: {}",
|
||||
root.user_display().cyan()
|
||||
);
|
||||
}
|
||||
Err(err) => {
|
||||
debug!("Failed to write `.uv-partial-rm` marker: {err}");
|
||||
}
|
||||
}
|
||||
return Err(e.into());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5000,6 +5000,59 @@ fn sync_update_project() -> Result<()> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sync_no_pyvenv_cfg() -> Result<()> {
|
||||
let context = TestContext::new("3.12");
|
||||
|
||||
let pyproject_toml = context.temp_dir.child("pyproject.toml");
|
||||
pyproject_toml.write_str(
|
||||
r#"
|
||||
[project]
|
||||
name = "my-project"
|
||||
version = "0.1.0"
|
||||
requires-python = ">=3.12"
|
||||
dependencies = ["iniconfig"]
|
||||
"#,
|
||||
)?;
|
||||
|
||||
// Break the virtual environment
|
||||
fs_err::remove_dir_all(
|
||||
context
|
||||
.venv
|
||||
.join(if cfg!(windows) { "Scripts" } else { "bin" }),
|
||||
)?;
|
||||
fs_err::remove_file(context.venv.join("pyvenv.cfg"))?;
|
||||
|
||||
// Running `uv sync` won't create the venv
|
||||
uv_snapshot!(context.filters(), context.sync(), @r"
|
||||
success: false
|
||||
exit_code: 2
|
||||
----- stdout -----
|
||||
|
||||
----- stderr -----
|
||||
error: Project virtual environment directory `[VENV]/` cannot be used because it is not a valid Python environment (no Python executable was found)
|
||||
");
|
||||
|
||||
// Write the marker that indicates the environment was partially removed by uv
|
||||
fs_err::write(context.venv.join(".uv-partial-rm"), "")?;
|
||||
uv_snapshot!(context.filters(), context.sync(), @r"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
|
||||
----- stderr -----
|
||||
Using CPython 3.12.[X] interpreter at: [PYTHON-3.12]
|
||||
Removed virtual environment at: .venv
|
||||
Creating virtual environment at: .venv
|
||||
Resolved 2 packages in [TIME]
|
||||
Prepared 1 package in [TIME]
|
||||
Installed 1 package in [TIME]
|
||||
+ iniconfig==2.0.0
|
||||
");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sync_environment_prompt() -> Result<()> {
|
||||
let context = TestContext::new_with_versions(&["3.12"]);
|
||||
|
|
|
|||
Loading…
Reference in New Issue