829 lines
		
	
	
		
			22 KiB
		
	
	
	
		
			Ruby
		
	
	
	
	
	
			
		
		
	
	
			829 lines
		
	
	
		
			22 KiB
		
	
	
	
		
			Ruby
		
	
	
	
	
	
| require 'formula_support'
 | |
| require 'formula_lock'
 | |
| require 'formula_pin'
 | |
| require 'hardware'
 | |
| require 'bottles'
 | |
| require 'patches'
 | |
| require 'compilers'
 | |
| require 'build_environment'
 | |
| require 'build_options'
 | |
| require 'formulary'
 | |
| require 'software_spec'
 | |
| require 'install_renamed'
 | |
| 
 | |
| class Formula
 | |
|   include FileUtils
 | |
|   include Utils::Inreplace
 | |
|   extend BuildEnvironmentDSL
 | |
| 
 | |
|   attr_reader :name, :path, :homepage, :downloader, :build
 | |
|   attr_reader :stable, :bottle, :devel, :head, :active_spec
 | |
| 
 | |
|   # The current working directory during builds and tests.
 | |
|   # Will only be non-nil inside #stage and #test.
 | |
|   attr_reader :buildpath, :testpath
 | |
| 
 | |
|   attr_accessor :local_bottle_path
 | |
| 
 | |
|   # Flag for marking whether this formula needs C++ standard library
 | |
|   # compatibility check
 | |
|   attr_reader :cxxstdlib
 | |
| 
 | |
|   # Homebrew determines the name
 | |
|   def initialize name='__UNKNOWN__', path=nil
 | |
|     @name = name
 | |
|     # If we got an explicit path, use that, else determine from the name
 | |
|     @path = path.nil? ? self.class.path(name) : Pathname.new(path).expand_path
 | |
|     @homepage = self.class.homepage
 | |
| 
 | |
|     set_spec :stable
 | |
|     set_spec :devel
 | |
|     set_spec :head
 | |
|     set_spec :bottle do |bottle|
 | |
|       # Ensure the bottle URL is set. If it does not have a checksum,
 | |
|       # then a bottle is not available for the current platform.
 | |
|       # TODO: push this down into Bottle; we can pass the formula instance
 | |
|       # into a validation method on the bottle instance.
 | |
|       unless bottle.checksum.nil? || bottle.checksum.empty?
 | |
|         @bottle = bottle
 | |
|         bottle.url ||= bottle_url(self, bottle.current_tag)
 | |
|         bottle.version = stable.version
 | |
|       end
 | |
|     end
 | |
| 
 | |
|     @active_spec = determine_active_spec
 | |
|     validate_attributes :url, :name, :version
 | |
|     @downloader = active_spec.downloader
 | |
|     @build = determine_build_options
 | |
| 
 | |
|     @pin = FormulaPin.new(self)
 | |
| 
 | |
|     @cxxstdlib ||= Set.new
 | |
|   end
 | |
| 
 | |
|   def set_spec(name)
 | |
|     spec = self.class.send(name)
 | |
|     if block_given? && yield(spec) || spec.url
 | |
|       spec.owner = self
 | |
|       instance_variable_set("@#{name}", spec)
 | |
|     end
 | |
|   end
 | |
| 
 | |
|   def determine_active_spec
 | |
|     case
 | |
|     when head && ARGV.build_head?        then head    # --HEAD
 | |
|     when devel && ARGV.build_devel?      then devel   # --devel
 | |
|     when bottle && install_bottle?(self) then bottle  # bottle available
 | |
|     when stable                          then stable
 | |
|     when devel && stable.nil?            then devel   # devel-only
 | |
|     when head && stable.nil?             then head    # head-only
 | |
|     else
 | |
|       raise FormulaSpecificationError, "formulae require at least a URL"
 | |
|     end
 | |
|   end
 | |
| 
 | |
|   def validate_attributes(*attrs)
 | |
|     attrs.each do |attr|
 | |
|       if (value = send(attr).to_s).empty? || value =~ /\s/
 | |
|         raise FormulaValidationError.new(attr, value)
 | |
|       end
 | |
|     end
 | |
|   end
 | |
| 
 | |
|   def default_build?
 | |
|     self.class.build.used_options.empty?
 | |
