From 56f93d9cfceb1cb168ef322de70c84e51ea8b457 Mon Sep 17 00:00:00 2001 From: Jo <10510431+j178@users.noreply.github.com> Date: Thu, 24 Oct 2024 02:43:09 +0800 Subject: [PATCH] `uv python install`: remove the existing version only after the new installation is downloaded successfully (#8485) ## Summary This PR delays the removal of an existing version after downloading the new version when running `uv python install --reinstall`. If the download fails, we can keep the existing version working. ## Test Plan ```console $ cargo run -- python install 3.13 $ cargo run -- python install --reinstall 3.13 # when downloading, `ctrl-c` to interrupt $ cargo run -- python list ``` --- crates/uv-python/src/downloads.rs | 13 ++++++++++--- crates/uv-python/src/installation.rs | 2 +- crates/uv/src/commands/python/install.rs | 10 +++++++--- 3 files changed, 18 insertions(+), 7 deletions(-) diff --git a/crates/uv-python/src/downloads.rs b/crates/uv-python/src/downloads.rs index 4e865375d..4e3e3f317 100644 --- a/crates/uv-python/src/downloads.rs +++ b/crates/uv-python/src/downloads.rs @@ -465,13 +465,14 @@ impl ManagedPythonDownload { client: &uv_client::BaseClient, installation_dir: &Path, cache_dir: &Path, + reinstall: bool, reporter: Option<&dyn Reporter>, ) -> Result { let url = self.download_url()?; let path = installation_dir.join(self.key().to_string()); - // If it already exists, return it - if path.is_dir() { + // If it is not a reinstall and the dir already exists, return it. + if !reinstall && path.is_dir() { return Ok(DownloadResult::AlreadyAvailable(path)); } @@ -560,7 +561,13 @@ impl ManagedPythonDownload { } } - // Persist it to the target + // Remove the target if it already exists. + if path.is_dir() { + debug!("Removing existing directory: {}", path.user_display()); + fs_err::tokio::remove_dir_all(&path).await?; + } + + // Persist it to the target. debug!("Moving {} to {}", extracted.display(), path.user_display()); rename_with_retry(extracted, &path) .await diff --git a/crates/uv-python/src/installation.rs b/crates/uv-python/src/installation.rs index b0a326bad..c6bf4e816 100644 --- a/crates/uv-python/src/installation.rs +++ b/crates/uv-python/src/installation.rs @@ -132,7 +132,7 @@ impl PythonInstallation { info!("Fetching requested Python..."); let result = download - .fetch(&client, installations_dir, &cache_dir, reporter) + .fetch(&client, installations_dir, &cache_dir, false, reporter) .await?; let path = match result { diff --git a/crates/uv/src/commands/python/install.rs b/crates/uv/src/commands/python/install.rs index 601694359..bb7c4be0b 100644 --- a/crates/uv/src/commands/python/install.rs +++ b/crates/uv/src/commands/python/install.rs @@ -1,5 +1,4 @@ use anyhow::Result; -use fs_err as fs; use futures::stream::FuturesUnordered; use futures::StreamExt; use itertools::Itertools; @@ -90,7 +89,6 @@ pub(crate) async fn install( )?; } if reinstall { - fs::remove_dir_all(installation.path())?; uninstalled.push(installation.key().clone()); unfilled_requests.push(download_request); } @@ -145,7 +143,13 @@ pub(crate) async fn install( ( download.key(), download - .fetch(&client, installations_dir, &cache_dir, Some(&reporter)) + .fetch( + &client, + installations_dir, + &cache_dir, + reinstall, + Some(&reporter), + ) .await, ) });