@@ -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 ! ( "\r Downloading 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 ! ( "\r Downloading LLVM... Done ({} MB)" , size / 1_000_000 ) ;
256+ Ok ( ( ) )
257+ }
258+ Err ( e) => {
259+ println ! ( "\r Downloading 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
245319fn verify_checksum (
0 commit comments