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
```
This commit is contained in:
Jo 2024-10-24 02:43:09 +08:00 committed by GitHub
parent 9ca1f0003f
commit 56f93d9cfc
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 18 additions and 7 deletions

View file

@ -465,13 +465,14 @@ impl ManagedPythonDownload {
client: &uv_client::BaseClient,
installation_dir: &Path,
cache_dir: &Path,
reinstall: bool,
reporter: Option<&dyn Reporter>,
) -> Result<DownloadResult, Error> {
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

View file

@ -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 {

View file

@ -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,
)
});