Skip to content

Commit e6084c8

Browse files
committed
feat: add disk space check for downloads on unix
1 parent 3788021 commit e6084c8

3 files changed

Lines changed: 57 additions & 2 deletions

File tree

src/dist/download.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,9 @@ use url::Url;
1515
use crate::config::Cfg;
1616
use crate::dist::manifest::Manifest;
1717
use crate::dist::{Channel, DEFAULT_DIST_SERVER, ToolchainDesc, temp};
18-
use crate::download::{download_file, download_file_with_resume, is_network_failure};
18+
use crate::download::{
19+
content_length, download_file, download_file_with_resume, is_network_failure,
20+
};
1921
use crate::errors::RustupError;
2022
use crate::process::Process;
2123
use crate::utils;
@@ -129,6 +131,10 @@ impl<'a> DownloadCfg<'a> {
129131
}
130132
}
131133

134+
pub(crate) async fn content_length(&self, url: &Url) -> Result<Option<u64>> {
135+
content_length(url, self.process).await
136+
}
137+
132138
pub(crate) fn clean(&self, hashes: &[impl AsRef<Path>]) -> Result<()> {
133139
for hash in hashes.iter() {
134140
let used_file = self.download_dir.join(hash);

src/dist/manifestation.rs

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,50 @@ impl Manifestation {
240240
);
241241
};
242242

243+
// TODO: enable this for windows
244+
// disk_free() is only available for cfg(unix) for now
245+
#[cfg(unix)]
246+
{
247+
let estimated_download_size = futures_util::future::join_all(
248+
components
249+
.iter()
250+
.map(|component| component.required_size_via_head()),
251+
)
252+
.await
253+
.iter()
254+
.try_fold(0u64, |acc, elem| {
255+
match elem {
256+
Ok(Some(size)) => Some(acc + size),
257+
// This component size's unknown (None or Err)
258+
_ => {
259+
warn!("failed to fetch component size, continueing...");
260+
None
261+
}
262+
}
263+
});
264+
265+
let path = &components
266+
.first()
267+
.unwrap()
268+
.download_cfg
269+
.tmp_cx
270+
.root_directory;
271+
let disk_free = match utils::disk_free(path) {
272+
Ok(size) => Some(size),
273+
Err(e) => {
274+
warn!("failed to acquire disk free space: {e}\ncontinueing... ");
275+
None
276+
}
277+
};
278+
279+
if let (Some(df), Some(est)) = (disk_free, estimated_download_size)
280+
&& df < est
281+
&& !force_update
282+
{
283+
bail!("insufficient storage: {est} bytes required, {df} bytes available")
284+
}
285+
};
286+
243287
let mut stream = InstallEvents::new(components.into_iter(), Arc::new(self));
244288
let mut transaction = Some(tx);
245289
tx = loop {
@@ -767,6 +811,11 @@ impl<'a> ComponentBinary<'a> {
767811
}))
768812
}
769813

814+
async fn required_size_via_head(&self) -> Result<Option<u64>> {
815+
let url = self.download_cfg.url(&self.binary.url)?;
816+
self.download_cfg.content_length(&url).await
817+
}
818+
770819
async fn download(self, max_retries: usize) -> Result<(ComponentInstall, &'a str)> {
771820
use tokio_retry::{RetryIf, strategy::FixedInterval};
772821

src/dist/temp.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ impl Drop for File {
7373
}
7474

7575
pub struct Context {
76-
root_directory: PathBuf,
76+
pub root_directory: PathBuf,
7777
pub dist_server: String,
7878
}
7979

0 commit comments

Comments
 (0)