aboutsummaryrefslogtreecommitdiffstats
path: root/Library/Homebrew/cmd
diff options
context:
space:
mode:
authorMike McQuaid2016-09-05 21:37:02 +0100
committerMike McQuaid2016-09-08 20:46:37 +0100
commitaf8605ea4ba1d9856c055c8c76b447e030540e3f (patch)
treed093b11340406c21a4b873a80effe3b068fd07d4 /Library/Homebrew/cmd
parent4f6bae46f9c0f7b713cdbb999318460135f423de (diff)
downloadbrew-af8605ea4ba1d9856c055c8c76b447e030540e3f.tar.bz2
Move developer-focused commands to dev-cmd.
Diffstat (limited to 'Library/Homebrew/cmd')
-rw-r--r--Library/Homebrew/cmd/audit.rb1361
-rw-r--r--Library/Homebrew/cmd/bottle.rb458
-rw-r--r--Library/Homebrew/cmd/create.rb218
-rw-r--r--Library/Homebrew/cmd/edit.rb50
-rw-r--r--Library/Homebrew/cmd/man.rb88
-rw-r--r--Library/Homebrew/cmd/pull.rb575
-rw-r--r--Library/Homebrew/cmd/tap-readme.rb36
-rw-r--r--Library/Homebrew/cmd/test.rb89
-rw-r--r--Library/Homebrew/cmd/tests.rb63
9 files changed, 0 insertions, 2938 deletions
diff --git a/Library/Homebrew/cmd/audit.rb b/Library/Homebrew/cmd/audit.rb
deleted file mode 100644
index 6d1fa055f..000000000
--- a/Library/Homebrew/cmd/audit.rb
+++ /dev/null
@@ -1,1361 +0,0 @@
-#: * `audit` [`--strict`] [`--online`] [`--new-formula`] [`--display-cop-names`] [`--display-filename`] [<formulae>]:
-#: Check <formulae> for Homebrew coding style violations. This should be
-#: run before submitting a new formula.
-#:
-#: If no <formulae> are provided, all of them are checked.
-#:
-#: If `--strict` is passed, additional checks are run, including RuboCop
-#: style checks.
-#:
-#: If `--online` is passed, additional slower checks that require a network
-#: connection are run.
-#:
-#: If `--new-formula` is passed, various additional checks are run that check
-#: if a new formula is eligable for Homebrew. This should be used when creating
-#: new formulae and implies `--strict` and `--online`.
-#:
-#: If `--display-cop-names` is passed, the RuboCop cop name for each violation
-#: is included in the output.
-#:
-#: If `--display-filename` is passed, every line of output is prefixed with the
-#: name of the file or formula being audited, to make the output easy to grep.
-#:
-#: `audit` exits with a non-zero status if any errors are found. This is useful,
-#: for instance, for implementing pre-commit hooks.
-
-# Undocumented options:
-# -D activates debugging and profiling of the audit methods (not the same as --debug)
-
-require "formula"
-require "formula_versions"
-require "utils"
-require "extend/ENV"
-require "formula_cellar_checks"
-require "official_taps"
-require "cmd/search"
-require "cmd/style"
-require "date"
-
-module Homebrew
- def audit
- if ARGV.switch? "D"
- Homebrew.inject_dump_stats!(FormulaAuditor, /^audit_/)
- end
-
- formula_count = 0
- problem_count = 0
-
- new_formula = ARGV.include? "--new-formula"
- strict = new_formula || ARGV.include?("--strict")
- online = new_formula || ARGV.include?("--online")
-
- ENV.activate_extensions!
- ENV.setup_build_environment
-
- if ARGV.named.empty?
- ff = Formula
- files = Tap.map(&:formula_dir)
- else
- ff = ARGV.resolved_formulae
- files = ARGV.resolved_formulae.map(&:path)
- end
-
- if strict
- # Check style in a single batch run up front for performance
- style_results = check_style_json(files, :realpath => true)
- end
-
- ff.each do |f|
- options = { :new_formula => new_formula, :strict => strict, :online => online }
- options[:style_offenses] = style_results.file_offenses(f.path) if strict
- fa = FormulaAuditor.new(f, options)
- fa.audit
-
- next if fa.problems.empty?
- fa.problems
- formula_count += 1
- problem_count += fa.problems.size
- problem_lines = fa.problems.map { |p| "* #{p.chomp.gsub("\n", "\n ")}" }
- if ARGV.include? "--display-filename"
- puts problem_lines.map { |s| "#{f.path}: #{s}" }
- else
- puts "#{f.full_name}:", problem_lines.map { |s| " #{s}" }
- end
- end
-
- unless problem_count.zero?
- problems = "problem" + plural(problem_count)
- formulae = "formula" + plural(formula_count, "e")
- ofail "#{problem_count} #{problems} in #{formula_count} #{formulae}"
- end
- end
-end
-
-class FormulaText
- def initialize(path)
- @text = path.open("rb", &:read)
- @lines = @text.lines.to_a
- end
-
- def without_patch
- @text.split("\n__END__").first
- end
-
- def has_DATA?
- /^[^#]*\bDATA\b/ =~ @text
- end
-
- def has_END?
- /^__END__$/ =~ @text
- end
-
- def has_trailing_newline?
- /\Z\n/ =~ @text
- end
-
- def =~(regex)
- regex =~ @text
- end
-
- def include?(s)
- @text.include? s
- end
-
- def line_number(regex, skip = 0)
- index = @lines.drop(skip).index { |line| line =~ regex }
- index ? index + 1 : nil
- end
-
- def reverse_line_number(regex)
- index = @lines.reverse.index { |line| line =~ regex }
- index ? @lines.count - index : nil
- end
-end
-
-class FormulaAuditor
- include FormulaCellarChecks
-
- attr_reader :formula, :text, :problems
-
- BUILD_TIME_DEPS = %W[
- autoconf
- automake
- boost-build
- bsdmake
- cmake
- godep
- imake
- intltool
- libtool
- pkg-config
- scons
- smake
- sphinx-doc
- swig
- ]
-
- FILEUTILS_METHODS = FileUtils.singleton_methods(false).map { |m| Regexp.escape(m) }.join "|"
-
- def initialize(formula, options = {})
- @formula = formula
- @new_formula = !!options[:new_formula]
- @strict = !!options[:strict]
- @online = !!options[:online]
- # Accept precomputed style offense results, for efficiency
- @style_offenses = options[:style_offenses]
- @problems = []
- @text = FormulaText.new(formula.path)
- @specs = %w[stable devel head].map { |s| formula.send(s) }.compact
- end
-
- def audit_style
- return unless @style_offenses
- display_cop_names = ARGV.include?("--display-cop-names")
- @style_offenses.each do |offense|
- problem offense.to_s(:display_cop_name => display_cop_names)
- end
- end
-
- def component_problem(before, after, offset = 0)
- problem "`#{before[1]}` (line #{before[0] + offset}) should be put before `#{after[1]}` (line #{after[0] + offset})"
- end
-
- # scan in the reverse direction for remaining problems but report problems
- # in the forward direction so that contributors don't reverse the order of
- # lines in the file simply by following instructions
- def audit_components(reverse = true, previous_pair = nil)
- component_list = [
- [/^ include Language::/, "include directive"],
- [/^ desc ["'][\S\ ]+["']/, "desc"],
- [/^ homepage ["'][\S\ ]+["']/, "homepage"],
- [/^ url ["'][\S\ ]+["']/, "url"],
- [/^ mirror ["'][\S\ ]+["']/, "mirror"],
- [/^ version ["'][\S\ ]+["']/, "version"],
- [/^ (sha1|sha256) ["'][\S\ ]+["']/, "checksum"],
- [/^ revision/, "revision"],
- [/^ version_scheme/, "version_scheme"],
- [/^ head ["'][\S\ ]+["']/, "head"],
- [/^ stable do/, "stable block"],
- [/^ bottle do/, "bottle block"],
- [/^ devel do/, "devel block"],
- [/^ head do/, "head block"],
- [/^ bottle (:unneeded|:disable)/, "bottle modifier"],
- [/^ keg_only/, "keg_only"],
- [/^ option/, "option"],
- [/^ depends_on/, "depends_on"],
- [/^ conflicts_with/, "conflicts_with"],
- [/^ (go_)?resource/, "resource"],
- [/^ def install/, "install method"],
- [/^ def caveats/, "caveats method"],
- [/^ (plist_options|def plist)/, "plist block"],
- [/^ test do/, "test block"],
- ]
- if previous_pair
- previous_before = previous_pair[0]
- previous_after = previous_pair[1]
- end
- offset = (previous_after && previous_after[0] && previous_after[0] >= 1) ? previous_after[0] - 1 : 0
- present = component_list.map do |regex, name|
- lineno = if reverse
- text.reverse_line_number regex
- else
- text.line_number regex, offset
- end
- next unless lineno
- [lineno, name]
- end.compact
- no_problem = true
- present.each_cons(2) do |c1, c2|
- if reverse
- # scan in the forward direction from the offset
- audit_components(false, [c1, c2]) if c1[0] > c2[0] # at least one more offense
- elsif c1[0] > c2[0] && (offset == 0 || previous_pair.nil? || (c1[0] + offset) != previous_before[0] || (c2[0] + offset) != previous_after[0])
- component_problem c1, c2, offset
- no_problem = false
- end
- end
- if no_problem && previous_pair
- component_problem previous_before, previous_after
- end
- present
- end
-
- def audit_file
- # Under normal circumstances (umask 0022), we expect a file mode of 644. If
- # the user's umask is more restrictive, respect that by masking out the
- # corresponding bits. (The also included 0100000 flag means regular file.)
- wanted_mode = 0100644 & ~File.umask
- actual_mode = formula.path.stat.mode
- unless actual_mode == wanted_mode
- problem format("Incorrect file permissions (%03o): chmod %03o %s",
- actual_mode & 0777, wanted_mode & 0777, formula.path)
- end
-
- if text.has_DATA? && !text.has_END?
- problem "'DATA' was found, but no '__END__'"
- end
-
- if text.has_END? && !text.has_DATA?
- problem "'__END__' was found, but 'DATA' is not used"
- end
-
- if text =~ /inreplace [^\n]* do [^\n]*\n[^\n]*\.gsub![^\n]*\n\ *end/m
- problem "'inreplace ... do' was used for a single substitution (use the non-block form instead)."
- end
-
- unless text.has_trailing_newline?
- problem "File should end with a newline"
- end
-
- return unless @strict
-
- present = audit_components
-
- present.map!(&:last)
- if present.include?("stable block")
- %w[url checksum mirror].each do |component|
- if present.include?(component)
- problem "`#{component}` should be put inside `stable block`"
- end
- end
- end
- if present.include?("head") && present.include?("head block")
- problem "Should not have both `head` and `head do`"
- end
- if present.include?("bottle modifier") && present.include?("bottle block")
- problem "Should not have `bottle :unneeded/:disable` and `bottle do`"
- end
- end
-
- def audit_class
- if @strict
- unless formula.test_defined?
- problem "A `test do` test block should be added"
- end
- end
-
- classes = %w[GithubGistFormula ScriptFileFormula AmazonWebServicesFormula]
- klass = classes.find do |c|
- Object.const_defined?(c) && formula.class < Object.const_get(c)
- end
-
- problem "#{klass} is deprecated, use Formula instead" if klass
- end
-
- # core aliases + tap alias names + tap alias full name
- @@aliases ||= Formula.aliases + Formula.tap_aliases
-
- def audit_formula_name
- return unless @strict
- # skip for non-official taps
- return if formula.tap.nil? || !formula.tap.official?
-
- name = formula.name
- full_name = formula.full_name
-
- if Formula.aliases.include? name
- problem "Formula name conflicts with existing aliases."
- return
- end
-
- if oldname = CoreTap.instance.formula_renames[name]
- problem "'#{name}' is reserved as the old name of #{oldname}"
- return
- end
-
- if !formula.core_formula? && Formula.core_names.include?(name)
- problem "Formula name conflicts with existing core formula."
- return
- end
-
- @@local_official_taps_name_map ||= Tap.select(&:official?).flat_map(&:formula_names).
- reduce(Hash.new) do |name_map, tap_formula_full_name|
- tap_formula_name = tap_formula_full_name.split("/").last
- name_map[tap_formula_name] ||= []
- name_map[tap_formula_name] << tap_formula_full_name
- name_map
- end
-
- same_name_tap_formulae = @@local_official_taps_name_map[name] || []
-
- if @online
- @@remote_official_taps ||= OFFICIAL_TAPS - Tap.select(&:official?).map(&:repo)
-
- same_name_tap_formulae += @@remote_official_taps.map do |tap|
- Thread.new { Homebrew.search_tap "homebrew", tap, name }
- end.flat_map(&:value)
- end
-
- same_name_tap_formulae.delete(full_name)
-
- unless same_name_tap_formulae.empty?
- problem "Formula name conflicts with #{same_name_tap_formulae.join ", "}"
- end
- end
-
- def audit_deps
- @specs.each do |spec|
- # Check for things we don't like to depend on.
- # We allow non-Homebrew installs whenever possible.
- spec.deps.each do |dep|
- begin
- dep_f = dep.to_formula
- rescue TapFormulaUnavailableError
- # Don't complain about missing cross-tap dependencies
- next
- rescue FormulaUnavailableError
- problem "Can't find dependency #{dep.name.inspect}."
- next
- rescue TapFormulaAmbiguityError
- problem "Ambiguous dependency #{dep.name.inspect}."
- next
- rescue TapFormulaWithOldnameAmbiguityError
- problem "Ambiguous oldname dependency #{dep.name.inspect}."
- next
- end
-
- if dep_f.oldname && dep.name.split("/").last == dep_f.oldname
- problem "Dependency '#{dep.name}' was renamed; use new name '#{dep_f.name}'."
- end
-
- if @@aliases.include?(dep.name)
- problem "Dependency '#{dep.name}' is an alias; use the canonical name '#{dep.to_formula.full_name}'."
- end
-
- dep.options.reject do |opt|
- next true if dep_f.option_defined?(opt)
- dep_f.requirements.detect do |r|
- if r.recommended?
- opt.name == "with-#{r.name}"
- elsif r.optional?
- opt.name == "without-#{r.name}"
- end
- end
- end.each do |opt|
- problem "Dependency #{dep} does not define option #{opt.name.inspect}"
- end
-
- case dep.name
- when *BUILD_TIME_DEPS
- next if dep.build? || dep.run?
- problem <<-EOS.undent
- #{dep} dependency should be
- depends_on "#{dep}" => :build
- Or if it is indeed a runtime dependency
- depends_on "#{dep}" => :run
- EOS
- when "git"
- problem "Don't use git as a dependency"
- when "mercurial"
- problem "Use `depends_on :hg` instead of `depends_on 'mercurial'`"
- when "gfortran"
- problem "Use `depends_on :fortran` instead of `depends_on 'gfortran'`"
- when "ruby"
- problem <<-EOS.undent
- Don't use "ruby" as a dependency. If this formula requires a
- minimum Ruby version not provided by the system you should
- use the RubyRequirement:
- depends_on :ruby => "1.8"
- where "1.8" is the minimum version of Ruby required.
- EOS
- when "open-mpi", "mpich"
- problem <<-EOS.undent
- There are multiple conflicting ways to install MPI. Use an MPIRequirement:
- depends_on :mpi => [<lang list>]
- Where <lang list> is a comma delimited list that can include:
- :cc, :cxx, :f77, :f90
- EOS
- end
- end
- end
- end
-
- def audit_conflicts
- formula.conflicts.each do |c|
- begin
- Formulary.factory(c.name)
- rescue TapFormulaUnavailableError
- # Don't complain about missing cross-tap conflicts.
- next
- rescue FormulaUnavailableError
- problem "Can't find conflicting formula #{c.name.inspect}."
- rescue TapFormulaAmbiguityError, TapFormulaWithOldnameAmbiguityError
- problem "Ambiguous conflicting formula #{c.name.inspect}."
- end
- end
- end
-
- def audit_options
- formula.options.each do |o|
- next unless @strict
- if o.name !~ /with(out)?-/ && o.name != "c++11" && o.name != "universal" && o.name != "32-bit"
- problem "Options should begin with with/without. Migrate '--#{o.name}' with `deprecated_option`."
- end
-
- if o.name =~ /^with(out)?-(?:checks?|tests)$/
- unless formula.deps.any? { |d| d.name == "check" && (d.optional? || d.recommended?) }
- problem "Use '--with#{$1}-test' instead of '--#{o.name}'. Migrate '--#{o.name}' with `deprecated_option`."
- end
- end
- end
- end
-
- def audit_desc
- # For now, only check the description when using `--strict`
- return unless @strict
-
- desc = formula.desc
-
- unless desc && !desc.empty?
- problem "Formula should have a desc (Description)."
- return
- end
-
- # Make sure the formula name plus description is no longer than 80 characters
- # Note full_name includes the name of the tap, while name does not
- linelength = formula.name.length + ": ".length + desc.length
- if linelength > 80
- problem <<-EOS.undent
- Description is too long. \"name: desc\" should be less than 80 characters.
- Length is calculated as #{formula.name} + desc. (currently #{linelength})
- EOS
- end
-
- if desc =~ /([Cc]ommand ?line)/
- problem "Description should use \"command-line\" instead of \"#{$1}\""
- end
-
- if desc =~ /^([Aa]n?)\s/
- problem "Description shouldn't start with an indefinite article (#{$1})"
- end
-
- if desc.downcase.start_with? "#{formula.name} "
- problem "Description shouldn't include the formula name"
- end
- end
-
- def audit_homepage
- homepage = formula.homepage
-
- unless homepage =~ %r{^https?://}
- problem "The homepage should start with http or https (URL is #{homepage})."
- end
-
- # Check for http:// GitHub homepage urls, https:// is preferred.
- # Note: only check homepages that are repo pages, not *.github.com hosts
- if homepage.start_with? "http://github.com/"
- problem "Please use https:// for #{homepage}"
- end
-
- # Savannah has full SSL/TLS support but no auto-redirect.
- # Doesn't apply to the download URLs, only the homepage.
- if homepage.start_with? "http://savannah.nongnu.org/"
- problem "Please use https:// for #{homepage}"
- end
-
- # Freedesktop is complicated to handle - It has SSL/TLS, but only on certain subdomains.
- # To enable https Freedesktop change the URL from http://project.freedesktop.org/wiki to
- # https://wiki.freedesktop.org/project_name.
- # "Software" is redirected to https://wiki.freedesktop.org/www/Software/project_name
- if homepage =~ %r{^http://((?:www|nice|libopenraw|liboil|telepathy|xorg)\.)?freedesktop\.org/(?:wiki/)?}
- if homepage =~ /Software/
- problem "#{homepage} should be styled `https://wiki.freedesktop.org/www/Software/project_name`"
- else
- problem "#{homepage} should be styled `https://wiki.freedesktop.org/project_name`"
- end
- end
-
- # Google Code homepages should end in a slash
- if homepage =~ %r{^https?://code\.google\.com/p/[^/]+[^/]$}
- problem "#{homepage} should end with a slash"
- end
-
- # People will run into mixed content sometimes, but we should enforce and then add
- # exemptions as they are discovered. Treat mixed content on homepages as a bug.
- # Justify each exemptions with a code comment so we can keep track here.
- if homepage =~ %r{^http://[^/]*github\.io/}
- problem "Please use https:// for #{homepage}"
- end
-
- # There's an auto-redirect here, but this mistake is incredibly common too.
- # Only applies to the homepage and subdomains for now, not the FTP URLs.
- if homepage =~ %r{^http://((?:build|cloud|developer|download|extensions|git|glade|help|library|live|nagios|news|people|projects|rt|static|wiki|www)\.)?gnome\.org}
- problem "Please use https:// for #{homepage}"
- end
-
- # Compact the above into this list as we're able to remove detailed notations, etc over time.
- case homepage
- when %r{^http://[^/]*\.apache\.org},
- %r{^http://packages\.debian\.org},
- %r{^http://wiki\.freedesktop\.org/},
- %r{^http://((?:www)\.)?gnupg\.org/},
- %r{^http://ietf\.org},
- %r{^http://[^/.]+\.ietf\.org},
- %r{^http://[^/.]+\.tools\.ietf\.org},
- %r{^http://www\.gnu\.org/},
- %r{^http://code\.google\.com/},
- %r{^http://bitbucket\.org/},
- %r{^http://(?:[^/]*\.)?archive\.org}
- problem "Please use https:// for #{homepage}"
- end
-
- return unless @online
- begin
- nostdout { curl "--connect-timeout", "15", "-o", "/dev/null", homepage }
- rescue ErrorDuringExecution
- problem "The homepage is not reachable (curl exit code #{$?.exitstatus})"
- end
- end
-
- def audit_bottle_spec
- if formula.bottle_disabled? && !formula.bottle_disable_reason.valid?
- problem "Unrecognized bottle modifier"
- end
- end
-
- def audit_github_repository
- return unless @online
- return unless @new_formula
-
- regex = %r{https?://github\.com/([^/]+)/([^/]+)/?.*}
- _, user, repo = *regex.match(formula.stable.url) if formula.stable
- _, user, repo = *regex.match(formula.homepage) unless user
- return if !user || !repo
-
- repo.gsub!(/.git$/, "")
-
- begin
- metadata = GitHub.repository(user, repo)
- rescue GitHub::HTTPNotFoundError
- return
- end
-
- return if metadata.nil?
-
- problem "GitHub fork (not canonical repository)" if metadata["fork"]
- if (metadata["forks_count"] < 20) && (metadata["subscribers_count"] < 20) &&
- (metadata["stargazers_count"] < 50)
- problem "GitHub repository not notable enough (<20 forks, <20 watchers and <50 stars)"
- end
-
- if Date.parse(metadata["created_at"]) > (Date.today - 30)
- problem "GitHub repository too new (<30 days old)"
- end
- end
-
- def audit_specs
- if head_only?(formula) && formula.tap.to_s.downcase !~ %r{[-/]head-only$}
- problem "Head-only (no stable download)"
- end
-
- if devel_only?(formula) && formula.tap.to_s.downcase !~ %r{[-/]devel-only$}
- problem "Devel-only (no stable download)"
- end
-
- %w[Stable Devel HEAD].each do |name|
- next unless spec = formula.send(name.downcase)
-
- ra = ResourceAuditor.new(spec).audit
- problems.concat ra.problems.map { |problem| "#{name}: #{problem}" }
-
- spec.resources.each_value do |resource|
- ra = ResourceAuditor.new(resource).audit
- problems.concat ra.problems.map { |problem|
- "#{name} resource #{resource.name.inspect}: #{problem}"
- }
- end
-
- spec.patches.each { |p| audit_patch(p) if p.external? }
- end
-
- %w[Stable Devel].each do |name|
- next unless spec = formula.send(name.downcase)
- version = spec.version
- if version.to_s !~ /\d/
- problem "#{name}: version (#{version}) is set to a string without a digit"
- end
- end
-
- if formula.stable && formula.devel
- if formula.devel.version < formula.stable.version
- problem "devel version #{formula.devel.version} is older than stable version #{formula.stable.version}"
- elsif formula.devel.version == formula.stable.version
- problem "stable and devel versions are identical"
- end
- end
-
- stable = formula.stable
- case stable && stable.url
- when %r{download\.gnome\.org/sources}, %r{ftp\.gnome\.org/pub/GNOME/sources}i
- version = Version.parse(stable.url)
- if version >= Version.create("1.0")
- minor_version = version.to_s.split(".", 3)[1].to_i
- if minor_version.odd?
- problem "#{stable.version} is a development release"
- end
- end
- end
- end
-
- def audit_revision_and_version_scheme
- return unless formula.tap # skip formula not from core or any taps
- return unless formula.tap.git? # git log is required
-
- fv = FormulaVersions.new(formula, :max_depth => 10)
- attributes = [:revision, :version_scheme]
- attributes_map = fv.version_attributes_map(attributes, "origin/master")
-
- attributes.each do |attribute|
- attributes_for_version = attributes_map[attribute][formula.version]
- if !attributes_for_version.empty?
- if formula.send(attribute) < attributes_for_version.max
- problem "#{attribute} should not decrease"
- end
- end
- end
-
- revision_map = attributes_map[:revision]
- if formula.revision != 0
- if formula.stable
- if revision_map[formula.stable.version].empty? # check stable spec
- problem "'revision #{formula.revision}' should be removed"
- end
- else # head/devel-only formula
- problem "'revision #{formula.revision}' should be removed"
- end
- end
- end
-
- def audit_legacy_patches
- return unless formula.respond_to?(:patches)
- legacy_patches = Patch.normalize_legacy_patches(formula.patches).grep(LegacyPatch)
- unless legacy_patches.empty?
- problem "Use the patch DSL instead of defining a 'patches' method"
- legacy_patches.each { |p| audit_patch(p) }
- end
- end
-
- def audit_patch(patch)
- case patch.url
- when /raw\.github\.com/, %r{gist\.github\.com/raw}, %r{gist\.github\.com/.+/raw},
- %r{gist\.githubusercontent\.com/.+/raw}
- unless patch.url =~ /[a-fA-F0-9]{40}/
- problem "GitHub/Gist patches should specify a revision:\n#{patch.url}"
- end
- when %r{https?://patch-diff\.githubusercontent\.com/raw/(.+)/(.+)/pull/(.+)\.(?:diff|patch)}
- problem <<-EOS.undent
- use GitHub pull request URLs:
- https://github.com/#{$1}/#{$2}/pull/#{$3}.patch
- Rather than patch-diff:
- #{patch.url}
- EOS
- when %r{macports/trunk}
- problem "MacPorts patches should specify a revision instead of trunk:\n#{patch.url}"
- when %r{^http://trac\.macports\.org}
- problem "Patches from MacPorts Trac should be https://, not http:\n#{patch.url}"
- when %r{^http://bugs\.debian\.org}
- problem "Patches from Debian should be https://, not http:\n#{patch.url}"
- end
- end
-
- def audit_text
- if text =~ /system\s+['"]scons/
- problem "use \"scons *args\" instead of \"system 'scons', *args\""
- end
-
- if text =~ /system\s+['"]xcodebuild/
- problem %(use "xcodebuild *args" instead of "system 'xcodebuild', *args")
- end
-
- if text =~ /xcodebuild[ (]["'*]/ && !text.include?("SYMROOT=")
- problem %(xcodebuild should be passed an explicit "SYMROOT")
- end
-
- if text.include? "Formula.factory("
- problem "\"Formula.factory(name)\" is deprecated in favor of \"Formula[name]\""
- end
-
- if text.include?("def plist") && !text.include?("plist_options")
- problem "Please set plist_options when using a formula-defined plist."
- end
-
- if text.include?('require "language/go"') && !text.include?("go_resource")
- problem "require \"language/go\" is unnecessary unless using `go_resource`s"
- end
- end
-
- def audit_line(line, lineno)
- if line =~ /<(Formula|AmazonWebServicesFormula|ScriptFileFormula|GithubGistFormula)/
- problem "Use a space in class inheritance: class Foo < #{$1}"
- end
-
- # Commented-out cmake support from default template
- if line.include?('# system "cmake')
- problem "Commented cmake call found"
- end
-
- # Comments from default template
- [
- "# PLEASE REMOVE",
- "# Documentation:",
- "# if this fails, try separate make/make install steps",
- "# The URL of the archive",
- "## Naming --",
- "# if your formula requires any X11/XQuartz components",
- "# if your formula fails when building in parallel",
- "# Remove unrecognized options if warned by configure",
- ].each do |comment|
- if line.include? comment
- problem "Please remove default template comments"
- end
- end
-
- # FileUtils is included in Formula
- # encfs modifies a file with this name, so check for some leading characters
- if line =~ /[^'"\/]FileUtils\.(\w+)/
- problem "Don't need 'FileUtils.' before #{$1}."
- end
-
- # Check for long inreplace block vars
- if line =~ /inreplace .* do \|(.{2,})\|/
- problem "\"inreplace <filenames> do |s|\" is preferred over \"|#{$1}|\"."
- end
-
- # Check for string interpolation of single values.
- if line =~ /(system|inreplace|gsub!|change_make_var!).*[ ,]"#\{([\w.]+)\}"/
- problem "Don't need to interpolate \"#{$2}\" with #{$1}"
- end
-
- # Check for string concatenation; prefer interpolation
- if line =~ /(#\{\w+\s*\+\s*['"][^}]+\})/
- problem "Try not to concatenate paths in string interpolation:\n #{$1}"
- end
-
- # Prefer formula path shortcuts in Pathname+
- if line =~ %r{\(\s*(prefix\s*\+\s*(['"])(bin|include|libexec|lib|sbin|share|Frameworks)[/'"])}
- problem "\"(#{$1}...#{$2})\" should be \"(#{$3.downcase}+...)\""
- end
-
- if line =~ /((man)\s*\+\s*(['"])(man[1-8])(['"]))/
- problem "\"#{$1}\" should be \"#{$4}\""
- end
-
- # Prefer formula path shortcuts in strings
- if line =~ %r[(\#\{prefix\}/(bin|include|libexec|lib|sbin|share|Frameworks))]
- problem "\"#{$1}\" should be \"\#{#{$2.downcase}}\""
- end
-
- if line =~ %r[((\#\{prefix\}/share/man/|\#\{man\}/)(man[1-8]))]
- problem "\"#{$1}\" should be \"\#{#{$3}}\""
- end
-
- if line =~ %r[((\#\{share\}/(man)))[/'"]]
- problem "\"#{$1}\" should be \"\#{#{$3}}\""
- end
-
- if line =~ %r[(\#\{prefix\}/share/(info|man))]
- problem "\"#{$1}\" should be \"\#{#{$2}}\""
- end
-
- if line =~ /depends_on :(automake|autoconf|libtool)/
- problem ":#{$1} is deprecated. Usage should be \"#{$1}\""
- end
-
- # Commented-out depends_on
- if line =~ /#\s*depends_on\s+(.+)\s*$/
- problem "Commented-out dep #{$1}"
- end
-
- # No trailing whitespace, please
- if line =~ /[\t ]+$/
- problem "#{lineno}: Trailing whitespace was found"
- end
-
- if line =~ /if\s+ARGV\.include\?\s+'--(HEAD|devel)'/
- problem "Use \"if build.#{$1.downcase}?\" instead"
- end
-
- if line.include?("make && make")
- problem "Use separate make calls"
- end
-
- if line =~ /^[ ]*\t/
- problem "Use spaces instead of tabs for indentation"
- end
-
- if line.include?("ENV.x11")
- problem "Use \"depends_on :x11\" instead of \"ENV.x11\""
- end
-
- # Avoid hard-coding compilers
- if line =~ %r{(system|ENV\[.+\]\s?=)\s?['"](/usr/bin/)?(gcc|llvm-gcc|clang)['" ]}
- problem "Use \"\#{ENV.cc}\" instead of hard-coding \"#{$3}\""
- end
-
- if line =~ %r{(system|ENV\[.+\]\s?=)\s?['"](/usr/bin/)?((g|llvm-g|clang)\+\+)['" ]}
- problem "Use \"\#{ENV.cxx}\" instead of hard-coding \"#{$3}\""
- end
-
- if line =~ /system\s+['"](env|export)(\s+|['"])/
- problem "Use ENV instead of invoking '#{$1}' to modify the environment"
- end
-
- if line =~ /version == ['"]HEAD['"]/
- problem "Use 'build.head?' instead of inspecting 'version'"
- end
-
- if line =~ /build\.include\?[\s\(]+['"]\-\-(.*)['"]/
- problem "Reference '#{$1}' without dashes"
- end
-
- if line =~ /build\.include\?[\s\(]+['"]with(out)?-(.*)['"]/
- problem "Use build.with#{$1}? \"#{$2}\" instead of build.include? 'with#{$1}-#{$2}'"
- end
-
- if line =~ /build\.with\?[\s\(]+['"]-?-?with-(.*)['"]/
- problem "Don't duplicate 'with': Use `build.with? \"#{$1}\"` to check for \"--with-#{$1}\""
- end
-
- if line =~ /build\.without\?[\s\(]+['"]-?-?without-(.*)['"]/
- problem "Don't duplicate 'without': Use `build.without? \"#{$1}\"` to check for \"--without-#{$1}\""
- end
-
- if line =~ /unless build\.with\?(.*)/
- problem "Use if build.without?#{$1} instead of unless build.with?#{$1}"
- end
-
- if line =~ /unless build\.without\?(.*)/
- problem "Use if build.with?#{$1} instead of unless build.without?#{$1}"
- end
-
- if line =~ /(not\s|!)\s*build\.with?\?/
- problem "Don't negate 'build.without?': use 'build.with?'"
- end
-
- if line =~ /(not\s|!)\s*build\.without?\?/
- problem "Don't negate 'build.with?': use 'build.without?'"
- end
-
- if line =~ /ARGV\.(?!(debug\?|verbose\?|value[\(\s]))/
- problem "Use build instead of ARGV to check options"
- end
-
- if line.include?("def options")
- problem "Use new-style option definitions"
- end
-
- if line.end_with?("def test")
- problem "Use new-style test definitions (test do)"
- end
-
- if line.include?("MACOS_VERSION")
- problem "Use MacOS.version instead of MACOS_VERSION"
- end
-
- if line.include?("MACOS_FULL_VERSION")
- problem "Use MacOS.full_version instead of MACOS_FULL_VERSION"
- end
-
- cats = %w[leopard snow_leopard lion mountain_lion].join("|")
- if line =~ /MacOS\.(?:#{cats})\?/
- problem "\"#{$&}\" is deprecated, use a comparison to MacOS.version instead"
- end
-
- if line =~ /skip_clean\s+:all/
- problem "`skip_clean :all` is deprecated; brew no longer strips symbols\n" \
- "\tPass explicit paths to prevent Homebrew from removing empty folders."
- end
-
- if line =~ /depends_on [A-Z][\w:]+\.new$/
- problem "`depends_on` can take requirement classes instead of instances"
- end
-
- if line =~ /^def (\w+).*$/
- problem "Define method #{$1.inspect} in the class body, not at the top-level"
- end
-
- if line.include?("ENV.fortran") && !formula.requirements.map(&:class).include?(FortranRequirement)
- problem "Use `depends_on :fortran` instead of `ENV.fortran`"
- end
-
- if line =~ /JAVA_HOME/i && !formula.requirements.map(&:class).include?(JavaRequirement)
- problem "Use `depends_on :java` to set JAVA_HOME"
- end
-
- if line =~ /depends_on :(.+) (if.+|unless.+)$/
- audit_conditional_dep($1.to_sym, $2, $&)
- end
-
- if line =~ /depends_on ['"](.+)['"] (if.+|unless.+)$/
- audit_conditional_dep($1, $2, $&)
- end
-
- if line =~ /(Dir\[("[^\*{},]+")\])/
- problem "#{$1} is unnecessary; just use #{$2}"
- end
-
- if line =~ /system (["'](#{FILEUTILS_METHODS})["' ])/o
- system = $1
- method = $2
- problem "Use the `#{method}` Ruby method instead of `system #{system}`"
- end
-
- if line =~ /assert [^!]+\.include?/
- problem "Use `assert_match` instead of `assert ...include?`"
- end
-
- if line.include?('system "npm", "install"') && !line.include?("Language::Node") && formula.name !~ /^kibana(\d{2})?$/
- problem "Use Language::Node for npm install args"
- end
-
- if @strict
- if line =~ /system ((["'])[^"' ]*(?:\s[^"' ]*)+\2)/
- bad_system = $1
- unless %w[| < > & ; *].any? { |c| bad_system.include? c }
- good_system = bad_system.gsub(" ", "\", \"")
- problem "Use `system #{good_system}` instead of `system #{bad_system}` "
- end
- end
-
- if line =~ /(require ["']formula["'])/
- problem "`#{$1}` is now unnecessary"
- end
-
- if line =~ %r{#\{share\}/#{Regexp.escape(formula.name)}[/'"]}
- problem "Use \#{pkgshare} instead of \#{share}/#{formula.name}"
- end
-
- if line =~ %r{share(\s*[/+]\s*)(['"])#{Regexp.escape(formula.name)}(?:\2|/)}
- problem "Use pkgshare instead of (share#{$1}\"#{formula.name}\")"
- end
- end
- end
-
- def audit_caveats
- caveats = formula.caveats.to_s
-
- if caveats.include?("setuid")
- problem "Don't recommend setuid in the caveats, suggest sudo instead."
- end
- end
-
- def audit_reverse_migration
- # Only enforce for new formula being re-added to core and official taps
- return unless @strict
- return unless formula.tap && formula.tap.official?
-
- if formula.tap.tap_migrations.key?(formula.name)
- problem <<-EOS.undent
- #{formula.name} seems to be listed in tap_migrations.json!
- Please remove #{formula.name} from present tap & tap_migrations.json
- before submitting it to Homebrew/homebrew-#{formula.tap.repo}.
- EOS
- end
- end
-
- def audit_prefix_has_contents
- return unless formula.prefix.directory?
-
- if Keg.new(formula.prefix).empty_installation?
- problem <<-EOS.undent
- The installation seems to be empty. Please ensure the prefix
- is set correctly and expected files are installed.
- The prefix configure/make argument may be case-sensitive.
- EOS
- end
- end
-
- def audit_conditional_dep(dep, condition, line)
- quoted_dep = quote_dep(dep)
- dep = Regexp.escape(dep.to_s)
-
- case condition
- when /if build\.include\? ['"]with-#{dep}['"]$/, /if build\.with\? ['"]#{dep}['"]$/
- problem %(Replace #{line.inspect} with "depends_on #{quoted_dep} => :optional")
- when /unless build\.include\? ['"]without-#{dep}['"]$/, /unless build\.without\? ['"]#{dep}['"]$/
- problem %(Replace #{line.inspect} with "depends_on #{quoted_dep} => :recommended")
- end
- end
-
- def quote_dep(dep)
- Symbol === dep ? dep.inspect : "'#{dep}'"
- end
-
- def audit_check_output(output)
- problem(output) if output
- end
-
- def audit
- audit_file
- audit_formula_name
- audit_class
- audit_specs
- audit_revision_and_version_scheme
- audit_desc
- audit_homepage
- audit_bottle_spec
- audit_github_repository
- audit_deps
- audit_conflicts
- audit_options
- audit_legacy_patches
- audit_text
- audit_caveats
- text.without_patch.split("\n").each_with_index { |line, lineno| audit_line(line, lineno+1) }
- audit_installed
- audit_prefix_has_contents
- audit_reverse_migration
- audit_style
- end
-
- private
-
- def problem(p)
- @problems << p
- end
-
- def head_only?(formula)
- formula.head && formula.devel.nil? && formula.stable.nil?
- end
-
- def devel_only?(formula)
- formula.devel && formula.stable.nil?
- end
-end
-
-class ResourceAuditor
- attr_reader :problems
- attr_reader :version, :checksum, :using, :specs, :url, :mirrors, :name
-
- def initialize(resource)
- @name = resource.name
- @version = resource.version
- @checksum = resource.checksum
- @url = resource.url
- @mirrors = resource.mirrors
- @using = resource.using
- @specs = resource.specs
- @problems = []
- end
-
- def audit
- audit_version
- audit_checksum
- audit_download_strategy
- audit_urls
- self
- end
-
- def audit_version
- if version.nil?
- problem "missing version"
- elsif version.to_s.empty?
- problem "version is set to an empty string"
- elsif !version.detected_from_url?
- version_text = version
- version_url = Version.detect(url, specs)
- if version_url.to_s == version_text.to_s && version.instance_of?(Version)
- problem "version #{version_text} is redundant with version scanned from URL"
- end
- end
-
- if version.to_s.start_with?("v")
- problem "version #{version} should not have a leading 'v'"
- end
-
- if version.to_s =~ /_\d+$/
- problem "version #{version} should not end with an underline and a number"
- end
- end
-
- def audit_checksum
- return unless checksum
-
- case checksum.hash_type
- when :md5
- problem "MD5 checksums are deprecated, please use SHA256"
- return
- when :sha1
- problem "SHA1 checksums are deprecated, please use SHA256"
- return
- when :sha256 then len = 64
- end
-
- if checksum.empty?
- problem "#{checksum.hash_type} is empty"
- else
- problem "#{checksum.hash_type} should be #{len} characters" unless checksum.hexdigest.length == len
- problem "#{checksum.hash_type} contains invalid characters" unless checksum.hexdigest =~ /^[a-fA-F0-9]+$/
- problem "#{checksum.hash_type} should be lowercase" unless checksum.hexdigest == checksum.hexdigest.downcase
- end
- end
-
- def audit_download_strategy
- if url =~ %r{^(cvs|bzr|hg|fossil)://} || url =~ %r{^(svn)\+http://}
- problem "Use of the #{$&} scheme is deprecated, pass `:using => :#{$1}` instead"
- end
-
- url_strategy = DownloadStrategyDetector.detect(url)
-
- if using == :git || url_strategy == GitDownloadStrategy
- if specs[:tag] && !specs[:revision]
- problem "Git should specify :revision when a :tag is specified."
- end
- end
-
- return unless using
-
- if using == :ssl3 || \
- (Object.const_defined?("CurlSSL3DownloadStrategy") && using == CurlSSL3DownloadStrategy)
- problem "The SSL3 download strategy is deprecated, please choose a different URL"
- elsif (Object.const_defined?("CurlUnsafeDownloadStrategy") && using == CurlUnsafeDownloadStrategy) || \
- (Object.const_defined?("UnsafeSubversionDownloadStrategy") && using == UnsafeSubversionDownloadStrategy)
- problem "#{using.name} is deprecated, please choose a different URL"
- end
-
- if using == :cvs
- mod = specs[:module]
-
- if mod == name
- problem "Redundant :module value in URL"
- end
-
- if url =~ %r{:[^/]+$}
- mod = url.split(":").last
-
- if mod == name
- problem "Redundant CVS module appended to URL"
- else
- problem "Specify CVS module as `:module => \"#{mod}\"` instead of appending it to the URL"
- end
- end
- end
-
- using_strategy = DownloadStrategyDetector.detect("", using)
-
- if url_strategy == using_strategy
- problem "Redundant :using value in URL"
- end
- end
-
- def audit_urls
- # Check GNU urls; doesn't apply to mirrors
- if url =~ %r{^(?:https?|ftp)://(?!alpha).+/gnu/}
- problem "Please use \"https://ftpmirror.gnu.org\" instead of #{url}."
- end
-
- if mirrors.include?(url)
- problem "URL should not be duplicated as a mirror: #{url}"
- end
-
- urls = [url] + mirrors
-
- # Check a variety of SSL/TLS URLs that don't consistently auto-redirect
- # or are overly common errors that need to be reduced & fixed over time.
- urls.each do |p|
- case p
- when %r{^http://ftp\.gnu\.org/},
- %r{^http://ftpmirror\.gnu\.org/},
- %r{^http://download\.savannah\.gnu\.org/},
- %r{^http://download-mirror\.savannah\.gnu\.org/},
- %r{^http://[^/]*\.apache\.org/},
- %r{^http://code\.google\.com/},
- %r{^http://fossies\.org/},
- %r{^http://mirrors\.kernel\.org/},
- %r{^http://(?:[^/]*\.)?bintray\.com/},
- %r{^http://tools\.ietf\.org/},
- %r{^http://launchpad\.net/},
- %r{^http://bitbucket\.org/},
- %r{^http://anonscm\.debian\.org/},
- %r{^http://cpan\.metacpan\.org/},
- %r{^http://hackage\.haskell\.org/},
- %r{^http://(?:[^/]*\.)?archive\.org},
- %r{^http://(?:[^/]*\.)?freedesktop\.org},
- %r{^http://(?:[^/]*\.)?mirrorservice\.org/}
- problem "Please use https:// for #{p}"
- when %r{^http://search\.mcpan\.org/CPAN/(.*)}i
- problem "#{p} should be `https://cpan.metacpan.org/#{$1}`"
- when %r{^(http|ftp)://ftp\.gnome\.org/pub/gnome/(.*)}i
- problem "#{p} should be `https://download.gnome.org/#{$2}`"
- when %r{^git://anonscm\.debian\.org/users/(.*)}i
- problem "#{p} should be `https://anonscm.debian.org/git/users/#{$1}`"
- end
- end
-
- # Prefer HTTP/S when possible over FTP protocol due to possible firewalls.
- urls.each do |p|
- case p
- when %r{^ftp://ftp\.mirrorservice\.org}
- problem "Please use https:// for #{p}"
- when %r{^ftp://ftp\.cpan\.org/pub/CPAN(.*)}i
- problem "#{p} should be `http://search.cpan.org/CPAN#{$1}`"
- end
- end
-
- # Check SourceForge urls
- urls.each do |p|
- # Skip if the URL looks like a SVN repo
- next if p.include? "/svnroot/"
- next if p.include? "svn.sourceforge"
-
- # Is it a sourceforge http(s) URL?
- next unless p =~ %r{^https?://.*\b(sourceforge|sf)\.(com|net)}
-
- if p =~ /(\?|&)use_mirror=/
- problem "Don't use #{$1}use_mirror in SourceForge urls (url is #{p})."
- end
-
- if p.end_with?("/download")
- problem "Don't use /download in SourceForge urls (url is #{p})."
- end
-
- if p =~ %r{^https?://sourceforge\.}
- problem "Use https://downloads.sourceforge.net to get geolocation (url is #{p})."
- end
-
- if p =~ %r{^https?://prdownloads\.}
- problem "Don't use prdownloads in SourceForge urls (url is #{p}).\n" \
- "\tSee: http://librelist.com/browser/homebrew/2011/1/12/prdownloads-is-bad/"
- end
-
- if p =~ %r{^http://\w+\.dl\.}
- problem "Don't use specific dl mirrors in SourceForge urls (url is #{p})."
- end
-
- if p.start_with? "http://downloads"
- problem "Please use https:// for #{p}"
- end
- end
-
- # Debian has an abundance of secure mirrors. Let's not pluck the insecure
- # one out of the grab bag.
- urls.each do |u|
- next unless u =~ %r{^http://http\.debian\.net/debian/(.*)}i
- problem <<-EOS.undent
- Please use a secure mirror for Debian URLs.
- We recommend:
- https://mirrors.ocf.berkeley.edu/debian/#{$1}
- EOS
- end
-
- # Check for Google Code download urls, https:// is preferred
- # Intentionally not extending this to SVN repositories due to certificate
- # issues.
- urls.grep(%r{^http://.*\.googlecode\.com/files.*}) do |u|
- problem "Please use https:// for #{u}"
- end
-
- # Check for new-url Google Code download urls, https:// is preferred
- urls.grep(%r{^http://code\.google\.com/}) do |u|
- problem "Please use https:// for #{u}"
- end
-
- # Check for git:// GitHub repo urls, https:// is preferred.
- urls.grep(%r{^git://[^/]*github\.com/}) do |u|
- problem "Please use https:// for #{u}"
- end
-
- # Check for git:// Gitorious repo urls, https:// is preferred.
- urls.grep(%r{^git://[^/]*gitorious\.org/}) do |u|
- problem "Please use https:// for #{u}"
- end
-
- # Check for http:// GitHub repo urls, https:// is preferred.
- urls.grep(%r{^http://github\.com/.*\.git$}) do |u|
- problem "Please use https:// for #{u}"
- end
-
- # Use new-style archive downloads
- urls.each do |u|
- next unless u =~ %r{https://.*github.*/(?:tar|zip)ball/} && u !~ /\.git$/
- problem "Use /archive/ URLs for GitHub tarballs (url is #{u})."
- end
-
- # Don't use GitHub .zip files
- urls.each do |u|
- next unless u =~ %r{https://.*github.*/(archive|releases)/.*\.zip$} && u !~ %r{releases/download}
- problem "Use GitHub tarballs rather than zipballs (url is #{u})."
- end
-
- # Don't use GitHub codeload URLs
- urls.each do |u|
- next unless u =~ %r{https?://codeload\.github\.com/(.+)/(.+)/(?:tar\.gz|zip)/(.+)}
- problem <<-EOS.undent
- use GitHub archive URLs:
- https://github.com/#{$1}/#{$2}/archive/#{$3}.tar.gz
- Rather than codeload:
- #{u}
- EOS
- end
-
- # Check for Maven Central urls, prefer HTTPS redirector over specific host
- urls.each do |u|
- next unless u =~ %r{https?://(?:central|repo\d+)\.maven\.org/maven2/(.+)$}
- problem "#{u} should be `https://search.maven.org/remotecontent?filepath=#{$1}`"
- end
- end
-
- def problem(text)
- @problems << text
- end
-end
diff --git a/Library/Homebrew/cmd/bottle.rb b/Library/Homebrew/cmd/bottle.rb
deleted file mode 100644
index 1980fbe9d..000000000
--- a/Library/Homebrew/cmd/bottle.rb
+++ /dev/null
@@ -1,458 +0,0 @@
-#: @hide_from_man_page
-#: * `bottle` [`--verbose`] [`--no-rebuild`] [`--keep-old`] [`--skip-relocation`] [`--root-url=<root_url>`]:
-#: * `bottle` `--merge` [`--no-commit`] [`--keep-old`] [`--write`]:
-#:
-#: Generate a bottle (binary package) from a formula installed with
-#: `--build-bottle`.
-
-require "formula"
-require "utils/bottles"
-require "tab"
-require "keg"
-require "formula_versions"
-require "utils/inreplace"
-require "erb"
-require "extend/pathname"
-
-BOTTLE_ERB = <<-EOS
- bottle do
- <% if !root_url.start_with?(BottleSpecification::DEFAULT_DOMAIN) %>
- root_url "<%= root_url %>"
- <% end %>
- <% if prefix != BottleSpecification::DEFAULT_PREFIX %>
- prefix "<%= prefix %>"
- <% end %>
- <% if cellar.is_a? Symbol %>
- cellar :<%= cellar %>
- <% elsif cellar != BottleSpecification::DEFAULT_CELLAR %>
- cellar "<%= cellar %>"
- <% end %>
- <% if rebuild > 0 %>
- rebuild <%= rebuild %>
- <% end %>
- <% checksums.each do |checksum_type, checksum_values| %>
- <% checksum_values.each do |checksum_value| %>
- <% checksum, osx = checksum_value.shift %>
- <%= checksum_type %> "<%= checksum %>" => :<%= osx %>
- <% end %>
- <% end %>
- end
-EOS
-
-MAXIMUM_STRING_MATCHES = 100
-
-module Homebrew
- def keg_contain?(string, keg, ignores)
- @put_string_exists_header, @put_filenames = nil
-
- def print_filename(string, filename)
- unless @put_string_exists_header
- opoo "String '#{string}' still exists in these files:"
- @put_string_exists_header = true
- end
-
- @put_filenames ||= []
- unless @put_filenames.include? filename
- puts "#{Tty.red}#{filename}#{Tty.reset}"
- @put_filenames << filename
- end
- end
-
- result = false
-
- keg.each_unique_file_matching(string) do |file|
- # skip document file.
- next if Metafiles::EXTENSIONS.include? file.extname
-
- linked_libraries = Keg.file_linked_libraries(file, string)
- result ||= !linked_libraries.empty?
-
- if ARGV.verbose?
- print_filename(string, file) unless linked_libraries.empty?
- linked_libraries.each do |lib|
- puts " #{Tty.gray}-->#{Tty.reset} links to #{lib}"
- end
- end
-
- text_matches = []
-
- # Use strings to search through the file for each string
- Utils.popen_read("strings", "-t", "x", "-", file.to_s) do |io|
- until io.eof?
- str = io.readline.chomp
- next if ignores.any? { |i| i =~ str }
- next unless str.include? string
- offset, match = str.split(" ", 2)
- next if linked_libraries.include? match # Don't bother reporting a string if it was found by otool
-
- result = true
- text_matches << [match, offset]
- end
- end
-
- if ARGV.verbose? && !text_matches.empty?
- print_filename string, file
- text_matches.first(MAXIMUM_STRING_MATCHES).each do |match, offset|
- puts " #{Tty.gray}-->#{Tty.reset} match '#{match}' at offset #{Tty.em}0x#{offset}#{Tty.reset}"
- end
-
- if text_matches.size > MAXIMUM_STRING_MATCHES
- puts "Only the first #{MAXIMUM_STRING_MATCHES} matches were output"
- end
- end
- end
-
- keg_contain_absolute_symlink_starting_with?(string, keg) || result
- end
-
- def keg_contain_absolute_symlink_starting_with?(string, keg)
- absolute_symlinks_start_with_string = []
- keg.find do |pn|
- if pn.symlink? && (link = pn.readlink).absolute?
- if link.to_s.start_with?(string)
- absolute_symlinks_start_with_string << pn
- end
- end
- end
-
- if ARGV.verbose?
- unless absolute_symlinks_start_with_string.empty?
- opoo "Absolute symlink starting with #{string}:"
- absolute_symlinks_start_with_string.each do |pn|
- puts " #{pn} -> #{pn.resolved_path}"
- end
- end
- end
-
- !absolute_symlinks_start_with_string.empty?
- end
-
- def bottle_output(bottle)
- erb = ERB.new BOTTLE_ERB
- erb.result(bottle.instance_eval { binding }).gsub(/^\s*$\n/, "")
- end
-
- def bottle_formula(f)
- unless f.installed?
- return ofail "Formula not installed or up-to-date: #{f.full_name}"
- end
-
- unless f.tap
- return ofail "Formula not from core or any taps: #{f.full_name}"
- end
-
- if f.bottle_disabled?
- ofail "Formula has disabled bottle: #{f.full_name}"
- puts f.bottle_disable_reason
- return
- end
-
- unless Utils::Bottles::built_as? f
- return ofail "Formula not installed with '--build-bottle': #{f.full_name}"
- end
-
- unless f.stable
- return ofail "Formula has no stable version: #{f.full_name}"
- end
-
- if ARGV.include? "--no-rebuild"
- rebuild = 0
- elsif ARGV.include? "--keep-old"
- rebuild = f.bottle_specification.rebuild
- else
- ohai "Determining #{f.full_name} bottle rebuild..."
- versions = FormulaVersions.new(f)
- rebuilds = versions.bottle_version_map("origin/master")[f.pkg_version]
- rebuilds.pop if rebuilds.last.to_i > 0
- rebuild = rebuilds.empty? ? 0 : rebuilds.max.to_i + 1
- end
-
- filename = Bottle::Filename.create(f, Utils::Bottles.tag, rebuild)
- bottle_path = Pathname.pwd/filename
-
- tar_filename = filename.to_s.sub(/.gz$/, "")
- tar_path = Pathname.pwd/tar_filename
-
- prefix = HOMEBREW_PREFIX.to_s
- cellar = HOMEBREW_CELLAR.to_s
-
- ohai "Bottling #{filename}..."
-
- keg = Keg.new(f.prefix)
- relocatable = false
- skip_relocation = false
-
- keg.lock do
- original_tab = nil
-
- begin
- unless ARGV.include? "--skip-relocation"
- keg.relocate_dynamic_linkage prefix, Keg::PREFIX_PLACEHOLDER,
- cellar, Keg::CELLAR_PLACEHOLDER
- keg.relocate_text_files prefix, Keg::PREFIX_PLACEHOLDER,
- cellar, Keg::CELLAR_PLACEHOLDER
- end
-
- keg.delete_pyc_files!
-
- Tab.clear_cache
- tab = Tab.for_keg(keg)
- original_tab = tab.dup
- tab.poured_from_bottle = false
- tab.HEAD = nil
- tab.time = nil
- tab.write
-
- keg.find do |file|
- if file.symlink?
- # Ruby does not support `File.lutime` yet.
- # Shellout using `touch` to change modified time of symlink itself.
- system "/usr/bin/touch", "-h",
- "-t", tab.source_modified_time.strftime("%Y%m%d%H%M.%S"), file
- else
- file.utime(tab.source_modified_time, tab.source_modified_time)
- end
- end
-
- cd cellar do
- safe_system "tar", "cf", tar_path, "#{f.name}/#{f.pkg_version}"
- tar_path.utime(tab.source_modified_time, tab.source_modified_time)
- relocatable_tar_path = "#{f}-bottle.tar"
- mv tar_path, relocatable_tar_path
- # Use gzip, faster to compress than bzip2, faster to uncompress than bzip2
- # or an uncompressed tarball (and more bandwidth friendly).
- safe_system "gzip", "-f", relocatable_tar_path
- mv "#{relocatable_tar_path}.gz", bottle_path
- end
-
- if bottle_path.size > 1*1024*1024
- ohai "Detecting if #{filename} is relocatable..."
- end
-
- if prefix == "/usr/local"
- prefix_check = File.join(prefix, "opt")
- else
- prefix_check = prefix
- end
-
- ignores = []
- if f.deps.any? { |dep| dep.name == "go" }
- ignores << %r{#{Regexp.escape(HOMEBREW_CELLAR)}/go/[\d\.]+/libexec}
- end
-
- relocatable = true
- if ARGV.include? "--skip-relocation"
- skip_relocation = true
- else
- relocatable = false if keg_contain?(prefix_check, keg, ignores)
- relocatable = false if keg_contain?(cellar, keg, ignores)
- if prefix != prefix_check
- relocatable = false if keg_contain_absolute_symlink_starting_with?(prefix, keg)
- end
- skip_relocation = relocatable && !keg.require_install_name_tool?
- end
- puts if !relocatable && ARGV.verbose?
- rescue Interrupt
- ignore_interrupts { bottle_path.unlink if bottle_path.exist? }
- raise
- ensure
- ignore_interrupts do
- original_tab.write if original_tab
- unless ARGV.include? "--skip-relocation"
- keg.relocate_dynamic_linkage Keg::PREFIX_PLACEHOLDER, prefix,
- Keg::CELLAR_PLACEHOLDER, cellar
- keg.relocate_text_files Keg::PREFIX_PLACEHOLDER, prefix,
- Keg::CELLAR_PLACEHOLDER, cellar
- end
- end
- end
- end
-
- root_url = ARGV.value("root-url")
- # Use underscored version for legacy reasons. Remove at some point.
- root_url ||= ARGV.value("root_url")
-
- bottle = BottleSpecification.new
- bottle.root_url(root_url) if root_url
- if relocatable
- if skip_relocation
- bottle.cellar :any_skip_relocation
- else
- bottle.cellar :any
- end
- else
- bottle.cellar cellar
- bottle.prefix prefix
- end
- bottle.rebuild rebuild
- sha256 = bottle_path.sha256
- bottle.sha256 sha256 => Utils::Bottles.tag
-
- old_spec = f.bottle_specification
- if ARGV.include?("--keep-old") && !old_spec.checksums.empty?
- bad_fields = [:root_url, :prefix, :cellar, :rebuild].select do |field|
- old_spec.send(field) != bottle.send(field)
- end
- bad_fields.delete(:cellar) if old_spec.cellar == :any && bottle.cellar == :any_skip_relocation
- unless bad_fields.empty?
- bottle_path.unlink if bottle_path.exist?
- odie "--keep-old is passed but there are changes in: #{bad_fields.join ", "}"
- end
- end
-
- output = bottle_output bottle
-
- puts "./#{filename}"
- puts output
-
- if ARGV.include? "--json"
- json = {
- f.full_name => {
- "formula" => {
- "pkg_version" => f.pkg_version.to_s,
- "path" => f.path.to_s.strip_prefix("#{HOMEBREW_REPOSITORY}/"),
- },
- "bottle" => {
- "root_url" => bottle.root_url,
- "prefix" => bottle.prefix,
- "cellar" => bottle.cellar.to_s,
- "rebuild" => bottle.rebuild,
- "tags" => {
- Utils::Bottles.tag.to_s => {
- "filename" => filename.to_s,
- "sha256" => sha256,
- },
- }
- },
- "bintray" => {
- "package" => Utils::Bottles::Bintray.package(f.name),
- "repository" => Utils::Bottles::Bintray.repository(f.tap),
- },
- },
- }
- File.open("#{filename.prefix}.bottle.json", "w") do |file|
- file.write Utils::JSON.dump json
- end
- end
- end
-
- def merge
- write = ARGV.include? "--write"
-
- bottles_hash = ARGV.named.reduce({}) do |hash, json_file|
- deep_merge_hashes hash, Utils::JSON.load(IO.read(json_file))
- end
-
- bottles_hash.each do |formula_name, bottle_hash|
- ohai formula_name
-
- bottle = BottleSpecification.new
- bottle.root_url bottle_hash["bottle"]["root_url"]
- cellar = bottle_hash["bottle"]["cellar"]
- if cellar == "any" || cellar == "any_skip_relocation"
- cellar = cellar.to_sym
- end
- bottle.cellar cellar
- bottle.prefix bottle_hash["bottle"]["prefix"]
- bottle.rebuild bottle_hash["bottle"]["rebuild"]
- bottle_hash["bottle"]["tags"].each do |tag, tag_hash|
- bottle.sha256 tag_hash["sha256"] => tag.to_sym
- end
-
- output = bottle_output bottle
-
- if write
- path = Pathname.new("#{HOMEBREW_REPOSITORY/bottle_hash["formula"]["path"]}")
- update_or_add = nil
-
- Utils::Inreplace.inreplace(path) do |s|
- if s.include? "bottle do"
- update_or_add = "update"
- if ARGV.include? "--keep-old"
- mismatches = []
- bottle_block_contents = s[/ bottle do(.+?)end\n/m, 1]
- bottle_block_contents.lines.each do |line|
- line = line.strip
- next if line.empty?
- key, value, _, tag = line.split " ", 4
- valid_key = %w[root_url prefix cellar rebuild sha1 sha256].include? key
- next unless valid_key
-
- value = value.to_s.delete ":'\""
- tag = tag.to_s.delete ":"
-
- if !tag.empty?
- if !bottle_hash["bottle"]["tags"][tag].to_s.empty?
- mismatches << "#{key} => #{tag}"
- else
- bottle.send(key, value => tag.to_sym)
- end
- next
- end
-
- old_value = bottle_hash["bottle"][key].to_s
- next if key == "cellar" && old_value == "any" && value == "any_skip_relocation"
- mismatches << key if old_value.empty? || value != old_value
- end
- unless mismatches.empty?
- odie "--keep-old was passed but there were changes in #{mismatches.join(", ")}!"
- end
- output = bottle_output bottle
- end
- puts output
- string = s.sub!(/ bottle do.+?end\n/m, output)
- odie "Bottle block update failed!" unless string
- else
- if ARGV.include? "--keep-old"
- odie "--keep-old was passed but there was no existing bottle block!"
- end
- puts output
- update_or_add = "add"
- if s.include? "stable do"
- indent = s.slice(/^ +stable do/).length - "stable do".length
- string = s.sub!(/^ {#{indent}}stable do(.|\n)+?^ {#{indent}}end\n/m, '\0' + output + "\n")
- else
- string = s.sub!(
- /(
- \ {2}( # two spaces at the beginning
- (url|head)\ ['"][\S\ ]+['"] # url or head with a string
- (
- ,[\S\ ]*$ # url may have options
- (\n^\ {3}[\S\ ]+$)* # options can be in multiple lines
- )?|
- (homepage|desc|sha1|sha256|version|mirror)\ ['"][\S\ ]+['"]| # specs with a string
- rebuild\ \d+ # rebuild with a number
- )\n+ # multiple empty lines
- )+
- /mx, '\0' + output + "\n")
- end
- odie "Bottle block addition failed!" unless string
- end
- end
-
- unless ARGV.include? "--no-commit"
- short_name = formula_name.split("/", -1).last
- pkg_version = bottle_hash["formula"]["pkg_version"]
-
- path.parent.cd do
- safe_system "git", "commit", "--no-edit", "--verbose",
- "--message=#{short_name}: #{update_or_add} #{pkg_version} bottle.",
- "--", path
- end
- end
- else
- puts output
- end
- end
- end
-
- def bottle
- if ARGV.include? "--merge"
- merge
- else
- ARGV.resolved_formulae.each do |f|
- bottle_formula f
- end
- end
- end
-end
diff --git a/Library/Homebrew/cmd/create.rb b/Library/Homebrew/cmd/create.rb
deleted file mode 100644
index 9be990318..000000000
--- a/Library/Homebrew/cmd/create.rb
+++ /dev/null
@@ -1,218 +0,0 @@
-#: * `create` <URL> [`--autotools`|`--cmake`] [`--no-fetch`] [`--set-name` <name>] [`--set-version` <version>] [`--tap` <user>`/`<repo>]:
-#: Generate a formula for the downloadable file at <URL> and open it in the editor.
-#: Homebrew will attempt to automatically derive the formula name
-#: and version, but if it fails, you'll have to make your own template. The `wget`
-#: formula serves as a simple example. For the complete API have a look at
-#:
-#: <http://www.rubydoc.info/github/Homebrew/brew/master/Formula>
-#:
-#: If `--autotools` is passed, create a basic template for an Autotools-style build.
-#: If `--cmake` is passed, create a basic template for a CMake-style build.
-#:
-#: If `--no-fetch` is passed, Homebrew will not download <URL> to the cache and
-#: will thus not add the SHA256 to the formula for you.
-#:
-#: The options `--set-name` and `--set-version` each take an argument and allow
-#: you to explicitly set the name and version of the package you are creating.
-#:
-#: The option `--tap` takes a tap as its argument and generates the formula in
-#: the specified tap.
-
-require "formula"
-require "blacklist"
-require "digest"
-require "erb"
-
-module Homebrew
- # Create a formula from a tarball URL
- def create
- # Allow searching MacPorts or Fink.
- if ARGV.include? "--macports"
- opoo "`brew create --macports` is deprecated; use `brew search --macports` instead"
- exec_browser "https://www.macports.org/ports.php?by=name&substr=#{ARGV.next}"
- elsif ARGV.include? "--fink"
- opoo "`brew create --fink` is deprecated; use `brew search --fink` instead"
- exec_browser "http://pdb.finkproject.org/pdb/browse.php?summary=#{ARGV.next}"
- end
-
- raise UsageError if ARGV.named.empty?
-
- # Ensure that the cache exists so we can fetch the tarball
- HOMEBREW_CACHE.mkpath
-
- url = ARGV.named.first # Pull the first (and only) url from ARGV
-
- version = ARGV.next if ARGV.include? "--set-version"
- name = ARGV.next if ARGV.include? "--set-name"
- tap = ARGV.next if ARGV.include? "--tap"
-
- fc = FormulaCreator.new
- fc.name = name
- fc.version = version
- fc.tap = Tap.fetch(tap || "homebrew/core")
- raise TapUnavailableError, tap unless fc.tap.installed?
- fc.url = url
-
- fc.mode = if ARGV.include? "--cmake"
- :cmake
- elsif ARGV.include? "--autotools"
- :autotools
- end
-
- if fc.name.nil? || fc.name.strip.empty?
- stem = Pathname.new(url).stem
- print "Formula name [#{stem}]: "
- fc.name = __gets || stem
- fc.update_path
- end
-
- # Don't allow blacklisted formula, or names that shadow aliases,
- # unless --force is specified.
- unless ARGV.force?
- if msg = blacklisted?(fc.name)
- raise "#{fc.name} is blacklisted for creation.\n#{msg}\nIf you really want to create this formula use --force."
- end
-
- if Formula.aliases.include? fc.name
- realname = Formulary.canonical_name(fc.name)
- raise <<-EOS.undent
- The formula #{realname} is already aliased to #{fc.name}
- Please check that you are not creating a duplicate.
- To force creation use --force.
- EOS
- end
- end
-
- fc.generate!
-
- puts "Please `brew audit --new-formula #{fc.name}` before submitting, thanks."
- exec_editor fc.path
- end
-
- def __gets
- gots = $stdin.gets.chomp
- if gots.empty? then nil else gots end
- end
-end
-
-class FormulaCreator
- attr_reader :url, :sha256
- attr_accessor :name, :version, :tap, :path, :mode
-
- def url=(url)
- @url = url
- path = Pathname.new(url)
- if @name.nil?
- case url
- when %r{github\.com/\S+/(\S+)\.git}
- @name = $1
- @head = true
- when %r{github\.com/\S+/(\S+)/archive/}
- @name = $1
- else
- @name = path.basename.to_s[/(.*?)[-_.]?#{Regexp.escape(path.version.to_s)}/, 1]
- end
- end
- update_path
- if @version
- @version = Version.create(@version)
- else
- @version = Pathname.new(url).version
- end
- end
-
- def update_path
- return if @name.nil? || @tap.nil?
- @path = Formulary.path "#{@tap}/#{@name}"
- end
-
- def fetch?
- !head? && !ARGV.include?("--no-fetch")
- end
-
- def head?
- @head || ARGV.build_head?
- end
-
- def generate!
- raise "#{path} already exists" if path.exist?
-
- if version.nil?
- opoo "Version cannot be determined from URL."
- puts "You'll need to add an explicit 'version' to the formula."
- end
-
- if fetch? && version
- r = Resource.new
- r.url(url)
- r.version(version)
- r.owner = self
- @sha256 = r.fetch.sha256 if r.download_strategy == CurlDownloadStrategy
- end
-
- path.write ERB.new(template, nil, ">").result(binding)
- end
-
- def template; <<-EOS.undent
- # Documentation: https://github.com/Homebrew/brew/blob/master/share/doc/homebrew/Formula-Cookbook.md
- # http://www.rubydoc.info/github/Homebrew/brew/master/Formula
- # PLEASE REMOVE ALL GENERATED COMMENTS BEFORE SUBMITTING YOUR PULL REQUEST!
-
- class #{Formulary.class_s(name)} < Formula
- desc ""
- homepage ""
- <% if head? %>
- head "#{url}"
- <% else %>
- url "#{url}"
- <% unless version.nil? or version.detected_from_url? %>
- version "#{version}"
- <% end %>
- sha256 "#{sha256}"
- <% end %>
-
- <% if mode == :cmake %>
- depends_on "cmake" => :build
- <% elsif mode.nil? %>
- # depends_on "cmake" => :build
- <% end %>
- depends_on :x11 # if your formula requires any X11/XQuartz components
-
- def install
- # ENV.deparallelize # if your formula fails when building in parallel
-
- <% if mode == :cmake %>
- system "cmake", ".", *std_cmake_args
- <% elsif mode == :autotools %>
- # Remove unrecognized options if warned by configure
- system "./configure", "--disable-debug",
- "--disable-dependency-tracking",
- "--disable-silent-rules",
- "--prefix=\#{prefix}"
- <% else %>
- # Remove unrecognized options if warned by configure
- system "./configure", "--disable-debug",
- "--disable-dependency-tracking",
- "--disable-silent-rules",
- "--prefix=\#{prefix}"
- # system "cmake", ".", *std_cmake_args
- <% end %>
- system "make", "install" # if this fails, try separate make/make install steps
- end
-
- test do
- # `test do` will create, run in and delete a temporary directory.
- #
- # This test will fail and we won't accept that! It's enough to just replace
- # "false" with the main program this formula installs, but it'd be nice if you
- # were more thorough. Run the test with `brew test #{name}`. Options passed
- # to `brew install` such as `--HEAD` also need to be provided to `brew test`.
- #
- # The installed folder is not in the path, so use the entire path to any
- # executables being tested: `system "\#{bin}/program", "do", "something"`.
- system "false"
- end
- end
- EOS
- end
-end
diff --git a/Library/Homebrew/cmd/edit.rb b/Library/Homebrew/cmd/edit.rb
deleted file mode 100644
index ef325b8b6..000000000
--- a/Library/Homebrew/cmd/edit.rb
+++ /dev/null
@@ -1,50 +0,0 @@
-#: * `edit`:
-#: Open all of Homebrew for editing.
-#:
-#: * `edit` <formula>:
-#: Open <formula> in the editor.
-
-require "formula"
-
-module Homebrew
- def edit
- unless (HOMEBREW_REPOSITORY/".git").directory?
- raise <<-EOS.undent
- Changes will be lost!
- The first time you `brew update', all local changes will be lost, you should
- thus `brew update' before you `brew edit'!
- EOS
- end
-
- # If no brews are listed, open the project root in an editor.
- if ARGV.named.empty?
- editor = File.basename which_editor
- if editor == "mate" || editor == "subl"
- # If the user is using TextMate or Sublime Text,
- # give a nice project view instead.
- exec_editor HOMEBREW_REPOSITORY+"bin/brew",
- HOMEBREW_REPOSITORY+"README.md",
- HOMEBREW_REPOSITORY+".gitignore",
- *library_folders
- else
- exec_editor HOMEBREW_REPOSITORY
- end
- else
- # Don't use ARGV.formulae as that will throw if the file doesn't parse
- paths = ARGV.named.map do |name|
- path = Formulary.path(name)
- unless path.file? || ARGV.force?
- raise FormulaUnavailableError, name
- end
- path
- end
- exec_editor(*paths)
- end
- end
-
- def library_folders
- Dir["#{HOMEBREW_LIBRARY}/*"].reject do |d|
- case File.basename(d) when "LinkedKegs", "Aliases" then true end
- end
- end
-end
diff --git a/Library/Homebrew/cmd/man.rb b/Library/Homebrew/cmd/man.rb
deleted file mode 100644
index 6754a15f2..000000000
--- a/Library/Homebrew/cmd/man.rb
+++ /dev/null
@@ -1,88 +0,0 @@
-#: @hide_from_man_page
-#: * `man`:
-#: Generate Homebrew's manpages.
-
-require "formula"
-require "erb"
-require "ostruct"
-
-module Homebrew
- SOURCE_PATH = HOMEBREW_LIBRARY_PATH/"manpages"
- TARGET_MAN_PATH = HOMEBREW_REPOSITORY/"share/man/man1"
- TARGET_DOC_PATH = HOMEBREW_REPOSITORY/"share/doc/homebrew"
-
- def man
- raise UsageError unless ARGV.named.empty?
-
- if ARGV.flag? "--link"
- odie "`brew man --link` is now done automatically by `brew update`."
- else
- regenerate_man_pages
- end
- end
-
- private
-
- def regenerate_man_pages
- Homebrew.install_gem_setup_path! "ronn"
-
- markup = build_man_page
- convert_man_page(markup, TARGET_DOC_PATH/"brew.1.html")
- convert_man_page(markup, TARGET_MAN_PATH/"brew.1")
-
- cask_markup = (HOMEBREW_LIBRARY/"Homebrew/manpages/brew-cask.1.md").read
- convert_man_page(cask_markup, TARGET_MAN_PATH/"brew-cask.1")
- end
-
- def build_man_page
- template = (SOURCE_PATH/"brew.1.md.erb").read
- variables = OpenStruct.new
-
- variables[:commands] = Pathname.glob("#{HOMEBREW_LIBRARY_PATH}/cmd/*.{rb,sh}").
- sort_by { |source_file| sort_key_for_path(source_file) }.
- map { |source_file|
- source_file.read.lines.
- grep(/^#:/).
- map { |line| line.slice(2..-1) }.
- join
- }.
- reject { |s| s.strip.empty? || s.include?("@hide_from_man_page") }
-
- variables[:maintainers] = (HOMEBREW_REPOSITORY/"README.md").
- read[/Homebrew's current maintainers are (.*)\./, 1].
- scan(/\[([^\]]*)\]/).flatten
-
- ERB.new(template, nil, ">").result(variables.instance_eval{ binding })
- end
-
- def sort_key_for_path(path)
- # Options after regular commands (`~` comes after `z` in ASCII table).
- path.basename.to_s.sub(/\.(rb|sh)$/, "").sub(/^--/, "~~")
- end
-
- def convert_man_page(markup, target)
- shared_args = %W[
- --pipe
- --organization=Homebrew
- --manual=#{target.basename(".1")}
- ]
-
- format_flag, format_desc = target_path_to_format(target)
-
- puts "Writing #{format_desc} to #{target}"
- Utils.popen(["ronn", format_flag] + shared_args, "rb+") do |ronn|
- ronn.write markup
- ronn.close_write
- target.atomic_write ronn.read
- end
- end
-
- def target_path_to_format(target)
- case target.basename
- when /\.html?$/ then ["--fragment", "HTML fragment"]
- when /\.\d$/ then ["--roff", "man page"]
- else
- odie "Failed to infer output format from '#{target.basename}'."
- end
- end
-end
diff --git a/Library/Homebrew/cmd/pull.rb b/Library/Homebrew/cmd/pull.rb
deleted file mode 100644
index 341eed34a..000000000
--- a/Library/Homebrew/cmd/pull.rb
+++ /dev/null
@@ -1,575 +0,0 @@
-#: @hide_from_man_page
-#: `pull` [`--bottle`] [`--bump`] [`--clean`] [`--ignore-whitespace`] [`--resolve`] [`--branch-okay`] [`--no-pbcopy`] [`--no-publish`] <patch-source> [<patch-source>]
-#:
-#: Gets a patch from a GitHub commit or pull request and applies it to Homebrew.
-#: Optionally, installs the formulae changed by the patch.
-#:
-#:
-#: Each <patch-source> may be one of:
-#: * The ID number of a PR (Pull Request) in the homebrew/core GitHub
-#: repository
-#: * The URL of a PR on GitHub, using either the web page or API URL
-#: formats. In this form, the PR may be on Homebrew/brew,
-#: Homebrew/homebrew-core or any tap.
-#: * The URL of a commit on GitHub
-#: * A "http://bot.brew.sh/job/..." string specifying a testing job ID
-#:
-#: If `--bottle` was passed, handle bottles, pulling the bottle-update
-#: commit and publishing files on Bintray.
-#: If `--bump` was passed, for one-formula PRs, automatically reword
-#: commit message to our preferred format.
-#: If `--clean` was passed, do not rewrite or otherwise modify the
-#: commits found in the pulled PR.
-#: If `--ignore-whitespace` was passed, silently ignore whitespace
-#: discrepancies when applying diffs.
-#: If `--resolve` was passed, when a patch fails to apply, leave in
-#: progress and allow user to
-#: resolve, instead of aborting.
-#: If `--branch-okay` was passed, do not warn if pulling to a branch
-#: besides master (useful for testing).
-#: If `--no-pbcopy` was passed, do not copy anything to the system
-# clipboard.
-#: If `--no-publish` was passed, do not publish bottles to Bintray.
-
-require "net/http"
-require "net/https"
-require "utils"
-require "utils/json"
-require "formula"
-require "formulary"
-require "tap"
-require "version"
-require "pkg_version"
-
-module Homebrew
- def pull
- if ARGV[0] == "--rebase"
- odie "You meant `git pull --rebase`."
- end
- if ARGV.named.empty?
- odie "This command requires at least one argument containing a URL or pull request number"
- end
- do_bump = ARGV.include?("--bump") && !ARGV.include?("--clean")
-
- # Formulae with affected bottles that were published
- bintray_published_formulae = []
- tap = nil
-
- ARGV.named.each do |arg|
- if arg.to_i > 0
- issue = arg
- url = "https://github.com/Homebrew/homebrew-core/pull/#{arg}"
- tap = CoreTap.instance
- elsif (testing_match = arg.match %r{/job/Homebrew.*Testing/(\d+)/})
- tap = ARGV.value("tap")
- tap = if tap && tap.start_with?("homebrew/")
- Tap.fetch("homebrew", tap.strip_prefix("homebrew/"))
- elsif tap
- odie "Tap option did not start with \"homebrew/\": #{tap}"
- else
- CoreTap.instance
- end
- _, testing_job = *testing_match
- url = "https://github.com/Homebrew/homebrew-#{tap.repo}/compare/master...BrewTestBot:testing-#{testing_job}"
- odie "Testing URLs require `--bottle`!" unless ARGV.include?("--bottle")
- elsif (api_match = arg.match HOMEBREW_PULL_API_REGEX)
- _, user, repo, issue = *api_match
- url = "https://github.com/#{user}/#{repo}/pull/#{issue}"
- tap = Tap.fetch(user, repo) if repo.start_with?("homebrew-")
- elsif (url_match = arg.match HOMEBREW_PULL_OR_COMMIT_URL_REGEX)
- url, user, repo, issue = *url_match
- tap = Tap.fetch(user, repo) if repo.start_with?("homebrew-")
- else
- odie "Not a GitHub pull request or commit: #{arg}"
- end
-
- if !testing_job && ARGV.include?("--bottle") && issue.nil?
- odie "No pull request detected!"
- end
-
- if tap
- tap.install unless tap.installed?
- Dir.chdir tap.path
- else
- Dir.chdir HOMEBREW_REPOSITORY
- end
-
- # The cache directory seems like a good place to put patches.
- HOMEBREW_CACHE.mkpath
-
- # Store current revision and branch
- orig_revision = `git rev-parse --short HEAD`.strip
- branch = `git symbolic-ref --short HEAD`.strip
-
- unless branch == "master" || ARGV.include?("--clean") || ARGV.include?("--branch-okay")
- opoo "Current branch is #{branch}: do you need to pull inside master?"
- end
-
- patch_puller = PatchPuller.new(url)
- patch_puller.fetch_patch
- patch_changes = files_changed_in_patch(patch_puller.patchpath, tap)
-
- is_bumpable = patch_changes[:formulae].length == 1 && patch_changes[:others].empty?
- if do_bump
- odie "No changed formulae found to bump" if patch_changes[:formulae].empty?
- if patch_changes[:formulae].length > 1
- odie "Can only bump one changed formula; bumped #{patch_changes[:formulae]}"
- end
- odie "Can not bump if non-formula files are changed" unless patch_changes[:others].empty?
- end
- if is_bumpable
- old_versions = current_versions_from_info_external(patch_changes[:formulae].first)
- end
- patch_puller.apply_patch
-
- changed_formulae_names = []
-
- if tap
- Utils.popen_read(
- "git", "diff-tree", "-r", "--name-only",
- "--diff-filter=AM", orig_revision, "HEAD", "--", tap.formula_dir.to_s
- ).each_line do |line|
- next unless line.end_with? ".rb\n"
- name = "#{tap.name}/#{File.basename(line.chomp, ".rb")}"
- changed_formulae_names << name
- end
- end
-
- fetch_bottles = false
- changed_formulae_names.each do |name|
- next if ENV["HOMEBREW_DISABLE_LOAD_FORMULA"]
-
- begin
- f = Formula[name]
- # Make sure we catch syntax errors.
- rescue Exception
- next
- end
-
- if ARGV.include? "--bottle"
- if f.bottle_unneeded?
- ohai "#{f}: skipping unneeded bottle."
- elsif f.bottle_disabled?
- ohai "#{f}: skipping disabled bottle: #{f.bottle_disable_reason}"
- else
- fetch_bottles = true
- end
- else
- next unless f.bottle_defined?
- opoo "#{f.full_name} has a bottle: do you need to update it with --bottle?"
- end
- end
-
- orig_message = message = `git log HEAD^.. --format=%B`
- if issue && !ARGV.include?("--clean")
- ohai "Patch closes issue ##{issue}"
- close_message = "Closes ##{issue}."
- # If this is a pull request, append a close message.
- message += "\n#{close_message}" unless message.include? close_message
- end
-
- if changed_formulae_names.empty?
- odie "cannot bump: no changed formulae found after applying patch" if do_bump
- is_bumpable = false
- end
-
- is_bumpable = false if ARGV.include?("--clean")
- is_bumpable = false if ENV["HOMEBREW_DISABLE_LOAD_FORMULA"]
-
- if is_bumpable
- formula = Formula[changed_formulae_names.first]
- new_versions = current_versions_from_info_external(patch_changes[:formulae].first)
- orig_subject = message.empty? ? "" : message.lines.first.chomp
- bump_subject = subject_for_bump(formula, old_versions, new_versions)
- if do_bump
- odie "No version changes found for #{formula.name}" if bump_subject.nil?
- unless orig_subject == bump_subject
- ohai "New bump commit subject: #{bump_subject}"
- pbcopy bump_subject unless ARGV.include? "--no-pbcopy"
- message = "#{bump_subject}\n\n#{message}"
- end
- elsif bump_subject != orig_subject && !bump_subject.nil?
- opoo "Nonstandard bump subject: #{orig_subject}"
- opoo "Subject should be: #{bump_subject}"
- end
- end
-
- if message != orig_message && !ARGV.include?("--clean")
- safe_system "git", "commit", "--amend", "--signoff", "--allow-empty", "-q", "-m", message
- end
-
- # Bottles: Pull bottle block commit and publish bottle files on Bintray
- if fetch_bottles
- bottle_commit_url = if testing_job
- bottle_branch = "testing-bottle-#{testing_job}"
- url
- else
- bottle_branch = "pull-bottle-#{issue}"
- "https://github.com/BrewTestBot/homebrew-#{tap.repo}/compare/homebrew:master...pr-#{issue}"
- end
-
- curl "--silent", "--fail", "-o", "/dev/null", "-I", bottle_commit_url
-
- safe_system "git", "checkout", "--quiet", "-B", bottle_branch, orig_revision
- pull_patch bottle_commit_url, "bottle commit"
- safe_system "git", "rebase", "--quiet", branch
- safe_system "git", "checkout", "--quiet", branch
- safe_system "git", "merge", "--quiet", "--ff-only", "--no-edit", bottle_branch
- safe_system "git", "branch", "--quiet", "-D", bottle_branch
-
- # Publish bottles on Bintray
- unless ARGV.include? "--no-publish"
- published = publish_changed_formula_bottles(tap, changed_formulae_names)
- bintray_published_formulae.concat(published)
- end
- end
-
- ohai "Patch changed:"
- safe_system "git", "diff-tree", "-r", "--stat", orig_revision, "HEAD"
- end
-
- # Verify bintray publishing after all patches have been applied
- bintray_published_formulae.uniq!
- verify_bintray_published(bintray_published_formulae)
- end
-
- def force_utf8!(str)
- str.force_encoding("UTF-8") if str.respond_to?(:force_encoding)
- end
-
- private
-
- def publish_changed_formula_bottles(tap, changed_formulae_names)
- if ENV["HOMEBREW_DISABLE_LOAD_FORMULA"]
- raise "Need to load formulae to publish them!"
- end
-
- published = []
- bintray_creds = { :user => ENV["BINTRAY_USER"], :key => ENV["BINTRAY_KEY"] }
- if bintray_creds[:user] && bintray_creds[:key]
- changed_formulae_names.each do |name|
- f = Formula[name]
- next if f.bottle_unneeded? || f.bottle_disabled?
- ohai "Publishing on Bintray: #{f.name} #{f.pkg_version}"
- publish_bottle_file_on_bintray(f, bintray_creds)
- published << f.full_name
- end
- else
- opoo "You must set BINTRAY_USER and BINTRAY_KEY to add or update bottles on Bintray!"
- end
- published
- end
-
- def pull_patch(url, description = nil)
- PatchPuller.new(url, description).pull_patch
- end
-
- class PatchPuller
- attr_reader :base_url
- attr_reader :patch_url
- attr_reader :patchpath
-
- def initialize(url, description = nil)
- @base_url = url
- # GitHub provides commits/pull-requests raw patches using this URL.
- @patch_url = url + ".patch"
- @patchpath = HOMEBREW_CACHE + File.basename(patch_url)
- @description = description
- end
-
- def pull_patch
- fetch_patch
- apply_patch
- end
-
- def fetch_patch
- extra_msg = @description ? "(#{@description})" : nil
- ohai "Fetching patch #{extra_msg}"
- puts "Patch: #{patch_url}"
- curl patch_url, "-s", "-o", patchpath
- end
-
- def apply_patch
- # Applies a patch previously downloaded with fetch_patch()
- # Deletes the patch file as a side effect, regardless of success
-
- ohai "Applying patch"
- patch_args = []
- # Normally we don't want whitespace errors, but squashing them can break
- # patches so an option is provided to skip this step.
- if ARGV.include?("--ignore-whitespace") || ARGV.include?("--clean")
- patch_args << "--whitespace=nowarn"
- else
- patch_args << "--whitespace=fix"
- end
-
- # Fall back to three-way merge if patch does not apply cleanly
- patch_args << "-3"
- patch_args << patchpath
-
- begin
- safe_system "git", "am", *patch_args
- rescue ErrorDuringExecution
- if ARGV.include? "--resolve"
- odie "Patch failed to apply: try to resolve it."
- else
- system "git", "am", "--abort"
- odie "Patch failed to apply: aborted."
- end
- ensure
- patchpath.unlink
- end
- end
- end
-
- # List files changed by a patch, partitioned in to those that are (probably)
- # formula definitions, and those which aren't. Only applies to patches on
- # Homebrew core or taps, based simply on relative pathnames of affected files.
- def files_changed_in_patch(patchfile, tap)
- files = []
- formulae = []
- others = []
- File.foreach(patchfile) do |line|
- files << $1 if line =~ %r{^\+\+\+ b/(.*)}
- end
- files.each do |file|
- if tap && tap.formula_file?(file)
- formula_name = File.basename(file, ".rb")
- formulae << formula_name unless formulae.include?(formula_name)
- else
- others << file
- end
- end
- { :files => files, :formulae => formulae, :others => others }
- end
-
- # Get current formula versions without loading formula definition in this process
- # Returns info as a hash (type => version), for pull.rb's internal use
- # Uses special key :nonexistent => true for nonexistent formulae
- def current_versions_from_info_external(formula_name)
- info = FormulaInfoFromJson.lookup(formula_name)
- versions = {}
- if info
- [:stable, :devel, :head].each do |spec_type|
- versions[spec_type] = info.version(spec_type)
- end
- else
- versions[:nonexistent] = true
- end
- versions
- end
-
- def subject_for_bump(formula, old, new)
- if old[:nonexistent]
- # New formula
- headline_ver = new[:stable] ? new[:stable] : new[:devel] ? new[:devel] : new[:head]
- subject = "#{formula.name} #{headline_ver} (new formula)"
- else
- # Update to existing formula
- subject_strs = []
- formula_name_str = formula.name
- if old[:stable] != new[:stable]
- if new[:stable].nil?
- subject_strs << "remove stable"
- formula_name_str += ":" # just for cosmetics
- else
- subject_strs << formula.version.to_s
- end
- end
- if old[:devel] != new[:devel]
- if new[:devel].nil?
- # Only bother mentioning if there's no accompanying stable change
- if !new[:stable].nil? && old[:stable] == new[:stable]
- subject_strs << "remove devel"
- formula_name_str += ":" # just for cosmetics
- end
- else
- subject_strs << "#{formula.devel.version} (devel)"
- end
- end
- subject = subject_strs.empty? ? nil : "#{formula_name_str} #{subject_strs.join(", ")}"
- end
- subject
- end
-
- def pbcopy(text)
- Utils.popen_write("pbcopy") { |io| io.write text }
- end
-
- # Publishes the current bottle files for a given formula to Bintray
- def publish_bottle_file_on_bintray(f, creds)
- repo = Utils::Bottles::Bintray.repository(f.tap)
- package = Utils::Bottles::Bintray.package(f.name)
- info = FormulaInfoFromJson.lookup(f.name)
- if info.nil?
- raise "Failed publishing bottle: failed reading formula info for #{f.full_name}"
- end
- version = info.pkg_version
- curl "-w", '\n', "--silent", "--fail",
- "-u#{creds[:user]}:#{creds[:key]}", "-X", "POST",
- "-H", "Content-Type: application/json",
- "-d", '{"publish_wait_for_secs": 0}',
- "https://api.bintray.com/content/homebrew/#{repo}/#{package}/#{version}/publish"
- end
-
- # Formula info drawn from an external "brew info --json" call
- class FormulaInfoFromJson
- # The whole info structure parsed from the JSON
- attr_accessor :info
-
- def initialize(info)
- @info = info
- end
-
- # Looks up formula on disk and reads its info
- # Returns nil if formula is absent or if there was an error reading it
- def self.lookup(name)
- json = Utils.popen_read(HOMEBREW_BREW_FILE, "info", "--json=v1", name)
- unless $?.success?
- return nil
- end
- Homebrew.force_utf8!(json)
- FormulaInfoFromJson.new(Utils::JSON.load(json)[0])
- end
-
- def bottle_tags()
- return [] unless info["bottle"]["stable"]
- info["bottle"]["stable"]["files"].keys
- end
-
- def bottle_info(my_bottle_tag = Utils::Bottles.tag)
- tag_s = my_bottle_tag.to_s
- return nil unless info["bottle"]["stable"]
- btl_info = info["bottle"]["stable"]["files"][tag_s]
- return nil unless btl_info
- BottleInfo.new(btl_info["url"], btl_info["sha256"])
- end
-
- def bottle_info_any
- bottle_info(any_bottle_tag)
- end
-
- def any_bottle_tag
- tag = Utils::Bottles.tag
- # Prefer native bottles as a convenience for download caching
- bottle_tags.include?(tag) ? tag : bottle_tags.first
- end
-
- def version(spec_type)
- version_str = info["versions"][spec_type.to_s]
- version_str && Version.create(version_str)
- end
-
- def pkg_version(spec_type = :stable)
- PkgVersion.new(version(spec_type), revision)
- end
-
- def revision
- info["revision"]
- end
- end
-
-
- # Bottle info as used internally by pull, with alternate platform support
- class BottleInfo
- # URL of bottle as string
- attr_accessor :url
- # Expected SHA256 as string
- attr_accessor :sha256
-
- def initialize(url, sha256)
- @url = url
- @sha256 = sha256
- end
- end
-
- # Verifies that formulae have been published on Bintray by downloading a bottle file
- # for each one. Blocks until the published files are available.
- # Raises an error if the verification fails.
- # This does not currently work for `brew pull`, because it may have cached the old
- # version of a formula.
- def verify_bintray_published(formulae_names)
- return if formulae_names.empty?
-
- if ENV["HOMEBREW_DISABLE_LOAD_FORMULA"]
- raise "Need to load formulae to verify their publication!"
- end
-
- ohai "Verifying bottles published on Bintray"
- formulae = formulae_names.map { |n| Formula[n] }
- max_retries = 300 # shared among all bottles
- poll_retry_delay_seconds = 2
-
- HOMEBREW_CACHE.cd do
- formulae.each do |f|
- retry_count = 0
- wrote_dots = false
- # Choose arbitrary bottle just to get the host/port for Bintray right
- jinfo = FormulaInfoFromJson.lookup(f.full_name)
- unless jinfo
- opoo "Cannot publish bottle: Failed reading info for formula #{f.full_name}"
- next
- end
- bottle_info = jinfo.bottle_info(jinfo.bottle_tags.first)
- unless bottle_info
- opoo "No bottle defined in formula #{f.full_name}"
- next
- end
-
- # Poll for publication completion using a quick partial HEAD, to avoid spurious error messages
- # 401 error is normal while file is still in async publishing process
- url = URI(bottle_info.url)
- puts "Verifying bottle: #{File.basename(url.path)}"
- http = Net::HTTP.new(url.host, url.port)
- http.use_ssl = true
- retry_count = 0
- http.start do
- while true do
- req = Net::HTTP::Head.new bottle_info.url
- req.initialize_http_header "User-Agent" => HOMEBREW_USER_AGENT_RUBY
- res = http.request req
- if res.is_a?(Net::HTTPSuccess)
- break
- elsif res.is_a?(Net::HTTPClientError)
- if retry_count >= max_retries
- raise "Failed to find published #{f} bottle at #{url}!"
- end
- print(wrote_dots ? "." : "Waiting on Bintray.")
- wrote_dots = true
- sleep poll_retry_delay_seconds
- retry_count += 1
- else
- raise "Failed to find published #{f} bottle at #{url} (#{res.code} #{res.message})!"
- end
- end
- end
-
- # Actual download and verification
- # We do a retry on this, too, because sometimes the external curl will fail even
- # when the prior HEAD has succeeded.
- puts "\n" if wrote_dots
- filename = File.basename(url.path)
- curl_retry_delay_seconds = 4
- max_curl_retries = 1
- retry_count = 0
- # We're in the cache; make sure to force re-download
- while true do
- begin
- curl url, "-o", filename
- break
- rescue
- if retry_count >= max_curl_retries
- raise "Failed to download #{f} bottle from #{url}!"
- end
- puts "curl download failed; retrying in #{curl_retry_delay_seconds} sec"
- sleep curl_retry_delay_seconds
- curl_retry_delay_seconds *= 2
- retry_count += 1
- end
- end
- checksum = Checksum.new(:sha256, bottle_info.sha256)
- Pathname.new(filename).verify_checksum(checksum)
- end
- end
- end
-end
diff --git a/Library/Homebrew/cmd/tap-readme.rb b/Library/Homebrew/cmd/tap-readme.rb
deleted file mode 100644
index ad115a53e..000000000
--- a/Library/Homebrew/cmd/tap-readme.rb
+++ /dev/null
@@ -1,36 +0,0 @@
-#: @hide_from_man_page
-#: * `tap_readme` [`-v`] <name>:
-#: Generate the README.md file for a new tap.
-
-module Homebrew
- def tap_readme
- name = ARGV.first
- raise "A name is required" if name.nil?
-
- titleized_name = name.dup
- titleized_name[0..0] = titleized_name[0..0].upcase
-
- template = <<-EOS.undent
- # Homebrew #{titleized_name}
-
- ## How do I install these formulae?
- `brew install homebrew/#{name}/<formula>`
-
- Or `brew tap homebrew/#{name}` and then `brew install <formula>`.
-
- Or install via URL (which will not receive updates):
-
- ```
- brew install https://raw.githubusercontent.com/Homebrew/homebrew-#{name}/master/<formula>.rb
- ```
-
- ## Documentation
- `brew help`, `man brew` or check [Homebrew's documentation](https://github.com/Homebrew/brew/tree/master/share/doc/homebrew#readme).
- EOS
-
- puts template if ARGV.verbose?
- path = HOMEBREW_LIBRARY/"Taps/homebrew/homebrew-#{name}/README.md"
- raise "#{path} already exists" if path.exist?
- path.write template
- end
-end
diff --git a/Library/Homebrew/cmd/test.rb b/Library/Homebrew/cmd/test.rb
deleted file mode 100644
index a80fa5e4f..000000000
--- a/Library/Homebrew/cmd/test.rb
+++ /dev/null
@@ -1,89 +0,0 @@
-#: * `test` [`--devel`|`--HEAD`] [`--debug`] [`--keep-tmp`] <formula>:
-#: A few formulae provide a test method. `brew test` <formula> runs this
-#: test method. There is no standard output or return code, but it should
-#: generally indicate to the user if something is wrong with the installed
-#: formula.
-#:
-#: To test the development or head version of a formula, use `--devel` or
-#: `--HEAD`.
-#:
-#: If `--debug` is passed and the test fails, an interactive debugger will be
-#: launched with access to IRB or a shell inside the temporary test directory.
-#:
-#: If `--keep-tmp` is passed, the temporary files created for the test are
-#: not deleted.
-#:
-#: Example: `brew install jruby && brew test jruby`
-
-require "extend/ENV"
-require "formula_assertions"
-require "sandbox"
-require "timeout"
-
-module Homebrew
- def test
- raise FormulaUnspecifiedError if ARGV.named.empty?
-
- ARGV.resolved_formulae.each do |f|
- # Cannot test uninstalled formulae
- unless f.installed?
- ofail "Testing requires the latest version of #{f.full_name}"
- next
- end
-
- # Cannot test formulae without a test method
- unless f.test_defined?
- ofail "#{f.full_name} defines no test"
- next
- end
-
- puts "Testing #{f.full_name}"
-
- env = ENV.to_hash
-
- begin
- args = %W[
- #{RUBY_PATH}
- -W0
- -I #{HOMEBREW_LOAD_PATH}
- --
- #{HOMEBREW_LIBRARY_PATH}/test.rb
- #{f.path}
- ].concat(ARGV.options_only)
-
- if f.head?
- args << "--HEAD"
- elsif f.devel?
- args << "--devel"
- end
-
- Sandbox.print_sandbox_message if Sandbox.test?
-
- Utils.safe_fork do
- if Sandbox.test?
- sandbox = Sandbox.new
- f.logs.mkpath
- sandbox.record_log(f.logs/"test.sandbox.log")
- sandbox.allow_write_temp_and_cache
- sandbox.allow_write_log(f)
- sandbox.allow_write_xcode
- sandbox.allow_write_path(HOMEBREW_PREFIX/"var/cache")
- sandbox.allow_write_path(HOMEBREW_PREFIX/"var/log")
- sandbox.allow_write_path(HOMEBREW_PREFIX/"var/run")
- sandbox.exec(*args)
- else
- exec(*args)
- end
- end
- rescue Assertions::FailedAssertion => e
- ofail "#{f.full_name}: failed"
- puts e.message
- rescue Exception => e
- ofail "#{f.full_name}: failed"
- puts e, e.backtrace
- ensure
- ENV.replace(env)
- end
- end
- end
-end
diff --git a/Library/Homebrew/cmd/tests.rb b/Library/Homebrew/cmd/tests.rb
deleted file mode 100644
index be8f72ace..000000000
--- a/Library/Homebrew/cmd/tests.rb
+++ /dev/null
@@ -1,63 +0,0 @@
-#: @hide_from_man_page
-#: * `tests` [`-v`] [`--coverage`] [`--generic`] [`--no-compat`] [`--only=`<test_script/test_method>] [`--seed` <seed>] [`--trace`] [`--online`] [`--official-cmd-taps`]:
-#: Run Homebrew's unit and integration tests.
-
-require "fileutils"
-require "tap"
-
-module Homebrew
- def tests
- (HOMEBREW_LIBRARY/"Homebrew/test").cd do
- ENV["HOMEBREW_NO_ANALYTICS_THIS_RUN"] = "1"
- ENV["TESTOPTS"] = "-v" if ARGV.verbose?
- ENV["HOMEBREW_NO_COMPAT"] = "1" if ARGV.include? "--no-compat"
- ENV["HOMEBREW_TEST_GENERIC_OS"] = "1" if ARGV.include? "--generic"
- ENV["HOMEBREW_NO_GITHUB_API"] = "1" unless ARGV.include? "--online"
- if ARGV.include? "--official-cmd-taps"
- ENV["HOMEBREW_TEST_OFFICIAL_CMD_TAPS"] = "1"
- end
-
- if ARGV.include? "--coverage"
- ENV["HOMEBREW_TESTS_COVERAGE"] = "1"
- FileUtils.rm_f "coverage/.resultset.json"
- end
-
- # Override author/committer as global settings might be invalid and thus
- # will cause silent failure during the setup of dummy Git repositories.
- %w[AUTHOR COMMITTER].each do |role|
- ENV["GIT_#{role}_NAME"] = "brew tests"
- ENV["GIT_#{role}_EMAIL"] = "brew-tests@localhost"
- end
-
- Homebrew.install_gem_setup_path! "bundler"
- unless quiet_system("bundle", "check")
- system "bundle", "install", "--path", "vendor/bundle"
- end
-
- # Make it easier to reproduce test runs.
- ENV["SEED"] = ARGV.next if ARGV.include? "--seed"
-
- args = []
- args << "--trace" if ARGV.include? "--trace"
- if ARGV.value("only")
- ENV["HOMEBREW_TESTS_ONLY"] = "1"
- test_name, test_method = ARGV.value("only").split("/", 2)
- args << "TEST=test_#{test_name}.rb"
- args << "TESTOPTS=--name=test_#{test_method}" if test_method
- end
- args += ARGV.named.select { |v| v[/^TEST(OPTS)?=/] }
- system "bundle", "exec", "rake", "test", *args
-
- Homebrew.failed = !$?.success?
-
- if (fs_leak_log = HOMEBREW_LIBRARY/"Homebrew/test/fs_leak_log").file?
- fs_leak_log_content = fs_leak_log.read
- unless fs_leak_log_content.empty?
- opoo "File leak is detected"
- puts fs_leak_log_content
- Homebrew.failed = true
- end
- end
- end
- end
-end