aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Library/Homebrew/bottles.rb8
-rw-r--r--Library/Homebrew/compat/compatibility.rb4
-rw-r--r--Library/Homebrew/formula.rb268
-rw-r--r--Library/Homebrew/formula_installer.rb6
-rw-r--r--Library/Homebrew/formula_specialties.rb4
-rw-r--r--Library/Homebrew/formula_support.rb128
-rw-r--r--Library/Homebrew/test/test_formula.rb234
-rw-r--r--Library/Homebrew/test/testball.rb130
-rw-r--r--Library/Homebrew/test/testing_env.rb5
9 files changed, 626 insertions, 161 deletions
diff --git a/Library/Homebrew/bottles.rb b/Library/Homebrew/bottles.rb
index d7ed83d23..0164b07dd 100644
--- a/Library/Homebrew/bottles.rb
+++ b/Library/Homebrew/bottles.rb
@@ -3,8 +3,8 @@ require 'extend/ARGV'
def bottle_filename f, bottle_version=nil
name = f.name.downcase
- version = f.version || f.standard.detect_version
- bottle_version = bottle_version || f.bottle_version
+ version = f.stable.version
+ bottle_version ||= f.bottle.revision.to_i
"#{name}-#{version}#{bottle_native_suffix(bottle_version)}"
end
@@ -22,7 +22,7 @@ def built_bottle? f
end
def bottle_current? f
- f.bottle_url && f.bottle_sha1 && Pathname.new(f.bottle_url).version == f.version
+ f.bottle.url && f.bottle.has_checksum? && f.bottle.version == f.stable.version
end
def bottle_file_outdated? f, file
@@ -39,7 +39,7 @@ end
def bottle_new_version f
return 0 unless bottle_current? f
- f.bottle_version + 1
+ f.bottle.revision + 1
end
def bottle_native_suffix version=nil
diff --git a/Library/Homebrew/compat/compatibility.rb b/Library/Homebrew/compat/compatibility.rb
index 45222cf82..3f0f23766 100644
--- a/Library/Homebrew/compat/compatibility.rb
+++ b/Library/Homebrew/compat/compatibility.rb
@@ -91,6 +91,10 @@ class Formula
def std_cmake_parameters
"-DCMAKE_INSTALL_PREFIX='#{prefix}' -DCMAKE_BUILD_TYPE=None -DCMAKE_FIND_FRAMEWORK=LAST -Wno-dev"
end
+
+ class << self
+ attr_rw :bottle_sha1
+ end
end
class UnidentifiedFormula < Formula
diff --git a/Library/Homebrew/formula.rb b/Library/Homebrew/formula.rb
index 541ee65d8..92509f13f 100644
--- a/Library/Homebrew/formula.rb
+++ b/Library/Homebrew/formula.rb
@@ -7,13 +7,12 @@ require 'extend/fileutils'
require 'patches'
require 'compilers'
-# Derive and define at least @url, see Library/Formula for examples
+
class Formula
include FileUtils
- attr_reader :name, :path, :url, :version, :homepage, :specs, :downloader
- attr_reader :standard, :unstable, :head
- attr_reader :bottle_version, :bottle_url, :bottle_sha1
+ attr_reader :name, :path, :homepage, :downloader
+ attr_reader :stable, :bottle, :devel, :head, :active_spec
# The build folder, usually in /tmp.
# Will only be non-nil during the stage method.
@@ -21,50 +20,76 @@ class Formula
# Homebrew determines the name
def initialize name='__UNKNOWN__', path=nil
- set_instance_variable 'homepage'
- set_instance_variable 'url'
- set_instance_variable 'bottle_version'
- set_instance_variable 'bottle_url'
- set_instance_variable 'bottle_sha1'
- set_instance_variable 'head'
- set_instance_variable 'specs'
- set_instance_variable 'standard'
- set_instance_variable 'unstable'
-
- if @head and (not @url or ARGV.build_head?)
- @url = @head
- @version = 'HEAD'
- @spec_to_use = @unstable
- else
- if @standard.nil?
- @spec_to_use = SoftwareSpecification.new(@url, @specs)
- else
- @spec_to_use = @standard
- end
- end
+ set_instance_variable :homepage
+ set_instance_variable :stable
+ set_instance_variable :bottle
+ set_instance_variable :devel
+ set_instance_variable :head
- raise "No url provided for formula #{name}" if @url.nil?
@name = name
validate_variable :name
- # If we got an explicit path, use that, else determine from the name
- @path = path.nil? ? self.class.path(name) : Pathname.new(path)
+ # Legacy formulae can set specs via class ivars
+ ensure_specs_set if @stable.nil?
+
+ # If a checksum or version was set in the DSL, but no stable URL
+ # was defined, make @stable nil and save callers some trouble
+ @stable = nil if @stable and @stable.url.nil?
- # Use a provided version, if any
- set_instance_variable 'version'
- # Otherwise detect the version from the URL
- @version ||= @spec_to_use.detect_version
- # Only validate if a version was set; GitHubGistFormula needs to get
- # the URL to determine the version
+ # Ensure the bottle URL is set. If it does not have a checksum,
+ # then a bottle is not available for the current platform.
+ if @bottle and @bottle.has_checksum?
+ @bottle.url ||= bottle_base_url + bottle_filename(self)
+ else
+ @bottle = nil
+ end
+
+ @active_spec = if @head and ARGV.build_head? then @head # --HEAD
+ elsif @devel and ARGV.build_devel? then @devel # --devel
+ elsif @bottle and install_bottle?(self) then @bottle # bottle available
+ elsif @stable.nil? and @head then @head # head-only
+ else @stable # default
+ end
+
+ @version = @active_spec.version
validate_variable :version if @version
- CHECKSUM_TYPES.each { |type| set_instance_variable type }
+ raise "No url provided for formula #{name}" if @active_spec.url.nil?
- @downloader = download_strategy.new @spec_to_use.url, name, version, @spec_to_use.specs
+ # If we got an explicit path, use that, else determine from the name
+ @path = path.nil? ? self.class.path(name) : Pathname.new(path)
+ @downloader = download_strategy.new(@active_spec.url, name, @active_spec.version, @active_spec.specs)
+ end
+
+ # Derive specs from class ivars
+ def ensure_specs_set
+ set_instance_variable :url
+ set_instance_variable :version
+ set_instance_variable :md5
+ set_instance_variable :sha1
+ set_instance_variable :sha256
+
+ unless @url.nil?
+ @stable = SoftwareSpec.new
+ @stable.url(@url)
+ @stable.version(@version)
+ @stable.md5(@md5)
+ @stable.sha1(@sha1)
+ @stable.sha256(@sha256)
+ end
- @bottle_url ||= bottle_base_url + bottle_filename(self) if @bottle_sha1
+ if @head.kind_of? String
+ url = @head
+ @head = HeadSoftwareSpec.new
+ @head.url(url, self.class.instance_variable_get("@specs"))
+ end
end
+ def url; @active_spec.url; end
+ def version; @active_spec.version; end
+ def specs; @active_spec.specs; end
+ def mirrors; @active_spec.mirrors or []; end
+
# if the dir is there, but it's empty we consider it not installed
def installed?
return installed_prefix.children.length > 0
@@ -84,9 +109,18 @@ class Formula
end
def installed_prefix
- head_prefix = HOMEBREW_CELLAR+@name+'HEAD'
- if @version == 'HEAD' || head_prefix.directory?
+ devel_prefix = unless @devel.nil?
+ HOMEBREW_CELLAR/@name/@devel.version
+ end
+
+ head_prefix = unless @head.nil?
+ HOMEBREW_CELLAR/@name/@head.version
+ end
+
+ if @active_spec == @head || @head and head_prefix.directory?
head_prefix
+ elsif @active_spec == @devel || @devel and devel_prefix.directory?
+ devel_prefix
else
prefix
end
@@ -126,10 +160,10 @@ class Formula
def plist_name; 'homebrew.mxcl.'+name end
def plist_path; prefix+(plist_name+'.plist') end
- # Use the @spec_to_use to detect the download strategy.
+ # Use the @active_spec to detect the download strategy.
# Can be overriden to force a custom download strategy
def download_strategy
- @spec_to_use.download_strategy
+ @active_spec.download_strategy
end
def cached_download
@@ -388,8 +422,6 @@ class Formula
HOMEBREW_REPOSITORY+"Library/Formula/#{name.downcase}.rb"
end
- def mirrors; self.class.mirrors or []; end
-
def deps; self.class.dependencies.deps; end
def external_deps; self.class.dependencies.external_deps; end
@@ -456,19 +488,17 @@ public
# For brew-fetch and others.
def fetch
- if install_bottle? self
- downloader = CurlBottleDownloadStrategy.new bottle_url, name, version, nil
- mirror_list = []
- else
- downloader = @downloader
- # Don't attempt mirrors if this install is not pointed at a "stable" URL.
- # This can happen when options like `--HEAD` are invoked.
- mirror_list = @spec_to_use == @standard ? mirrors : []
+ downloader = @downloader
+ mirror_list = case @active_spec
+ when @stable, @devel then @active_spec.mirrors
+ else []
end
# Ensure the cache exists
HOMEBREW_CACHE.mkpath
+ # TODO teach download strategies to take a SoftwareSpec
+ # object, and move mirror handling into CurlDownloadStrategy
begin
fetched = downloader.fetch
rescue CurlDownloadStrategyError => e
@@ -482,34 +512,27 @@ public
return fetched, downloader
end
- # Detect which type of checksum is being used, or nil if none
- def checksum_type
- CHECKSUM_TYPES.detect { |type| instance_variable_defined?("@#{type}") }
- end
-
# For FormulaInstaller.
- def verify_download_integrity fn, *args
- require 'digest'
- if args.length != 2
- type = checksum_type || :md5
- supplied = instance_variable_get("@#{type}")
- # Convert symbol to readable string
- type = type.to_s.upcase
- else
- supplied, type = args
- end
+ def verify_download_integrity fn
+ # Checksums don't apply to HEAD
+ return if @active_spec == @head
+
+ type = @active_spec.checksum_type || :md5
+ supplied = @active_spec.send(type)
+ type = type.to_s.upcase
+ require 'digest'
hasher = Digest.const_get(type)
hash = fn.incremental_hash(hasher)
if supplied and not supplied.empty?
- message = <<-EOF
-#{type} mismatch
-Expected: #{supplied}
-Got: #{hash}
-Archive: #{fn}
-(To retry an incomplete download, remove the file above.)
-EOF
+ message = <<-EOS.undent
+ #{type} mismatch
+ Expected: #{supplied}
+ Got: #{hash}
+ Archive: #{fn}
+ (To retry an incomplete download, remove the file above.)
+ EOS
raise message unless supplied.upcase == hash.upcase
else
opoo "Cannot verify package integrity"
@@ -520,8 +543,6 @@ EOF
private
- CHECKSUM_TYPES=[:md5, :sha1, :sha256].freeze
-
def stage
fetched, downloader = fetch
verify_download_integrity fetched if fetched.kind_of? Pathname
@@ -571,7 +592,6 @@ private
class << self
# The methods below define the formula DSL.
- attr_reader :standard, :unstable
def self.attr_rw(*attrs)
attrs.each do |attr|
@@ -583,79 +603,61 @@ private
end
end
- attr_rw :version, :homepage, :mirrors, :specs
- attr_rw :keg_only_reason, :skip_clean_all, :cc_failures
- attr_rw :bottle_version, :bottle_url, :bottle_sha1
- attr_rw(*CHECKSUM_TYPES)
+ attr_rw :homepage, :keg_only_reason, :skip_clean_all, :cc_failures
- def head val=nil, specs=nil
- return @head if val.nil?
- @unstable = SoftwareSpecification.new(val, specs)
- @head = val
- @specs = specs
+ SoftwareSpec::CHECKSUM_TYPES.each do |cksum|
+ class_eval %Q{
+ def #{cksum}(val=nil)
+ unless val.nil?
+ @stable ||= SoftwareSpec.new
+ @stable.#{cksum}(val)
+ end
+ return @stable ? @stable.#{cksum} : @#{cksum}
+ end
+ }
end
def url val=nil, specs=nil
- return @url if val.nil?
- @standard = SoftwareSpecification.new(val, specs)
- @url = val
- @specs = specs
+ if val.nil?
+ return @stable.url if @stable
+ return @url if @url
+ end
+ @stable ||= SoftwareSpec.new
+ @stable.url(val, specs)
end
def stable &block
- raise "url and md5 must be specified in a block" unless block_given?
- instance_eval(&block) unless ARGV.build_devel? or ARGV.build_head?
- end
-
- def devel &block
- raise "url and md5 must be specified in a block" unless block_given?
- if ARGV.build_devel?
- @mirrors = nil # clear out mirrors from the stable release
- instance_eval(&block)
- end
+ return @stable unless block_given?
+ instance_eval(&block)
end
def bottle url=nil, &block
- return unless block_given?
-
- bottle_block = Class.new do
- def self.version version
- @version = version
- end
-
- def self.url url
- @url = url
- end
+ return @bottle unless block_given?
+ @bottle ||= Bottle.new
+ @bottle.instance_eval(&block)
+ end
- def self.sha1 sha1
- case sha1
- when Hash
- key, value = sha1.shift
- @sha1 = key if value == MacOS.cat
- when String
- @sha1 = sha1 if MacOS.lion?
- end
- end
+ def devel &block
+ return @devel unless block_given?
+ @devel ||= SoftwareSpec.new
+ @devel.instance_eval(&block)
+ end
- def self.data
- @version = 0 unless @version
- return @version, @url, @sha1 if @sha1 && @url
- return @version, nil, @sha1 if @sha1
- end
- end
+ def head val=nil, specs=nil
+ return @head if val.nil?
+ @head ||= HeadSoftwareSpec.new
+ @head.url(val, specs)
+ end
- bottle_block.instance_eval(&block)
- @bottle_version, @bottle_url, @bottle_sha1 = bottle_block.data
+ def version val=nil
+ return @version if val.nil?
+ @stable ||= SoftwareSpec.new
+ @stable.version(val)
end
def mirror val, specs=nil
- @mirrors ||= []
- @mirrors << {:url => val, :specs => specs}
- # Added the uniq after some inspection with Pry---seems `mirror` gets
- # called three times. The first two times only one copy of the input is
- # left in `@mirrors`. On the final call, two copies are present. This
- # happens with `@deps` as well. Odd.
- @mirrors.uniq!
+ @stable ||= SoftwareSpec.new
+ @stable.mirror(val, specs)
end
def dependencies
diff --git a/Library/Homebrew/formula_installer.rb b/Library/Homebrew/formula_installer.rb
index 9d4b3b492..a7fd0d07f 100644
--- a/Library/Homebrew/formula_installer.rb
+++ b/Library/Homebrew/formula_installer.rb
@@ -29,7 +29,7 @@ class FormulaInstaller
end
# Building head-only without --HEAD is an error
- if not ARGV.build_head? and f.standard.nil?
+ if not ARGV.build_head? and f.stable.nil?
raise CannotInstallFormulaError, <<-EOS.undent
#{f} is a head-only formula
Install with `brew install --HEAD #{f.name}
@@ -37,7 +37,7 @@ class FormulaInstaller
end
# Building stable-only with --HEAD is an error
- if ARGV.build_head? and f.unstable.nil?
+ if ARGV.build_head? and f.head.nil?
raise CannotInstallFormulaError, "No head is defined for #{f.name}"
end
@@ -261,7 +261,7 @@ class FormulaInstaller
def pour
fetched, downloader = f.fetch
- f.verify_download_integrity fetched, f.bottle_sha1, "SHA1"
+ f.verify_download_integrity fetched
HOMEBREW_CELLAR.cd do
downloader.stage
end
diff --git a/Library/Homebrew/formula_specialties.rb b/Library/Homebrew/formula_specialties.rb
index 6cae0887f..4e63440a6 100644
--- a/Library/Homebrew/formula_specialties.rb
+++ b/Library/Homebrew/formula_specialties.rb
@@ -11,7 +11,9 @@ end
class GithubGistFormula < ScriptFileFormula
def initialize name='__UNKNOWN__', path=nil
super name, path
- @version=File.basename(File.dirname(url))[0,6]
+ @stable.version(File.basename(File.dirname(url))[0,6])
+ @version = @active_spec.version
+ validate_variable :version
end
end
diff --git a/Library/Homebrew/formula_support.rb b/Library/Homebrew/formula_support.rb
index 06b25729b..9bd7b6d6b 100644
--- a/Library/Homebrew/formula_support.rb
+++ b/Library/Homebrew/formula_support.rb
@@ -1,9 +1,9 @@
require 'download_strategy'
+class SoftwareSpec
+ attr_reader :checksum, :mirrors, :specs, :strategy
-# Defines a URL and download method for a stable or HEAD build
-class SoftwareSpecification
- attr_reader :url, :specs, :using
+ CHECKSUM_TYPES = [:md5, :sha1, :sha256].freeze
VCS_SYMBOLS = {
:bzr => BazaarDownloadStrategy,
@@ -16,34 +16,122 @@ class SoftwareSpecification
:svn => SubversionDownloadStrategy,
}
- def initialize url, specs=nil
- raise "No url provided" if url.nil?
- @url = url
- if specs.nil?
- @using = nil
- else
- # Get download strategy hint, if any
- @using = specs.delete :using
- # The rest of the specs are for source control
- @specs = specs
+ # Detect which type of checksum is being used, or nil if none
+ def checksum_type
+ @checksum_type ||= CHECKSUM_TYPES.detect do |type|
+ instance_variable_defined?("@#{type}")
end
end
+ def has_checksum?
+ (checksum_type and self.send(checksum_type)) || false
+ end
+
+ # Was the version defined in the DSL, or detected from the URL?
+ def explicit_version?
+ @explicit_version || false
+ end
+
# Returns a suitable DownloadStrategy class that can be
- # used to retreive this software package.
+ # used to retrieve this software package.
def download_strategy
- return detect_download_strategy(@url) if @using.nil?
+ return detect_download_strategy(@url) if @strategy.nil?
# If a class is passed, assume it is a download strategy
- return @using if @using.kind_of? Class
+ return @strategy if @strategy.kind_of? Class
- detected = VCS_SYMBOLS[@using]
- raise "Unknown strategy #{@using} was requested." unless detected
+ detected = VCS_SYMBOLS[@strategy]
+ raise "Unknown strategy #{@strategy} was requested." unless detected
return detected
end
- def detect_version
- Pathname.new(@url).version
+ # The methods that follow are used in the block-form DSL spec methods
+ CHECKSUM_TYPES.each do |cksum|
+ class_eval %Q{
+ def #{cksum}(val=nil)
+ val.nil? ? @#{cksum} : @#{cksum} = val
+ end
+ }
+ end
+
+ def url val=nil, specs=nil
+ return @url if val.nil?
+ @url = val
+ if specs.nil?
+ @strategy = nil
+ else
+ @strategy = specs.delete :using
+ @specs = specs
+ end
+ end
+
+ def version val=nil
+ unless val.nil?
+ @version = val
+ @explicit_version = true
+ end
+ @version ||= Pathname.new(@url).version
+ return @version
+ end
+
+ def mirror val, specs=nil
+ @mirrors ||= []
+ @mirrors << { :url => val, :specs => specs }
+ end
+end
+
+class HeadSoftwareSpec < SoftwareSpec
+ def initialize
+ super
+ @version = 'HEAD'
+ @checksum = nil
+ end
+
+ def verify_download_integrity fn
+ return
+ end
+end
+
+class Bottle < SoftwareSpec
+ attr_writer :url
+ attr_reader :revision
+
+ def initialize
+ @revision = 0
+ @strategy = CurlBottleDownloadStrategy
+ end
+
+ # Checksum methods in the DSL's bottle block optionally take
+ # a Hash, which indicates the platform the checksum applies on.
+ CHECKSUM_TYPES.each do |cksum|
+ class_eval %Q{
+ def #{cksum}(val=nil)
+ @#{cksum} ||= Hash.new
+ case val
+ when nil
+ @#{cksum}[MacOS.cat]
+ when String
+ @#{cksum}[:lion] = val
+ when Hash
+ key, value = val.shift
+ @#{cksum}[value] = key
+ end
+ end
+ }
+ end
+
+ def url val=nil
+ val.nil? ? @url : @url = val
+ end
+
+ # Used in the bottle DSL to set @revision, but acts as an
+ # as accessor for @version to preserve the interface
+ def version val=nil
+ if val.nil?
+ return @version ||= Pathname.new(@url).version
+ else
+ @revision = val
+ end
end
end
diff --git a/Library/Homebrew/test/test_formula.rb b/Library/Homebrew/test/test_formula.rb
index b49b06757..55b48e3b0 100644
--- a/Library/Homebrew/test/test_formula.rb
+++ b/Library/Homebrew/test/test_formula.rb
@@ -66,4 +66,238 @@ class FormulaTests < Test::Unit::TestCase
assert_equal downloader.url, "file:///#{TEST_FOLDER}/tarballs/testball-0.1.tbz"
end
end
+
+ def test_formula_specs
+ f = SpecTestBall.new
+
+ assert_equal 'http://example.com', f.homepage
+ assert_equal 'file:///foo.com/testball-0.1.tbz', f.url
+ assert_equal 1, f.mirrors.length
+ assert_equal '0.1', f.version
+ assert_equal f.stable, f.active_spec
+ assert_equal CurlDownloadStrategy, f.download_strategy
+ assert_instance_of CurlDownloadStrategy, f.downloader
+
+ assert_instance_of SoftwareSpec, f.stable
+ assert_instance_of Bottle, f.bottle
+ assert_instance_of SoftwareSpec, f.devel
+ assert_instance_of HeadSoftwareSpec, f.head
+
+ assert_equal 'file:///foo.com/testball-0.1.tbz', f.stable.url
+ assert_equal "https://downloads.sf.net/project/machomebrew/Bottles/spectestball-0.1.#{MacOS.cat}.bottle.tar.gz",
+ f.bottle.url
+ assert_equal 'file:///foo.com/testball-0.2.tbz', f.devel.url
+ assert_equal 'https://github.com/mxcl/homebrew.git', f.head.url
+
+ assert_nil f.stable.specs
+ assert_nil f.bottle.specs
+ assert_nil f.devel.specs
+ assert_equal({ :tag => 'foo' }, f.head.specs)
+
+ assert_equal CurlDownloadStrategy, f.stable.download_strategy
+ assert_equal CurlBottleDownloadStrategy, f.bottle.download_strategy
+ assert_equal CurlDownloadStrategy, f.devel.download_strategy
+ assert_equal GitDownloadStrategy, f.head.download_strategy
+
+ assert f.stable.has_checksum?
+ assert f.bottle.has_checksum?
+ assert f.devel.has_checksum?
+ assert !f.head.has_checksum?
+ assert_equal :sha1, f.stable.checksum_type
+ assert_equal :sha1, f.bottle.checksum_type
+ assert_equal :sha256, f.devel.checksum_type
+ assert_nil f.head.checksum_type
+ assert_equal case MacOS.cat
+ when :snowleopard then 'deadbeefdeadbeefdeadbeefdeadbeefdeadbeef'
+ when :lion then 'baadf00dbaadf00dbaadf00dbaadf00dbaadf00d'
+ end, f.bottle.sha1
+ assert_match /[0-9a-fA-F]{40}/, f.stable.sha1
+ assert_match /[0-9a-fA-F]{64}/, f.devel.sha256
+
+ assert_nil f.stable.md5
+ assert_nil f.stable.sha256
+ assert_nil f.bottle.md5
+ assert_nil f.bottle.sha256
+ assert_nil f.devel.md5
+ assert_nil f.devel.sha1
+
+ assert_equal 1, f.stable.mirrors.length
+ assert_nil f.bottle.mirrors
+ assert_equal 1, f.devel.mirrors.length
+ assert_nil f.head.mirrors
+
+ assert !f.stable.explicit_version?
+ assert !f.bottle.explicit_version?
+ assert !f.devel.explicit_version?
+ assert_equal '0.1', f.stable.version
+ assert_equal '0.1', f.bottle.version
+ assert_equal '0.2', f.devel.version
+ assert_equal 'HEAD', f.head.version
+ assert_equal 0, f.bottle.revision
+ end
+
+ def test_ancient_formula_specs
+ f = AncientSpecTestBall.new
+
+ assert_equal 'http://example.com', f.homepage
+ assert_equal 'file:///foo.com/testball-0.1.tbz', f.url
+ assert_equal '0.1', f.version
+ assert_equal f.stable, f.active_spec
+ assert_equal CurlDownloadStrategy, f.download_strategy
+ assert_instance_of CurlDownloadStrategy, f.downloader
+
+ assert_instance_of SoftwareSpec, f.stable
+ assert_instance_of HeadSoftwareSpec, f.head
+
+ assert_equal 'file:///foo.com/testball-0.1.tbz', f.stable.url
+ assert_equal 'https://github.com/mxcl/homebrew.git', f.head.url
+
+ assert_nil f.stable.specs
+ assert_equal({ :tag => 'foo' }, f.head.specs)
+
+ assert f.stable.has_checksum?
+ assert !f.head.has_checksum?
+ assert_equal :md5, f.stable.checksum_type
+ assert_nil f.head.checksum_type
+ assert_match /[0-9a-fA-F]{32}/, f.stable.md5
+
+ assert !f.stable.explicit_version?
+ assert_equal '0.1', f.stable.version
+ assert_equal 'HEAD', f.head.version
+ end
+
+ def test_devel_active_spec
+ ARGV.push '--devel'
+ f = SpecTestBall.new
+ assert_equal f.devel, f.active_spec
+ assert_equal '0.2', f.version
+ assert_equal 'file:///foo.com/testball-0.2.tbz', f.url
+ assert_equal CurlDownloadStrategy, f.download_strategy
+ assert_instance_of CurlDownloadStrategy, f.downloader
+ ARGV.delete '--devel'
+ end
+
+ def test_head_active_spec
+ ARGV.push '--HEAD'
+ f = SpecTestBall.new
+ assert_equal f.head, f.active_spec
+ assert_equal 'HEAD', f.version
+ assert_equal 'https://github.com/mxcl/homebrew.git', f.url
+ assert_equal GitDownloadStrategy, f.download_strategy
+ assert_instance_of GitDownloadStrategy, f.downloader
+ ARGV.delete '--HEAD'
+ end
+
+ def test_explicit_version_spec
+ f = ExplicitVersionSpecTestBall.new
+ assert_equal '0.3', f.version
+ assert_equal '0.3', f.stable.version
+ assert_equal '0.4', f.devel.version
+ assert f.stable.explicit_version?
+ assert f.devel.explicit_version?
+ end
+
+ def test_old_bottle_specs
+ f = OldBottleSpecTestBall.new
+
+ case MacOS.cat
+ when :lion
+ assert_instance_of Bottle, f.bottle
+ assert_equal CurlBottleDownloadStrategy, f.bottle.download_strategy
+ assert_nil f.bottle.specs
+ assert_nil f.bottle.mirrors
+
+ assert_equal 'file:///foo.com/testball-0.1-bottle.tar.gz', f.bottle.url
+
+ assert f.bottle.has_checksum?
+ assert_equal :sha1, f.bottle.checksum_type
+ assert_equal 'baadf00dbaadf00dbaadf00dbaadf00dbaadf00d', f.bottle.sha1
+ assert_nil f.bottle.md5
+ assert_nil f.bottle.sha256
+
+ assert !f.bottle.explicit_version?
+ assert_equal 0, f.bottle.revision
+ assert_equal '0.1', f.bottle.version
+ else
+ assert_nil f.bottle
+ end
+ end
+
+ def test_ancient_bottle_specs
+ f = AncientBottleSpecTestBall.new
+ assert_nil f.bottle
+ end
+
+ def test_head_only_specs
+ f = HeadOnlySpecTestBall.new
+
+ assert_not_nil f.head
+ assert_nil f.stable
+ assert_nil f.bottle
+ assert_nil f.devel
+
+ assert_equal f.head, f.active_spec
+ assert_equal 'HEAD', f.version
+ assert !f.head.has_checksum?
+ assert_equal 'https://github.com/mxcl/homebrew.git', f.url
+ assert_equal GitDownloadStrategy, f.download_strategy
+ assert_instance_of GitDownloadStrategy, f.downloader
+ assert_instance_of HeadSoftwareSpec, f.head
+ end
+
+ def test_incomplete_stable_specs
+ f = IncompleteStableSpecTestBall.new
+
+ assert_not_nil f.head
+ assert_nil f.stable
+ assert_nil f.bottle
+ assert_nil f.devel
+
+ assert_equal f.head, f.active_spec
+ assert_equal 'HEAD', f.version
+ assert !f.head.has_checksum?
+ assert_equal 'https://github.com/mxcl/homebrew.git', f.url
+ assert_equal GitDownloadStrategy, f.download_strategy
+ assert_instance_of GitDownloadStrategy, f.downloader
+ assert_instance_of HeadSoftwareSpec, f.head
+ end
+
+ def test_head_only_with_version_specs
+ f = IncompleteStableSpecTestBall.new
+
+ assert_not_nil f.head
+ assert_nil f.stable
+ assert_nil f.bottle
+ assert_nil f.devel
+
+ assert_equal f.head, f.active_spec
+ assert_equal 'HEAD', f.version
+ assert !f.head.has_checksum?
+ assert_equal 'https://github.com/mxcl/homebrew.git', f.url
+ assert_equal GitDownloadStrategy, f.download_strategy
+ assert_instance_of GitDownloadStrategy, f.downloader
+ assert_instance_of HeadSoftwareSpec, f.head
+ end
+
+ def test_explicit_strategy_specs
+ f = ExplicitStrategySpecTestBall.new
+
+ assert_not_nil f.stable
+ assert_not_nil f.devel
+ assert_not_nil f.head
+
+ assert_equal f.stable, f.active_spec
+
+ assert !f.stable.has_checksum?
+ assert !f.devel.has_checksum?
+ assert !f.head.has_checksum?
+
+ assert_equal MercurialDownloadStrategy, f.stable.download_strategy
+ assert_equal BazaarDownloadStrategy, f.devel.download_strategy
+ assert_equal SubversionDownloadStrategy, f.head.download_strategy
+
+ assert_equal({ :tag => '0.2' }, f.stable.specs)
+ assert_equal({ :tag => '0.3' }, f.devel.specs)
+ assert f.head.specs.empty?
+ end
end
diff --git a/Library/Homebrew/test/testball.rb b/Library/Homebrew/test/testball.rb
index f440a6ed9..b61eef178 100644
--- a/Library/Homebrew/test/testball.rb
+++ b/Library/Homebrew/test/testball.rb
@@ -94,3 +94,133 @@ class TestBlockWithoutBuildCompilerFailure < TestCompilerFailures
cause "failure"
end
end
+
+class SpecTestBall < Formula
+ homepage 'http://example.com'
+ url 'file:///foo.com/testball-0.1.tbz'
+ mirror 'file:///foo.org/testball-0.1.tbz'
+ sha1 '482e737739d946b7c8cbaf127d9ee9c148b999f5'
+
+ head 'https://github.com/mxcl/homebrew.git', :tag => 'foo'
+
+ devel do
+ url 'file:///foo.com/testball-0.2.tbz'
+ mirror 'file:///foo.org/testball-0.2.tbz'
+ sha256 'deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef'
+ end
+
+ bottle do
+ sha1 'deadbeefdeadbeefdeadbeefdeadbeefdeadbeef' => :snowleopard
+ sha1 'baadf00dbaadf00dbaadf00dbaadf00dbaadf00d' => :lion
+ end
+
+ def initialize name=nil
+ super "spectestball"
+ end
+end
+
+class AncientSpecTestBall < Formula
+ @homepage='http://example.com'
+ @url='file:///foo.com/testball-0.1.tbz'
+ @md5='060844753f2a3b36ecfc3192d307dab2'
+ @head='https://github.com/mxcl/homebrew.git'
+ @specs={ :tag => 'foo' }
+
+ def initialize name=nil
+ super "ancientspectestball"
+ end
+end
+
+class ExplicitVersionSpecTestBall < Formula
+ homepage 'http://example.com'
+ url 'file:///foo.com/testball-stable.tbz'
+ sha1 '482e737739d946b7c8cbaf127d9ee9c148b999f5'
+ version '0.3'
+
+ devel do
+ url 'file:///foo.com/testball-devel.tbz'
+ sha1 'deadbeefdeadbeefdeadbeefdeadbeefdeadbeef'
+ version '0.4'
+ end
+
+ bottle do
+ version '1'
+ url 'file:///foo.com/test-0.3.lion.bottle.tar.gz'
+ sha1 'baadf00dbaadf00dbaadf00dbaadf00dbaadf00d'
+ end
+
+ def initialize name=nil
+ super "explicitversionspectestball"
+ end
+end
+
+class OldBottleSpecTestBall < Formula
+ homepage 'http://example.com'
+ url 'file:///foo.com/testball-0.1.tbz'
+ sha1 '482e737739d946b7c8cbaf127d9ee9c148b999f5'
+
+ bottle do
+ url 'file:///foo.com/testball-0.1-bottle.tar.gz'
+ sha1 'deadbeefdeadbeefdeadbeefdeadbeefdeadbeef'
+ end
+
+ def initialize name=nil
+ super "oldbottlespectestball"
+ end
+end
+
+class AncientBottleSpecTestBall < Formula
+ homepage 'http://example.com'
+ url 'file:///foo.com/testball-0.1.tbz'
+ sha1 '482e737739d946b7c8cbaf127d9ee9c148b999f5'
+
+ bottle 'file:///foo.com/testball-0.1-bottle.tar.gz'
+ bottle_sha1 'deadbeefdeadbeefdeadbeefdeadbeefdeadbeef'
+
+ def initialize name=nil
+ super "ancientbottlespectestball"
+ end
+end
+
+class HeadOnlySpecTestBall < Formula
+ homepage 'http://example.com'
+ head 'https://github.com/mxcl/homebrew.git'
+
+ def initialize name=nil
+ super "headyonlyspectestball"
+ end
+end
+
+class IncompleteStableSpecTestBall < Formula
+ homepage 'http://example.com'
+ head 'https://github.com/mxcl/homebrew.git'
+ sha1 '482e737739d946b7c8cbaf127d9ee9c148b999f5'
+
+ def initialize name=nil
+ super "incompletestablespectestball"
+ end
+end
+
+class HeadOnlyWithVersionSpecTestBall < Formula
+ homepage 'http://example.com'
+ head 'https://github.com/mxcl/homebrew.git'
+ version '0.3'
+
+ def initialize name=nil
+ super "headonlywithversionspectestball"
+ end
+end
+
+class ExplicitStrategySpecTestBall < Formula
+ homepage 'http://example.com'
+ url 'file:///foo.com/testball-stable', :using => :hg, :tag => '0.2'
+ head 'file:///foo.com/testball-head', :using => :svn
+
+ devel do
+ url 'file:///foo.com/testball-devel', :using => :bzr, :tag => '0.3'
+ end
+
+ def initialize name=nil
+ super "explicitstrategyspectestball"
+ end
+end
diff --git a/Library/Homebrew/test/testing_env.rb b/Library/Homebrew/test/testing_env.rb
index a283dbf25..68df4e17e 100644
--- a/Library/Homebrew/test/testing_env.rb
+++ b/Library/Homebrew/test/testing_env.rb
@@ -52,4 +52,9 @@ def shutup
end
end
+unless ARGV.include? "--no-compat" or ENV['HOMEBREW_NO_COMPAT']
+ $:.unshift(File.expand_path("#{ABS__FILE__}/../../compat"))
+ require 'compatibility'
+end
+
require 'test/unit' # must be after at_exit