<commit_before>require 'download_strategy'
require 'fileutils'

class FormulaUnavailableError <RuntimeError
  def initialize name
    @name = name
    super "No available formula for #{name}"
  end

  attr_reader :name
end


class SoftwareSpecification
  attr_reader :url, :specs, :using

  VCS_SYMBOLS = {
    :bzr,     BazaarDownloadStrategy,
    :curl,    CurlDownloadStrategy,
    :cvs,     CVSDownloadStrategy,
    :git,     GitDownloadStrategy,
    :hg,      MercurialDownloadStrategy,
    :nounzip, NoUnzipCurlDownloadStrategy,
    :post,    CurlPostDownloadStrategy,
    :svn,     SubversionDownloadStrategy,
  }

  def initialize url, specs=nil
    raise "No url provided" if url.nil?
    @url = url
    unless specs.nil?
      # Get download strategy hint, if any
      @using = specs.delete :using
      # The rest of the specs are for source control
      @specs = specs
    end
  end

  # Returns a suitable DownloadStrategy class that can be
  # used to retreive this software package.
  def download_strategy
    return detect_download_strategy(@url) if @using.nil?

    # If a class is passed, assume it is a download strategy
    return @using if @using.kind_of? Class

    detected = VCS_SYMBOLS[@using]
    raise "Unknown strategy #{@using} was requested." unless detected
    return detected
  end

  def detect_version
    Pathname.new(@url).version
  end
end


