<commit_before>require 'formula'
require 'utils'
require 'superenv'

module Homebrew extend self
  def audit
    formula_count = 0
    problem_count = 0

    ff = if ARGV.named.empty?
      Formula
    else
      ARGV.formulae
    end

    ff.each do |f|
      fa = FormulaAuditor.new f
      fa.audit

      unless fa.problems.empty?
        puts "#{f.name}:"
        fa.problems.each { |p| puts " * #{p}" }
        puts
        formula_count += 1
        problem_count += fa.problems.size
      end
    end

    unless problem_count.zero?
      ofail "#{problem_count} problems in #{formula_count} formulae"
    end
  end
end

class Module
  def redefine_const(name, value)
    __send__(:remove_const, name) if const_defined?(name)
    const_set(name, value)
  end
end

# Formula extensions for auditing
class Formula
  def head_only?
    @head and @stable.nil?
  end

  def text
    @text ||= FormulaText.new(@path)
  end
end

class FormulaText
  def initialize path
    @text = path.open('r') { |f| f.read }
  end

  def without_patch
    @text.split("__END__")[0].strip()
  end

  def has_DATA?
    /\bDATA\b/ =~ @text
  end

  def has_END?
    /^__END__$/ =~ @text
  end

  def has_trailing_newline?
    /.+\z/ =~ @text
  end
end