|   end
 | |
| 
 | |
|   def determine_build_options
 | |
|     build = active_spec.build
 | |
|     options.each { |opt, desc| build.add(opt, desc) }
 | |
|     build
 | |
|   end
 | |
| 
 | |
|   def url;      active_spec.url;     end
 | |
|   def version;  active_spec.version; end
 | |
|   def mirrors;  active_spec.mirrors; end
 | |
| 
 | |
|   def resource(name)
 | |
|     active_spec.resource(name)
 | |
|   end
 | |
| 
 | |
|   def resources
 | |
|     active_spec.resources.values
 | |
|   end
 | |
| 
 | |
|   def deps
 | |
|     active_spec.deps
 | |
|   end
 | |
| 
 | |
|   def requirements
 | |
|     active_spec.requirements
 | |
|   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
 | |
|   end
 | |
| 
 | |
|   def linked_keg
 | |
|     Pathname.new("#{HOMEBREW_LIBRARY}/LinkedKegs/#{name}")
 | |
|   end
 | |
| 
 | |
|   def installed_prefix
 | |
|     if head && (head_prefix = prefix(head.version)).directory?
 | |
|       head_prefix
 | |
|     elsif devel && (devel_prefix = prefix(devel.version)).directory?
 | |
|       devel_prefix
 | |
|     else
 | |
|       prefix
 | |
|     end
 | |
|   end
 | |
| 
 | |
|   def installed_version
 | |
|     require 'keg'
 | |
|     Keg.new(installed_prefix).version
 | |
|   end
 | |
| 
 | |
|   def prefix(v=version)
 | |
|     Pathname.new("#{HOMEBREW_CELLAR}/#{name}/#{v}")
 | |
|   end
 | |
|   def rack; prefix.parent end
 | |
| 
 | |
|   def bin;     prefix+'bin'     end
 | |
|   def doc;     share+'doc'+name end
 | |
|   def include; prefix+'include' end
 | |
|   def info;    share+'info'     end
 | |
|   def lib;     prefix+'lib'     end
 | |
|   def libexec; prefix+'libexec' end
 | |
|   def man;     share+'man'      end
 | |
|   def man1;    man+'man1'       end
 | |
|   def man2;    man+'man2'       end
 | |
|   def man3;    man+'man3'       end
 | |
|   def man4;    man+'man4'       end
 | |
|   def man5;    man+'man5'       end
 | |
|   def man6;    man+'man6'       end
 | |
|   def man7;    man+'man7'       end
 | |
|   def man8;    man+'man8'       end
 | |
|   def sbin;    prefix+'sbin'    end
 | |
|   def share;   prefix+'share'   end
 | |
| 
 | |
|   def frameworks; prefix+'Frameworks' end
 | |
|   def kext_prefix; prefix+'Library/Extensions' end
 | |
| 
 | |
|   # configuration needs to be preserved past upgrades
 | |
|   def etc; (HOMEBREW_PREFIX+'etc').extend(InstallRenamed) end
 | |
| 
 | |
|   # generally we don't want var stuff inside the keg
 | |
|   def var; HOMEBREW_PREFIX+'var' end
 | |
| 
 | |
|   def bash_completion; prefix+'etc/bash_completion.d' end
 | |
|   def zsh_completion;  share+'zsh/site-functions'     end
 | |
| 
 | |
|   # for storing etc, var files for later copying from bottles
 | |
|   def bottle_prefix; prefix+'.bottle' end
 | |
| 
 | |
|   # override this to provide a plist
 | |
|   def plist; nil; end
 | |
|   alias :startup_plist :plist
 | |
|   # plist name, i.e. the name of the launchd service
 | |
|   def plist_name; 'homebrew.mxcl.'+name end
 | |
|   def plist_path; prefix+(plist_name+'.plist') end
 | |
|   def plist_manual; self.class.plist_manual end
 | |
|   def plist_startup; self.class.plist_startup end
 | |
| 
 | |
|   def opt_prefix
 | |
|     Pathname.new("#{HOMEBREW_PREFIX}/opt/#{name}")
 | |
|   end
 | |
| 
 | |
|   def cached_download
 | |
|     downloader.cached_location
 | |
|   end
 | |
| 
 | |
