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