| 
									
										
										
										
											2023-03-12 17:06:29 -07:00
										 |  |  | # typed: true | 
					
						
							| 
									
										
										
										
											2019-04-19 15:38:03 +09:00
										 |  |  | # frozen_string_literal: true | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-17 14:01:37 +08:00
										 |  |  | require "cask/cache" | 
					
						
							| 
									
										
										
										
											2018-09-03 19:39:07 +01:00
										 |  |  | require "cask/cask" | 
					
						
							| 
									
										
										
										
											2018-03-07 16:14:55 +00:00
										 |  |  | require "uri" | 
					
						
							| 
									
										
										
										
											2023-09-04 22:17:57 -04:00
										 |  |  | require "utils/curl" | 
					
						
							| 
									
										
										
										
											2024-01-12 09:38:49 -08:00
										 |  |  | require "extend/hash/keys" | 
					
						
							| 
									
										
										
										
											2018-03-07 16:14:55 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-06 08:29:14 +02:00
										 |  |  | module Cask | 
					
						
							| 
									
										
										
										
											2020-08-24 22:50:29 +02:00
										 |  |  |   # Loads a cask from various sources. | 
					
						
							| 
									
										
										
										
											2017-03-12 19:18:41 +01:00
										 |  |  |   module CaskLoader | 
					
						
							| 
									
										
										
										
											2023-02-05 13:06:56 -08:00
										 |  |  |     extend Context | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-07-13 12:16:36 -04:00
										 |  |  |     ALLOWED_URL_SCHEMES = %w[file].freeze | 
					
						
							|  |  |  |     private_constant :ALLOWED_URL_SCHEMES | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-12 17:06:29 -07:00
										 |  |  |     module ILoader | 
					
						
							|  |  |  |       extend T::Helpers | 
					
						
							|  |  |  |       interface! | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-02-20 18:08:55 +01:00
										 |  |  |       sig { abstract.params(config: T.nilable(Config)).returns(Cask) } | 
					
						
							| 
									
										
										
										
											2023-03-12 17:06:29 -07:00
										 |  |  |       def load(config:); end | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-24 22:50:29 +02:00
										 |  |  |     # Loads a cask from a string. | 
					
						
							| 
									
										
										
										
											2023-04-18 00:22:13 +01:00
										 |  |  |     class AbstractContentLoader | 
					
						
							| 
									
										
										
										
											2023-03-12 17:06:29 -07:00
										 |  |  |       include ILoader | 
					
						
							| 
									
										
										
										
											2023-04-18 00:22:13 +01:00
										 |  |  |       extend T::Helpers | 
					
						
							|  |  |  |       abstract! | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       sig { returns(String) } | 
					
						
							|  |  |  |       attr_reader :content | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       sig { returns(T.nilable(Tap)) } | 
					
						
							|  |  |  |       attr_reader :tap | 
					
						
							| 
									
										
										
										
											2017-06-28 09:25:14 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-18 00:22:13 +01:00
										 |  |  |       private | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       sig { | 
					
						
							|  |  |  |         overridable.params( | 
					
						
							|  |  |  |           header_token: String, | 
					
						
							|  |  |  |           options:      T.untyped, | 
					
						
							|  |  |  |           block:        T.nilable(T.proc.bind(DSL).void), | 
					
						
							|  |  |  |         ).returns(Cask) | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       def cask(header_token, **options, &block) | 
					
						
							| 
									
										
										
										
											2024-03-07 16:20:20 +00:00
										 |  |  |         Cask.new(header_token, source: content, tap:, **options, config: @config, &block) | 
					
						
							| 
									
										
										
										
											2023-04-18 00:22:13 +01:00
										 |  |  |       end | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # Loads a cask from a string. | 
					
						
							|  |  |  |     class FromContentLoader < AbstractContentLoader | 
					
						
							| 
									
										
										
										
											2024-02-06 21:59:55 +01:00
										 |  |  |       def self.try_new(ref, warn: false) | 
					
						
							| 
									
										
										
										
											2017-10-08 15:20:58 +02:00
										 |  |  |         return false unless ref.respond_to?(:to_str) | 
					
						
							| 
									
										
										
										
											2018-09-17 02:45:00 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-02-06 22:12:51 +01:00
										 |  |  |         content = T.unsafe(ref).to_str | 
					
						
							| 
									
										
										
										
											2017-10-08 15:20:58 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-27 01:28:08 -04:00
										 |  |  |         # Cache compiled regex | 
					
						
							|  |  |  |         @regex ||= begin | 
					
						
							|  |  |  |           token  = /(?:"[^"]*"|'[^']*')/ | 
					
						
							|  |  |  |           curly  = /\(\s*#{token.source}\s*\)\s*\{.*\}/ | 
					
						
							|  |  |  |           do_end = /\s+#{token.source}\s+do(?:\s*;\s*|\s+).*end/ | 
					
						
							|  |  |  |           /\A\s*cask(?:#{curly.source}|#{do_end.source})\s*\Z/m | 
					
						
							|  |  |  |         end | 
					
						
							| 
									
										
										
										
											2017-10-08 15:20:58 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-02-06 21:59:55 +01:00
										 |  |  |         return unless content.match?(@regex) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         new(content) | 
					
						
							| 
									
										
										
										
											2017-10-08 15:20:58 +02:00
										 |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-02-06 22:12:51 +01:00
										 |  |  |       sig { params(content: String, tap: Tap).void } | 
					
						
							|  |  |  |       def initialize(content, tap: T.unsafe(nil)) | 
					
						
							| 
									
										
										
										
											2023-04-18 00:22:13 +01:00
										 |  |  |         super() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-02-06 21:59:55 +01:00
										 |  |  |         @content = content.dup.force_encoding("UTF-8") | 
					
						
							| 
									
										
										
										
											2023-02-25 16:24:58 -05:00
										 |  |  |         @tap = tap | 
					
						
							| 
									
										
										
										
											2017-03-12 19:18:41 +01:00
										 |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-29 23:46:30 +02:00
										 |  |  |       def load(config:) | 
					
						
							|  |  |  |         @config = config | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-13 17:23:49 +01:00
										 |  |  |         instance_eval(content, __FILE__, __LINE__) | 
					
						
							| 
									
										
										
										
											2017-03-12 19:18:41 +01:00
										 |  |  |       end | 
					
						
							| 
									
										
										
										
											2016-10-08 13:25:38 +02:00
										 |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-24 22:50:29 +02:00
										 |  |  |     # Loads a cask from a path. | 
					
						
							| 
									
										
										
										
											2023-04-18 00:22:13 +01:00
										 |  |  |     class FromPathLoader < AbstractContentLoader | 
					
						
							| 
									
										
										
										
											2024-02-06 21:59:55 +01:00
										 |  |  |       sig { | 
					
						
							| 
									
										
										
										
											2024-06-30 10:18:03 -07:00
										 |  |  |         overridable.params(ref: T.any(String, Pathname, Cask, URI::Generic), warn: T::Boolean) | 
					
						
							|  |  |  |                    .returns(T.nilable(T.attached_class)) | 
					
						
							| 
									
										
										
										
											2024-02-06 21:59:55 +01:00
										 |  |  |       } | 
					
						
							|  |  |  |       def self.try_new(ref, warn: false) | 
					
						
							| 
									
										
										
										
											2024-02-08 14:44:41 +01:00
										 |  |  |         path = case ref | 
					
						
							|  |  |  |         when String | 
					
						
							|  |  |  |           Pathname(ref) | 
					
						
							|  |  |  |         when Pathname | 
					
						
							|  |  |  |           ref | 
					
						
							|  |  |  |         else | 
					
						
							|  |  |  |           return | 
					
						
							|  |  |  |         end | 
					
						
							| 
									
										
										
										
											2024-02-06 21:59:55 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |         return if %w[.rb .json].exclude?(path.extname) | 
					
						
							|  |  |  |         return unless path.expand_path.exist? | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-07-24 05:39:06 +01:00
										 |  |  |         return if Homebrew::EnvConfig.forbid_packages_from_paths? && | 
					
						
							|  |  |  |                   !path.realpath.to_s.start_with?("#{Caskroom.path}/", "#{HOMEBREW_LIBRARY}/Taps/") | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-02-06 21:59:55 +01:00
										 |  |  |         new(path) | 
					
						
							| 
									
										
										
										
											2017-03-12 19:18:41 +01:00
										 |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       attr_reader :token, :path | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-02-06 22:12:51 +01:00
										 |  |  |       sig { params(path: T.any(Pathname, String), token: String).void } | 
					
						
							|  |  |  |       def initialize(path, token: T.unsafe(nil)) | 
					
						
							| 
									
										
										
										
											2023-04-18 00:22:13 +01:00
										 |  |  |         super() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-28 09:25:14 +02:00
										 |  |  |         path = Pathname(path).expand_path | 
					
						
							| 
									
										
										
										
											2017-03-12 19:18:41 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-05 12:22:08 +01:00
										 |  |  |         @token = path.basename(path.extname).to_s | 
					
						
							| 
									
										
										
										
											2017-03-12 19:18:41 +01:00
										 |  |  |         @path = path | 
					
						
							| 
									
										
										
										
											2024-02-08 14:53:55 +01:00
										 |  |  |         @tap = Tap.from_path(path) || Homebrew::API.tap_from_source_download(path) | 
					
						
							| 
									
										
										
										
											2017-03-12 19:18:41 +01:00
										 |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-02-20 18:08:55 +01:00
										 |  |  |       sig { override.params(config: T.nilable(Config)).returns(Cask) } | 
					
						
							| 
									
										
										
										
											2020-09-29 23:46:30 +02:00
										 |  |  |       def load(config:) | 
					
						
							| 
									
										
										
										
											2017-06-28 09:25:14 +02:00
										 |  |  |         raise CaskUnavailableError.new(token, "'#{path}' does not exist.")  unless path.exist? | 
					
						
							|  |  |  |         raise CaskUnavailableError.new(token, "'#{path}' is not readable.") unless path.readable? | 
					
						
							|  |  |  |         raise CaskUnavailableError.new(token, "'#{path}' is not a file.")   unless path.file? | 
					
						
							| 
									
										
										
										
											2017-03-12 19:18:41 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-29 23:46:30 +02:00
										 |  |  |         @content = path.read(encoding: "UTF-8") | 
					
						
							|  |  |  |         @config = config | 
					
						
							| 
									
										
										
										
											2017-03-12 19:18:41 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-05-06 23:34:23 -07:00
										 |  |  |         if path.extname == ".json" | 
					
						
							|  |  |  |           return FromAPILoader.new(token, from_json: JSON.parse(@content), path:).load(config:) | 
					
						
							|  |  |  |         end | 
					
						
							| 
									
										
										
										
											2023-02-05 12:22:08 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-29 11:05:23 +02:00
										 |  |  |         begin | 
					
						
							|  |  |  |           instance_eval(content, path).tap do |cask| | 
					
						
							| 
									
										
										
										
											2019-02-19 13:11:32 +00:00
										 |  |  |             raise CaskUnreadableError.new(token, "'#{path}' does not contain a cask.") unless cask.is_a?(Cask) | 
					
						
							| 
									
										
										
										
											2018-07-29 11:05:23 +02:00
										 |  |  |           end | 
					
						
							|  |  |  |         rescue NameError, ArgumentError, ScriptError => e | 
					
						
							| 
									
										
										
										
											2020-09-29 23:46:30 +02:00
										 |  |  |           error = CaskUnreadableError.new(token, e.message) | 
					
						
							|  |  |  |           error.set_backtrace e.backtrace | 
					
						
							|  |  |  |           raise error | 
					
						
							| 
									
										
										
										
											2018-07-29 11:05:23 +02:00
										 |  |  |         end | 
					
						
							| 
									
										
										
										
											2017-03-12 19:18:41 +01:00
										 |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       private | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-29 16:27:54 +02:00
										 |  |  |       def cask(header_token, **options, &block) | 
					
						
							| 
									
										
										
										
											2019-02-19 13:11:32 +00:00
										 |  |  |         raise CaskTokenMismatchError.new(token, header_token) if token != header_token | 
					
						
							| 
									
										
										
										
											2017-03-12 19:18:41 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-29 16:27:54 +02:00
										 |  |  |         super(header_token, **options, sourcefile_path: path, &block) | 
					
						
							| 
									
										
										
										
											2017-03-12 19:18:41 +01:00
										 |  |  |       end | 
					
						
							| 
									
										
										
										
											2016-10-08 13:25:38 +02:00
										 |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-24 22:50:29 +02:00
										 |  |  |     # Loads a cask from a URI. | 
					
						
							| 
									
										
										
										
											2017-03-12 19:18:41 +01:00
										 |  |  |     class FromURILoader < FromPathLoader | 
					
						
							| 
									
										
										
										
											2024-02-06 21:59:55 +01:00
										 |  |  |       sig { | 
					
						
							| 
									
										
										
										
											2024-06-30 10:18:03 -07:00
										 |  |  |         override.params(ref: T.any(String, Pathname, Cask, URI::Generic), warn: T::Boolean) | 
					
						
							|  |  |  |                 .returns(T.nilable(T.attached_class)) | 
					
						
							| 
									
										
										
										
											2024-02-06 21:59:55 +01:00
										 |  |  |       } | 
					
						
							|  |  |  |       def self.try_new(ref, warn: false) | 
					
						
							| 
									
										
										
										
											2024-07-24 05:39:06 +01:00
										 |  |  |         return if Homebrew::EnvConfig.forbid_packages_from_paths? | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-27 01:28:08 -04:00
										 |  |  |         # Cache compiled regex | 
					
						
							|  |  |  |         @uri_regex ||= begin | 
					
						
							|  |  |  |           uri_regex = ::URI::DEFAULT_PARSER.make_regexp | 
					
						
							|  |  |  |           Regexp.new("\\A#{uri_regex.source}\\Z", uri_regex.options) | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-02-06 22:12:51 +01:00
										 |  |  |         uri = ref.to_s | 
					
						
							| 
									
										
										
										
											2024-02-06 21:59:55 +01:00
										 |  |  |         return unless uri.match?(@uri_regex) | 
					
						
							| 
									
										
										
										
											2019-11-14 07:38:24 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-02-06 22:12:51 +01:00
										 |  |  |         uri = URI(uri) | 
					
						
							| 
									
										
										
										
											2024-02-06 21:59:55 +01:00
										 |  |  |         return unless uri.path | 
					
						
							| 
									
										
										
										
											2019-11-14 07:38:24 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-02-06 21:59:55 +01:00
										 |  |  |         new(uri) | 
					
						
							| 
									
										
										
										
											2017-03-12 19:18:41 +01:00
										 |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-07-13 12:16:36 -04:00
										 |  |  |       attr_reader :url, :name | 
					
						
							| 
									
										
										
										
											2017-06-11 02:00:59 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-20 12:03:48 +02:00
										 |  |  |       sig { params(url: T.any(URI::Generic, String)).void } | 
					
						
							| 
									
										
										
										
											2017-03-12 19:18:41 +01:00
										 |  |  |       def initialize(url) | 
					
						
							| 
									
										
										
										
											2017-06-11 02:00:59 +02:00
										 |  |  |         @url = URI(url) | 
					
						
							| 
									
										
										
										
											2024-07-13 12:16:36 -04:00
										 |  |  |         @name = File.basename(T.must(@url.path)) | 
					
						
							|  |  |  |         super Cache.path/name | 
					
						
							| 
									
										
										
										
											2017-03-12 19:18:41 +01:00
										 |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-29 23:46:30 +02:00
										 |  |  |       def load(config:) | 
					
						
							| 
									
										
										
										
											2017-06-28 09:25:14 +02:00
										 |  |  |         path.dirname.mkpath | 
					
						
							| 
									
										
										
										
											2017-03-12 19:18:41 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-07-13 12:16:36 -04:00
										 |  |  |         if ALLOWED_URL_SCHEMES.exclude?(url.scheme) | 
					
						
							|  |  |  |           raise UnsupportedInstallationMethod, | 
					
						
							|  |  |  |                 "Non-checksummed download of #{name} formula file from an arbitrary URL is unsupported! " \ | 
					
						
							|  |  |  |                 "`brew extract` or `brew create` and `brew tap-new` to create a formula file in a tap " \ | 
					
						
							|  |  |  |                 "on GitHub instead." | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-12 19:18:41 +01:00
										 |  |  |         begin | 
					
						
							| 
									
										
										
										
											2021-01-26 15:21:24 -05:00
										 |  |  |           ohai "Downloading #{url}" | 
					
						
							| 
									
										
										
										
											2023-09-04 22:17:57 -04:00
										 |  |  |           ::Utils::Curl.curl_download url, to: path | 
					
						
							| 
									
										
										
										
											2017-03-12 19:18:41 +01:00
										 |  |  |         rescue ErrorDuringExecution | 
					
						
							| 
									
										
										
										
											2017-06-28 09:25:14 +02:00
										 |  |  |           raise CaskUnavailableError.new(token, "Failed to download #{Formatter.url(url)}.") | 
					
						
							| 
									
										
										
										
											2017-03-12 19:18:41 +01:00
										 |  |  |         end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         super | 
					
						
							|  |  |  |       end | 
					
						
							| 
									
										
										
										
											2016-10-08 13:25:38 +02:00
										 |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-24 22:50:29 +02:00
										 |  |  |     # Loads a cask from a specific tap. | 
					
						
							| 
									
										
										
										
											2024-02-08 14:53:55 +01:00
										 |  |  |     class FromTapLoader < FromPathLoader | 
					
						
							| 
									
										
										
										
											2024-02-09 18:26:54 +01:00
										 |  |  |       sig { returns(Tap) } | 
					
						
							|  |  |  |       attr_reader :tap | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-02-06 21:59:55 +01:00
										 |  |  |       sig { | 
					
						
							| 
									
										
										
										
											2024-06-30 10:18:03 -07:00
										 |  |  |         override(allow_incompatible: true) # rubocop:todo Sorbet/AllowIncompatibleOverride | 
					
						
							|  |  |  |           .params(ref: T.any(String, Pathname, Cask, URI::Generic), warn: T::Boolean) | 
					
						
							|  |  |  |           .returns(T.nilable(T.any(T.attached_class, FromAPILoader))) | 
					
						
							| 
									
										
										
										
											2024-02-06 21:59:55 +01:00
										 |  |  |       } | 
					
						
							|  |  |  |       def self.try_new(ref, warn: false) | 
					
						
							|  |  |  |         ref = ref.to_s | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-07 16:20:20 +00:00
										 |  |  |         return unless (token_tap_type = CaskLoader.tap_cask_token_type(ref, warn:)) | 
					
						
							| 
									
										
										
										
											2024-02-06 21:59:55 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-06-30 10:18:03 -07:00
										 |  |  |         token, tap, type = token_tap_type | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if type == :migration && tap.core_cask_tap? && (loader = FromAPILoader.try_new(token)) | 
					
						
							|  |  |  |           loader | 
					
						
							|  |  |  |         else | 
					
						
							|  |  |  |           new("#{tap}/#{token}") | 
					
						
							|  |  |  |         end | 
					
						
							| 
									
										
										
										
											2017-07-29 16:27:54 +02:00
										 |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-02-08 14:44:10 +01:00
										 |  |  |       sig { params(tapped_token: String).void } | 
					
						
							|  |  |  |       def initialize(tapped_token) | 
					
						
							| 
									
										
										
										
											2024-02-23 15:02:10 +01:00
										 |  |  |         tap, token = Tap.with_cask_token(tapped_token) | 
					
						
							| 
									
										
										
										
											2023-02-24 10:57:41 +00:00
										 |  |  |         cask = CaskLoader.find_cask_in_tap(token, tap) | 
					
						
							|  |  |  |         super cask | 
					
						
							| 
									
										
										
										
											2017-03-12 19:18:41 +01:00
										 |  |  |       end | 
					
						
							| 
									
										
										
										
											2016-10-08 13:25:38 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-02-20 18:08:55 +01:00
										 |  |  |       sig { override.params(config: T.nilable(Config)).returns(Cask) } | 
					
						
							| 
									
										
										
										
											2020-09-29 23:46:30 +02:00
										 |  |  |       def load(config:) | 
					
						
							| 
									
										
										
										
											2023-04-18 00:22:13 +01:00
										 |  |  |         raise TapCaskUnavailableError.new(tap, token) unless T.must(tap).installed? | 
					
						
							| 
									
										
										
										
											2017-03-12 19:18:41 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |         super | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-24 22:50:29 +02:00
										 |  |  |     # Loads a cask from an existing {Cask} instance. | 
					
						
							| 
									
										
										
										
											2017-09-11 08:37:15 +02:00
										 |  |  |     class FromInstanceLoader | 
					
						
							| 
									
										
										
										
											2023-03-12 17:06:29 -07:00
										 |  |  |       include ILoader | 
					
						
							| 
									
										
										
										
											2024-02-06 22:12:51 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-02-06 21:59:55 +01:00
										 |  |  |       sig { | 
					
						
							|  |  |  |         params(ref: T.any(String, Pathname, Cask, URI::Generic), warn: T::Boolean) | 
					
						
							|  |  |  |           .returns(T.nilable(T.attached_class)) | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       def self.try_new(ref, warn: false) | 
					
						
							| 
									
										
										
										
											2024-02-07 11:28:29 +01:00
										 |  |  |         new(ref) if ref.is_a?(Cask) | 
					
						
							| 
									
										
										
										
											2017-09-11 08:37:15 +02:00
										 |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-02-06 22:12:51 +01:00
										 |  |  |       sig { params(cask: Cask).void } | 
					
						
							| 
									
										
										
										
											2017-09-11 08:37:15 +02:00
										 |  |  |       def initialize(cask) | 
					
						
							|  |  |  |         @cask = cask | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-29 23:46:30 +02:00
										 |  |  |       def load(config:) | 
					
						
							|  |  |  |         @cask | 
					
						
							| 
									
										
										
										
											2017-09-11 08:37:15 +02:00
										 |  |  |       end | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-29 02:48:31 -05:00
										 |  |  |     # Loads a cask from the JSON API. | 
					
						
							|  |  |  |     class FromAPILoader | 
					
						
							| 
									
										
										
										
											2023-03-12 17:06:29 -07:00
										 |  |  |       include ILoader | 
					
						
							| 
									
										
										
										
											2024-02-06 22:12:51 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-02-08 16:18:05 +01:00
										 |  |  |       sig { returns(String) } | 
					
						
							|  |  |  |       attr_reader :token | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       sig { returns(Pathname) } | 
					
						
							|  |  |  |       attr_reader :path | 
					
						
							| 
									
										
										
										
											2022-12-29 02:48:31 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-02-06 22:12:51 +01:00
										 |  |  |       sig { returns(T.nilable(Hash)) } | 
					
						
							|  |  |  |       attr_reader :from_json | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-02-06 21:59:55 +01:00
										 |  |  |       sig { | 
					
						
							|  |  |  |         params(ref: T.any(String, Pathname, Cask, URI::Generic), warn: T::Boolean) | 
					
						
							|  |  |  |           .returns(T.nilable(T.attached_class)) | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       def self.try_new(ref, warn: false) | 
					
						
							|  |  |  |         return if Homebrew::EnvConfig.no_install_from_api? | 
					
						
							|  |  |  |         return unless ref.is_a?(String) | 
					
						
							| 
									
										
										
										
											2024-02-09 16:59:27 +01:00
										 |  |  |         return unless (token = ref[HOMEBREW_DEFAULT_TAP_CASK_REGEX, :token]) | 
					
						
							| 
									
										
										
										
											2024-02-09 18:27:58 +01:00
										 |  |  |         if !Homebrew::API::Cask.all_casks.key?(token) && | 
					
						
							|  |  |  |            !Homebrew::API::Cask.all_renames.key?(token) | 
					
						
							|  |  |  |           return | 
					
						
							|  |  |  |         end | 
					
						
							| 
									
										
										
										
											2024-02-06 21:59:55 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |         ref = "#{CoreCaskTap.instance}/#{token}" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-07 16:20:20 +00:00
										 |  |  |         token, tap, = CaskLoader.tap_cask_token_type(ref, warn:) | 
					
						
							| 
									
										
										
										
											2024-02-06 21:59:55 +01:00
										 |  |  |         new("#{tap}/#{token}") | 
					
						
							| 
									
										
										
										
											2022-12-29 02:48:31 -05:00
										 |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-05-06 23:34:23 -07:00
										 |  |  |       sig { params(token: String, from_json: Hash, path: T.nilable(Pathname)).void } | 
					
						
							|  |  |  |       def initialize(token, from_json: T.unsafe(nil), path: nil) | 
					
						
							| 
									
										
										
										
											2023-04-18 00:22:13 +01:00
										 |  |  |         @token = token.sub(%r{^homebrew/(?:homebrew-)?cask/}i, "") | 
					
						
							| 
									
										
										
										
											2024-07-03 13:41:52 -04:00
										 |  |  |         @sourcefile_path = path || Homebrew::API::Cask.cached_json_file_path | 
					
						
							| 
									
										
										
										
											2024-05-06 23:34:23 -07:00
										 |  |  |         @path = path || CaskLoader.default_path(@token) | 
					
						
							| 
									
										
										
										
											2023-02-05 12:22:08 +01:00
										 |  |  |         @from_json = from_json | 
					
						
							| 
									
										
										
										
											2022-12-29 02:48:31 -05:00
										 |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       def load(config:) | 
					
						
							| 
									
										
										
										
											2024-02-08 16:18:05 +01:00
										 |  |  |         json_cask = from_json || Homebrew::API::Cask.all_casks.fetch(token) | 
					
						
							| 
									
										
										
										
											2023-02-18 12:08:54 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |         cask_options = { | 
					
						
							|  |  |  |           loaded_from_api: true, | 
					
						
							| 
									
										
										
										
											2024-05-06 23:34:23 -07:00
										 |  |  |           sourcefile_path: @sourcefile_path, | 
					
						
							| 
									
										
										
										
											2023-02-18 12:08:54 -08:00
										 |  |  |           source:          JSON.pretty_generate(json_cask), | 
					
						
							| 
									
										
										
										
											2024-03-07 16:20:20 +00:00
										 |  |  |           config:, | 
					
						
							| 
									
										
										
										
											2023-02-18 12:08:54 -08:00
										 |  |  |           loader:          self, | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2022-12-29 02:48:31 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-25 02:08:39 -08:00
										 |  |  |         json_cask = Homebrew::API.merge_variations(json_cask).deep_symbolize_keys.freeze | 
					
						
							| 
									
										
										
										
											2023-01-06 02:41:35 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-18 12:08:54 -08:00
										 |  |  |         cask_options[:tap] = Tap.fetch(json_cask[:tap]) if json_cask[:tap].to_s.include?("/") | 
					
						
							| 
									
										
										
										
											2023-01-26 17:36:40 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-24 13:56:46 +00:00
										 |  |  |         user_agent = json_cask.dig(:url_specs, :user_agent) | 
					
						
							|  |  |  |         json_cask[:url_specs][:user_agent] = user_agent[1..].to_sym if user_agent && user_agent[0] == ":" | 
					
						
							|  |  |  |         if (using = json_cask.dig(:url_specs, :using)) | 
					
						
							|  |  |  |           json_cask[:url_specs][:using] = using.to_sym | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-18 12:08:54 -08:00
										 |  |  |         api_cask = Cask.new(token, **cask_options) do | 
					
						
							| 
									
										
										
										
											2022-12-29 02:48:31 -05:00
										 |  |  |           version json_cask[:version] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           if json_cask[:sha256] == "no_check" | 
					
						
							|  |  |  |             sha256 :no_check | 
					
						
							|  |  |  |           else | 
					
						
							|  |  |  |             sha256 json_cask[:sha256] | 
					
						
							|  |  |  |           end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-20 12:20:39 -07:00
										 |  |  |           url json_cask[:url], **json_cask.fetch(:url_specs, {}) if json_cask[:url].present? | 
					
						
							| 
									
										
										
										
											2024-01-01 19:10:48 -08:00
										 |  |  |           json_cask[:name]&.each do |cask_name| | 
					
						
							| 
									
										
										
										
											2022-12-29 02:48:31 -05:00
										 |  |  |             name cask_name | 
					
						
							|  |  |  |           end | 
					
						
							|  |  |  |           desc json_cask[:desc] | 
					
						
							|  |  |  |           homepage json_cask[:homepage] | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-12-04 00:30:49 -05:00
										 |  |  |           if (deprecation_date = json_cask[:deprecation_date].presence) | 
					
						
							|  |  |  |             reason = DeprecateDisable.to_reason_string_or_symbol json_cask[:deprecation_reason], type: :cask | 
					
						
							|  |  |  |             deprecate! date: deprecation_date, because: reason | 
					
						
							|  |  |  |           end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           if (disable_date = json_cask[:disable_date].presence) | 
					
						
							|  |  |  |             reason = DeprecateDisable.to_reason_string_or_symbol json_cask[:disable_reason], type: :cask | 
					
						
							| 
									
										
										
										
											2023-12-16 20:08:26 -05:00
										 |  |  |             disable! date: disable_date, because: reason | 
					
						
							| 
									
										
										
										
											2023-12-04 00:30:49 -05:00
										 |  |  |           end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-18 12:08:54 -08:00
										 |  |  |           auto_updates json_cask[:auto_updates] unless json_cask[:auto_updates].nil? | 
					
						
							| 
									
										
										
										
											2022-12-29 02:48:31 -05:00
										 |  |  |           conflicts_with(**json_cask[:conflicts_with]) if json_cask[:conflicts_with].present? | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           if json_cask[:depends_on].present? | 
					
						
							|  |  |  |             dep_hash = json_cask[:depends_on].to_h do |dep_key, dep_value| | 
					
						
							| 
									
										
										
										
											2023-01-11 13:16:34 -05:00
										 |  |  |               # Arch dependencies are encoded like `{ type: :intel, bits: 64 }` | 
					
						
							|  |  |  |               # but `depends_on arch:` only accepts `:intel` or `:arm64` | 
					
						
							| 
									
										
										
										
											2023-01-10 12:35:39 -05:00
										 |  |  |               if dep_key == :arch | 
					
						
							|  |  |  |                 next [:arch, :intel] if dep_value.first[:type] == "intel" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 next [:arch, :arm64] | 
					
						
							|  |  |  |               end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-18 15:06:50 -07:00
										 |  |  |               next [dep_key, dep_value] if dep_key != :macos | 
					
						
							| 
									
										
										
										
											2022-12-29 02:48:31 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |               dep_type = dep_value.keys.first | 
					
						
							|  |  |  |               if dep_type == :== | 
					
						
							|  |  |  |                 version_symbols = dep_value[dep_type].map do |version| | 
					
						
							| 
									
										
										
										
											2023-05-09 02:15:28 +02:00
										 |  |  |                   MacOSVersion::SYMBOLS.key(version) || version | 
					
						
							| 
									
										
										
										
											2022-12-29 02:48:31 -05:00
										 |  |  |                 end | 
					
						
							|  |  |  |                 next [dep_key, version_symbols] | 
					
						
							|  |  |  |               end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |               version_symbol = dep_value[dep_type].first | 
					
						
							| 
									
										
										
										
											2023-05-09 02:15:28 +02:00
										 |  |  |               version_symbol = MacOSVersion::SYMBOLS.key(version_symbol) || version_symbol | 
					
						
							| 
									
										
										
										
											2022-12-29 02:48:31 -05:00
										 |  |  |               [dep_key, "#{dep_type} :#{version_symbol}"] | 
					
						
							|  |  |  |             end.compact | 
					
						
							|  |  |  |             depends_on(**dep_hash) | 
					
						
							|  |  |  |           end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           if json_cask[:container].present? | 
					
						
							|  |  |  |             container_hash = json_cask[:container].to_h do |container_key, container_value| | 
					
						
							| 
									
										
										
										
											2023-04-18 15:06:50 -07:00
										 |  |  |               next [container_key, container_value] if container_key != :type | 
					
						
							| 
									
										
										
										
											2022-12-29 02:48:31 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |               [container_key, container_value.to_sym] | 
					
						
							|  |  |  |             end | 
					
						
							|  |  |  |             container(**container_hash) | 
					
						
							|  |  |  |           end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           json_cask[:artifacts].each do |artifact| | 
					
						
							| 
									
										
										
										
											2023-02-14 14:19:40 +00:00
										 |  |  |             # convert generic string replacements into actual ones | 
					
						
							| 
									
										
										
										
											2023-02-18 12:08:54 -08:00
										 |  |  |             artifact = cask.loader.from_h_gsubs(artifact, appdir) | 
					
						
							| 
									
										
										
										
											2022-12-29 02:48:31 -05:00
										 |  |  |             key = artifact.keys.first | 
					
						
							| 
									
										
										
										
											2023-02-25 02:08:39 -08:00
										 |  |  |             if artifact[key].nil? | 
					
						
							|  |  |  |               # for artifacts with blocks that can't be loaded from the API | 
					
						
							|  |  |  |               send(key) {} # empty on purpose | 
					
						
							|  |  |  |             else | 
					
						
							| 
									
										
										
										
											2023-09-29 04:47:44 +01:00
										 |  |  |               args = artifact[key] | 
					
						
							|  |  |  |               kwargs = if args.last.is_a?(Hash) | 
					
						
							|  |  |  |                 args.pop | 
					
						
							|  |  |  |               else | 
					
						
							|  |  |  |                 {} | 
					
						
							|  |  |  |               end | 
					
						
							|  |  |  |               send(key, *args, **kwargs) | 
					
						
							| 
									
										
										
										
											2023-02-25 02:08:39 -08:00
										 |  |  |             end | 
					
						
							| 
									
										
										
										
											2022-12-29 02:48:31 -05:00
										 |  |  |           end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-14 14:19:40 +00:00
										 |  |  |           if json_cask[:caveats].present? | 
					
						
							|  |  |  |             # convert generic string replacements into actual ones | 
					
						
							| 
									
										
										
										
											2023-02-25 02:08:39 -08:00
										 |  |  |             caveats cask.loader.from_h_string_gsubs(json_cask[:caveats], appdir) | 
					
						
							| 
									
										
										
										
											2023-02-14 14:19:40 +00:00
										 |  |  |           end | 
					
						
							| 
									
										
										
										
											2022-12-29 02:48:31 -05:00
										 |  |  |         end | 
					
						
							| 
									
										
										
										
											2023-02-25 02:08:39 -08:00
										 |  |  |         api_cask.populate_from_api!(json_cask) | 
					
						
							|  |  |  |         api_cask | 
					
						
							| 
									
										
										
										
											2022-12-29 02:48:31 -05:00
										 |  |  |       end | 
					
						
							| 
									
										
										
										
											2023-01-25 15:07:44 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-14 14:19:40 +00:00
										 |  |  |       def from_h_string_gsubs(string, appdir) | 
					
						
							| 
									
										
										
										
											2023-01-25 15:07:44 +00:00
										 |  |  |         string.to_s | 
					
						
							| 
									
										
										
										
											2023-03-21 19:05:41 -07:00
										 |  |  |               .gsub(HOMEBREW_HOME_PLACEHOLDER, Dir.home) | 
					
						
							|  |  |  |               .gsub(HOMEBREW_PREFIX_PLACEHOLDER, HOMEBREW_PREFIX) | 
					
						
							| 
									
										
										
										
											2023-07-18 10:59:27 +01:00
										 |  |  |               .gsub(HOMEBREW_CELLAR_PLACEHOLDER, HOMEBREW_CELLAR) | 
					
						
							| 
									
										
										
										
											2023-03-22 19:43:49 -07:00
										 |  |  |               .gsub(HOMEBREW_CASK_APPDIR_PLACEHOLDER, appdir) | 
					
						
							| 
									
										
										
										
											2023-01-25 15:07:44 +00:00
										 |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-14 14:19:40 +00:00
										 |  |  |       def from_h_array_gsubs(array, appdir) | 
					
						
							| 
									
										
										
										
											2023-01-25 15:07:44 +00:00
										 |  |  |         array.to_a.map do |value| | 
					
						
							| 
									
										
										
										
											2023-02-14 14:19:40 +00:00
										 |  |  |           from_h_gsubs(value, appdir) | 
					
						
							| 
									
										
										
										
											2023-01-25 15:07:44 +00:00
										 |  |  |         end | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-14 14:19:40 +00:00
										 |  |  |       def from_h_hash_gsubs(hash, appdir) | 
					
						
							| 
									
										
										
										
											2023-01-25 15:07:44 +00:00
										 |  |  |         hash.to_h.transform_values do |value| | 
					
						
							| 
									
										
										
										
											2023-02-14 14:19:40 +00:00
										 |  |  |           from_h_gsubs(value, appdir) | 
					
						
							| 
									
										
										
										
											2023-01-25 15:07:44 +00:00
										 |  |  |         end | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-14 14:19:40 +00:00
										 |  |  |       def from_h_gsubs(value, appdir) | 
					
						
							| 
									
										
										
										
											2023-02-05 02:49:41 +01:00
										 |  |  |         return value if value.blank? | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-18 12:08:54 -08:00
										 |  |  |         case value | 
					
						
							|  |  |  |         when Hash | 
					
						
							| 
									
										
										
										
											2023-02-14 14:19:40 +00:00
										 |  |  |           from_h_hash_gsubs(value, appdir) | 
					
						
							| 
									
										
										
										
											2023-02-18 12:08:54 -08:00
										 |  |  |         when Array | 
					
						
							| 
									
										
										
										
											2023-02-14 14:19:40 +00:00
										 |  |  |           from_h_array_gsubs(value, appdir) | 
					
						
							| 
									
										
										
										
											2023-02-18 12:08:54 -08:00
										 |  |  |         when String | 
					
						
							| 
									
										
										
										
											2023-02-14 14:19:40 +00:00
										 |  |  |           from_h_string_gsubs(value, appdir) | 
					
						
							| 
									
										
										
										
											2023-01-25 15:07:44 +00:00
										 |  |  |         else | 
					
						
							| 
									
										
										
										
											2023-02-06 15:07:28 +01:00
										 |  |  |           value | 
					
						
							| 
									
										
										
										
											2023-01-25 15:07:44 +00:00
										 |  |  |         end | 
					
						
							|  |  |  |       end | 
					
						
							| 
									
										
										
										
											2022-12-29 02:48:31 -05:00
										 |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-02-06 21:59:55 +01:00
										 |  |  |     # Loader which tries loading casks from tap paths, failing | 
					
						
							|  |  |  |     # if the same token exists in multiple taps. | 
					
						
							| 
									
										
										
										
											2024-02-12 07:43:29 +01:00
										 |  |  |     class FromNameLoader < FromTapLoader | 
					
						
							| 
									
										
										
										
											2024-02-09 19:28:45 +01:00
										 |  |  |       sig { | 
					
						
							| 
									
										
										
										
											2024-06-30 10:18:03 -07:00
										 |  |  |         override.params(ref: T.any(String, Pathname, Cask, URI::Generic), warn: T::Boolean) | 
					
						
							|  |  |  |                 .returns(T.nilable(T.any(T.attached_class, FromAPILoader))) | 
					
						
							| 
									
										
										
										
											2024-02-09 19:28:45 +01:00
										 |  |  |       } | 
					
						
							| 
									
										
										
										
											2024-02-06 21:59:55 +01:00
										 |  |  |       def self.try_new(ref, warn: false) | 
					
						
							| 
									
										
										
										
											2024-02-09 18:26:54 +01:00
										 |  |  |         return unless ref.is_a?(String) | 
					
						
							| 
									
										
										
										
											2024-03-06 23:06:36 +01:00
										 |  |  |         return unless ref.match?(/\A#{HOMEBREW_TAP_CASK_TOKEN_REGEX}\Z/o) | 
					
						
							| 
									
										
										
										
											2024-02-09 18:26:54 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |         token = ref | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-06 23:06:36 +01:00
										 |  |  |         # If it exists in the default tap, never treat it as ambiguous with another tap. | 
					
						
							|  |  |  |         if (core_cask_tap = CoreCaskTap.instance).installed? && | 
					
						
							| 
									
										
										
										
											2024-07-01 18:41:53 -07:00
										 |  |  |            (core_cask_loader = super("#{core_cask_tap}/#{token}", warn:))&.path&.exist? | 
					
						
							|  |  |  |           return core_cask_loader | 
					
						
							| 
									
										
										
										
											2024-03-06 23:06:36 +01:00
										 |  |  |         end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         loaders = Tap.select { |tap| tap.installed? && !tap.core_cask_tap? } | 
					
						
							| 
									
										
										
										
											2024-03-07 16:20:20 +00:00
										 |  |  |                      .filter_map { |tap| super("#{tap}/#{token}", warn:) } | 
					
						
							| 
									
										
										
										
											2024-05-28 20:36:19 +02:00
										 |  |  |                      .uniq(&:path) | 
					
						
							| 
									
										
										
										
											2024-07-01 18:41:53 -07:00
										 |  |  |                      .select { |loader| loader.is_a?(FromAPILoader) || loader.path.exist? } | 
					
						
							| 
									
										
										
										
											2024-02-09 18:26:54 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |         case loaders.count | 
					
						
							| 
									
										
										
										
											2024-02-06 21:59:55 +01:00
										 |  |  |         when 1
 | 
					
						
							| 
									
										
										
										
											2024-02-09 18:26:54 +01:00
										 |  |  |           loaders.first | 
					
						
							| 
									
										
										
										
											2024-02-06 21:59:55 +01:00
										 |  |  |         when 2..Float::INFINITY | 
					
						
							| 
									
										
										
										
											2024-02-20 18:08:55 +01:00
										 |  |  |           raise TapCaskAmbiguityError.new(token, loaders) | 
					
						
							| 
									
										
										
										
											2024-02-06 21:59:55 +01:00
										 |  |  |         end | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # Loader which loads a cask from the installed cask file. | 
					
						
							|  |  |  |     class FromInstalledPathLoader < FromPathLoader | 
					
						
							| 
									
										
										
										
											2024-02-09 19:28:45 +01:00
										 |  |  |       sig { | 
					
						
							| 
									
										
										
										
											2024-06-30 10:18:03 -07:00
										 |  |  |         override.params(ref: T.any(String, Pathname, Cask, URI::Generic), warn: T::Boolean) | 
					
						
							|  |  |  |                 .returns(T.nilable(T.attached_class)) | 
					
						
							| 
									
										
										
										
											2024-02-09 19:28:45 +01:00
										 |  |  |       } | 
					
						
							| 
									
										
										
										
											2024-02-06 21:59:55 +01:00
										 |  |  |       def self.try_new(ref, warn: false) | 
					
						
							| 
									
										
										
										
											2024-02-09 19:28:45 +01:00
										 |  |  |         return unless ref.is_a?(String) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-02-06 21:59:55 +01:00
										 |  |  |         possible_installed_cask = Cask.new(ref) | 
					
						
							|  |  |  |         return unless (installed_caskfile = possible_installed_cask.installed_caskfile) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         new(installed_caskfile) | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-24 22:50:29 +02:00
										 |  |  |     # Pseudo-loader which raises an error when trying to load the corresponding cask. | 
					
						
							| 
									
										
										
										
											2017-03-12 19:18:41 +01:00
										 |  |  |     class NullLoader < FromPathLoader | 
					
						
							| 
									
										
										
										
											2024-02-06 21:59:55 +01:00
										 |  |  |       sig { | 
					
						
							| 
									
										
										
										
											2024-06-30 10:18:03 -07:00
										 |  |  |         override.params(ref: T.any(String, Pathname, Cask, URI::Generic), warn: T::Boolean) | 
					
						
							|  |  |  |                 .returns(T.nilable(T.attached_class)) | 
					
						
							| 
									
										
										
										
											2024-02-06 21:59:55 +01:00
										 |  |  |       } | 
					
						
							|  |  |  |       def self.try_new(ref, warn: false) | 
					
						
							|  |  |  |         return if ref.is_a?(Cask) | 
					
						
							|  |  |  |         return if ref.is_a?(URI::Generic) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         new(ref) | 
					
						
							| 
									
										
										
										
											2017-03-12 19:18:41 +01:00
										 |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-20 12:03:48 +02:00
										 |  |  |       sig { params(ref: T.any(String, Pathname)).void } | 
					
						
							| 
									
										
										
										
											2017-03-12 19:18:41 +01:00
										 |  |  |       def initialize(ref) | 
					
						
							| 
									
										
										
										
											2017-06-28 09:25:14 +02:00
										 |  |  |         token = File.basename(ref, ".rb") | 
					
						
							|  |  |  |         super CaskLoader.default_path(token) | 
					
						
							| 
									
										
										
										
											2017-03-12 19:18:41 +01:00
										 |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-29 23:46:30 +02:00
										 |  |  |       def load(config:) | 
					
						
							| 
									
										
										
										
											2017-06-28 09:25:14 +02:00
										 |  |  |         raise CaskUnavailableError.new(token, "No Cask with this name exists.") | 
					
						
							| 
									
										
										
										
											2017-03-12 19:18:41 +01:00
										 |  |  |       end | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def self.path(ref) | 
					
						
							| 
									
										
										
										
											2023-01-04 13:51:21 +00:00
										 |  |  |       self.for(ref, need_path: true).path | 
					
						
							| 
									
										
										
										
											2017-03-12 19:18:41 +01:00
										 |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-08 14:10:58 +02:00
										 |  |  |     def self.load(ref, config: nil, warn: true) | 
					
						
							| 
									
										
										
										
											2024-03-07 16:20:20 +00:00
										 |  |  |       self.for(ref, warn:).load(config:) | 
					
						
							| 
									
										
										
										
											2017-03-12 19:18:41 +01:00
										 |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-01 03:13:56 +01:00
										 |  |  |     sig { params(tapped_token: String, warn: T::Boolean).returns(T.nilable([String, Tap, T.nilable(Symbol)])) } | 
					
						
							| 
									
										
										
										
											2024-02-06 22:12:51 +01:00
										 |  |  |     def self.tap_cask_token_type(tapped_token, warn:) | 
					
						
							| 
									
										
										
										
											2024-03-01 03:13:56 +01:00
										 |  |  |       return unless (tap_with_token = Tap.with_cask_token(tapped_token)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       tap, token = tap_with_token | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-02-06 22:12:51 +01:00
										 |  |  |       type = nil | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       if (new_token = tap.cask_renames[token].presence) | 
					
						
							| 
									
										
										
										
											2024-02-13 04:09:49 +01:00
										 |  |  |         old_token = tap.core_cask_tap? ? token : tapped_token | 
					
						
							| 
									
										
										
										
											2024-02-06 22:12:51 +01:00
										 |  |  |         token = new_token | 
					
						
							|  |  |  |         new_token = tap.core_cask_tap? ? token : "#{tap}/#{token}" | 
					
						
							|  |  |  |         type = :rename | 
					
						
							|  |  |  |       elsif (new_tap_name = tap.tap_migrations[token].presence) | 
					
						
							| 
									
										
										
										
											2024-02-23 15:02:10 +01:00
										 |  |  |         new_tap, new_token = Tap.with_cask_token(new_tap_name) || [Tap.fetch(new_tap_name), token] | 
					
						
							| 
									
										
										
										
											2024-02-06 22:12:51 +01:00
										 |  |  |         new_tap.ensure_installed! | 
					
						
							| 
									
										
										
										
											2024-02-13 04:09:49 +01:00
										 |  |  |         new_tapped_token = "#{new_tap}/#{new_token}" | 
					
						
							| 
									
										
										
										
											2024-02-10 14:56:53 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |         if tapped_token == new_tapped_token | 
					
						
							|  |  |  |           opoo "Tap migration for #{tapped_token} points to itself, stopping recursion." | 
					
						
							|  |  |  |         else | 
					
						
							| 
									
										
										
										
											2024-02-13 04:09:49 +01:00
										 |  |  |           old_token = tap.core_cask_tap? ? token : tapped_token | 
					
						
							| 
									
										
										
										
											2024-03-01 03:13:56 +01:00
										 |  |  |           return unless (token_tap_type = tap_cask_token_type(new_tapped_token, warn: false)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           token, tap, = token_tap_type | 
					
						
							| 
									
										
										
										
											2024-02-13 04:09:49 +01:00
										 |  |  |           new_token = new_tap.core_cask_tap? ? token : "#{tap}/#{token}" | 
					
						
							| 
									
										
										
										
											2024-02-10 14:56:53 +01:00
										 |  |  |           type = :migration | 
					
						
							|  |  |  |         end | 
					
						
							| 
									
										
										
										
											2024-02-06 22:12:51 +01:00
										 |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       opoo "Cask #{old_token} was renamed to #{new_token}." if warn && old_token && new_token | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       [token, tap, type] | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-08 14:10:58 +02:00
										 |  |  |     def self.for(ref, need_path: false, warn: true) | 
					
						
							| 
									
										
										
										
											2017-03-12 19:18:41 +01:00
										 |  |  |       [ | 
					
						
							| 
									
										
										
										
											2017-09-11 08:37:15 +02:00
										 |  |  |         FromInstanceLoader, | 
					
						
							| 
									
										
										
										
											2017-10-08 15:20:58 +02:00
										 |  |  |         FromContentLoader, | 
					
						
							| 
									
										
										
										
											2017-03-12 19:18:41 +01:00
										 |  |  |         FromURILoader, | 
					
						
							| 
									
										
										
										
											2023-01-31 00:09:57 -08:00
										 |  |  |         FromAPILoader, | 
					
						
							| 
									
										
										
										
											2017-03-12 19:18:41 +01:00
										 |  |  |         FromTapLoader, | 
					
						
							| 
									
										
										
										
											2024-02-09 18:26:54 +01:00
										 |  |  |         FromNameLoader, | 
					
						
							| 
									
										
										
										
											2017-03-12 19:18:41 +01:00
										 |  |  |         FromPathLoader, | 
					
						
							| 
									
										
										
										
											2024-02-06 21:59:55 +01:00
										 |  |  |         FromInstalledPathLoader, | 
					
						
							|  |  |  |         NullLoader, | 
					
						
							| 
									
										
										
										
											2017-03-12 19:18:41 +01:00
										 |  |  |       ].each do |loader_class| | 
					
						
							| 
									
										
										
										
											2024-03-07 16:20:20 +00:00
										 |  |  |         if (loader = loader_class.try_new(ref, warn:)) | 
					
						
							| 
									
										
										
										
											2024-02-07 11:29:39 +01:00
										 |  |  |           $stderr.puts "#{$PROGRAM_NAME} (#{loader.class}): loading #{ref}" if debug? | 
					
						
							| 
									
										
										
										
											2024-02-06 21:59:55 +01:00
										 |  |  |           return loader | 
					
						
							| 
									
										
										
										
											2023-02-05 13:06:56 -08:00
										 |  |  |         end | 
					
						
							| 
									
										
										
										
											2016-10-08 13:25:38 +02:00
										 |  |  |       end | 
					
						
							| 
									
										
										
										
											2017-03-12 19:18:41 +01:00
										 |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def self.default_path(token) | 
					
						
							| 
									
										
										
										
											2023-08-04 16:21:31 +01:00
										 |  |  |       find_cask_in_tap(token.to_s.downcase, CoreCaskTap.instance) | 
					
						
							| 
									
										
										
										
											2017-03-12 19:18:41 +01:00
										 |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-24 10:57:41 +00:00
										 |  |  |     def self.find_cask_in_tap(token, tap) | 
					
						
							|  |  |  |       filename = "#{token}.rb" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-02-23 15:03:05 +01:00
										 |  |  |       tap.cask_files_by_name.fetch(token, tap.cask_dir/filename) | 
					
						
							| 
									
										
										
										
											2016-10-08 13:25:38 +02:00
										 |  |  |     end | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | end |