|   def clear_cache
 | |
|     downloader.clear_cache
 | |
|   end
 | |
| 
 | |
|   # Can be overridden to selectively disable bottles from formulae.
 | |
|   # Defaults to true so overridden version does not have to check if bottles
 | |
|   # are supported.
 | |
|   def pour_bottle?; true end
 | |
| 
 | |
|   # Can be overridden to run commands on both source and bottle installation.
 | |
|   def post_install; end
 | |
| 
 | |
|   # tell the user about any caveats regarding this package, return a string
 | |
|   def caveats; nil end
 | |
| 
 | |
|   # any e.g. configure options for this package
 | |
|   def options; [] end
 | |
| 
 | |
|   # patches are automatically applied after extracting the tarball
 | |
|   # return an array of strings, or if you need a patch level other than -p1
 | |
|   # return a Hash eg.
 | |
|   #   {
 | |
|   #     :p0 => ['http://foo.com/patch1', 'http://foo.com/patch2'],
 | |
|   #     :p1 =>  'http://bar.com/patch2'
 | |
|   #   }
 | |
|   # The final option is to return DATA, then put a diff after __END__. You
 | |
|   # can still return a Hash with DATA as the value for a patch level key.
 | |
|   def patches; end
 | |
| 
 | |
|   # rarely, you don't want your library symlinked into the main prefix
 | |
|   # see gettext.rb for an example
 | |
|   def keg_only?
 | |
|     kor = self.class.keg_only_reason
 | |
|     not kor.nil? and kor.valid?
 | |
|   end
 | |
| 
 | |
|   def keg_only_reason
 | |
|     self.class.keg_only_reason
 | |
|   end
 | |
| 
 | |
|   def fails_with? cc
 | |
|     cc = Compiler.new(cc) unless cc.is_a? Compiler
 | |
|     (self.class.cc_failures || []).any? do |failure|
 | |
|       # Major version check distinguishes between, e.g.,
 | |
|       # GCC 4.7.1 and GCC 4.8.2, where a comparison is meaningless
 | |
|       failure.compiler == cc.name && failure.major_version == cc.major_version && \
 | |
|         failure.version >= cc.version
 | |
|     end
 | |
|   end
 | |
| 
 | |
|   # sometimes the clean process breaks things
 | |
|   # skip cleaning paths in a formula with a class method like this:
 | |
|   #   skip_clean [bin+"foo", lib+"bar"]
 | |
|   # redefining skip_clean? now deprecated
 | |
|   def skip_clean? path
 | |
|     return true if self.class.skip_clean_all?
 | |
|     return true if path.extname == '.la' and self.class.skip_clean_paths.include? :la
 | |
|     to_check = path.relative_path_from(prefix).to_s
 | |
|     self.class.skip_clean_paths.include? to_check
 | |
|   end
 | |
| 
 | |
|   # yields self with current working directory set to the uncompressed tarball
 | |
|   def brew
 | |
|     validate_attributes :name, :version
 | |
| 
 | |
|     stage do
 | |
|       begin
 | |
|         patch
 | |
|         # we allow formulae to do anything they want to the Ruby process
 | |
|         # so load any deps before this point! And exit asap afterwards
 | |
|         yield self
 | |
|       rescue RuntimeError, SystemCallError
 | |
|         %w(config.log CMakeCache.txt).each do |fn|
 | |
|           (HOMEBREW_LOGS/name).install(fn) if File.file?(fn)
 | |
|         end
 | |
|         raise
 | |
|       end
 | |
|     end
 | |
|   end
 | |
| 
 | |
|   def lock
 | |
|     @lock = FormulaLock.new(name)
 | |
|     @lock.lock
 | |
|   end
 | |
| 
 | |
|   def unlock
 | |
|     @lock.unlock unless @lock.nil?
 | |
|   end
 | |
| 
 | |
|   def pinnable?
 | |
|     @pin.pinnable?
 | |
|   end
 | |
| 
 | |
|   def pinned?
 | |
|     @pin.pinned?
 | |
|   end
 | |
| 
 | |
|   def pin
 | |
|     @pin.pin
 | |
|   end
 | |
| 
 | |
|   def unpin
 | |
|     @pin.unpin
 | |
|   end
 | |
