Skip to content
Open
13 changes: 10 additions & 3 deletions src/cli/self_update.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ use crate::{
DistOptions, PartialToolchainDesc, Profile, TargetTuple, ToolchainDesc,
download::DownloadCfg,
},
download::download_file,
download::DownloadOptions,
errors::RustupError,
install::{InstallMethod, UpdateStatus},
process::Process,
Expand Down Expand Up @@ -1340,7 +1340,10 @@ pub(crate) async fn prepare_update(dl_cfg: &DownloadCfg<'_>) -> Result<Option<Pa

// Download new version
info!("downloading self-update (new version: {available_version})");
download_file(&download_url, &setup_path, None, None, dl_cfg.process).await?;
DownloadOptions::try_from(dl_cfg.process)?
.start(&download_url, &setup_path)
.download()
.await?;

// Mark as executable
utils::make_executable(&setup_path)?;
Expand All @@ -1359,7 +1362,11 @@ async fn get_available_rustup_version(dl_cfg: &DownloadCfg<'_>) -> Result<String
let release_file_url = format!("{update_root}/release-stable.toml");
let release_file_url = utils::parse_url(&release_file_url)?;
let release_file = tempdir.path().join("release-stable.toml");
download_file(&release_file_url, &release_file, None, None, dl_cfg.process).await?;
DownloadOptions::try_from(dl_cfg.process)?
.start(&release_file_url, &release_file)
.download()
.await?;

let release_toml_str = utils::read_file("rustup release", &release_file)?;
let release_toml = toml::from_str::<RustupManifest>(&release_toml_str)
.context("unable to parse rustup release file")?;
Expand Down
16 changes: 5 additions & 11 deletions src/cli/self_update/windows.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,7 @@ use super::{InstallOpts, install_bins, report_error};
use crate::cli::markdown::md;
use crate::config::Cfg;
use crate::dist::TargetTuple;
use crate::dist::download::DownloadCfg;
use crate::download::download_file;
use crate::download::DownloadOptions;
use crate::process::{ColorableTerminal, Process};
use crate::utils;

Expand Down Expand Up @@ -271,16 +270,11 @@ pub(crate) async fn try_install_msvc(
.context("error creating temp directory")?;

let visual_studio = tempdir.path().join("vs_setup.exe");
let dl_cfg = DownloadCfg::new(cfg);
info!("downloading Visual Studio installer");
download_file(
&visual_studio_url,
&visual_studio,
None,
None,
dl_cfg.process,
)
.await?;
DownloadOptions::try_from(cfg.process)?
.start(&visual_studio_url, &visual_studio)
.download()
.await?;

// Run the installer. Arguments are documented at:
// https://docs.microsoft.com/en-us/visualstudio/install/use-command-line-parameters-to-install-visual-studio
Expand Down
36 changes: 21 additions & 15 deletions src/dist/download.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use url::Url;
use crate::config::Cfg;
use crate::dist::manifest::{Manifest, ManifestWithHash};
use crate::dist::{Channel, DEFAULT_DIST_SERVER, ToolchainDesc, temp};
use crate::download::{download_file, download_file_with_resume, is_network_failure};
use crate::download::{DownloadOptions, is_network_failure};
use crate::errors::RustupError;
use crate::process::Process;
use crate::utils;
Expand Down Expand Up @@ -82,17 +82,13 @@ impl<'a> DownloadCfg<'a> {
let partial_file_existed = partial_file_path.exists();

let mut hasher = Sha256::new();
let download = DownloadOptions::try_from(self.process)?
.start(url, &partial_file_path)
.with_hasher(&mut hasher)
.with_status(status)
.with_resume();

if let Err(e) = download_file_with_resume(
url,
&partial_file_path,
Some(&mut hasher),
true,
Some(status),
self.process,
)
.await
{
if let Err(e) = download.download().await {
let is_network_failure = is_network_failure(&e);
let err = Err(e);
return match (partial_file_existed, is_network_failure) {
Expand Down Expand Up @@ -142,9 +138,10 @@ impl<'a> DownloadCfg<'a> {
async fn download_hash(&self, url: &str) -> Result<String> {
let hash_url = utils::parse_url(&(url.to_owned() + ".sha256"))?;
let hash_file = self.tmp_cx.new_file()?;

download_file(&hash_url, &hash_file, None, None, self.process).await?;

DownloadOptions::try_from(self.process)?
.start(&hash_url, &hash_file)
.download()
.await?;
utils::read_file("hash", &hash_file).map(|s| s[0..64].to_owned())
}

Expand Down Expand Up @@ -267,7 +264,16 @@ impl<'a> DownloadCfg<'a> {
let file = self.tmp_cx.new_file_with_ext("", ext)?;

let mut hasher = Sha256::new();
download_file(&url, &file, Some(&mut hasher), status, self.process).await?;
let download = DownloadOptions::try_from(self.process)?
.start(&url, &file)
.with_hasher(&mut hasher);

let download = match status {
Some(status) => download.with_status(status),
Copy link
Copy Markdown
Member

@rami3l rami3l May 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: A common builder trick is to let .with_foo() accept impl Into<Option<Foo>> so it can take foo, Some(foo) and None at the same time. Hopefully this way the chain can be more readable here 🙏

View changes since the review

Copy link
Copy Markdown
Contributor Author

@djc djc May 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, not sure I love it. I like the added precision of the builder method exactly taking the thing (not the thing wrapped in Option), and I don't mind this boilerplate so much -- while it's more verbose, it still seems still pretty straightforward to understand.

None => download,
};

download.download().await?;
let actual_hash = faster_hex::hex_string(&hasher.finalize());

if hash != actual_hash {
Expand Down
7 changes: 5 additions & 2 deletions src/dist/manifestation/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ use crate::{
prefix::InstallPrefix,
temp,
},
download::download_file,
download::DownloadOptions,
errors::RustupError,
process::TestProcess,
test::{
Expand Down Expand Up @@ -490,7 +490,10 @@ impl TestContext {
// Download the dist manifest and place it into the installation prefix
let manifest_url = make_manifest_url(&self.url, &self.toolchain)?;
let manifest_file = self.tmp_cx.new_file()?;
download_file(&manifest_url, &manifest_file, None, None, dl_cfg.process).await?;
DownloadOptions::try_from(dl_cfg.process)?
.start(&manifest_url, &manifest_file)
.download()
.await?;
let manifest_str = utils::read_file("manifest", &manifest_file)?;
let manifest = Manifest::parse(&manifest_str)?;

Expand Down
Loading
Loading