aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.github/ISSUE_TEMPLATE.md17
-rw-r--r--Library/Homebrew/cask/lib/hbc/cli/search.rb21
-rw-r--r--Library/Homebrew/cleanup.rb8
-rw-r--r--Library/Homebrew/cmd/search.rb8
-rw-r--r--Library/Homebrew/cmd/update-report.rb1
-rw-r--r--Library/Homebrew/compat/ENV/shared.rb4
-rw-r--r--Library/Homebrew/dev-cmd/audit.rb78
-rw-r--r--Library/Homebrew/dev-cmd/pull.rb2
-rw-r--r--Library/Homebrew/download_strategy.rb2
-rw-r--r--Library/Homebrew/extend/ENV/shared.rb4
-rw-r--r--Library/Homebrew/extend/fileutils.rb2
-rw-r--r--Library/Homebrew/extend/pathname.rb2
-rw-r--r--Library/Homebrew/formula.rb6
-rw-r--r--Library/Homebrew/formula_installer.rb3
-rw-r--r--Library/Homebrew/gpg.rb23
-rw-r--r--Library/Homebrew/manpages/brew-cask.1.md13
-rw-r--r--Library/Homebrew/missing_formula.rb13
-rw-r--r--Library/Homebrew/requirements/gpg2_requirement.rb6
-rw-r--r--Library/Homebrew/rubocops/extend/formula_cop.rb32
-rw-r--r--Library/Homebrew/rubocops/lines_cop.rb54
-rw-r--r--Library/Homebrew/rubocops/patches_cop.rb12
-rw-r--r--Library/Homebrew/test/cask/cli/search_spec.rb48
-rw-r--r--Library/Homebrew/test/cleanup_spec.rb132
-rw-r--r--Library/Homebrew/test/cmd/search_remote_tap_spec.rb3
-rw-r--r--Library/Homebrew/test/cmd/search_spec.rb2
-rw-r--r--Library/Homebrew/test/dev-cmd/audit_spec.rb22
-rw-r--r--Library/Homebrew/test/download_strategies_spec.rb11
-rw-r--r--Library/Homebrew/test/missing_formula_spec.rb6
-rw-r--r--Library/Homebrew/test/rubocops/lines_cop_spec.rb151
-rw-r--r--Library/Homebrew/test/rubocops/patches_cop_spec.rb222
-rw-r--r--Library/Homebrew/test/utils/analytics_spec.rb88
-rw-r--r--Library/Homebrew/test/utils/git_spec.rb150
-rw-r--r--Library/Homebrew/test/utils/svn_spec.rb39
-rw-r--r--Library/Homebrew/utils/analytics.rb5
-rw-r--r--Library/Homebrew/utils/curl.rb7
-rw-r--r--Library/Homebrew/utils/fork.rb2
-rw-r--r--Library/Homebrew/utils/git.rb3
-rw-r--r--Library/Homebrew/utils/github.rb2
-rw-r--r--Library/Homebrew/utils/svn.rb4
-rw-r--r--docs/Analytics.md4
-rw-r--r--docs/FAQ.md13
-rw-r--r--docs/Formula-Cookbook.md2
-rw-r--r--docs/Homebrew-and-Python.md8
-rw-r--r--docs/Prose-Style-Guidelines.md2
-rw-r--r--docs/Python-for-Formula-Authors.md48
-rw-r--r--manpages/brew-cask.12
46 files changed, 985 insertions, 302 deletions
diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md
index f4e56604e..287e95b03 100644
--- a/.github/ISSUE_TEMPLATE.md
+++ b/.github/ISSUE_TEMPLATE.md
@@ -1,17 +1,22 @@
+**Please note we will close your issue without comment if you delete, do not read or do not fill out the issue checklist below and provide ALL the requested information. If you repeatedly fail to use the issue template, we will block you from ever submitting issues to Homebrew again.**
+
# Please always follow these steps:
-- [ ] Confirmed this is a problem with running a `brew` command and not `brew install`ing or the post-install behaviour of one or more formulae? If it's a formulae-specific problem please file this issue at https://github.com/Homebrew/homebrew-core/issues/new
+- [ ] Confirmed this is a problem with running a `brew` command and not `brew install`ing or the post-install behaviour of one or more formulae? If it's a formulae-specific problem please file this issue at the relevant tap e.g. for Homebrew/homebrew-core https://github.com/Homebrew/homebrew-core/issues/new
- [ ] Ran `brew update` and retried your prior step?
- [ ] Ran `brew doctor`, fixed all issues and retried your prior step?
- [ ] Ran `brew config` and `brew doctor` and included their output with your issue?
-**Please note we will close your issue without comment if you delete or do not fill out the issue checklist and provide ALL the requested information.**
-
To help us debug your issue please explain:
- What you were trying to do (and why)
- What happened (include command output)
- What you expected to happen
- Step-by-step reproduction instructions (by running `brew` commands)
-# Or propose a feature:
-Please replace this section with a detailed description of your proposed feature, the motivation for it, how it would be relevant to at least 90% of Homebrew users and alternatives considered.
-Please note we will close this issue or ask you to create a pull-request if it's something we're not actively planning to work on.
+# Features
+Please replace this section with:
+- a detailed description of your proposed feature
+- the motivation for the feature
+- how the feature would be relevant to at least 90% of Homebrew users
+- what alternatives to the feature you have considered
+
+We will close this issue or ask you to create a pull-request if it's something we're not actively planning to work on.
diff --git a/Library/Homebrew/cask/lib/hbc/cli/search.rb b/Library/Homebrew/cask/lib/hbc/cli/search.rb
index e89dced92..d56d0c81f 100644
--- a/Library/Homebrew/cask/lib/hbc/cli/search.rb
+++ b/Library/Homebrew/cask/lib/hbc/cli/search.rb
@@ -2,8 +2,12 @@ module Hbc
class CLI
class Search < AbstractCommand
def run
- results = self.class.search(*args)
- self.class.render_results(*results)
+ if args.empty?
+ puts Formatter.columns(CLI.nice_listing(Hbc.all_tokens))
+ else
+ results = self.class.search(*args)
+ self.class.render_results(*results)
+ end
end
def self.extract_regexp(string)
@@ -15,8 +19,17 @@ module Hbc
end
def self.search_remote(query)
- matches = GitHub.search_code(user: "caskroom", path: "Casks",
- filename: query, extension: "rb")
+ matches = begin
+ GitHub.search_code(
+ user: "caskroom",
+ path: "Casks",
+ filename: query,
+ extension: "rb",
+ )
+ rescue GitHub::Error => error
+ opoo "Error searching on GitHub: #{error}\n"
+ []
+ end
matches.map do |match|
tap = Tap.fetch(match["repository"]["full_name"])
next if tap.installed?
diff --git a/Library/Homebrew/cleanup.rb b/Library/Homebrew/cleanup.rb
index d1f0b2516..340161204 100644
--- a/Library/Homebrew/cleanup.rb
+++ b/Library/Homebrew/cleanup.rb
@@ -6,6 +6,10 @@ module Homebrew
module Cleanup
@disk_cleanup_size = 0
+ class << self
+ attr_reader :disk_cleanup_size
+ end
+
module_function
def cleanup
@@ -21,10 +25,6 @@ module Homebrew
@disk_cleanup_size += path_size
end
- def disk_cleanup_size
- @disk_cleanup_size
- end
-
def unremovable_kegs
@unremovable_kegs ||= []
end
diff --git a/Library/Homebrew/cmd/search.rb b/Library/Homebrew/cmd/search.rb
index 0718a3af4..acee9817f 100644
--- a/Library/Homebrew/cmd/search.rb
+++ b/Library/Homebrew/cmd/search.rb
@@ -36,7 +36,7 @@ module Homebrew
elsif ARGV.include? "--fedora"
exec_browser "https://apps.fedoraproject.org/packages/s/#{ARGV.next}"
elsif ARGV.include? "--ubuntu"
- exec_browser "http://packages.ubuntu.com/search?keywords=#{ARGV.next}&searchon=names&suite=all&section=all"
+ exec_browser "https://packages.ubuntu.com/search?keywords=#{ARGV.next}&searchon=names&suite=all&section=all"
elsif ARGV.include? "--desc"
query = ARGV.next
regex = query_regexp(query)
@@ -102,11 +102,13 @@ module Homebrew
odie "#{query} is not a valid regex"
end
- def search_taps(query)
+ def search_taps(query, silent: false)
return [] if ENV["HOMEBREW_NO_GITHUB_API"]
# Use stderr to avoid breaking parsed output
- $stderr.puts Formatter.headline("Searching taps on GitHub...", color: :blue)
+ unless silent
+ $stderr.puts Formatter.headline("Searching taps on GitHub...", color: :blue)
+ end
valid_dirnames = ["Formula", "HomebrewFormula", "Casks", "."].freeze
matches = GitHub.search_code(user: ["Homebrew", "caskroom"], filename: query, extension: "rb")
diff --git a/Library/Homebrew/cmd/update-report.rb b/Library/Homebrew/cmd/update-report.rb
index ea915f99c..164413cd1 100644
--- a/Library/Homebrew/cmd/update-report.rb
+++ b/Library/Homebrew/cmd/update-report.rb
@@ -203,6 +203,7 @@ module Homebrew
end
new_homebrew_repository = Pathname.new "/usr/local/Homebrew"
+ new_homebrew_repository.rmdir_if_possible
if new_homebrew_repository.exist?
ofail <<-EOS.undent
#{new_homebrew_repository} already exists.
diff --git a/Library/Homebrew/compat/ENV/shared.rb b/Library/Homebrew/compat/ENV/shared.rb
index 200e7b132..c700b1e00 100644
--- a/Library/Homebrew/compat/ENV/shared.rb
+++ b/Library/Homebrew/compat/ENV/shared.rb
@@ -3,4 +3,8 @@ module SharedEnvExtension
odeprecated "ENV.j1", "ENV.deparallelize"
deparallelize
end
+
+ def java_cache
+ # odeprecated "ENV.java_cache"
+ end
end
diff --git a/Library/Homebrew/dev-cmd/audit.rb b/Library/Homebrew/dev-cmd/audit.rb
index 170fb6d5f..d089f308d 100644
--- a/Library/Homebrew/dev-cmd/audit.rb
+++ b/Library/Homebrew/dev-cmd/audit.rb
@@ -201,7 +201,7 @@ class FormulaAuditor
@specs = %w[stable devel head].map { |s| formula.send(s) }.compact
end
- def self.check_http_content(url, name, user_agents: [:default])
+ def self.check_http_content(url, name, user_agents: [:default], check_content: false, strict: false)
return unless url.start_with? "http"
details = nil
@@ -236,8 +236,32 @@ class FormulaAuditor
details[:content_length] == secure_details[:content_length]
file_match = details[:file_hash] == secure_details[:file_hash]
- return if !etag_match && !content_length_match && !file_match
- "The URL #{url} could use HTTPS rather than HTTP"
+ if etag_match || content_length_match || file_match
+ return "The URL #{url} should use HTTPS rather than HTTP"
+ end
+
+ return unless check_content
+
+ no_protocol_file_contents = %r{https?:\\?/\\?/}
+ details[:file] = details[:file].gsub(no_protocol_file_contents, "/")
+ secure_details[:file] = secure_details[:file].gsub(no_protocol_file_contents, "/")
+
+ # Check for the same content after removing all protocols
+ if details[:file] == secure_details[:file]
+ return "The URL #{url} should use HTTPS rather than HTTP"
+ end
+
+ return unless strict
+
+ # Same size, different content after normalization
+ # (typical causes: Generated ID, Timestamp, Unix time)
+ if details[:file].length == secure_details[:file].length
+ return "The URL #{url} may be able to use HTTPS rather than HTTP. Please verify it in a browser."
+ end
+
+ lenratio = (100 * secure_details[:file].length / details[:file].length).to_i
+ return unless (90..110).cover?(lenratio)
+ "The URL #{url} may be able to use HTTPS rather than HTTP. Please verify it in a browser."
end
def self.http_content_headers_and_checksum(url, hash_needed: false, user_agent: :default)
@@ -260,6 +284,7 @@ class FormulaAuditor
etag: headers[%r{ETag: ([wW]\/)?"(([^"]|\\")*)"}, 2],
content_length: headers[/Content-Length: (\d+)/, 1],
file_hash: output_hash,
+ file: output,
}
end
@@ -412,7 +437,7 @@ class FormulaAuditor
same_name_tap_formulae = @@local_official_taps_name_map[name] || []
if @online
- Homebrew.search_taps(name).each do |tap_formula_full_name|
+ Homebrew.search_taps(name, silent: true).each do |tap_formula_full_name|
tap_formula_name = tap_formula_full_name.split("/").last
next if tap_formula_name != name
same_name_tap_formulae << tap_formula_full_name
@@ -566,7 +591,9 @@ class FormulaAuditor
return unless DevelopmentTools.curl_handles_most_https_homepages?
if http_content_problem = FormulaAuditor.check_http_content(homepage,
formula.name,
- user_agents: [:browser, :default])
+ user_agents: [:browser, :default],
+ check_content: true,
+ strict: @strict)
problem http_content_problem
end
end
@@ -808,39 +835,6 @@ class FormulaAuditor
end
def line_problems(line, _lineno)
- if line =~ /<(Formula|AmazonWebServicesFormula|ScriptFileFormula|GithubGistFormula)/
- problem "Use a space in class inheritance: class Foo < #{Regexp.last_match(1)}"
- end
-
- # Commented-out cmake support from default template
- problem "Commented cmake call found" if line.include?('# system "cmake')
-
- # 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|
- next unless line.include?(comment)
- problem "Please remove default template comments"
- end
-
- # FileUtils is included in Formula
- # encfs modifies a file with this name, so check for some leading characters
- if line =~ %r{[^'"/]FileUtils\.(\w+)}
- problem "Don't need 'FileUtils.' before #{Regexp.last_match(1)}."
- end
-
- # Check for long inreplace block vars
- if line =~ /inreplace .* do \|(.{2,})\|/
- problem "\"inreplace <filenames> do |s|\" is preferred over \"|#{Regexp.last_match(1)}|\"."
- end
-
# Check for string interpolation of single values.
if line =~ /(system|inreplace|gsub!|change_make_var!).*[ ,]"#\{([\w.]+)\}"/
problem "Don't need to interpolate \"#{Regexp.last_match(2)}\" with #{Regexp.last_match(1)}"
@@ -890,9 +884,6 @@ class FormulaAuditor
end
end
- # Commented-out depends_on
- problem "Commented-out dep #{Regexp.last_match(1)}" if line =~ /#\s*depends_on\s+(.+)\s*$/
-
if line =~ /if\s+ARGV\.include\?\s+'--(HEAD|devel)'/
problem "Use \"if build.#{Regexp.last_match(1).downcase}?\" instead"
end
@@ -905,6 +896,10 @@ class FormulaAuditor
problem "Use \"depends_on :x11\" instead of \"ENV.x11\""
end
+ if line.include?("ENV.java_cache")
+ problem "In-formula ENV.java_cache usage has been deprecated & should be removed."
+ 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 \"#{Regexp.last_match(3)}\""
@@ -1264,6 +1259,7 @@ class ResourceAuditor
end
elsif strategy <= SubversionDownloadStrategy
next unless DevelopmentTools.subversion_handles_most_https_certificates?
+ next unless Utils.svn_available?
unless Utils.svn_remote_exists url
problem "The URL #{url} is not a valid svn URL"
end
diff --git a/Library/Homebrew/dev-cmd/pull.rb b/Library/Homebrew/dev-cmd/pull.rb
index dd2bc6270..a8f35531f 100644
--- a/Library/Homebrew/dev-cmd/pull.rb
+++ b/Library/Homebrew/dev-cmd/pull.rb
@@ -587,7 +587,7 @@ module Homebrew
# We're in the cache; make sure to force re-download
loop do
begin
- curl_download url, to: filename
+ curl_download url, continue_at: 0, to: filename
break
rescue
if retry_count >= max_curl_retries
diff --git a/Library/Homebrew/download_strategy.rb b/Library/Homebrew/download_strategy.rb
index 2a8b6e585..adeb0a02a 100644
--- a/Library/Homebrew/download_strategy.rb
+++ b/Library/Homebrew/download_strategy.rb
@@ -381,7 +381,7 @@ class CurlDownloadStrategy < AbstractFileDownloadStrategy
# Curl options to be always passed to curl,
# with raw head calls (`curl --head`) or with actual `fetch`.
def _curl_opts
- return ["--user" << meta.fetch(:user)] if meta.key?(:user)
+ return ["--user", meta.fetch(:user)] if meta.key?(:user)
[]
end
diff --git a/Library/Homebrew/extend/ENV/shared.rb b/Library/Homebrew/extend/ENV/shared.rb
index b51ade48b..15488ee19 100644
--- a/Library/Homebrew/extend/ENV/shared.rb
+++ b/Library/Homebrew/extend/ENV/shared.rb
@@ -260,10 +260,6 @@ module SharedEnvExtension
set_cpu_flags(flags)
end
- def java_cache
- append "_JAVA_OPTIONS", "-Duser.home=#{HOMEBREW_CACHE}/java_cache"
- end
-
# ld64 is a newer linker provided for Xcode 2.5
# @private
def ld64
diff --git a/Library/Homebrew/extend/fileutils.rb b/Library/Homebrew/extend/fileutils.rb
index 52d4cbf51..ed5bfe6c3 100644
--- a/Library/Homebrew/extend/fileutils.rb
+++ b/Library/Homebrew/extend/fileutils.rb
@@ -3,7 +3,7 @@ require "tmpdir"
require "etc"
# Homebrew extends Ruby's `FileUtils` to make our code more readable.
-# @see http://ruby-doc.org/stdlib-2.0.0/libdoc/fileutils/rdoc/FileUtils.html Ruby's FileUtils API
+# @see https://ruby-doc.org/stdlib-2.0.0/libdoc/fileutils/rdoc/FileUtils.html Ruby's FileUtils API
module FileUtils
# Create a temporary directory then yield. When the block returns,
# recursively delete the temporary directory. Passing opts[:retain]
diff --git a/Library/Homebrew/extend/pathname.rb b/Library/Homebrew/extend/pathname.rb
index 767d83ff9..e1acd1f77 100644
--- a/Library/Homebrew/extend/pathname.rb
+++ b/Library/Homebrew/extend/pathname.rb
@@ -59,7 +59,7 @@ module DiskUsageExtension
end
# Homebrew extends Ruby's `Pathname` to make our code more readable.
-# @see http://ruby-doc.org/stdlib-1.8.7/libdoc/pathname/rdoc/Pathname.html Ruby's Pathname API
+# @see https://ruby-doc.org/stdlib-1.8.7/libdoc/pathname/rdoc/Pathname.html Ruby's Pathname API
class Pathname
include DiskUsageExtension
diff --git a/Library/Homebrew/formula.rb b/Library/Homebrew/formula.rb
index 8cea85a99..2f0c913c2 100644
--- a/Library/Homebrew/formula.rb
+++ b/Library/Homebrew/formula.rb
@@ -1613,6 +1613,7 @@ class Formula
def run_test
@prefix_returns_versioned_prefix = true
old_home = ENV["HOME"]
+ old_java_opts = ENV["_JAVA_OPTIONS"]
old_curl_home = ENV["CURL_HOME"]
old_tmpdir = ENV["TMPDIR"]
old_temp = ENV["TEMP"]
@@ -1626,6 +1627,7 @@ class Formula
ENV["TERM"] = "dumb"
ENV["PATH"] = PATH.new(old_path).append(HOMEBREW_PREFIX/"bin")
ENV["HOMEBREW_PATH"] = nil
+ ENV["_JAVA_OPTIONS"] = "#{old_java_opts} -Duser.home=#{HOMEBREW_CACHE}/java_cache"
ENV.clear_sensitive_environment!
@@ -1646,6 +1648,7 @@ class Formula
ensure
@testpath = nil
ENV["HOME"] = old_home
+ ENV["_JAVA_OPTIONS"] = old_java_opts
ENV["CURL_HOME"] = old_curl_home
ENV["TMPDIR"] = old_tmpdir
ENV["TEMP"] = old_temp
@@ -1888,11 +1891,13 @@ class Formula
mkdir_p env_home
old_home = ENV["HOME"]
+ old_java_opts = ENV["_JAVA_OPTIONS"]
old_curl_home = ENV["CURL_HOME"]
old_path = ENV["HOMEBREW_PATH"]
unless ARGV.interactive?
ENV["HOME"] = env_home
+ ENV["_JAVA_OPTIONS"] = "#{old_java_opts} -Duser.home=#{HOMEBREW_CACHE}/java_cache"
ENV["CURL_HOME"] = old_curl_home || old_home
end
ENV["HOMEBREW_PATH"] = nil
@@ -1907,6 +1912,7 @@ class Formula
@buildpath = nil
unless ARGV.interactive?
ENV["HOME"] = old_home
+ ENV["_JAVA_OPTIONS"] = old_java_opts
ENV["CURL_HOME"] = old_curl_home
end
ENV["HOMEBREW_PATH"] = old_path
diff --git a/Library/Homebrew/formula_installer.rb b/Library/Homebrew/formula_installer.rb
index 6c5b8bdab..216a375ce 100644
--- a/Library/Homebrew/formula_installer.rb
+++ b/Library/Homebrew/formula_installer.rb
@@ -85,13 +85,12 @@ class FormulaInstaller
return false if @pour_failed
bottle = formula.bottle
- return false unless bottle
+ return false if !bottle && !formula.local_bottle_path
return true if force_bottle?
return false if build_from_source? || build_bottle? || interactive?
return false if ARGV.cc
return false unless options.empty?
return false if formula.bottle_disabled?
- return true if formula.local_bottle_path
unless formula.pour_bottle?
if install_bottle_options[:warn] && formula.pour_bottle_check_unsatisfied_reason
opoo <<-EOS.undent
diff --git a/Library/Homebrew/gpg.rb b/Library/Homebrew/gpg.rb
index f56473df3..de2089dda 100644
--- a/Library/Homebrew/gpg.rb
+++ b/Library/Homebrew/gpg.rb
@@ -7,8 +7,7 @@ class Gpg
next unless gpg_short_version
gpg_version = Version.create(gpg_short_version.to_s)
@version = gpg_version
- gpg_version == Version.create("2.1") ||
- gpg_version == Version.create("2.0")
+ gpg_version >= Version.create("2.0")
end
end
@@ -38,12 +37,30 @@ class Gpg
Key-Length: 2048
Subkey-Type: RSA
Subkey-Length: 2048
- Passphrase: ''
Name-Real: Testing
Name-Email: testing@foo.bar
Expire-Date: 1d
+ %no-protection
%commit
EOS
system GPG_EXECUTABLE, "--batch", "--gen-key", "batch.gpg"
end
+
+ def self.cleanup_test_processes!
+ odie "No GPG present to test against!" unless available?
+ gpgconf = Pathname.new(GPG_EXECUTABLE).parent/"gpgconf"
+
+ system gpgconf, "--kill", "gpg-agent"
+ system gpgconf, "--homedir", "keyrings/live", "--kill",
+ "gpg-agent"
+ end
+
+ def self.test(path)
+ create_test_key(path)
+ begin
+ yield
+ ensure
+ cleanup_test_processes!
+ end
+ end
end
diff --git a/Library/Homebrew/manpages/brew-cask.1.md b/Library/Homebrew/manpages/brew-cask.1.md
index bfb9cd7a5..715d8fd77 100644
--- a/Library/Homebrew/manpages/brew-cask.1.md
+++ b/Library/Homebrew/manpages/brew-cask.1.md
@@ -1,5 +1,5 @@
brew-cask(1) - a friendly binary installer for macOS
-========================================================
+====================================================
## SYNOPSIS
@@ -85,7 +85,7 @@ names, and other aspects of this manual are still subject to change.
If <token> is given, summarize the staged files associated with the
given Cask.
-
+
* `outdated` [--greedy] [--verbose|--quiet] [ <token> ...]:
Without token arguments, display all the installed Casks that have newer
versions available in the tap; otherwise check only the tokens given
@@ -101,9 +101,10 @@ names, and other aspects of this manual are still subject to change.
Reinstall the given Cask.
* `search` or `-S` [<text> | /<regexp>/]:
- Without an argument, display all Casks available for install; otherwise
- perform a substring search of known Cask tokens for <text> or, if the
- text is delimited by slashes (/<regexp>/), it is interpreted as a
+ Without an argument, display all locally available Casks for install; no
+ online search is performed.
+ Otherwise perform a substring search of known Cask tokens for <text> or,
+ if the text is delimited by slashes (/<regexp>/), it is interpreted as a
Ruby regular expression.
* `style` [--fix] [ <token> ... ]:
@@ -255,7 +256,7 @@ Environment variables specific to Homebrew-Cask:
export HOMEBREW_CASK_OPTS='--appdir=~/Applications --fontdir=/Library/Fonts'
Other environment variables:
-
+
* `SUDO_ASKPASS`:
When this variable is set, Homebrew-Cask will call `sudo`(8) with the `-A` option.
diff --git a/Library/Homebrew/missing_formula.rb b/Library/Homebrew/missing_formula.rb
index 4d90ddb61..a3d182a2b 100644
--- a/Library/Homebrew/missing_formula.rb
+++ b/Library/Homebrew/missing_formula.rb
@@ -31,7 +31,7 @@ module Homebrew
#{Formatter.url("https://pip.readthedocs.io/en/stable/installing/")}
EOS
when "pil" then <<-EOS.undent
- Instead of PIL, consider `pip install pillow` or `brew install Homebrew/science/pillow`.
+ Instead of PIL, consider `pip2 install pillow`.
EOS
when "macruby" then <<-EOS.undent
MacRuby is not packaged and is on an indefinite development hiatus.
@@ -53,16 +53,7 @@ module Homebrew
ruin SSH's security.
EOS
when "gsutil" then <<-EOS.undent
- Install gsutil with `pip install gsutil`
- EOS
- when "clojure" then <<-EOS.undent
- Clojure isn't really a program but a library managed as part of a
- project and Leiningen is the user interface to that library.
-
- To install Clojure you should install Leiningen:
- brew install leiningen
- and then follow the tutorial:
- #{Formatter.url("https://github.com/technomancy/leiningen/blob/stable/doc/TUTORIAL.md")}
+ Install gsutil with `pip2 install gsutil`
EOS
when "gfortran" then <<-EOS.undent
GNU Fortran is now provided as part of GCC, and can be installed with:
diff --git a/Library/Homebrew/requirements/gpg2_requirement.rb b/Library/Homebrew/requirements/gpg2_requirement.rb
index d570983eb..ebdd71f6e 100644
--- a/Library/Homebrew/requirements/gpg2_requirement.rb
+++ b/Library/Homebrew/requirements/gpg2_requirement.rb
@@ -5,8 +5,8 @@ class GPG2Requirement < Requirement
fatal true
default_formula "gnupg"
- # GPGTools installs GnuPG 2.0.x as a vanilla `gpg` symlink
- # pointing to `gpg2`. Homebrew install 2.1.x as a non-symlink `gpg`.
- # We support both the 2.0.x "stable" and 2.1.x "modern" series here.
+ # GPGTools installs GnuPG 2.0.x as a `gpg` symlink pointing
+ # to `gpg2`. Our `gnupg` installs only a non-symlink `gpg`.
+ # The aim is to retain support for any version above 2.0.
satisfy(build_env: false) { Gpg.gpg || Gpg.gpg2 }
end
diff --git a/Library/Homebrew/rubocops/extend/formula_cop.rb b/Library/Homebrew/rubocops/extend/formula_cop.rb
index 862664010..7844f7bf2 100644
--- a/Library/Homebrew/rubocops/extend/formula_cop.rb
+++ b/Library/Homebrew/rubocops/extend/formula_cop.rb
@@ -86,9 +86,13 @@ module RuboCop
end
# Returns an array of method call nodes matching method_name in every descendant of node
- def find_every_method_call_by_name(node, method_name)
+ # Returns every method call if no method_name is passed
+ def find_every_method_call_by_name(node, method_name = nil)
return if node.nil?
- node.each_descendant(:send).select { |method_node| method_name == method_node.method_name }
+ node.each_descendant(:send).select do |method_node|
+ method_name.nil? ||
+ method_name == method_node.method_name
+ end
end
# Given a method_name and arguments, yields to a block with
@@ -108,7 +112,7 @@ module RuboCop
def find_instance_method_call(node, instance, method_name)
methods = find_every_method_call_by_name(node, method_name)
methods.each do |method|
- next unless method.receiver.const_name == instance
+ next unless method.receiver && method.receiver.const_name == instance
@offense_source_range = method.source_range
@offensive_node = method
yield method
@@ -202,9 +206,15 @@ module RuboCop
end
# Returns an array of block nodes of any depth below node in AST
+ # If a block is given then yields matching block node to the block!
def find_all_blocks(node, block_name)
return if node.nil?
- node.each_descendant(:block).select { |block_node| block_name == block_node.method_name }
+ blocks = node.each_descendant(:block).select { |block_node| block_name == block_node.method_name }
+ return blocks unless block_given?
+ blocks.each do |block_node|
+ offending_node(block_node)
+ yield block_node
+ end
end
# Returns a method definition node with method_name
@@ -316,6 +326,15 @@ module RuboCop
end
end
+ # Yields to a block with comment text as parameter
+ def audit_comments
+ @processed_source.comments.each do |comment_node|
+ @offensive_node = comment_node
+ @offense_source_range = :expression
+ yield comment_node.text
+ end
+ end
+
# Returns the begin position of the node's line in source code
def line_start_column(node)
node.source_range.source_buffer.line_range(node.loc.line).begin_pos
@@ -326,6 +345,11 @@ module RuboCop
node.source_range.begin_pos
end
+ # Returns the ending position of the node in source code
+ def end_column(node)
+ node.source_range.end_pos
+ end
+
# Returns the line number of the node
def line_number(node)
node.loc.line
diff --git a/Library/Homebrew/rubocops/lines_cop.rb b/Library/Homebrew/rubocops/lines_cop.rb
index 22039869b..ed50ba49c 100644
--- a/Library/Homebrew/rubocops/lines_cop.rb
+++ b/Library/Homebrew/rubocops/lines_cop.rb
@@ -15,6 +15,60 @@ module RuboCop
problem ":tex is deprecated" if depends_on?(:tex)
end
end
+
+ class ClassInheritance < FormulaCop
+ def audit_formula(_node, class_node, parent_class_node, _body_node)
+ begin_pos = start_column(parent_class_node)
+ end_pos = end_column(class_node)
+ return unless begin_pos-end_pos != 3
+ problem "Use a space in class inheritance: class #{@formula_name} < #{class_name(parent_class_node)}"
+ end
+ end
+
+ class Comments < FormulaCop
+ def audit_formula(_node, _class_node, _parent_class_node, _body_node)
+ audit_comments do |comment|
+ [
+ "# 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",
+ '# system "cmake',
+ ].each do |template_comment|
+ next unless comment.include?(template_comment)
+ problem "Please remove default template comments"
+ break
+ end
+ end
+
+ audit_comments do |comment|
+ # Commented-out depends_on
+ next unless comment =~ /#\s*depends_on\s+(.+)\s*$/
+ problem "Commented-out dependency #{Regexp.last_match(1)}"
+ end
+ end
+ end
+
+ class Miscellaneous < FormulaCop
+ def audit_formula(_node, _class_node, _parent_class_node, body_node)
+ # FileUtils is included in Formula
+ # encfs modifies a file with this name, so check for some leading characters
+ find_instance_method_call(body_node, "FileUtils", nil) do |method_node|
+ problem "Don't need 'FileUtils.' before #{method_node.method_name}"
+ end
+
+ # Check for long inreplace block vars
+ find_all_blocks(body_node, :inreplace) do |node|
+ block_arg = node.arguments.children.first
+ next unless block_arg.source.size>1
+ problem "\"inreplace <filenames> do |s|\" is preferred over \"|#{block_arg.source}|\"."
+ end
+ end
+ end
end
end
end
diff --git a/Library/Homebrew/rubocops/patches_cop.rb b/Library/Homebrew/rubocops/patches_cop.rb
index b27283382..7ee1a127a 100644
--- a/Library/Homebrew/rubocops/patches_cop.rb
+++ b/Library/Homebrew/rubocops/patches_cop.rb
@@ -25,12 +25,22 @@ module RuboCop
def patch_problems(patch)
patch_url = string_content(patch)
+ gh_patch_param_pattern = %r{https?://github\.com/.+/.+/(?:commit|pull)/[a-fA-F0-9]*.(?:patch|diff)}
+ if regex_match_group(patch, gh_patch_param_pattern)
+ if patch_url !~ /\?full_index=\w+$/
+ problem <<-EOS.undent
+ GitHub patches should use the full_index parameter:
+ #{patch_url}?full_index=1
+ EOS
+ end
+ end
+
gh_patch_patterns = Regexp.union([%r{/raw\.github\.com/},
%r{gist\.github\.com/raw},
%r{gist\.github\.com/.+/raw},
%r{gist\.githubusercontent\.com/.+/raw}])
if regex_match_group(patch, gh_patch_patterns)
- unless patch_url =~ /[a-fA-F0-9]{40}/
+ if patch_url !~ /[a-fA-F0-9]{40}/
problem <<-EOS.undent.chomp
GitHub/Gist patches should specify a revision:
#{patch_url}
diff --git a/Library/Homebrew/test/cask/cli/search_spec.rb b/Library/Homebrew/test/cask/cli/search_spec.rb
index e237ad464..6dc980590 100644
--- a/Library/Homebrew/test/cask/cli/search_spec.rb
+++ b/Library/Homebrew/test/cask/cli/search_spec.rb
@@ -22,16 +22,36 @@ describe Hbc::CLI::Search, :cask do
EOS
end
+ it "returns matches even when online search failed" do
+ allow(GitHub).to receive(:search_code).and_raise(GitHub::Error.new("reason"))
+ expect {
+ Hbc::CLI::Search.run("local")
+ }.to output(<<-EOS.undent).to_stdout
+ local-caffeine
+ local-transmission
+ EOS
+ .and output(/^Warning: Error searching on GitHub: reason/).to_stderr
+ end
+
it "shows that there are no Casks matching a search term that did not result in anything" do
expect {
Hbc::CLI::Search.run("foo-bar-baz")
- }.to output("No Cask found for \"foo-bar-baz\".\n").to_stdout.as_tty
+ }.to output(<<-EOS.undent).to_stdout.as_tty
+ No Cask found for "foo-bar-baz".
+ EOS
end
- it "lists all available Casks with no search term" do
- expect {
- Hbc::CLI::Search.run
- }.to output(/local-caffeine/).to_stdout.as_tty
+ it "doesn't output anything to non-TTY stdout when there are no matches" do
+ expect { Hbc::CLI::Search.run("foo-bar-baz") }
+ .to not_to_output.to_stdout
+ .and not_to_output.to_stderr
+ end
+
+ it "lists all Casks available offline with no search term" do
+ allow(GitHub).to receive(:search_code).and_raise(GitHub::Error.new("reason"))
+ expect { Hbc::CLI::Search.run }
+ .to output(/local-caffeine/).to_stdout.as_tty
+ .and not_to_output.to_stderr
end
it "ignores hyphens in search terms" do
@@ -55,19 +75,29 @@ describe Hbc::CLI::Search, :cask do
it "accepts a regexp argument" do
expect {
Hbc::CLI::Search.run("/^local-c[a-z]ffeine$/")
- }.to output("==> Regexp Matches\nlocal-caffeine\n").to_stdout.as_tty
+ }.to output(<<-EOS.undent).to_stdout.as_tty
+ ==> Regexp Matches
+ local-caffeine
+ EOS
end
- it "Returns both exact and partial matches" do
+ it "returns both exact and partial matches" do
expect {
Hbc::CLI::Search.run("test-opera")
- }.to output(/^==> Exact Match\ntest-opera\n==> Partial Matches\ntest-opera-mail/).to_stdout.as_tty
+ }.to output(<<-EOS.undent).to_stdout.as_tty
+ ==> Exact Match
+ test-opera
+ ==> Partial Matches
+ test-opera-mail
+ EOS
end
it "does not search the Tap name" do
expect {
Hbc::CLI::Search.run("caskroom")
- }.to output(/^No Cask found for "caskroom"\.\n/).to_stdout.as_tty
+ }.to output(<<-EOS.undent).to_stdout.as_tty
+ No Cask found for "caskroom".
+ EOS
end
it "doesn't highlight packages that aren't installed" do
diff --git a/Library/Homebrew/test/cleanup_spec.rb b/Library/Homebrew/test/cleanup_spec.rb
index 4e5e42efa..da262c5ca 100644
--- a/Library/Homebrew/test/cleanup_spec.rb
+++ b/Library/Homebrew/test/cleanup_spec.rb
@@ -5,6 +5,7 @@ require "pathname"
describe Homebrew::Cleanup do
let(:ds_store) { Pathname.new("#{HOMEBREW_PREFIX}/Library/.DS_Store") }
+ let(:sec_in_a_day) { 60 * 60 * 24 }
around(:each) do |example|
begin
@@ -104,14 +105,30 @@ describe Homebrew::Cleanup do
expect(f4).to be_installed
end
- specify "::cleanup_logs" do
- path = (HOMEBREW_LOGS/"delete_me")
- path.mkpath
- ARGV << "--prune=all"
+ describe "::cleanup_logs" do
+ let(:path) { (HOMEBREW_LOGS/"delete_me") }
- described_class.cleanup_logs
+ before do
+ path.mkpath
+ end
+
+ it "cleans all logs if prune all" do
+ ARGV << "--prune=all"
+ described_class.cleanup_logs
+ expect(path).not_to exist
+ end
- expect(path).not_to exist
+ it "cleans up logs if older than 14 days" do
+ allow_any_instance_of(Pathname).to receive(:mtime).and_return(Time.now - sec_in_a_day * 15)
+ described_class.cleanup_logs
+ expect(path).not_to exist
+ end
+
+ it "does not clean up logs less than 14 days old" do
+ allow_any_instance_of(Pathname).to receive(:mtime).and_return(Time.now - sec_in_a_day * 2)
+ described_class.cleanup_logs
+ expect(path).to exist
+ end
end
describe "::cleanup_cache" do
@@ -124,6 +141,15 @@ describe Homebrew::Cleanup do
expect(incomplete).not_to exist
end
+ it "cleans up 'glide_home'" do
+ glide_home = (HOMEBREW_CACHE/"glide_home")
+ glide_home.mkpath
+
+ described_class.cleanup_cache
+
+ expect(glide_home).not_to exist
+ end
+
it "cleans up 'java_cache'" do
java_cache = (HOMEBREW_CACHE/"java_cache")
java_cache.mkpath
@@ -141,5 +167,99 @@ describe Homebrew::Cleanup do
expect(npm_cache).not_to exist
end
+
+ it "cleans up all files and directories" do
+ git = (HOMEBREW_CACHE/"gist--git")
+ gist = (HOMEBREW_CACHE/"gist")
+ svn = (HOMEBREW_CACHE/"gist--svn")
+
+ git.mkpath
+ gist.mkpath
+ FileUtils.touch svn
+
+ allow(ARGV).to receive(:value).with("prune").and_return("all")
+
+ described_class.cleanup_cache
+
+ expect(git).not_to exist
+ expect(gist).to exist
+ expect(svn).not_to exist
+ end
+
+ it "does not clean up directories that are not VCS checkouts" do
+ git = (HOMEBREW_CACHE/"git")
+ git.mkpath
+ allow(ARGV).to receive(:value).with("prune").and_return("all")
+
+ described_class.cleanup_cache
+
+ expect(git).to exist
+ end
+
+ it "cleans up VCS checkout directories with modified time < prune time" do
+ foo = (HOMEBREW_CACHE/"--foo")
+ foo.mkpath
+ allow(ARGV).to receive(:value).with("prune").and_return("1")
+ allow_any_instance_of(Pathname).to receive(:mtime).and_return(Time.now - sec_in_a_day * 2)
+ described_class.cleanup_cache
+ expect(foo).not_to exist
+ end
+
+ it "does not clean up VCS checkout directories with modified time >= prune time" do
+ foo = (HOMEBREW_CACHE/"--foo")
+ foo.mkpath
+ allow(ARGV).to receive(:value).with("prune").and_return("1")
+ described_class.cleanup_cache
+ expect(foo).to exist
+ end
+
+ context "cleans old files in HOMEBREW_CACHE" do
+ let(:bottle) { (HOMEBREW_CACHE/"testball-0.0.1.bottle.tar.gz") }
+ let(:testball) { (HOMEBREW_CACHE/"testball-0.0.1") }
+
+ before(:each) do
+ FileUtils.touch(bottle)
+ FileUtils.touch(testball)
+ (HOMEBREW_CELLAR/"testball"/"0.0.1").mkpath
+ FileUtils.touch(CoreTap.instance.formula_dir/"testball.rb")
+ end
+
+ it "cleans up file if outdated" do
+ allow(Utils::Bottles).to receive(:file_outdated?).with(any_args).and_return(true)
+ described_class.cleanup_cache
+ expect(bottle).not_to exist
+ expect(testball).not_to exist
+ end
+
+ it "cleans up file if ARGV has -s and formula not installed" do
+ ARGV << "-s"
+ described_class.cleanup_cache
+ expect(bottle).not_to exist
+ expect(testball).not_to exist
+ end
+
+ it "cleans up file if stale" do
+ described_class.cleanup_cache
+ expect(bottle).not_to exist
+ expect(testball).not_to exist
+ end
+ end
+ end
+
+ describe "::prune?" do
+ before do
+ foo.mkpath
+ end
+
+ let(:foo) { HOMEBREW_CACHE/"foo" }
+
+ it "returns true when path_modified_time < days_default" do
+ allow_any_instance_of(Pathname).to receive(:mtime).and_return(Time.now - sec_in_a_day * 2)
+ expect(described_class.prune?(foo, days_default: "1")).to be_truthy
+ end
+
+ it "returns false when path_modified_time >= days_default" do
+ expect(described_class.prune?(foo, days_default: "2")).to be_falsey
+ end
end
end
diff --git a/Library/Homebrew/test/cmd/search_remote_tap_spec.rb b/Library/Homebrew/test/cmd/search_remote_tap_spec.rb
index b0beb122c..eb256b924 100644
--- a/Library/Homebrew/test/cmd/search_remote_tap_spec.rb
+++ b/Library/Homebrew/test/cmd/search_remote_tap_spec.rb
@@ -2,6 +2,9 @@ require "cmd/search"
describe Homebrew do
specify "#search_taps" do
+ # Otherwise the tested method returns [], regardless of our stub
+ ENV.delete("HOMEBREW_NO_GITHUB_API")
+
json_response = {
"items" => [
{
diff --git a/Library/Homebrew/test/cmd/search_spec.rb b/Library/Homebrew/test/cmd/search_spec.rb
index 77c2c6352..36ddde3e1 100644
--- a/Library/Homebrew/test/cmd/search_spec.rb
+++ b/Library/Homebrew/test/cmd/search_spec.rb
@@ -53,7 +53,7 @@ describe "brew search", :integration_test do
"debian" => "https://packages.debian.org/search?keywords=testball&searchon=names&suite=all&section=all",
"opensuse" => "https://software.opensuse.org/search?q=testball",
"fedora" => "https://apps.fedoraproject.org/packages/s/testball",
- "ubuntu" => "http://packages.ubuntu.com/search?keywords=testball&searchon=names&suite=all&section=all",
+ "ubuntu" => "https://packages.ubuntu.com/search?keywords=testball&searchon=names&suite=all&section=all",
}.each do |flag, url|
specify "--#{flag}" do
expect { brew "search", "--#{flag}", "testball", "HOMEBREW_BROWSER" => "echo" }
diff --git a/Library/Homebrew/test/dev-cmd/audit_spec.rb b/Library/Homebrew/test/dev-cmd/audit_spec.rb
index f2d8a8e7c..037865fdf 100644
--- a/Library/Homebrew/test/dev-cmd/audit_spec.rb
+++ b/Library/Homebrew/test/dev-cmd/audit_spec.rb
@@ -263,28 +263,6 @@ describe FormulaAuditor do
expect(fa.problems.shift)
.to eq('Use pkgshare instead of (share/"foolibc++")')
end
-
- specify "no space in class inheritance" do
- fa = formula_auditor "foo", <<-EOS.undent
- class Foo<Formula
- url '/foo-1.0.tgz'
- end
- EOS
-
- fa.line_problems "class Foo<Formula", 1
- expect(fa.problems.shift)
- .to eq("Use a space in class inheritance: class Foo < Formula")
- end
-
- specify "default template" do
- fa = formula_auditor "foo", "class Foo < Formula; url '/foo-1.0.tgz'; end"
-
- fa.line_problems '# system "cmake", ".", *std_cmake_args', 3
- expect(fa.problems.shift).to eq("Commented cmake call found")
-
- fa.line_problems "# PLEASE REMOVE", 3
- expect(fa.problems.shift).to eq("Please remove default template comments")
- end
end
describe "#audit_github_repository" do
diff --git a/Library/Homebrew/test/download_strategies_spec.rb b/Library/Homebrew/test/download_strategies_spec.rb
index 8c376a649..06d6fa855 100644
--- a/Library/Homebrew/test/download_strategies_spec.rb
+++ b/Library/Homebrew/test/download_strategies_spec.rb
@@ -200,6 +200,17 @@ describe GitDownloadStrategy do
end
end
+describe CurlDownloadStrategy do
+ subject { described_class.new(name, resource) }
+ let(:name) { "foo" }
+ let(:url) { "http://example.com/foo.tar.gz" }
+ let(:resource) { double(Resource, url: url, mirrors: [], specs: { user: "download:123456" }, version: nil) }
+
+ it "parses the opts and sets the corresponding args" do
+ expect(subject.send(:_curl_opts)).to eq(["--user", "download:123456"])
+ end
+end
+
describe DownloadStrategyDetector do
describe "::detect" do
subject { described_class.detect(url) }
diff --git a/Library/Homebrew/test/missing_formula_spec.rb b/Library/Homebrew/test/missing_formula_spec.rb
index a48f12ecd..0a905004b 100644
--- a/Library/Homebrew/test/missing_formula_spec.rb
+++ b/Library/Homebrew/test/missing_formula_spec.rb
@@ -82,12 +82,6 @@ describe Homebrew::MissingFormula do
it { is_expected.to be_blacklisted }
end
- context "clojure" do
- subject { "clojure" }
-
- it { is_expected.to be_blacklisted }
- end
-
context "gfortran" do
subject { "gfortran" }
diff --git a/Library/Homebrew/test/rubocops/lines_cop_spec.rb b/Library/Homebrew/test/rubocops/lines_cop_spec.rb
index c865e1480..b0ed8f4d1 100644
--- a/Library/Homebrew/test/rubocops/lines_cop_spec.rb
+++ b/Library/Homebrew/test/rubocops/lines_cop_spec.rb
@@ -51,3 +51,154 @@ describe RuboCop::Cop::FormulaAudit::Lines do
end
end
end
+
+describe RuboCop::Cop::FormulaAudit::ClassInheritance do
+ subject(:cop) { described_class.new }
+
+ context "When auditing lines" do
+ it "with no space in class inheritance" do
+ source = <<-EOS.undent
+ class Foo<Formula
+ desc "foo"
+ url 'http://example.com/foo-1.0.tgz'
+ end
+ EOS
+
+ expected_offenses = [{ message: "Use a space in class inheritance: class Foo < Formula",
+ severity: :convention,
+ line: 1,
+ column: 10,
+ source: source }]
+
+ inspect_source(cop, source)
+
+ expected_offenses.zip(cop.offenses).each do |expected, actual|
+ expect_offense(expected, actual)
+ end
+ end
+ end
+end
+
+describe RuboCop::Cop::FormulaAudit::Comments do
+ subject(:cop) { described_class.new }
+
+ context "When auditing formula" do
+ it "with commented cmake call" do
+ source = <<-EOS.undent
+ class Foo < Formula
+ desc "foo"
+ url 'http://example.com/foo-1.0.tgz'
+ # system "cmake", ".", *std_cmake_args
+ end
+ EOS
+
+ expected_offenses = [{ message: "Please remove default template comments",
+ severity: :convention,
+ line: 4,
+ column: 2,
+ source: source }]
+
+ inspect_source(cop, source)
+
+ expected_offenses.zip(cop.offenses).each do |expected, actual|
+ expect_offense(expected, actual)
+ end
+ end
+
+ it "with default template comments" do
+ source = <<-EOS.undent
+ class Foo < Formula
+ # PLEASE REMOVE
+ desc "foo"
+ url 'http://example.com/foo-1.0.tgz'
+ end
+ EOS
+
+ expected_offenses = [{ message: "Please remove default template comments",
+ severity: :convention,
+ line: 2,
+ column: 2,
+ source: source }]
+
+ inspect_source(cop, source)
+
+ expected_offenses.zip(cop.offenses).each do |expected, actual|
+ expect_offense(expected, actual)
+ end
+ end
+
+ it "with commented out depends_on" do
+ source = <<-EOS.undent
+ class Foo < Formula
+ desc "foo"
+ url 'http://example.com/foo-1.0.tgz'
+ # depends_on "foo"
+ end
+ EOS
+
+ expected_offenses = [{ message: 'Commented-out dependency "foo"',
+ severity: :convention,
+ line: 4,
+ column: 2,
+ source: source }]
+
+ inspect_source(cop, source)
+
+ expected_offenses.zip(cop.offenses).each do |expected, actual|
+ expect_offense(expected, actual)
+ end
+ end
+ end
+end
+
+describe RuboCop::Cop::FormulaAudit::Miscellaneous do
+ subject(:cop) { described_class.new }
+
+ context "When auditing formula" do
+ it "with FileUtils" do
+ source = <<-EOS.undent
+ class Foo < Formula
+ desc "foo"
+ url 'http://example.com/foo-1.0.tgz'
+ FileUtils.mv "hello"
+ end
+ EOS
+
+ expected_offenses = [{ message: "Don't need 'FileUtils.' before mv",
+ severity: :convention,
+ line: 4,
+ column: 2,
+ source: source }]
+
+ inspect_source(cop, source)
+
+ expected_offenses.zip(cop.offenses).each do |expected, actual|
+ expect_offense(expected, actual)
+ end
+ end
+
+ it "with long inreplace block vars" do
+ source = <<-EOS.undent
+ class Foo < Formula
+ desc "foo"
+ url 'http://example.com/foo-1.0.tgz'
+ inreplace "foo" do |longvar|
+ somerandomCall(longvar)
+ end
+ end
+ EOS
+
+ expected_offenses = [{ message: "\"inreplace <filenames> do |s|\" is preferred over \"|longvar|\".",
+ severity: :convention,
+ line: 4,
+ column: 2,
+ source: source }]
+
+ inspect_source(cop, source)
+
+ expected_offenses.zip(cop.offenses).each do |expected, actual|
+ expect_offense(expected, actual)
+ end
+ end
+ end
+end
diff --git a/Library/Homebrew/test/rubocops/patches_cop_spec.rb b/Library/Homebrew/test/rubocops/patches_cop_spec.rb
index 092782bfb..28915a1ec 100644
--- a/Library/Homebrew/test/rubocops/patches_cop_spec.rb
+++ b/Library/Homebrew/test/rubocops/patches_cop_spec.rb
@@ -28,11 +28,11 @@ describe RuboCop::Cop::FormulaAudit::Patches do
end
EOS
- expected_offenses = [{ message: "Use the patch DSL instead of defining a 'patches' method",
- severity: :convention,
- line: 4,
- column: 2,
- source: source }]
+ expected_offenses = [{ message: "Use the patch DSL instead of defining a 'patches' method",
+ severity: :convention,
+ line: 4,
+ column: 2,
+ source: source }]
inspect_source(cop, source)
@@ -48,6 +48,7 @@ describe RuboCop::Cop::FormulaAudit::Patches do
"http://trac.macports.org/export/102865/trunk/dports/mail/uudeview/files/inews.c.patch",
"http://bugs.debian.org/cgi-bin/bugreport.cgi?msg=5;filename=patch-libunac1.txt;att=1;bug=623340",
"https://patch-diff.githubusercontent.com/raw/foo/foo-bar/pull/100.patch",
+ "https://github.com/dlang/dub/pull/1221.patch",
]
patch_urls.each do |patch_url|
source = <<-EOS.undent
@@ -61,55 +62,64 @@ describe RuboCop::Cop::FormulaAudit::Patches do
EOS
inspect_source(cop, source)
- if patch_url =~ %r{/raw\.github\.com/}
- expected_offenses = [{ message: <<-EOS.undent.chomp,
- GitHub/Gist patches should specify a revision:
- #{patch_url}
- EOS
- severity: :convention,
- line: 5,
- column: 12,
- source: source }]
+ expected_offense = if patch_url =~ %r{/raw\.github\.com/}
+ [{ message: <<-EOS.undent.chomp,
+ GitHub/Gist patches should specify a revision:
+ #{patch_url}
+ EOS
+ severity: :convention,
+ line: 5,
+ column: 12,
+ source: source }]
elsif patch_url =~ %r{macports/trunk}
- expected_offenses = [{ message: <<-EOS.undent.chomp,
- MacPorts patches should specify a revision instead of trunk:
- #{patch_url}
- EOS
- severity: :convention,
- line: 5,
- column: 33,
- source: source }]
+ [{ message: <<-EOS.undent.chomp,
+ MacPorts patches should specify a revision instead of trunk:
+ #{patch_url}
+ EOS
+ severity: :convention,
+ line: 5,
+ column: 33,
+ source: source }]
elsif patch_url =~ %r{^http://trac\.macports\.org}
- expected_offenses = [{ message: <<-EOS.undent.chomp,
- Patches from MacPorts Trac should be https://, not http:
- #{patch_url}
- EOS
- severity: :convention,
- line: 5,
- column: 5,
- source: source }]
+ [{ message: <<-EOS.undent.chomp,
+ Patches from MacPorts Trac should be https://, not http:
+ #{patch_url}
+ EOS
+ severity: :convention,
+ line: 5,
+ column: 5,
+ source: source }]
elsif patch_url =~ %r{^http://bugs\.debian\.org}
- expected_offenses = [{ message: <<-EOS.undent.chomp,
- Patches from Debian should be https://, not http:
- #{patch_url}
- EOS
- severity: :convention,
- line: 5,
- column: 5,
- source: source }]
+ [{ message: <<-EOS.undent.chomp,
+ Patches from Debian should be https://, not http:
+ #{patch_url}
+ EOS
+ severity: :convention,
+ line: 5,
+ column: 5,
+ source: source }]
elsif patch_url =~ %r{https?://patch-diff\.githubusercontent\.com/raw/(.+)/(.+)/pull/(.+)\.(?:diff|patch)}
- expected_offenses = [{ message: <<-EOS.undent,
- use GitHub pull request URLs:
- https://github.com/foo/foo-bar/pull/100.patch
- Rather than patch-diff:
- https://patch-diff.githubusercontent.com/raw/foo/foo-bar/pull/100.patch
- EOS
- severity: :convention,
- line: 5,
- column: 5,
- source: source }]
+ [{ message: <<-EOS.undent,
+ use GitHub pull request URLs:
+ https://github.com/foo/foo-bar/pull/100.patch
+ Rather than patch-diff:
+ https://patch-diff.githubusercontent.com/raw/foo/foo-bar/pull/100.patch
+ EOS
+ severity: :convention,
+ line: 5,
+ column: 5,
+ source: source }]
+ elsif patch_url =~ %r{https?://github\.com/.+/.+/(?:commit|pull)/[a-fA-F0-9]*.(?:patch|diff)}
+ [{ message: <<-EOS.undent,
+ GitHub patches should use the full_index parameter:
+ #{patch_url}?full_index=1
+ EOS
+ severity: :convention,
+ line: 5,
+ column: 5,
+ source: source }]
end
- expected_offenses.zip([cop.offenses.last]).each do |expected, actual|
+ expected_offense.zip([cop.offenses.last]).each do |expected, actual|
expect_offense(expected, actual)
end
end
@@ -130,19 +140,19 @@ describe RuboCop::Cop::FormulaAudit::Patches do
end
EOS
- expected_offenses = [{ message: "Use the patch DSL instead of defining a 'patches' method",
- severity: :convention,
- line: 4,
- column: 2,
- source: source },
- { message: <<-EOS.undent.chomp,
- Patches from MacPorts Trac should be https://, not http:
- http://trac.macports.org/export/68507/trunk/dports/net/trafshow/files/
- EOS
- severity: :convention,
- line: 8,
- column: 26,
- source: source }]
+ expected_offenses = [{ message: "Use the patch DSL instead of defining a 'patches' method",
+ severity: :convention,
+ line: 4,
+ column: 2,
+ source: source },
+ { message: <<-EOS.undent.chomp,
+ Patches from MacPorts Trac should be https://, not http:
+ http://trac.macports.org/export/68507/trunk/dports/net/trafshow/files/
+ EOS
+ severity: :convention,
+ line: 8,
+ column: 26,
+ source: source }]
inspect_source(cop, source)
@@ -174,55 +184,55 @@ describe RuboCop::Cop::FormulaAudit::Patches do
EOS
inspect_source(cop, source)
- if patch_url =~ %r{/raw\.github\.com/}
- expected_offenses = [{ message: <<-EOS.undent.chomp,
- GitHub/Gist patches should specify a revision:
- #{patch_url}
- EOS
- severity: :convention,
- line: 5,
- column: 16,
- source: source }]
+ expected_offense = if patch_url =~ %r{/raw\.github\.com/}
+ [{ message: <<-EOS.undent.chomp,
+ GitHub/Gist patches should specify a revision:
+ #{patch_url}
+ EOS
+ severity: :convention,
+ line: 5,
+ column: 16,
+ source: source }]
elsif patch_url =~ %r{macports/trunk}
- expected_offenses = [{ message: <<-EOS.undent.chomp,
- MacPorts patches should specify a revision instead of trunk:
- #{patch_url}
- EOS
- severity: :convention,
- line: 5,
- column: 37,
- source: source }]
+ [{ message: <<-EOS.undent.chomp,
+ MacPorts patches should specify a revision instead of trunk:
+ #{patch_url}
+ EOS
+ severity: :convention,
+ line: 5,
+ column: 37,
+ source: source }]
elsif patch_url =~ %r{^http://trac\.macports\.org}
- expected_offenses = [{ message: <<-EOS.undent.chomp,
- Patches from MacPorts Trac should be https://, not http:
- #{patch_url}
- EOS
- severity: :convention,
- line: 5,
- column: 9,
- source: source }]
+ [{ message: <<-EOS.undent.chomp,
+ Patches from MacPorts Trac should be https://, not http:
+ #{patch_url}
+ EOS
+ severity: :convention,
+ line: 5,
+ column: 9,
+ source: source }]
elsif patch_url =~ %r{^http://bugs\.debian\.org}
- expected_offenses = [{ message: <<-EOS.undent.chomp,
- Patches from Debian should be https://, not http:
- #{patch_url}
- EOS
- severity: :convention,
- line: 5,
- column: 9,
- source: source }]
+ [{ message: <<-EOS.undent.chomp,
+ Patches from Debian should be https://, not http:
+ #{patch_url}
+ EOS
+ severity: :convention,
+ line: 5,
+ column: 9,
+ source: source }]
elsif patch_url =~ %r{https?://patch-diff\.githubusercontent\.com/raw/(.+)/(.+)/pull/(.+)\.(?:diff|patch)}
- expected_offenses = [{ message: <<-EOS.undent,
- use GitHub pull request URLs:
- https://github.com/foo/foo-bar/pull/100.patch
- Rather than patch-diff:
- https://patch-diff.githubusercontent.com/raw/foo/foo-bar/pull/100.patch
- EOS
- severity: :convention,
- line: 5,
- column: 9,
- source: source }]
+ [{ message: <<-EOS.undent,
+ use GitHub pull request URLs:
+ https://github.com/foo/foo-bar/pull/100.patch
+ Rather than patch-diff:
+ https://patch-diff.githubusercontent.com/raw/foo/foo-bar/pull/100.patch
+ EOS
+ severity: :convention,
+ line: 5,
+ column: 9,
+ source: source }]
end
- expected_offenses.zip([cop.offenses.last]).each do |expected, actual|
+ expected_offense.zip([cop.offenses.last]).each do |expected, actual|
expect_offense(expected, actual)
end
end
diff --git a/Library/Homebrew/test/utils/analytics_spec.rb b/Library/Homebrew/test/utils/analytics_spec.rb
new file mode 100644
index 000000000..bb6cda0b1
--- /dev/null
+++ b/Library/Homebrew/test/utils/analytics_spec.rb
@@ -0,0 +1,88 @@
+require "utils/analytics"
+require "formula_installer"
+
+describe Utils::Analytics do
+ describe "::os_prefix_ci" do
+ context "when anonymous_os_prefix_ci is not set" do
+ before(:each) do
+ described_class.clear_anonymous_os_prefix_ci_cache
+ end
+
+ it "returns OS_VERSION and prefix when HOMEBREW_PREFIX is not /usr/local" do
+ stub_const("HOMEBREW_PREFIX", "blah")
+ expect(described_class.os_prefix_ci).to include("#{OS_VERSION}, non-/usr/local")
+ end
+
+ it "includes CI when ENV['CI'] is set" do
+ ENV["CI"] = "true"
+ expect(described_class.os_prefix_ci).to include("CI")
+ end
+
+ it "does not include prefix when HOMEBREW_PREFIX is /usr/local" do
+ stub_const("HOMEBREW_PREFIX", "/usr/local")
+ expect(described_class.os_prefix_ci).not_to include("non-/usr/local")
+ end
+ end
+ end
+
+ describe "::report_event" do
+ let(:f) { formula { url "foo-1.0" } }
+ let(:options) { FormulaInstaller.new(f).display_options(f) }
+ let(:action) { "#{f.full_name} #{options}".strip }
+
+ context "when ENV vars is set" do
+ it "returns nil when HOMEBREW_NO_ANALYTICS is true" do
+ ENV["HOMEBREW_NO_ANALYTICS"] = "true"
+ expect(described_class.report_event("install", action)).to be_nil
+ end
+
+ it "returns nil when HOMEBREW_NO_ANALYTICS_THIS_RUN is true" do
+ ENV["HOMEBREW_NO_ANALYTICS_THIS_RUN"] = "true"
+ expect(described_class.report_event("install", action)).to be_nil
+ end
+
+ it "returns nil when HOMEBREW_ANALYTICS_DEBUG is true" do
+ ENV.delete("HOMEBREW_NO_ANALYTICS_THIS_RUN")
+ ENV.delete("HOMEBREW_NO_ANALYTICS")
+ ENV["HOMEBREW_ANALYTICS_DEBUG"] = "true"
+ expect(described_class.report_event("install", action)).to be_nil
+ end
+ end
+ end
+
+ describe "::report_build_error" do
+ context "when tap is installed" do
+ let(:err) { BuildError.new(f, "badprg", %w[arg1 arg2], {}) }
+ let(:f) { formula { url "foo-1.0" } }
+
+ it "reports event if BuildError raised for a formula with a public remote repository" do
+ allow_any_instance_of(Tap).to receive(:custom_remote?).and_return(false)
+ expect(described_class).to respond_to(:report_event)
+ described_class.report_build_error(err)
+ end
+
+ it "does not report event if BuildError raised for a formula with a private remote repository" do
+ expect(described_class.report_build_error(err)).to be_nil
+ end
+ end
+
+ context "when formula does not have a tap" do
+ let(:err) { BuildError.new(f, "badprg", %w[arg1 arg2], {}) }
+ let(:f) { double(Formula, name: "foo", path: "blah", tap: nil) }
+
+ it "does not report event if BuildError is raised" do
+ expect(described_class.report_build_error(err)).to be_nil
+ end
+ end
+
+ context "when tap for a formula is not installed" do
+ let(:err) { BuildError.new(f, "badprg", %w[arg1 arg2], {}) }
+ let(:f) { double(Formula, name: "foo", path: "blah", tap: CoreTap.instance) }
+
+ it "does not report event if BuildError is raised" do
+ allow_any_instance_of(Pathname).to receive(:directory?).and_return(false)
+ expect(described_class.report_build_error(err)).to be_nil
+ end
+ end
+ end
+end
diff --git a/Library/Homebrew/test/utils/git_spec.rb b/Library/Homebrew/test/utils/git_spec.rb
new file mode 100644
index 000000000..e511212f4
--- /dev/null
+++ b/Library/Homebrew/test/utils/git_spec.rb
@@ -0,0 +1,150 @@
+require "utils/git"
+
+describe Git do
+ before(:each) do
+ git = HOMEBREW_SHIMS_PATH/"scm/git"
+
+ HOMEBREW_CACHE.cd do
+ system git, "init"
+
+ File.open(file, "w") { |f| f.write("blah") }
+ system git, "add", HOMEBREW_CACHE/file
+ system git, "commit", "-m", "'File added'"
+ @h1 = `git rev-parse HEAD`
+
+ File.open(file, "w") { |f| f.write("brew") }
+ system git, "add", HOMEBREW_CACHE/file
+ system git, "commit", "-m", "'written to File'"
+ @h2 = `git rev-parse HEAD`
+ end
+ end
+
+ let(:file) { "blah.rb" }
+ let(:hash1) { @h1[0..6] }
+ let(:hash2) { @h2[0..6] }
+
+ describe "#last_revision_commit_of_file" do
+ it "gives last revision commit when before_commit is nil" do
+ expect(
+ described_class.last_revision_commit_of_file(HOMEBREW_CACHE, file),
+ ).to eq(hash1)
+ end
+
+ it "gives revision commit based on before_commit when it is not nil" do
+ expect(
+ described_class.last_revision_commit_of_file(HOMEBREW_CACHE,
+ file,
+ before_commit: hash2),
+ ).to eq(hash2)
+ end
+ end
+
+ describe "#last_revision_of_file" do
+ it "returns last revision of file" do
+ expect(
+ described_class.last_revision_of_file(HOMEBREW_CACHE,
+ HOMEBREW_CACHE/file),
+ ).to eq("blah")
+ end
+
+ it "returns last revision of file based on before_commit" do
+ expect(
+ described_class.last_revision_of_file(HOMEBREW_CACHE, HOMEBREW_CACHE/file,
+ before_commit: "0..3"),
+ ).to eq("brew")
+ end
+ end
+end
+
+describe Utils do
+ before(:each) do
+ described_class.clear_git_available_cache
+ end
+
+ describe "::git_available?" do
+ it "returns true if git --version command succeeds" do
+ expect(described_class.git_available?).to be_truthy
+ end
+
+ it "returns false if git --version command does not succeed" do
+ stub_const("HOMEBREW_SHIMS_PATH", HOMEBREW_PREFIX/"bin/shim")
+ expect(described_class.git_available?).to be_falsey
+ end
+ end
+
+ describe "::git_path" do
+ it "returns nil when git is not available" do
+ stub_const("HOMEBREW_SHIMS_PATH", HOMEBREW_PREFIX/"bin/shim")
+ expect(described_class.git_path).to eq(nil)
+ end
+
+ it "returns path of git when git is available" do
+ expect(described_class.git_path).to end_with("git")
+ end
+ end
+
+ describe "::git_version" do
+ it "returns nil when git is not available" do
+ stub_const("HOMEBREW_SHIMS_PATH", HOMEBREW_PREFIX/"bin/shim")
+ expect(described_class.git_path).to eq(nil)
+ end
+
+ it "returns version of git when git is available" do
+ expect(described_class.git_version).not_to be_nil
+ end
+ end
+
+ describe "::ensure_git_installed!" do
+ it "returns nil if git already available" do
+ expect(described_class.ensure_git_installed!).to be_nil
+ end
+
+ context "when git is not already available" do
+ before do
+ stub_const("HOMEBREW_SHIMS_PATH", HOMEBREW_PREFIX/"bin/shim")
+ end
+
+ it "can't install brewed git if homebrew/core is unavailable" do
+ allow_any_instance_of(Pathname).to receive(:directory?).and_return(false)
+ expect { described_class.ensure_git_installed! }.to raise_error("Git is unavailable")
+ end
+
+ it "raises error if can't install git" do
+ stub_const("HOMEBREW_BREW_FILE", HOMEBREW_PREFIX/"bin/brew")
+ expect { described_class.ensure_git_installed! }.to raise_error("Git is unavailable")
+ end
+
+ it "installs git" do
+ allow(Homebrew).to receive(:_system).with(any_args).and_return(true)
+ described_class.ensure_git_installed!
+ end
+ end
+ end
+
+ describe "::git_remote_exists" do
+ it "returns true when git is not available" do
+ stub_const("HOMEBREW_SHIMS_PATH", HOMEBREW_PREFIX/"bin/shim")
+ expect(described_class.git_remote_exists("blah")).to be_truthy
+ end
+
+ context "when git is available" do
+ it "returns true when git remote exists", :needs_network do
+ git = HOMEBREW_SHIMS_PATH/"scm/git"
+ url = "http://github.com/Homebrew/homebrew.github.io"
+ repo = HOMEBREW_CACHE/"hey"
+ repo.mkpath
+
+ repo.cd do
+ system git, "init"
+ system git, "remote", "add", "origin", url
+ end
+
+ expect(described_class.git_remote_exists(url)).to be_truthy
+ end
+
+ it "returns false when git remote does not exist" do
+ expect(described_class.git_remote_exists("blah")).to be_falsey
+ end
+ end
+ end
+end
diff --git a/Library/Homebrew/test/utils/svn_spec.rb b/Library/Homebrew/test/utils/svn_spec.rb
new file mode 100644
index 000000000..4edb365a0
--- /dev/null
+++ b/Library/Homebrew/test/utils/svn_spec.rb
@@ -0,0 +1,39 @@
+require "utils/svn"
+
+describe Utils do
+ describe "#self.svn_available?" do
+ before(:each) do
+ described_class.clear_svn_version_cache
+ end
+
+ it "returns svn version if svn available" do
+ expect(described_class.svn_available?).to be_truthy
+ end
+ end
+
+ describe "#self.svn_remote_exists" do
+ it "returns true when svn is not available" do
+ allow(Utils).to receive(:svn_available?).and_return(false)
+ expect(described_class.svn_remote_exists("blah")).to be_truthy
+ end
+
+ context "when svn is available" do
+ before do
+ allow(Utils).to receive(:svn_available?).and_return(true)
+ end
+
+ it "returns false when remote does not exist" do
+ expect(described_class.svn_remote_exists(HOMEBREW_CACHE/"install")).to be_falsey
+ end
+
+ it "returns true when remote exists", :needs_network do
+ remote = "http://github.com/Homebrew/install"
+ svn = HOMEBREW_SHIMS_PATH/"scm/svn"
+
+ HOMEBREW_CACHE.cd { system svn, "checkout", remote }
+
+ expect(described_class.svn_remote_exists(HOMEBREW_CACHE/"install")).to be_truthy
+ end
+ end
+ end
+end
diff --git a/Library/Homebrew/utils/analytics.rb b/Library/Homebrew/utils/analytics.rb
index a89995ba9..9766c14db 100644
--- a/Library/Homebrew/utils/analytics.rb
+++ b/Library/Homebrew/utils/analytics.rb
@@ -3,6 +3,11 @@ require "erb"
module Utils
module Analytics
class << self
+ def clear_anonymous_os_prefix_ci_cache
+ return unless instance_variable_defined?(:@anonymous_os_prefix_ci)
+ remove_instance_variable(:@anonymous_os_prefix_ci)
+ end
+
def os_prefix_ci
@anonymous_os_prefix_ci ||= begin
os = OS_VERSION
diff --git a/Library/Homebrew/utils/curl.rb b/Library/Homebrew/utils/curl.rb
index 52d03c93e..bc7055c0c 100644
--- a/Library/Homebrew/utils/curl.rb
+++ b/Library/Homebrew/utils/curl.rb
@@ -37,13 +37,12 @@ def curl(*args)
safe_system(*curl_args(*args))
end
-def curl_download(*args, to: nil, **options)
- continue_at ||= "-"
- curl("--location", "--remote-time", "--continue-at", continue_at, "--output", to, *args, **options)
+def curl_download(*args, to: nil, continue_at: "-", **options)
+ curl("--location", "--remote-time", "--continue-at", continue_at.to_s, "--output", to, *args, **options)
rescue ErrorDuringExecution
# `curl` error 33: HTTP server doesn't seem to support byte ranges. Cannot resume.
if $CHILD_STATUS.exitstatus == 33 && continue_at == "-"
- continue_at = "0"
+ continue_at = 0
retry
end
diff --git a/Library/Homebrew/utils/fork.rb b/Library/Homebrew/utils/fork.rb
index 92f5bf899..2f2a403e2 100644
--- a/Library/Homebrew/utils/fork.rb
+++ b/Library/Homebrew/utils/fork.rb
@@ -38,7 +38,7 @@ module Utils
Process.wait(pid) unless socket.nil?
raise Marshal.load(data) unless data.nil? || data.empty?
raise Interrupt if $CHILD_STATUS.exitstatus == 130
- raise "Suspicious failure" unless $CHILD_STATUS.success?
+ raise "Forked child process failed: #{$CHILD_STATUS}" unless $CHILD_STATUS.success?
end
end
end
diff --git a/Library/Homebrew/utils/git.rb b/Library/Homebrew/utils/git.rb
index 43d93b64e..1fc01188c 100644
--- a/Library/Homebrew/utils/git.rb
+++ b/Library/Homebrew/utils/git.rb
@@ -16,8 +16,7 @@ module Git
def last_revision_of_file(repo, file, before_commit: nil)
relative_file = Pathname(file).relative_path_from(repo)
- commit_hash = last_revision_commit_of_file(repo, file, before_commit: before_commit)
-
+ commit_hash = last_revision_commit_of_file(repo, relative_file, before_commit: before_commit)
out, = Open3.capture3(
HOMEBREW_SHIMS_PATH/"scm/git", "-C", repo,
"show", "#{commit_hash}:#{relative_file}"
diff --git a/Library/Homebrew/utils/github.rb b/Library/Homebrew/utils/github.rb
index a1cf5fbba..a50d6d8e5 100644
--- a/Library/Homebrew/utils/github.rb
+++ b/Library/Homebrew/utils/github.rb
@@ -245,7 +245,7 @@ module GitHub
end
def print_pull_requests_matching(query)
- open_or_closed_prs = search_issues(query, type: "pr")
+ open_or_closed_prs = search_issues(query, type: "pr", user: "Homebrew")
open_prs = open_or_closed_prs.select { |i| i["state"] == "open" }
prs = if !open_prs.empty?
diff --git a/Library/Homebrew/utils/svn.rb b/Library/Homebrew/utils/svn.rb
index fb49ac2e9..150b7eee7 100644
--- a/Library/Homebrew/utils/svn.rb
+++ b/Library/Homebrew/utils/svn.rb
@@ -1,4 +1,8 @@
module Utils
+ def self.clear_svn_version_cache
+ remove_instance_variable(:@svn) if instance_variable_defined?(:@svn)
+ end
+
def self.svn_available?
return @svn if instance_variable_defined?(:@svn)
@svn = quiet_system HOMEBREW_SHIMS_PATH/"scm/svn", "--version"
diff --git a/docs/Analytics.md b/docs/Analytics.md
index 15fa6fc93..18dc7bfa6 100644
--- a/docs/Analytics.md
+++ b/docs/Analytics.md
@@ -37,7 +37,9 @@ As far as we can tell it would be impossible for Google to match the randomly ge
Homebrew's analytics are sent throughout Homebrew's execution to Google Analytics over HTTPS.
## Who?
-Homebrew's analytics are accessible to Homebrew's current maintainers. Contact @MikeMcQuaid if you are a maintainer and need access.
+Homebrew's detailed analytics are accessible to Homebrew's current maintainers. Contact @MikeMcQuaid if you are a maintainer and need access.
+
+Summaries of installation and error analytics are publicly available [here](https://brew.sh/analytics/).
## How?
The code is viewable in [analytics.rb](https://github.com/Homebrew/brew/blob/master/Library/Homebrew/utils/analytics.rb) and [analytics.sh](https://github.com/Homebrew/brew/blob/master/Library/Homebrew/utils/analytics.sh). They are done in a separate background process and fail fast to avoid delaying any execution. They will fail immediately and silently if you have no network connection.
diff --git a/docs/FAQ.md b/docs/FAQ.md
index 788c49626..9d76bf4ab 100644
--- a/docs/FAQ.md
+++ b/docs/FAQ.md
@@ -68,13 +68,12 @@ Be careful as this is a destructive operation.
Which is usually: `~/Library/Caches/Homebrew`
## My Mac `.app`s don’t find `/usr/local/bin` utilities!
-GUI apps on macOS don’t have `/usr/local/bin` in their `PATH` by default.
-If you’re on Mountain Lion, you can fix this by running
-`launchctl setenv PATH "/usr/local/bin:$PATH"`. [More details
-here](https://stackoverflow.com/questions/135688/setting-environment-variables-in-os-x/5444960#5444960),
-including how to set this across reboots. If you’re pre-Mountain Lion,
-[here’s an official
-alternative](https://developer.apple.com/legacy/library/qa/qa1067/_index.html).
+GUI apps on macOS don’t have `/usr/local/bin` in their `PATH` by
+default. If you’re on Mountain Lion or later, you can fix this by
+running `sudo launchctl config user path "/usr/local/bin:$PATH"` and
+then rebooting, as documented in `man launchctl`. Note that this sets
+the launchctl PATH for _all users_. For earlier versions of macOS, see
+[this page](https://developer.apple.com/legacy/library/qa/qa1067/_index.html).
## How do I contribute to Homebrew?
Read [CONTRIBUTING.md](https://github.com/Homebrew/brew/blob/master/CONTRIBUTING.md).
diff --git a/docs/Formula-Cookbook.md b/docs/Formula-Cookbook.md
index e60afe071..0266d39e5 100644
--- a/docs/Formula-Cookbook.md
+++ b/docs/Formula-Cookbook.md
@@ -693,7 +693,7 @@ Note that [`option`](http://www.rubydoc.info/github/Homebrew/brew/master/Formula
### File level operations
-You can use the file utilities provided by Ruby's [`FileUtils`](http://www.ruby-doc.org/stdlib/libdoc/fileutils/rdoc/index.html). These are included in the `Formula` class, so you do not need the `FileUtils.` prefix to use them.
+You can use the file utilities provided by Ruby's [`FileUtils`](https://www.ruby-doc.org/stdlib/libdoc/fileutils/rdoc/index.html). These are included in the `Formula` class, so you do not need the `FileUtils.` prefix to use them.
When creating symlinks, take special care to ensure they are *relative* symlinks. This makes it easier to create a relocatable bottle. For example, to create a symlink in `bin` to an executable in `libexec`, use
diff --git a/docs/Homebrew-and-Python.md b/docs/Homebrew-and-Python.md
index 692e5c617..8b263cb38 100644
--- a/docs/Homebrew-and-Python.md
+++ b/docs/Homebrew-and-Python.md
@@ -24,13 +24,13 @@ The Python formulae install [pip](http://www.pip-installer.org) (as `pip2` or `p
Setuptools can be updated via pip, without having to re-brew Python:
```sh
-pip install --upgrade setuptools
+python2 -m pip --upgrade setuptools
```
Similarly, pip can be used to upgrade itself via:
```sh
-pip install --upgrade pip
+python2 -m pip install --upgrade pip
```
### Note on `pip install --user`
@@ -39,7 +39,7 @@ The normal `pip install --user` is disabled for brewed Python. This is because o
A possible workaround (which puts executable scripts in `~/Library/Python/<X>.<Y>/bin`) is:
```sh
-pip install --user --install-option="--prefix=" <package-name>
+python2 -m pip install --user --install-option="--prefix=" <package-name>
```
## `site-packages` and the `PYTHONPATH`
@@ -86,7 +86,7 @@ CFLAGS=-I$(brew --prefix)/include LDFLAGS=-L$(brew --prefix)/lib pip install <pa
Activate the virtualenv *after* you've brewed, or brew in a fresh Terminal window.
Homebrew will still install Python modules into Homebrew's `site-packages` and *not* into the virtual environment's site-package.
-Virtualenv has a switch to allow "global" (i.e. Homebrew's) `site-packages` to be accessible from within the virtualenv.
+Virtualenv has a `--system-site-packages` switch to allow "global" (i.e. Homebrew's) `site-packages` to be accessible from within the virtualenv.
## Why is Homebrew's Python being installed as a dependency?
Formulae that depend on the special `:python` target are bottled against the Homebrew Python and require it to be installed. You can avoid installing Homebrew's Python by building these formulae with `--build-from-source`.
diff --git a/docs/Prose-Style-Guidelines.md b/docs/Prose-Style-Guidelines.md
index 232ccb1be..4fe19bdb8 100644
--- a/docs/Prose-Style-Guidelines.md
+++ b/docs/Prose-Style-Guidelines.md
@@ -16,7 +16,7 @@ Homebrew's audience includes users with a wide range of education and experience
We strive for "correct" but not "fancy" usage. Think newspaper article, not academic paper.
-This is a set of guidelines to be applied using human judgment, not a set of hard and fast rules. It is like [The Economist's Style Guide](http://www.economist.com/styleguide/introduction) or [Garner's Modern American Usage](https://en.wikipedia.org/wiki/Garner's_Modern_American_Usage). It is less like the [Ruby Style Guide](https://github.com/bbatsov/ruby-style-guide). All guidelines here are open to interpretation and discussion. 100% conformance to these guidelines is *not* a goal.
+This is a set of guidelines to be applied using human judgment, not a set of hard and fast rules. It is like [The Economist's Style Guide](https://www.economist.com/styleguide/introduction) or [Garner's Modern American Usage](https://en.wikipedia.org/wiki/Garner's_Modern_American_Usage). It is less like the [Ruby Style Guide](https://github.com/bbatsov/ruby-style-guide). All guidelines here are open to interpretation and discussion. 100% conformance to these guidelines is *not* a goal.
The intent of this document is to help authors make decisions about clarity, style, and consistency. It is not to help settle arguments about who knows English better. Don't use this document to be a jerk.
diff --git a/docs/Python-for-Formula-Authors.md b/docs/Python-for-Formula-Authors.md
index 5b9d6ced6..129f5ba5e 100644
--- a/docs/Python-for-Formula-Authors.md
+++ b/docs/Python-for-Formula-Authors.md
@@ -10,33 +10,7 @@ Bindings are a special case of libraries that allow Python code to interact with
Homebrew is happy to accept applications that are built in Python, whether the apps are available from PyPI or not. Homebrew generally won't accept libraries that can be installed correctly with `pip install foo`. Bindings may be installed for packages that provide them, especially if equivalent functionality isn't available through pip.
-## Running `setup.py`
-
-Homebrew provides a helper method, `Language::Python.setup_install_args`, which returns arguments for invoking `setup.py`. Your formula should use this instead of invoking `setup.py` explicitly. The syntax is:
-
-```ruby
-system "python", *Language::Python.setup_install_args(prefix)
-```
-
-where `prefix` is the destination prefix (usually `libexec` or `prefix`).
-
-## Python module dependencies
-
-In general, applications should unconditionally bundle all of their dependencies and libraries and should install any unsatisfied dependencies; these strategies are discussed in depth in the following sections.
-
-In the rare instance that this proves impractical, you can specify a Python module as an external dependency using this syntax:
-
-```ruby
-depends_on "numpy" => :python
-```
-
-Or if the import name is different from the module name:
-
-```ruby
-depends_on "MacFSEvents" => [:python, "fsevents"]
-```
-
-If you submit a formula with this syntax to core, you may be asked to rewrite it as a `Requirement`.
+Applications should unconditionally bundle all of their Python-language dependencies and libraries and should install any unsatisfied dependencies; these strategies are discussed in depth in the following sections.
## Applications
@@ -147,9 +121,9 @@ in case you need to do different things for different resources.
## Bindings
-To add an option to a formula to build Python bindings, use `depends_on :python => :recommended` and install the bindings conditionally on `build.with? "python"` in your `install` method.
+Build bindings with system Python by default (don't add an option) and they should be usable with any binary-compatible Python. If that isn't the case, it's an upstream bug; [here's some advice for resolving it](http://blog.tim-smith.us/2015/09/python-extension-modules-os-x/).
-Python bindings should be optional because if the formula is bottled, any `:recommended` or mandatory dependencies on `:python` are always resolved by installing the Homebrew `python` formula, which will upset users that prefer to use the system Python. This is because we cannot generally create a binary package that works against both versions of Python.
+To add bindings for Python 3, please add `depends_on :python3 => :optional` and make the bindings conditional on `build.with?("python3")`.
### Dependencies
@@ -179,9 +153,7 @@ Sometimes we have to `inreplace` a `Makefile` to use our prefix for the Python b
### Python declarations
-Libraries **should** declare a dependency on `:python` or `:python3` as appropriate, which will respectively cause the formula to use the first python or python3 discovered in `PATH` at install time. If a library supports both Python 2.x and Python 3.x, the `:python` dependency **should** be `:recommended` (i.e. built by default) and the `:python3` dependency should be `:optional`. Python 2.x libraries **must** function when they are installed against either the system Python or Homebrew Python.
-
-Formulae that declare a dependency on `:python` will always be bottled against Homebrew's python, since we cannot in general build binary packages that can be imported from both Pythons. Users can add `--build-from-source` after `brew install` to compile against whichever python is in `PATH`.
+Python 2 libraries do not need a `depends_on :python` declaration; they will be built with system Python, but should still be usable with any other Python 2.7. If this is not the case, it is an upstream bug; [here is some advice for resolving it](http://blog.tim-smith.us/2015/09/python-extension-modules-os-x/). Libraries built for Python 3 should include `depends_on :python3`, which will bottle against Homebrew's python3, and use the first python3 discovered in `PATH` at build time when installing from source with `brew install --build-from-source`. If a library supports both Python 2.x and Python 3.x, the `:python3` dependency should be `:optional`. Python 2.x libraries must function when they are installed against either the system Python or Homebrew Python.
### Installing
@@ -191,7 +163,7 @@ Most formulae presently just install to `prefix`.
### Dependencies
-The dependencies of libraries must be installed so that they are importable. The principle of minimum surprise suggests that installing a Homebrew library should not alter the other libraries in a user's `sys.path`. The best way to achieve this is to only install dependencies if they are not already installed. To minimize the potential for linking conflicts, dependencies should be installed to `libexec/"vendor"` and added to `sys.path` by writing a second .pth file (named like "homebrew-foo-dependencies.pth") to the `prefix` site-packages.
+The dependencies of libraries must be installed so that they are importable. To minimize the potential for linking conflicts, dependencies should be installed to `libexec/"vendor"` and added to `sys.path` by writing a second .pth file (named like "homebrew-foo-dependencies.pth") to the `prefix` site-packages.
The [matplotlib](https://github.com/Homebrew/homebrew-science/blob/master/matplotlib.rb) formula in [homebrew/science](https://github.com/Homebrew/homebrew-science) deploys this strategy.
@@ -209,6 +181,16 @@ Distutils and pip use a "flat" installation hierarchy that installs modules as i
Distribute (not to be confused with distutils) is an obsolete fork of setuptools. Distlib is a package maintained outside the standard library which is used by pip for some low-level packaging operations and is not relevant to most `setup.py` users.
+### Running `setup.py`
+
+In the event that a formula needs to interact with `setup.py` instead of calling `pip`, Homebrew provides a helper method, `Language::Python.setup_install_args`, which returns useful arguments for invoking `setup.py`. Your formula should use this instead of invoking `setup.py` explicitly. The syntax is:
+
+```ruby
+system "python", *Language::Python.setup_install_args(prefix)
+```
+
+where `prefix` is the destination prefix (usually `libexec` or `prefix`).
+
### What is `--single-version-externally-managed`?
`--single-version-externally-managed` ("SVEM") is a setuptools-only [argument to `setup.py install`](https://setuptools.readthedocs.io/en/latest/setuptools.html?#install-run-easy-install-or-old-style-installation). The primary effect of SVEM is to use distutils to perform the install instead of using setuptools' `easy_install`.
diff --git a/manpages/brew-cask.1 b/manpages/brew-cask.1
index 763d78ebe..f8f58a123 100644
--- a/manpages/brew-cask.1
+++ b/manpages/brew-cask.1
@@ -103,7 +103,7 @@ Reinstall the given Cask\.
.
.TP
\fBsearch\fR or \fB\-S\fR [\fItext\fR | /\fIregexp\fR/]
-Without an argument, display all Casks available for install; otherwise perform a substring search of known Cask tokens for \fItext\fR or, if the text is delimited by slashes (/\fIregexp\fR/), it is interpreted as a Ruby regular expression\.
+Without an argument, display all locally available Casks for install; no online search is performed\. Otherwise perform a substring search of known Cask tokens for \fItext\fR or, if the text is delimited by slashes (/\fIregexp\fR/), it is interpreted as a Ruby regular expression\.
.
.TP
\fBstyle\fR [\-\-fix] [ \fItoken\fR \.\.\. ]