| 
 | |
|   def == other
 | |
|     instance_of?(other.class) && name == other.name
 | |
|   end
 | |
|   alias_method :eql?, :==
 | |
| 
 | |
|   def hash
 | |
|     name.hash
 | |
|   end
 | |
|   def <=> b
 | |
|     name <=> b.name
 | |
|   end
 | |
|   def to_s
 | |
|     name
 | |
|   end
 | |
|   def inspect
 | |
|     name
 | |
|   end
 | |
| 
 | |
|   # Standard parameters for CMake builds.
 | |
|   # Using Build Type "None" tells cmake to use our CFLAGS,etc. settings.
 | |
|   # Setting it to Release would ignore our flags.
 | |
|   # Setting CMAKE_FIND_FRAMEWORK to "LAST" tells CMake to search for our
 | |
|   # libraries before trying to utilize Frameworks, many of which will be from
 | |
|   # 3rd party installs.
 | |
|   # Note: there isn't a std_autotools variant because autotools is a lot
 | |
|   # less consistent and the standard parameters are more memorable.
 | |
|   def std_cmake_args
 | |
|     %W[
 | |
|       -DCMAKE_INSTALL_PREFIX=#{prefix}
 | |
|       -DCMAKE_BUILD_TYPE=None
 | |
|       -DCMAKE_FIND_FRAMEWORK=LAST
 | |
|       -DCMAKE_VERBOSE_MAKEFILE=ON
 | |
|       -Wno-dev
 | |
|     ]
 | |
|   end
 | |
| 
 | |
|   # Install python bindings inside of a block given to this method and/or
 | |
|   # call python so: `system python, "setup.py", "install", "--prefix=#{prefix}"
 | |
|   # Note that there are no quotation marks around python!
 | |
|   # <https://github.com/Homebrew/homebrew/wiki/Homebrew-and-Python>
 | |
|   def python(options={:allowed_major_versions => [2, 3]}, &block)
 | |
|     require 'python_helper'
 | |
|     python_helper(options, &block)
 | |
|   end
 | |
| 
 | |
|   # Explicitly only execute the block for 2.x (if a python 2.x is available)
 | |
|   def python2 &block
 | |
|     python(:allowed_major_versions => [2], &block)
 | |
|   end
 | |
| 
 | |
|   # Explicitly only execute the block for 3.x (if a python 3.x is available)
 | |
|   def python3 &block
 | |
|     python(:allowed_major_versions => [3], &block)
 | |
|   end
 | |
| 
 | |
|   # Generates a formula's ruby class name from a formula's name
 | |
|   def self.class_s name
 | |
|     # remove invalid characters and then camelcase it
 | |
|     name.capitalize.gsub(/[-_.\s]([a-zA-Z0-9])/) { $1.upcase } \
 | |
|                    .gsub('+', 'x')
 | |
|   end
 | |
| 
 | |
|   # an array of all Formula names
 | |
|   def self.names
 | |
|     Dir["#{HOMEBREW_LIBRARY}/Formula/*.rb"].map{ |f| File.basename f, '.rb' }.sort
 | |
|   end
 | |
| 
 | |
|   def self.each
 | |
|     names.each do |name|
 | |
|       begin
 | |
|         yield Formula.factory(name)
 | |
|       rescue StandardError => e
 | |
|         # Don't let one broken formula break commands. But do complain.
 | |
|         onoe "Failed to import: #{name}"
 | |
|         puts e
 | |
|         next
 | |
|       end
 | |
|     end
 | |
|   end
 | |
|   class << self
 | |
|     include Enumerable
 | |
|   end
 | |
| 
 | |
|   def self.installed
 | |
|     return [] unless HOMEBREW_CELLAR.directory?
 | |
| 
 | |
|     HOMEBREW_CELLAR.subdirs.map do |rack|
 | |
|       begin
 | |
|         factory(rack.basename.to_s)
 | |
|       rescue FormulaUnavailableError
 | |
|       end
 | |
|     end.compact
 | |
|   end
 | |
| 
 | |
|   def self.aliases
 | |
|     Dir["#{HOMEBREW_LIBRARY}/Aliases/*"].map{ |f| File.basename f }.sort
 | |
|   end
 | |