# Derive and define at least @url, see Library/Formula for examples
class Formula
  include FileUtils

  attr_reader :url, :version, :homepage, :name, :specs, :downloader

  # Homebrew determines the name
  def initialize name='__UNKNOWN__'
    set_instance_variable 'homepage'
    set_instance_variable 'url'
    set_instance_variable 'head'
    set_instance_variable 'specs'

    set_instance_variable 'stable'
    set_instance_variable 'unstable'

    if @head and (not @url or ARGV.build_head?)
      @url = @head
      @version = 'HEAD'
      @spec_to_use = @unstable
    else
      if @stable.nil?
        @spec_to_use = SoftwareSpecification.new(@url, @specs)
      else
        @spec_to_use = @stable
      end
    end

    raise "No url provided for formula #{name}" if @url.nil?
    @name=name
    validate_variable :name

    set_instance_variable 'version'
    @version ||= @spec_to_use.detect_version
    validate_variable :version if @version

    CHECKSUM_TYPES.each { |type| set_instance_variable type }

    @downloader=download_strategy.new @spec_to_use.url, name, version, @spec_to_use.specs
  end

  # if the dir is there, but it's empty we consider it not installed
  def installed?
    return prefix.children.length > 0
  rescue
    return false
  end

  def path
    self.class.path name
  end

  def prefix
    validate_variable :name
    validate_variable :version
    HOMEBREW_CELLAR+@name+@version
  end

  def bin;     prefix+'bin'            end
  def doc;     prefix+'share/doc'+name end
  def include; prefix+'include'        end
  def info;    prefix+'share/info'     end
  def lib;     prefix+'lib'            end
  def libexec; prefix+'libexec'        end
  def man;     prefix+'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

  # configuration needs to be preserved past upgrades
  def etc; HOMEBREW_PREFIX+'etc' end
  # generally we don't want var stuff inside the keg
  def var; HOMEBREW_PREFIX+'var' end

  # Use the @spec_to_use to detect the download strategy.
  # Can be overriden to force a custom download strategy
  def download_strategy
    @spec_to_use.download_strategy
  end

  def cached_download
    @downloader.cached_location
  end

  # tell the user about any caveats regarding this package, return a string
  def caveats; nil 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',
  #     :p2 => ['http://moo.com/patch5', 'http://moo.com/patch6']
  #   }
  # 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?
    self.class.keg_only_reason || false
  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? in formulas is now deprecated
  def skip_clean? path
    return true if self.class.skip_clean_all?
    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_variable :name
    validate_variable :version

    stage do
      begin
        patch
        # we allow formulas to do anything they want to the Ruby process
        # so load any deps before this point! And exit asap afterwards
        yield self
      rescue Interrupt, RuntimeError, SystemCallError => e
        raise unless ARGV.debug?
        onoe e.inspect
        puts e.backtrace
        ohai "Rescuing build..."
        if (e.was_running_configure? rescue false) and File.exist? 'config.log'
          puts "It looks like an autotools configure failed."
          puts "Gist 'config.log' and any error output when reporting an issue."
          puts
        end

        puts "When you exit this shell Homebrew will attempt to finalise the installation."
        puts "If nothing is installed or the shell exits with a non-zero error code,"
        puts "Homebrew will abort. The installation prefix is:"
        puts prefix
        ENV['HOMEBREW_DEBUG_INSTALL'] = name
        interactive_shell
      end
    end
  end

  # we don't have a std_autotools variant because autotools is a lot less
  # consistent and the standard parameters are more memorable
  # really Homebrew should determine what works inside brew() then
  # we could add --disable-dependency-tracking when it will work
  def std_cmake_parameters
    # The None part makes cmake use the environment's CFLAGS etc. settings
    "-DCMAKE_INSTALL_PREFIX='#{prefix}' -DCMAKE_BUILD_TYPE=None -Wno-dev"
  end

  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_REPOSITORY}/Library/Formula/*.rb"].map{ |f| File.basename f, '.rb' }.sort
  end

  # an array of all Formula, instantiated
  def self.all
    all = []
    names.each do |n|
      begin
        all << Formula.factory(n)
      rescue
        # Don't let one broken formula break commands.
      end
    end
    return all
  end

  def self.aliases
    Dir["#{HOMEBREW_REPOSITORY}/Library/Aliases/*"].map{ |f| File.basename f }.sort
  end

  def self.factory name
    return name if name.kind_of? Formula
    path = Pathname.new(name)
    if path.absolute?
      require name
      name = path.stem
    else
      require self.path(name)
    end
    begin
      klass_name = self.class_s(name)
      klass = eval(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
    end
    return klass.new(name)
  rescue LoadError
    raise FormulaUnavailableError.new(name)
  end

  def self.path name
    HOMEBREW_REPOSITORY+"Library/Formula/#{name.downcase}.rb"
  end

  def deps
    self.class.deps or []
  end

  def external_deps
    self.class.external_deps
  end

  def fails_with_llvm msg="", data=nil
    return unless (ENV['HOMEBREW_USE_LLVM'] or ARGV.include? '--use-llvm')

    build = data.delete :build rescue nil
    msg = "(No specific reason was given)" if msg.empty?

    opoo "LLVM was requested, but this formula is reported as not working with LLVM:"
    puts msg
    puts "Tested with LLVM build #{build}" unless build == nil
  end

protected
  # Pretty titles the command and buffers stdout/stderr
  # Throws if there's an error
  def system cmd, *args
    ohai "#{cmd} #{args*' '}".strip

    if ARGV.verbose?
      safe_system cmd, *args
    else
      rd, wr = IO.pipe
      pid = fork do<commit_msg>fails_with_llvm will switch to GCC 4.2 by default<commit_after>require 'download_strategy'
require 'fileutils'

class FormulaUnavailableError <RuntimeError
  def initialize name
    @name = name
    super "No available formula for #{name}"
  end

  attr_reader :name
end


class SoftwareSpecification
  attr_reader :url, :specs, :using

  VCS_SYMBOLS = {
    :bzr,     BazaarDownloadStrategy,
    :curl,    CurlDownloadStrategy,
    :cvs,     CVSDownloadStrategy,
    :git,     GitDownloadStrategy,
    :hg,      MercurialDownloadStrategy,
    :nounzip, NoUnzipCurlDownloadStrategy,
    :post,    CurlPostDownloadStrategy,
    :svn,     SubversionDownloadStrategy,
  }

  def initialize url, specs=nil
    raise "No url provided" if url.nil?
    @url = url
    unless specs.nil?
      # Get download strategy hint, if any
      @using = specs.delete :using
      # The rest of the specs are for source control
      @specs = specs
    end
  end

  # Returns a suitable DownloadStrategy class that can be
  # used to retreive this software package.
  def download_strategy
    return detect_download_strategy(@url) if @using.nil?

    # If a class is passed, assume it is a download strategy
    return @using if @using.kind_of? Class

    detected = VCS_SYMBOLS[@using]
    raise "Unknown strategy #{@using} was requested." unless detected
    return detected
  end

  def detect_version
    Pathname.new(@url).version
  end
end


# Derive and define at least @url, see Library/Formula for examples
class Formula
  include FileUtils

  attr_reader :url, :version, :homepage, :name, :specs, :downloader

  # Homebrew determines the name
  def initialize name='__UNKNOWN__'
    set_instance_variable 'homepage'
    set_instance_variable 'url'
    set_instance_variable 'head'
    set_instance_variable 'specs'

    set_instance_variable 'stable'
    set_instance_variable 'unstable'

    if @head and (not @url or ARGV.build_head?)
      @url = @head
      @version = 'HEAD'
      @spec_to_use = @unstable
    else
      if @stable.nil?
        @spec_to_use = SoftwareSpecification.new(@url, @specs)
      else
        @spec_to_use = @stable
      end
    end

    raise "No url provided for formula #{name}" if @url.nil?
    @name=name
    validate_variable :name

    set_instance_variable 'version'
    @version ||= @spec_to_use.detect_version
    validate_variable :version if @version

    CHECKSUM_TYPES.each { |type| set_instance_variable type }

    @downloader=download_strategy.new @spec_to_use.url, name, version, @spec_to_use.specs
  end

  # if the dir is there, but it's empty we consider it not installed
  def installed?
    return prefix.children.length > 0
  rescue
    return false
  end

  def path
    self.class.path name
  end

  def prefix
    validate_variable :name
    validate_variable :version
    HOMEBREW_CELLAR+@name+@version
  end

  def bin;     prefix+'bin'            end
  def doc;     prefix+'share/doc'+name end
  def include; prefix+'include'        end
  def info;    prefix+'share/info'     end
  def lib;     prefix+'lib'            end
  def libexec; prefix+'libexec'        end
  def man;     prefix+'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

  # configuration needs to be preserved past upgrades
  def etc; HOMEBREW_PREFIX+'etc' end
  # generally we don't want var stuff inside the keg
  def var; HOMEBREW_PREFIX+'var' end

  # Use the @spec_to_use to detect the download strategy.
  # Can be overriden to force a custom download strategy
  def download_strategy
    @spec_to_use.download_strategy
  end

  def cached_download
    @downloader.cached_location
  end

  # tell the user about any caveats regarding this package, return a string
  def caveats; nil 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',
  #     :p2 => ['http://moo.com/patch5', 'http://moo.com/patch6']
  #   }
  # 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?
    self.class.keg_only_reason || false
  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? in formulas is now deprecated
  def skip_clean? path
    return true if self.class.skip_clean_all?
    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_variable :name
    validate_variable :version

    stage do
      begin
        patch
        # we allow formulas to do anything they want to the Ruby process
        # so load any deps before this point! And exit asap afterwards
        yield self
      rescue Interrupt, RuntimeError, SystemCallError => e
        raise unless ARGV.debug?
        onoe e.inspect
        puts e.backtrace
        ohai "Rescuing build..."
        if (e.was_running_configure? rescue false) and File.exist? 'config.log'
          puts "It looks like an autotools configure failed."
          puts "Gist 'config.log' and any error output when reporting an issue."
          puts
        end

        puts "When you exit this shell Homebrew will attempt to finalise the installation."
        puts "If nothing is installed or the shell exits with a non-zero error code,"
        puts "Homebrew will abort. The installation prefix is:"
        puts prefix
        ENV['HOMEBREW_DEBUG_INSTALL'] = name
        interactive_shell
      end
    end
  end

  # we don't have a std_autotools variant because autotools is a lot less
  # consistent and the standard parameters are more memorable
  # really Homebrew should determine what works inside brew() then
  # we could add --disable-dependency-tracking when it will work
  def std_cmake_parameters
    # The None part makes cmake use the environment's CFLAGS etc. settings
    "-DCMAKE_INSTALL_PREFIX='#{prefix}' -DCMAKE_BUILD_TYPE=None -Wno-dev"
  end

  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_REPOSITORY}/Library/Formula/*.rb"].map{ |f| File.basename f, '.rb' }.sort
  end

  # an array of all Formula, instantiated
  def self.all
    all = []
    names.each do |n|
      begin
        all << Formula.factory(n)
      rescue
        # Don't let one broken formula break commands.
      end
    end
    return all
  end

  def self.aliases
    Dir["#{HOMEBREW_REPOSITORY}/Library/Aliases/*"].map{ |f| File.basename f }.sort
  end

  def self.factory name
    return name if name.kind_of? Formula
    path = Pathname.new(name)
    if path.absolute?
      require name
      name = path.stem
    else
      require self.path(name)
    end
    begin
      klass_name = self.class_s(name)
      klass = eval(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
    end
    return klass.new(name)
  rescue LoadError
    raise FormulaUnavailableError.new(name)
  end

  def self.path name
    HOMEBREW_REPOSITORY+"Library/Formula/#{name.downcase}.rb"
  end

  def deps
    self.class.deps or []
  end

  def external_deps
    self.class.external_deps
  end

  def fails_with_llvm msg="", data=nil
    return unless (ENV['HOMEBREW_USE_LLVM'] or ARGV.include? '--use-llvm')

    build = data.delete :build rescue nil
    msg = "(No specific reason was given)" if msg.empty?

    opoo "LLVM was requested, but this formula is reported as not working with LLVM:"
    puts msg
    puts "Tested with LLVM build #{build}" unless build == nil
    puts

    if ARGV.force?
      puts "Continuing anyway. If this works, let us know so we can update the\n"+
           "formula to remove the warning."
    else
      puts "Continuing with GCC 4.2 instead.\n"+
           "(Use `brew install --force ...` to force use of LLVM.)"
      ENV.gcc_4_2
    end
  end

protected
  # Pretty titles the command and buffers stdout/stderr
  # Throws if there's an error
  def system cmd, *args
    ohai "#{cmd} #{args*' '}".strip

    if ARGV.verbose?
      safe_system cmd, *args
    else
      rd, wr = IO.pipe
      pid = fork do
{'fraction_non_alphanumeric': 0.07998031926525256, 'fraction_numerical': 0.0034987972884321017, 'mean_word_length': 2.6476570289132604, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 13, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 46, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4009506', 'n_tokens_mistral': 5688, 'n_tokens_neox': 5581, 'n_words': 1948}