239 lines
		
	
	
		
			5.7 KiB
		
	
	
	
		
			Ruby
		
	
	
	
	
	
			
		
		
	
	
			239 lines
		
	
	
		
			5.7 KiB
		
	
	
	
		
			Ruby
		
	
	
	
	
	
| # The Formulary is responsible for creating instances of Formula.
 | |
| # It is not meant to be used directy from formulae.
 | |
| 
 | |
| class Formulary
 | |
|   module Formulae
 | |
|     class << self
 | |
|       if instance_method(:const_defined?).arity == -1
 | |
|         def formula_const_defined?(name)
 | |
|           const_defined?(name, false)
 | |
|         end
 | |
| 
 | |
|         def formula_const_get(name)
 | |
|           const_get(name, false)
 | |
|         end
 | |
|       else
 | |
|         def formula_const_defined?(name)
 | |
|           const_defined?(name)
 | |
|         end
 | |
| 
 | |
|         def formula_const_get(name)
 | |
|           const_get(name)
 | |
|         end
 | |
|       end
 | |
| 
 | |
|       def remove_formula_const(name)
 | |
|         remove_const(name)
 | |
|       end
 | |
| 
 | |
|       def formula_const_set(name, value)
 | |
|         const_set(name, value)
 | |
|       end
 | |
|     end
 | |
|   end
 | |
| 
 | |
|   def self.unload_formula formula_name
 | |
|     Formulae.remove_formula_const(class_s(formula_name))
 | |
|   end
 | |
| 
 | |
|   def self.restore_formula formula_name, value
 | |
|     old_verbose, $VERBOSE = $VERBOSE, nil
 | |
|     Formulae.formula_const_set(class_s(formula_name), value)
 | |
|   ensure
 | |
|     $VERBOSE = old_verbose
 | |
|   end
 | |
| 
 | |
|   def self.class_s name
 | |
|     class_name = name.capitalize
 | |
|     class_name.gsub!(/[-_.\s]([a-zA-Z0-9])/) { $1.upcase }
 | |
|     class_name.gsub!('+', 'x')
 | |
|     class_name
 | |
|   end
 | |
| 
 | |
|   # 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
 | |
|     # The ruby constant name of the formula's class
 | |
|     attr_reader :class_name
 | |
| 
 | |
|     def initialize(name, path)
 | |
|       @name = name
 | |
|       @path = path.resolved_path
 | |
|       @class_name = Formulary.class_s(name)
 | |
|     end
 | |
| 
 | |
|     # Gets the formula instance.
 | |
|     def get_formula(spec)
 | |
|       klass.new(name, path, spec)
 | |
|     end
 | |
| 
 | |
|     def klass
 | |
|       begin
 | |
|         have_klass = Formulae.formula_const_defined?(class_name)
 | |
|       rescue NameError => e
 | |
|         raise unless e.name.to_s == class_name
 | |
|         raise FormulaUnavailableError, name, e.backtrace
 | |
|       end
 | |
| 
 | |
|       load_file unless have_klass
 | |
| 
 | |
|       Formulae.formula_const_get(class_name)
 | |
|     end
 | |
| 
 | |
|     private
 | |
| 
 | |
|     def load_file
 | |
|       STDERR.puts "#{$0} (#{self.class.name}): loading #{path}" if ARGV.debug?
 | |
|       raise FormulaUnavailableError.new(name) unless path.file?
 | |
|       Formulae.module_eval(path.read, path)
 | |
|     end
 | |
|   end
 | |
| 
 | |
|   # Loads formulae from bottles.
 | |
|   class BottleLoader < FormulaLoader
 | |
|     def initialize bottle_name
 | |
|       @bottle_filename = Pathname(bottle_name).realpath
 | |
|       name_without_version = bottle_filename_formula_name @bottle_filename
 | |
|       if name_without_version.empty?
 | |
|         if ARGV.homebrew_developer?
 | |
|           opoo "Add a new regex to bottle_version.rb to parse this filename."
 | |
|         end
 | |
|         name = bottle_name
 | |
|       else
 | |
|         name = name_without_version
 | |
|       end
 | |
| 
 | |
|       super name, Formula.path(name)
 | |
|     end
 | |
| 
 | |
|     def get_formula(spec)
 | |
|       formula = super
 | |
|       formula.local_bottle_path = @bottle_filename
 | |
|       formula
 | |
|     end
 | |
|   end
 | |
| 
 | |
|   class AliasLoader < FormulaLoader
 | |
|     def initialize alias_path
 | |
|       path = alias_path.resolved_path
 | |
