| 
									
										
										
										
											2024-08-12 10:30:59 +01:00
										 |  |  | # typed: true # rubocop:todo Sorbet/StrictSigil | 
					
						
							| 
									
										
										
										
											2019-04-19 15:38:03 +09:00
										 |  |  | # frozen_string_literal: true | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-09 11:12:49 +00:00
										 |  |  | require "digest/sha2" | 
					
						
							| 
									
										
										
										
											2017-10-07 00:31:28 +02:00
										 |  |  | require "extend/cachable" | 
					
						
							| 
									
										
										
										
											2020-08-18 00:23:23 +01:00
										 |  |  | require "tab" | 
					
						
							| 
									
										
										
										
											2024-07-14 08:49:39 -04:00
										 |  |  | require "utils" | 
					
						
							| 
									
										
										
										
											2021-03-30 17:35:13 +01:00
										 |  |  | require "utils/bottles" | 
					
						
							| 
									
										
										
										
											2023-03-24 09:23:09 +00:00
										 |  |  | require "service" | 
					
						
							| 
									
										
										
										
											2023-09-04 22:17:57 -04:00
										 |  |  | require "utils/curl" | 
					
						
							| 
									
										
										
										
											2023-12-04 00:30:49 -05:00
										 |  |  | require "deprecate_disable" | 
					
						
							| 
									
										
										
										
											2024-01-11 20:03:06 -08:00
										 |  |  | require "extend/hash/deep_transform_values" | 
					
						
							| 
									
										
										
										
											2024-01-12 09:38:49 -08:00
										 |  |  | require "extend/hash/keys" | 
					
						
							| 
									
										
										
										
											2024-07-14 08:49:39 -04:00
										 |  |  | require "tap" | 
					
						
							| 
									
										
										
										
											2021-12-07 00:13:56 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-05 17:17:03 -05:00
										 |  |  | # The {Formulary} is responsible for creating instances of {Formula}. | 
					
						
							| 
									
										
										
										
											2016-05-22 21:29:22 +01:00
										 |  |  | # It is not meant to be used directly from formulae. | 
					
						
							| 
									
										
										
										
											2017-02-20 13:06:23 +01:00
										 |  |  | module Formulary | 
					
						
							| 
									
										
										
										
											2024-02-16 21:27:02 +01:00
										 |  |  |   extend Context | 
					
						
							| 
									
										
										
										
											2017-10-07 00:31:28 +02:00
										 |  |  |   extend Cachable | 
					
						
							| 
									
										
										
										
											2015-01-01 01:21:59 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-07-13 12:16:36 -04:00
										 |  |  |   ALLOWED_URL_SCHEMES = %w[file].freeze | 
					
						
							|  |  |  |   private_constant :ALLOWED_URL_SCHEMES | 
					
						
							| 
									
										
										
										
											2020-05-29 13:15:08 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-06 01:00:39 +01:00
										 |  |  |   # `:codesign` and custom requirement classes are not supported. | 
					
						
							| 
									
										
										
										
											2023-02-14 02:03:58 +00:00
										 |  |  |   API_SUPPORTED_REQUIREMENTS = [:arch, :linux, :macos, :maximum_macos, :xcode].freeze | 
					
						
							| 
									
										
										
										
											2024-03-06 01:00:39 +01:00
										 |  |  |   private_constant :API_SUPPORTED_REQUIREMENTS | 
					
						
							| 
									
										
										
										
											2023-02-14 02:03:58 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-22 21:05:48 +02:00
										 |  |  |   # Enable the factory cache. | 
					
						
							|  |  |  |   # | 
					
						
							|  |  |  |   # @api internal | 
					
						
							| 
									
										
										
										
											2020-10-20 12:03:48 +02:00
										 |  |  |   sig { void } | 
					
						
							| 
									
										
										
										
											2019-11-06 10:03:44 +00:00
										 |  |  |   def self.enable_factory_cache! | 
					
						
							|  |  |  |     @factory_cache = true | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   def self.factory_cached? | 
					
						
							|  |  |  |     !@factory_cache.nil? | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-09 11:12:49 +00:00
										 |  |  |   def self.platform_cache | 
					
						
							|  |  |  |     cache["#{Homebrew::SimulateSystem.current_os}_#{Homebrew::SimulateSystem.current_arch}"] ||= {} | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-06-14 14:49:00 -04:00
										 |  |  |   def self.formula_class_defined_from_path?(path) | 
					
						
							| 
									
										
										
										
											2024-01-09 11:12:49 +00:00
										 |  |  |     platform_cache.key?(:path) && platform_cache[:path].key?(path) | 
					
						
							| 
									
										
										
										
											2013-06-18 10:11:06 -07:00
										 |  |  |   end | 
					
						
							| 
									
										
										
										
											2013-06-08 20:58:43 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-06-14 14:49:00 -04:00
										 |  |  |   def self.formula_class_defined_from_api?(name) | 
					
						
							| 
									
										
										
										
											2024-01-09 11:12:49 +00:00
										 |  |  |     platform_cache.key?(:api) && platform_cache[:api].key?(name) | 
					
						
							| 
									
										
										
										
											2022-06-14 14:49:00 -04:00
										 |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   def self.formula_class_get_from_path(path) | 
					
						
							| 
									
										
										
										
											2024-01-09 11:12:49 +00:00
										 |  |  |     platform_cache[:path].fetch(path) | 
					
						
							| 
									
										
										
										
											2022-06-14 14:49:00 -04:00
										 |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   def self.formula_class_get_from_api(name) | 
					
						
							| 
									
										
										
										
											2024-01-09 11:12:49 +00:00
										 |  |  |     platform_cache[:api].fetch(name) | 
					
						
							| 
									
										
										
										
											2013-06-18 10:11:06 -07:00
										 |  |  |   end | 
					
						
							| 
									
										
										
										
											2013-06-08 20:58:43 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-02-17 15:14:16 +00:00
										 |  |  |   def self.clear_cache | 
					
						
							| 
									
										
										
										
											2024-01-09 11:12:49 +00:00
										 |  |  |     platform_cache.each do |type, cached_objects| | 
					
						
							| 
									
										
										
										
											2022-06-14 14:49:00 -04:00
										 |  |  |       next if type == :formulary_factory | 
					
						
							| 
									
										
										
										
											2021-02-17 15:14:16 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-06-14 15:09:44 -04:00
										 |  |  |       cached_objects.each_value do |klass| | 
					
						
							| 
									
										
										
										
											2023-04-14 15:33:40 +02:00
										 |  |  |         class_name = klass.name | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # Already removed from namespace. | 
					
						
							|  |  |  |         next if class_name.nil? | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         namespace = Utils.deconstantize(class_name) | 
					
						
							| 
									
										
										
										
											2023-02-27 20:16:34 -08:00
										 |  |  |         next if Utils.deconstantize(namespace) != name | 
					
						
							| 
									
										
										
										
											2021-02-17 15:14:16 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-25 08:36:56 -07:00
										 |  |  |         remove_const(Utils.demodulize(namespace).to_sym) | 
					
						
							| 
									
										
										
										
											2022-06-14 14:49:00 -04:00
										 |  |  |       end | 
					
						
							| 
									
										
										
										
											2021-02-17 15:14:16 +00:00
										 |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     super | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-03 13:24:32 +01:00
										 |  |  |   module PathnameWriteMkpath | 
					
						
							|  |  |  |     refine Pathname do | 
					
						
							|  |  |  |       def write(content, offset = nil, **open_args) | 
					
						
							| 
									
										
										
										
											2023-03-25 08:36:56 -07:00
										 |  |  |         T.bind(self, Pathname) | 
					
						
							| 
									
										
										
										
											2021-05-03 13:24:32 +01:00
										 |  |  |         raise "Will not overwrite #{self}" if exist? && !offset && !open_args[:mode]&.match?(/^a\+?$/) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         dirname.mkpath | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         super | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   using PathnameWriteMkpath | 
					
						
							| 
									
										
										
										
											2021-04-13 17:40:41 +01:00
										 |  |  |   def self.load_formula(name, path, contents, namespace, flags:, ignore_errors:) | 
					
						
							| 
									
										
										
										
											2020-04-05 15:44:50 +01:00
										 |  |  |     raise "Formula loading disabled by HOMEBREW_DISABLE_LOAD_FORMULA!" if Homebrew::EnvConfig.disable_load_formula? | 
					
						
							| 
									
										
										
										
											2016-05-28 15:54:05 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-18 00:23:23 +01:00
										 |  |  |     require "formula" | 
					
						
							| 
									
										
										
										
											2021-04-13 17:40:41 +01:00
										 |  |  |     require "ignorable" | 
					
						
							| 
									
										
										
										
											2020-08-18 00:23:23 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-01 19:20:11 -04:00
										 |  |  |     mod = Module.new | 
					
						
							| 
									
										
										
										
											2021-03-31 09:27:07 +01:00
										 |  |  |     remove_const(namespace) if const_defined?(namespace) | 
					
						
							| 
									
										
										
										
											2015-09-02 16:12:26 +08:00
										 |  |  |     const_set(namespace, mod) | 
					
						
							| 
									
										
										
										
											2020-07-26 07:24:14 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-04-13 17:40:41 +01:00
										 |  |  |     eval_formula = lambda do | 
					
						
							| 
									
										
										
										
											2020-07-30 10:10:42 +02:00
										 |  |  |       # Set `BUILD_FLAGS` in the formula's namespace so we can | 
					
						
							|  |  |  |       # access them from within the formula's class scope. | 
					
						
							| 
									
										
										
										
											2020-07-26 07:24:14 +02:00
										 |  |  |       mod.const_set(:BUILD_FLAGS, flags) | 
					
						
							| 
									
										
										
										
											2017-02-01 18:30:55 +00:00
										 |  |  |       mod.module_eval(contents, path) | 
					
						
							| 
									
										
										
										
											2023-05-09 02:15:28 +02:00
										 |  |  |     rescue NameError, ArgumentError, ScriptError, MethodDeprecatedError, MacOSVersion::Error => e | 
					
						
							| 
									
										
										
										
											2021-04-13 17:40:41 +01:00
										 |  |  |       if e.is_a?(Ignorable::ExceptionMixin) | 
					
						
							|  |  |  |         e.ignore | 
					
						
							|  |  |  |       else | 
					
						
							|  |  |  |         remove_const(namespace) | 
					
						
							|  |  |  |         raise FormulaUnreadableError.new(name, e) | 
					
						
							|  |  |  |       end | 
					
						
							| 
									
										
										
										
											2017-02-01 18:30:55 +00:00
										 |  |  |     end | 
					
						
							| 
									
										
										
										
											2021-04-13 17:40:41 +01:00
										 |  |  |     if ignore_errors | 
					
						
							|  |  |  |       Ignorable.hook_raise(&eval_formula) | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |       eval_formula.call | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-01 19:20:11 -04:00
										 |  |  |     class_name = class_s(name) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     begin | 
					
						
							| 
									
										
										
										
											2015-09-02 16:12:26 +08:00
										 |  |  |       mod.const_get(class_name) | 
					
						
							| 
									
										
										
										
											2019-04-30 08:44:35 +01:00
										 |  |  |     rescue NameError => e | 
					
						
							| 
									
										
										
										
											2016-09-17 15:17:27 +01:00
										 |  |  |       class_list = mod.constants | 
					
						
							|  |  |  |                       .map { |const_name| mod.const_get(const_name) } | 
					
						
							|  |  |  |                       .select { |const| const.is_a?(Class) } | 
					
						
							| 
									
										
										
										
											2019-04-30 08:44:35 +01:00
										 |  |  |       new_exception = FormulaClassUnavailableError.new(name, path, class_name, class_list) | 
					
						
							| 
									
										
										
										
											2021-02-17 17:38:16 +00:00
										 |  |  |       remove_const(namespace) | 
					
						
							| 
									
										
										
										
											2019-04-30 08:44:35 +01:00
										 |  |  |       raise new_exception, "", e.backtrace | 
					
						
							| 
									
										
										
										
											2015-06-01 19:20:11 -04:00
										 |  |  |     end | 
					
						
							| 
									
										
										
										
											2013-12-09 21:10:32 -06:00
										 |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-09 11:12:49 +00:00
										 |  |  |   sig { params(identifier: String).returns(String) } | 
					
						
							|  |  |  |   def self.namespace_key(identifier) | 
					
						
							|  |  |  |     Digest::SHA2.hexdigest( | 
					
						
							|  |  |  |       "#{Homebrew::SimulateSystem.current_os}_#{Homebrew::SimulateSystem.current_arch}:#{identifier}", | 
					
						
							|  |  |  |     ) | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-14 15:33:40 +02:00
										 |  |  |   sig { | 
					
						
							|  |  |  |     params(name: String, path: Pathname, flags: T::Array[String], ignore_errors: T::Boolean) | 
					
						
							|  |  |  |       .returns(T.class_of(Formula)) | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2021-04-13 17:40:41 +01:00
										 |  |  |   def self.load_formula_from_path(name, path, flags:, ignore_errors:) | 
					
						
							| 
									
										
										
										
											2016-09-24 17:59:14 +02:00
										 |  |  |     contents = path.open("r") { |f| ensure_utf8_encoding(f).read } | 
					
						
							| 
									
										
										
										
											2024-01-09 11:12:49 +00:00
										 |  |  |     namespace = "FormulaNamespace#{namespace_key(path.to_s)}" | 
					
						
							| 
									
										
										
										
											2024-03-07 16:20:20 +00:00
										 |  |  |     klass = load_formula(name, path, contents, namespace, flags:, ignore_errors:) | 
					
						
							| 
									
										
										
										
											2024-01-09 11:12:49 +00:00
										 |  |  |     platform_cache[:path] ||= {} | 
					
						
							|  |  |  |     platform_cache[:path][path] = klass | 
					
						
							| 
									
										
										
										
											2022-06-14 14:49:00 -04:00
										 |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-14 15:33:40 +02:00
										 |  |  |   sig { params(name: String, flags: T::Array[String]).returns(T.class_of(Formula)) } | 
					
						
							| 
									
										
										
										
											2022-06-15 16:57:15 -04:00
										 |  |  |   def self.load_formula_from_api(name, flags:) | 
					
						
							| 
									
										
										
										
											2024-01-09 11:12:49 +00:00
										 |  |  |     namespace = :"FormulaNamespaceAPI#{namespace_key(name)}" | 
					
						
							| 
									
										
										
										
											2022-06-14 14:49:00 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  |     mod = Module.new | 
					
						
							| 
									
										
										
										
											2023-03-25 17:39:39 -07:00
										 |  |  |     remove_const(namespace) if const_defined?(namespace) | 
					
						
							| 
									
										
										
										
											2022-06-14 14:49:00 -04:00
										 |  |  |     const_set(namespace, mod) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     mod.const_set(:BUILD_FLAGS, flags) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-15 13:58:33 +02:00
										 |  |  |     class_name = class_s(name) | 
					
						
							| 
									
										
										
										
											2022-06-14 14:49:00 -04:00
										 |  |  |     json_formula = Homebrew::API::Formula.all_formulae[name] | 
					
						
							| 
									
										
										
										
											2023-10-12 16:59:10 +01:00
										 |  |  |     raise FormulaUnavailableError, name if json_formula.nil? | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-10 12:07:36 -05:00
										 |  |  |     json_formula = Homebrew::API.merge_variations(json_formula) | 
					
						
							| 
									
										
										
										
											2022-07-24 22:59:42 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-09 23:33:20 -08:00
										 |  |  |     uses_from_macos_names = json_formula.fetch("uses_from_macos", []).map do |dep| | 
					
						
							| 
									
										
										
										
											2022-07-25 08:49:19 +02:00
										 |  |  |       next dep unless dep.is_a? Hash | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       dep.keys.first | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-19 06:07:53 +01:00
										 |  |  |     requirements = {} | 
					
						
							| 
									
										
										
										
											2024-01-01 19:10:48 -08:00
										 |  |  |     json_formula["requirements"]&.map do |req| | 
					
						
							| 
									
										
										
										
											2023-06-19 06:07:53 +01:00
										 |  |  |       req_name = req["name"].to_sym | 
					
						
							|  |  |  |       next if API_SUPPORTED_REQUIREMENTS.exclude?(req_name) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       req_version = case req_name | 
					
						
							|  |  |  |       when :arch | 
					
						
							|  |  |  |         req["version"]&.to_sym | 
					
						
							|  |  |  |       when :macos, :maximum_macos | 
					
						
							|  |  |  |         MacOSVersion::SYMBOLS.key(req["version"]) | 
					
						
							|  |  |  |       else | 
					
						
							|  |  |  |         req["version"] | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       req_tags = [] | 
					
						
							|  |  |  |       req_tags << req_version if req_version.present? | 
					
						
							| 
									
										
										
										
											2024-01-01 19:10:48 -08:00
										 |  |  |       req_tags += req["contexts"]&.map do |tag| | 
					
						
							| 
									
										
										
										
											2023-06-19 06:07:53 +01:00
										 |  |  |         case tag | 
					
						
							|  |  |  |         when String | 
					
						
							|  |  |  |           tag.to_sym | 
					
						
							|  |  |  |         when Hash | 
					
						
							|  |  |  |           tag.deep_transform_keys(&:to_sym) | 
					
						
							|  |  |  |         else | 
					
						
							|  |  |  |           tag | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       spec_hash = req_tags.empty? ? req_name : { req_name => req_tags } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       specs = req["specs"] | 
					
						
							|  |  |  |       specs ||= ["stable", "head"] # backwards compatibility | 
					
						
							|  |  |  |       specs.each do |spec| | 
					
						
							|  |  |  |         requirements[spec.to_sym] ||= [] | 
					
						
							|  |  |  |         requirements[spec.to_sym] << spec_hash | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-02-06 21:04:08 -08:00
										 |  |  |     add_deps = lambda do |spec| | 
					
						
							|  |  |  |       T.bind(self, SoftwareSpec) | 
					
						
							| 
									
										
										
										
											2023-06-19 06:07:53 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-02-06 21:04:08 -08:00
										 |  |  |       dep_json = json_formula.fetch("#{spec}_dependencies", json_formula) | 
					
						
							| 
									
										
										
										
											2024-04-25 21:41:13 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-02-06 21:04:08 -08:00
										 |  |  |       dep_json["dependencies"]&.each do |dep| | 
					
						
							|  |  |  |         # Backwards compatibility check - uses_from_macos used to be a part of dependencies on Linux | 
					
						
							|  |  |  |         next if !json_formula.key?("uses_from_macos_bounds") && uses_from_macos_names.include?(dep) && | 
					
						
							|  |  |  |                 !Homebrew::SimulateSystem.simulating_or_running_on_macos? | 
					
						
							| 
									
										
										
										
											2024-04-25 21:41:13 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-02-06 21:04:08 -08:00
										 |  |  |         depends_on dep | 
					
						
							|  |  |  |       end | 
					
						
							| 
									
										
										
										
											2023-06-19 06:07:53 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-02-06 21:04:08 -08:00
										 |  |  |       [:build, :test, :recommended, :optional].each do |type| | 
					
						
							|  |  |  |         dep_json["#{type}_dependencies"]&.each do |dep| | 
					
						
							| 
									
										
										
										
											2023-06-19 06:07:53 +01:00
										 |  |  |           # Backwards compatibility check - uses_from_macos used to be a part of dependencies on Linux | 
					
						
							|  |  |  |           next if !json_formula.key?("uses_from_macos_bounds") && uses_from_macos_names.include?(dep) && | 
					
						
							|  |  |  |                   !Homebrew::SimulateSystem.simulating_or_running_on_macos? | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-02-06 21:04:08 -08:00
										 |  |  |           depends_on dep => type | 
					
						
							| 
									
										
										
										
											2024-04-25 21:41:13 -07:00
										 |  |  |         end | 
					
						
							| 
									
										
										
										
											2025-02-06 21:04:08 -08:00
										 |  |  |       end | 
					
						
							| 
									
										
										
										
											2024-04-25 21:41:13 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-02-06 21:04:08 -08:00
										 |  |  |       dep_json["uses_from_macos"]&.each_with_index do |dep, index| | 
					
						
							|  |  |  |         bounds = dep_json.fetch("uses_from_macos_bounds", [])[index].dup || {} | 
					
						
							|  |  |  |         bounds.deep_transform_keys!(&:to_sym) | 
					
						
							|  |  |  |         bounds.deep_transform_values!(&:to_sym) | 
					
						
							| 
									
										
										
										
											2024-04-25 21:41:13 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-02-06 21:04:08 -08:00
										 |  |  |         if dep.is_a?(Hash) | 
					
						
							|  |  |  |           uses_from_macos dep.deep_transform_values(&:to_sym).merge(bounds) | 
					
						
							|  |  |  |         else | 
					
						
							|  |  |  |           uses_from_macos dep, bounds | 
					
						
							| 
									
										
										
										
											2023-06-19 06:07:53 +01:00
										 |  |  |         end | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-06-14 14:49:00 -04:00
										 |  |  |     klass = Class.new(::Formula) do | 
					
						
							| 
									
										
										
										
											2023-05-15 13:58:33 +02:00
										 |  |  |       @loaded_from_api = true | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-06-14 14:49:00 -04:00
										 |  |  |       desc json_formula["desc"] | 
					
						
							|  |  |  |       homepage json_formula["homepage"] | 
					
						
							| 
									
										
										
										
											2023-02-06 09:57:25 +00:00
										 |  |  |       license SPDX.string_to_license_expression(json_formula["license"]) | 
					
						
							| 
									
										
										
										
											2024-02-10 23:00:38 -08:00
										 |  |  |       revision json_formula.fetch("revision", 0) | 
					
						
							|  |  |  |       version_scheme json_formula.fetch("version_scheme", 0) | 
					
						
							| 
									
										
										
										
											2022-06-14 14:49:00 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-18 13:14:52 +01:00
										 |  |  |       if (urls_stable = json_formula["urls"]["stable"].presence) | 
					
						
							| 
									
										
										
										
											2022-06-14 14:49:00 -04:00
										 |  |  |         stable do | 
					
						
							| 
									
										
										
										
											2023-10-11 09:47:15 -04:00
										 |  |  |           url_spec = { | 
					
						
							|  |  |  |             tag:      urls_stable["tag"], | 
					
						
							|  |  |  |             revision: urls_stable["revision"], | 
					
						
							|  |  |  |             using:    urls_stable["using"]&.to_sym, | 
					
						
							|  |  |  |           }.compact | 
					
						
							| 
									
										
										
										
											2023-02-15 03:44:44 +00:00
										 |  |  |           url urls_stable["url"], **url_spec | 
					
						
							| 
									
										
										
										
											2025-02-06 21:04:08 -08:00
										 |  |  |           version json_formula["versions"]["stable"] | 
					
						
							| 
									
										
										
										
											2022-10-21 01:22:36 -04:00
										 |  |  |           sha256 urls_stable["checksum"] if urls_stable["checksum"].present? | 
					
						
							| 
									
										
										
										
											2023-06-19 06:07:53 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-02-06 21:04:08 -08:00
										 |  |  |           instance_exec(:stable, &add_deps) | 
					
						
							| 
									
										
										
										
											2023-06-19 06:07:53 +01:00
										 |  |  |           requirements[:stable]&.each do |req| | 
					
						
							|  |  |  |             depends_on req | 
					
						
							|  |  |  |           end | 
					
						
							| 
									
										
										
										
											2022-06-14 14:49:00 -04:00
										 |  |  |         end | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-18 13:14:52 +01:00
										 |  |  |       if (urls_head = json_formula["urls"]["head"].presence) | 
					
						
							| 
									
										
										
										
											2023-06-19 06:07:53 +01:00
										 |  |  |         head do | 
					
						
							| 
									
										
										
										
											2023-10-11 09:47:15 -04:00
										 |  |  |           url_spec = { | 
					
						
							|  |  |  |             branch: urls_head["branch"], | 
					
						
							|  |  |  |             using:  urls_head["using"]&.to_sym, | 
					
						
							|  |  |  |           }.compact | 
					
						
							| 
									
										
										
										
											2023-06-19 06:07:53 +01:00
										 |  |  |           url urls_head["url"], **url_spec | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-02-06 21:04:08 -08:00
										 |  |  |           instance_exec(:head, &add_deps) | 
					
						
							| 
									
										
										
										
											2023-06-19 06:07:53 +01:00
										 |  |  |           requirements[:head]&.each do |req| | 
					
						
							|  |  |  |             depends_on req | 
					
						
							|  |  |  |           end | 
					
						
							|  |  |  |         end | 
					
						
							| 
									
										
										
										
											2023-02-06 13:04:16 +00:00
										 |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-02-06 21:04:08 -08:00
										 |  |  |       bottles_stable = json_formula["bottle"]["stable"].presence | 
					
						
							| 
									
										
										
										
											2024-02-10 23:00:38 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |       if bottles_stable | 
					
						
							| 
									
										
										
										
											2022-06-14 14:49:00 -04:00
										 |  |  |         bottle do | 
					
						
							| 
									
										
										
										
											2023-02-20 10:03:23 +00:00
										 |  |  |           if Homebrew::EnvConfig.bottle_domain == HOMEBREW_BOTTLE_DEFAULT_DOMAIN | 
					
						
							|  |  |  |             root_url HOMEBREW_BOTTLE_DEFAULT_DOMAIN | 
					
						
							| 
									
										
										
										
											2023-02-07 12:12:00 +00:00
										 |  |  |           else | 
					
						
							| 
									
										
										
										
											2023-02-20 10:03:23 +00:00
										 |  |  |             root_url Homebrew::EnvConfig.bottle_domain | 
					
						
							| 
									
										
										
										
											2023-02-07 12:12:00 +00:00
										 |  |  |           end | 
					
						
							| 
									
										
										
										
											2022-06-14 14:49:00 -04:00
										 |  |  |           rebuild bottles_stable["rebuild"] | 
					
						
							|  |  |  |           bottles_stable["files"].each do |tag, bottle_spec| | 
					
						
							| 
									
										
										
										
											2022-06-16 13:26:51 -04:00
										 |  |  |             cellar = Formulary.convert_to_string_or_symbol bottle_spec["cellar"] | 
					
						
							| 
									
										
										
										
											2024-03-07 16:20:20 +00:00
										 |  |  |             sha256 cellar:, tag.to_sym => bottle_spec["sha256"] | 
					
						
							| 
									
										
										
										
											2022-06-14 14:49:00 -04:00
										 |  |  |           end | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-12-07 18:05:36 +00:00
										 |  |  |       if (pour_bottle_only_if = json_formula["pour_bottle_only_if"]) | 
					
						
							|  |  |  |         pour_bottle? only_if: pour_bottle_only_if.to_sym | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-18 13:14:52 +01:00
										 |  |  |       if (keg_only_reason = json_formula["keg_only_reason"].presence) | 
					
						
							| 
									
										
										
										
											2022-06-16 13:26:51 -04:00
										 |  |  |         reason = Formulary.convert_to_string_or_symbol keg_only_reason["reason"] | 
					
						
							| 
									
										
										
										
											2022-06-14 14:49:00 -04:00
										 |  |  |         keg_only reason, keg_only_reason["explanation"] | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-18 13:14:52 +01:00
										 |  |  |       if (deprecation_date = json_formula["deprecation_date"].presence) | 
					
						
							| 
									
										
										
										
											2023-12-04 00:30:49 -05:00
										 |  |  |         reason = DeprecateDisable.to_reason_string_or_symbol json_formula["deprecation_reason"], type: :formula | 
					
						
							| 
									
										
										
										
											2022-06-16 16:14:39 -04:00
										 |  |  |         deprecate! date: deprecation_date, because: reason | 
					
						
							| 
									
										
										
										
											2022-06-14 14:49:00 -04:00
										 |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-18 13:14:52 +01:00
										 |  |  |       if (disable_date = json_formula["disable_date"].presence) | 
					
						
							| 
									
										
										
										
											2023-12-04 00:30:49 -05:00
										 |  |  |         reason = DeprecateDisable.to_reason_string_or_symbol json_formula["disable_reason"], type: :formula | 
					
						
							| 
									
										
										
										
											2022-06-16 16:14:39 -04:00
										 |  |  |         disable! date: disable_date, because: reason | 
					
						
							| 
									
										
										
										
											2022-06-14 14:49:00 -04:00
										 |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-01 19:10:48 -08:00
										 |  |  |       json_formula["conflicts_with"]&.each_with_index do |conflict, index| | 
					
						
							| 
									
										
										
										
											2023-02-20 16:08:38 +00:00
										 |  |  |         conflicts_with conflict, because: json_formula.dig("conflicts_with_reasons", index) | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       json_formula["link_overwrite"]&.each do |overwrite_path| | 
					
						
							|  |  |  |         link_overwrite overwrite_path | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-06-14 14:49:00 -04:00
										 |  |  |       def install | 
					
						
							|  |  |  |         raise "Cannot build from source from abstract formula." | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-22 03:06:45 +01:00
										 |  |  |       @post_install_defined_boolean = json_formula["post_install_defined"] | 
					
						
							|  |  |  |       @post_install_defined_boolean = true if @post_install_defined_boolean.nil? # Backwards compatibility | 
					
						
							|  |  |  |       def post_install_defined? | 
					
						
							|  |  |  |         self.class.instance_variable_get(:@post_install_defined_boolean) | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-18 13:14:52 +01:00
										 |  |  |       if (service_hash = json_formula["service"].presence) | 
					
						
							| 
									
										
										
										
											2024-01-30 23:07:19 -08:00
										 |  |  |         service_hash = Homebrew::Service.from_hash(service_hash) | 
					
						
							| 
									
										
										
										
											2023-03-17 23:24:37 -07:00
										 |  |  |         service do | 
					
						
							| 
									
										
										
										
											2023-03-25 08:36:56 -07:00
										 |  |  |           T.bind(self, Homebrew::Service) | 
					
						
							| 
									
										
										
										
											2023-05-13 12:35:50 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-18 13:14:52 +01:00
										 |  |  |           if (run_params = service_hash.delete(:run).presence) | 
					
						
							| 
									
										
										
										
											2023-05-13 12:35:50 -07:00
										 |  |  |             case run_params | 
					
						
							|  |  |  |             when Hash | 
					
						
							|  |  |  |               run(**run_params) | 
					
						
							|  |  |  |             when Array, String | 
					
						
							|  |  |  |               run run_params | 
					
						
							|  |  |  |             end | 
					
						
							| 
									
										
										
										
											2023-03-17 23:24:37 -07:00
										 |  |  |           end | 
					
						
							| 
									
										
										
										
											2023-05-13 12:35:50 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-18 13:14:52 +01:00
										 |  |  |           if (name_params = service_hash.delete(:name).presence) | 
					
						
							| 
									
										
										
										
											2023-05-13 12:35:50 -07:00
										 |  |  |             name(**name_params) | 
					
						
							|  |  |  |           end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-17 23:24:37 -07:00
										 |  |  |           service_hash.each do |key, arg| | 
					
						
							|  |  |  |             public_send(key, arg) | 
					
						
							|  |  |  |           end | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-06-14 14:49:00 -04:00
										 |  |  |       @caveats_string = json_formula["caveats"] | 
					
						
							|  |  |  |       def caveats | 
					
						
							| 
									
										
										
										
											2024-11-02 15:03:10 -07:00
										 |  |  |         caveats_string = self.class.instance_variable_get(:@caveats_string) | 
					
						
							|  |  |  |         return unless caveats_string | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         caveats_string.gsub(HOMEBREW_PREFIX_PLACEHOLDER, HOMEBREW_PREFIX) | 
					
						
							|  |  |  |                       .gsub(HOMEBREW_CELLAR_PLACEHOLDER, HOMEBREW_CELLAR) | 
					
						
							|  |  |  |                       .gsub(HOMEBREW_HOME_PLACEHOLDER, Dir.home) | 
					
						
							| 
									
										
										
										
											2022-06-14 14:49:00 -04:00
										 |  |  |       end | 
					
						
							| 
									
										
										
										
											2023-02-06 13:06:11 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-02-06 21:04:08 -08:00
										 |  |  |       @tap_git_head_string = json_formula["tap_git_head"] | 
					
						
							| 
									
										
										
										
											2024-02-10 23:00:38 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-06 13:06:11 +00:00
										 |  |  |       def tap_git_head | 
					
						
							|  |  |  |         self.class.instance_variable_get(:@tap_git_head_string) | 
					
						
							|  |  |  |       end | 
					
						
							| 
									
										
										
										
											2023-02-14 02:03:58 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-02-06 21:04:08 -08:00
										 |  |  |       @oldnames_array = json_formula["oldnames"] || [json_formula["oldname"]].compact | 
					
						
							|  |  |  |       def oldnames | 
					
						
							|  |  |  |         self.class.instance_variable_get(:@oldnames_array) | 
					
						
							|  |  |  |       end | 
					
						
							| 
									
										
										
										
											2023-02-14 02:03:58 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-02-06 21:04:08 -08:00
										 |  |  |       @aliases_array = json_formula.fetch("aliases", []) | 
					
						
							|  |  |  |       def aliases | 
					
						
							|  |  |  |         self.class.instance_variable_get(:@aliases_array) | 
					
						
							| 
									
										
										
										
											2023-02-14 02:03:58 +00:00
										 |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-09 23:33:20 -08:00
										 |  |  |       @versioned_formulae_array = json_formula.fetch("versioned_formulae", []) | 
					
						
							| 
									
										
										
										
											2023-02-14 02:03:58 +00:00
										 |  |  |       def versioned_formulae_names | 
					
						
							|  |  |  |         self.class.instance_variable_get(:@versioned_formulae_array) | 
					
						
							|  |  |  |       end | 
					
						
							| 
									
										
										
										
											2023-04-18 00:22:13 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |       @ruby_source_path_string = json_formula["ruby_source_path"] | 
					
						
							|  |  |  |       def ruby_source_path | 
					
						
							|  |  |  |         self.class.instance_variable_get(:@ruby_source_path_string) | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-02-28 21:06:10 -08:00
										 |  |  |       @ruby_source_checksum_string = json_formula.dig("ruby_source_checksum", "sha256") | 
					
						
							|  |  |  |       @ruby_source_checksum_string ||= json_formula["ruby_source_sha256"] | 
					
						
							| 
									
										
										
										
											2023-04-18 00:22:13 +01:00
										 |  |  |       def ruby_source_checksum | 
					
						
							| 
									
										
										
										
											2024-02-28 21:06:10 -08:00
										 |  |  |         checksum = self.class.instance_variable_get(:@ruby_source_checksum_string) | 
					
						
							|  |  |  |         Checksum.new(checksum) if checksum | 
					
						
							| 
									
										
										
										
											2023-04-18 00:22:13 +01:00
										 |  |  |       end | 
					
						
							| 
									
										
										
										
											2022-06-14 14:49:00 -04:00
										 |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-15 13:58:33 +02:00
										 |  |  |     mod.const_set(class_name, klass) | 
					
						
							| 
									
										
										
										
											2022-06-14 14:49:00 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-09 11:12:49 +00:00
										 |  |  |     platform_cache[:api] ||= {} | 
					
						
							|  |  |  |     platform_cache[:api][name] = klass | 
					
						
							| 
									
										
										
										
											2015-09-02 16:12:26 +08:00
										 |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-12-06 11:06:27 -08:00
										 |  |  |   sig { | 
					
						
							|  |  |  |     params(name: String, spec: T.nilable(Symbol), force_bottle: T::Boolean, flags: T::Array[String]).returns(Formula) | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2023-04-14 15:33:40 +02:00
										 |  |  |   def self.resolve( | 
					
						
							|  |  |  |     name, | 
					
						
							| 
									
										
										
										
											2024-12-06 11:06:27 -08:00
										 |  |  |     spec: nil, | 
					
						
							|  |  |  |     force_bottle: false, | 
					
						
							|  |  |  |     flags: [] | 
					
						
							| 
									
										
										
										
											2023-04-14 15:33:40 +02:00
										 |  |  |   ) | 
					
						
							| 
									
										
										
										
											2018-09-11 17:44:18 +02:00
										 |  |  |     if name.include?("/") || File.exist?(name) | 
					
						
							| 
									
										
										
										
											2024-12-06 11:06:27 -08:00
										 |  |  |       f = factory(name, *spec, force_bottle:, flags:) | 
					
						
							| 
									
										
										
										
											2018-09-11 17:44:18 +02:00
										 |  |  |       if f.any_version_installed? | 
					
						
							|  |  |  |         tab = Tab.for_formula(f) | 
					
						
							|  |  |  |         resolved_spec = spec || tab.spec | 
					
						
							|  |  |  |         f.active_spec = resolved_spec if f.send(resolved_spec) | 
					
						
							|  |  |  |         f.build = tab | 
					
						
							|  |  |  |         if f.head? && tab.tabfile | 
					
						
							|  |  |  |           k = Keg.new(tab.tabfile.parent) | 
					
						
							|  |  |  |           f.version.update_commit(k.version.version.commit) if k.version.head? | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |       rack = to_rack(name) | 
					
						
							| 
									
										
										
										
											2024-12-06 11:06:27 -08:00
										 |  |  |       alias_path = factory(name, force_bottle:, flags:).alias_path | 
					
						
							|  |  |  |       f = from_rack(rack, *spec, alias_path:, force_bottle:, flags:) | 
					
						
							| 
									
										
										
										
											2018-09-11 17:44:18 +02:00
										 |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # If this formula was installed with an alias that has since changed, | 
					
						
							|  |  |  |     # then it was specified explicitly in ARGV. (Using the alias would | 
					
						
							|  |  |  |     # instead have found the new formula.) | 
					
						
							|  |  |  |     # | 
					
						
							|  |  |  |     # Because of this, the user is referring to this specific formula, | 
					
						
							| 
									
										
										
										
											2019-08-19 14:27:29 +10:00
										 |  |  |     # not any formula targeted by the same alias, so in this context | 
					
						
							| 
									
										
										
										
											2018-09-11 17:44:18 +02:00
										 |  |  |     # the formula shouldn't be considered outdated if the alias used to | 
					
						
							|  |  |  |     # install it has changed. | 
					
						
							|  |  |  |     f.follow_installed_alias = false | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     f | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-09 15:29:40 +01:00
										 |  |  |   def self.ensure_utf8_encoding(io) | 
					
						
							|  |  |  |     io.set_encoding(Encoding::UTF_8) | 
					
						
							| 
									
										
										
										
											2015-06-06 18:10:47 -04:00
										 |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-03 13:09:07 +01:00
										 |  |  |   def self.class_s(name) | 
					
						
							| 
									
										
										
										
											2014-04-03 22:40:40 -05:00
										 |  |  |     class_name = name.capitalize | 
					
						
							| 
									
										
										
										
											2023-03-25 08:36:56 -07:00
										 |  |  |     class_name.gsub!(/[-_.\s]([a-zA-Z0-9])/) { T.must(Regexp.last_match(1)).upcase } | 
					
						
							| 
									
										
										
										
											2015-08-06 15:45:52 +08:00
										 |  |  |     class_name.tr!("+", "x") | 
					
						
							| 
									
										
										
										
											2016-08-29 16:00:40 +01:00
										 |  |  |     class_name.sub!(/(.)@(\d)/, "\\1AT\\2") | 
					
						
							| 
									
										
										
										
											2014-04-03 22:40:40 -05:00
										 |  |  |     class_name | 
					
						
							| 
									
										
										
										
											2014-02-21 00:43:58 -05:00
										 |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-06-16 13:26:51 -04:00
										 |  |  |   def self.convert_to_string_or_symbol(string) | 
					
						
							|  |  |  |     return string[1..].to_sym if string.start_with?(":") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     string | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-05 17:17:03 -05:00
										 |  |  |   # A {FormulaLoader} returns instances of formulae. | 
					
						
							| 
									
										
										
										
											2013-06-18 10:11:06 -07:00
										 |  |  |   # Subclasses implement loaders for particular sources of formulae. | 
					
						
							|  |  |  |   class FormulaLoader | 
					
						
							| 
									
										
										
										
											2020-08-02 14:32:31 +02:00
										 |  |  |     include Context | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-30 11:10:23 +02:00
										 |  |  |     # The formula's name. | 
					
						
							| 
									
										
										
										
											2024-02-16 21:27:02 +01:00
										 |  |  |     sig { returns(String) } | 
					
						
							| 
									
										
										
										
											2013-06-18 10:11:06 -07:00
										 |  |  |     attr_reader :name | 
					
						
							| 
									
										
										
										
											2024-02-16 21:27:02 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-30 11:10:23 +02:00
										 |  |  |     # The formula file's path. | 
					
						
							| 
									
										
										
										
											2024-02-16 21:27:02 +01:00
										 |  |  |     sig { returns(Pathname) } | 
					
						
							| 
									
										
										
										
											2013-06-18 10:11:06 -07:00
										 |  |  |     attr_reader :path | 
					
						
							| 
									
										
										
										
											2024-02-16 21:27:02 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-30 11:10:23 +02:00
										 |  |  |     # The name used to install the formula. | 
					
						
							| 
									
										
										
										
											2024-02-16 21:27:02 +01:00
										 |  |  |     sig { returns(T.nilable(Pathname)) } | 
					
						
							| 
									
										
										
										
											2016-09-05 01:11:36 +01:00
										 |  |  |     attr_reader :alias_path | 
					
						
							| 
									
										
										
										
											2024-02-16 21:27:02 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-30 11:10:23 +02:00
										 |  |  |     # The formula's tap (`nil` if it should be implicitly determined). | 
					
						
							| 
									
										
										
										
											2024-02-16 21:27:02 +01:00
										 |  |  |     sig { returns(T.nilable(Tap)) } | 
					
						
							| 
									
										
										
										
											2023-04-18 00:22:13 +01:00
										 |  |  |     attr_reader :tap | 
					
						
							| 
									
										
										
										
											2014-04-03 22:40:40 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-12-06 11:06:27 -08:00
										 |  |  |     sig { params(name: String, path: Pathname, alias_path: T.nilable(Pathname), tap: T.nilable(Tap)).void } | 
					
						
							|  |  |  |     def initialize(name, path, alias_path: nil, tap: nil) | 
					
						
							| 
									
										
										
										
											2014-04-03 22:40:40 -05:00
										 |  |  |       @name = name | 
					
						
							| 
									
										
										
										
											2023-04-18 00:22:13 +01:00
										 |  |  |       @path = path | 
					
						
							| 
									
										
										
										
											2024-02-16 21:27:02 +01:00
										 |  |  |       @alias_path = alias_path | 
					
						
							| 
									
										
										
										
											2023-04-18 00:22:13 +01:00
										 |  |  |       @tap = tap | 
					
						
							| 
									
										
										
										
											2014-04-03 22:40:40 -05:00
										 |  |  |     end | 
					
						
							| 
									
										
										
										
											2013-06-18 10:11:06 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     # Gets the formula instance. | 
					
						
							| 
									
										
										
										
											2016-09-15 16:01:18 +01:00
										 |  |  |     # `alias_path` can be overridden here in case an alias was used to refer to | 
					
						
							|  |  |  |     # a formula that was loaded in another way. | 
					
						
							| 
									
										
										
										
											2021-04-13 17:40:41 +01:00
										 |  |  |     def get_formula(spec, alias_path: nil, force_bottle: false, flags: [], ignore_errors: false) | 
					
						
							| 
									
										
										
										
											2020-07-30 03:24:37 +02:00
										 |  |  |       alias_path ||= self.alias_path | 
					
						
							| 
									
										
										
										
											2024-03-07 16:20:20 +00:00
										 |  |  |       klass(flags:, ignore_errors:) | 
					
						
							|  |  |  |         .new(name, path, spec, alias_path:, tap:, force_bottle:) | 
					
						
							| 
									
										
										
										
											2014-03-07 17:23:44 -06:00
										 |  |  |     end | 
					
						
							| 
									
										
										
										
											2013-06-18 10:11:06 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-04-13 17:40:41 +01:00
										 |  |  |     def klass(flags:, ignore_errors:) | 
					
						
							| 
									
										
										
										
											2024-03-07 16:20:20 +00:00
										 |  |  |       load_file(flags:, ignore_errors:) unless Formulary.formula_class_defined_from_path?(path) | 
					
						
							| 
									
										
										
										
											2022-06-14 14:49:00 -04:00
										 |  |  |       Formulary.formula_class_get_from_path(path) | 
					
						
							| 
									
										
										
										
											2013-06-18 10:11:06 -07:00
										 |  |  |     end | 
					
						
							| 
									
										
										
										
											2014-12-29 14:53:22 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |     private | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-04-13 17:40:41 +01:00
										 |  |  |     def load_file(flags:, ignore_errors:) | 
					
						
							| 
									
										
										
										
											2016-09-17 15:17:27 +01:00
										 |  |  |       raise FormulaUnavailableError, name unless path.file? | 
					
						
							| 
									
										
										
										
											2018-09-17 02:45:00 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-07 16:20:20 +00:00
										 |  |  |       Formulary.load_formula_from_path(name, path, flags:, ignore_errors:) | 
					
						
							| 
									
										
										
										
											2014-12-29 14:53:22 -05:00
										 |  |  |     end | 
					
						
							| 
									
										
										
										
											2013-06-18 10:11:06 -07:00
										 |  |  |   end | 
					
						
							| 
									
										
										
										
											2013-06-08 20:58:43 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-17 06:10:42 +02:00
										 |  |  |   # Loads a formula from a bottle. | 
					
						
							| 
									
										
										
										
											2024-02-16 21:27:02 +01:00
										 |  |  |   class FromBottleLoader < FormulaLoader | 
					
						
							|  |  |  |     sig { | 
					
						
							| 
									
										
										
										
											2024-12-06 11:06:27 -08:00
										 |  |  |       params(ref: T.any(String, Pathname, URI::Generic), from: T.nilable(Symbol), warn: T::Boolean) | 
					
						
							| 
									
										
										
										
											2024-02-16 21:27:02 +01:00
										 |  |  |         .returns(T.nilable(T.attached_class)) | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2024-12-06 11:06:27 -08:00
										 |  |  |     def self.try_new(ref, from: nil, warn: false) | 
					
						
							| 
									
										
										
										
											2024-07-24 05:39:06 +01:00
										 |  |  |       return if Homebrew::EnvConfig.forbid_packages_from_paths? | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-02-16 21:27:02 +01:00
										 |  |  |       ref = ref.to_s | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-07-13 11:57:44 -04:00
										 |  |  |       new(ref) if HOMEBREW_BOTTLES_EXTNAME_REGEX.match?(ref) && File.exist?(ref) | 
					
						
							| 
									
										
										
										
											2024-02-16 21:27:02 +01:00
										 |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-07-13 11:36:03 -04:00
										 |  |  |     def initialize(bottle_name, warn: false) | 
					
						
							| 
									
										
										
										
											2024-07-13 11:57:44 -04:00
										 |  |  |       @bottle_path = Pathname(bottle_name).realpath | 
					
						
							|  |  |  |       name, full_name = Utils::Bottles.resolve_formula_names(@bottle_path) | 
					
						
							| 
									
										
										
										
											2015-05-27 22:49:18 +08:00
										 |  |  |       super name, Formulary.path(full_name) | 
					
						
							| 
									
										
										
										
											2013-06-18 10:11:06 -07:00
										 |  |  |     end | 
					
						
							| 
									
										
										
										
											2013-06-08 20:58:43 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-04-13 17:40:41 +01:00
										 |  |  |     def get_formula(spec, force_bottle: false, flags: [], ignore_errors: false, **) | 
					
						
							| 
									
										
										
										
											2017-10-04 10:14:06 +01:00
										 |  |  |       formula = begin | 
					
						
							| 
									
										
										
										
											2024-07-13 11:57:44 -04:00
										 |  |  |         contents = Utils::Bottles.formula_contents(@bottle_path, name:) | 
					
						
							| 
									
										
										
										
											2024-03-07 16:20:20 +00:00
										 |  |  |         Formulary.from_contents(name, path, contents, spec, force_bottle:, | 
					
						
							|  |  |  |                                 flags:, ignore_errors:) | 
					
						
							| 
									
										
										
										
											2017-10-04 10:14:06 +01:00
										 |  |  |       rescue FormulaUnreadableError => e | 
					
						
							| 
									
										
										
										
											2017-10-15 02:28:32 +02:00
										 |  |  |         opoo <<~EOS | 
					
						
							| 
									
										
										
										
											2024-07-13 11:57:44 -04:00
										 |  |  |           Unreadable formula in #{@bottle_path}: | 
					
						
							| 
									
										
										
										
											2017-10-04 10:14:06 +01:00
										 |  |  |           #{e} | 
					
						
							|  |  |  |         EOS | 
					
						
							|  |  |  |         super | 
					
						
							| 
									
										
										
										
											2021-04-01 16:52:58 +01:00
										 |  |  |       rescue BottleFormulaUnavailableError => e | 
					
						
							|  |  |  |         opoo <<~EOS | 
					
						
							|  |  |  |           #{e} | 
					
						
							|  |  |  |           Falling back to non-bottle formula. | 
					
						
							|  |  |  |         EOS | 
					
						
							|  |  |  |         super | 
					
						
							| 
									
										
										
										
											2017-10-04 10:14:06 +01:00
										 |  |  |       end | 
					
						
							| 
									
										
										
										
											2024-07-13 11:57:44 -04:00
										 |  |  |       formula.local_bottle_path = @bottle_path | 
					
						
							| 
									
										
										
										
											2014-03-07 17:23:44 -06:00
										 |  |  |       formula | 
					
						
							| 
									
										
										
										
											2013-06-18 10:11:06 -07:00
										 |  |  |     end | 
					
						
							|  |  |  |   end | 
					
						
							| 
									
										
										
										
											2013-06-08 20:58:43 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-02-16 21:27:02 +01:00
										 |  |  |   # Loads formulae from disk using a path. | 
					
						
							|  |  |  |   class FromPathLoader < FormulaLoader | 
					
						
							|  |  |  |     sig { | 
					
						
							| 
									
										
										
										
											2024-12-06 11:06:27 -08:00
										 |  |  |       params(ref: T.any(String, Pathname, URI::Generic), from: T.nilable(Symbol), warn: T::Boolean) | 
					
						
							| 
									
										
										
										
											2024-02-16 21:27:02 +01:00
										 |  |  |         .returns(T.nilable(T.attached_class)) | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2024-12-06 11:06:27 -08:00
										 |  |  |     def self.try_new(ref, from: nil, warn: false) | 
					
						
							| 
									
										
										
										
											2024-02-16 21:27:02 +01:00
										 |  |  |       path = case ref | 
					
						
							|  |  |  |       when String | 
					
						
							|  |  |  |         Pathname(ref) | 
					
						
							|  |  |  |       when Pathname | 
					
						
							|  |  |  |         ref | 
					
						
							|  |  |  |       else | 
					
						
							|  |  |  |         return | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       return unless path.expand_path.exist? | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-27 10:17:04 +08:00
										 |  |  |       return if Homebrew::EnvConfig.forbid_packages_from_paths? && | 
					
						
							|  |  |  |                 !path.realpath.to_s.start_with?("#{HOMEBREW_CELLAR}/", "#{HOMEBREW_LIBRARY}/Taps/") | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-12-06 11:06:27 -08:00
										 |  |  |       if (tap = Tap.from_path(path)) | 
					
						
							| 
									
										
										
										
											2024-02-16 22:23:41 +01:00
										 |  |  |         # Only treat symlinks in taps as aliases. | 
					
						
							|  |  |  |         if path.symlink? | 
					
						
							|  |  |  |           alias_path = path | 
					
						
							|  |  |  |           path = alias_path.resolved_path | 
					
						
							|  |  |  |         end | 
					
						
							| 
									
										
										
										
											2024-02-16 21:27:02 +01:00
										 |  |  |       else | 
					
						
							| 
									
										
										
										
											2024-12-06 11:06:27 -08:00
										 |  |  |         # Don't treat cache symlinks as aliases. | 
					
						
							|  |  |  |         tap = Homebrew::API.tap_from_source_download(path) | 
					
						
							| 
									
										
										
										
											2024-02-16 22:23:41 +01:00
										 |  |  |       end | 
					
						
							| 
									
										
										
										
											2024-02-16 21:27:02 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |       return if path.extname != ".rb" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-12-06 11:06:27 -08:00
										 |  |  |       new(path, alias_path:, tap:) | 
					
						
							| 
									
										
										
										
											2024-02-16 22:23:41 +01:00
										 |  |  |     end | 
					
						
							| 
									
										
										
										
											2013-06-18 10:11:06 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-12-06 11:06:27 -08:00
										 |  |  |     sig { params(path: T.any(Pathname, String), alias_path: T.nilable(Pathname), tap: T.nilable(Tap)).void } | 
					
						
							|  |  |  |     def initialize(path, alias_path: nil, tap: nil) | 
					
						
							| 
									
										
										
										
											2024-02-16 21:27:02 +01:00
										 |  |  |       path = Pathname(path).expand_path | 
					
						
							| 
									
										
										
										
											2024-02-16 13:41:54 +00:00
										 |  |  |       name = path.basename(".rb").to_s | 
					
						
							| 
									
										
										
										
											2024-02-16 21:27:02 +01:00
										 |  |  |       alias_path = alias_path&.expand_path | 
					
						
							|  |  |  |       alias_dir = alias_path&.dirname | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-12-06 11:06:27 -08:00
										 |  |  |       alias_path = nil if alias_dir != tap&.alias_dir | 
					
						
							| 
									
										
										
										
											2024-02-16 21:27:02 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-12-06 11:25:51 -08:00
										 |  |  |       super(name, path, alias_path:, tap:) | 
					
						
							| 
									
										
										
										
											2024-02-08 12:14:26 +01:00
										 |  |  |     end | 
					
						
							| 
									
										
										
										
											2024-02-16 13:41:54 +00:00
										 |  |  |   end | 
					
						
							| 
									
										
										
										
											2024-02-08 12:14:26 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-02-16 21:27:02 +01:00
										 |  |  |   # Loads formula from a URI. | 
					
						
							|  |  |  |   class FromURILoader < FormulaLoader | 
					
						
							|  |  |  |     sig { | 
					
						
							| 
									
										
										
										
											2024-12-06 11:06:27 -08:00
										 |  |  |       params(ref: T.any(String, Pathname, URI::Generic), from: T.nilable(Symbol), warn: T::Boolean) | 
					
						
							| 
									
										
										
										
											2024-02-16 21:27:02 +01:00
										 |  |  |         .returns(T.nilable(T.attached_class)) | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2024-12-06 11:06:27 -08:00
										 |  |  |     def self.try_new(ref, from: nil, warn: false) | 
					
						
							| 
									
										
										
										
											2024-07-24 05:39:06 +01:00
										 |  |  |       return if Homebrew::EnvConfig.forbid_packages_from_paths? | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-07-15 14:02:44 -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 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       uri = ref.to_s | 
					
						
							|  |  |  |       return unless uri.match?(@uri_regex) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       uri = URI(uri) | 
					
						
							|  |  |  |       return unless uri.path | 
					
						
							|  |  |  |       return unless uri.scheme.present? | 
					
						
							| 
									
										
										
										
											2024-02-16 21:27:02 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-07-15 14:02:44 -04:00
										 |  |  |       new(uri, from:) | 
					
						
							| 
									
										
										
										
											2024-02-16 21:27:02 +01:00
										 |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-18 10:11:06 -07:00
										 |  |  |     attr_reader :url | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-06 13:06:11 +00:00
										 |  |  |     sig { params(url: T.any(URI::Generic, String), from: T.nilable(Symbol)).void } | 
					
						
							|  |  |  |     def initialize(url, from: nil) | 
					
						
							| 
									
										
										
										
											2013-06-18 10:11:06 -07:00
										 |  |  |       @url = url | 
					
						
							| 
									
										
										
										
											2023-02-06 13:06:11 +00:00
										 |  |  |       @from = from | 
					
						
							| 
									
										
										
										
											2023-03-25 17:39:39 -07:00
										 |  |  |       uri_path = URI(url).path | 
					
						
							|  |  |  |       raise ArgumentError, "URL has no path component" unless uri_path | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-25 08:36:56 -07:00
										 |  |  |       formula = File.basename(uri_path, ".rb") | 
					
						
							|  |  |  |       super formula, HOMEBREW_CACHE_FORMULA/File.basename(uri_path) | 
					
						
							| 
									
										
										
										
											2013-06-18 10:11:06 -07:00
										 |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-04-13 17:40:41 +01:00
										 |  |  |     def load_file(flags:, ignore_errors:) | 
					
						
							| 
									
										
										
										
											2024-07-13 12:16:36 -04:00
										 |  |  |       url_scheme = URI(url).scheme | 
					
						
							|  |  |  |       if ALLOWED_URL_SCHEMES.exclude?(url_scheme) | 
					
						
							| 
									
										
										
										
											2023-04-18 00:22:13 +01:00
										 |  |  |         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." | 
					
						
							| 
									
										
										
										
											2019-05-07 10:50:19 +01:00
										 |  |  |       end | 
					
						
							| 
									
										
										
										
											2014-12-29 14:53:22 -05:00
										 |  |  |       HOMEBREW_CACHE_FORMULA.mkpath | 
					
						
							|  |  |  |       FileUtils.rm_f(path) | 
					
						
							| 
									
										
											  
											
												Curl: use `typed: strict`
This upgrades `utils/curl.rb` to `typed: strict`, which requires
a number of changes to pass `brew typecheck`. The most
straightforward are adding type signatures to methods, adding type
annotations (e.g., `T.let`) to variables that need them, and ensuring
that methods always use the expected return type.
I had to refactor areas where we call a `Utils::Curl` method and use
array destructuring on a `SystemCommand::Result` return value
(e.g., `output, errors, status = curl_output(...)`), as Sorbet
doesn't understand implicit array conversion. As suggested by Markus,
I've switched these areas to use `#stdout`, `#stderr`, and `#status`.
This requires the use of an intermediate variable (`result`) in some
cases but this was a fairly straightforward substitution.
I also had to refactor how `Cask::URL::BlockDSL::PageWithURL` works.
It currently uses `page.extend PageWithURL` to add a `url` attribute
but this reworks it to subclass `SimpleDelegator` and use an
`initialize` method instead. This achieves the same goal but in a way
that Sorbet can understand.
											
										 
											2025-01-10 21:37:20 -05:00
										 |  |  |       Utils::Curl.curl_download url.to_s, to: path | 
					
						
							| 
									
										
										
										
											2014-03-07 17:23:44 -06:00
										 |  |  |       super | 
					
						
							| 
									
										
										
										
											2016-12-10 13:04:14 +00:00
										 |  |  |     rescue MethodDeprecatedError => e | 
					
						
							| 
									
										
										
										
											2023-05-18 13:14:52 +01:00
										 |  |  |       if (match_data = url.match(%r{github.com/(?<user>[\w-]+)/(?<repo>[\w-]+)/}).presence) | 
					
						
							| 
									
										
										
										
											2023-03-25 08:36:56 -07:00
										 |  |  |         e.issues_url = "https://github.com/#{match_data[:user]}/#{match_data[:repo]}/issues/new" | 
					
						
							| 
									
										
										
										
											2016-12-10 13:04:14 +00:00
										 |  |  |       end | 
					
						
							|  |  |  |       raise | 
					
						
							| 
									
										
										
										
											2013-06-08 20:58:43 -07:00
										 |  |  |     end | 
					
						
							| 
									
										
										
										
											2013-06-18 10:11:06 -07:00
										 |  |  |   end | 
					
						
							| 
									
										
										
										
											2013-06-08 20:58:43 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-18 10:11:06 -07:00
										 |  |  |   # Loads tapped formulae. | 
					
						
							| 
									
										
										
										
											2024-02-16 21:27:02 +01:00
										 |  |  |   class FromTapLoader < FormulaLoader | 
					
						
							|  |  |  |     sig { returns(Tap) } | 
					
						
							|  |  |  |     attr_reader :tap | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     sig { returns(Pathname) } | 
					
						
							|  |  |  |     attr_reader :path | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     sig { | 
					
						
							| 
									
										
										
										
											2024-12-06 11:06:27 -08:00
										 |  |  |       params(ref: T.any(String, Pathname, URI::Generic), from: T.nilable(Symbol), warn: T::Boolean) | 
					
						
							| 
									
										
										
										
											2024-06-30 10:18:03 -07:00
										 |  |  |         .returns(T.nilable(FormulaLoader)) | 
					
						
							| 
									
										
										
										
											2024-02-16 21:27:02 +01:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2024-12-06 11:06:27 -08:00
										 |  |  |     def self.try_new(ref, from: nil, warn: false) | 
					
						
							| 
									
										
										
										
											2024-02-16 21:27:02 +01:00
										 |  |  |       ref = ref.to_s | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-07 16:20:20 +00:00
										 |  |  |       return unless (name_tap_type = Formulary.tap_formula_name_type(ref, warn:)) | 
					
						
							| 
									
										
										
										
											2024-02-16 21:27:02 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-01 03:13:56 +01:00
										 |  |  |       name, tap, type = name_tap_type | 
					
						
							| 
									
										
										
										
											2024-02-16 21:27:02 +01:00
										 |  |  |       path = Formulary.find_formula_in_tap(name, tap) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-12-06 11:06:27 -08:00
										 |  |  |       if type == :alias | 
					
						
							| 
									
										
										
										
											2024-03-01 03:13:56 +01:00
										 |  |  |         # TODO: Simplify this by making `tap_formula_name_type` return the alias name. | 
					
						
							| 
									
										
										
										
											2024-12-06 11:06:27 -08:00
										 |  |  |         alias_name = T.must(ref[HOMEBREW_TAP_FORMULA_REGEX, :name]).downcase | 
					
						
							| 
									
										
										
										
											2024-02-16 21:27:02 +01:00
										 |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-06-30 10:18:03 -07:00
										 |  |  |       if type == :migration && tap.core_tap? && (loader = FromAPILoader.try_new(name)) | 
					
						
							|  |  |  |         loader | 
					
						
							|  |  |  |       else | 
					
						
							| 
									
										
										
										
											2024-12-06 11:06:27 -08:00
										 |  |  |         new(name, path, tap:, alias_name:) | 
					
						
							| 
									
										
										
										
											2024-06-30 10:18:03 -07:00
										 |  |  |       end | 
					
						
							| 
									
										
										
										
											2024-02-16 21:27:02 +01:00
										 |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-12-06 11:06:27 -08:00
										 |  |  |     sig { params(name: String, path: Pathname, tap: Tap, alias_name: T.nilable(String)).void } | 
					
						
							|  |  |  |     def initialize(name, path, tap:, alias_name: nil) | 
					
						
							|  |  |  |       alias_path = tap.alias_dir/alias_name if alias_name | 
					
						
							| 
									
										
										
										
											2024-02-16 21:27:02 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-12-06 11:06:27 -08:00
										 |  |  |       super(name, path, alias_path:, tap:) | 
					
						
							|  |  |  |       @tap = tap | 
					
						
							| 
									
										
										
										
											2024-02-16 21:27:02 +01:00
										 |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-04-13 17:40:41 +01:00
										 |  |  |     def get_formula(spec, alias_path: nil, force_bottle: false, flags: [], ignore_errors: false) | 
					
						
							| 
									
										
										
										
											2014-03-07 17:23:44 -06:00
										 |  |  |       super | 
					
						
							| 
									
										
										
										
											2017-04-18 08:43:39 +01:00
										 |  |  |     rescue FormulaUnreadableError => e | 
					
						
							|  |  |  |       raise TapFormulaUnreadableError.new(tap, name, e.formula_error), "", e.backtrace | 
					
						
							|  |  |  |     rescue FormulaClassUnavailableError => e | 
					
						
							|  |  |  |       raise TapFormulaClassUnavailableError.new(tap, name, e.path, e.class_name, e.class_list), "", e.backtrace | 
					
						
							| 
									
										
										
										
											2014-12-29 15:23:01 -05:00
										 |  |  |     rescue FormulaUnavailableError => e | 
					
						
							| 
									
										
										
										
											2015-07-14 21:33:29 +08:00
										 |  |  |       raise TapFormulaUnavailableError.new(tap, name), "", e.backtrace | 
					
						
							| 
									
										
										
										
											2013-06-18 10:11:06 -07:00
										 |  |  |     end | 
					
						
							| 
									
										
										
										
											2016-12-10 13:04:14 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-04-13 17:40:41 +01:00
										 |  |  |     def load_file(flags:, ignore_errors:) | 
					
						
							| 
									
										
										
										
											2016-12-10 13:04:14 +00:00
										 |  |  |       super | 
					
						
							|  |  |  |     rescue MethodDeprecatedError => e | 
					
						
							| 
									
										
										
										
											2016-12-14 05:07:54 +03:00
										 |  |  |       e.issues_url = tap.issues_url || tap.to_s | 
					
						
							| 
									
										
										
										
											2016-12-10 13:04:14 +00:00
										 |  |  |       raise | 
					
						
							|  |  |  |     end | 
					
						
							| 
									
										
										
										
											2024-02-16 21:27:02 +01:00
										 |  |  |   end | 
					
						
							| 
									
										
										
										
											2024-02-08 12:14:26 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-02-16 21:27:02 +01:00
										 |  |  |   # Loads a formula from a name, as long as it exists only in a single tap. | 
					
						
							|  |  |  |   class FromNameLoader < FromTapLoader | 
					
						
							|  |  |  |     sig { | 
					
						
							| 
									
										
										
										
											2024-12-06 11:06:27 -08:00
										 |  |  |       params(ref: T.any(String, Pathname, URI::Generic), from: T.nilable(Symbol), warn: T::Boolean) | 
					
						
							| 
									
										
										
										
											2024-06-30 10:18:03 -07:00
										 |  |  |         .returns(T.nilable(FormulaLoader)) | 
					
						
							| 
									
										
										
										
											2024-02-16 21:27:02 +01:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2024-12-06 11:06:27 -08:00
										 |  |  |     def self.try_new(ref, from: nil, warn: false) | 
					
						
							| 
									
										
										
										
											2024-02-16 21:27:02 +01:00
										 |  |  |       return unless ref.is_a?(String) | 
					
						
							| 
									
										
										
										
											2024-03-06 23:06:36 +01:00
										 |  |  |       return unless ref.match?(/\A#{HOMEBREW_TAP_FORMULA_NAME_REGEX}\Z/o) | 
					
						
							| 
									
										
										
										
											2024-02-16 21:27:02 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |       name = 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_tap = CoreTap.instance).installed? && | 
					
						
							| 
									
										
										
										
											2024-07-01 18:41:53 -07:00
										 |  |  |          (core_loader = super("#{core_tap}/#{name}", warn:))&.path&.exist? | 
					
						
							|  |  |  |         return core_loader | 
					
						
							| 
									
										
										
										
											2024-03-06 23:06:36 +01:00
										 |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       loaders = Tap.select { |tap| tap.installed? && !tap.core_tap? } | 
					
						
							| 
									
										
										
										
											2024-03-07 16:20:20 +00:00
										 |  |  |                    .filter_map { |tap| super("#{tap}/#{name}", 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-16 21:27:02 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |       case loaders.count | 
					
						
							|  |  |  |       when 1
 | 
					
						
							|  |  |  |         loaders.first | 
					
						
							|  |  |  |       when 2..Float::INFINITY | 
					
						
							|  |  |  |         raise TapFormulaAmbiguityError.new(name, loaders) | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   # Loads a formula from a formula file in a keg. | 
					
						
							|  |  |  |   class FromKegLoader < FormulaLoader | 
					
						
							|  |  |  |     sig { | 
					
						
							| 
									
										
										
										
											2024-12-06 11:06:27 -08:00
										 |  |  |       params(ref: T.any(String, Pathname, URI::Generic), from: T.nilable(Symbol), warn: T::Boolean) | 
					
						
							| 
									
										
										
										
											2024-02-16 21:27:02 +01:00
										 |  |  |         .returns(T.nilable(T.attached_class)) | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2024-12-06 11:06:27 -08:00
										 |  |  |     def self.try_new(ref, from: nil, warn: false) | 
					
						
							| 
									
										
										
										
											2024-02-16 21:27:02 +01:00
										 |  |  |       ref = ref.to_s | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       return unless (keg_formula = HOMEBREW_PREFIX/"opt/#{ref}/.brew/#{ref}.rb").file? | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       new(ref, keg_formula) | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   # Loads a formula from a cached formula file. | 
					
						
							|  |  |  |   class FromCacheLoader < FormulaLoader | 
					
						
							|  |  |  |     sig { | 
					
						
							| 
									
										
										
										
											2024-12-06 11:06:27 -08:00
										 |  |  |       params(ref: T.any(String, Pathname, URI::Generic), from: T.nilable(Symbol), warn: T::Boolean) | 
					
						
							| 
									
										
										
										
											2024-02-16 21:27:02 +01:00
										 |  |  |         .returns(T.nilable(T.attached_class)) | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2024-12-06 11:06:27 -08:00
										 |  |  |     def self.try_new(ref, from: nil, warn: false) | 
					
						
							| 
									
										
										
										
											2024-02-16 21:27:02 +01:00
										 |  |  |       ref = ref.to_s | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       return unless (cached_formula = HOMEBREW_CACHE_FORMULA/"#{ref}.rb").file? | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       new(ref, cached_formula) | 
					
						
							| 
									
										
										
										
											2023-02-24 10:57:41 +00:00
										 |  |  |     end | 
					
						
							| 
									
										
										
										
											2013-06-18 10:11:06 -07:00
										 |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-05 17:17:03 -05:00
										 |  |  |   # Pseudo-loader which will raise a {FormulaUnavailableError} when trying to load the corresponding formula. | 
					
						
							| 
									
										
										
										
											2015-01-01 01:21:59 -05:00
										 |  |  |   class NullLoader < FormulaLoader | 
					
						
							| 
									
										
										
										
											2024-02-16 21:27:02 +01:00
										 |  |  |     sig { | 
					
						
							| 
									
										
										
										
											2024-12-06 11:06:27 -08:00
										 |  |  |       params(ref: T.any(String, Pathname, URI::Generic), from: T.nilable(Symbol), warn: T::Boolean) | 
					
						
							| 
									
										
										
										
											2024-02-16 21:27:02 +01:00
										 |  |  |         .returns(T.nilable(T.attached_class)) | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2024-12-06 11:06:27 -08:00
										 |  |  |     def self.try_new(ref, from: nil, warn: false) | 
					
						
							| 
									
										
										
										
											2024-02-16 21:27:02 +01:00
										 |  |  |       return if ref.is_a?(URI::Generic) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       new(ref) | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     sig { params(ref: T.any(String, Pathname)).void } | 
					
						
							|  |  |  |     def initialize(ref) | 
					
						
							|  |  |  |       name = File.basename(ref, ".rb") | 
					
						
							| 
									
										
										
										
											2015-05-08 18:59:08 +08:00
										 |  |  |       super name, Formulary.core_path(name) | 
					
						
							| 
									
										
										
										
											2015-01-01 01:21:59 -05:00
										 |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-19 16:28:28 +01:00
										 |  |  |     def get_formula(*) | 
					
						
							| 
									
										
										
										
											2016-09-17 15:17:27 +01:00
										 |  |  |       raise FormulaUnavailableError, name | 
					
						
							| 
									
										
										
										
											2015-01-01 01:21:59 -05:00
										 |  |  |     end | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-18 21:42:43 -04:00
										 |  |  |   # Load formulae directly from their contents. | 
					
						
							| 
									
										
										
										
											2015-09-02 16:25:46 +08:00
										 |  |  |   class FormulaContentsLoader < FormulaLoader | 
					
						
							| 
									
										
										
										
											2020-11-05 17:17:03 -05:00
										 |  |  |     # The formula's contents. | 
					
						
							| 
									
										
										
										
											2015-09-02 16:25:46 +08:00
										 |  |  |     attr_reader :contents | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def initialize(name, path, contents) | 
					
						
							|  |  |  |       @contents = contents | 
					
						
							|  |  |  |       super name, path | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-04-13 17:40:41 +01:00
										 |  |  |     def klass(flags:, ignore_errors:) | 
					
						
							| 
									
										
										
										
											2020-07-26 07:24:14 +02:00
										 |  |  |       namespace = "FormulaNamespace#{Digest::MD5.hexdigest(contents.to_s)}" | 
					
						
							| 
									
										
										
										
											2024-03-07 16:20:20 +00:00
										 |  |  |       Formulary.load_formula(name, path, contents, namespace, flags:, ignore_errors:) | 
					
						
							| 
									
										
										
										
											2015-09-02 16:25:46 +08:00
										 |  |  |     end | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-02-16 21:27:02 +01:00
										 |  |  |   # Load a formula from the API. | 
					
						
							|  |  |  |   class FromAPILoader < FormulaLoader | 
					
						
							|  |  |  |     sig { | 
					
						
							| 
									
										
										
										
											2024-12-06 11:06:27 -08:00
										 |  |  |       params(ref: T.any(String, Pathname, URI::Generic), from: T.nilable(Symbol), warn: T::Boolean) | 
					
						
							| 
									
										
										
										
											2024-02-16 21:27:02 +01:00
										 |  |  |         .returns(T.nilable(T.attached_class)) | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2024-12-06 11:06:27 -08:00
										 |  |  |     def self.try_new(ref, from: nil, warn: false) | 
					
						
							| 
									
										
										
										
											2024-02-16 21:27:02 +01:00
										 |  |  |       return if Homebrew::EnvConfig.no_install_from_api? | 
					
						
							|  |  |  |       return unless ref.is_a?(String) | 
					
						
							|  |  |  |       return unless (name = ref[HOMEBREW_DEFAULT_TAP_FORMULA_REGEX, :name]) | 
					
						
							|  |  |  |       if !Homebrew::API::Formula.all_formulae.key?(name) && | 
					
						
							|  |  |  |          !Homebrew::API::Formula.all_aliases.key?(name) && | 
					
						
							|  |  |  |          !Homebrew::API::Formula.all_renames.key?(name) | 
					
						
							|  |  |  |         return | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       alias_name = name | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       ref = "#{CoreTap.instance}/#{name}" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-07 16:20:20 +00:00
										 |  |  |       return unless (name_tap_type = Formulary.tap_formula_name_type(ref, warn:)) | 
					
						
							| 
									
										
										
										
											2024-03-01 03:13:56 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |       name, tap, type = name_tap_type | 
					
						
							| 
									
										
										
										
											2024-02-16 21:27:02 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-12-06 11:25:51 -08:00
										 |  |  |       alias_name = (type == :alias) ? alias_name.downcase : nil | 
					
						
							| 
									
										
										
										
											2024-02-16 21:27:02 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-12-06 11:06:27 -08:00
										 |  |  |       new(name, tap:, alias_name:) | 
					
						
							| 
									
										
										
										
											2024-02-16 21:27:02 +01:00
										 |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-12-06 11:06:27 -08:00
										 |  |  |     sig { params(name: String, tap: T.nilable(Tap), alias_name: T.nilable(String)).void } | 
					
						
							|  |  |  |     def initialize(name, tap: nil, alias_name: nil) | 
					
						
							|  |  |  |       alias_path = CoreTap.instance.alias_dir/alias_name if alias_name | 
					
						
							| 
									
										
										
										
											2024-02-16 21:27:02 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-12-06 11:06:27 -08:00
										 |  |  |       super(name, Formulary.core_path(name), alias_path:, tap:) | 
					
						
							| 
									
										
										
										
											2021-12-07 00:13:56 +00:00
										 |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def klass(flags:, ignore_errors:) | 
					
						
							| 
									
										
										
										
											2024-03-07 16:20:20 +00:00
										 |  |  |       load_from_api(flags:) unless Formulary.formula_class_defined_from_api?(name) | 
					
						
							| 
									
										
										
										
											2022-06-14 14:49:00 -04:00
										 |  |  |       Formulary.formula_class_get_from_api(name) | 
					
						
							|  |  |  |     end | 
					
						
							| 
									
										
										
										
											2021-12-07 00:13:56 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-06-14 14:49:00 -04:00
										 |  |  |     private | 
					
						
							| 
									
										
										
										
											2021-12-07 00:13:56 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-06-15 16:57:15 -04:00
										 |  |  |     def load_from_api(flags:) | 
					
						
							| 
									
										
										
										
											2024-03-07 16:20:20 +00:00
										 |  |  |       Formulary.load_formula_from_api(name, flags:) | 
					
						
							| 
									
										
										
										
											2021-12-07 00:13:56 +00:00
										 |  |  |     end | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-05 17:17:03 -05:00
										 |  |  |   # Return a {Formula} instance for the given reference. | 
					
						
							| 
									
										
										
										
											2018-10-18 21:42:43 -04:00
										 |  |  |   # `ref` is a string containing: | 
					
						
							|  |  |  |   # | 
					
						
							| 
									
										
										
										
											2013-06-23 12:47:10 -07:00
										 |  |  |   # * a formula name | 
					
						
							|  |  |  |   # * a formula pathname | 
					
						
							|  |  |  |   # * a formula URL | 
					
						
							|  |  |  |   # * a local bottle reference | 
					
						
							| 
									
										
										
										
											2024-04-22 21:05:48 +02:00
										 |  |  |   # | 
					
						
							|  |  |  |   # @api internal | 
					
						
							| 
									
										
										
										
											2023-04-14 15:33:40 +02:00
										 |  |  |   sig { | 
					
						
							|  |  |  |     params( | 
					
						
							| 
									
										
										
										
											2023-07-24 06:55:41 -07:00
										 |  |  |       ref:           T.any(Pathname, String), | 
					
						
							| 
									
										
										
										
											2023-04-14 15:33:40 +02:00
										 |  |  |       spec:          Symbol, | 
					
						
							| 
									
										
										
										
											2023-07-24 14:01:53 -07:00
										 |  |  |       alias_path:    T.any(NilClass, Pathname, String), | 
					
						
							| 
									
										
										
										
											2024-12-06 11:06:27 -08:00
										 |  |  |       from:          T.nilable(Symbol), | 
					
						
							| 
									
										
										
										
											2023-04-14 15:33:40 +02:00
										 |  |  |       warn:          T::Boolean, | 
					
						
							|  |  |  |       force_bottle:  T::Boolean, | 
					
						
							|  |  |  |       flags:         T::Array[String], | 
					
						
							|  |  |  |       ignore_errors: T::Boolean, | 
					
						
							|  |  |  |     ).returns(Formula) | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2021-04-13 17:40:41 +01:00
										 |  |  |   def self.factory( | 
					
						
							| 
									
										
										
										
											2023-04-14 15:33:40 +02:00
										 |  |  |     ref, | 
					
						
							|  |  |  |     spec = :stable, | 
					
						
							| 
									
										
										
										
											2023-07-24 06:55:41 -07:00
										 |  |  |     alias_path: nil, | 
					
						
							| 
									
										
										
										
											2024-12-06 11:06:27 -08:00
										 |  |  |     from: nil, | 
					
						
							|  |  |  |     warn: false, | 
					
						
							|  |  |  |     force_bottle: false, | 
					
						
							|  |  |  |     flags: [], | 
					
						
							|  |  |  |     ignore_errors: false | 
					
						
							| 
									
										
										
										
											2021-04-13 17:40:41 +01:00
										 |  |  |   ) | 
					
						
							| 
									
										
										
										
											2019-11-06 10:03:44 +00:00
										 |  |  |     cache_key = "#{ref}-#{spec}-#{alias_path}-#{from}" | 
					
						
							| 
									
										
										
										
											2024-01-09 11:12:49 +00:00
										 |  |  |     if factory_cached? && platform_cache[:formulary_factory]&.key?(cache_key) | 
					
						
							|  |  |  |       return platform_cache[:formulary_factory][cache_key] | 
					
						
							|  |  |  |     end | 
					
						
							| 
									
										
										
										
											2023-04-14 15:33:40 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-12-06 11:06:27 -08:00
										 |  |  |     formula = loader_for(ref, from:, warn:) | 
					
						
							|  |  |  |               .get_formula(spec, alias_path:, force_bottle:, flags:, ignore_errors:) | 
					
						
							| 
									
										
										
										
											2019-11-06 10:03:44 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if factory_cached? | 
					
						
							| 
									
										
										
										
											2024-01-09 11:12:49 +00:00
										 |  |  |       platform_cache[:formulary_factory] ||= {} | 
					
						
							|  |  |  |       platform_cache[:formulary_factory][cache_key] ||= formula | 
					
						
							| 
									
										
										
										
											2019-11-06 10:03:44 +00:00
										 |  |  |     end | 
					
						
							| 
									
										
										
										
											2023-04-14 15:33:40 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-06 10:03:44 +00:00
										 |  |  |     formula | 
					
						
							| 
									
										
										
										
											2014-04-05 22:03:33 -05:00
										 |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-05 17:17:03 -05:00
										 |  |  |   # Return a {Formula} instance for the given rack. | 
					
						
							| 
									
										
										
										
											2016-09-15 16:01:18 +01:00
										 |  |  |   # | 
					
						
							| 
									
										
										
										
											2020-11-05 15:19:56 -05:00
										 |  |  |   # @param spec when nil, will auto resolve the formula's spec. | 
					
						
							| 
									
										
										
										
											2024-04-30 11:10:23 +02:00
										 |  |  |   # @param alias_path will be used if the formula is found not to be | 
					
						
							|  |  |  |   #   installed and discarded if it is installed because the `alias_path` used | 
					
						
							| 
									
										
										
										
											2020-11-05 15:19:56 -05:00
										 |  |  |   #   to install the formula will be set instead. | 
					
						
							| 
									
										
										
										
											2023-04-14 15:33:40 +02:00
										 |  |  |   sig { | 
					
						
							|  |  |  |     params( | 
					
						
							|  |  |  |       rack:         Pathname, | 
					
						
							|  |  |  |       # Automatically resolves the formula's spec if not specified. | 
					
						
							| 
									
										
										
										
											2024-12-06 11:06:27 -08:00
										 |  |  |       spec:         T.nilable(Symbol), | 
					
						
							|  |  |  |       alias_path:   T.any(NilClass, Pathname, String), | 
					
						
							| 
									
										
										
										
											2023-04-14 15:33:40 +02:00
										 |  |  |       force_bottle: T::Boolean, | 
					
						
							|  |  |  |       flags:        T::Array[String], | 
					
						
							|  |  |  |     ).returns(Formula) | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2024-12-06 11:06:27 -08:00
										 |  |  |   def self.from_rack(rack, spec = nil, alias_path: nil, force_bottle: false, flags: []) | 
					
						
							| 
									
										
										
										
											2015-05-16 11:26:26 +08:00
										 |  |  |     kegs = rack.directory? ? rack.subdirs.map { |d| Keg.new(d) } : [] | 
					
						
							| 
									
										
										
										
											2024-03-31 16:53:15 -07:00
										 |  |  |     keg = kegs.find(&:linked?) || kegs.find(&:optlinked?) || kegs.max_by(&:scheme_and_version) | 
					
						
							| 
									
										
										
										
											2015-05-16 11:26:26 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-14 15:33:40 +02:00
										 |  |  |     options = { | 
					
						
							| 
									
										
										
										
											2024-03-07 16:20:20 +00:00
										 |  |  |       alias_path:, | 
					
						
							|  |  |  |       force_bottle:, | 
					
						
							|  |  |  |       flags:, | 
					
						
							| 
									
										
										
										
											2023-04-14 15:33:40 +02:00
										 |  |  |     }.compact | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-15 17:45:21 +08:00
										 |  |  |     if keg | 
					
						
							| 
									
										
										
										
											2023-04-14 15:33:40 +02:00
										 |  |  |       from_keg(keg, *spec, **options) | 
					
						
							| 
									
										
										
										
											2016-07-15 17:45:21 +08:00
										 |  |  |     else | 
					
						
							| 
									
										
										
										
											2023-04-14 15:33:40 +02:00
										 |  |  |       factory(rack.basename.to_s, *spec, from: :rack, warn: false, **options) | 
					
						
							| 
									
										
										
										
											2016-07-15 17:45:21 +08:00
										 |  |  |     end | 
					
						
							|  |  |  |   end | 
					
						
							| 
									
										
										
										
											2018-06-05 23:19:18 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-05 17:17:03 -05:00
										 |  |  |   # Return whether given rack is keg-only. | 
					
						
							| 
									
										
										
										
											2018-06-05 23:19:18 -04:00
										 |  |  |   def self.keg_only?(rack) | 
					
						
							|  |  |  |     Formulary.from_rack(rack).keg_only? | 
					
						
							| 
									
										
										
										
											2024-02-16 21:27:02 +01:00
										 |  |  |   rescue FormulaUnavailableError, TapFormulaAmbiguityError | 
					
						
							| 
									
										
										
										
											2018-06-05 23:19:18 -04:00
										 |  |  |     false | 
					
						
							|  |  |  |   end | 
					
						
							| 
									
										
										
										
											2016-07-15 17:45:21 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-05 15:19:56 -05:00
										 |  |  |   # Return a {Formula} instance for the given keg. | 
					
						
							| 
									
										
										
										
											2023-04-14 15:33:40 +02:00
										 |  |  |   sig { | 
					
						
							|  |  |  |     params( | 
					
						
							|  |  |  |       keg:          Keg, | 
					
						
							|  |  |  |       # Automatically resolves the formula's spec if not specified. | 
					
						
							| 
									
										
										
										
											2024-12-06 11:06:27 -08:00
										 |  |  |       spec:         T.nilable(Symbol), | 
					
						
							|  |  |  |       alias_path:   T.any(NilClass, Pathname, String), | 
					
						
							| 
									
										
										
										
											2023-04-14 15:33:40 +02:00
										 |  |  |       force_bottle: T::Boolean, | 
					
						
							|  |  |  |       flags:        T::Array[String], | 
					
						
							|  |  |  |     ).returns(Formula) | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   def self.from_keg( | 
					
						
							|  |  |  |     keg, | 
					
						
							| 
									
										
										
										
											2024-12-06 11:06:27 -08:00
										 |  |  |     spec = nil, | 
					
						
							|  |  |  |     alias_path: nil, | 
					
						
							|  |  |  |     force_bottle: false, | 
					
						
							|  |  |  |     flags: [] | 
					
						
							| 
									
										
										
										
											2023-04-14 15:33:40 +02:00
										 |  |  |   ) | 
					
						
							| 
									
										
										
										
											2024-04-28 03:23:21 +02:00
										 |  |  |     tab = keg.tab | 
					
						
							| 
									
										
										
										
											2015-07-30 16:33:19 +08:00
										 |  |  |     tap = tab.tap | 
					
						
							|  |  |  |     spec ||= tab.spec | 
					
						
							| 
									
										
										
										
											2015-05-16 11:26:26 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-14 15:33:40 +02:00
										 |  |  |     formula_name = keg.rack.basename.to_s | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     options = { | 
					
						
							| 
									
										
										
										
											2024-03-07 16:20:20 +00:00
										 |  |  |       alias_path:, | 
					
						
							| 
									
										
										
										
											2023-04-14 15:33:40 +02:00
										 |  |  |       from:         :keg, | 
					
						
							|  |  |  |       warn:         false, | 
					
						
							| 
									
										
										
										
											2024-03-07 16:20:20 +00:00
										 |  |  |       force_bottle:, | 
					
						
							|  |  |  |       flags:, | 
					
						
							| 
									
										
										
										
											2023-04-14 15:33:40 +02:00
										 |  |  |     }.compact | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-15 15:03:58 +08:00
										 |  |  |     f = if tap.nil? | 
					
						
							| 
									
										
										
										
											2023-04-14 15:33:40 +02:00
										 |  |  |       factory(formula_name, spec, **options) | 
					
						
							| 
									
										
										
										
											2015-05-16 11:26:26 +08:00
										 |  |  |     else | 
					
						
							| 
									
										
										
										
											2015-10-09 15:27:59 +08:00
										 |  |  |       begin | 
					
						
							| 
									
										
										
										
											2023-04-14 15:33:40 +02:00
										 |  |  |         factory("#{tap}/#{formula_name}", spec, **options) | 
					
						
							| 
									
										
										
										
											2015-10-09 15:27:59 +08:00
										 |  |  |       rescue FormulaUnavailableError | 
					
						
							|  |  |  |         # formula may be migrated to different tap. Try to search in core and all taps. | 
					
						
							| 
									
										
										
										
											2023-04-14 15:33:40 +02:00
										 |  |  |         factory(formula_name, spec, **options) | 
					
						
							| 
									
										
										
										
											2015-10-09 15:27:59 +08:00
										 |  |  |       end | 
					
						
							| 
									
										
										
										
											2015-05-16 11:26:26 +08:00
										 |  |  |     end | 
					
						
							| 
									
										
										
										
											2016-07-15 15:03:58 +08:00
										 |  |  |     f.build = tab | 
					
						
							| 
									
										
										
										
											2023-07-24 14:01:53 -07:00
										 |  |  |     T.cast(f.build, Tab).used_options = Tab.remap_deprecated_options(f.deprecated_options, tab.used_options).as_flags | 
					
						
							| 
									
										
										
										
											2016-08-06 11:22:12 +03:00
										 |  |  |     f.version.update_commit(keg.version.version.commit) if f.head? && keg.version.head? | 
					
						
							| 
									
										
										
										
											2016-07-15 15:03:58 +08:00
										 |  |  |     f | 
					
						
							| 
									
										
										
										
											2015-05-16 11:26:26 +08:00
										 |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-05 17:17:03 -05:00
										 |  |  |   # Return a {Formula} instance directly from contents. | 
					
						
							| 
									
										
										
										
											2023-04-14 15:33:40 +02:00
										 |  |  |   sig { | 
					
						
							|  |  |  |     params( | 
					
						
							|  |  |  |       name:          String, | 
					
						
							|  |  |  |       path:          Pathname, | 
					
						
							|  |  |  |       contents:      String, | 
					
						
							|  |  |  |       spec:          Symbol, | 
					
						
							| 
									
										
										
										
											2024-12-06 11:06:27 -08:00
										 |  |  |       alias_path:    T.nilable(Pathname), | 
					
						
							| 
									
										
										
										
											2023-04-14 15:33:40 +02:00
										 |  |  |       force_bottle:  T::Boolean, | 
					
						
							|  |  |  |       flags:         T::Array[String], | 
					
						
							|  |  |  |       ignore_errors: T::Boolean, | 
					
						
							|  |  |  |     ).returns(Formula) | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2021-04-13 17:40:41 +01:00
										 |  |  |   def self.from_contents( | 
					
						
							| 
									
										
										
										
											2023-04-14 15:33:40 +02:00
										 |  |  |     name, | 
					
						
							|  |  |  |     path, | 
					
						
							|  |  |  |     contents, | 
					
						
							|  |  |  |     spec = :stable, | 
					
						
							| 
									
										
										
										
											2024-12-06 11:06:27 -08:00
										 |  |  |     alias_path: nil, | 
					
						
							|  |  |  |     force_bottle: false, | 
					
						
							|  |  |  |     flags: [], | 
					
						
							|  |  |  |     ignore_errors: false | 
					
						
							| 
									
										
										
										
											2021-04-13 17:40:41 +01:00
										 |  |  |   ) | 
					
						
							| 
									
										
										
										
											2024-12-06 11:06:27 -08:00
										 |  |  |     FormulaContentsLoader.new(name, path, contents) | 
					
						
							|  |  |  |                          .get_formula(spec, alias_path:, force_bottle:, flags:, ignore_errors:) | 
					
						
							| 
									
										
										
										
											2015-09-02 16:25:46 +08:00
										 |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-09 14:56:01 +03:00
										 |  |  |   def self.to_rack(ref) | 
					
						
							| 
									
										
										
										
											2016-08-10 08:48:30 +01:00
										 |  |  |     # If using a fully-scoped reference, check if the formula can be resolved. | 
					
						
							|  |  |  |     factory(ref) if ref.include? "/" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # Check whether the rack with the given name exists. | 
					
						
							| 
									
										
										
										
											2015-08-10 21:35:59 +08:00
										 |  |  |     if (rack = HOMEBREW_CELLAR/File.basename(ref, ".rb")).directory? | 
					
						
							| 
									
										
										
										
											2015-08-15 16:12:42 +08:00
										 |  |  |       return rack.resolved_path | 
					
						
							| 
									
										
										
										
											2015-08-09 14:56:01 +03:00
										 |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-10 08:48:30 +01:00
										 |  |  |     # Use canonical name to locate rack. | 
					
						
							| 
									
										
										
										
											2015-08-15 16:12:42 +08:00
										 |  |  |     (HOMEBREW_CELLAR/canonical_name(ref)).resolved_path | 
					
						
							| 
									
										
										
										
											2015-08-09 14:56:01 +03:00
										 |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-04-05 22:03:34 -05:00
										 |  |  |   def self.canonical_name(ref) | 
					
						
							|  |  |  |     loader_for(ref).name | 
					
						
							| 
									
										
										
										
											2015-05-15 19:41:31 +08:00
										 |  |  |   rescue TapFormulaAmbiguityError | 
					
						
							|  |  |  |     # If there are multiple tap formulae with the name of ref, | 
					
						
							|  |  |  |     # then ref is the canonical name | 
					
						
							|  |  |  |     ref.downcase | 
					
						
							| 
									
										
										
										
											2014-04-05 22:03:34 -05:00
										 |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-05-08 13:48:36 +08:00
										 |  |  |   def self.path(ref) | 
					
						
							|  |  |  |     loader_for(ref).path | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-01 03:13:56 +01:00
										 |  |  |   sig { params(tapped_name: String, warn: T::Boolean).returns(T.nilable([String, Tap, T.nilable(Symbol)])) } | 
					
						
							| 
									
										
										
										
											2024-02-05 23:22:49 +01:00
										 |  |  |   def self.tap_formula_name_type(tapped_name, warn:) | 
					
						
							| 
									
										
										
										
											2024-03-01 03:13:56 +01:00
										 |  |  |     return unless (tap_with_name = Tap.with_formula_name(tapped_name)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     tap, name = tap_with_name | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-02-05 23:22:49 +01:00
										 |  |  |     type = nil | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-02-16 21:27:02 +01:00
										 |  |  |     # FIXME: Remove the need to do this here. | 
					
						
							|  |  |  |     alias_table_key = tap.core_tap? ? name : "#{tap}/#{name}" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (possible_alias = tap.alias_table[alias_table_key].presence) | 
					
						
							|  |  |  |       # FIXME: Remove the need to split the name and instead make | 
					
						
							|  |  |  |       #        the alias table only contain short names. | 
					
						
							| 
									
										
										
										
											2024-03-01 03:13:56 +01:00
										 |  |  |       name = T.must(possible_alias.split("/").last) | 
					
						
							| 
									
										
										
										
											2024-02-05 23:22:49 +01:00
										 |  |  |       type = :alias | 
					
						
							|  |  |  |     elsif (new_name = tap.formula_renames[name].presence) | 
					
						
							| 
									
										
										
										
											2024-02-13 04:09:49 +01:00
										 |  |  |       old_name = tap.core_tap? ? name : tapped_name | 
					
						
							| 
									
										
										
										
											2024-02-05 23:22:49 +01:00
										 |  |  |       name = new_name | 
					
						
							|  |  |  |       new_name = tap.core_tap? ? name : "#{tap}/#{name}" | 
					
						
							|  |  |  |       type = :rename | 
					
						
							|  |  |  |     elsif (new_tap_name = tap.tap_migrations[name].presence) | 
					
						
							| 
									
										
										
										
											2024-02-23 15:02:10 +01:00
										 |  |  |       new_tap, new_name = Tap.with_formula_name(new_tap_name) || [Tap.fetch(new_tap_name), name] | 
					
						
							| 
									
										
										
										
											2024-02-05 23:22:49 +01:00
										 |  |  |       new_tap.ensure_installed! | 
					
						
							| 
									
										
										
										
											2024-02-13 04:09:49 +01:00
										 |  |  |       new_tapped_name = "#{new_tap}/#{new_name}" | 
					
						
							| 
									
										
										
										
											2024-02-10 14:56:53 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |       if tapped_name == new_tapped_name | 
					
						
							|  |  |  |         opoo "Tap migration for #{tapped_name} points to itself, stopping recursion." | 
					
						
							|  |  |  |       else | 
					
						
							| 
									
										
										
										
											2024-02-13 04:09:49 +01:00
										 |  |  |         old_name = tap.core_tap? ? name : tapped_name | 
					
						
							| 
									
										
										
										
											2024-03-01 03:13:56 +01:00
										 |  |  |         return unless (name_tap_type = tap_formula_name_type(new_tapped_name, warn: false)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         name, tap, = name_tap_type | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-02-13 04:09:49 +01:00
										 |  |  |         new_name = new_tap.core_tap? ? name : "#{tap}/#{name}" | 
					
						
							| 
									
										
										
										
											2024-02-10 14:56:53 +01:00
										 |  |  |         type = :migration | 
					
						
							|  |  |  |       end | 
					
						
							| 
									
										
										
										
											2023-11-11 16:33:49 -05:00
										 |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-02-05 23:22:49 +01:00
										 |  |  |     opoo "Formula #{old_name} was renamed to #{new_name}." if warn && old_name && new_name | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     [name, tap, type] | 
					
						
							| 
									
										
										
										
											2023-11-11 16:33:49 -05:00
										 |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-12-06 11:06:27 -08:00
										 |  |  |   def self.loader_for(ref, from: nil, warn: true) | 
					
						
							| 
									
										
										
										
											2024-02-16 21:27:02 +01:00
										 |  |  |     [ | 
					
						
							|  |  |  |       FromBottleLoader, | 
					
						
							|  |  |  |       FromURILoader, | 
					
						
							|  |  |  |       FromAPILoader, | 
					
						
							|  |  |  |       FromTapLoader, | 
					
						
							|  |  |  |       FromPathLoader, | 
					
						
							|  |  |  |       FromNameLoader, | 
					
						
							|  |  |  |       FromKegLoader, | 
					
						
							|  |  |  |       FromCacheLoader, | 
					
						
							|  |  |  |       NullLoader, | 
					
						
							|  |  |  |     ].each do |loader_class| | 
					
						
							| 
									
										
										
										
											2024-12-06 11:06:27 -08:00
										 |  |  |       if (loader = loader_class.try_new(ref, from:, warn:)) | 
					
						
							| 
									
										
										
										
											2024-02-16 21:27:02 +01:00
										 |  |  |         $stderr.puts "#{$PROGRAM_NAME} (#{loader_class}): loading #{ref}" if debug? | 
					
						
							|  |  |  |         return loader | 
					
						
							| 
									
										
										
										
											2024-02-05 23:22:49 +01:00
										 |  |  |       end | 
					
						
							| 
									
										
										
										
											2023-11-11 16:33:49 -05:00
										 |  |  |     end | 
					
						
							| 
									
										
										
										
											2013-06-08 20:58:43 -07:00
										 |  |  |   end | 
					
						
							| 
									
										
										
										
											2015-05-08 18:59:08 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   def self.core_path(name) | 
					
						
							| 
									
										
										
										
											2023-02-24 10:57:41 +00:00
										 |  |  |     find_formula_in_tap(name.to_s.downcase, CoreTap.instance) | 
					
						
							| 
									
										
										
										
											2015-05-08 18:59:08 +08:00
										 |  |  |   end | 
					
						
							| 
									
										
										
										
											2015-05-08 19:16:06 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-04 16:21:31 +01:00
										 |  |  |   sig { params(name: String, tap: Tap).returns(Pathname) } | 
					
						
							| 
									
										
										
										
											2023-02-24 10:57:41 +00:00
										 |  |  |   def self.find_formula_in_tap(name, tap) | 
					
						
							| 
									
										
										
										
											2023-08-04 16:21:31 +01:00
										 |  |  |     filename = if name.end_with?(".rb") | 
					
						
							|  |  |  |       name | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |       "#{name}.rb" | 
					
						
							|  |  |  |     end | 
					
						
							| 
									
										
										
										
											2023-02-24 10:57:41 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-02-23 15:03:33 +01:00
										 |  |  |     tap.formula_files_by_name.fetch(name, tap.formula_dir/filename) | 
					
						
							| 
									
										
										
										
											2015-05-08 19:16:06 +08:00
										 |  |  |   end | 
					
						
							| 
									
										
										
										
											2013-06-08 20:58:43 -07:00
										 |  |  | end |