| 
									
										
										
										
											2015-06-02 20:51:16 -04:00
										 |  |  | require "digest/md5" | 
					
						
							| 
									
										
										
										
											2015-12-13 20:19:53 -08:00
										 |  |  | require "tap" | 
					
						
							| 
									
										
										
										
											2015-06-02 20:51:16 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-23 12:47:10 -07: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. | 
					
						
							| 
									
										
										
										
											2014-05-02 07:39:23 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-08 20:58:43 -07:00
										 |  |  | class Formulary | 
					
						
							| 
									
										
										
										
											2015-06-01 19:20:11 -04:00
										 |  |  |   FORMULAE = {} | 
					
						
							| 
									
										
										
										
											2015-01-01 01:21:59 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-01 19:20:11 -04:00
										 |  |  |   def self.formula_class_defined?(path) | 
					
						
							|  |  |  |     FORMULAE.key?(path) | 
					
						
							| 
									
										
										
										
											2013-06-18 10:11:06 -07:00
										 |  |  |   end | 
					
						
							| 
									
										
										
										
											2013-06-08 20:58:43 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-01 19:20:11 -04:00
										 |  |  |   def self.formula_class_get(path) | 
					
						
							|  |  |  |     FORMULAE.fetch(path) | 
					
						
							| 
									
										
										
										
											2013-06-18 10:11:06 -07:00
										 |  |  |   end | 
					
						
							| 
									
										
										
										
											2013-06-08 20:58:43 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-02 16:12:26 +08:00
										 |  |  |   def self.load_formula(name, path, contents, namespace) | 
					
						
							| 
									
										
										
										
											2016-05-28 15:54:05 +01:00
										 |  |  |     if ENV["HOMEBREW_DISABLE_LOAD_FORMULA"] | 
					
						
							|  |  |  |       raise "Formula loading disabled by HOMEBREW_DISABLE_LOAD_FORMULA!" | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-01 19:20:11 -04:00
										 |  |  |     mod = Module.new | 
					
						
							| 
									
										
										
										
											2015-09-02 16:12:26 +08:00
										 |  |  |     const_set(namespace, mod) | 
					
						
							| 
									
										
										
										
											2015-06-06 18:10:47 -04:00
										 |  |  |     mod.module_eval(contents, path) | 
					
						
							| 
									
										
										
										
											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) | 
					
						
							| 
									
										
										
										
											2016-04-16 20:58:20 +02:00
										 |  |  |     rescue NameError => original_exception | 
					
						
							| 
									
										
										
										
											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) } | 
					
						
							| 
									
										
										
										
											2016-04-16 20:58:20 +02:00
										 |  |  |       e = FormulaClassUnavailableError.new(name, path, class_name, class_list) | 
					
						
							|  |  |  |       raise e, "", original_exception.backtrace | 
					
						
							| 
									
										
										
										
											2015-06-01 19:20:11 -04:00
										 |  |  |     end | 
					
						
							| 
									
										
										
										
											2013-12-09 21:10:32 -06:00
										 |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-02 16:12:26 +08:00
										 |  |  |   def self.load_formula_from_path(name, path) | 
					
						
							| 
									
										
										
										
											2016-09-24 17:59:14 +02:00
										 |  |  |     contents = path.open("r") { |f| ensure_utf8_encoding(f).read } | 
					
						
							| 
									
										
										
										
											2015-09-02 16:12:26 +08:00
										 |  |  |     namespace = "FormulaNamespace#{Digest::MD5.hexdigest(path.to_s)}" | 
					
						
							|  |  |  |     klass = load_formula(name, path, contents, namespace) | 
					
						
							|  |  |  |     FORMULAE[path] = klass | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-06 18:10:47 -04:00
										 |  |  |   if IO.method_defined?(:set_encoding) | 
					
						
							| 
									
										
										
										
											2016-09-24 17:59:14 +02:00
										 |  |  |     def self.ensure_utf8_encoding(io) | 
					
						
							| 
									
										
										
										
											2015-06-06 18:10:47 -04:00
										 |  |  |       io.set_encoding(Encoding::UTF_8) | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  |   else | 
					
						
							| 
									
										
										
										
											2016-09-24 17:59:14 +02:00
										 |  |  |     def self.ensure_utf8_encoding(io) | 
					
						
							| 
									
										
										
										
											2015-06-06 18:10:47 -04:00
										 |  |  |       io | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  |   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 | 
					
						
							|  |  |  |     class_name.gsub!(/[-_.\s]([a-zA-Z0-9])/) { $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 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-18 10:11:06 -07:00
										 |  |  |   # A FormulaLoader returns instances of formulae. | 
					
						
							|  |  |  |   # Subclasses implement loaders for particular sources of formulae. | 
					
						
							|  |  |  |   class FormulaLoader | 
					
						
							|  |  |  |     # The formula's name | 
					
						
							|  |  |  |     attr_reader :name | 
					
						
							|  |  |  |     # The formula's ruby file's path or filename | 
					
						
							|  |  |  |     attr_reader :path | 
					
						
							| 
									
										
										
										
											2016-09-03 21:10:44 +01:00
										 |  |  |     # The name used to install the formula | 
					
						
							| 
									
										
										
										
											2016-09-05 01:11:36 +01:00
										 |  |  |     attr_reader :alias_path | 
					
						
							| 
									
										
										
										
											2014-04-03 22:40:40 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def initialize(name, path) | 
					
						
							|  |  |  |       @name = name | 
					
						
							| 
									
										
										
										
											2014-04-06 00:31:07 -05:00
										 |  |  |       @path = path.resolved_path | 
					
						
							| 
									
										
										
										
											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. | 
					
						
							|  |  |  |     def get_formula(spec, alias_path: nil) | 
					
						
							|  |  |  |       klass.new(name, path, spec, alias_path: alias_path || self.alias_path) | 
					
						
							| 
									
										
										
										
											2014-03-07 17:23:44 -06:00
										 |  |  |     end | 
					
						
							| 
									
										
										
										
											2013-06-18 10:11:06 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def klass | 
					
						
							| 
									
										
										
										
											2015-06-01 19:20:11 -04:00
										 |  |  |       load_file unless Formulary.formula_class_defined?(path) | 
					
						
							|  |  |  |       Formulary.formula_class_get(path) | 
					
						
							| 
									
										
										
										
											2013-06-18 10:11:06 -07:00
										 |  |  |     end | 
					
						
							| 
									
										
										
										
											2014-12-29 14:53:22 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |     private | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def load_file | 
					
						
							| 
									
										
										
										
											2016-06-01 09:45:49 +02:00
										 |  |  |       $stderr.puts "#{$0} (#{self.class.name}): loading #{path}" if ARGV.debug? | 
					
						
							| 
									
										
										
										
											2016-09-17 15:17:27 +01:00
										 |  |  |       raise FormulaUnavailableError, name unless path.file? | 
					
						
							| 
									
										
										
										
											2015-09-02 16:12:26 +08:00
										 |  |  |       Formulary.load_formula_from_path(name, path) | 
					
						
							| 
									
										
										
										
											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
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-18 10:11:06 -07:00
										 |  |  |   # Loads formulae from bottles. | 
					
						
							|  |  |  |   class BottleLoader < FormulaLoader | 
					
						
							| 
									
										
										
										
											2015-08-03 13:09:07 +01:00
										 |  |  |     def initialize(bottle_name) | 
					
						
							| 
									
										
										
										
											2013-06-18 10:11:06 -07:00
										 |  |  |       @bottle_filename = Pathname(bottle_name).realpath | 
					
						
							| 
									
										
										
										
											2016-04-25 17:57:51 +01:00
										 |  |  |       name, full_name = Utils::Bottles.resolve_formula_names @bottle_filename | 
					
						
							| 
									
										
										
										
											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
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-15 16:01:18 +01:00
										 |  |  |     def get_formula(spec, alias_path: nil) | 
					
						
							| 
									
										
										
										
											2014-03-07 17:23:44 -06:00
										 |  |  |       formula = super | 
					
						
							| 
									
										
										
										
											2013-09-25 18:51:30 -05:00
										 |  |  |       formula.local_bottle_path = @bottle_filename | 
					
						
							| 
									
										
										
										
											2015-07-23 14:09:32 +08:00
										 |  |  |       formula_version = formula.pkg_version | 
					
						
							| 
									
										
										
										
											2016-04-25 17:57:51 +01:00
										 |  |  |       bottle_version =  Utils::Bottles.resolve_version(@bottle_filename) | 
					
						
							| 
									
										
										
										
											2015-07-23 14:09:32 +08:00
										 |  |  |       unless formula_version == bottle_version | 
					
						
							|  |  |  |         raise BottleVersionMismatchError.new(@bottle_filename, bottle_version, formula, formula_version) | 
					
						
							|  |  |  |       end | 
					
						
							| 
									
										
										
										
											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
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-04-05 22:03:34 -05:00
										 |  |  |   class AliasLoader < FormulaLoader | 
					
						
							| 
									
										
										
										
											2015-08-03 13:09:07 +01:00
										 |  |  |     def initialize(alias_path) | 
					
						
							| 
									
										
										
										
											2014-04-05 22:03:34 -05:00
										 |  |  |       path = alias_path.resolved_path | 
					
						
							|  |  |  |       name = path.basename(".rb").to_s | 
					
						
							|  |  |  |       super name, path | 
					
						
							| 
									
										
										
										
											2016-09-15 16:01:18 +01:00
										 |  |  |       @alias_path = alias_path.to_s | 
					
						
							| 
									
										
										
										
											2014-04-05 22:03:34 -05:00
										 |  |  |     end | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-18 10:11:06 -07:00
										 |  |  |   # Loads formulae from disk using a path | 
					
						
							|  |  |  |   class FromPathLoader < FormulaLoader | 
					
						
							| 
									
										
										
										
											2015-08-03 13:09:07 +01:00
										 |  |  |     def initialize(path) | 
					
						
							| 
									
										
										
										
											2014-04-03 22:40:40 -05:00
										 |  |  |       path = Pathname.new(path).expand_path | 
					
						
							| 
									
										
										
										
											2014-04-05 22:03:34 -05:00
										 |  |  |       super path.basename(".rb").to_s, path | 
					
						
							| 
									
										
										
										
											2013-06-18 10:11:06 -07:00
										 |  |  |     end | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-23 12:47:10 -07:00
										 |  |  |   # Loads formulae from URLs | 
					
						
							| 
									
										
										
										
											2013-06-18 10:11:06 -07:00
										 |  |  |   class FromUrlLoader < FormulaLoader | 
					
						
							|  |  |  |     attr_reader :url | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-03 13:09:07 +01:00
										 |  |  |     def initialize(url) | 
					
						
							| 
									
										
										
										
											2013-06-18 10:11:06 -07:00
										 |  |  |       @url = url | 
					
						
							| 
									
										
										
										
											2014-04-10 18:58:09 -04:00
										 |  |  |       uri = URI(url) | 
					
						
							|  |  |  |       formula = File.basename(uri.path, ".rb") | 
					
						
							|  |  |  |       super formula, HOMEBREW_CACHE_FORMULA/File.basename(uri.path) | 
					
						
							| 
									
										
										
										
											2013-06-18 10:11:06 -07:00
										 |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-12-29 14:53:22 -05:00
										 |  |  |     def load_file | 
					
						
							|  |  |  |       HOMEBREW_CACHE_FORMULA.mkpath | 
					
						
							|  |  |  |       FileUtils.rm_f(path) | 
					
						
							|  |  |  |       curl url, "-o", path | 
					
						
							| 
									
										
										
										
											2014-03-07 17:23:44 -06:00
										 |  |  |       super | 
					
						
							| 
									
										
										
										
											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. | 
					
						
							|  |  |  |   class TapLoader < FormulaLoader | 
					
						
							| 
									
										
										
										
											2015-07-14 21:33:29 +08:00
										 |  |  |     attr_reader :tap | 
					
						
							| 
									
										
										
										
											2014-04-05 22:03:33 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-11 16:42:29 +00:00
										 |  |  |     def initialize(tapped_name, from: nil) | 
					
						
							|  |  |  |       warn = ![:keg, :rack].include?(from) | 
					
						
							|  |  |  |       name, path = formula_name_path(tapped_name, warn: warn) | 
					
						
							| 
									
										
										
										
											2016-11-02 14:47:24 -04:00
										 |  |  |       super name, path | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def formula_name_path(tapped_name, warn: true) | 
					
						
							| 
									
										
										
										
											2014-04-05 22:03:33 -05:00
										 |  |  |       user, repo, name = tapped_name.split("/", 3).map(&:downcase) | 
					
						
							| 
									
										
										
										
											2015-12-02 14:35:42 +08:00
										 |  |  |       @tap = Tap.fetch user, repo | 
					
						
							| 
									
										
										
										
											2016-02-24 20:06:33 +08:00
										 |  |  |       formula_dir = @tap.formula_dir || @tap.path | 
					
						
							|  |  |  |       path = formula_dir/"#{name}.rb" | 
					
						
							| 
									
										
										
										
											2015-09-12 18:04:06 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-24 20:06:33 +08:00
										 |  |  |       unless path.file? | 
					
						
							| 
									
										
										
										
											2015-12-06 21:44:18 +08:00
										 |  |  |         if (possible_alias = @tap.alias_dir/name).file? | 
					
						
							| 
									
										
										
										
											2015-09-12 18:04:06 +08:00
										 |  |  |           path = possible_alias.resolved_path | 
					
						
							|  |  |  |           name = path.basename(".rb").to_s | 
					
						
							| 
									
										
										
										
											2016-02-24 20:06:33 +08:00
										 |  |  |         elsif (new_name = @tap.formula_renames[name]) && | 
					
						
							|  |  |  |               (new_path = formula_dir/"#{new_name}.rb").file? | 
					
						
							| 
									
										
										
										
											2016-11-02 14:47:24 -04:00
										 |  |  |           old_name = name | 
					
						
							| 
									
										
										
										
											2016-02-24 20:06:33 +08:00
										 |  |  |           path = new_path | 
					
						
							|  |  |  |           name = new_name | 
					
						
							| 
									
										
										
										
											2016-11-02 14:47:24 -04:00
										 |  |  |           new_name = @tap.core_tap? ? name : "#{@tap}/#{name}" | 
					
						
							|  |  |  |         elsif (new_tap_name = @tap.tap_migrations[name]) | 
					
						
							|  |  |  |           new_tap = Tap.fetch new_tap_name | 
					
						
							|  |  |  |           new_tap.install unless new_tap.installed? | 
					
						
							|  |  |  |           new_tapped_name = "#{new_tap_name}/#{name}" | 
					
						
							|  |  |  |           name, path = formula_name_path(new_tapped_name, warn: false) | 
					
						
							|  |  |  |           old_name = tapped_name | 
					
						
							|  |  |  |           new_name = new_tap.core_tap? ? name : new_tapped_name | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if warn && old_name && new_name | 
					
						
							|  |  |  |           opoo "Use #{new_name} instead of deprecated #{old_name}" | 
					
						
							| 
									
										
										
										
											2015-09-12 18:04:06 +08:00
										 |  |  |         end | 
					
						
							|  |  |  |       end | 
					
						
							| 
									
										
										
										
											2014-04-07 18:44:29 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-02 14:47:24 -04:00
										 |  |  |       [name, path] | 
					
						
							| 
									
										
										
										
											2013-06-08 20:58:43 -07:00
										 |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-15 16:01:18 +01:00
										 |  |  |     def get_formula(spec, alias_path: nil) | 
					
						
							| 
									
										
										
										
											2014-03-07 17:23:44 -06:00
										 |  |  |       super | 
					
						
							| 
									
										
										
										
											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 | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-01-01 01:21:59 -05:00
										 |  |  |   class NullLoader < FormulaLoader | 
					
						
							|  |  |  |     def initialize(name) | 
					
						
							| 
									
										
										
										
											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 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-02 16:25:46 +08:00
										 |  |  |   # Load formulae directly from their contents | 
					
						
							|  |  |  |   class FormulaContentsLoader < FormulaLoader | 
					
						
							|  |  |  |     # The formula's contents | 
					
						
							|  |  |  |     attr_reader :contents | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def initialize(name, path, contents) | 
					
						
							|  |  |  |       @contents = contents | 
					
						
							|  |  |  |       super name, path | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def klass | 
					
						
							| 
									
										
										
										
											2016-06-01 09:45:49 +02:00
										 |  |  |       $stderr.puts "#{$0} (#{self.class.name}): loading #{path}" if ARGV.debug? | 
					
						
							| 
									
										
										
										
											2015-09-02 16:25:46 +08:00
										 |  |  |       namespace = "FormulaNamespace#{Digest::MD5.hexdigest(contents)}" | 
					
						
							|  |  |  |       Formulary.load_formula(name, path, contents, namespace) | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-18 10:11:06 -07:00
										 |  |  |   # Return a Formula instance for the given reference. | 
					
						
							| 
									
										
										
										
											2013-06-23 12:47:10 -07:00
										 |  |  |   # `ref` is string containing: | 
					
						
							|  |  |  |   # * a formula name | 
					
						
							|  |  |  |   # * a formula pathname | 
					
						
							|  |  |  |   # * a formula URL | 
					
						
							|  |  |  |   # * a local bottle reference | 
					
						
							| 
									
										
										
										
											2016-11-11 16:42:29 +00:00
										 |  |  |   def self.factory(ref, spec = :stable, alias_path: nil, from: nil) | 
					
						
							|  |  |  |     loader_for(ref, from: from).get_formula(spec, alias_path: alias_path) | 
					
						
							| 
									
										
										
										
											2014-04-05 22:03:33 -05:00
										 |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-05-16 11:26:26 +08:00
										 |  |  |   # Return a Formula instance for the given rack. | 
					
						
							| 
									
										
										
										
											2015-07-30 16:33:19 +08:00
										 |  |  |   # It will auto resolve formula's spec when requested spec is nil | 
					
						
							| 
									
										
										
										
											2016-09-15 16:01:18 +01:00
										 |  |  |   # | 
					
						
							|  |  |  |   # The :alias_path option will be used if the formula is found not to be | 
					
						
							|  |  |  |   # installed, and discarded if it is installed because the alias_path used | 
					
						
							|  |  |  |   # to install the formula will be set instead. | 
					
						
							|  |  |  |   def self.from_rack(rack, spec = nil, alias_path: nil) | 
					
						
							| 
									
										
										
										
											2015-05-16 11:26:26 +08:00
										 |  |  |     kegs = rack.directory? ? rack.subdirs.map { |d| Keg.new(d) } : [] | 
					
						
							|  |  |  |     keg = kegs.detect(&:linked?) || kegs.detect(&:optlinked?) || kegs.max_by(&:version) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-15 17:45:21 +08:00
										 |  |  |     if keg | 
					
						
							| 
									
										
										
										
											2016-09-19 16:04:32 +01:00
										 |  |  |       from_keg(keg, spec, alias_path: alias_path) | 
					
						
							| 
									
										
										
										
											2016-07-15 17:45:21 +08:00
										 |  |  |     else | 
					
						
							| 
									
										
										
										
											2016-11-11 16:42:29 +00:00
										 |  |  |       factory(rack.basename.to_s, spec || :stable, alias_path: alias_path, from: :rack) | 
					
						
							| 
									
										
										
										
											2016-07-15 17:45:21 +08:00
										 |  |  |     end | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   # Return a Formula instance for the given keg. | 
					
						
							|  |  |  |   # It will auto resolve formula's spec when requested spec is nil | 
					
						
							| 
									
										
										
										
											2016-09-15 16:01:18 +01:00
										 |  |  |   def self.from_keg(keg, spec = nil, alias_path: nil) | 
					
						
							| 
									
										
										
										
											2015-07-30 16:33:19 +08:00
										 |  |  |     tab = Tab.for_keg(keg) | 
					
						
							|  |  |  |     tap = tab.tap | 
					
						
							|  |  |  |     spec ||= tab.spec | 
					
						
							| 
									
										
										
										
											2015-05-16 11:26:26 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-15 15:03:58 +08:00
										 |  |  |     f = if tap.nil? | 
					
						
							| 
									
										
										
										
											2016-11-11 16:42:29 +00:00
										 |  |  |       factory(keg.rack.basename.to_s, spec, alias_path: alias_path, from: :keg) | 
					
						
							| 
									
										
										
										
											2015-05-16 11:26:26 +08:00
										 |  |  |     else | 
					
						
							| 
									
										
										
										
											2015-10-09 15:27:59 +08:00
										 |  |  |       begin | 
					
						
							| 
									
										
										
										
											2016-11-11 16:42:29 +00:00
										 |  |  |         factory("#{tap}/#{keg.rack.basename}", spec, alias_path: alias_path, from: :keg) | 
					
						
							| 
									
										
										
										
											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. | 
					
						
							| 
									
										
										
										
											2016-11-11 16:42:29 +00:00
										 |  |  |         factory(keg.rack.basename.to_s, spec, alias_path: alias_path, from: :keg) | 
					
						
							| 
									
										
										
										
											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 | 
					
						
							| 
									
										
										
										
											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 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-02 16:25:46 +08:00
										 |  |  |   # Return a Formula instance directly from contents | 
					
						
							|  |  |  |   def self.from_contents(name, path, contents, spec = :stable) | 
					
						
							|  |  |  |     FormulaContentsLoader.new(name, path, contents).get_formula(spec) | 
					
						
							|  |  |  |   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 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-11 16:42:29 +00:00
										 |  |  |   def self.loader_for(ref, from: nil) | 
					
						
							| 
									
										
										
										
											2014-04-05 22:03:33 -05:00
										 |  |  |     case ref | 
					
						
							| 
									
										
										
										
											2015-09-02 20:21:43 +08:00
										 |  |  |     when %r{(https?|ftp|file)://} | 
					
						
							| 
									
										
										
										
											2014-04-05 22:03:33 -05:00
										 |  |  |       return FromUrlLoader.new(ref) | 
					
						
							|  |  |  |     when Pathname::BOTTLE_EXTNAME_RX | 
					
						
							|  |  |  |       return BottleLoader.new(ref) | 
					
						
							| 
									
										
										
										
											2014-04-05 22:03:33 -05:00
										 |  |  |     when HOMEBREW_TAP_FORMULA_REGEX | 
					
						
							| 
									
										
										
										
											2016-11-11 16:42:29 +00:00
										 |  |  |       return TapLoader.new(ref, from: from) | 
					
						
							| 
									
										
										
										
											2013-06-08 20:58:43 -07:00
										 |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-23 11:01:40 +02:00
										 |  |  |     return FromPathLoader.new(ref) if File.extname(ref) == ".rb" | 
					
						
							| 
									
										
										
										
											2014-04-05 22:03:33 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-05-08 18:59:08 +08:00
										 |  |  |     formula_with_that_name = core_path(ref) | 
					
						
							| 
									
										
										
										
											2014-04-05 22:03:33 -05:00
										 |  |  |     if formula_with_that_name.file? | 
					
						
							| 
									
										
										
										
											2015-01-01 01:21:59 -05:00
										 |  |  |       return FormulaLoader.new(ref, formula_with_that_name) | 
					
						
							| 
									
										
										
										
											2014-04-05 22:03:33 -05:00
										 |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-07 18:04:25 +08:00
										 |  |  |     possible_alias = CoreTap.instance.alias_dir/ref | 
					
						
							| 
									
										
										
										
											2016-09-23 11:01:40 +02:00
										 |  |  |     return AliasLoader.new(possible_alias) if possible_alias.file? | 
					
						
							| 
									
										
										
										
											2014-04-05 22:03:33 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-22 13:15:33 +08:00
										 |  |  |     possible_tap_formulae = tap_paths(ref) | 
					
						
							| 
									
										
										
										
											2015-05-08 19:16:06 +08:00
										 |  |  |     if possible_tap_formulae.size > 1
 | 
					
						
							|  |  |  |       raise TapFormulaAmbiguityError.new(ref, possible_tap_formulae) | 
					
						
							| 
									
										
										
										
											2016-09-23 22:02:23 +02:00
										 |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if possible_tap_formulae.size == 1
 | 
					
						
							| 
									
										
										
										
											2015-09-12 18:04:06 +08:00
										 |  |  |       path = possible_tap_formulae.first.resolved_path | 
					
						
							|  |  |  |       name = path.basename(".rb").to_s | 
					
						
							|  |  |  |       return FormulaLoader.new(name, path) | 
					
						
							| 
									
										
										
										
											2015-05-08 19:16:06 +08:00
										 |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-07 18:04:25 +08:00
										 |  |  |     if newref = CoreTap.instance.formula_renames[ref] | 
					
						
							| 
									
										
										
										
											2015-08-09 14:52:49 +03:00
										 |  |  |       formula_with_that_oldname = core_path(newref) | 
					
						
							|  |  |  |       if formula_with_that_oldname.file? | 
					
						
							|  |  |  |         return FormulaLoader.new(newref, formula_with_that_oldname) | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     possible_tap_newname_formulae = [] | 
					
						
							|  |  |  |     Tap.each do |tap| | 
					
						
							|  |  |  |       if newref = tap.formula_renames[ref] | 
					
						
							|  |  |  |         possible_tap_newname_formulae << "#{tap.name}/#{newref}" | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if possible_tap_newname_formulae.size > 1
 | 
					
						
							|  |  |  |       raise TapFormulaWithOldnameAmbiguityError.new(ref, possible_tap_newname_formulae) | 
					
						
							| 
									
										
										
										
											2016-09-23 22:02:23 +02:00
										 |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     unless possible_tap_newname_formulae.empty? | 
					
						
							| 
									
										
										
										
											2016-11-11 16:42:29 +00:00
										 |  |  |       return TapLoader.new(possible_tap_newname_formulae.first, from: from) | 
					
						
							| 
									
										
										
										
											2015-08-09 14:52:49 +03:00
										 |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-04-05 22:03:33 -05:00
										 |  |  |     possible_cached_formula = Pathname.new("#{HOMEBREW_CACHE_FORMULA}/#{ref}.rb") | 
					
						
							|  |  |  |     if possible_cached_formula.file? | 
					
						
							| 
									
										
										
										
											2015-01-01 01:21:59 -05:00
										 |  |  |       return FormulaLoader.new(ref, possible_cached_formula) | 
					
						
							| 
									
										
										
										
											2014-04-05 22:03:33 -05:00
										 |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-03 13:09:07 +01:00
										 |  |  |     NullLoader.new(ref) | 
					
						
							| 
									
										
										
										
											2013-06-08 20:58:43 -07:00
										 |  |  |   end | 
					
						
							| 
									
										
										
										
											2015-05-08 18:59:08 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   def self.core_path(name) | 
					
						
							| 
									
										
										
										
											2016-09-15 16:01:18 +01:00
										 |  |  |     CoreTap.instance.formula_dir/"#{name.to_s.downcase}.rb" | 
					
						
							| 
									
										
										
										
											2015-05-08 18:59:08 +08:00
										 |  |  |   end | 
					
						
							| 
									
										
										
										
											2015-05-08 19:16:06 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-22 13:15:33 +08:00
										 |  |  |   def self.tap_paths(name, taps = Dir["#{HOMEBREW_LIBRARY}/Taps/*/*/"]) | 
					
						
							| 
									
										
										
										
											2015-05-08 19:16:06 +08:00
										 |  |  |     name = name.downcase | 
					
						
							| 
									
										
										
										
											2015-08-09 22:43:01 +08:00
										 |  |  |     taps.map do |tap| | 
					
						
							| 
									
										
										
										
											2015-06-12 13:26:46 +08:00
										 |  |  |       Pathname.glob([ | 
					
						
							| 
									
										
										
										
											2016-09-17 15:17:27 +01:00
										 |  |  |                       "#{tap}Formula/#{name}.rb", | 
					
						
							|  |  |  |                       "#{tap}HomebrewFormula/#{name}.rb", | 
					
						
							|  |  |  |                       "#{tap}#{name}.rb", | 
					
						
							|  |  |  |                       "#{tap}Aliases/#{name}", | 
					
						
							|  |  |  |                     ]).detect(&:file?) | 
					
						
							| 
									
										
										
										
											2015-06-12 13:26:46 +08:00
										 |  |  |     end.compact | 
					
						
							| 
									
										
										
										
											2015-05-08 19:16:06 +08:00
										 |  |  |   end | 
					
						
							| 
									
										
										
										
											2015-08-09 22:43:01 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-22 13:15:33 +08:00
										 |  |  |   def self.find_with_priority(ref, spec = :stable) | 
					
						
							| 
									
										
										
										
											2015-08-09 22:43:01 +08:00
										 |  |  |     possible_pinned_tap_formulae = tap_paths(ref, Dir["#{HOMEBREW_LIBRARY}/PinnedTaps/*/*/"]).map(&:realpath) | 
					
						
							|  |  |  |     if possible_pinned_tap_formulae.size > 1
 | 
					
						
							|  |  |  |       raise TapFormulaAmbiguityError.new(ref, possible_pinned_tap_formulae) | 
					
						
							| 
									
										
										
										
											2016-09-23 22:02:23 +02:00
										 |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if possible_pinned_tap_formulae.size == 1
 | 
					
						
							| 
									
										
										
										
											2015-08-09 22:43:01 +08:00
										 |  |  |       selected_formula = factory(possible_pinned_tap_formulae.first, spec) | 
					
						
							|  |  |  |       if core_path(ref).file? | 
					
						
							|  |  |  |         opoo <<-EOS.undent
 | 
					
						
							|  |  |  |           #{ref} is provided by core, but is now shadowed by #{selected_formula.full_name}. | 
					
						
							| 
									
										
										
										
											2016-03-06 14:50:33 +08:00
										 |  |  |           To refer to the core formula, use Homebrew/core/#{ref} instead. | 
					
						
							| 
									
										
										
										
											2015-08-09 22:43:01 +08:00
										 |  |  |         EOS | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  |       selected_formula | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |       factory(ref, spec) | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  |   end | 
					
						
							| 
									
										
										
										
											2013-06-08 20:58:43 -07:00
										 |  |  | end |