|       name = path.basename(".rb").to_s
 | |
|       super name, path
 | |
|     end
 | |
|   end
 | |
| 
 | |
|   # Loads formulae from disk using a path
 | |
|   class FromPathLoader < FormulaLoader
 | |
|     def initialize path
 | |
|       path = Pathname.new(path).expand_path
 | |
|       super path.basename(".rb").to_s, path
 | |
|     end
 | |
|   end
 | |
| 
 | |
|   # Loads formulae from URLs
 | |
|   class FromUrlLoader < FormulaLoader
 | |
|     attr_reader :url
 | |
| 
 | |
|     def initialize url
 | |
|       @url = url
 | |
|       uri = URI(url)
 | |
|       formula = File.basename(uri.path, ".rb")
 | |
|       super formula, HOMEBREW_CACHE_FORMULA/File.basename(uri.path)
 | |
|     end
 | |
| 
 | |
|     def load_file
 | |
|       HOMEBREW_CACHE_FORMULA.mkpath
 | |
|       FileUtils.rm_f(path)
 | |
|       curl url, "-o", path
 | |
|       super
 | |
|     end
 | |
|   end
 | |
| 
 | |
|   # Loads tapped formulae.
 | |
|   class TapLoader < FormulaLoader
 | |
|     attr_reader :tapped_name
 | |
| 
 | |
|     def initialize tapped_name
 | |
|       @tapped_name = tapped_name
 | |
|       user, repo, name = tapped_name.split("/", 3).map(&:downcase)
 | |
|       tap = Pathname.new("#{HOMEBREW_LIBRARY}/Taps/#{user}/homebrew-#{repo}")
 | |
|       path = tap.join("#{name}.rb")
 | |
| 
 | |
|       if tap.directory?
 | |
|         tap.find_formula do |file|
 | |
|           if file.basename(".rb").to_s == name
 | |
|             path = file
 | |
|           end
 | |
|         end
 | |
|       end
 | |
| 
 | |
|       super name, path
 | |
|     end
 | |
| 
 | |
|     def get_formula(spec)
 | |
|       super
 | |
|     rescue FormulaUnavailableError => e
 | |
|       raise TapFormulaUnavailableError, tapped_name, e.backtrace
 | |
|     end
 | |
|   end
 | |
| 
 | |
|   class NullLoader < FormulaLoader
 | |
|     def initialize(name)
 | |
|       @name = name
 | |
|     end
 | |
| 
 | |
|     def get_formula(spec)
 | |
|       raise FormulaUnavailableError.new(name)
 | |
|     end
 | |
|   end
 | |
| 
 | |
|   # Return a Formula instance for the given reference.
 | |
|   # `ref` is string containing:
 | |
|   # * a formula name
 | |
|   # * a formula pathname
 | |
|   # * a formula URL
 | |
|   # * a local bottle reference
 | |
|   def self.factory(ref, spec=:stable)
 | |
|     loader_for(ref).get_formula(spec)
 | |
|   end
 | |
| 
 | |
|   def self.canonical_name(ref)
 | |
|     loader_for(ref).name
 | |
|   end
 | |
| 
 | |
|   def self.loader_for(ref)
 | |
|     case ref
 | |
|     when %r[(https?|ftp)://]
 | |
|       return FromUrlLoader.new(ref)
 | |
|     when Pathname::BOTTLE_EXTNAME_RX
 | |
|       return BottleLoader.new(ref)
 | |
|     when HOMEBREW_TAP_FORMULA_REGEX
 | |
|       return TapLoader.new(ref)
 | |
|     end
 | |
| 
 | |
|     if File.extname(ref) == ".rb"
 | |
|       return FromPathLoader.new(ref)
 | |
|     end
 | |
| 
 | |
|     formula_with_that_name = Formula.path(ref)
 | |
|     if formula_with_that_name.file?
 | |
|       return FormulaLoader.new(ref, formula_with_that_name)
 | |
|     end
 | |
| 
 | |
|     possible_alias = Pathname.new("#{HOMEBREW_LIBRARY}/Aliases/#{ref}")
 | |
|     if possible_alias.file?
 | |
|       return AliasLoader.new(possible_alias)
 | |
|     end
 | |
| 
 | |
|     possible_cached_formula = Pathname.new("#{HOMEBREW_CACHE_FORMULA}/#{ref}.rb")
 | |
|     if possible_cached_formula.file?
 | |
|       return FormulaLoader.new(ref, possible_cached_formula)
 | |
|     end
 | |
| 
 | |
|     return NullLoader.new(ref)
 | |
|   end
 | |
| end
 | 