class FormulaAuditor
  attr :f
  attr :text
  attr :problems, true

  BUILD_TIME_DEPS = %W[
    autoconf
    automake
    boost-build
    bsdmake
    cmake
    imake
    intltool
    libtool
    pkg-config
    scons
    smake
    swig
  ]

  def initialize f
    @f = f
    @problems = []
    @text = f.text.without_patch

    # We need to do this in case the formula defines a patch that uses DATA.
    f.class.redefine_const :DATA, ""
  end

  def audit_file
    unless f.path.stat.mode.to_s(8) == "100644"
      problem "Incorrect file permissions: chmod 644 #{f.path}"
    end

    if f.text.has_DATA? and not f.text.has_END?
      problem "'DATA' was found, but no '__END__'"
    end

    if f.text.has_END? and not f.text.has_DATA?
      problem "'__END__' was found, but 'DATA' is not used"
    end

    if f.text.has_trailing_newline?
      problem "File should end with a newline"
    end
  end

  def audit_deps
    problems = []

    # Don't depend_on aliases; use full name
    aliases = Formula.aliases
    f.deps.select { |d| aliases.include? d.name }.each do |d|
      problem "Dependency #{d} is an alias; use the canonical name."
    end

    # Check for things we don't like to depend on.
    # We allow non-Homebrew installs whenever possible.
    f.deps.each do |dep|
      begin
        dep_f = dep.to_formula
      rescue
        problem "Can't find dependency #{dep.name.inspect}."
      end

      dep.options.reject do |opt|
        dep_f.build.has_option?(opt.name)
      end.each do |opt|
        problem "Dependency #{dep} does not define option #{opt.name.inspect}"
      end

      case dep.name
      when "git", "python", "ruby", "emacs", "mysql", "postgresql", "mercurial"
        problem <<-EOS.undent
          Don't use #{dep} as a dependency. We allow non-Homebrew
          #{dep} installations.
          EOS
      when 'gfortran'
        problem "Use ENV.fortran during install instead of depends_on 'gfortran'"
      when 'open-mpi', 'mpich2'
        problem <<-EOS.undent
          There are multiple conflicting ways to install MPI. Use an MPIDependency:
            depends_on MPIDependency.new(<lang list>)
          Where <lang list> is a comma delimited list that can include:
            :cc, :cxx, :f90, :f77
          EOS
      end
    end
  end

  def audit_conflicts
    f.conflicts.each do |req|
      begin
        conflict_f = Formula.factory req.formula
      rescue
        problem "Can't find conflicting formula \"#{req.formula}\"."
      end
    end
  end

  def audit_urls
    unless f.homepage =~ %r[^https?://]
      problem "The homepage should start with http or https."
    end

    # Google Code homepages should end in a slash
    if f.homepage =~ %r[^https?://code\.google\.com/p/[^/]+[^/]$]
      problem "Google Code homepage should end with a slash."
    end

    urls = [(f.stable.url rescue nil), (f.devel.url rescue nil), (f.head.url rescue nil)].compact

    # Check GNU urls; doesn't apply to mirrors
    if urls.any? { |p| p =~ %r[^(https?|ftp)://(.+)/gnu/] }<commit_msg>audit: allow alpha.gnu.org URLs<commit_after>require 'formula'
require 'utils'
require 'superenv'

module Homebrew extend self
  def audit
    formula_count = 0
    problem_count = 0

    ff = if ARGV.named.empty?
      Formula
    else
      ARGV.formulae
    end

    ff.each do |f|
      fa = FormulaAuditor.new f
      fa.audit

      unless fa.problems.empty?
        puts "#{f.name}:"
        fa.problems.each { |p| puts " * #{p}" }
        puts
        formula_count += 1
        problem_count += fa.problems.size
      end
    end

    unless problem_count.zero?
      ofail "#{problem_count} problems in #{formula_count} formulae"
    end
  end
end

class Module
  def redefine_const(name, value)
    __send__(:remove_const, name) if const_defined?(name)
    const_set(name, value)
  end
end

# Formula extensions for auditing
class Formula
  def head_only?
    @head and @stable.nil?
  end

  def text
    @text ||= FormulaText.new(@path)
  end
end

class FormulaText
  def initialize path
    @text = path.open('r') { |f| f.read }
  end

  def without_patch
    @text.split("__END__")[0].strip()
  end

  def has_DATA?
    /\bDATA\b/ =~ @text
  end

  def has_END?
    /^__END__$/ =~ @text
  end

  def has_trailing_newline?
    /.+\z/ =~ @text
  end
end

class FormulaAuditor
  attr :f
  attr :text
  attr :problems, true

  BUILD_TIME_DEPS = %W[
    autoconf
    automake
    boost-build
    bsdmake
    cmake
    imake
    intltool
    libtool
    pkg-config
    scons
    smake
    swig
  ]

  def initialize f
    @f = f
    @problems = []
    @text = f.text.without_patch

    # We need to do this in case the formula defines a patch that uses DATA.
    f.class.redefine_const :DATA, ""
  end

  def audit_file
    unless f.path.stat.mode.to_s(8) == "100644"
      problem "Incorrect file permissions: chmod 644 #{f.path}"
    end

    if f.text.has_DATA? and not f.text.has_END?
      problem "'DATA' was found, but no '__END__'"
    end

    if f.text.has_END? and not f.text.has_DATA?
      problem "'__END__' was found, but 'DATA' is not used"
    end

    if f.text.has_trailing_newline?
      problem "File should end with a newline"
    end
  end

  def audit_deps
    problems = []

    # Don't depend_on aliases; use full name
    aliases = Formula.aliases
    f.deps.select { |d| aliases.include? d.name }.each do |d|
      problem "Dependency #{d} is an alias; use the canonical name."
    end

    # Check for things we don't like to depend on.
    # We allow non-Homebrew installs whenever possible.
    f.deps.each do |dep|
      begin
        dep_f = dep.to_formula
      rescue
        problem "Can't find dependency #{dep.name.inspect}."
      end

      dep.options.reject do |opt|
        dep_f.build.has_option?(opt.name)
      end.each do |opt|
        problem "Dependency #{dep} does not define option #{opt.name.inspect}"
      end

      case dep.name
      when "git", "python", "ruby", "emacs", "mysql", "postgresql", "mercurial"
        problem <<-EOS.undent
          Don't use #{dep} as a dependency. We allow non-Homebrew
          #{dep} installations.
          EOS
      when 'gfortran'
        problem "Use ENV.fortran during install instead of depends_on 'gfortran'"
      when 'open-mpi', 'mpich2'
        problem <<-EOS.undent
          There are multiple conflicting ways to install MPI. Use an MPIDependency:
            depends_on MPIDependency.new(<lang list>)
          Where <lang list> is a comma delimited list that can include:
            :cc, :cxx, :f90, :f77
          EOS
      end
    end
  end

  def audit_conflicts
    f.conflicts.each do |req|
      begin
        conflict_f = Formula.factory req.formula
      rescue
        problem "Can't find conflicting formula \"#{req.formula}\"."
      end
    end
  end

  def audit_urls
    unless f.homepage =~ %r[^https?://]
      problem "The homepage should start with http or https."
    end

    # Google Code homepages should end in a slash
    if f.homepage =~ %r[^https?://code\.google\.com/p/[^/]+[^/]$]
      problem "Google Code homepage should end with a slash."
    end

    urls = [(f.stable.url rescue nil), (f.devel.url rescue nil), (f.head.url rescue nil)].compact

    # Check GNU urls; doesn't apply to mirrors
    if urls.any? { |p| p =~ %r[^(https?|ftp)://(?!alpha).+/gnu/] }
{'fraction_non_alphanumeric': 0.10782831220193091, 'fraction_numerical': 0.00442014656275445, 'mean_word_length': 2.2592873388931007, 'pattern_counts': {'":': 0, '<': 15, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6933074', 'n_tokens_mistral': 3041, 'n_tokens_neox': 2877, 'n_words': 885}