| 
 | |
|   # TODO - document what this returns and why
 | |
|   def self.canonical_name name
 | |
|     # if name includes a '/', it may be a tap reference, path, or URL
 | |
|     if name.include? "/"
 | |
|       if name =~ %r{(.+)/(.+)/(.+)}
 | |
|         tap_name = "#$1-#$2".downcase
 | |
|         tapd = Pathname.new("#{HOMEBREW_LIBRARY}/Taps/#{tap_name}")
 | |
|         tapd.find_formula do |relative_pathname|
 | |
|           return "#{tapd}/#{relative_pathname}" if relative_pathname.stem.to_s == $3
 | |
|         end if tapd.directory?
 | |
|       end
 | |
|       # Otherwise don't resolve paths or URLs
 | |
|       return name
 | |
|     end
 | |
| 
 | |
|     # test if the name is a core formula
 | |
|     formula_with_that_name = Pathname.new("#{HOMEBREW_LIBRARY}/Formula/#{name}.rb")
 | |
|     if formula_with_that_name.file? and formula_with_that_name.readable?
 | |
|       return name
 | |
|     end
 | |
| 
 | |
|     # test if the name is a formula alias
 | |
|     possible_alias = Pathname.new("#{HOMEBREW_LIBRARY}/Aliases/#{name}")
 | |
|     if possible_alias.file?
 | |
|       return possible_alias.realpath.basename('.rb').to_s
 | |
|     end
 | |
| 
 | |
|     # test if the name is a cached downloaded formula
 | |
|     possible_cached_formula = Pathname.new("#{HOMEBREW_CACHE_FORMULA}/#{name}.rb")
 | |
|     if possible_cached_formula.file?
 | |
|       return possible_cached_formula.to_s
 | |
|     end
 | |
| 
 | |
|     # dunno, pass through the name
 | |
|     return name
 | |
|   end
 | |
| 
 | |
|   def self.factory name
 | |
|     Formulary.factory name
 | |
|   end
 | |
| 
 | |
|   def tap?
 | |
|     !!path.realpath.to_s.match(HOMEBREW_TAP_DIR_REGEX)
 | |
|   end
 | |
| 
 | |
|   def tap
 | |
|     if path.realpath.to_s =~ HOMEBREW_TAP_DIR_REGEX
 | |
|       "#$1/#$2"
 | |
|     elsif core_formula?
 | |
|       "Homebrew/homebrew"
 | |
|     else
 | |
|       "path or URL"
 | |
|     end
 | |
|   end
 | |
| 
 | |
|   # True if this formula is provided by Homebrew itself
 | |
|   def core_formula?
 | |
|     path.realpath.to_s == Formula.path(name).to_s
 | |
|   end
 | |
| 
 | |
|   def self.path name
 | |
|     Pathname.new("#{HOMEBREW_LIBRARY}/Formula/#{name.downcase}.rb")
 | |
|   end
 | |
| 
 | |
|   def env
 | |
|     @env ||= self.class.env
 | |
|   end
 | |
| 
 | |
|   def conflicts
 | |
|     self.class.conflicts
 | |
|   end
 | |
| 
 | |
|   # Returns a list of Dependency objects in an installable order, which
 | |
|   # means if a depends on b then b will be ordered before a in this list
 | |
|   def recursive_dependencies(&block)
 | |
|     Dependency.expand(self, &block)
 | |
|   end
 | |
| 
 | |
|   # The full set of Requirements for this formula's dependency tree.
 | |
|   def recursive_requirements(&block)
 | |
|     Requirement.expand(self, &block)
 | |
|   end
 | |
| 
 | |
|   def to_hash
 | |
|     hsh = {
 | |
|       "name" => name,
 | |
|       "homepage" => homepage,
 | |
|       "versions" => {
 | |
|         "stable" => (stable.version.to_s if stable),
 | |
|         "bottle" => bottle ? true : false,
 | |
|         "devel" => (devel.version.to_s if devel),
 | |
|         "head" => (head.version.to_s if head)
 | |
|       },
 | |
|       "installed" => [],
 | |
|       "linked_keg" => (linked_keg.realpath.basename.to_s if linked_keg.exist?),
 | |
|       "keg_only" => keg_only?,
 | |
|       "dependencies" => deps.map {|dep| dep.to_s},
 | |
|       "conflicts_with" => conflicts.map(&:name),
 | |
|       "options" => [],
 | |
|       "caveats" => caveats
 | |
|     }
 | |
