brew/Library/Homebrew/formulary.rb

243 lines
5.8 KiB
Ruby
Raw Normal View History

# The Formulary is responsible for creating instances of Formula.
2014-05-02 07:39:23 -07:00
# It is not meant to be used directy from formulae.
class Formulary
2015-01-01 01:21:59 -05:00
module Formulae
class << self
if instance_method(:const_defined?).arity == -1
def formula_const_defined?(name)
const_defined?(name, false)
end
2015-01-01 01:21:59 -05:00
def formula_const_get(name)
const_get(name, false)
end
else
def formula_const_defined?(name)
const_defined?(name)
end
2013-06-23 14:07:46 -07:00
2015-01-01 01:21:59 -05:00
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
2013-06-18 10:11:06 -07:00
end
2015-01-01 01:21:59 -05:00
def self.unload_formula formula_name
Formulae.remove_formula_const(class_s(formula_name))
2013-06-18 10:11:06 -07:00
end
def self.restore_formula formula_name, value
old_verbose, $VERBOSE = $VERBOSE, nil
2015-01-01 01:21:59 -05:00
Formulae.formula_const_set(class_s(formula_name), value)
ensure
$VERBOSE = old_verbose
end
2014-02-21 00:43:58 -05:00
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
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
# 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
2013-06-18 10:11:06 -07:00
# Gets the formula instance.
def get_formula(spec)
klass.new(name, path, spec)
end
2013-06-18 10:11:06 -07:00
def klass
begin
2015-01-01 01:21:59 -05:00
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
2014-12-29 14:53:22 -05:00
load_file unless have_klass
2015-01-01 01:21:59 -05:00
Formulae.formula_const_get(class_name)
2013-06-18 10:11:06 -07:00
end
2014-12-29 14:53:22 -05:00
private
def load_file
STDERR.puts "#{$0} (#{self.class.name}): loading #{path}" if ARGV.debug?
raise FormulaUnavailableError.new(name) unless path.file?
2015-01-01 01:21:59 -05:00
Formulae.module_eval(path.read, path)
2014-12-29 14:53:22 -05:00
end
2013-06-18 10:11:06 -07:00
end
2013-06-18 10:11:06 -07:00
# 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, Formulary.path(name)
2013-06-18 10:11:06 -07:00
end
def get_formula(spec)
formula = super
formula.local_bottle_path = @bottle_filename
formula
2013-06-18 10:11:06 -07:00
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
2013-06-18 10:11:06 -07:00
# 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
2013-06-18 10:11:06 -07:00
end
end
# Loads formulae from URLs
2013-06-18 10:11:06 -07:00
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)
2013-06-18 10:11:06 -07:00
end
def load_file
HOMEBREW_CACHE_FORMULA.mkpath
FileUtils.rm_f(path)
curl url, "-o", path
super
end
2013-06-18 10:11:06 -07:00
end
2013-06-18 10:11:06 -07:00
# Loads tapped formulae.
class TapLoader < FormulaLoader
2014-04-05 22:03:33 -05:00
attr_reader :tapped_name
2013-06-18 10:11:06 -07:00
def initialize tapped_name
2014-04-05 22:03:33 -05:00
@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?
2014-04-25 18:58:16 -05:00
tap.find_formula do |file|
if file.basename(".rb").to_s == name
path = file
end
end
end
2014-04-05 22:03:33 -05:00
super name, path
end
def get_formula(spec)
super
rescue FormulaUnavailableError => e
raise TapFormulaUnavailableError, tapped_name, e.backtrace
2013-06-18 10:11:06 -07:00
end
end
class NullLoader < FormulaLoader
def initialize(name)
super name, Formula.path(name)
end
def get_formula(spec)
raise FormulaUnavailableError.new(name)
end
end
2013-06-18 10:11:06 -07:00
# 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
2014-04-05 22:03:34 -05:00
def self.canonical_name(ref)
loader_for(ref).name
end
def self.path(ref)
loader_for(ref).path
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)
2014-04-05 22:03:33 -05:00
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?
2015-01-01 01:21:59 -05:00
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?
2015-01-01 01:21:59 -05:00
return FormulaLoader.new(ref, possible_cached_formula)
end
return NullLoader.new(ref)
end
end