From 636682e66a1467d0cce481163fa64cc20a5edc69 Mon Sep 17 00:00:00 2001 From: Brendan <2bndy5@gmail.com> Date: Sat, 6 Jun 2026 04:15:33 -0700 Subject: [PATCH 1/2] fix: rename temp downloaded file to given cache path resolves #330 This simply keeps the downloaded temp file in the same directory as the destination of the downloaded file. When download is done, the file is renamed to the specified file name. This also removes the `tempfile` dependency from production code. It is still used heavily in tests. --- clang-installer/Cargo.toml | 2 +- clang-installer/src/downloader/mod.rs | 21 +++++++++++++++------ 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/clang-installer/Cargo.toml b/clang-installer/Cargo.toml index 8282c370..917c7f9a 100644 --- a/clang-installer/Cargo.toml +++ b/clang-installer/Cargo.toml @@ -36,12 +36,12 @@ tokio = { workspace = true, features = ["macros"], optional = true } url = "2.5.8" which = "8.0.2" zip = { version = "8.6.0", default-features = false, features = ["deflate"] } -tempfile = { workspace = true } [dev-dependencies] colored = { workspace = true } mockito = { workspace = true } reqwest = { workspace = true, features = ["default-tls"] } +tempfile = { workspace = true } tokio = { workspace = true, features = ["macros", "rt-multi-thread"] } [features] diff --git a/clang-installer/src/downloader/mod.rs b/clang-installer/src/downloader/mod.rs index 78de368f..ebc1f944 100644 --- a/clang-installer/src/downloader/mod.rs +++ b/clang-installer/src/downloader/mod.rs @@ -31,9 +31,9 @@ pub enum DownloadError { #[error("Hash mismatch for downloaded file. Expected: {expected}, Actual: {actual}")] HashMismatch { expected: String, actual: String }, - /// An error that occurred while moving/persisting a temporary file into a cache path. - #[error("Error persisting temporary file: {0}")] - TempFilePersistence(#[from] tempfile::PersistError), + /// An error that occurred while creating or persisting a temporary file into a cache path. + #[error("Error when {0}: {1}")] + TempFile(&'static str, #[source] std::io::Error), } /// Downloads data from the specified URL and returns the response. @@ -58,7 +58,15 @@ async fn download(url: &Url, cache_path: &Path, timeout: u64) -> Result<(), Down } return Err(e.into()); } - let mut tmp_file = tempfile::NamedTempFile::new()?; + let tmp_file_path = cache_path.with_extension("tmp"); + let mut tmp_file = fs::OpenOptions::new() + .write(true) + .truncate(true) + .create(true) + .open(&tmp_file_path) + .map_err(|e| { + DownloadError::TempFile("creating temporary file for download placeholder", e) + })?; let content_len = response.content_length().and_then(NonZero::new); let mut progress_bar = ProgressBar::new( content_len, @@ -79,8 +87,9 @@ async fn download(url: &Url, cache_path: &Path, timeout: u64) -> Result<(), Down } progress_bar.finish()?; tmp_file.flush()?; - tmp_file.as_file_mut().set_modified(SystemTime::now())?; - tmp_file.persist(cache_path)?; + tmp_file.set_modified(SystemTime::now())?; + fs::rename(tmp_file_path, cache_path) + .map_err(|e| DownloadError::TempFile("renaming temporary file after download", e))?; Ok(()) } From 94a806c0e6b059ab1b3e4380f1c0b2470c6336af Mon Sep 17 00:00:00 2001 From: Brendan <2bndy5@gmail.com> Date: Sat, 6 Jun 2026 07:03:12 -0700 Subject: [PATCH 2/2] explicitly close the tmp file before renaming run CI tests on installer crate too --- .github/workflows/run-dev-tests.yml | 2 ++ clang-installer/src/downloader/mod.rs | 1 + 2 files changed, 3 insertions(+) diff --git a/.github/workflows/run-dev-tests.yml b/.github/workflows/run-dev-tests.yml index 4fc4c386..bc11211c 100644 --- a/.github/workflows/run-dev-tests.yml +++ b/.github/workflows/run-dev-tests.yml @@ -5,6 +5,7 @@ on: branches: [main] paths: - cpp-linter/** + - clang-installer/** - Cargo.toml - Cargo.lock - .github/workflows/run-dev-tests.yml @@ -12,6 +13,7 @@ on: branches: [main] paths: - cpp-linter/** + - clang-installer/** - Cargo.toml - Cargo.lock - .github/workflows/run-dev-tests.yml diff --git a/clang-installer/src/downloader/mod.rs b/clang-installer/src/downloader/mod.rs index ebc1f944..a288548d 100644 --- a/clang-installer/src/downloader/mod.rs +++ b/clang-installer/src/downloader/mod.rs @@ -88,6 +88,7 @@ async fn download(url: &Url, cache_path: &Path, timeout: u64) -> Result<(), Down progress_bar.finish()?; tmp_file.flush()?; tmp_file.set_modified(SystemTime::now())?; + drop(tmp_file); // ensure the file is closed before renaming fs::rename(tmp_file_path, cache_path) .map_err(|e| DownloadError::TempFile("renaming temporary file after download", e))?; Ok(())