Skip to content

Commit 56f93d9

Browse files
authored
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 ```
1 parent 9ca1f00 commit 56f93d9

File tree

3 files changed

+18
-7
lines changed

3 files changed

+18
-7
lines changed

crates/uv-python/src/downloads.rs

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -465,13 +465,14 @@ impl ManagedPythonDownload {
465465
client: &uv_client::BaseClient,
466466
installation_dir: &Path,
467467
cache_dir: &Path,
468+
reinstall: bool,
468469
reporter: Option<&dyn Reporter>,
469470
) -> Result<DownloadResult, Error> {
470471
let url = self.download_url()?;
471472
let path = installation_dir.join(self.key().to_string());
472473

473-
// If it already exists, return it
474-
if path.is_dir() {
474+
// If it is not a reinstall and the dir already exists, return it.
475+
if !reinstall && path.is_dir() {
475476
return Ok(DownloadResult::AlreadyAvailable(path));
476477
}
477478

@@ -560,7 +561,13 @@ impl ManagedPythonDownload {
560561
}
561562
}
562563

563-
// Persist it to the target
564+
// Remove the target if it already exists.
565+
if path.is_dir() {
566+
debug!("Removing existing directory: {}", path.user_display());
567+
fs_err::tokio::remove_dir_all(&path).await?;
568+
}
569+
570+
// Persist it to the target.
564571
debug!("Moving {} to {}", extracted.display(), path.user_display());
565572
rename_with_retry(extracted, &path)
566573
.await

crates/uv-python/src/installation.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ impl PythonInstallation {
132132

133133
info!("Fetching requested Python...");
134134
let result = download
135-
.fetch(&client, installations_dir, &cache_dir, reporter)
135+
.fetch(&client, installations_dir, &cache_dir, false, reporter)
136136
.await?;
137137

138138
let path = match result {

crates/uv/src/commands/python/install.rs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
use anyhow::Result;
2-
use fs_err as fs;
32
use futures::stream::FuturesUnordered;
43
use futures::StreamExt;
54
use itertools::Itertools;
@@ -90,7 +89,6 @@ pub(crate) async fn install(
9089
)?;
9190
}
9291
if reinstall {
93-
fs::remove_dir_all(installation.path())?;
9492
uninstalled.push(installation.key().clone());
9593
unfilled_requests.push(download_request);
9694
}
@@ -145,7 +143,13 @@ pub(crate) async fn install(
145143
(
146144
download.key(),
147145
download
148-
.fetch(&client, installations_dir, &cache_dir, Some(&reporter))
146+
.fetch(
147+
&client,
148+
installations_dir,
149+
&cache_dir,
150+
reinstall,
151+
Some(&reporter),
152+
)
149153
.await,
150154
)
151155
});

0 commit comments

Comments
 (0)