| 
 | |
|     build.each do |opt|
 | |
|       hsh["options"] << {
 | |
|         "option" => "--"+opt.name,
 | |
|         "description" => opt.description
 | |
|       }
 | |
|     end
 | |
| 
 | |
|     if rack.directory?
 | |
|       rack.subdirs.each do |keg|
 | |
|         tab = Tab.for_keg keg
 | |
| 
 | |
|         hsh["installed"] << {
 | |
|           "version" => keg.basename.to_s,
 | |
|           "used_options" => tab.used_options.map(&:flag),
 | |
|           "built_as_bottle" => tab.built_bottle,
 | |
|           "poured_from_bottle" => tab.poured_from_bottle
 | |
|         }
 | |
|       end
 | |
|     end
 | |
| 
 | |
|     hsh
 | |
| 
 | |
|   end
 | |
| 
 | |
|   # For brew-fetch and others.
 | |
|   def fetch
 | |
|     active_spec.fetch
 | |
|   end
 | |
| 
 | |
|   # For FormulaInstaller.
 | |
|   def verify_download_integrity fn
 | |
|     active_spec.verify_download_integrity(fn)
 | |
|   end
 | |
| 
 | |
|   def test
 | |
|     require 'test/unit/assertions'
 | |
|     extend(Test::Unit::Assertions)
 | |
|     # Adding the used options allows us to use `build.with?` inside of tests
 | |
|     tab = Tab.for_name(name)
 | |
|     tab.used_options.each { |opt| build.args << opt unless build.has_opposite_of? opt }
 | |
|     ret = nil
 | |
|     mktemp do
 | |
|       @testpath = Pathname.pwd
 | |
|       ret = instance_eval(&self.class.test)
 | |
|       @testpath = nil
 | |
|     end
 | |
|     ret
 | |
|   end
 | |
| 
 | |
|   def test_defined?
 | |
|     not self.class.instance_variable_get(:@test_defined).nil?
 | |
|   end
 | |
| 
 | |
|   protected
 | |
| 
 | |
|   # Pretty titles the command and buffers stdout/stderr
 | |
|   # Throws if there's an error
 | |
|   def system cmd, *args
 | |
|     # remove "boring" arguments so that the important ones are more likely to
 | |
|     # be shown considering that we trim long ohai lines to the terminal width
 | |
|     pretty_args = args.dup
 | |
|     if cmd == "./configure" and not ARGV.verbose?
 | |
|       pretty_args.delete "--disable-dependency-tracking"
 | |
|       pretty_args.delete "--disable-debug"
 | |
|     end
 | |
|     ohai "#{cmd} #{pretty_args*' '}".strip
 | |
| 
 | |
|     removed_ENV_variables = case if args.empty? then cmd.split(' ').first else cmd end
 | |
|     when "xcodebuild"
 | |
|       ENV.remove_cc_etc
 | |
|     end
 | |
| 
 | |
|     @exec_count ||= 0
 | |
|     @exec_count += 1
 | |
|     logd = HOMEBREW_LOGS/name
 | |
|     logfn = "#{logd}/%02d.%s" % [@exec_count, File.basename(cmd.to_s).split(' ').first]
 | |
|     mkdir_p(logd)
 | |
| 
 | |
|     rd, wr = IO.pipe
 | |
|     fork do
 | |
|       ENV['HOMEBREW_CC_LOG_PATH'] = logfn
 | |
|       rd.close
 | |
|       $stdout.reopen wr
 | |
|       $stderr.reopen wr
 | |
|       args.collect!{|arg| arg.to_s}
 | |
|       exec(cmd.to_s, *args) rescue nil
 | |
|       puts "Failed to execute: #{cmd}"
 | |
|       exit! 1 # never gets here unless exec threw or failed
 | |
|     end
 | |
|     wr.close
 | |
| 
 | |
|     File.open(logfn, 'w') do |f|
 | |
|       while buf = rd.gets
 | |
|         f.puts buf
 | |
|         puts buf if ARGV.verbose?
 | |
