aboutsummaryrefslogtreecommitdiffstats
path: root/Library
diff options
context:
space:
mode:
authorAdam Vandenberg2013-06-18 10:11:06 -0700
committerAdam Vandenberg2013-06-29 16:44:45 -0700
commitc2a5e3608ca435a969f62b2fa28722c3a1a106f0 (patch)
tree06e184d54685c5825e7d2229a84e5494f1a71522 /Library
parent099a62c95bb957ec676157533f06d621e75e5e85 (diff)
downloadbrew-c2a5e3608ca435a969f62b2fa28722c3a1a106f0.tar.bz2
Use Formula Loaders
Diffstat (limited to 'Library')
-rw-r--r--Library/Homebrew/formulary.rb230
1 files changed, 151 insertions, 79 deletions
diff --git a/Library/Homebrew/formulary.rb b/Library/Homebrew/formulary.rb
index 6cdbe9588..eb86a1fb8 100644
--- a/Library/Homebrew/formulary.rb
+++ b/Library/Homebrew/formulary.rb
@@ -1,106 +1,178 @@
+# The Formulary is responsible for creating instances
+# of Formula.
class Formulary
- # Return a Formula instance for the given `name`.
- # `name` may be:
- # * a Formula instance, in which case it is returned
- # TODO: is this code path used?
- # * a Pathname to a local formula
- # * a string containing a formula pathname
- # * a string containing a formula URL
- # * a string containing a formula name
- # * a string containing a local bottle reference
- def self.factory name
- # If an instance of Formula is passed, just return it
- return name if name.kind_of? Formula
- # Otherwise, convert to String in case a Pathname comes in
- name = name.to_s
+ def self.formula_class_defined? formula_name
+ Object.const_defined?(Formula.class_s(formula_name))
+ end
- # If a URL is passed, download to the cache and install
- if name =~ %r[(https?|ftp)://]
- url = name
- name = Pathname.new(name).basename
- path = HOMEBREW_CACHE_FORMULA+name
- name = name.basename(".rb").to_s
+ def self.get_formula_class formula_name
+ Object.const_get(Formula.class_s(formula_name))
+ end
- unless Object.const_defined? Formula.class_s(name)
- HOMEBREW_CACHE_FORMULA.mkpath
- FileUtils.rm path, :force => true
- curl url, '-o', path
+ # 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
+
+ # Gets the formula instance.
+ # Subclasses must define this.
+ def get_formula; end
+
+ # Return the Class for this formula, `require`-ing it if
+ # it has not been parsed before.
+ def klass
+ unless Formulary.formula_class_defined? name
+ puts "#{$0}: loading #{path}" if ARGV.debug?
+ begin
+ require path.to_s
+ rescue NoMethodError
+ # This is a programming error in an existing formula, and should not
+ # have a "no such formula" message.
+ raise
+ rescue LoadError, NameError
+ # TODO - show exception details
+ raise FormulaUnavailableError.new(name)
+ end
end
+ klass = Formulary.get_formula_class(name)
+ if (klass == Formula) || !klass.ancestors.include?(Formula)
+ raise FormulaUnavailableError.new(name)
+ end
+ klass
+ end
+ end
- install_type = :from_url
- elsif name.match bottle_regex
- bottle_filename = Pathname(name).realpath
- version = Version.parse(bottle_filename).to_s
- bottle_basename = bottle_filename.basename.to_s
+ # Loads formulae from bottles.
+ class BottleLoader < FormulaLoader
+ def initialize bottle_name
+ @bottle_filename = Pathname(bottle_name).realpath
+ version = Version.parse(@bottle_filename).to_s
+ bottle_basename = @bottle_filename.basename.to_s
name_without_version = bottle_basename.rpartition("-#{version}").first
if name_without_version.empty?
if ARGV.homebrew_developer?
opoo "Add a new version regex to version.rb to parse this filename."
end
+ @name = name
else
- name = name_without_version
+ @name = name_without_version
end
- path = Formula.path(name)
- install_type = :from_local_bottle
- else
- name = Formula.canonical_name(name)
+ @path = Formula.path(@name)
+ end
- if name =~ %r{^(\w+)/(\w+)/([^/])+$}
- # name appears to be a tapped formula, so we don't munge it
- # in order to provide a useful error message when require fails.
- path = Pathname.new(name)
- elsif name.include? "/"
- # If name was a path or mapped to a cached formula
+ def get_formula
+ formula = klass.new(name)
+ formula.downloader.local_bottle_path = @bottle_filename
+ return formula
+ end
+ end
- # require allows filenames to drop the .rb extension, but everything else
- # in our codebase will require an exact and fullpath.
- name = "#{name}.rb" unless name =~ /\.rb$/
+ # Loads formulae from Homebrew's provided Library
+ class StandardLoader < FormulaLoader
+ def initialize name
+ @name = name
+ @path = Formula.path(name)
+ end
- path = Pathname.new(name)
- name = path.stem
- install_type = :from_path
- else
- # For names, map to the path and then require
- path = Formula.path(name)
- install_type = :from_name
+ def get_formula
+ return klass.new(name)
+ end
+ end
+
+ # Loads formulae from disk using a path
+ class FromPathLoader < FormulaLoader
+ def initialize path
+ # require allows filenames to drop the .rb extension, but everything else
+ # in our codebase will require an exact and fullpath.
+ path = "#{name}.rb" unless path =~ /\.rb$/
+
+ @path = Pathname.new(path)
+ @name = @path.stem
+ end
+
+ def get_formula
+ klass.new(name, path.to_s)
+ end
+ end
+
+ # Loads formulae from URLs.
+ class FromUrlLoader < FormulaLoader
+ attr_reader :url
+
+ def initialize url
+ @url = url
+ @path = (HOMEBREW_CACHE_FORMULA/(File.basename(url)))
+ @name = File.basename(url, '.rb')
+ end
+
+ # Downloads the formula's .rb file
+ def fetch
+ unless Formulary.formula_class_defined? name
+ HOMEBREW_CACHE_FORMULA.mkpath
+ FileUtils.rm path.to_s, :force => true
+ curl url, '-o', path.to_s
end
end
- klass_name = Formula.class_s(name)
- unless Object.const_defined? klass_name
- puts "#{$0}: loading #{path}" if ARGV.debug?
- require path
+ def get_formula
+ return klass.new(name, path.to_s)
end
+ end
- begin
- klass = Object.const_get klass_name
- rescue NameError
- # TODO really this text should be encoded into the exception
- # and only shown if the UI deems it correct to show it
- onoe "class \"#{klass_name}\" expected but not found in #{name}.rb"
- puts "Double-check the name of the class in that formula."
- raise LoadError
+ # Loads tapped formulae.
+ class TapLoader < FormulaLoader
+ def initialize tapped_name
+ @name = tapped_name
+ @path = Pathname.new(tapped_name)
end
- if install_type == :from_local_bottle
- formula = klass.new(name)
- formula.downloader.local_bottle_path = bottle_filename
- return formula
+ def get_formula
+ klass.new(tapped_name, path.to_s)
+ end
+ end
+
+ # Return a Formula instance for the given reference.
+ # `ref` may be:
+ # * a Formula instance, in which case it is returned
+ # TODO: is this code path used?
+ # * a Pathname to a local formula
+ # * a string containing a formula pathname
+ # * a string containing a formula URL
+ # * a string containing a formula name
+ # * a string containing a local bottle reference
+ def self.factory ref
+ # If an instance of Formula is passed, just return it
+ return ref if ref.kind_of? Formula
+
+ # Otherwise, convert to String in case a Pathname comes in
+ # TODO - do we call with a Pathname instead of a string anywhere?
+ ref = ref.to_s
+
+ # If a URL is passed, download to the cache and install
+ if ref =~ %r[(https?|ftp)://]
+ f = FromUrlLoader.new(ref)
+ f.fetch
+ elsif ref =~ Pathname::BOTTLE_EXTNAME_RX
+ f = BottleLoader.new(ref)
+ else
+ name_or_path = Formula.canonical_name(ref)
+ if name_or_path =~ %r{^(\w+)/(\w+)/([^/])+$}
+ # name appears to be a tapped formula, so we don't munge it
+ # in order to provide a useful error message when require fails.
+ f = TapLoader.new(name_or_path)
+ elsif name_or_path.include? "/"
+ # If name was a path or mapped to a cached formula
+ f = FromPathLoader.new(name_or_path)
+ else
+ # For names, map to the path and then require
+ f = StandardLoader.new(name_or_path)
+ end
end
- raise NameError if !klass.ancestors.include? Formula
- raise NameError if klass == Formula
-
- return klass.new(name) if install_type == :from_name
- return klass.new(name, path.to_s)
- rescue NoMethodError
- # This is a programming error in an existing formula, and should not
- # have a "no such formula" message.
- raise
- rescue LoadError, NameError
- # Catch NameError so that things that are invalid symbols still get
- # a useful error message.
- raise FormulaUnavailableError.new(name)
+ f.get_formula
end
end