diff --git a/Library/Homebrew/exceptions.rb b/Library/Homebrew/exceptions.rb index 5865eb98e51ea3369b346c81ccff655d620a626c..986fdeaa9c979548ce26d24431ed3ed1a2ccfedc 100644 --- a/Library/Homebrew/exceptions.rb +++ b/Library/Homebrew/exceptions.rb @@ -260,3 +260,24 @@ class ChecksumMismatchError < RuntimeError super + advice.to_s end end + +class ResourceMissingError < ArgumentError + def initialize formula, resource + @formula = formula + @resource = resource + end + + def to_s + "Formula #{@formula} does not define resource \"#{@resource}\"." + end +end + +class DuplicateResourceError < ArgumentError + def initialize resource + @resource = resource + end + + def to_s + "Resource \"#{@resource}\" defined more than once." + end +end diff --git a/Library/Homebrew/extend/pathname.rb b/Library/Homebrew/extend/pathname.rb index 60e55278c55e4dec201b8937d3cf775782abb0bb..cdc5907c508b733c52ed4013754c167cc383693e 100644 --- a/Library/Homebrew/extend/pathname.rb +++ b/Library/Homebrew/extend/pathname.rb @@ -10,6 +10,8 @@ class Pathname def install *sources sources.each do |src| case src + when Resource + src.stage(self) when Array if src.empty? opoo "tried to install empty array to #{self}" diff --git a/Library/Homebrew/formula.rb b/Library/Homebrew/formula.rb index 15561b1001b234f053c4d6f5b1f5095fcbc92b9a..0ccf9292c10fd69d8b6ba81b2aed7a791e051573 100644 --- a/Library/Homebrew/formula.rb +++ b/Library/Homebrew/formula.rb @@ -1,3 +1,4 @@ +require 'resource' require 'download_strategy' require 'dependency_collector' require 'formula_support' @@ -56,6 +57,11 @@ class Formula end @pin = FormulaPin.new(self) + + @resources = self.class.resources + @resources.each_value do |r| + r.set_owner name + end end def set_spec(name) @@ -91,6 +97,16 @@ class Formula def version; active_spec.version; end def mirrors; active_spec.mirrors; end + def resource(name) + res = @resources[name] + raise ResourceMissingError.new(@name, name) if res.nil? + res + end + + def resources + @resources.values + end + # if the dir is there, but it's empty we consider it not installed def installed? (dir = installed_prefix).directory? && dir.children.length > 0 @@ -694,6 +710,19 @@ class Formula @stable.mirror(val) end + # Hold any resources defined by this formula + def resources + @resources ||= Hash.new + end + + # Define a named resource using a SoftwareSpec style block + def resource res_name, &block + raise DuplicateResourceError.new(res_name) if resources.has_key?(res_name) + spec = SoftwareSpec.new + spec.instance_eval(&block) + resources[res_name] = Resource.new(res_name, spec) + end + def dependencies @dependencies ||= DependencyCollector.new end diff --git a/Library/Homebrew/resource.rb b/Library/Homebrew/resource.rb new file mode 100644 index 0000000000000000000000000000000000000000..1136af1c017623dfc3c563c3dbba0c51e5692542 --- /dev/null +++ b/Library/Homebrew/resource.rb @@ -0,0 +1,57 @@ +# A Resource describes a tarball that a formula needs in addition +# to the formula's own download. +class Resource + include FileUtils + + # The mktmp mixin expects a name property + # This is the resource name + attr_reader :name + + # This is the associated formula name + attr_reader :owner_name + + def initialize name, spec + @name = name + @spec = spec + end + + # Formula name must be set after the DSL, as we have no access to the + # formula name before initialization of the formula + def set_owner owner + @owner = owner + @downloader = @spec.download_strategy.new("#{owner}--#{name}", @spec) + end + + # Download the resource + # If a target is given, unpack there; else unpack to a temp folder + # If block is given, yield to that block + # A target or a block must be given, but not both + def stage(target=nil) + fetched = fetch + verify_download_integrity(fetched) if fetched.file? + mktemp do + @downloader.stage + if block_given? + yield self + else + target.install Dir['*'] + end + end + end + + def cached_download + @downloader.cached_location + end + + # For brew-fetch and others. + def fetch + # Ensure the cache exists + HOMEBREW_CACHE.mkpath + @downloader.fetch + cached_download + end + + def verify_download_integrity fn + @spec.verify_download_integrity(fn) + end +end