|       end
 | |
| 
 | |
|       Process.wait
 | |
| 
 | |
|       $stdout.flush
 | |
| 
 | |
|       unless $?.success?
 | |
|         f.flush
 | |
|         Kernel.system "/usr/bin/tail", "-n", "5", logfn unless ARGV.verbose?
 | |
|         f.puts
 | |
|         require 'cmd/--config'
 | |
|         Homebrew.write_build_config(f)
 | |
|         raise BuildError.new(self, cmd, args, $?)
 | |
|       end
 | |
|     end
 | |
|   ensure
 | |
|     rd.close if rd and not rd.closed?
 | |
|     ENV.update(removed_ENV_variables) if removed_ENV_variables
 | |
|   end
 | |
| 
 | |
|   private
 | |
| 
 | |
|   def stage
 | |
|     active_spec.stage do
 | |
|       @buildpath = Pathname.pwd
 | |
|       yield
 | |
|       @buildpath = nil
 | |
|     end
 | |
|   end
 | |
| 
 | |
|   def patch
 | |
|     patch_list = Patches.new(patches)
 | |
|     return if patch_list.empty?
 | |
| 
 | |
|     if patch_list.external_patches?
 | |
|       ohai "Downloading patches"
 | |
|       patch_list.download!
 | |
|     end
 | |
| 
 | |
|     ohai "Patching"
 | |
|     patch_list.each do |p|
 | |
|       case p.compression
 | |
|         when :gzip  then with_system_path { safe_system "gunzip",  p.compressed_filename }
 | |
|         when :bzip2 then with_system_path { safe_system "bunzip2", p.compressed_filename }
 | |
|       end
 | |
|       # -f means don't prompt the user if there are errors; just exit with non-zero status
 | |
|       safe_system '/usr/bin/patch', '-f', *(p.patch_args)
 | |
|     end
 | |
|   end
 | |
| 
 | |
|   # Explicitly request changing C++ standard library compatibility check
 | |
|   # settings. Use with caution!
 | |
|   def cxxstdlib_check check_type
 | |
|     @cxxstdlib << check_type
 | |
|   end
 | |
| 
 | |
|   def self.method_added method
 | |
|     case method
 | |
|     when :brew
 | |
|       raise "You cannot override Formula#brew in class #{name}"
 | |
|     when :test
 | |
|       @test_defined = true
 | |
|     end
 | |
|   end
 | |
| 
 | |
|   # The methods below define the formula DSL.
 | |
|   class << self
 | |
| 
 | |
|     attr_reader :keg_only_reason, :cc_failures
 | |
|     attr_rw :homepage, :plist_startup, :plist_manual
 | |
| 
 | |
|     def specs
 | |
|       @specs ||= [stable, devel, head, bottle].freeze
 | |
|     end
 | |
| 
 | |
|     def url val, specs={}
 | |
|       stable.url(val, specs)
 | |
|     end
 | |
| 
 | |
|     def version val=nil
 | |
|       stable.version(val)
 | |
|     end
 | |
| 
 | |
|     def mirror val
 | |
|       stable.mirror(val)
 | |
|     end
 | |
| 
 | |
|     Checksum::TYPES.each do |cksum|
 | |
|       class_eval <<-EOS, __FILE__, __LINE__ + 1
 | |
|         def #{cksum}(val)
 | |
|           stable.#{cksum}(val)
 | |
|         end
 | |
|       EOS
 | |
|     end
 | |
| 
 | |
|     def build
 | |
|       stable.build
 | |
|     end
 | |
| 
 | |
|     def stable &block
 | |
|       @stable ||= SoftwareSpec.new
 | |
|       return @stable unless block_given?
 | |
|       @stable.instance_eval(&block)
 | |
|     end
 | |
| 
 | |
|     def bottle *, &block
 | |
|       @bottle ||= Bottle.new
 | |
|       return @bottle unless block_given?
 | |
|       @bottle.instance_eval(&block)
 | |
|       @bottle.version = @stable.version
 | |
|     end
 | |
| 
 | |
|     def devel &block
 | |
|       @devel ||= SoftwareSpec.new
 | |
|       return @devel unless block_given?
 | |
|       @devel.instance_eval(&block)
 | |
