| 
									
										
										
										
											2025-04-23 03:30:15 +01:00
										 |  |  | # typed: strict | 
					
						
							| 
									
										
										
										
											2024-07-14 11:42:22 -04:00
										 |  |  | # frozen_string_literal: true | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-07-22 17:48:32 +01:00
										 |  |  | require "bottle" | 
					
						
							|  |  |  | require "api/json_download" | 
					
						
							| 
									
										
										
										
											2025-08-20 19:20:19 +01:00
										 |  |  | require "utils/output" | 
					
						
							| 
									
										
										
										
											2025-07-22 17:48:32 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-07-14 11:42:22 -04:00
										 |  |  | module Homebrew | 
					
						
							| 
									
										
										
										
											2024-07-14 21:03:08 -04:00
										 |  |  |   class RetryableDownload | 
					
						
							|  |  |  |     include Downloadable | 
					
						
							| 
									
										
										
										
											2025-08-20 19:20:19 +01:00
										 |  |  |     include Utils::Output::Mixin | 
					
						
							| 
									
										
										
										
											2024-07-14 21:03:08 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-03-26 11:35:26 -07:00
										 |  |  |     sig { override.returns(T.any(NilClass, String, URL)) } | 
					
						
							| 
									
										
										
										
											2024-07-14 22:51:54 -04:00
										 |  |  |     def url = downloadable.url | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     sig { override.returns(T.nilable(Checksum)) } | 
					
						
							|  |  |  |     def checksum = downloadable.checksum | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     sig { override.returns(T::Array[String]) } | 
					
						
							|  |  |  |     def mirrors = downloadable.mirrors | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-07-22 17:48:32 +01:00
										 |  |  |     sig { params(downloadable: Downloadable, tries: Integer, pour: T::Boolean).void } | 
					
						
							|  |  |  |     def initialize(downloadable, tries:, pour: false) | 
					
						
							| 
									
										
										
										
											2024-07-14 11:42:22 -04:00
										 |  |  |       super() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       @downloadable = downloadable | 
					
						
							| 
									
										
										
										
											2025-04-23 03:30:15 +01:00
										 |  |  |       @try = T.let(0, Integer) | 
					
						
							| 
									
										
										
										
											2024-07-14 11:42:22 -04:00
										 |  |  |       @tries = tries | 
					
						
							| 
									
										
										
										
											2025-07-22 17:48:32 +01:00
										 |  |  |       @pour = pour | 
					
						
							| 
									
										
										
										
											2024-07-14 11:42:22 -04:00
										 |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     sig { override.returns(String) } | 
					
						
							| 
									
										
										
										
											2025-08-04 15:51:02 +01:00
										 |  |  |     def download_queue_name = downloadable.download_queue_name | 
					
						
							| 
									
										
										
										
											2024-07-14 11:42:22 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  |     sig { override.returns(String) } | 
					
						
							| 
									
										
										
										
											2025-08-04 15:51:02 +01:00
										 |  |  |     def download_queue_type = downloadable.download_queue_type | 
					
						
							| 
									
										
										
										
											2024-07-14 11:42:22 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  |     sig { override.returns(Pathname) } | 
					
						
							|  |  |  |     def cached_download = downloadable.cached_download | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-07-14 22:51:54 -04:00
										 |  |  |     sig { override.void } | 
					
						
							|  |  |  |     def clear_cache = downloadable.clear_cache | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     sig { override.returns(T.nilable(Version)) } | 
					
						
							|  |  |  |     def version = downloadable.version | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-04-23 03:30:15 +01:00
										 |  |  |     sig { override.returns(T::Class[AbstractDownloadStrategy]) } | 
					
						
							| 
									
										
										
										
											2024-07-14 22:51:54 -04:00
										 |  |  |     def download_strategy = downloadable.download_strategy | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     sig { override.returns(AbstractDownloadStrategy) } | 
					
						
							|  |  |  |     def downloader = downloadable.downloader | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-07-14 11:42:22 -04:00
										 |  |  |     sig { | 
					
						
							|  |  |  |       override.params( | 
					
						
							|  |  |  |         verify_download_integrity: T::Boolean, | 
					
						
							|  |  |  |         timeout:                   T.nilable(T.any(Integer, Float)), | 
					
						
							|  |  |  |         quiet:                     T::Boolean, | 
					
						
							|  |  |  |       ).returns(Pathname) | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     def fetch(verify_download_integrity: true, timeout: nil, quiet: false) | 
					
						
							|  |  |  |       @try += 1
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       already_downloaded = downloadable.downloaded? | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-08-01 16:56:24 +01:00
										 |  |  |       download = if downloadable.is_a?(Resource) && (resource = T.cast(downloadable, Resource)) | 
					
						
							|  |  |  |         resource.fetch(verify_download_integrity: false, timeout:, quiet:, skip_patches: true) | 
					
						
							|  |  |  |       else | 
					
						
							|  |  |  |         downloadable.fetch(verify_download_integrity: false, timeout:, quiet:) | 
					
						
							|  |  |  |       end | 
					
						
							| 
									
										
										
										
											2024-07-14 11:42:22 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  |       return download unless download.file? | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       unless quiet | 
					
						
							|  |  |  |         puts "Downloaded to: #{download}" unless already_downloaded | 
					
						
							| 
									
										
										
										
											2025-08-06 12:07:10 -04:00
										 |  |  |         puts "SHA-256: #{download.sha256}" | 
					
						
							| 
									
										
										
										
											2024-07-14 11:42:22 -04:00
										 |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-07-22 17:48:32 +01:00
										 |  |  |       json_download = downloadable.is_a?(API::JSONDownload) | 
					
						
							|  |  |  |       downloadable.verify_download_integrity(download) if verify_download_integrity && !json_download | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       if pour && downloadable.is_a?(Bottle) | 
					
						
							| 
									
										
										
										
											2025-07-23 17:00:52 +01:00
										 |  |  |         HOMEBREW_CELLAR.mkpath | 
					
						
							| 
									
										
										
										
											2025-07-22 17:48:32 +01:00
										 |  |  |         UnpackStrategy.detect(download, prioritize_extension: true) | 
					
						
							|  |  |  |                       .extract_nestedly(to: HOMEBREW_CELLAR) | 
					
						
							|  |  |  |       elsif json_download | 
					
						
							|  |  |  |         FileUtils.touch(download, mtime: Time.now) | 
					
						
							|  |  |  |       end | 
					
						
							| 
									
										
										
										
											2024-07-14 11:42:22 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  |       download | 
					
						
							| 
									
										
										
										
											2025-07-21 15:07:19 +01:00
										 |  |  |     rescue DownloadError, ChecksumMismatchError, Resource::BottleManifest::Error | 
					
						
							| 
									
										
										
										
											2024-07-14 11:42:22 -04:00
										 |  |  |       tries_remaining = @tries - @try | 
					
						
							|  |  |  |       raise if tries_remaining.zero? | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       wait = 2 ** @try | 
					
						
							|  |  |  |       unless quiet | 
					
						
							|  |  |  |         what = Utils.pluralize("tr", tries_remaining, plural: "ies", singular: "y") | 
					
						
							|  |  |  |         ohai "Retrying download in #{wait}s... (#{tries_remaining} #{what} left)" | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  |       sleep wait | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       downloadable.clear_cache | 
					
						
							|  |  |  |       retry | 
					
						
							|  |  |  |     end | 
					
						
							| 
									
										
										
										
											2024-07-14 22:51:54 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  |     sig { override.params(filename: Pathname).void } | 
					
						
							|  |  |  |     def verify_download_integrity(filename) = downloadable.verify_download_integrity(filename) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-07-17 17:49:53 +01:00
										 |  |  |     private | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     sig { returns(Downloadable) } | 
					
						
							|  |  |  |     attr_reader :downloadable | 
					
						
							| 
									
										
										
										
											2025-07-22 17:48:32 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     sig { returns(T::Boolean) } | 
					
						
							|  |  |  |     attr_reader :pour | 
					
						
							| 
									
										
										
										
											2024-07-14 11:42:22 -04:00
										 |  |  |   end | 
					
						
							|  |  |  | end |