Skip to content

Commit bb783eb

Browse files
committed
Make LLVM downloading more robust
1 parent 716334a commit bb783eb

File tree

1 file changed

+83
-9
lines changed

1 file changed

+83
-9
lines changed

crates/pecos-llvm-utils/src/installer.rs

Lines changed: 83 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -101,10 +101,10 @@ pub fn install_llvm(
101101
let temp_dir = temp_base.join("llvm");
102102
fs::create_dir_all(&temp_dir)?;
103103
let archive_path = temp_dir.join(&archive_name);
104-
download_llvm(&url, &archive_path)?;
105104

106-
// Verify checksum
107-
verify_checksum(&archive_path, &archive_name)?;
105+
// Download and verify with retry on checksum failure
106+
// This handles transient network issues that cause corrupted downloads
107+
download_and_verify_with_retry(&url, &archive_path, &archive_name)?;
108108

109109
// Extract
110110
extract_llvm(&archive_path, &llvm_dir)?;
@@ -203,10 +203,7 @@ fn get_download_url() -> Result<(String, String), Box<dyn std::error::Error>> {
203203
}
204204
}
205205

206-
fn download_llvm(url: &str, dest: &PathBuf) -> Result<(), Box<dyn std::error::Error>> {
207-
print!("Downloading LLVM... ");
208-
io::Write::flush(&mut io::stdout())?;
209-
206+
fn download_llvm_once(url: &str, dest: &PathBuf) -> Result<u64, Box<dyn std::error::Error>> {
210207
let response = reqwest::blocking::get(url)?;
211208
let total_size = response.content_length().unwrap_or(0);
212209

@@ -238,8 +235,85 @@ fn download_llvm(url: &str, dest: &PathBuf) -> Result<(), Box<dyn std::error::Er
238235
}
239236
}
240237

241-
println!("\rDownloading LLVM... Done");
242-
Ok(())
238+
// Verify we got the expected size
239+
if total_size > 0 && downloaded != total_size {
240+
return Err(format!(
241+
"Incomplete download: expected {total_size} bytes, got {downloaded} bytes"
242+
)
243+
.into());
244+
}
245+
246+
Ok(downloaded)
247+
}
248+
249+
fn download_llvm(url: &str, dest: &PathBuf) -> Result<(), Box<dyn std::error::Error>> {
250+
print!("Downloading LLVM... ");
251+
io::Write::flush(&mut io::stdout())?;
252+
253+
match download_llvm_once(url, dest) {
254+
Ok(size) => {
255+
println!("\rDownloading LLVM... Done ({} MB)", size / 1_000_000);
256+
Ok(())
257+
}
258+
Err(e) => {
259+
println!("\rDownloading LLVM... FAILED");
260+
Err(e)
261+
}
262+
}
263+
}
264+
265+
/// Download LLVM and verify its checksum, with automatic retry on failure.
266+
///
267+
/// This function handles transient network issues that may cause corrupted downloads
268+
/// by retrying the entire download+verify cycle up to 3 times.
269+
fn download_and_verify_with_retry(
270+
url: &str,
271+
dest: &PathBuf,
272+
archive_name: &str,
273+
) -> Result<(), Box<dyn std::error::Error>> {
274+
const MAX_RETRIES: u32 = 3;
275+
276+
for attempt in 1..=MAX_RETRIES {
277+
if attempt > 1 {
278+
println!();
279+
println!("Retry attempt {attempt}/{MAX_RETRIES}...");
280+
}
281+
282+
// Clean up any existing partial file
283+
let _ = fs::remove_file(dest);
284+
285+
// Download
286+
if let Err(e) = download_llvm(url, dest) {
287+
if attempt < MAX_RETRIES {
288+
eprintln!("Download error: {e}");
289+
eprintln!("Waiting 5 seconds before retry...");
290+
std::thread::sleep(std::time::Duration::from_secs(5));
291+
continue;
292+
}
293+
return Err(e);
294+
}
295+
296+
// Verify checksum
297+
match verify_checksum(dest, archive_name) {
298+
Ok(()) => return Ok(()),
299+
Err(e) => {
300+
if attempt < MAX_RETRIES {
301+
eprintln!();
302+
eprintln!(
303+
"Checksum verification failed. This may be a transient network issue."
304+
);
305+
eprintln!("Waiting 5 seconds before retry...");
306+
std::thread::sleep(std::time::Duration::from_secs(5));
307+
// Clean up corrupted file
308+
let _ = fs::remove_file(dest);
309+
continue;
310+
}
311+
return Err(e);
312+
}
313+
}
314+
}
315+
316+
Err("Download and verification failed after all retries".into())
243317
}
244318

245319
fn verify_checksum(

0 commit comments

Comments
 (0)