aboutsummaryrefslogtreecommitdiffstats
path: root/Library
diff options
context:
space:
mode:
Diffstat (limited to 'Library')
-rw-r--r--Library/Homebrew/cask/lib/hbc/audit.rb10
-rw-r--r--Library/Homebrew/cask/lib/hbc/cask.rb9
-rw-r--r--Library/Homebrew/cask/lib/hbc/cask_loader.rb54
-rw-r--r--Library/Homebrew/cask/lib/hbc/cli/search.rb5
-rw-r--r--Library/Homebrew/cask/lib/hbc/container.rb3
-rw-r--r--Library/Homebrew/cask/lib/hbc/container/criteria.rb6
-rw-r--r--Library/Homebrew/cask/lib/hbc/container/directory.rb24
-rw-r--r--Library/Homebrew/cask/lib/hbc/container/executable.rb2
-rw-r--r--Library/Homebrew/cask/lib/hbc/container/svn_repository.rb15
-rw-r--r--Library/Homebrew/cask/lib/hbc/download_strategy.rb87
-rw-r--r--Library/Homebrew/cask/lib/hbc/dsl/appcast.rb6
-rw-r--r--Library/Homebrew/cask/lib/hbc/pkg.rb7
-rw-r--r--Library/Homebrew/cask/lib/hbc/system_command.rb4
-rw-r--r--Library/Homebrew/cask/lib/hbc/url.rb11
-rw-r--r--Library/Homebrew/cask/lib/hbc/verify/gpg.rb2
-rw-r--r--Library/Homebrew/cmd/deps.rb134
-rw-r--r--Library/Homebrew/cmd/pin.rb3
-rw-r--r--Library/Homebrew/cmd/postinstall.rb2
-rw-r--r--Library/Homebrew/cmd/search.rb23
-rw-r--r--Library/Homebrew/cmd/unpin.rb4
-rw-r--r--Library/Homebrew/compat/hbc/cask_loader.rb4
-rw-r--r--Library/Homebrew/dev-cmd/audit.rb40
-rw-r--r--Library/Homebrew/dev-cmd/bump-formula-pr.rb5
-rw-r--r--Library/Homebrew/dev-cmd/mirror.rb10
-rw-r--r--Library/Homebrew/dev-cmd/pull.rb16
-rw-r--r--Library/Homebrew/dev-cmd/test.rb2
-rw-r--r--Library/Homebrew/download_strategy.rb105
-rw-r--r--Library/Homebrew/exceptions.rb4
-rw-r--r--Library/Homebrew/extend/ENV/super.rb1
-rw-r--r--Library/Homebrew/extend/os/mac/extend/ENV/super.rb2
-rw-r--r--Library/Homebrew/extend/os/mac/formula_cellar_checks.rb18
-rw-r--r--Library/Homebrew/formula.rb6
-rw-r--r--Library/Homebrew/formula_installer.rb5
-rw-r--r--Library/Homebrew/formulary.rb2
-rw-r--r--Library/Homebrew/gpg.rb7
-rw-r--r--Library/Homebrew/keg.rb5
-rw-r--r--Library/Homebrew/os/mac/xcode.rb2
-rw-r--r--Library/Homebrew/requirements/gpg2_requirement.rb8
-rw-r--r--Library/Homebrew/rubocops.rb2
-rw-r--r--Library/Homebrew/rubocops/extend/formula_cop.rb28
-rw-r--r--Library/Homebrew/rubocops/patches_cop.rb (renamed from Library/Homebrew/rubocops/legacy_patches_cop.rb)15
-rw-r--r--Library/Homebrew/sandbox.rb6
-rwxr-xr-xLibrary/Homebrew/shims/super/cc2
-rw-r--r--Library/Homebrew/software_spec.rb14
-rw-r--r--Library/Homebrew/tap.rb6
-rw-r--r--Library/Homebrew/tap_constants.rb2
-rw-r--r--Library/Homebrew/test/cask/download_strategy_spec.rb66
-rw-r--r--Library/Homebrew/test/cask/dsl/appcast_spec.rb11
-rw-r--r--Library/Homebrew/test/cask/pkg_spec.rb28
-rw-r--r--Library/Homebrew/test/cmd/search_spec.rb12
-rw-r--r--Library/Homebrew/test/formula_installer_spec.rb2
-rw-r--r--Library/Homebrew/test/rubocops/patches_cop_spec.rb (renamed from Library/Homebrew/test/rubocops/legacy_patches_cop_spec.rb)77
-rw-r--r--Library/Homebrew/test/rubocops/text_cop_spec.rb48
-rw-r--r--Library/Homebrew/test/utils/github_spec.rb30
-rw-r--r--Library/Homebrew/utils/curl.rb49
-rw-r--r--Library/Homebrew/utils/github.rb80
56 files changed, 671 insertions, 460 deletions
diff --git a/Library/Homebrew/cask/lib/hbc/audit.rb b/Library/Homebrew/cask/lib/hbc/audit.rb
index cee1fe807..b8bb6ab81 100644
--- a/Library/Homebrew/cask/lib/hbc/audit.rb
+++ b/Library/Homebrew/cask/lib/hbc/audit.rb
@@ -143,7 +143,15 @@ module Hbc
def check_appcast_http_code
odebug "Verifying appcast returns 200 HTTP response code"
- result = @command.run("/usr/bin/curl", args: ["--compressed", "--location", "--user-agent", URL::FAKE_USER_AGENT, "--output", "/dev/null", "--write-out", "%{http_code}", cask.appcast], print_stderr: false)
+
+ curl_executable, *args = curl_args(
+ "--compressed", "--location", "--fail",
+ "--write-out", "%{http_code}",
+ "--output", "/dev/null",
+ cask.appcast,
+ user_agent: :fake
+ )
+ result = @command.run(curl_executable, args: args, print_stderr: false)
if result.success?
http_code = result.stdout.chomp
add_warning "unexpected HTTP response code retrieving appcast: #{http_code}" unless http_code == "200"
diff --git a/Library/Homebrew/cask/lib/hbc/cask.rb b/Library/Homebrew/cask/lib/hbc/cask.rb
index 672d18954..6d89a997c 100644
--- a/Library/Homebrew/cask/lib/hbc/cask.rb
+++ b/Library/Homebrew/cask/lib/hbc/cask.rb
@@ -7,9 +7,16 @@ module Hbc
include Metadata
attr_reader :token, :sourcefile_path
- def initialize(token, sourcefile_path: nil, &block)
+
+ def tap
+ return super if block_given? # Object#tap
+ @tap
+ end
+
+ def initialize(token, sourcefile_path: nil, tap: nil, &block)
@token = token
@sourcefile_path = sourcefile_path
+ @tap = tap
@dsl = DSL.new(@token)
return unless block_given?
@dsl.instance_eval(&block)
diff --git a/Library/Homebrew/cask/lib/hbc/cask_loader.rb b/Library/Homebrew/cask/lib/hbc/cask_loader.rb
index 8cd010ef6..dd9c61089 100644
--- a/Library/Homebrew/cask/lib/hbc/cask_loader.rb
+++ b/Library/Homebrew/cask/lib/hbc/cask_loader.rb
@@ -13,8 +13,8 @@ module Hbc
private
- def cask(header_token, &block)
- Cask.new(header_token, &block)
+ def cask(header_token, **options, &block)
+ Cask.new(header_token, **options, &block)
end
end
@@ -45,12 +45,12 @@ module Hbc
private
- def cask(header_token, &block)
+ def cask(header_token, **options, &block)
if token != header_token
raise CaskTokenMismatchError.new(token, header_token)
end
- Cask.new(header_token, sourcefile_path: path, &block)
+ super(header_token, **options, sourcefile_path: path, &block)
end
end
@@ -71,7 +71,7 @@ module Hbc
begin
ohai "Downloading #{url}."
- curl url, "-o", path
+ curl_download url, to: path
rescue ErrorDuringExecution
raise CaskUnavailableError.new(token, "Failed to download #{Formatter.url(url)}.")
end
@@ -80,18 +80,33 @@ module Hbc
end
end
- class FromTapLoader < FromPathLoader
+ class FromTapPathLoader < FromPathLoader
def self.can_load?(ref)
- ref.to_s.match?(HOMEBREW_TAP_CASK_REGEX)
+ ref.to_s.match?(HOMEBREW_TAP_PATH_REGEX) && super
end
attr_reader :tap
+ def initialize(tap_path)
+ @tap = Tap.from_path(tap_path)
+ super tap_path
+ end
+
+ private
+
+ def cask(*args, &block)
+ super(*args, tap: tap, &block)
+ end
+ end
+
+ class FromTapLoader < FromTapPathLoader
+ def self.can_load?(ref)
+ ref.to_s.match?(HOMEBREW_TAP_CASK_REGEX)
+ end
+
def initialize(tapped_name)
user, repo, token = tapped_name.split("/", 3)
- @tap = Tap.fetch(user, repo)
-
- super @tap.cask_dir/"#{token}.rb"
+ super Tap.fetch(user, repo).cask_dir/"#{token}.rb"
end
def load
@@ -136,19 +151,26 @@ module Hbc
[
FromURILoader,
FromTapLoader,
+ FromTapPathLoader,
FromPathLoader,
].each do |loader_class|
return loader_class.new(ref) if loader_class.can_load?(ref)
end
- if FromPathLoader.can_load?(default_path(ref))
- return FromPathLoader.new(default_path(ref))
+ if FromTapPathLoader.can_load?(default_path(ref))
+ return FromTapPathLoader.new(default_path(ref))
end
- possible_tap_casks = tap_paths(ref)
- if possible_tap_casks.count == 1
- possible_tap_cask = possible_tap_casks.first
- return FromPathLoader.new(possible_tap_cask)
+ case (possible_tap_casks = tap_paths(ref)).count
+ when 1
+ return FromTapPathLoader.new(possible_tap_casks.first)
+ when 2..Float::INFINITY
+ loaders = possible_tap_casks.map(&FromTapPathLoader.method(:new))
+
+ raise CaskError, <<-EOS.undent
+ Cask #{ref} exists in multiple taps:
+ #{loaders.map { |loader| " #{loader.tap}/#{loader.token}" }.join("\n")}
+ EOS
end
possible_installed_cask = Cask.new(ref)
diff --git a/Library/Homebrew/cask/lib/hbc/cli/search.rb b/Library/Homebrew/cask/lib/hbc/cli/search.rb
index 643d18d55..e89dced92 100644
--- a/Library/Homebrew/cask/lib/hbc/cli/search.rb
+++ b/Library/Homebrew/cask/lib/hbc/cli/search.rb
@@ -15,8 +15,9 @@ module Hbc
end
def self.search_remote(query)
- matches = GitHub.search_code("user:caskroom", "path:Casks", "filename:#{query}", "extension:rb")
- [*matches].map do |match|
+ matches = GitHub.search_code(user: "caskroom", path: "Casks",
+ filename: query, extension: "rb")
+ matches.map do |match|
tap = Tap.fetch(match["repository"]["full_name"])
next if tap.installed?
"#{tap.name}/#{File.basename(match["path"], ".rb")}"
diff --git a/Library/Homebrew/cask/lib/hbc/container.rb b/Library/Homebrew/cask/lib/hbc/container.rb
index 93e825e03..fab3a3c1c 100644
--- a/Library/Homebrew/cask/lib/hbc/container.rb
+++ b/Library/Homebrew/cask/lib/hbc/container.rb
@@ -4,6 +4,7 @@ require "hbc/container/bzip2"
require "hbc/container/cab"
require "hbc/container/criteria"
require "hbc/container/dmg"
+require "hbc/container/directory"
require "hbc/container/executable"
require "hbc/container/generic_unar"
require "hbc/container/gpg"
@@ -14,6 +15,7 @@ require "hbc/container/otf"
require "hbc/container/pkg"
require "hbc/container/seven_zip"
require "hbc/container/sit"
+require "hbc/container/svn_repository"
require "hbc/container/tar"
require "hbc/container/ttf"
require "hbc/container/rar"
@@ -43,6 +45,7 @@ module Hbc
Xz, # pure xz
Gpg, # GnuPG signed data
Executable,
+ SvnRepository,
]
# for explicit use only (never autodetected):
# Hbc::Container::Naked
diff --git a/Library/Homebrew/cask/lib/hbc/container/criteria.rb b/Library/Homebrew/cask/lib/hbc/container/criteria.rb
index 66ecb8c87..52f171d6a 100644
--- a/Library/Homebrew/cask/lib/hbc/container/criteria.rb
+++ b/Library/Homebrew/cask/lib/hbc/container/criteria.rb
@@ -13,9 +13,11 @@ module Hbc
end
def magic_number(regex)
+ return false if path.directory?
+
# 262: length of the longest regex (currently: Hbc::Container::Tar)
- @magic_number ||= File.open(@path, "rb") { |f| f.read(262) }
- @magic_number =~ regex
+ @magic_number ||= File.open(path, "rb") { |f| f.read(262) }
+ @magic_number.match?(regex)
end
end
end
diff --git a/Library/Homebrew/cask/lib/hbc/container/directory.rb b/Library/Homebrew/cask/lib/hbc/container/directory.rb
new file mode 100644
index 000000000..e4bb1095b
--- /dev/null
+++ b/Library/Homebrew/cask/lib/hbc/container/directory.rb
@@ -0,0 +1,24 @@
+require "hbc/container/base"
+
+module Hbc
+ class Container
+ class Directory < Base
+ def self.me?(*)
+ false
+ end
+
+ def extract
+ @path.children.each do |child|
+ next if skip_path?(child)
+ FileUtils.cp child, @cask.staged_path
+ end
+ end
+
+ private
+
+ def skip_path?(*)
+ false
+ end
+ end
+ end
+end
diff --git a/Library/Homebrew/cask/lib/hbc/container/executable.rb b/Library/Homebrew/cask/lib/hbc/container/executable.rb
index 848f6d4be..af3b36fd1 100644
--- a/Library/Homebrew/cask/lib/hbc/container/executable.rb
+++ b/Library/Homebrew/cask/lib/hbc/container/executable.rb
@@ -8,7 +8,7 @@ module Hbc
return true if criteria.magic_number(/^#!\s*\S+/)
begin
- MachO.open(criteria.path).header.executable?
+ criteria.path.file? && MachO.open(criteria.path).header.executable?
rescue MachO::MagicError
false
end
diff --git a/Library/Homebrew/cask/lib/hbc/container/svn_repository.rb b/Library/Homebrew/cask/lib/hbc/container/svn_repository.rb
new file mode 100644
index 000000000..cae613b2d
--- /dev/null
+++ b/Library/Homebrew/cask/lib/hbc/container/svn_repository.rb
@@ -0,0 +1,15 @@
+require "hbc/container/directory"
+
+module Hbc
+ class Container
+ class SvnRepository < Directory
+ def self.me?(criteria)
+ criteria.path.join(".svn").directory?
+ end
+
+ def skip_path?(path)
+ path.basename.to_s == ".svn"
+ end
+ end
+ end
+end
diff --git a/Library/Homebrew/cask/lib/hbc/download_strategy.rb b/Library/Homebrew/cask/lib/hbc/download_strategy.rb
index 28ae704ee..245ad4ade 100644
--- a/Library/Homebrew/cask/lib/hbc/download_strategy.rb
+++ b/Library/Homebrew/cask/lib/hbc/download_strategy.rb
@@ -10,7 +10,7 @@ module Hbc
class AbstractDownloadStrategy
attr_reader :cask, :name, :url, :uri_object, :version
- def initialize(cask, command = SystemCommand)
+ def initialize(cask, command: SystemCommand)
@cask = cask
@command = command
# TODO: this excess of attributes is a function of integrating
@@ -33,8 +33,8 @@ module Hbc
class HbVCSDownloadStrategy < AbstractDownloadStrategy
REF_TYPES = [:branch, :revision, :revisions, :tag].freeze
- def initialize(cask, command = SystemCommand)
- super
+ def initialize(*args, **options)
+ super(*args, **options)
@ref_type, @ref = extract_ref
@clone = Hbc.cache.join(cache_filename)
end
@@ -64,11 +64,6 @@ module Hbc
end
class CurlDownloadStrategy < AbstractDownloadStrategy
- # TODO: should be part of url object
- def mirrors
- @mirrors ||= []
- end
-
def tarball_path
@tarball_path ||= Hbc.cache.join("#{name}--#{version}#{ext}")
end
@@ -95,13 +90,8 @@ module Hbc
end
end
- def downloaded_size
- temporary_path.size? || 0
- end
-
def _fetch
- odebug "Calling curl with args #{cask_curl_args}"
- curl(*cask_curl_args)
+ curl_download url, *cask_curl_args, to: temporary_path, user_agent: uri_object.user_agent
end
def fetch
@@ -131,33 +121,12 @@ module Hbc
ignore_interrupts { temporary_path.rename(tarball_path) }
end
tarball_path
- rescue CurlDownloadStrategyError
- raise if mirrors.empty?
- puts "Trying a mirror..."
- @url = mirrors.shift
- retry
end
private
def cask_curl_args
- default_curl_args.tap do |args|
- args.concat(user_agent_args)
- args.concat(cookies_args)
- args.concat(referer_args)
- end
- end
-
- def default_curl_args
- [url, "-C", downloaded_size, "-o", temporary_path]
- end
-
- def user_agent_args
- if uri_object.user_agent
- ["-A", uri_object.user_agent]
- else
- []
- end
+ cookies_args + referer_args
end
def cookies_args
@@ -185,14 +154,13 @@ module Hbc
end
def ext
- Pathname.new(@url).extname
+ Pathname.new(@url).extname[/[^?]+/]
end
end
class CurlPostDownloadStrategy < CurlDownloadStrategy
def cask_curl_args
- super
- default_curl_args.concat(post_args)
+ super.concat(post_args)
end
def post_args
@@ -225,8 +193,8 @@ module Hbc
# super does not provide checks for already-existing downloads
def fetch
- if tarball_path.exist?
- puts "Already downloaded: #{tarball_path}"
+ if cached_location.directory?
+ puts "Already downloaded: #{cached_location}"
else
@url = @url.sub(/^svn\+/, "") if @url =~ %r{^svn\+http://}
ohai "Checking out #{@url}"
@@ -252,9 +220,8 @@ module Hbc
else
fetch_repo @clone, @url
end
- compress
end
- tarball_path
+ cached_location
end
# This primary reason for redefining this method is the trust_cert
@@ -288,10 +255,6 @@ module Hbc
print_stderr: false)
end
- def tarball_path
- @tarball_path ||= cached_location.dirname.join(cached_location.basename.to_s + "-#{@cask.version}.tar")
- end
-
def shell_quote(str)
# Oh god escaping shell args.
# See http://notetoself.vrensk.com/2008/08/escaping-single-quotes-in-ruby-harder-than-expected/
@@ -304,35 +267,5 @@ module Hbc
yield name, url
end
end
-
- private
-
- # TODO/UPDATE: the tar approach explained below is fragile
- # against challenges such as case-sensitive filesystems,
- # and must be re-implemented.
- #
- # Seems nutty: we "download" the contents into a tape archive.
- # Why?
- # * A single file is tractable to the rest of the Cask toolchain,
- # * An alternative would be to create a Directory container type.
- # However, some type of file-serialization trick would still be
- # needed in order to enable calculating a single checksum over
- # a directory. So, in that alternative implementation, the
- # special cases would propagate outside this class, including
- # the use of tar or equivalent.
- # * SubversionDownloadStrategy.cached_location is not versioned
- # * tarball_path provides a needed return value for our overridden
- # fetch method.
- # * We can also take this private opportunity to strip files from
- # the download which are protocol-specific.
-
- def compress
- Dir.chdir(cached_location) do
- @command.run!("/usr/bin/tar",
- args: ['-s/^\.//', "--exclude", ".svn", "-cf", Pathname.new(tarball_path), "--", "."],
- print_stderr: false)
- end
- clear_cache
- end
end
end
diff --git a/Library/Homebrew/cask/lib/hbc/dsl/appcast.rb b/Library/Homebrew/cask/lib/hbc/dsl/appcast.rb
index d302d0946..fc7e83a20 100644
--- a/Library/Homebrew/cask/lib/hbc/dsl/appcast.rb
+++ b/Library/Homebrew/cask/lib/hbc/dsl/appcast.rb
@@ -12,7 +12,11 @@ module Hbc
end
def calculate_checkpoint
- result = SystemCommand.run("/usr/bin/curl", args: ["--compressed", "--location", "--user-agent", URL::FAKE_USER_AGENT, "--fail", @uri], print_stderr: false)
+ curl_executable, *args = curl_args(
+ "--compressed", "--location", "--fail", @uri,
+ user_agent: :fake
+ )
+ result = SystemCommand.run(curl_executable, args: args, print_stderr: false)
checkpoint = if result.success?
processed_appcast_text = result.stdout.gsub(%r{<pubDate>[^<]*</pubDate>}m, "")
diff --git a/Library/Homebrew/cask/lib/hbc/pkg.rb b/Library/Homebrew/cask/lib/hbc/pkg.rb
index c9aa3180f..8938268a2 100644
--- a/Library/Homebrew/cask/lib/hbc/pkg.rb
+++ b/Library/Homebrew/cask/lib/hbc/pkg.rb
@@ -16,19 +16,17 @@ module Hbc
def uninstall
unless pkgutil_bom_files.empty?
odebug "Deleting pkg files"
- @command.run("/usr/bin/xargs", args: ["-0", "--", "/bin/rm", "--"], input: pkgutil_bom_files.join("\0"), sudo: true)
+ @command.run!("/usr/bin/xargs", args: ["-0", "--", "/bin/rm", "--"], input: pkgutil_bom_files.join("\0"), sudo: true)
end
unless pkgutil_bom_specials.empty?
odebug "Deleting pkg symlinks and special files"
- @command.run("/usr/bin/xargs", args: ["-0", "--", "/bin/rm", "--"], input: pkgutil_bom_specials.join("\0"), sudo: true)
+ @command.run!("/usr/bin/xargs", args: ["-0", "--", "/bin/rm", "--"], input: pkgutil_bom_specials.join("\0"), sudo: true)
end
unless pkgutil_bom_dirs.empty?
odebug "Deleting pkg directories"
deepest_path_first(pkgutil_bom_dirs).each do |dir|
- next if MacOS.undeletable?(dir)
-
with_full_permissions(dir) do
clean_broken_symlinks(dir)
clean_ds_store(dir)
@@ -67,6 +65,7 @@ module Hbc
.stdout
.split("\n")
.map { |path| root.join(path) }
+ .reject(&MacOS.public_method(:undeletable?))
end
def root
diff --git a/Library/Homebrew/cask/lib/hbc/system_command.rb b/Library/Homebrew/cask/lib/hbc/system_command.rb
index 901617b71..b735ae4f9 100644
--- a/Library/Homebrew/cask/lib/hbc/system_command.rb
+++ b/Library/Homebrew/cask/lib/hbc/system_command.rb
@@ -112,11 +112,7 @@ module Hbc
processed_output[:stderr],
processed_status.exitstatus)
end
- end
-end
-module Hbc
- class SystemCommand
class Result
attr_accessor :command, :stdout, :stderr, :exit_status
diff --git a/Library/Homebrew/cask/lib/hbc/url.rb b/Library/Homebrew/cask/lib/hbc/url.rb
index 15da2ced2..8c652657b 100644
--- a/Library/Homebrew/cask/lib/hbc/url.rb
+++ b/Library/Homebrew/cask/lib/hbc/url.rb
@@ -1,8 +1,6 @@
module Hbc
class URL
- FAKE_USER_AGENT = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10) https://caskroom.github.io".freeze
-
- attr_reader :using, :revision, :trust_cert, :uri, :cookies, :referer, :data
+ attr_reader :using, :revision, :trust_cert, :uri, :cookies, :referer, :data, :user_agent
extend Forwardable
def_delegators :uri, :path, :scheme, :to_s
@@ -17,7 +15,7 @@ module Hbc
def initialize(uri, options = {})
@uri = Hbc::UnderscoreSupportingURI.parse(uri)
- @user_agent = options[:user_agent]
+ @user_agent = options.fetch(:user_agent, :default)
@cookies = options[:cookies]
@referer = options[:referer]
@using = options[:using]
@@ -25,10 +23,5 @@ module Hbc
@trust_cert = options[:trust_cert]
@data = options[:data]
end
-
- def user_agent
- return FAKE_USER_AGENT if @user_agent == :fake
- @user_agent
- end
end
end
diff --git a/Library/Homebrew/cask/lib/hbc/verify/gpg.rb b/Library/Homebrew/cask/lib/hbc/verify/gpg.rb
index dbb537756..f4996a5b5 100644
--- a/Library/Homebrew/cask/lib/hbc/verify/gpg.rb
+++ b/Library/Homebrew/cask/lib/hbc/verify/gpg.rb
@@ -33,7 +33,7 @@ module Hbc
meta_dir = cached || cask.metadata_subdir("gpg", :now, true)
sig_path = meta_dir.join("signature.asc")
- curl(cask.gpg.signature, "-o", sig_path.to_s) unless cached || force
+ curl_download cask.gpg.signature, to: sig_path unless cached || force
sig_path
end
diff --git a/Library/Homebrew/cmd/deps.rb b/Library/Homebrew/cmd/deps.rb
index bbf0c1b0b..de7aa4a51 100644
--- a/Library/Homebrew/cmd/deps.rb
+++ b/Library/Homebrew/cmd/deps.rb
@@ -1,4 +1,4 @@
-#: * `deps` [`--1`] [`-n`] [`--union`] [`--full-name`] [`--installed`] [`--include-build`] [`--include-optional`] [`--skip-recommended`] <formulae>:
+#: * `deps` [`--1`] [`-n`] [`--union`] [`--full-name`] [`--installed`] [`--include-build`] [`--include-optional`] [`--skip-recommended`] [`--include-requirements`] <formulae>:
#: Show dependencies for <formulae>. When given multiple formula arguments,
#: show the intersection of dependencies for <formulae>.
#:
@@ -19,15 +19,22 @@
#: <formulae>. To include the `:build` type dependencies, pass `--include-build`.
#: Similarly, pass `--include-optional` to include `:optional` dependencies.
#: To skip `:recommended` type dependencies, pass `--skip-recommended`.
+#: To include requirements in addition to dependencies, pass `--include-requirements`.
#:
-#: * `deps` `--tree` [<filters>] (<formulae>|`--installed`):
+#: * `deps` `--tree` [`--1`] [<filters>] [`--annotate`] (<formulae>|`--installed`):
#: Show dependencies as a tree. When given multiple formula arguments, output
#: individual trees for every formula.
#:
+#: If `--1` is passed, only one level of children is displayed.
+#:
#: If `--installed` is passed, output a tree for every installed formula.
#:
#: The <filters> placeholder is any combination of options `--include-build`,
-#: `--include-optional`, and `--skip-recommended` as documented above.
+#: `--include-optional`, `--skip-recommended`, and `--include-requirements` as
+#: documented above.
+#:
+#: If `--annotate` is passed, the build, optional, and recommended dependencies
+#: are marked as such in the output.
#:
#: * `deps` [<filters>] (`--installed`|`--all`):
#: Show dependencies for installed or all available formulae. Every line of
@@ -37,6 +44,10 @@
#: The <filters> placeholder is any combination of options `--include-build`,
#: `--include-optional`, and `--skip-recommended` as documented above.
+# The undocumented `--for-each` option will switch into the mode used by `deps --all`,
+# but only list dependencies for specified formula, one specified formula per line.
+# This is used for debugging the `--installed`/`--all` display mode.
+
# encoding: UTF-8
require "formula"
@@ -52,20 +63,26 @@ module Homebrew
all?: ARGV.include?("--all"),
topo_order?: ARGV.include?("-n"),
union?: ARGV.include?("--union"),
+ for_each?: ARGV.include?("--for-each"),
)
- if mode.installed? && mode.tree?
- puts_deps_tree Formula.installed
+ if mode.tree?
+ if mode.installed?
+ puts_deps_tree Formula.installed, !ARGV.one?
+ else
+ raise FormulaUnspecifiedError if ARGV.named.empty?
+ puts_deps_tree ARGV.formulae, !ARGV.one?
+ end
elsif mode.all?
puts_deps Formula
- elsif mode.tree?
- raise FormulaUnspecifiedError if ARGV.named.empty?
- puts_deps_tree ARGV.formulae
elsif ARGV.named.empty?
raise FormulaUnspecifiedError unless mode.installed?
puts_deps Formula.installed
+ elsif mode.for_each?
+ puts_deps ARGV.formulae
else
all_deps = deps_for_formulae(ARGV.formulae, !ARGV.one?, &(mode.union? ? :| : :&))
+ all_deps = condense_requirements(all_deps)
all_deps = all_deps.select(&:installed?) if mode.installed?
all_deps = all_deps.map(&method(:dep_display_name)).uniq
all_deps.sort! unless mode.topo_order?
@@ -73,24 +90,59 @@ module Homebrew
end
end
- def dep_display_name(d)
- ARGV.include?("--full-name") ? d.to_formula.full_name : d.name
+ def condense_requirements(deps)
+ if ARGV.include?("--include-requirements")
+ deps
+ else
+ deps.map do |dep|
+ if dep.is_a? Dependency
+ dep
+ elsif dep.default_formula?
+ dep.to_dependency
+ end
+ end.compact
+ end
+ end
+
+ def dep_display_name(dep)
+ str = if dep.is_a? Requirement
+ if ARGV.include?("--include-requirements")
+ if dep.default_formula?
+ ":#{dep.display_s} (#{dep_display_name(dep.to_dependency)})"
+ else
+ ":#{dep.display_s}"
+ end
+ elsif dep.default_formula?
+ dep_display_name(dep.to_dependency)
+ else
+ # This shouldn't happen, but we'll put something here to help debugging
+ "::#{dep.name}"
+ end
+ else
+ ARGV.include?("--full-name") ? dep.to_formula.full_name : dep.name
+ end
+ if ARGV.include?("--annotate")
+ str = "#{str} [build]" if dep.build?
+ str = "#{str} [optional" if dep.optional?
+ str = "#{str} [recommended]" if dep.recommended?
+ end
+ str
end
def deps_for_formula(f, recursive = false)
includes = []
ignores = []
- if ARGV.include? "--include-build"
+ if ARGV.include?("--include-build")
includes << "build?"
else
ignores << "build?"
end
- if ARGV.include? "--include-optional"
+ if ARGV.include?("--include-optional")
includes << "optional?"
else
ignores << "optional?"
end
- ignores << "recommended?" if ARGV.include? "--skip-recommended"
+ ignores << "recommended?" if ARGV.include?("--skip-recommended")
if recursive
deps = f.recursive_dependencies do |dependent, dep|
@@ -120,7 +172,7 @@ module Homebrew
end
end
- deps + reqs.select(&:default_formula?).map(&:to_dependency)
+ deps + reqs.to_a
end
def deps_for_formulae(formulae, recursive = false, &block)
@@ -129,41 +181,55 @@ module Homebrew
def puts_deps(formulae)
formulae.each do |f|
- deps = deps_for_formula(f).sort_by(&:name).map(&method(:dep_display_name))
+ deps = deps_for_formula(f)
+ deps = condense_requirements(deps)
+ deps = deps.sort_by(&:name).map(&method(:dep_display_name))
puts "#{f.full_name}: #{deps.join(" ")}"
end
end
- def puts_deps_tree(formulae)
+ def puts_deps_tree(formulae, recursive = false)
formulae.each do |f|
- puts "#{f.full_name} (required dependencies)"
- recursive_deps_tree(f, "")
+ puts f.full_name
+ @dep_stack = []
+ recursive_deps_tree(f, "", recursive)
puts
end
end
- def recursive_deps_tree(f, prefix)
- reqs = f.requirements.select(&:default_formula?)
- deps = f.deps.default
- max = reqs.length - 1
- reqs.each_with_index do |req, i|
- chr = if i == max && deps.empty?
+ def recursive_deps_tree(f, prefix, recursive)
+ reqs = f.requirements
+ deps = f.deps
+ dependables = reqs + deps
+ dependables = dependables.reject(&:optional?) unless ARGV.include?("--include-optional")
+ dependables = dependables.reject(&:build?) unless ARGV.include?("--include-build")
+ dependables = dependables.reject(&:recommended?) if ARGV.include?("--skip-recommended")
+ max = dependables.length - 1
+ @dep_stack.push f.name
+ dependables.each_with_index do |dep, i|
+ next if !ARGV.include?("--include-requirements") && dep.is_a?(Requirement) && !dep.default_formula?
+ tree_lines = if i == max
"└──"
else
"├──"
end
- puts prefix + "#{chr} :#{dep_display_name(req.to_dependency)}"
- end
- max = deps.length - 1
- deps.each_with_index do |dep, i|
- chr = if i == max
- "└──"
+ display_s = "#{tree_lines} #{dep_display_name(dep)}"
+ is_circular = @dep_stack.include?(dep.name)
+ display_s = "#{display_s} (CIRCULAR DEPENDENCY)" if is_circular
+ puts "#{prefix}#{display_s}"
+ next if !recursive || is_circular
+ prefix_addition = if i == max
+ " "
else
- "├──"
+ "│ "
+ end
+ if dep.is_a?(Requirement) && dep.default_formula?
+ recursive_deps_tree(Formulary.factory(dep.to_dependency.name), prefix + prefix_addition, true)
+ end
+ if dep.is_a? Dependency
+ recursive_deps_tree(Formulary.factory(dep.name), prefix + prefix_addition, true)
end
- prefix_ext = (i == max) ? " " : "│ "
- puts prefix + "#{chr} #{dep_display_name(dep)}"
- recursive_deps_tree(Formulary.factory(dep.name), prefix + prefix_ext)
end
+ @dep_stack.pop
end
end
diff --git a/Library/Homebrew/cmd/pin.rb b/Library/Homebrew/cmd/pin.rb
index c5087f6d4..5a14f853c 100644
--- a/Library/Homebrew/cmd/pin.rb
+++ b/Library/Homebrew/cmd/pin.rb
@@ -1,6 +1,7 @@
#: * `pin` <formulae>:
#: Pin the specified <formulae>, preventing them from being upgraded when
-#: issuing the `brew upgrade` command. See also `unpin`.
+#: issuing the `brew upgrade <formulae>` command (but can still be upgraded
+#: as dependencies for other formulae). See also `unpin`.
require "formula"
diff --git a/Library/Homebrew/cmd/postinstall.rb b/Library/Homebrew/cmd/postinstall.rb
index f5d091227..02fd8a5f6 100644
--- a/Library/Homebrew/cmd/postinstall.rb
+++ b/Library/Homebrew/cmd/postinstall.rb
@@ -29,8 +29,6 @@ module Homebrew
args << "--devel"
end
- Sandbox.print_sandbox_message if Sandbox.formula?(formula)
-
Utils.safe_fork do
if Sandbox.formula?(formula)
sandbox = Sandbox.new
diff --git a/Library/Homebrew/cmd/search.rb b/Library/Homebrew/cmd/search.rb
index b2d069744..0718a3af4 100644
--- a/Library/Homebrew/cmd/search.rb
+++ b/Library/Homebrew/cmd/search.rb
@@ -34,7 +34,7 @@ module Homebrew
elsif ARGV.include? "--opensuse"
exec_browser "https://software.opensuse.org/search?q=#{ARGV.next}"
elsif ARGV.include? "--fedora"
- exec_browser "https://admin.fedoraproject.org/pkgdb/packages/%2A#{ARGV.next}%2A/"
+ 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"
elsif ARGV.include? "--desc"
@@ -43,27 +43,29 @@ module Homebrew
Descriptions.search(regex, :desc).print
elsif ARGV.first =~ HOMEBREW_TAP_FORMULA_REGEX
query = ARGV.first
- user, repo, name = query.split("/", 3)
begin
result = Formulary.factory(query).name
+ results = Array(result)
rescue FormulaUnavailableError
- result = search_tap(user, repo, name)
+ _, _, name = query.split("/", 3)
+ results = search_taps(name)
end
- results = Array(result)
puts Formatter.columns(results) unless results.empty?
else
query = ARGV.first
regex = query_regexp(query)
local_results = search_formulae(regex)
puts Formatter.columns(local_results) unless local_results.empty?
+
tap_results = search_taps(query)
puts Formatter.columns(tap_results) unless tap_results.empty?
if $stdout.tty?
count = local_results.length + tap_results.length
+ ohai "Searching blacklisted, migrated and deleted formulae..."
if reason = Homebrew::MissingFormula.reason(query, silent: true)
if count > 0
puts
@@ -101,9 +103,15 @@ module Homebrew
end
def search_taps(query)
+ return [] if ENV["HOMEBREW_NO_GITHUB_API"]
+
+ # Use stderr to avoid breaking parsed output
+ $stderr.puts Formatter.headline("Searching taps on GitHub...", color: :blue)
+
valid_dirnames = ["Formula", "HomebrewFormula", "Casks", "."].freeze
- matches = GitHub.search_code("user:Homebrew", "user:caskroom", "filename:#{query}", "extension:rb")
- [*matches].map do |match|
+ matches = GitHub.search_code(user: ["Homebrew", "caskroom"], filename: query, extension: "rb")
+
+ matches.map do |match|
dirname, filename = File.split(match["path"])
next unless valid_dirnames.include?(dirname)
tap = Tap.fetch(match["repository"]["full_name"])
@@ -113,6 +121,9 @@ module Homebrew
end
def search_formulae(regex)
+ # Use stderr to avoid breaking parsed output
+ $stderr.puts Formatter.headline("Searching local taps...", color: :blue)
+
aliases = Formula.alias_full_names
results = (Formula.full_names + aliases).grep(regex).sort
diff --git a/Library/Homebrew/cmd/unpin.rb b/Library/Homebrew/cmd/unpin.rb
index a669df1ec..e15a156ea 100644
--- a/Library/Homebrew/cmd/unpin.rb
+++ b/Library/Homebrew/cmd/unpin.rb
@@ -1,6 +1,6 @@
#: * `unpin` <formulae>:
-#: Unpin <formulae>, allowing them to be upgraded by `brew upgrade`. See also
-#: `pin`.
+#: Unpin <formulae>, allowing them to be upgraded by `brew upgrade <formulae>`.
+#: See also `pin`.
require "formula"
diff --git a/Library/Homebrew/compat/hbc/cask_loader.rb b/Library/Homebrew/compat/hbc/cask_loader.rb
index e6cb65b4f..e57aea71d 100644
--- a/Library/Homebrew/compat/hbc/cask_loader.rb
+++ b/Library/Homebrew/compat/hbc/cask_loader.rb
@@ -1,13 +1,13 @@
module CaskLoaderCompatibilityLayer
private
- def cask(header_token, &block)
+ def cask(header_token, **options, &block)
if header_token.is_a?(Hash) && header_token.key?(:v1)
odeprecated %q("cask :v1 => 'token'"), %q("cask 'token'")
header_token = header_token[:v1]
end
- super(header_token, &block)
+ super(header_token, **options, &block)
end
end
diff --git a/Library/Homebrew/dev-cmd/audit.rb b/Library/Homebrew/dev-cmd/audit.rb
index 7b5befaa0..170fb6d5f 100644
--- a/Library/Homebrew/dev-cmd/audit.rb
+++ b/Library/Homebrew/dev-cmd/audit.rb
@@ -242,12 +242,10 @@ class FormulaAuditor
def self.http_content_headers_and_checksum(url, hash_needed: false, user_agent: :default)
max_time = hash_needed ? "600" : "25"
- args = curl_args(
- extra_args: ["--connect-timeout", "15", "--include", "--max-time", max_time, url],
- show_output: true,
- user_agent: user_agent,
+ output, = curl_output(
+ "--connect-timeout", "15", "--include", "--max-time", max_time, "--location", url,
+ user_agent: user_agent
)
- output = Open3.popen3(*args) { |_, stdout, _, _| stdout.read }
status_code = :unknown
while status_code == :unknown || status_code.to_s.start_with?("3")
@@ -330,6 +328,7 @@ class FormulaAuditor
valid_alias_names = [alias_name_major, alias_name_major_minor]
if formula.tap && !formula.tap.core_tap?
+ versioned_aliases.map! { |a| "#{formula.tap}/#{a}" }
valid_alias_names.map! { |a| "#{formula.tap}/#{a}" }
end
@@ -630,7 +629,6 @@ class FormulaAuditor
end
next if spec.patches.empty?
- spec.patches.each { |p| patch_problems(p) if p.external? }
next unless @new_formula
problem "New formulae should not require patches to build. Patches should be submitted and accepted upstream first."
end
@@ -786,36 +784,6 @@ class FormulaAuditor
end
end
- def patch_problems(patch)
- case patch.url
- when %r{https?://github\.com/.+/.+/(?:commit|pull)/[a-fA-F0-9]*.(?:patch|diff)}
- unless patch.url =~ /\?full_index=\w+$/
- problem <<-EOS.undent
- GitHub patches should use the full_index parameter:
- #{patch.url}?full_index=1
- EOS
- end
- 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/#{Regexp.last_match(1)}/#{Regexp.last_match(2)}/pull/#{Regexp.last_match(3)}.patch?full_index=1
- 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
bin_names = Set.new
bin_names << formula.name
diff --git a/Library/Homebrew/dev-cmd/bump-formula-pr.rb b/Library/Homebrew/dev-cmd/bump-formula-pr.rb
index 1c56749a3..e9e98d450 100644
--- a/Library/Homebrew/dev-cmd/bump-formula-pr.rb
+++ b/Library/Homebrew/dev-cmd/bump-formula-pr.rb
@@ -176,7 +176,10 @@ module Homebrew
rsrc.version = forced_version if forced_version
odie "No version specified!" unless rsrc.version
rsrc_path = rsrc.fetch
- if Utils.popen_read("/usr/bin/tar", "-tf", rsrc_path) =~ %r{/.*\.}
+ gnu_tar_gtar_path = HOMEBREW_PREFIX/"opt/gnu-tar/bin/gtar"
+ gnu_tar_gtar = gnu_tar_gtar_path if gnu_tar_gtar_path.executable?
+ tar = which("gtar") || gnu_tar_gtar || which("tar")
+ if Utils.popen_read(tar, "-tf", rsrc_path) =~ %r{/.*\.}
new_hash = rsrc_path.sha256
elsif new_url.include? ".tar"
odie "#{formula}: no url/#{hash_type} specified!"
diff --git a/Library/Homebrew/dev-cmd/mirror.rb b/Library/Homebrew/dev-cmd/mirror.rb
index e2492203d..6445bc34c 100644
--- a/Library/Homebrew/dev-cmd/mirror.rb
+++ b/Library/Homebrew/dev-cmd/mirror.rb
@@ -25,9 +25,9 @@ module Homebrew
"public_download_numbers": true,
"public_stats": true}
EOS
- curl "--silent", "--fail", "-u#{bintray_user}:#{bintray_key}",
- "-H", "Content-Type: application/json",
- "-d", package_blob, bintray_repo_url
+ curl "--silent", "--fail", "--user", "#{bintray_user}:#{bintray_key}",
+ "--header", "Content-Type: application/json",
+ "--data", package_blob, bintray_repo_url
puts
end
@@ -40,8 +40,8 @@ module Homebrew
content_url = "https://api.bintray.com/content/homebrew/mirror"
content_url += "/#{bintray_package}/#{f.pkg_version}/#{filename}"
content_url += "?publish=1"
- curl "--silent", "--fail", "-u#{bintray_user}:#{bintray_key}",
- "-T", download, content_url
+ curl "--silent", "--fail", "--user", "#{bintray_user}:#{bintray_key}",
+ "--upload-file", download, content_url
puts
ohai "Mirrored #{filename}!"
end
diff --git a/Library/Homebrew/dev-cmd/pull.rb b/Library/Homebrew/dev-cmd/pull.rb
index 9681bb2bc..dd2bc6270 100644
--- a/Library/Homebrew/dev-cmd/pull.rb
+++ b/Library/Homebrew/dev-cmd/pull.rb
@@ -228,7 +228,7 @@ module Homebrew
"https://github.com/BrewTestBot/homebrew-#{tap.repo}/compare/homebrew:master...pr-#{issue}"
end
- curl "--silent", "--fail", "-o", "/dev/null", "-I", bottle_commit_url
+ curl "--silent", "--fail", "--output", "/dev/null", "--head", bottle_commit_url
safe_system "git", "checkout", "--quiet", "-B", bottle_branch, orig_revision
pull_patch bottle_commit_url, "bottle commit"
@@ -303,7 +303,7 @@ module Homebrew
extra_msg = @description ? "(#{@description})" : nil
ohai "Fetching patch #{extra_msg}"
puts "Patch: #{patch_url}"
- curl patch_url, "-s", "-o", patchpath
+ curl_download patch_url, to: patchpath
end
def apply_patch
@@ -433,10 +433,10 @@ module Homebrew
end
version = info.pkg_version
ohai "Publishing on Bintray: #{package} #{version}"
- curl "-w", '\n', "--silent", "--fail",
- "-u#{creds[:user]}:#{creds[:key]}", "-X", "POST",
- "-H", "Content-Type: application/json",
- "-d", '{"publish_wait_for_secs": 0}',
+ curl "--write-out", '\n', "--silent", "--fail",
+ "--user", "#{creds[:user]}:#{creds[:key]}", "--request", "POST",
+ "--header", "Content-Type: application/json",
+ "--data", '{"publish_wait_for_secs": 0}',
"https://api.bintray.com/content/homebrew/#{repo}/#{package}/#{version}/publish"
true
rescue => e
@@ -587,7 +587,7 @@ module Homebrew
# We're in the cache; make sure to force re-download
loop do
begin
- curl url, "-o", filename
+ curl_download url, to: filename
break
rescue
if retry_count >= max_curl_retries
@@ -606,7 +606,7 @@ module Homebrew
end
def check_bintray_mirror(name, url)
- headers = curl_output("--connect-timeout", "15", "--head", url)[0]
+ headers, = curl_output("--connect-timeout", "15", "--location", "--head", url)
status_code = headers.scan(%r{^HTTP\/.* (\d+)}).last.first
return if status_code.start_with?("2")
opoo "The Bintray mirror #{url} is not reachable (HTTP status code #{status_code})."
diff --git a/Library/Homebrew/dev-cmd/test.rb b/Library/Homebrew/dev-cmd/test.rb
index c678171ac..ab2b0edb0 100644
--- a/Library/Homebrew/dev-cmd/test.rb
+++ b/Library/Homebrew/dev-cmd/test.rb
@@ -65,8 +65,6 @@ module Homebrew
args << "--devel"
end
- Sandbox.print_sandbox_message if Sandbox.test?
-
Utils.safe_fork do
if Sandbox.test?
sandbox = Sandbox.new
diff --git a/Library/Homebrew/download_strategy.rb b/Library/Homebrew/download_strategy.rb
index 717334714..2a8b6e585 100644
--- a/Library/Homebrew/download_strategy.rb
+++ b/Library/Homebrew/download_strategy.rb
@@ -375,75 +375,59 @@ class CurlDownloadStrategy < AbstractFileDownloadStrategy
ohai "Downloading from #{url}"
end
- urls = actual_urls(url)
- unless urls.empty?
- ohai "Downloading from #{urls.last}"
- if !ENV["HOMEBREW_NO_INSECURE_REDIRECT"].nil? && url.start_with?("https://") &&
- urls.any? { |u| !u.start_with? "https://" }
- puts "HTTPS to HTTP redirect detected & HOMEBREW_NO_INSECURE_REDIRECT is set."
- raise CurlDownloadStrategyError, url
- end
- url = urls.last
- end
-
- curl url, "-C", downloaded_size, "-o", temporary_path
+ curl_download resolved_url(url), to: temporary_path
end
# Curl options to be always passed to curl,
- # with raw head calls (`curl -I`) or with actual `fetch`.
+ # with raw head calls (`curl --head`) or with actual `fetch`.
def _curl_opts
- copts = []
- copts << "--user" << meta.fetch(:user) if meta.key?(:user)
- copts
+ return ["--user" << meta.fetch(:user)] if meta.key?(:user)
+ []
end
- def actual_urls(url)
- urls = []
- curl_args = _curl_opts << "-I" << "-L" << url
- Utils.popen_read("curl", *curl_args).scan(/^Location: (.+)$/).map do |m|
- urls << URI.join(urls.last || url, m.first.chomp).to_s
+ def resolved_url(url)
+ redirect_url, _, status = curl_output(
+ *_curl_opts, "--silent", "--head",
+ "--write-out", "%{redirect_url}",
+ "--output", "/dev/null",
+ url.to_s
+ )
+
+ return url unless status.success?
+ return url if redirect_url.empty?
+
+ ohai "Downloading from #{redirect_url}"
+ if ENV["HOMEBREW_NO_INSECURE_REDIRECT"] &&
+ url.start_with?("https://") && !redirect_url.start_with?("https://")
+ puts "HTTPS to HTTP redirect detected & HOMEBREW_NO_INSECURE_REDIRECT is set."
+ raise CurlDownloadStrategyError, url
end
- urls
- end
- def downloaded_size
- temporary_path.size? || 0
+ redirect_url
end
- def curl(*args)
+ def curl(*args, **options)
args.concat _curl_opts
args << "--connect-timeout" << "5" unless mirrors.empty?
- super
+ super(*args, **options)
end
end
# Detect and download from Apache Mirror
class CurlApacheMirrorDownloadStrategy < CurlDownloadStrategy
def apache_mirrors
- rd, wr = IO.pipe
- buf = ""
-
- pid = fork do
- ENV.delete "HOMEBREW_CURL_VERBOSE"
- rd.close
- $stdout.reopen(wr)
- $stderr.reopen(wr)
- curl "#{@url}&asjson=1"
- end
- wr.close
+ mirrors, = Open3.capture3(
+ *curl_args(*_curl_opts, "--silent", "--location", "#{@url}&asjson=1"),
+ )
- rd.readline if ARGV.verbose? # Remove Homebrew output
- buf << rd.read until rd.eof?
- rd.close
- Process.wait(pid)
- buf
+ JSON.parse(mirrors)
end
def _fetch
return super if @tried_apache_mirror
@tried_apache_mirror = true
- mirrors = JSON.parse(apache_mirrors)
+ mirrors = apache_mirrors
path_info = mirrors.fetch("path_info")
@url = mirrors.fetch("preferred") + path_info
@mirrors |= %W[https://archive.apache.org/dist/#{path_info}]
@@ -460,7 +444,7 @@ end
class CurlPostDownloadStrategy < CurlDownloadStrategy
def _fetch
base_url, data = @url.split("?")
- curl base_url, "-d", data, "-C", downloaded_size, "-o", temporary_path
+ curl_download base_url, "--data", data, to: temporary_path
end
end
@@ -530,7 +514,7 @@ class S3DownloadStrategy < CurlDownloadStrategy
s3url = obj.public_url
end
- curl s3url, "-C", downloaded_size, "-o", temporary_path
+ curl_download s3url, to: temporary_path
end
end
@@ -566,7 +550,7 @@ class GitHubPrivateRepositoryDownloadStrategy < CurlDownloadStrategy
end
def _fetch
- curl download_url, "-C", downloaded_size, "-o", temporary_path
+ curl_download download_url, to: temporary_path
end
private
@@ -615,7 +599,7 @@ class GitHubPrivateRepositoryReleaseDownloadStrategy < GitHubPrivateRepositoryDo
def _fetch
# HTTP request header `Accept: application/octet-stream` is required.
# Without this, the GitHub API will respond with metadata, not binary.
- curl download_url, "-C", downloaded_size, "-o", temporary_path, "-H", "Accept: application/octet-stream"
+ curl_download download_url, "--header", "Accept: application/octet-stream", to: temporary_path
end
private
@@ -915,18 +899,27 @@ class GitHubGitDownloadStrategy < GitDownloadStrategy
def github_last_commit
return if ENV["HOMEBREW_NO_GITHUB_API"]
- output, _, status = curl_output "-H", "Accept: application/vnd.github.v3.sha", \
- "-I", "https://api.github.com/repos/#{@user}/#{@repo}/commits/#{@ref}"
+ output, _, status = curl_output(
+ "--silent", "--head", "--location",
+ "-H", "Accept: application/vnd.github.v3.sha",
+ "https://api.github.com/repos/#{@user}/#{@repo}/commits/#{@ref}"
+ )
+
+ return unless status.success?
- commit = output[/^ETag: \"(\h+)\"/, 1] if status.success?
+ commit = output[/^ETag: \"(\h+)\"/, 1]
version.update_commit(commit) if commit
commit
end
def multiple_short_commits_exist?(commit)
return if ENV["HOMEBREW_NO_GITHUB_API"]
- output, _, status = curl_output "-H", "Accept: application/vnd.github.v3.sha", \
- "-I", "https://api.github.com/repos/#{@user}/#{@repo}/commits/#{commit}"
+
+ output, _, status = curl_output(
+ "--silent", "--head", "--location",
+ "-H", "Accept: application/vnd.github.v3.sha",
+ "https://api.github.com/repos/#{@user}/#{@repo}/commits/#{commit}"
+ )
!(status.success? && output && output[/^Status: (200)/, 1] == "200")
end
@@ -1159,15 +1152,13 @@ class DownloadStrategyDetector
SubversionDownloadStrategy
when %r{^cvs://}
CVSDownloadStrategy
- when %r{^https?://(.+?\.)?googlecode\.com/hg}
- MercurialDownloadStrategy
- when %r{^hg://}
+ when %r{^hg://}, %r{^https?://(.+?\.)?googlecode\.com/hg}
MercurialDownloadStrategy
when %r{^bzr://}
BazaarDownloadStrategy
when %r{^fossil://}
FossilDownloadStrategy
- when %r{^http://svn\.apache\.org/repos/}, %r{^svn\+http://}
+ when %r{^svn\+http://}, %r{^http://svn\.apache\.org/repos/}
SubversionDownloadStrategy
when %r{^https?://(.+?\.)?sourceforge\.net/hgweb/}
MercurialDownloadStrategy
diff --git a/Library/Homebrew/exceptions.rb b/Library/Homebrew/exceptions.rb
index 23a123c44..8b4cddc59 100644
--- a/Library/Homebrew/exceptions.rb
+++ b/Library/Homebrew/exceptions.rb
@@ -181,8 +181,8 @@ class TapFormulaAmbiguityError < RuntimeError
@name = name
@paths = paths
@formulae = paths.map do |path|
- path.to_s =~ HOMEBREW_TAP_PATH_REGEX
- "#{Tap.fetch(Regexp.last_match(1), Regexp.last_match(2))}/#{path.basename(".rb")}"
+ match = path.to_s.match(HOMEBREW_TAP_PATH_REGEX)
+ "#{Tap.fetch(match[:user], match[:repo])}/#{path.basename(".rb")}"
end
super <<-EOS.undent
diff --git a/Library/Homebrew/extend/ENV/super.rb b/Library/Homebrew/extend/ENV/super.rb
index 692fd3623..b518c22a1 100644
--- a/Library/Homebrew/extend/ENV/super.rb
+++ b/Library/Homebrew/extend/ENV/super.rb
@@ -138,7 +138,6 @@ module Superenv
def determine_pkg_config_libdir
PATH.new(
- "/usr/lib/pkgconfig",
homebrew_extra_pkg_config_paths,
).existing
end
diff --git a/Library/Homebrew/extend/os/mac/extend/ENV/super.rb b/Library/Homebrew/extend/os/mac/extend/ENV/super.rb
index f97a2dbbb..9c20cc7c6 100644
--- a/Library/Homebrew/extend/os/mac/extend/ENV/super.rb
+++ b/Library/Homebrew/extend/os/mac/extend/ENV/super.rb
@@ -28,7 +28,7 @@ module Superenv
# @private
def homebrew_extra_pkg_config_paths
paths = \
- ["#{HOMEBREW_LIBRARY}/Homebrew/os/mac/pkgconfig/#{MacOS.version}"]
+ ["/usr/lib/pkgconfig", "#{HOMEBREW_LIBRARY}/Homebrew/os/mac/pkgconfig/#{MacOS.version}"]
paths << "#{MacOS::X11.lib}/pkgconfig" << "#{MacOS::X11.share}/pkgconfig" if x11?
paths
end
diff --git a/Library/Homebrew/extend/os/mac/formula_cellar_checks.rb b/Library/Homebrew/extend/os/mac/formula_cellar_checks.rb
index 10379c981..32e5774f6 100644
--- a/Library/Homebrew/extend/os/mac/formula_cellar_checks.rb
+++ b/Library/Homebrew/extend/os/mac/formula_cellar_checks.rb
@@ -6,7 +6,7 @@ module FormulaCellarChecks
formula.name.start_with?(formula_name)
end
- return if formula.name =~ /^php\d+$/
+ return if formula.name =~ /^php(@?\d+\.?\d*?)?$/
return if MacOS.version < :mavericks && formula.name.start_with?("postgresql")
return if MacOS.version < :yosemite && formula.name.start_with?("memcached")
@@ -67,11 +67,19 @@ module FormulaCellarChecks
checker = LinkageChecker.new(keg, formula)
return unless checker.broken_dylibs?
- problem_if_output <<-EOS.undent
- The installation was broken.
- Broken dylib links found:
- #{checker.broken_dylibs.to_a * "\n "}
+ output = <<-EOS.undent
+ #{formula} has broken dynamic library links:
+ #{checker.broken_dylibs.to_a * "\n "}
EOS
+ tab = Tab.for_keg(keg)
+ if tab.poured_from_bottle
+ output += <<-EOS.undent
+ Rebuild this from source with:
+ brew reinstall --build-from-source #{formula}
+ If that's successful, file an issue#{formula.tap ? " here:\n #{formula.tap.issues_url}" : "."}
+ EOS
+ end
+ problem_if_output output
end
def audit_installed
diff --git a/Library/Homebrew/formula.rb b/Library/Homebrew/formula.rb
index 5673a433f..8cea85a99 100644
--- a/Library/Homebrew/formula.rb
+++ b/Library/Homebrew/formula.rb
@@ -177,8 +177,8 @@ class Formula
@tap = if path == Formulary.core_path(name)
CoreTap.instance
- elsif path.to_s =~ HOMEBREW_TAP_PATH_REGEX
- Tap.fetch(Regexp.last_match(1), Regexp.last_match(2))
+ elsif match = path.to_s.match(HOMEBREW_TAP_PATH_REGEX)
+ Tap.fetch(match[:user], match[:repo])
end
@full_name = full_name_with_optional_tap(name)
@@ -2213,7 +2213,7 @@ class Formula
# depends_on :arch => :x86_64 # If this formula only builds on Intel x86 64-bit.
# depends_on :arch => :ppc # Only builds on PowerPC?
# depends_on :ld64 # Sometimes ld fails on `MacOS.version < :leopard`. Then use this.
- # depends_on :x11 # X11/XQuartz components. Non-optional X11 deps should go in Homebrew/Homebrew-x11
+ # depends_on :x11 # X11/XQuartz components.
# depends_on :osxfuse # Permits the use of the upstream signed binary or our source package.
# depends_on :tuntap # Does the same thing as above. This is vital for Yosemite and above.
# depends_on :mysql => :recommended</pre>
diff --git a/Library/Homebrew/formula_installer.rb b/Library/Homebrew/formula_installer.rb
index 4e4a59972..6c5b8bdab 100644
--- a/Library/Homebrew/formula_installer.rb
+++ b/Library/Homebrew/formula_installer.rb
@@ -46,7 +46,7 @@ class FormulaInstaller
@ignore_deps = false
@only_deps = false
@build_from_source = ARGV.build_from_source? || ARGV.build_all_from_source?
- @build_bottle = ARGV.build_bottle?
+ @build_bottle = false
@force_bottle = ARGV.force_bottle?
@interactive = false
@git = false
@@ -543,7 +543,6 @@ class FormulaInstaller
fi.options |= inherited_options
fi.options &= df.options
fi.build_from_source = ARGV.build_formula_from_source?(df)
- fi.build_bottle = false
fi.force_bottle = false
fi.verbose = verbose?
fi.quieter = quieter?
@@ -680,8 +679,6 @@ class FormulaInstaller
#{formula.specified_path}
].concat(build_argv)
- Sandbox.print_sandbox_message if Sandbox.formula?(formula)
-
Utils.safe_fork do
# Invalidate the current sudo timestamp in case a build script calls sudo.
# Travis CI's Linux sudoless workers have a weird sudo that fails here.
diff --git a/Library/Homebrew/formulary.rb b/Library/Homebrew/formulary.rb
index 195d15cec..dd67b4f24 100644
--- a/Library/Homebrew/formulary.rb
+++ b/Library/Homebrew/formulary.rb
@@ -165,7 +165,7 @@ module Formulary
def load_file
HOMEBREW_CACHE_FORMULA.mkpath
FileUtils.rm_f(path)
- curl url, "-o", path
+ curl_download url, to: path
super
rescue MethodDeprecatedError => e
if url =~ %r{github.com/([\w-]+)/homebrew-([\w-]+)/}
diff --git a/Library/Homebrew/gpg.rb b/Library/Homebrew/gpg.rb
index cb9e367df..f56473df3 100644
--- a/Library/Homebrew/gpg.rb
+++ b/Library/Homebrew/gpg.rb
@@ -7,8 +7,8 @@ class Gpg
next unless gpg_short_version
gpg_version = Version.create(gpg_short_version.to_s)
@version = gpg_version
- gpg_version == Version.create("2.0") ||
- gpg_version == Version.create("2.1")
+ gpg_version == Version.create("2.1") ||
+ gpg_version == Version.create("2.0")
end
end
@@ -20,7 +20,7 @@ class Gpg
find_gpg("gpg2")
end
- GPG_EXECUTABLE = gpg2 || gpg
+ GPG_EXECUTABLE = gpg || gpg2
def self.available?
File.executable?(GPG_EXECUTABLE.to_s)
@@ -38,6 +38,7 @@ class Gpg
Key-Length: 2048
Subkey-Type: RSA
Subkey-Length: 2048
+ Passphrase: ''
Name-Real: Testing
Name-Email: testing@foo.bar
Expire-Date: 1d
diff --git a/Library/Homebrew/keg.rb b/Library/Homebrew/keg.rb
index 8fcbecfbd..92eab7ad3 100644
--- a/Library/Homebrew/keg.rb
+++ b/Library/Homebrew/keg.rb
@@ -253,6 +253,11 @@ class Keg
FileUtils.rm_rf bad_tap_opt if bad_tap_opt.directory?
end
+ aliases.each do |a|
+ alias_symlink = opt/a
+ alias_symlink.delete if alias_symlink.symlink? || alias_symlink.exist?
+ end
+
Pathname.glob("#{opt_record}@*").each do |a|
a = a.basename
next if aliases.include?(a)
diff --git a/Library/Homebrew/os/mac/xcode.rb b/Library/Homebrew/os/mac/xcode.rb
index e23a7cf3d..6f7deaa10 100644
--- a/Library/Homebrew/os/mac/xcode.rb
+++ b/Library/Homebrew/os/mac/xcode.rb
@@ -216,7 +216,7 @@ module OS
# on the older supported platform for that Xcode release, i.e there's no
# CLT package for 10.11 that contains the Clang version from Xcode 8.
case MacOS.version
- when "10.13" then "900.0.31"
+ when "10.13" then "900.0.34.1"
when "10.12" then "802.0.42"
when "10.11" then "800.0.42.1"
when "10.10" then "700.1.81"
diff --git a/Library/Homebrew/requirements/gpg2_requirement.rb b/Library/Homebrew/requirements/gpg2_requirement.rb
index 97fabcca0..d570983eb 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"
- # MacGPG2/GPGTools installs GnuPG 2.0.x as a vanilla `gpg` symlink
- # pointing to `gpg2`, as do we. Ensure we're actually using a 2.0 `gpg`.
- # Support both the 2.0.x "stable" and 2.1.x "modern" series.
- satisfy(build_env: false) { Gpg.gpg2 || Gpg.gpg }
+ # 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.
+ satisfy(build_env: false) { Gpg.gpg || Gpg.gpg2 }
end
diff --git a/Library/Homebrew/rubocops.rb b/Library/Homebrew/rubocops.rb
index 4323e044c..b1144e075 100644
--- a/Library/Homebrew/rubocops.rb
+++ b/Library/Homebrew/rubocops.rb
@@ -6,7 +6,7 @@ require_relative "./rubocops/homepage_cop"
require_relative "./rubocops/text_cop"
require_relative "./rubocops/caveats_cop"
require_relative "./rubocops/checksum_cop"
-require_relative "./rubocops/legacy_patches_cop"
+require_relative "./rubocops/patches_cop"
require_relative "./rubocops/conflicts_cop"
require_relative "./rubocops/options_cop"
require_relative "./rubocops/urls_cop"
diff --git a/Library/Homebrew/rubocops/extend/formula_cop.rb b/Library/Homebrew/rubocops/extend/formula_cop.rb
index 4be0c0fe3..862664010 100644
--- a/Library/Homebrew/rubocops/extend/formula_cop.rb
+++ b/Library/Homebrew/rubocops/extend/formula_cop.rb
@@ -1,4 +1,5 @@
require "parser/current"
+require_relative "../../extend/string"
module RuboCop
module Cop
@@ -138,17 +139,14 @@ module RuboCop
case type
when :required
- type_match = !node.method_args.nil? &&
- (node.method_args.first.str_type? || node.method_args.first.sym_type?)
+ type_match = required_dependency?(node)
if type_match && !name_match
- name_match = node_equals?(node.method_args.first, name)
+ name_match = required_dependency_name?(node, name)
end
when :build, :optional, :recommended, :run
- type_match = !node.method_args.nil? &&
- node.method_args.first.hash_type? &&
- node.method_args.first.values.first.children.first == type
+ type_match = dependency_type_hash_match?(node, type)
if type_match && !name_match
- name_match = node_equals?(node.method_args.first.keys.first.children.first, name)
+ name_match = dependency_name_hash_match?(node, name)
end
else
type_match = false
@@ -161,6 +159,22 @@ module RuboCop
type_match && name_match
end
+ def_node_search :required_dependency?, <<-EOS.undent
+ (send nil :depends_on ({str sym} _))
+ EOS
+
+ def_node_search :required_dependency_name?, <<-EOS.undent
+ (send nil :depends_on ({str sym} %1))
+ EOS
+
+ def_node_search :dependency_type_hash_match?, <<-EOS.undent
+ (hash (pair ({str sym} _) ({str sym} %1)))
+ EOS
+
+ def_node_search :dependency_name_hash_match?, <<-EOS.undent
+ (hash (pair ({str sym} %1) ({str sym} _)))
+ EOS
+
# To compare node with appropriate Ruby variable
def node_equals?(node, var)
node == Parser::CurrentRuby.parse(var.inspect)
diff --git a/Library/Homebrew/rubocops/legacy_patches_cop.rb b/Library/Homebrew/rubocops/patches_cop.rb
index e569f650e..fb14d8acc 100644
--- a/Library/Homebrew/rubocops/legacy_patches_cop.rb
+++ b/Library/Homebrew/rubocops/patches_cop.rb
@@ -4,9 +4,16 @@ require_relative "../extend/string"
module RuboCop
module Cop
module FormulaAudit
- # This cop checks for and audits legacy patches in Formulae
- class LegacyPatches < FormulaCop
+ # This cop audits patches in Formulae
+ class Patches < FormulaCop
def audit_formula(_node, _class_node, _parent_class_node, body)
+ external_patches = find_all_blocks(body, :patch)
+ external_patches.each do |patch_block|
+ url_node = find_every_method_call_by_name(patch_block, :url).first
+ url_string = parameters(url_node).first
+ patch_problems(url_string)
+ end
+
patches_node = find_method_def(body, :patches)
return if patches_node.nil?
legacy_patches = find_strings(patches_node)
@@ -14,6 +21,8 @@ module RuboCop
legacy_patches.each { |p| patch_problems(p) }
end
+ private
+
def patch_problems(patch)
patch_url = string_content(patch)
gh_patch_patterns = Regexp.union([%r{/raw\.github\.com/},
@@ -30,7 +39,7 @@ module RuboCop
if match_obj = regex_match_group(patch, gh_patch_diff_pattern)
problem <<-EOS.undent
use GitHub pull request URLs:
- https://github.com/#{match_obj[1]}/#{match_obj[2]}/pull/#{match_ojb[3]}.patch
+ https://github.com/#{match_obj[1]}/#{match_obj[2]}/pull/#{match_obj[3]}.patch
Rather than patch-diff:
#{patch_url}
EOS
diff --git a/Library/Homebrew/sandbox.rb b/Library/Homebrew/sandbox.rb
index 0de970773..8c662857e 100644
--- a/Library/Homebrew/sandbox.rb
+++ b/Library/Homebrew/sandbox.rb
@@ -18,12 +18,6 @@ class Sandbox
!ARGV.no_sandbox?
end
- def self.print_sandbox_message
- return if @printed_sandbox_message
- ohai "Using the sandbox"
- @printed_sandbox_message = true
- end
-
def initialize
@profile = SandboxProfile.new
end
diff --git a/Library/Homebrew/shims/super/cc b/Library/Homebrew/shims/super/cc
index d894d3d69..afe72156f 100755
--- a/Library/Homebrew/shims/super/cc
+++ b/Library/Homebrew/shims/super/cc
@@ -43,6 +43,8 @@ class Cmd
else
:cc
end
+ elsif @args.include?("-xc++-header") || @args.each_cons(2).include?(["-x", "c++-header"])
+ :cxx
elsif @args.include? "-E"
:ccE
else
diff --git a/Library/Homebrew/software_spec.rb b/Library/Homebrew/software_spec.rb
index c6e704350..49d818f0f 100644
--- a/Library/Homebrew/software_spec.rb
+++ b/Library/Homebrew/software_spec.rb
@@ -51,8 +51,18 @@ class SoftwareSpec
@owner = owner
@resource.owner = self
resources.each_value do |r|
- r.owner = self
- r.version ||= (version.head? ? Version.create("HEAD") : version.dup)
+ r.owner = self
+ r.version ||= begin
+ if version.nil?
+ raise "#{full_name}: version missing for \"#{r.name}\" resource!"
+ end
+
+ if version.head?
+ Version.create("HEAD")
+ else
+ version.dup
+ end
+ end
end
patches.each { |p| p.owner = self }
end
diff --git a/Library/Homebrew/tap.rb b/Library/Homebrew/tap.rb
index 84953726f..f232be428 100644
--- a/Library/Homebrew/tap.rb
+++ b/Library/Homebrew/tap.rb
@@ -42,9 +42,9 @@ class Tap
end
def self.from_path(path)
- path.to_s =~ HOMEBREW_TAP_PATH_REGEX
- raise "Invalid tap path '#{path}'" unless Regexp.last_match(1)
- fetch(Regexp.last_match(1), Regexp.last_match(2))
+ match = path.to_s.match(HOMEBREW_TAP_PATH_REGEX)
+ raise "Invalid tap path '#{path}'" unless match
+ fetch(match[:user], match[:repo])
rescue
# No need to error as a nil tap is sufficient to show failure.
nil
diff --git a/Library/Homebrew/tap_constants.rb b/Library/Homebrew/tap_constants.rb
index 773eff816..23bbc61ed 100644
--- a/Library/Homebrew/tap_constants.rb
+++ b/Library/Homebrew/tap_constants.rb
@@ -3,7 +3,7 @@ HOMEBREW_TAP_FORMULA_REGEX = %r{^([\w-]+)/([\w-]+)/([\w+-.@]+)$}
# match taps' casks, e.g. someuser/sometap/somecask
HOMEBREW_TAP_CASK_REGEX = %r{^([\w-]+)/([\w-]+)/([a-z0-9\-]+)$}
# match taps' directory paths, e.g. HOMEBREW_LIBRARY/Taps/someuser/sometap
-HOMEBREW_TAP_DIR_REGEX = %r{#{Regexp.escape(HOMEBREW_LIBRARY)}/Taps/([\w-]+)/([\w-]+)}
+HOMEBREW_TAP_DIR_REGEX = %r{#{Regexp.escape(HOMEBREW_LIBRARY)}/Taps/(?<user>[\w-]+)/(?<repo>[\w-]+)}
# match taps' formula paths, e.g. HOMEBREW_LIBRARY/Taps/someuser/sometap/someformula
HOMEBREW_TAP_PATH_REGEX = Regexp.new(HOMEBREW_TAP_DIR_REGEX.source + %r{/(.*)}.source)
# match the default and the versions brew-cask tap e.g. Caskroom/cask or Caskroom/versions
diff --git a/Library/Homebrew/test/cask/download_strategy_spec.rb b/Library/Homebrew/test/cask/download_strategy_spec.rb
index 222352c07..17da1e36e 100644
--- a/Library/Homebrew/test/cask/download_strategy_spec.rb
+++ b/Library/Homebrew/test/cask/download_strategy_spec.rb
@@ -26,9 +26,12 @@ describe "download strategies", :cask do
downloader.fetch
expect(downloader).to have_received(:curl).with(
+ "--location",
+ "--remote-time",
+ "--continue-at", "-",
+ "--output", kind_of(Pathname),
cask.url.to_s,
- "-C", 0,
- "-o", kind_of(Pathname)
+ user_agent: :default
)
end
@@ -36,25 +39,25 @@ describe "download strategies", :cask do
let(:url_options) { { user_agent: "Mozilla/25.0.1" } }
it "adds the appropriate curl args" do
- curl_args = []
- allow(downloader).to receive(:curl) { |*args| curl_args = args }
+ expect(downloader).to receive(:safe_system) { |*args|
+ expect(args.each_cons(2)).to include(["--user-agent", "Mozilla/25.0.1"])
+ }
downloader.fetch
-
- expect(curl_args.each_cons(2)).to include(["-A", "Mozilla/25.0.1"])
end
end
context "with a generalized fake user agent" do
+ alias_matcher :a_string_matching, :match
+
let(:url_options) { { user_agent: :fake } }
it "adds the appropriate curl args" do
- curl_args = []
- allow(downloader).to receive(:curl) { |*args| curl_args = args }
+ expect(downloader).to receive(:safe_system) { |*args|
+ expect(args.each_cons(2).to_a).to include(["--user-agent", a_string_matching(/Mozilla.*Mac OS X 10.*AppleWebKit/)])
+ }
downloader.fetch
-
- expect(curl_args.each_cons(2)).to include(["-A", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10) https://caskroom.github.io"])
end
end
@@ -138,7 +141,7 @@ describe "download strategies", :cask do
describe Hbc::SubversionDownloadStrategy do
let(:url_options) { { using: :svn } }
let(:fake_system_command) { class_double(Hbc::SystemCommand) }
- let(:downloader) { Hbc::SubversionDownloadStrategy.new(cask, fake_system_command) }
+ let(:downloader) { Hbc::SubversionDownloadStrategy.new(cask, command: fake_system_command) }
before do
allow(fake_system_command).to receive(:run!)
end
@@ -147,7 +150,7 @@ describe "download strategies", :cask do
allow(downloader).to receive(:compress)
allow(downloader).to receive(:fetch_repo)
- expect(downloader.fetch).to equal(downloader.tarball_path)
+ expect(downloader.fetch).to equal(downloader.cached_location)
end
it "calls fetch_repo with default arguments for a simple Cask" do
@@ -237,44 +240,5 @@ describe "download strategies", :cask do
)
end
end
-
- it "runs tar to serialize svn downloads" do
- # sneaky stub to remake the directory, since homebrew code removes it
- # before tar is called
- allow(downloader).to receive(:fetch_repo) {
- downloader.cached_location.mkdir
- }
-
- downloader.fetch
-
- expect(fake_system_command).to have_received(:run!).with(
- "/usr/bin/tar",
- hash_including(args: [
- '-s/^\\.//',
- "--exclude",
- ".svn",
- "-cf",
- downloader.tarball_path,
- "--",
- ".",
- ]),
- )
- end
end
-
- # does not work yet, because (for unknown reasons), the tar command
- # returns an error code when running under the test suite
- # it 'creates a tarball matching the expected checksum' do
- # cask = Hbc::CaskLoader.load('svn-download-check-cask')
- # downloader = Hbc::SubversionDownloadStrategy.new(cask)
- # # special mocking required for tar to have something to work with
- # def downloader.fetch_repo(target, url, revision = nil, ignore_externals=false)
- # target.mkpath
- # FileUtils.touch(target.join('empty_file.txt'))
- # File.utime(1000,1000,target.join('empty_file.txt'))
- # end
- # expect(downloader.fetch).to equal(downloader.tarball_path)
- # d = Hbc::Download.new(cask)
- # d.send(:_check_sums, downloader.tarball_path, cask.sums)
- # end
end
diff --git a/Library/Homebrew/test/cask/dsl/appcast_spec.rb b/Library/Homebrew/test/cask/dsl/appcast_spec.rb
index b8903b1be..ccc6a4633 100644
--- a/Library/Homebrew/test/cask/dsl/appcast_spec.rb
+++ b/Library/Homebrew/test/cask/dsl/appcast_spec.rb
@@ -33,13 +33,18 @@ describe Hbc::DSL::Appcast do
describe "#calculate_checkpoint" do
before do
- expect(Hbc::SystemCommand).to receive(:run).with(*cmd_args).and_return(cmd_result)
+ expect(Hbc::SystemCommand).to receive(:run) do |executable, **options|
+ expect(executable).to eq "/usr/bin/curl"
+ expect(options[:args]).to include(*cmd_args)
+ expect(options[:print_stderr]).to be false
+ cmd_result
+ end
allow(cmd_result).to receive(:success?).and_return(cmd_success)
allow(cmd_result).to receive(:stdout).and_return(cmd_stdout)
end
context "when server returns a successful HTTP status" do
- let(:cmd_args) { ["/usr/bin/curl", args: ["--compressed", "--location", "--user-agent", Hbc::URL::FAKE_USER_AGENT, "--fail", uri], print_stderr: false] }
+ let(:cmd_args) { [HOMEBREW_USER_AGENT_FAKE_SAFARI, "--compressed", "--location", "--fail", uri] }
let(:cmd_result) { double("Hbc::SystemCommand::Result") }
let(:cmd_success) { true }
let(:cmd_stdout) { "hello world" }
@@ -56,7 +61,7 @@ describe Hbc::DSL::Appcast do
end
context "when server returns a non-successful HTTP status" do
- let(:cmd_args) { ["/usr/bin/curl", args: ["--compressed", "--location", "--user-agent", Hbc::URL::FAKE_USER_AGENT, "--fail", uri], print_stderr: false] }
+ let(:cmd_args) { [HOMEBREW_USER_AGENT_FAKE_SAFARI, "--compressed", "--location", "--fail", uri] }
let(:cmd_result) { double("Hbc::SystemCommand::Result") }
let(:cmd_success) { false }
let(:cmd_stdout) { "some error message from the server" }
diff --git a/Library/Homebrew/test/cask/pkg_spec.rb b/Library/Homebrew/test/cask/pkg_spec.rb
index 56061c9fd..07443e76e 100644
--- a/Library/Homebrew/test/cask/pkg_spec.rb
+++ b/Library/Homebrew/test/cask/pkg_spec.rb
@@ -5,16 +5,16 @@ describe Hbc::Pkg, :cask do
let(:pkg) { described_class.new("my.fake.pkg", fake_system_command) }
it "removes files and dirs referenced by the pkg" do
- some_files = Array.new(3) { Pathname.new(Tempfile.new("testfile").path) }
+ some_files = Array.new(3) { Pathname.new(Tempfile.new("plain_file").path) }
allow(pkg).to receive(:pkgutil_bom_files).and_return(some_files)
- some_specials = Array.new(3) { Pathname.new(Tempfile.new("testfile").path) }
+ some_specials = Array.new(3) { Pathname.new(Tempfile.new("special_file").path) }
allow(pkg).to receive(:pkgutil_bom_specials).and_return(some_specials)
- some_dirs = Array.new(3) { Pathname.new(Dir.mktmpdir) }
+ some_dirs = Array.new(3) { mktmpdir }
allow(pkg).to receive(:pkgutil_bom_dirs).and_return(some_dirs)
- root_dir = Pathname.new(Dir.mktmpdir)
+ root_dir = Pathname.new(mktmpdir)
allow(pkg).to receive(:root).and_return(root_dir)
allow(pkg).to receive(:forget)
@@ -55,8 +55,8 @@ describe Hbc::Pkg, :cask do
end
it "removes broken symlinks" do
- fake_dir = Pathname.new(Dir.mktmpdir)
- fake_root = Pathname.new(Dir.mktmpdir)
+ fake_root = mktmpdir
+ fake_dir = mktmpdir
fake_file = fake_dir.join("ima_file").tap { |path| FileUtils.touch(path) }
intact_symlink = fake_dir.join("intact_symlink").tap { |path| path.make_symlink(fake_file) }
@@ -77,13 +77,13 @@ describe Hbc::Pkg, :cask do
end
it "snags permissions on ornery dirs, but returns them afterwards" do
- fake_root = Pathname.new(Dir.mktmpdir)
- fake_dir = Pathname.new(Dir.mktmpdir)
- fake_file = fake_dir.join("ima_installed_file").tap { |path| FileUtils.touch(path) }
+ fake_root = mktmpdir
+ fake_dir = mktmpdir
+ fake_file = fake_dir.join("ima_unrelated_file").tap { |path| FileUtils.touch(path) }
fake_dir.chmod(0000)
allow(pkg).to receive(:pkgutil_bom_specials).and_return([])
- allow(pkg).to receive(:pkgutil_bom_files).and_return([fake_file])
+ allow(pkg).to receive(:pkgutil_bom_files).and_return([])
allow(pkg).to receive(:pkgutil_bom_dirs).and_return([fake_dir])
allow(pkg).to receive(:root).and_return(fake_root)
allow(pkg).to receive(:forget)
@@ -91,8 +91,12 @@ describe Hbc::Pkg, :cask do
pkg.uninstall
expect(fake_dir).to be_a_directory
- expect(fake_file).not_to be_a_file
- expect((fake_dir.stat.mode % 01000).to_s(8)).to eq("0")
+ expect((fake_dir.stat.mode % 01000)).to eq(0)
+
+ fake_dir.chmod(0777)
+ expect(fake_file).to be_a_file
+
+ FileUtils.rm_r fake_dir
end
end
diff --git a/Library/Homebrew/test/cmd/search_spec.rb b/Library/Homebrew/test/cmd/search_spec.rb
index 06b7073d8..77c2c6352 100644
--- a/Library/Homebrew/test/cmd/search_spec.rb
+++ b/Library/Homebrew/test/cmd/search_spec.rb
@@ -1,6 +1,7 @@
describe "brew search", :integration_test do
before(:each) do
setup_test_formula "testball"
+ setup_remote_tap "caskroom/cask"
end
it "lists all available Formulae when no argument is given" do
@@ -13,7 +14,7 @@ describe "brew search", :integration_test do
it "supports searching by name" do
expect { brew "search", "testball" }
.to output(/testball/).to_stdout
- .and not_to_output.to_stderr
+ .and output(/Searching/).to_stderr
.and be_a_success
end
@@ -24,6 +25,13 @@ describe "brew search", :integration_test do
.and be_a_success
end
+ it "falls back to a GitHub tap search when no formula is found", :needs_network do
+ expect { brew "search", "caskroom/cask/firefox" }
+ .to output(/firefox/).to_stdout
+ .and output(/Searching/).to_stderr
+ .and be_a_success
+ end
+
describe "--desc" do
let(:desc_cache) { HOMEBREW_CACHE/"desc_cache.json" }
@@ -44,7 +52,7 @@ describe "brew search", :integration_test do
"fink" => "http://pdb.finkproject.org/pdb/browse.php?summary=testball",
"debian" => "https://packages.debian.org/search?keywords=testball&searchon=names&suite=all&section=all",
"opensuse" => "https://software.opensuse.org/search?q=testball",
- "fedora" => "https://admin.fedoraproject.org/pkgdb/packages/%2Atestball%2A/",
+ "fedora" => "https://apps.fedoraproject.org/packages/s/testball",
"ubuntu" => "http://packages.ubuntu.com/search?keywords=testball&searchon=names&suite=all&section=all",
}.each do |flag, url|
specify "--#{flag}" do
diff --git a/Library/Homebrew/test/formula_installer_spec.rb b/Library/Homebrew/test/formula_installer_spec.rb
index c3573ae94..7365b2758 100644
--- a/Library/Homebrew/test/formula_installer_spec.rb
+++ b/Library/Homebrew/test/formula_installer_spec.rb
@@ -133,7 +133,7 @@ describe FormulaInstaller do
}.to raise_error(CannotInstallFormulaError)
end
- describe "#install_requirement_formula?", :focus do
+ describe "#install_requirement_formula?" do
before do
@requirement = Python3Requirement.new
@requirement_dependency = @requirement.to_dependency
diff --git a/Library/Homebrew/test/rubocops/legacy_patches_cop_spec.rb b/Library/Homebrew/test/rubocops/patches_cop_spec.rb
index a08fa614d..4bd79bf35 100644
--- a/Library/Homebrew/test/rubocops/legacy_patches_cop_spec.rb
+++ b/Library/Homebrew/test/rubocops/patches_cop_spec.rb
@@ -1,9 +1,9 @@
require "rubocop"
require "rubocop/rspec/support"
require_relative "../../extend/string"
-require_relative "../../rubocops/legacy_patches_cop"
+require_relative "../../rubocops/patches_cop"
-describe RuboCop::Cop::FormulaAudit::LegacyPatches do
+describe RuboCop::Cop::FormulaAudit::Patches do
subject(:cop) { described_class.new }
context "When auditing legacy patches" do
@@ -47,6 +47,7 @@ describe RuboCop::Cop::FormulaAudit::LegacyPatches do
"https://mirrors.ustc.edu.cn/macports/trunk/",
"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",
]
patch_urls.each do |patch_url|
source = <<-EOS.undent
@@ -84,6 +85,15 @@ describe RuboCop::Cop::FormulaAudit::LegacyPatches do
line: 5,
column: 5,
source: source }]
+ elsif patch_url =~ %r{https?://patch-diff\.githubusercontent\.com/raw/(.+)/(.+)/pull/(.+)\.(?:diff|patch)}
+ expected_offenses = [{ message: "use GitHub pull request URLs:\n"\
+ " https://github.com/foo/foo-bar/pull/100.patch\n"\
+ "Rather than patch-diff:\n"\
+ " https://patch-diff.githubusercontent.com/raw/foo/foo-bar/pull/100.patch\n",
+ severity: :convention,
+ line: 5,
+ column: 5,
+ source: source }]
end
expected_offenses.zip([cop.offenses.last]).each do |expected, actual|
expect_offense(expected, actual)
@@ -125,4 +135,67 @@ describe RuboCop::Cop::FormulaAudit::LegacyPatches do
end
end
end
+
+ context "When auditing external patches" do
+ it "Patch URLs" do
+ patch_urls = [
+ "https://raw.github.com/mogaal/sendemail",
+ "https://mirrors.ustc.edu.cn/macports/trunk/",
+ "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",
+ ]
+ patch_urls.each do |patch_url|
+ source = <<-EOS.undent
+ class Foo < Formula
+ homepage "ftp://example.com/foo"
+ url "http://example.com/foo-1.0.tgz"
+ patch do
+ url "#{patch_url}"
+ sha256 "63376b8fdd6613a91976106d9376069274191860cd58f039b29ff16de1925621"
+ end
+ end
+ EOS
+
+ inspect_source(cop, source)
+ if patch_url =~ %r{/raw\.github\.com/}
+ expected_offenses = [{ message: "GitHub/Gist patches should specify a revision:\n#{patch_url}",
+ severity: :convention,
+ line: 5,
+ column: 16,
+ source: source }]
+ elsif patch_url =~ %r{macports/trunk}
+ expected_offenses = [{ message: "MacPorts patches should specify a revision instead of trunk:\n#{patch_url}",
+ severity: :convention,
+ line: 5,
+ column: 37,
+ source: source }]
+ elsif patch_url =~ %r{^http://trac\.macports\.org}
+ expected_offenses = [{ message: "Patches from MacPorts Trac should be https://, not http:\n#{patch_url}",
+ severity: :convention,
+ line: 5,
+ column: 9,
+ source: source }]
+ elsif patch_url =~ %r{^http://bugs\.debian\.org}
+ expected_offenses = [{ message: "Patches from Debian should be https://, not http:\n#{patch_url}",
+ severity: :convention,
+ line: 5,
+ column: 9,
+ source: source }]
+ elsif patch_url =~ %r{https?://patch-diff\.githubusercontent\.com/raw/(.+)/(.+)/pull/(.+)\.(?:diff|patch)}
+ expected_offenses = [{ message: "use GitHub pull request URLs:\n"\
+ " https://github.com/foo/foo-bar/pull/100.patch\n"\
+ "Rather than patch-diff:\n"\
+ " https://patch-diff.githubusercontent.com/raw/foo/foo-bar/pull/100.patch\n",
+ severity: :convention,
+ line: 5,
+ column: 9,
+ source: source }]
+ end
+ expected_offenses.zip([cop.offenses.last]).each do |expected, actual|
+ expect_offense(expected, actual)
+ end
+ end
+ end
+ end
end
diff --git a/Library/Homebrew/test/rubocops/text_cop_spec.rb b/Library/Homebrew/test/rubocops/text_cop_spec.rb
index b218e9c25..ec13c4041 100644
--- a/Library/Homebrew/test/rubocops/text_cop_spec.rb
+++ b/Library/Homebrew/test/rubocops/text_cop_spec.rb
@@ -7,6 +7,54 @@ describe RuboCop::Cop::FormulaAudit::Text do
subject(:cop) { described_class.new }
context "When auditing formula text" do
+ it "with both openssl and libressl optional dependencies" do
+ source = <<-EOS.undent
+ class Foo < Formula
+ url "http://example.com/foo-1.0.tgz"
+ homepage "http://example.com"
+
+ depends_on "openssl"
+ depends_on "libressl" => :optional
+ end
+ EOS
+
+ expected_offenses = [{ message: "Formulae should not depend on both OpenSSL and LibreSSL (even optionally).",
+ severity: :convention,
+ line: 6,
+ 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 both openssl and libressl dependencies" do
+ source = <<-EOS.undent
+ class Foo < Formula
+ url "http://example.com/foo-1.0.tgz"
+ homepage "http://example.com"
+
+ depends_on "openssl"
+ depends_on "libressl"
+ end
+ EOS
+
+ expected_offenses = [{ message: "Formulae should not depend on both OpenSSL and LibreSSL (even optionally).",
+ severity: :convention,
+ line: 6,
+ column: 2,
+ source: source }]
+
+ inspect_source(cop, source)
+
+ expected_offenses.zip(cop.offenses).each do |expected, actual|
+ expect_offense(expected, actual)
+ end
+ end
+
it "When xcodebuild is called without SYMROOT" do
source = <<-EOS.undent
class Foo < Formula
diff --git a/Library/Homebrew/test/utils/github_spec.rb b/Library/Homebrew/test/utils/github_spec.rb
index 9b539262f..9322898ee 100644
--- a/Library/Homebrew/test/utils/github_spec.rb
+++ b/Library/Homebrew/test/utils/github_spec.rb
@@ -2,12 +2,38 @@ require "utils/github"
describe GitHub do
describe "::search_code", :needs_network do
- it "searches code" do
- results = subject.search_code("repo:Homebrew/brew", "path:/", "filename:readme", "language:markdown")
+ it "queries GitHub code with the passed paramaters" do
+ results = subject.search_code(repo: "Homebrew/brew", path: "/",
+ filename: "readme", language: "markdown")
expect(results.count).to eq(1)
expect(results.first["name"]).to eq("README.md")
expect(results.first["path"]).to eq("README.md")
end
end
+
+ describe "::query_string" do
+ it "builds a query with the given hash parameters formatted as key:value" do
+ query = subject.query_string(user: "Homebrew", repo: "brew")
+ expect(query).to eq("q=user%3AHomebrew+repo%3Abrew&per_page=100")
+ end
+
+ it "adds a variable number of top-level string parameters to the query when provided" do
+ query = subject.query_string("value1", "value2", user: "Homebrew")
+ expect(query).to eq("q=value1+value2+user%3AHomebrew&per_page=100")
+ end
+
+ it "turns array values into multiple key:value parameters" do
+ query = subject.query_string(user: ["Homebrew", "caskroom"])
+ expect(query).to eq("q=user%3AHomebrew+user%3Acaskroom&per_page=100")
+ end
+ end
+
+ describe "::search_issues", :needs_network do
+ it "queries GitHub issues with the passed parameters" do
+ results = subject.search_issues("brew search", repo: "Homebrew/brew", author: "avetamine", is: "closed")
+ expect(results).not_to be_empty
+ expect(results.last["title"]).to eq("brew search : 422 Unprocessable Entity")
+ end
+ end
end
diff --git a/Library/Homebrew/utils/curl.rb b/Library/Homebrew/utils/curl.rb
index 5a40ae846..52d03c93e 100644
--- a/Library/Homebrew/utils/curl.rb
+++ b/Library/Homebrew/utils/curl.rb
@@ -1,42 +1,55 @@
require "pathname"
require "open3"
-def curl_args(options = {})
+def curl_executable
curl = Pathname.new ENV["HOMEBREW_CURL"]
curl = Pathname.new "/usr/bin/curl" unless curl.exist?
- raise "#{curl} is not executable" unless curl.exist? && curl.executable?
+ return curl if curl.executable?
+ raise "#{curl} is not executable"
+end
+def curl_args(*extra_args, show_output: false, user_agent: :default)
args = [
- curl.to_s,
- "--remote-time",
- "--location",
+ curl_executable.to_s,
+ "--show-error",
]
- case options[:user_agent]
- when :browser
- args << "--user-agent" << HOMEBREW_USER_AGENT_FAKE_SAFARI
+ args << "--user-agent" << case user_agent
+ when :browser, :fake
+ HOMEBREW_USER_AGENT_FAKE_SAFARI
+ when :default
+ HOMEBREW_USER_AGENT_CURL
else
- args << "--user-agent" << HOMEBREW_USER_AGENT_CURL
+ user_agent
end
- unless options[:show_output]
+ unless show_output
+ args << "--fail"
args << "--progress-bar" unless ARGV.verbose?
args << "--verbose" if ENV["HOMEBREW_CURL_VERBOSE"]
- args << "--fail"
args << "--silent" if !$stdout.tty? || ENV["TRAVIS"]
end
- args += options[:extra_args] if options[:extra_args]
- args
+ args + extra_args
end
def curl(*args)
- safe_system(*curl_args(extra_args: args))
+ safe_system(*curl_args(*args))
end
-def curl_output(*args)
- curl_args = curl_args(extra_args: args, show_output: true)
- Open3.popen3(*curl_args) do |_, stdout, stderr, wait_thread|
- [stdout.read, stderr.read, wait_thread.value]
+def curl_download(*args, to: nil, **options)
+ continue_at ||= "-"
+ curl("--location", "--remote-time", "--continue-at", continue_at, "--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"
+ retry
end
+
+ raise
+end
+
+def curl_output(*args, **options)
+ Open3.capture3(*curl_args(*args, show_output: true, **options))
end
diff --git a/Library/Homebrew/utils/github.rb b/Library/Homebrew/utils/github.rb
index 1a781cee6..a1cf5fbba 100644
--- a/Library/Homebrew/utils/github.rb
+++ b/Library/Homebrew/utils/github.rb
@@ -133,7 +133,7 @@ module GitHub
def open(url, data: nil, scopes: [].freeze)
# This is a no-op if the user is opting out of using the GitHub API.
- return if ENV["HOMEBREW_NO_GITHUB_API"]
+ return block_given? ? yield({}) : {} if ENV["HOMEBREW_NO_GITHUB_API"]
args = %W[--header application/vnd.github.v3+json --write-out \n%{http_code}]
args += curl_args
@@ -166,7 +166,7 @@ module GitHub
args += ["--dump-header", headers_tmpfile.path]
- output, errors, status = curl_output(url.to_s, *args)
+ output, errors, status = curl_output(url.to_s, "--location", *args)
output, _, http_code = output.rpartition("\n")
output, _, http_code = output.rpartition("\n") if http_code == "000"
headers = headers_tmpfile.read
@@ -227,72 +227,60 @@ module GitHub
end
end
- def issues_matching(query, qualifiers = {})
- uri = URI.parse("#{API_URL}/search/issues")
- uri.query = build_query_string(query, qualifiers)
- open(uri) { |json| json["items"] }
+ def search_issues(query, **qualifiers)
+ search("issues", query, **qualifiers)
end
def repository(user, repo)
- open(URI.parse("#{API_URL}/repos/#{user}/#{repo}"))
+ open(url_to("repos", user, repo))
end
- def search_code(*params)
- uri = URI.parse("#{API_URL}/search/code")
- uri.query = "q=#{uri_escape(params.join(" "))}"
- open(uri) { |json| json["items"] }
- end
-
- def build_query_string(query, qualifiers)
- s = "q=#{uri_escape(query)}+"
- s << build_search_qualifier_string(qualifiers)
- s << "&per_page=100"
- end
-
- def build_search_qualifier_string(qualifiers)
- {
- repo: "Homebrew/homebrew-core",
- in: "title",
- }.update(qualifiers).map do |qualifier, value|
- "#{qualifier}:#{value}"
- end.join("+")
- end
-
- def uri_escape(query)
- if URI.respond_to?(:encode_www_form_component)
- URI.encode_www_form_component(query)
- else
- require "erb"
- ERB::Util.url_encode(query)
- end
+ def search_code(**qualifiers)
+ search("code", **qualifiers)
end
def issues_for_formula(name, options = {})
tap = options[:tap] || CoreTap.instance
- issues_matching(name, state: "open", repo: "#{tap.user}/homebrew-#{tap.repo}")
+ search_issues(name, state: "open", repo: "#{tap.user}/homebrew-#{tap.repo}")
end
def print_pull_requests_matching(query)
- return [] if ENV["HOMEBREW_NO_GITHUB_API"]
-
- open_or_closed_prs = issues_matching(query, type: "pr")
+ open_or_closed_prs = search_issues(query, type: "pr")
open_prs = open_or_closed_prs.select { |i| i["state"] == "open" }
- if !open_prs.empty?
+ prs = if !open_prs.empty?
puts "Open pull requests:"
- prs = open_prs
- elsif !open_or_closed_prs.empty?
- puts "Closed pull requests:"
- prs = open_or_closed_prs
+ open_prs
else
- return
+ puts "Closed pull requests:" unless open_or_closed_prs.empty?
+ open_or_closed_prs
end
prs.each { |i| puts "#{i["title"]} (#{i["html_url"]})" }
end
def private_repo?(full_name)
- uri = URI.parse("#{API_URL}/repos/#{full_name}")
+ uri = url_to "repos", full_name
open(uri) { |json| json["private"] }
end
+
+ def query_string(*main_params, **qualifiers)
+ params = main_params
+
+ params += qualifiers.flat_map do |key, value|
+ Array(value).map { |v| "#{key}:#{v}" }
+ end
+
+ "q=#{URI.encode_www_form_component(params.join(" "))}&per_page=100"
+ end
+
+ def url_to(*subroutes)
+ URI.parse([API_URL, *subroutes].join("/"))
+ end
+
+ def search(entity, *queries, **qualifiers)
+ uri = url_to "search", entity
+ uri.query = query_string(*queries, **qualifiers)
+ open(uri) { |json| json.fetch("items", []) }
+ end
end