|     end
 | |
| 
 | |
|     def head val=nil, specs={}, &block
 | |
|       @head ||= HeadSoftwareSpec.new
 | |
|       if block_given?
 | |
|         @head.instance_eval(&block)
 | |
|       elsif val
 | |
|         @head.url(val, specs)
 | |
|       else
 | |
|         @head
 | |
|       end
 | |
|     end
 | |
| 
 | |
|     # Define a named resource using a SoftwareSpec style block
 | |
|     def resource name, &block
 | |
|       specs.each do |spec|
 | |
|         spec.resource(name, &block) unless spec.resource?(name)
 | |
|       end
 | |
|     end
 | |
| 
 | |
|     def depends_on dep
 | |
|       specs.each { |spec| spec.depends_on(dep) }
 | |
|     end
 | |
| 
 | |
|     def option name, description=nil
 | |
|       specs.each { |spec| spec.option(name, description) }
 | |
|     end
 | |
| 
 | |
|     def plist_options options
 | |
|       @plist_startup = options[:startup]
 | |
|       @plist_manual = options[:manual]
 | |
|     end
 | |
| 
 | |
|     def conflicts
 | |
|       @conflicts ||= []
 | |
|     end
 | |
| 
 | |
|     def conflicts_with *names
 | |
|       opts = Hash === names.last ? names.pop : {}
 | |
|       names.each { |name| conflicts << FormulaConflict.new(name, opts[:because]) }
 | |
|     end
 | |
| 
 | |
|     def skip_clean *paths
 | |
|       paths.flatten!
 | |
| 
 | |
|       # :all is deprecated though
 | |
|       if paths.include? :all
 | |
|         @skip_clean_all = true
 | |
|         return
 | |
|       end
 | |
| 
 | |
|       skip_clean_paths.merge(paths)
 | |
|     end
 | |
| 
 | |
|     def skip_clean_all?
 | |
|       @skip_clean_all
 | |
|     end
 | |
| 
 | |
|     def skip_clean_paths
 | |
|       @skip_clean_paths ||= Set.new
 | |
|     end
 | |
| 
 | |
|     def keg_only reason, explanation=nil
 | |
|       @keg_only_reason = KegOnlyReason.new(reason, explanation.to_s.chomp)
 | |
|     end
 | |
| 
 | |
|     # For Apple compilers, this should be in the format:
 | |
|     # fails_with compiler do
 | |
|     #   cause "An explanation for why the build doesn't work."
 | |
|     #   build "The Apple build number for the newest incompatible release."
 | |
|     # end
 | |
|     #
 | |
|     # The block may be omitted, and if present the build may be omitted;
 | |
|     # if so, then the compiler will be blacklisted for *all* versions.
 | |
|     #
 | |
|     # For GNU GCC compilers, this should be in the format:
 | |
|     # fails_with compiler => major_version do
 | |
|     #   cause
 | |
|     #   version "The official release number for the latest incompatible
 | |
|     #            version, for instance 4.8.1"
 | |
|     # end
 | |
|     #
 | |
|     # `major_version` should be the major release number only, for instance
 | |
|     # '4.8' for the GCC 4.8 series (4.8.0, 4.8.1, etc.).
 | |
|     # If `version` or the block is omitted, then the compiler will be
 | |
|     # blacklisted for all compilers in that series.
 | |
|     #
 | |
|     # For example, if a bug is only triggered on GCC 4.8.1 but is not
 | |
|     # encountered on 4.8.2:
 | |
|     #
 | |
|     # fails_with :gcc => '4.8' do
 | |
|     #   version '4.8.1'
 | |
|     # end
 | |
|     def fails_with compiler, &block
 | |
|       @cc_failures ||= Set.new
 | |
|       @cc_failures << CompilerFailure.new(compiler, &block)
 | |
|     end
 | |
| 
 | |
|     def require_universal_deps
 | |
|       specs.each { |spec| spec.build.universal = true }
 | |
|     end
 | |
| 
 | |
|     def test &block
 | |
|       return @test unless block_given?
 | |
|       @test_defined = true
 | |
|       @test = block
 | |
|     end
 | |
|   end
 | |
| end
 | |
| 
 | |
| require 'formula_specialties'
 | 
